Metadata-Version: 2.4
Name: a2spa
Version: 0.1.4
Summary: A2SPA payload helper library for AI-agent runtime authorization
Author: AI Modularity
License-Expression: LicenseRef-Proprietary
Project-URL: Homepage, https://aimodularity.com/A2SPA
Project-URL: Documentation, https://aimodularity.com/A2SPA/docs
Keywords: a2spa,ai-agents,authorization,payload-helpers,signed-payloads,runtime-security
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Security
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: cryptography==45.0.5
Provides-Extra: pq
Requires-Dist: pqcrypto==0.4.0; extra == "pq"
Dynamic: license-file

# A2SPA Python Payload Helpers

Helper-only Python package for building, hashing, and signing A2SPA runtime authorization payloads.

The verifier remains server-side. This package does not authorize actions by itself.

## Install

```bash
pip install a2spa
```

For ML-DSA signing support where the optional wheel is available:

```bash
pip install "a2spa[pq]"
```

## Basic Usage

```python
from pathlib import Path

from a2spa import build_payload_fields, build_signed_request, policy_input

private_key_text = Path("sender.priv.pem").read_text(encoding="utf-8")

payload = build_payload_fields(
    agent_id="user-123_sender",
    target_agent_id="user-123_receiver",
    input_data=policy_input(action="deliver", workflow_scope="messages:deliver"),
)

request_body = build_signed_request(private_key_text, payload)
```

Send `request_body` to `POST /api/verify_payload` with your account API key in the `x-api-key` header.

## Helper Functions

- `build_payload_fields(...)`
- `policy_input(...)`
- `policy_template(...)`
- `state_continuity_claim(...)`
- `canonicalize_payload(...)`
- `compute_payload_hash(...)`
- `finalize_payload(...)`
- `sign_payload(...)`
- `build_signed_request(...)`
- `is_authorized_result(...)`
- `require_authorized_result(...)`
- `verify_execution_receipt(...)`
- `enforce_target_authorization(...)`
- `build_target_acknowledgement(...)`
- `execute_protected_action(...)`
- `build_debug_snapshot(...)`

## Signed Bytes

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.

## Security Boundary

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.

## A2SPA 2.1 Target Enforcement

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.

```python
from a2spa import build_target_acknowledgement, enforce_target_authorization

authorization = enforce_target_authorization(
    result,
    target_agent_id="user-123_email-target",
    action="send_email",
    workflow_scope="email:send",
    trusted_receipt_public_key_pem=trusted_a2spa_receipt_public_key,
)

# Commit the protected side effect only after enforce_target_authorization returns.
provider_result = email_provider.send(message)

target_ack = build_target_acknowledgement(
    authorization,
    target_id="smtp-gateway",
    operation_id=message["idempotency_key"],
    result={"provider_message_id": provider_result.id},
)
```

If the agent can reach another route that commits the same protected consequence without this guard, the deployment fails the A2SPA 2.1 profile.
