a2spa 0.1.4__tar.gz → 2.4.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- a2spa-2.4.2/PKG-INFO +164 -0
- {a2spa-0.1.4 → a2spa-2.4.2}/README.md +7 -1
- {a2spa-0.1.4 → a2spa-2.4.2}/pyproject.toml +45 -41
- a2spa-2.4.2/sdk/README.md +137 -0
- a2spa-2.4.2/sdk/a2spa/__init__.py +1441 -0
- a2spa-2.4.2/sdk/a2spa/delegation.py +1 -0
- a2spa-2.4.2/sdk/a2spa/ephemeral_agents.py +123 -0
- a2spa-2.4.2/sdk/a2spa/evidence.py +1 -0
- a2spa-2.4.2/sdk/a2spa/policy_constraints.py +1 -0
- a2spa-2.4.2/sdk/a2spa/state_integrity.py +1 -0
- a2spa-2.4.2/sdk/a2spa.egg-info/PKG-INFO +164 -0
- a2spa-2.4.2/sdk/a2spa.egg-info/SOURCES.txt +24 -0
- a2spa-2.4.2/sdk/a2spa.egg-info/requires.txt +4 -0
- a2spa-2.4.2/sdk/a2spa.egg-info/top_level.txt +8 -0
- a2spa-2.4.2/sdk/a2spa_delegation.py +923 -0
- a2spa-2.4.2/sdk/a2spa_evidence.py +821 -0
- a2spa-2.4.2/sdk/a2spa_operation_ledger.py +274 -0
- a2spa-2.4.2/sdk/a2spa_policy_constraints.py +1056 -0
- a2spa-2.4.2/sdk/a2spa_policy_usage_ledger.py +273 -0
- a2spa-2.4.2/sdk/a2spa_receipt_verifier.py +127 -0
- a2spa-2.4.2/sdk/a2spa_state_integrity.py +250 -0
- a2spa-0.1.4/PKG-INFO +0 -116
- a2spa-0.1.4/sdk/README.md +0 -92
- a2spa-0.1.4/sdk/a2spa/__init__.py +0 -622
- a2spa-0.1.4/sdk/a2spa.egg-info/PKG-INFO +0 -116
- a2spa-0.1.4/sdk/a2spa.egg-info/SOURCES.txt +0 -12
- a2spa-0.1.4/sdk/a2spa.egg-info/requires.txt +0 -4
- a2spa-0.1.4/sdk/a2spa.egg-info/top_level.txt +0 -1
- {a2spa-0.1.4 → a2spa-2.4.2}/LICENSE +0 -0
- {a2spa-0.1.4 → a2spa-2.4.2}/MANIFEST.in +0 -0
- {a2spa-0.1.4 → a2spa-2.4.2}/sdk/a2spa/py.typed +0 -0
- {a2spa-0.1.4 → a2spa-2.4.2}/sdk/a2spa.egg-info/dependency_links.txt +0 -0
- {a2spa-0.1.4 → a2spa-2.4.2}/setup.cfg +0 -0
a2spa-2.4.2/PKG-INFO
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: a2spa
|
|
3
|
+
Version: 2.4.2
|
|
4
|
+
Summary: A2SPA payload helper library for AI-agent runtime authorization
|
|
5
|
+
Author: AI Modularity
|
|
6
|
+
License-Expression: LicenseRef-Proprietary
|
|
7
|
+
Project-URL: Homepage, https://aimodularity.com/A2SPA
|
|
8
|
+
Project-URL: Documentation, https://aimodularity.com/A2SPA/docs
|
|
9
|
+
Project-URL: Source, https://github.com/gavincapriola/A2SPA
|
|
10
|
+
Project-URL: Changelog, https://github.com/gavincapriola/A2SPA/blob/main/CHANGELOG.md
|
|
11
|
+
Project-URL: Issues, https://github.com/gavincapriola/A2SPA/issues
|
|
12
|
+
Keywords: a2spa,ai-agents,authorization,payload-helpers,signed-payloads,runtime-security
|
|
13
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Topic :: Security
|
|
19
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
20
|
+
Requires-Python: <3.13,>=3.11
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Requires-Dist: cryptography==50.0.2
|
|
24
|
+
Provides-Extra: pq
|
|
25
|
+
Requires-Dist: pqcrypto==1.0.0; extra == "pq"
|
|
26
|
+
Dynamic: license-file
|
|
27
|
+
|
|
28
|
+
# A2SPA Python Payload Helpers
|
|
29
|
+
|
|
30
|
+
Helper-only Python package for building, hashing, and signing A2SPA runtime authorization payloads.
|
|
31
|
+
|
|
32
|
+
The verifier remains server-side. This package does not authorize actions by itself.
|
|
33
|
+
|
|
34
|
+
## Install
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
pip install a2spa
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
For ML-DSA signing support where the optional wheel is available:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
pip install "a2spa[pq]"
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Basic Usage
|
|
47
|
+
|
|
48
|
+
```python
|
|
49
|
+
from pathlib import Path
|
|
50
|
+
|
|
51
|
+
from a2spa import build_payload_fields, build_signed_request, policy_input
|
|
52
|
+
|
|
53
|
+
private_key_text = Path("sender.priv.pem").read_text(encoding="utf-8")
|
|
54
|
+
|
|
55
|
+
payload = build_payload_fields(
|
|
56
|
+
agent_id="user-123_sender",
|
|
57
|
+
target_agent_id="user-123_receiver",
|
|
58
|
+
input_data=policy_input(action="deliver", workflow_scope="messages:deliver"),
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
request_body = build_signed_request(private_key_text, payload)
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Send `request_body` to `POST /v1/verify_payload` with your account API key in the `x-api-key` header. The previous `/api/verify_payload` path remains a deprecated compatibility alias.
|
|
65
|
+
|
|
66
|
+
See the [A2SPA 2.4 migration guide](https://aimodularity.com/A2SPA/docs#api-versioning) for route compatibility and `docs/a2spa-2.4-migration.md` in the server source repository for detailed retry and rollback guidance.
|
|
67
|
+
|
|
68
|
+
## Helper Functions
|
|
69
|
+
|
|
70
|
+
- `build_payload_fields(...)`
|
|
71
|
+
- `policy_input(...)`
|
|
72
|
+
- `policy_template(...)`
|
|
73
|
+
- `state_continuity_claim(...)`
|
|
74
|
+
- `canonicalize_payload(...)`
|
|
75
|
+
- `compute_payload_hash(...)`
|
|
76
|
+
- `finalize_payload(...)`
|
|
77
|
+
- `sign_payload(...)`
|
|
78
|
+
- `build_signed_request(...)`
|
|
79
|
+
- `is_authorized_result(...)`
|
|
80
|
+
- `require_authorized_result(...)`
|
|
81
|
+
- `verify_execution_receipt(...)`
|
|
82
|
+
- `enforce_target_authorization(...)`
|
|
83
|
+
- `build_target_acknowledgement(...)`
|
|
84
|
+
- `execute_protected_action(...)`
|
|
85
|
+
- `InMemoryTargetOperationLedger(...)`
|
|
86
|
+
- `SQLiteTargetOperationLedger(...)`
|
|
87
|
+
- `InMemoryPolicyUsageLedger(...)`
|
|
88
|
+
- `SQLitePolicyUsageLedger(...)`
|
|
89
|
+
- `policy_constraints_input(...)`
|
|
90
|
+
- `evaluate_policy_constraints(...)`
|
|
91
|
+
- `build_authorization_evidence_package(...)`
|
|
92
|
+
- `normalize_agent_lifecycle(...)`
|
|
93
|
+
- `agent_is_active(...)`
|
|
94
|
+
- `sign_delegation_grant(...)`
|
|
95
|
+
- `validate_delegation_chain(...)`
|
|
96
|
+
- `build_consumption_state_record(...)`
|
|
97
|
+
- `verify_consumption_state_record(...)`
|
|
98
|
+
- `build_debug_snapshot(...)`
|
|
99
|
+
|
|
100
|
+
## Signed Bytes
|
|
101
|
+
|
|
102
|
+
Current helper compatibility signs the UTF-8 bytes of `json.dumps(signable_payload, sort_keys=True)` using the normalized signable fields. Do not reimplement canonicalization unless your bytes match `canonicalize_payload(...)` exactly.
|
|
103
|
+
|
|
104
|
+
## Security Boundary
|
|
105
|
+
|
|
106
|
+
Private keys must stay in a secret manager, server environment, or deployment secret. Do not paste private keys into chats, logs, client-side code, or source control.
|
|
107
|
+
|
|
108
|
+
## A2SPA 2.1 Target Enforcement
|
|
109
|
+
|
|
110
|
+
A2SPA 2.1 adds a deployment profile for protected targets. The target, trusted gateway, service, or executor should fail closed unless the A2SPA authorization result is valid for the exact operation being committed.
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
from a2spa import SQLiteTargetOperationLedger, execute_protected_action
|
|
114
|
+
|
|
115
|
+
operation_id = message["idempotency_key"]
|
|
116
|
+
operation_ledger = SQLiteTargetOperationLedger("target-operations.sqlite3")
|
|
117
|
+
execution = execute_protected_action(
|
|
118
|
+
result,
|
|
119
|
+
lambda authorization: {
|
|
120
|
+
"provider_message_id": email_provider.send(message).id,
|
|
121
|
+
},
|
|
122
|
+
target_id="smtp-gateway",
|
|
123
|
+
operation_id=operation_id,
|
|
124
|
+
target_private_key_pem=target_ack_private_key,
|
|
125
|
+
target_agent_id="user-123_email-target",
|
|
126
|
+
action="send_email",
|
|
127
|
+
workflow_scope="email:send",
|
|
128
|
+
trusted_receipt_public_key_pem=trusted_a2spa_receipt_public_key,
|
|
129
|
+
operation_ledger=operation_ledger,
|
|
130
|
+
require_target_idempotency=True,
|
|
131
|
+
)
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
`SQLiteTargetOperationLedger` is a durable single-node implementation. Multi-instance targets should supply a transactional shared-store adapter with the same `begin_operation`, `commit_operation`, `cancel_operation`, and `fail_operation` contract. In-progress or indeterminate operations fail closed; an exact committed retry returns the stored execution without invoking the operation again.
|
|
135
|
+
|
|
136
|
+
Policies containing `usage.max_uses` or `usage.rate_limit` also require a target-owned policy usage ledger and an operation ledger. `execute_protected_action(...)` atomically reserves the use before invoking the callback. The bundled SQLite implementation is single-node; multi-instance targets must supply a transactional shared-store adapter with equivalent `usage_context` and `reserve_usage` behavior.
|
|
137
|
+
|
|
138
|
+
If the agent can reach another route that commits the same protected consequence without this guard, the deployment fails the A2SPA 2.1 profile.
|
|
139
|
+
|
|
140
|
+
## A2SPA 2.2-2.4 Capability Helpers
|
|
141
|
+
|
|
142
|
+
The Python package also exposes dependency-light helpers for granular policy constraints, evidence packages, signed delegation chains, and HMAC-protected state-integrity records.
|
|
143
|
+
|
|
144
|
+
```python
|
|
145
|
+
from a2spa import build_action_context, evaluate_policy_constraints, policy_constraints_input
|
|
146
|
+
|
|
147
|
+
policy = policy_constraints_input(
|
|
148
|
+
resource="dataset:customers:acme",
|
|
149
|
+
environment="production",
|
|
150
|
+
parameters={"requested_fields": {"subset": ["name", "status"]}},
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
result = evaluate_policy_constraints(
|
|
154
|
+
policy,
|
|
155
|
+
build_action_context(
|
|
156
|
+
resource="dataset:customers:acme",
|
|
157
|
+
environment="production",
|
|
158
|
+
parameters={"requested_fields": ["name"]},
|
|
159
|
+
),
|
|
160
|
+
)
|
|
161
|
+
assert result["allowed"] is True
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
These helpers are local verification/building primitives. Production deployments still need explicit trust-anchor operation, revocation freshness, protected state-integrity keys, and target-side enforcement at every side-effect path.
|
|
@@ -14,9 +14,15 @@ This repository contains the Flask verifier application, dashboard, integration
|
|
|
14
14
|
|
|
15
15
|
A2SPA does not prove target-side execution, commit, or exactly-once effects unless an integration adds target acknowledgement and idempotency semantics.
|
|
16
16
|
|
|
17
|
+
## Hosted Service 2.4
|
|
18
|
+
|
|
19
|
+
The hosted GA contract uses product and Python/npm package version `2.4.2`, protocol `v1.0`, and canonical `/v1` API routes. Existing `/api` runtime routes remain compatibility aliases during the documented migration window. The machine-readable API contract is published at `/A2SPA/openapi.json`.
|
|
20
|
+
|
|
21
|
+
Enterprise/on-prem A2SPA is a separately sold product with its own release process and is not part of the hosted-service release contract.
|
|
22
|
+
|
|
17
23
|
## A2SPA 2.1 Enforcement Profile
|
|
18
24
|
|
|
19
|
-
A2SPA 2.1 is target-side enforcement
|
|
25
|
+
A2SPA 2.1 is a target-side enforcement profile. It does not expand the hosted v1 authorization decision into a guarantee of arbitrary downstream execution.
|
|
20
26
|
|
|
21
27
|
Core invariant: every path to consequence must cross the authorization boundary.
|
|
22
28
|
|
|
@@ -1,41 +1,45 @@
|
|
|
1
|
-
[build-system]
|
|
2
|
-
requires = ["setuptools
|
|
3
|
-
build-backend = "setuptools.build_meta"
|
|
4
|
-
|
|
5
|
-
[project]
|
|
6
|
-
name = "a2spa"
|
|
7
|
-
version = "
|
|
8
|
-
description = "A2SPA payload helper library for AI-agent runtime authorization"
|
|
9
|
-
readme = "sdk/README.md"
|
|
10
|
-
requires-python = ">=3.11"
|
|
11
|
-
license = "LicenseRef-Proprietary"
|
|
12
|
-
authors = [
|
|
13
|
-
{ name = "AI Modularity" },
|
|
14
|
-
]
|
|
15
|
-
keywords = ["a2spa", "ai-agents", "authorization", "payload-helpers", "signed-payloads", "runtime-security"]
|
|
16
|
-
classifiers = [
|
|
17
|
-
"Development Status ::
|
|
18
|
-
"Intended Audience :: Developers",
|
|
19
|
-
"Programming Language :: Python :: 3",
|
|
20
|
-
"Programming Language :: Python :: 3.11",
|
|
21
|
-
"Programming Language :: Python :: 3.12",
|
|
22
|
-
"Topic :: Security",
|
|
23
|
-
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
24
|
-
]
|
|
25
|
-
dependencies = [
|
|
26
|
-
"cryptography==
|
|
27
|
-
]
|
|
28
|
-
|
|
29
|
-
[project.optional-dependencies]
|
|
30
|
-
pq = ["pqcrypto==0.
|
|
31
|
-
|
|
32
|
-
[project.urls]
|
|
33
|
-
Homepage = "https://aimodularity.com/A2SPA"
|
|
34
|
-
Documentation = "https://aimodularity.com/A2SPA/docs"
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools==84.2.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "a2spa"
|
|
7
|
+
version = "2.4.2"
|
|
8
|
+
description = "A2SPA payload helper library for AI-agent runtime authorization"
|
|
9
|
+
readme = "sdk/README.md"
|
|
10
|
+
requires-python = ">=3.11,<3.13"
|
|
11
|
+
license = "LicenseRef-Proprietary"
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "AI Modularity" },
|
|
14
|
+
]
|
|
15
|
+
keywords = ["a2spa", "ai-agents", "authorization", "payload-helpers", "signed-payloads", "runtime-security"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 5 - Production/Stable",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"Programming Language :: Python :: 3",
|
|
20
|
+
"Programming Language :: Python :: 3.11",
|
|
21
|
+
"Programming Language :: Python :: 3.12",
|
|
22
|
+
"Topic :: Security",
|
|
23
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
24
|
+
]
|
|
25
|
+
dependencies = [
|
|
26
|
+
"cryptography==50.0.2",
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
[project.optional-dependencies]
|
|
30
|
+
pq = ["pqcrypto==1.0.0"]
|
|
31
|
+
|
|
32
|
+
[project.urls]
|
|
33
|
+
Homepage = "https://aimodularity.com/A2SPA"
|
|
34
|
+
Documentation = "https://aimodularity.com/A2SPA/docs"
|
|
35
|
+
Source = "https://github.com/gavincapriola/A2SPA"
|
|
36
|
+
Changelog = "https://github.com/gavincapriola/A2SPA/blob/main/CHANGELOG.md"
|
|
37
|
+
Issues = "https://github.com/gavincapriola/A2SPA/issues"
|
|
38
|
+
|
|
39
|
+
[tool.setuptools]
|
|
40
|
+
package-dir = {"" = "sdk"}
|
|
41
|
+
packages = ["a2spa"]
|
|
42
|
+
py-modules = ["a2spa_delegation", "a2spa_evidence", "a2spa_operation_ledger", "a2spa_policy_constraints", "a2spa_policy_usage_ledger", "a2spa_receipt_verifier", "a2spa_state_integrity"]
|
|
43
|
+
|
|
44
|
+
[tool.setuptools.package-data]
|
|
45
|
+
a2spa = ["py.typed"]
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# A2SPA Python Payload Helpers
|
|
2
|
+
|
|
3
|
+
Helper-only Python package for building, hashing, and signing A2SPA runtime authorization payloads.
|
|
4
|
+
|
|
5
|
+
The verifier remains server-side. This package does not authorize actions by itself.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install a2spa
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
For ML-DSA signing support where the optional wheel is available:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pip install "a2spa[pq]"
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Basic Usage
|
|
20
|
+
|
|
21
|
+
```python
|
|
22
|
+
from pathlib import Path
|
|
23
|
+
|
|
24
|
+
from a2spa import build_payload_fields, build_signed_request, policy_input
|
|
25
|
+
|
|
26
|
+
private_key_text = Path("sender.priv.pem").read_text(encoding="utf-8")
|
|
27
|
+
|
|
28
|
+
payload = build_payload_fields(
|
|
29
|
+
agent_id="user-123_sender",
|
|
30
|
+
target_agent_id="user-123_receiver",
|
|
31
|
+
input_data=policy_input(action="deliver", workflow_scope="messages:deliver"),
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
request_body = build_signed_request(private_key_text, payload)
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Send `request_body` to `POST /v1/verify_payload` with your account API key in the `x-api-key` header. The previous `/api/verify_payload` path remains a deprecated compatibility alias.
|
|
38
|
+
|
|
39
|
+
See the [A2SPA 2.4 migration guide](https://aimodularity.com/A2SPA/docs#api-versioning) for route compatibility and `docs/a2spa-2.4-migration.md` in the server source repository for detailed retry and rollback guidance.
|
|
40
|
+
|
|
41
|
+
## Helper Functions
|
|
42
|
+
|
|
43
|
+
- `build_payload_fields(...)`
|
|
44
|
+
- `policy_input(...)`
|
|
45
|
+
- `policy_template(...)`
|
|
46
|
+
- `state_continuity_claim(...)`
|
|
47
|
+
- `canonicalize_payload(...)`
|
|
48
|
+
- `compute_payload_hash(...)`
|
|
49
|
+
- `finalize_payload(...)`
|
|
50
|
+
- `sign_payload(...)`
|
|
51
|
+
- `build_signed_request(...)`
|
|
52
|
+
- `is_authorized_result(...)`
|
|
53
|
+
- `require_authorized_result(...)`
|
|
54
|
+
- `verify_execution_receipt(...)`
|
|
55
|
+
- `enforce_target_authorization(...)`
|
|
56
|
+
- `build_target_acknowledgement(...)`
|
|
57
|
+
- `execute_protected_action(...)`
|
|
58
|
+
- `InMemoryTargetOperationLedger(...)`
|
|
59
|
+
- `SQLiteTargetOperationLedger(...)`
|
|
60
|
+
- `InMemoryPolicyUsageLedger(...)`
|
|
61
|
+
- `SQLitePolicyUsageLedger(...)`
|
|
62
|
+
- `policy_constraints_input(...)`
|
|
63
|
+
- `evaluate_policy_constraints(...)`
|
|
64
|
+
- `build_authorization_evidence_package(...)`
|
|
65
|
+
- `normalize_agent_lifecycle(...)`
|
|
66
|
+
- `agent_is_active(...)`
|
|
67
|
+
- `sign_delegation_grant(...)`
|
|
68
|
+
- `validate_delegation_chain(...)`
|
|
69
|
+
- `build_consumption_state_record(...)`
|
|
70
|
+
- `verify_consumption_state_record(...)`
|
|
71
|
+
- `build_debug_snapshot(...)`
|
|
72
|
+
|
|
73
|
+
## Signed Bytes
|
|
74
|
+
|
|
75
|
+
Current helper compatibility signs the UTF-8 bytes of `json.dumps(signable_payload, sort_keys=True)` using the normalized signable fields. Do not reimplement canonicalization unless your bytes match `canonicalize_payload(...)` exactly.
|
|
76
|
+
|
|
77
|
+
## Security Boundary
|
|
78
|
+
|
|
79
|
+
Private keys must stay in a secret manager, server environment, or deployment secret. Do not paste private keys into chats, logs, client-side code, or source control.
|
|
80
|
+
|
|
81
|
+
## A2SPA 2.1 Target Enforcement
|
|
82
|
+
|
|
83
|
+
A2SPA 2.1 adds a deployment profile for protected targets. The target, trusted gateway, service, or executor should fail closed unless the A2SPA authorization result is valid for the exact operation being committed.
|
|
84
|
+
|
|
85
|
+
```python
|
|
86
|
+
from a2spa import SQLiteTargetOperationLedger, execute_protected_action
|
|
87
|
+
|
|
88
|
+
operation_id = message["idempotency_key"]
|
|
89
|
+
operation_ledger = SQLiteTargetOperationLedger("target-operations.sqlite3")
|
|
90
|
+
execution = execute_protected_action(
|
|
91
|
+
result,
|
|
92
|
+
lambda authorization: {
|
|
93
|
+
"provider_message_id": email_provider.send(message).id,
|
|
94
|
+
},
|
|
95
|
+
target_id="smtp-gateway",
|
|
96
|
+
operation_id=operation_id,
|
|
97
|
+
target_private_key_pem=target_ack_private_key,
|
|
98
|
+
target_agent_id="user-123_email-target",
|
|
99
|
+
action="send_email",
|
|
100
|
+
workflow_scope="email:send",
|
|
101
|
+
trusted_receipt_public_key_pem=trusted_a2spa_receipt_public_key,
|
|
102
|
+
operation_ledger=operation_ledger,
|
|
103
|
+
require_target_idempotency=True,
|
|
104
|
+
)
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
`SQLiteTargetOperationLedger` is a durable single-node implementation. Multi-instance targets should supply a transactional shared-store adapter with the same `begin_operation`, `commit_operation`, `cancel_operation`, and `fail_operation` contract. In-progress or indeterminate operations fail closed; an exact committed retry returns the stored execution without invoking the operation again.
|
|
108
|
+
|
|
109
|
+
Policies containing `usage.max_uses` or `usage.rate_limit` also require a target-owned policy usage ledger and an operation ledger. `execute_protected_action(...)` atomically reserves the use before invoking the callback. The bundled SQLite implementation is single-node; multi-instance targets must supply a transactional shared-store adapter with equivalent `usage_context` and `reserve_usage` behavior.
|
|
110
|
+
|
|
111
|
+
If the agent can reach another route that commits the same protected consequence without this guard, the deployment fails the A2SPA 2.1 profile.
|
|
112
|
+
|
|
113
|
+
## A2SPA 2.2-2.4 Capability Helpers
|
|
114
|
+
|
|
115
|
+
The Python package also exposes dependency-light helpers for granular policy constraints, evidence packages, signed delegation chains, and HMAC-protected state-integrity records.
|
|
116
|
+
|
|
117
|
+
```python
|
|
118
|
+
from a2spa import build_action_context, evaluate_policy_constraints, policy_constraints_input
|
|
119
|
+
|
|
120
|
+
policy = policy_constraints_input(
|
|
121
|
+
resource="dataset:customers:acme",
|
|
122
|
+
environment="production",
|
|
123
|
+
parameters={"requested_fields": {"subset": ["name", "status"]}},
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
result = evaluate_policy_constraints(
|
|
127
|
+
policy,
|
|
128
|
+
build_action_context(
|
|
129
|
+
resource="dataset:customers:acme",
|
|
130
|
+
environment="production",
|
|
131
|
+
parameters={"requested_fields": ["name"]},
|
|
132
|
+
),
|
|
133
|
+
)
|
|
134
|
+
assert result["allowed"] is True
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
These helpers are local verification/building primitives. Production deployments still need explicit trust-anchor operation, revocation freshness, protected state-integrity keys, and target-side enforcement at every side-effect path.
|