feat: add draft data, gap analysis report, and workspace config
Some checks failed
CI / test (3.11) (push) Failing after 1m37s
CI / test (3.12) (push) Failing after 57s

This commit is contained in:
2026-04-06 18:47:15 +02:00
parent 4f310407b0
commit 2506b6325a
189 changed files with 62649 additions and 0 deletions

View File

@@ -0,0 +1,312 @@
# Master Prompt: ACT Reference Implementation
## Context
You are implementing the reference implementation for the Agent Compact
Token (ACT), as defined in `draft-nennemann-act-00`. The full draft is
attached or provided in context. Your implementation must be a clean,
well-documented Python package that serves as the normative reference
for the specification — meaning it is the ground truth for
interoperability testing.
The ACS (Agent Compliance Seal) reference implementation (~1,900 lines,
Python) exists as a prior art reference for code style and structure.
ACT follows the same philosophy: minimal dependencies, sub-millisecond
performance for the hot path, Ed25519 as the primary algorithm.
---
## Deliverables
Produce the following files in a single `act/` package directory:
```
act/
├── __init__.py # Public API exports
├── token.py # ACTMandate and ACTRecord dataclasses + serialization
├── crypto.py # Key management: Tier 1 (pre-shared), Tier 2 (PKI),
│ # Tier 3 (DID:key, DID:web); sign/verify primitives
├── lifecycle.py # Phase 1 → Phase 2 transition logic (re-signing)
├── delegation.py # Delegation chain construction and verification
├── dag.py # DAG validation (uniqueness, parent existence,
│ # temporal ordering, acyclicity, capability
│ # consistency)
├── ledger.py # In-memory append-only audit ledger (for testing;
│ # interface suitable for external backends)
├── verify.py # Unified verification entry point (Phase 1 + Phase 2)
├── errors.py # All ACT-specific exception types
└── vectors.py # Generates and validates all Appendix B test vectors
tests/
├── test_token.py
├── test_crypto.py
├── test_lifecycle.py
├── test_delegation.py
├── test_dag.py
├── test_ledger.py
├── test_verify.py
└── test_vectors.py # Must pass all vectors defined in vectors.py
```
---
## Specification Summary
### Token Structure
An ACT is a JWT (JWS Compact Serialization). It has two phases:
**Phase 1 — Authorization Mandate** (signed by issuing agent):
JOSE Header:
```json
{
"alg": "EdDSA", // Ed25519; also support ES256
"typ": "act+jwt",
"kid": "<key-id>"
// optional: "x5c" (Tier 2), "did" (Tier 3)
}
```
Required JWT claims:
- `iss` — issuer agent identifier (opaque string / X.509 DN / DID)
- `sub` — target agent identifier (same format as iss)
- `aud` — intended recipient(s); string or array
- `iat` — issuance time (NumericDate)
- `exp` — expiration time (NumericDate); SHOULD be iat + ≤900s for automated flows
- `jti` — UUID v4; doubles as task identifier for DAG par references
Optional:
- `wid` — workflow UUID grouping related ACTs
Required ACT-specific claims:
- `task` — object: { purpose (str, REQUIRED), data_sensitivity (str, OPTIONAL),
created_by (str, OPTIONAL), expires_at (NumericDate, OPTIONAL) }
- `cap` — array of { action (str, REQUIRED), constraints (object, OPTIONAL) }
action names conform to ABNF: component *("." component)
component = ALPHA *(ALPHA / DIGIT / "-" / "_")
- `del` — object: { depth (int), max_depth (int), chain (array) }
chain entries: { delegator (str), jti (str), sig (base64url str) }
chain is ordered root → immediate parent (chain[0] = root authority)
If `del` is absent: treat as root mandate, depth=0, delegation forbidden
Optional:
- `oversight` — { requires_approval_for (array of action strings),
approval_ref (str, OPTIONAL) }
**Phase 2 — Execution Record** (re-signed by executing agent, i.e. `sub`):
All Phase 1 claims are preserved unchanged. Additional required claims:
- `exec_act` — string; MUST match one of the cap[].action values
- `par` — array of jti strings (parent task IDs in DAG); [] for root tasks
- `exec_ts` — NumericDate; actual execution time; MUST be >= iat; SHOULD be <= exp
(if exec_ts > exp: log warning, do NOT reject)
- `status` — one of: "completed", "failed", "partial"
Additional optional claims:
- `inp_hash` — base64url(SHA-256(raw input bytes)), no padding
- `out_hash` — base64url(SHA-256(raw output bytes)), no padding
- `err` — { code (str), detail (str) }; present when status != "completed"
**Critical**: In Phase 2, the JOSE header `kid` MUST reference the `sub`
agent's key (not the `iss` agent's key). The re-signature is produced by
the executing agent over the complete Phase 2 payload (all Phase 1 claims
+ execution claims combined).
---
### Trust Tiers
**Tier 1 — Pre-Shared Keys (mandatory-to-implement)**
- Keys: Ed25519 (primary) or P-256
- `kid`: opaque string agreed out-of-band
- Key registry: a dict mapping kid → public key bytes, configured at init time
- No external resolution needed
**Tier 2 — PKI / X.509**
- `kid`: SHA-256 thumbprint of DER-encoded certificate
- `x5c` JOSE header MAY carry the certificate chain
- Verification: standard X.509 chain validation against trusted CA store
**Tier 3 — DID**
- Support `did:key` (self-contained, no resolution needed)
- Support `did:web` (requires HTTP resolution; cache with configurable TTL)
- `kid`: DID key fragment (e.g. `did:key:z6Mk...#key-1`)
- `did` JOSE header MAY carry the full DID for resolution
---
### Delegation Chain
When issuing a delegated ACT (Agent A → Agent B):
1. `del.depth` = parent ACT's `del.depth` + 1
2. `del.max_depth` ≤ parent ACT's `del.max_depth`
3. `cap` must be a subset of parent ACT's `cap` with constraints at least
as restrictive
4. Each chain entry `sig` = Sign(A.private_key, SHA-256(parent_act_compact_bytes))
where `parent_act_compact_bytes` is the raw bytes of the parent ACT's
JWS Compact Serialization (UTF-8 encoded)
Verification of chain entry:
- Retrieve public key for entry.delegator
- Recompute SHA-256(parent_act_compact_bytes)
- Verify entry.sig against that hash using entry.delegator's public key
Rejection conditions:
- `del.depth` > `del.max_depth`
- `del.chain` length != `del.depth`
- Any chain entry sig fails verification
- `cap` contains actions not in parent ACT's `cap`
- Any constraint in `cap` is less restrictive than in parent ACT
---
### DAG Validation (Phase 2)
The ACT ledger (or set of received parent ACTs) is the ECT store.
Required checks on receiving a Phase 2 ACT:
1. `jti` uniqueness within `wid` scope (or globally if `wid` absent)
2. Every `jti` in `par` exists in the ledger/store as a verified Phase 2 ACT
3. For each parent: `parent.exec_ts < child.exec_ts + 30s` (clock skew tolerance)
4. No cycle: following `par` references must not return to current `jti`
— enforce max traversal limit of 10,000 nodes
5. `exec_act` matches one of the `cap[].action` values in the Phase 1 claims
---
### Verification Procedure
**Phase 1 verification** (ACTVerifier.verify_mandate):
1. Parse JWS Compact Serialization
2. Check `typ` == "act+jwt"
3. Check `alg` in allowlist (must include EdDSA/Ed25519, ES256; MUST NOT include
"none" or any HS* algorithm)
4. Resolve public key for `kid` per trust tier
5. Verify JWS signature
6. Check `exp` not passed (clock skew tolerance: ≤300s)
7. Check `iat` not unreasonably future (≤30s ahead)
8. Check `aud` contains verifier's own identifier
9. Check `iss` is trusted per local policy
10. Check `sub` matches verifier's own identifier (when verifier is the target)
11. Check all required claims present and well-formed
12. If `del.chain` non-empty: verify delegation chain
**Phase 2 verification** (ACTVerifier.verify_record):
All Phase 1 steps, plus:
13. Check `exec_act` present and matches a `cap[].action`
14. Check `par` present; perform DAG validation
15. Check `exec_ts` present and >= `iat`; if > `exp` log warning but do NOT reject
16. Check `status` present and valid
17. Check re-signature was produced by `sub` agent's key (kid in Phase 2
header must correspond to sub's public key, not iss's key)
18. Optionally verify `inp_hash`/`out_hash` against provided data
---
### Audit Ledger Interface
`ACTLedger` (in-memory reference implementation):
- `append(act_record: ACTRecord) -> int` — returns sequence number
- `get(jti: str) -> ACTRecord | None`
- `list(wid: str | None) -> list[ACTRecord]`
- `verify_integrity() -> bool` — verifies no records have been tampered with
(hash-chain over sequence-ordered records)
The ledger must enforce append-only semantics: once appended, a record
cannot be modified or deleted. Raise `ACTLedgerImmutabilityError` on
any attempt.
---
### Error Types
Define in `errors.py`:
```python
ACTError # base
ACTValidationError # malformed token structure
ACTSignatureError # signature verification failed
ACTExpiredError # token expired
ACTAudienceMismatchError # aud does not contain verifier identity
ACTCapabilityError # no matching capability / capability escalation
ACTDelegationError # delegation chain invalid
ACTDAGError # DAG validation failed (cycle, missing parent, etc.)
ACTPhaseError # wrong phase for operation (e.g. mandate used as record)
ACTKeyResolutionError # cannot resolve kid to public key
ACTLedgerImmutabilityError # attempt to modify ledger
ACTPrivilegeEscalationError # delegated cap exceeds parent cap
```
---
### Test Vectors (Appendix B)
`vectors.py` must generate and validate all of the following. Each vector
must include: description, input parameters, expected output (encoded token
or expected exception class).
**Valid vectors:**
- B.1: Phase 1 ACT — root mandate, Tier 1 (Ed25519 pre-shared key), no delegation
- B.2: Phase 2 ACT — completed execution, transition from B.1 mandate
- B.3: Phase 2 ACT — fan-in, two parent jti values from parallel branches
- B.4: Phase 1 ACT — delegated mandate (depth=1), chain entry with sig
- B.5: Phase 2 ACT — delegated execution record
**Invalid vectors (must raise specified exception):**
- B.6: `del.depth` > `del.max_depth` → ACTDelegationError
- B.7: `cap` escalation in delegated ACT → ACTPrivilegeEscalationError
- B.8: `exec_act` not in `cap` → ACTCapabilityError
- B.9: DAG cycle (par references own jti) → ACTDAGError
- B.10: Missing parent jti in DAG → ACTDAGError
- B.11: Tampered payload (bit flip in claims) → ACTSignatureError
- B.12: Expired token → ACTExpiredError
- B.13: Wrong audience → ACTAudienceMismatchError
- B.14: Phase 2 re-signed by iss key instead of sub → ACTSignatureError
- B.15: Algorithm "none" → ACTValidationError
---
## Implementation Constraints
**Dependencies**: use only the Python standard library plus:
- `cryptography` (for Ed25519, P-256, X.509)
- `pyjwt` OR manual JWS implementation (prefer manual for spec fidelity)
- `pytest` (test runner only)
**Performance target**: Phase 1 creation ≤ 500µs mean on modern hardware.
Benchmark in a `bench/` directory.
**Code style**:
- Type-annotated throughout (Python 3.11+)
- Dataclasses for token structures
- No global mutable state
- All public API functions documented with docstrings referencing the
relevant draft section (e.g. `# ACT §8.1`)
**Security constraints**:
- MUST NOT use symmetric algorithms (HS256 etc.) anywhere
- MUST NOT implement "alg: none" path
- Ed25519 signing MUST use bound key-pair APIs (private key object that
carries the public key) — never pass raw private key bytes
- All secret key material must be zeroed on deletion where the
cryptography library supports it
**What NOT to implement**:
- DID:web resolution with live HTTP calls in the reference implementation
(stub it with a configurable resolver callback instead)
- Token revocation infrastructure
- Persistence (ledger is in-memory only)
---
## Output Format
Produce each file completely, in order. After all files, produce a
`README.md` for the `act/` package that includes:
- Installation instructions
- Quick-start example (Phase 1 mandate → Phase 2 record → verify)
- Running the test suite
- Running the test vectors
- Performance benchmark instructions
At the end, confirm: "All Appendix B test vectors pass."