agent-manifest 0.1.0__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.
- agent_manifest-0.1.0/PKG-INFO +196 -0
- agent_manifest-0.1.0/README.md +142 -0
- agent_manifest-0.1.0/pyproject.toml +89 -0
- agent_manifest-0.1.0/src/agent_manifest/__init__.py +47 -0
- agent_manifest-0.1.0/src/agent_manifest/_auto_provider.py +85 -0
- agent_manifest-0.1.0/src/agent_manifest/_canonicalize.py +160 -0
- agent_manifest-0.1.0/src/agent_manifest/_delegation.py +291 -0
- agent_manifest-0.1.0/src/agent_manifest/_hw_providers.py +336 -0
- agent_manifest-0.1.0/src/agent_manifest/_merkle.py +329 -0
- agent_manifest-0.1.0/src/agent_manifest/_providers.py +234 -0
- agent_manifest-0.1.0/src/agent_manifest/_revocation.py +252 -0
- agent_manifest-0.1.0/src/agent_manifest/_signing.py +446 -0
- agent_manifest-0.1.0/src/agent_manifest/_transparency.py +191 -0
- agent_manifest-0.1.0/src/agent_manifest/_types.py +95 -0
- agent_manifest-0.1.0/src/agent_manifest/_verify.py +680 -0
- agent_manifest-0.1.0/src/agent_manifest/cli.py +339 -0
- agent_manifest-0.1.0/src/agent_manifest/models.py +720 -0
- agent_manifest-0.1.0/tests/__init__.py +0 -0
- agent_manifest-0.1.0/tests/test_am_attest.py +238 -0
- agent_manifest-0.1.0/tests/test_am_bind.py +479 -0
- agent_manifest-0.1.0/tests/test_am_compat.py +354 -0
- agent_manifest-0.1.0/tests/test_am_crypto.py +268 -0
- agent_manifest-0.1.0/tests/test_am_verify.py +433 -0
- agent_manifest-0.1.0/tests/test_canonicalize.py +235 -0
- agent_manifest-0.1.0/tests/test_delegation_hitl.py +282 -0
- agent_manifest-0.1.0/tests/test_examples.py +112 -0
- agent_manifest-0.1.0/tests/test_hw_providers.py +496 -0
- agent_manifest-0.1.0/tests/test_merkle.py +260 -0
- agent_manifest-0.1.0/tests/test_poisoning_scan.py +171 -0
- agent_manifest-0.1.0/tests/test_providers.py +173 -0
- agent_manifest-0.1.0/tests/test_revocation.py +307 -0
- agent_manifest-0.1.0/tests/test_signing.py +525 -0
- agent_manifest-0.1.0/tests/test_transparency.py +404 -0
- agent_manifest-0.1.0/tests/test_verify.py +412 -0
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: agent-manifest
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Agent Manifest SDK — cryptographically anchor all 10 artifacts defining an AI agent at deployment
|
|
5
|
+
Project-URL: Homepage, https://github.com/agentrust-io/agent-manifest
|
|
6
|
+
Project-URL: Repository, https://github.com/agentrust-io/agent-manifest
|
|
7
|
+
Project-URL: Documentation, https://github.com/agentrust-io/agent-manifest/tree/main/spec
|
|
8
|
+
Project-URL: Bug Tracker, https://github.com/agentrust-io/agent-manifest/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/agentrust-io/agent-manifest/releases
|
|
10
|
+
Author-email: Imran Siddique <maintainers@agentrust.io>
|
|
11
|
+
License: Apache-2.0
|
|
12
|
+
Keywords: agent-manifest,ai-agents,attestation,confidential-computing,governance,hardware-attestation,mcp,pydantic,tee,trust
|
|
13
|
+
Classifier: Development Status :: 3 - Alpha
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Security :: Cryptography
|
|
21
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
22
|
+
Classifier: Topic :: System :: Monitoring
|
|
23
|
+
Classifier: Typing :: Typed
|
|
24
|
+
Requires-Python: >=3.11
|
|
25
|
+
Requires-Dist: cryptography<50,>=42
|
|
26
|
+
Requires-Dist: pydantic<3,>=2.7
|
|
27
|
+
Provides-Extra: all
|
|
28
|
+
Requires-Dist: click>=8.1; extra == 'all'
|
|
29
|
+
Requires-Dist: fastapi>=0.111; extra == 'all'
|
|
30
|
+
Requires-Dist: httpx>=0.27; extra == 'all'
|
|
31
|
+
Requires-Dist: pyoqs>=0.10; extra == 'all'
|
|
32
|
+
Requires-Dist: uvicorn[standard]>=0.29; extra == 'all'
|
|
33
|
+
Provides-Extra: cli
|
|
34
|
+
Requires-Dist: click>=8.1; extra == 'cli'
|
|
35
|
+
Provides-Extra: dev
|
|
36
|
+
Requires-Dist: bandit[toml]>=1.7; extra == 'dev'
|
|
37
|
+
Requires-Dist: click>=8.1; extra == 'dev'
|
|
38
|
+
Requires-Dist: fastapi>=0.111; extra == 'dev'
|
|
39
|
+
Requires-Dist: httpx>=0.27; extra == 'dev'
|
|
40
|
+
Requires-Dist: jcs>=0.2; extra == 'dev'
|
|
41
|
+
Requires-Dist: mypy>=1.10; extra == 'dev'
|
|
42
|
+
Requires-Dist: pip-audit>=2.7; extra == 'dev'
|
|
43
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
44
|
+
Requires-Dist: pytest-cov>=5; extra == 'dev'
|
|
45
|
+
Requires-Dist: pytest>=8; extra == 'dev'
|
|
46
|
+
Requires-Dist: uvicorn[standard]>=0.29; extra == 'dev'
|
|
47
|
+
Provides-Extra: pq
|
|
48
|
+
Requires-Dist: pyoqs>=0.10; extra == 'pq'
|
|
49
|
+
Provides-Extra: server
|
|
50
|
+
Requires-Dist: fastapi>=0.111; extra == 'server'
|
|
51
|
+
Requires-Dist: httpx>=0.27; extra == 'server'
|
|
52
|
+
Requires-Dist: uvicorn[standard]>=0.29; extra == 'server'
|
|
53
|
+
Description-Content-Type: text/markdown
|
|
54
|
+
|
|
55
|
+
# agent-manifest
|
|
56
|
+
|
|
57
|
+
**Cryptographically anchor all 10 artifacts defining an AI agent at deployment.**
|
|
58
|
+
|
|
59
|
+
The Agent Manifest SDK implements the Agent Manifest Specification v0.1 - a hardware-attestable document that binds every artifact defining an agent's behavior (system prompt, policy bundle, tool schemas, model identity, RAG corpus, memory state, audit chain, delegation chain, supply chain, and human approvals) into a single tamper-evident identity primitive.
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
pip install agent-manifest
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Why
|
|
66
|
+
|
|
67
|
+
A signed JWT proves who called an API. An Agent Manifest proves who the agent **was**, what it was **allowed to do**, how it was **built**, what it **decided**, who **approved** it, and whether any of that changed between approval and execution.
|
|
68
|
+
|
|
69
|
+
```python
|
|
70
|
+
from agent_manifest import (
|
|
71
|
+
Manifest, ArtifactBindings,
|
|
72
|
+
SystemPromptBinding, PolicyBundleBinding, ModelIdentityBinding,
|
|
73
|
+
CryptoProfile, DeploymentType, EnforcementMode, PolicyLanguage,
|
|
74
|
+
generate_ed25519, Ed25519Signer,
|
|
75
|
+
)
|
|
76
|
+
from agent_manifest._types import HashValue, ManifestId
|
|
77
|
+
from datetime import datetime, timedelta, timezone
|
|
78
|
+
|
|
79
|
+
now = datetime.now(timezone.utc)
|
|
80
|
+
|
|
81
|
+
manifest = Manifest(
|
|
82
|
+
manifest_id=ManifestId("018f4a3b-2c1d-7e5f-a8b9-0d1e2f3a4b5c"),
|
|
83
|
+
agent_id="spiffe://trust.example/agent/kyc/prod",
|
|
84
|
+
issued_at=now,
|
|
85
|
+
expires_at=now + timedelta(days=90),
|
|
86
|
+
issuer="spiffe://trust.example/signing-authority",
|
|
87
|
+
crypto_profile=CryptoProfile.standard,
|
|
88
|
+
artifacts=ArtifactBindings(
|
|
89
|
+
system_prompt=SystemPromptBinding(
|
|
90
|
+
hash=HashValue("sha256:" + "a" * 64),
|
|
91
|
+
bound_at=now,
|
|
92
|
+
),
|
|
93
|
+
policy_bundle=PolicyBundleBinding(
|
|
94
|
+
hash=HashValue("sha256:" + "b" * 64),
|
|
95
|
+
policy_language=PolicyLanguage.cedar,
|
|
96
|
+
version="1.0.0",
|
|
97
|
+
enforcement_mode=EnforcementMode.enforce,
|
|
98
|
+
bound_at=now,
|
|
99
|
+
),
|
|
100
|
+
model_identity=ModelIdentityBinding(
|
|
101
|
+
provider="anthropic",
|
|
102
|
+
model_id="claude-sonnet-4-6",
|
|
103
|
+
version="20251001",
|
|
104
|
+
deployment_type=DeploymentType.api,
|
|
105
|
+
bound_at=now,
|
|
106
|
+
),
|
|
107
|
+
),
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
keypair = generate_ed25519()
|
|
111
|
+
signer = Ed25519Signer(keypair)
|
|
112
|
+
sig_block = signer.sign(manifest.model_dump(mode="json", by_alias=True))
|
|
113
|
+
print(sig_block["algorithm"]) # Ed25519
|
|
114
|
+
print(sig_block["key_id"]) # sha256:<hex>
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## The 10 Attested Artifacts
|
|
118
|
+
|
|
119
|
+
| # | Artifact | What it proves |
|
|
120
|
+
|---|----------|---------------|
|
|
121
|
+
| 1 | System Prompt | The exact prompt that defines the agent's persona and safety constraints |
|
|
122
|
+
| 2 | Policy Bundle | The Cedar/Rego/YAML governance rules that were in force |
|
|
123
|
+
| 3 | Tool Manifest | Every tool schema and description the agent was authorized to call |
|
|
124
|
+
| 4 | Model Identity | Which model and version ran (binary hash for local, version for API) |
|
|
125
|
+
| 5 | RAG Corpus | The knowledge base the agent was grounded on (Merkle root) |
|
|
126
|
+
| 6 | Memory Baseline | Approved agent memory state with TTL-based re-approval |
|
|
127
|
+
| 7 | Decision Trace | Hardware-signed audit chain root for all agent decisions |
|
|
128
|
+
| 8 | A2A Delegation | Signed delegation chain from human principal to current agent |
|
|
129
|
+
| 9 | Supply Chain | Container digest, SLSA provenance, SBOM, MCP server supply chain |
|
|
130
|
+
| 10 | HITL Approvals | Hardware-signed human oversight records (EU AI Act Art. 14) |
|
|
131
|
+
|
|
132
|
+
## Hardware Attestation
|
|
133
|
+
|
|
134
|
+
```python
|
|
135
|
+
from agent_manifest._auto_provider import select_provider
|
|
136
|
+
|
|
137
|
+
# auto-selects: SEV-SNP → TDX → TPM → software (OPAQUE is explicit opt-in via OPAQUE_ATTESTATION_URL)
|
|
138
|
+
provider = select_provider(level=1) # Level 1+ requires hardware
|
|
139
|
+
provider.extend_manifest_hash(manifest_dict)
|
|
140
|
+
report = provider.get_attestation_report()
|
|
141
|
+
# report.platform: "amd-sev-snp" | "intel-tdx" | "tpm" | "opaque" | "software"
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
| Provider | Hardware | Level | Install |
|
|
145
|
+
|----------|----------|-------|---------|
|
|
146
|
+
| `TPMProvider` | TPM 2.0 / AWS Nitro | 1 | `apt install tpm2-tools` |
|
|
147
|
+
| `SEVSNPProvider` | AMD SEV-SNP | 2 | Needs `/dev/sev-guest` |
|
|
148
|
+
| `TDXProvider` | Intel TDX | 2 | Needs `/dev/tdx-guest` |
|
|
149
|
+
| `OPAQUEProvider` | Opaque Runtime | 3 | Set `OPAQUE_ATTESTATION_URL` |
|
|
150
|
+
|
|
151
|
+
## Verification
|
|
152
|
+
|
|
153
|
+
```python
|
|
154
|
+
from agent_manifest._verify import verify_manifest, VerificationContext, RevocationStore
|
|
155
|
+
|
|
156
|
+
result = verify_manifest(
|
|
157
|
+
manifest_dict,
|
|
158
|
+
VerificationContext(
|
|
159
|
+
system_prompt_hash="sha256:...",
|
|
160
|
+
policy_bundle_hash="sha256:...",
|
|
161
|
+
enforce_hitl=True,
|
|
162
|
+
),
|
|
163
|
+
RevocationStore(),
|
|
164
|
+
)
|
|
165
|
+
print(result.result) # VALID | MISMATCH | EXPIRED | REVOKED | ...
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## CLI
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
pip install "agent-manifest[cli]"
|
|
172
|
+
|
|
173
|
+
manifest keygen -d ./keys/
|
|
174
|
+
manifest create config.json -o draft.json
|
|
175
|
+
manifest sign draft.json --key keys/private.hex -o signed.json
|
|
176
|
+
manifest attest signed.json --provider auto --level 1 -o attested.json
|
|
177
|
+
manifest verify attested.json
|
|
178
|
+
manifest revoke <manifest-id> --reason "key compromise" --revoked-by security@example.com
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Cryptography
|
|
182
|
+
|
|
183
|
+
- **Standard profile**: Ed25519 (RFC 8032), SHA-256, RFC 8785 canonical JSON
|
|
184
|
+
- **Post-quantum profile**: ML-DSA-65 (NIST FIPS 204), SHAKE-256 - `pip install "agent-manifest[pq]"`
|
|
185
|
+
- **Hybrid**: Both signatures required, identical pre-image
|
|
186
|
+
- **Transparency**: Rekor/Sigstore integration for non-repudiation
|
|
187
|
+
|
|
188
|
+
## Specification
|
|
189
|
+
|
|
190
|
+
The full Agent Manifest Specification v0.1 is at [`spec/agent-manifest-spec-v0.1.md`](https://github.com/agentrust-io/agent-manifest/blob/main/spec/agent-manifest-spec-v0.1.md).
|
|
191
|
+
|
|
192
|
+
Being submitted to the [Agentic AI Foundation (AAIF)](https://agenticai.foundation) under the Linux Foundation alongside AGT.
|
|
193
|
+
|
|
194
|
+
## License
|
|
195
|
+
|
|
196
|
+
Apache 2.0
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# agent-manifest
|
|
2
|
+
|
|
3
|
+
**Cryptographically anchor all 10 artifacts defining an AI agent at deployment.**
|
|
4
|
+
|
|
5
|
+
The Agent Manifest SDK implements the Agent Manifest Specification v0.1 - a hardware-attestable document that binds every artifact defining an agent's behavior (system prompt, policy bundle, tool schemas, model identity, RAG corpus, memory state, audit chain, delegation chain, supply chain, and human approvals) into a single tamper-evident identity primitive.
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
pip install agent-manifest
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Why
|
|
12
|
+
|
|
13
|
+
A signed JWT proves who called an API. An Agent Manifest proves who the agent **was**, what it was **allowed to do**, how it was **built**, what it **decided**, who **approved** it, and whether any of that changed between approval and execution.
|
|
14
|
+
|
|
15
|
+
```python
|
|
16
|
+
from agent_manifest import (
|
|
17
|
+
Manifest, ArtifactBindings,
|
|
18
|
+
SystemPromptBinding, PolicyBundleBinding, ModelIdentityBinding,
|
|
19
|
+
CryptoProfile, DeploymentType, EnforcementMode, PolicyLanguage,
|
|
20
|
+
generate_ed25519, Ed25519Signer,
|
|
21
|
+
)
|
|
22
|
+
from agent_manifest._types import HashValue, ManifestId
|
|
23
|
+
from datetime import datetime, timedelta, timezone
|
|
24
|
+
|
|
25
|
+
now = datetime.now(timezone.utc)
|
|
26
|
+
|
|
27
|
+
manifest = Manifest(
|
|
28
|
+
manifest_id=ManifestId("018f4a3b-2c1d-7e5f-a8b9-0d1e2f3a4b5c"),
|
|
29
|
+
agent_id="spiffe://trust.example/agent/kyc/prod",
|
|
30
|
+
issued_at=now,
|
|
31
|
+
expires_at=now + timedelta(days=90),
|
|
32
|
+
issuer="spiffe://trust.example/signing-authority",
|
|
33
|
+
crypto_profile=CryptoProfile.standard,
|
|
34
|
+
artifacts=ArtifactBindings(
|
|
35
|
+
system_prompt=SystemPromptBinding(
|
|
36
|
+
hash=HashValue("sha256:" + "a" * 64),
|
|
37
|
+
bound_at=now,
|
|
38
|
+
),
|
|
39
|
+
policy_bundle=PolicyBundleBinding(
|
|
40
|
+
hash=HashValue("sha256:" + "b" * 64),
|
|
41
|
+
policy_language=PolicyLanguage.cedar,
|
|
42
|
+
version="1.0.0",
|
|
43
|
+
enforcement_mode=EnforcementMode.enforce,
|
|
44
|
+
bound_at=now,
|
|
45
|
+
),
|
|
46
|
+
model_identity=ModelIdentityBinding(
|
|
47
|
+
provider="anthropic",
|
|
48
|
+
model_id="claude-sonnet-4-6",
|
|
49
|
+
version="20251001",
|
|
50
|
+
deployment_type=DeploymentType.api,
|
|
51
|
+
bound_at=now,
|
|
52
|
+
),
|
|
53
|
+
),
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
keypair = generate_ed25519()
|
|
57
|
+
signer = Ed25519Signer(keypair)
|
|
58
|
+
sig_block = signer.sign(manifest.model_dump(mode="json", by_alias=True))
|
|
59
|
+
print(sig_block["algorithm"]) # Ed25519
|
|
60
|
+
print(sig_block["key_id"]) # sha256:<hex>
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## The 10 Attested Artifacts
|
|
64
|
+
|
|
65
|
+
| # | Artifact | What it proves |
|
|
66
|
+
|---|----------|---------------|
|
|
67
|
+
| 1 | System Prompt | The exact prompt that defines the agent's persona and safety constraints |
|
|
68
|
+
| 2 | Policy Bundle | The Cedar/Rego/YAML governance rules that were in force |
|
|
69
|
+
| 3 | Tool Manifest | Every tool schema and description the agent was authorized to call |
|
|
70
|
+
| 4 | Model Identity | Which model and version ran (binary hash for local, version for API) |
|
|
71
|
+
| 5 | RAG Corpus | The knowledge base the agent was grounded on (Merkle root) |
|
|
72
|
+
| 6 | Memory Baseline | Approved agent memory state with TTL-based re-approval |
|
|
73
|
+
| 7 | Decision Trace | Hardware-signed audit chain root for all agent decisions |
|
|
74
|
+
| 8 | A2A Delegation | Signed delegation chain from human principal to current agent |
|
|
75
|
+
| 9 | Supply Chain | Container digest, SLSA provenance, SBOM, MCP server supply chain |
|
|
76
|
+
| 10 | HITL Approvals | Hardware-signed human oversight records (EU AI Act Art. 14) |
|
|
77
|
+
|
|
78
|
+
## Hardware Attestation
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
from agent_manifest._auto_provider import select_provider
|
|
82
|
+
|
|
83
|
+
# auto-selects: SEV-SNP → TDX → TPM → software (OPAQUE is explicit opt-in via OPAQUE_ATTESTATION_URL)
|
|
84
|
+
provider = select_provider(level=1) # Level 1+ requires hardware
|
|
85
|
+
provider.extend_manifest_hash(manifest_dict)
|
|
86
|
+
report = provider.get_attestation_report()
|
|
87
|
+
# report.platform: "amd-sev-snp" | "intel-tdx" | "tpm" | "opaque" | "software"
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
| Provider | Hardware | Level | Install |
|
|
91
|
+
|----------|----------|-------|---------|
|
|
92
|
+
| `TPMProvider` | TPM 2.0 / AWS Nitro | 1 | `apt install tpm2-tools` |
|
|
93
|
+
| `SEVSNPProvider` | AMD SEV-SNP | 2 | Needs `/dev/sev-guest` |
|
|
94
|
+
| `TDXProvider` | Intel TDX | 2 | Needs `/dev/tdx-guest` |
|
|
95
|
+
| `OPAQUEProvider` | Opaque Runtime | 3 | Set `OPAQUE_ATTESTATION_URL` |
|
|
96
|
+
|
|
97
|
+
## Verification
|
|
98
|
+
|
|
99
|
+
```python
|
|
100
|
+
from agent_manifest._verify import verify_manifest, VerificationContext, RevocationStore
|
|
101
|
+
|
|
102
|
+
result = verify_manifest(
|
|
103
|
+
manifest_dict,
|
|
104
|
+
VerificationContext(
|
|
105
|
+
system_prompt_hash="sha256:...",
|
|
106
|
+
policy_bundle_hash="sha256:...",
|
|
107
|
+
enforce_hitl=True,
|
|
108
|
+
),
|
|
109
|
+
RevocationStore(),
|
|
110
|
+
)
|
|
111
|
+
print(result.result) # VALID | MISMATCH | EXPIRED | REVOKED | ...
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## CLI
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
pip install "agent-manifest[cli]"
|
|
118
|
+
|
|
119
|
+
manifest keygen -d ./keys/
|
|
120
|
+
manifest create config.json -o draft.json
|
|
121
|
+
manifest sign draft.json --key keys/private.hex -o signed.json
|
|
122
|
+
manifest attest signed.json --provider auto --level 1 -o attested.json
|
|
123
|
+
manifest verify attested.json
|
|
124
|
+
manifest revoke <manifest-id> --reason "key compromise" --revoked-by security@example.com
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Cryptography
|
|
128
|
+
|
|
129
|
+
- **Standard profile**: Ed25519 (RFC 8032), SHA-256, RFC 8785 canonical JSON
|
|
130
|
+
- **Post-quantum profile**: ML-DSA-65 (NIST FIPS 204), SHAKE-256 - `pip install "agent-manifest[pq]"`
|
|
131
|
+
- **Hybrid**: Both signatures required, identical pre-image
|
|
132
|
+
- **Transparency**: Rekor/Sigstore integration for non-repudiation
|
|
133
|
+
|
|
134
|
+
## Specification
|
|
135
|
+
|
|
136
|
+
The full Agent Manifest Specification v0.1 is at [`spec/agent-manifest-spec-v0.1.md`](https://github.com/agentrust-io/agent-manifest/blob/main/spec/agent-manifest-spec-v0.1.md).
|
|
137
|
+
|
|
138
|
+
Being submitted to the [Agentic AI Foundation (AAIF)](https://agenticai.foundation) under the Linux Foundation alongside AGT.
|
|
139
|
+
|
|
140
|
+
## License
|
|
141
|
+
|
|
142
|
+
Apache 2.0
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "agent-manifest"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Agent Manifest SDK — cryptographically anchor all 10 artifacts defining an AI agent at deployment"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.11"
|
|
11
|
+
license = {text = "Apache-2.0"}
|
|
12
|
+
authors = [{name = "Imran Siddique", email = "maintainers@agentrust.io"}]
|
|
13
|
+
keywords = [
|
|
14
|
+
"ai-agents", "attestation", "governance", "tee", "confidential-computing",
|
|
15
|
+
"mcp", "agent-manifest", "trust", "hardware-attestation", "pydantic",
|
|
16
|
+
]
|
|
17
|
+
classifiers = [
|
|
18
|
+
"Development Status :: 3 - Alpha",
|
|
19
|
+
"Intended Audience :: Developers",
|
|
20
|
+
"License :: OSI Approved :: Apache Software License",
|
|
21
|
+
"Programming Language :: Python :: 3",
|
|
22
|
+
"Programming Language :: Python :: 3.11",
|
|
23
|
+
"Programming Language :: Python :: 3.12",
|
|
24
|
+
"Programming Language :: Python :: 3.13",
|
|
25
|
+
"Topic :: Security :: Cryptography",
|
|
26
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
27
|
+
"Topic :: System :: Monitoring",
|
|
28
|
+
"Typing :: Typed",
|
|
29
|
+
]
|
|
30
|
+
dependencies = [
|
|
31
|
+
"pydantic>=2.7,<3",
|
|
32
|
+
"cryptography>=42,<50",
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
[project.optional-dependencies]
|
|
36
|
+
pq = ["pyoqs>=0.10"]
|
|
37
|
+
server = ["fastapi>=0.111", "uvicorn[standard]>=0.29", "httpx>=0.27"]
|
|
38
|
+
cli = ["click>=8.1"]
|
|
39
|
+
all = ["pyoqs>=0.10", "fastapi>=0.111", "uvicorn[standard]>=0.29", "httpx>=0.27", "click>=8.1"]
|
|
40
|
+
dev = ["pytest>=8", "pytest-asyncio>=0.23", "pytest-cov>=5", "httpx>=0.27",
|
|
41
|
+
"jcs>=0.2", "fastapi>=0.111", "uvicorn[standard]>=0.29",
|
|
42
|
+
"click>=8.1", "mypy>=1.10", "bandit[toml]>=1.7", "pip-audit>=2.7"]
|
|
43
|
+
|
|
44
|
+
[project.scripts]
|
|
45
|
+
manifest = "agent_manifest.cli:main"
|
|
46
|
+
|
|
47
|
+
[project.urls]
|
|
48
|
+
Homepage = "https://github.com/agentrust-io/agent-manifest"
|
|
49
|
+
Repository = "https://github.com/agentrust-io/agent-manifest"
|
|
50
|
+
Documentation = "https://github.com/agentrust-io/agent-manifest/tree/main/spec"
|
|
51
|
+
"Bug Tracker" = "https://github.com/agentrust-io/agent-manifest/issues"
|
|
52
|
+
Changelog = "https://github.com/agentrust-io/agent-manifest/releases"
|
|
53
|
+
|
|
54
|
+
[tool.hatch.build.targets.wheel]
|
|
55
|
+
packages = ["src/agent_manifest"]
|
|
56
|
+
|
|
57
|
+
[tool.hatch.build.targets.sdist]
|
|
58
|
+
include = ["src/", "tests/", "README.md", "LICENSE"]
|
|
59
|
+
|
|
60
|
+
[tool.pytest.ini_options]
|
|
61
|
+
asyncio_mode = "auto"
|
|
62
|
+
testpaths = ["tests"]
|
|
63
|
+
|
|
64
|
+
[tool.hatch.version]
|
|
65
|
+
path = "src/agent_manifest/__init__.py"
|
|
66
|
+
|
|
67
|
+
[tool.mypy]
|
|
68
|
+
python_version = "3.11"
|
|
69
|
+
strict = true
|
|
70
|
+
ignore_missing_imports = true
|
|
71
|
+
|
|
72
|
+
[[tool.mypy.overrides]]
|
|
73
|
+
module = "agent_manifest._hw_providers"
|
|
74
|
+
warn_unused_ignores = false
|
|
75
|
+
|
|
76
|
+
[tool.coverage.run]
|
|
77
|
+
source = ["src/agent_manifest"]
|
|
78
|
+
omit = ["src/agent_manifest/cli.py"]
|
|
79
|
+
|
|
80
|
+
[tool.coverage.report]
|
|
81
|
+
fail_under = 80
|
|
82
|
+
show_missing = true
|
|
83
|
+
|
|
84
|
+
[tool.bandit]
|
|
85
|
+
exclude_dirs = ["tests"]
|
|
86
|
+
# B101: assert statements (test helpers); B404/B603/B607: TPM attestation
|
|
87
|
+
# providers require subprocess — inputs are validated before the call and
|
|
88
|
+
# never include user-controlled data, so these are false positives.
|
|
89
|
+
skips = ["B101", "B404", "B603", "B607"]
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"""Agent Manifest SDK - public API."""
|
|
2
|
+
from .models import (
|
|
3
|
+
Manifest, ArtifactBindings,
|
|
4
|
+
SystemPromptBinding, PolicyBundleBinding, ToolManifestBinding,
|
|
5
|
+
ModelIdentityBinding, RagCorpusBinding, MemoryBaselineBinding,
|
|
6
|
+
DecisionTraceBinding, SupplyChainBinding,
|
|
7
|
+
DelegationHop, HitlRecord, HitlApproval, ManifestSignature,
|
|
8
|
+
ToolEntry, ScopeGrant, ApprovedScope, PoisoningScan, SlsaProvenance,
|
|
9
|
+
Sbom, McpServer,
|
|
10
|
+
EscalationPolicy, HitlRuntime,
|
|
11
|
+
TransparencyLogEntry, InclusionProof,
|
|
12
|
+
LogRetention, DataScope, OperationalLifecycle,
|
|
13
|
+
PolicyLanguage, EnforcementMode, DeploymentType, MemoryType, DriftPolicy,
|
|
14
|
+
RugPullPolicy, TraceType, SbomFormat, SlsaLevel, PoisoningResult,
|
|
15
|
+
ApprovalMethod, ApproverIdentityType, PrincipalType, DataClassification,
|
|
16
|
+
CryptoProfile, SignatureAlgorithm, KeyType, RiskTier,
|
|
17
|
+
ModelAttestationType, OverrideMechanism, TimeoutAction,
|
|
18
|
+
)
|
|
19
|
+
from ._types import HashValue, ManifestId
|
|
20
|
+
from ._canonicalize import canonicalize, canonical_hash
|
|
21
|
+
from ._signing import (
|
|
22
|
+
SIGNED_FIELDS,
|
|
23
|
+
signing_pre_image,
|
|
24
|
+
generate_ed25519, Ed25519KeyPair, Ed25519Signer, Ed25519Verifier,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
__all__ = [
|
|
28
|
+
"Manifest", "ArtifactBindings",
|
|
29
|
+
"SystemPromptBinding", "PolicyBundleBinding", "ToolManifestBinding",
|
|
30
|
+
"ModelIdentityBinding", "RagCorpusBinding", "MemoryBaselineBinding",
|
|
31
|
+
"DecisionTraceBinding", "SupplyChainBinding",
|
|
32
|
+
"DelegationHop", "HitlRecord", "HitlApproval", "ManifestSignature",
|
|
33
|
+
"ToolEntry", "ScopeGrant", "ApprovedScope", "PoisoningScan", "SlsaProvenance",
|
|
34
|
+
"Sbom", "McpServer",
|
|
35
|
+
"EscalationPolicy", "HitlRuntime",
|
|
36
|
+
"TransparencyLogEntry", "InclusionProof",
|
|
37
|
+
"LogRetention", "DataScope", "OperationalLifecycle",
|
|
38
|
+
"PolicyLanguage", "EnforcementMode", "DeploymentType", "MemoryType", "DriftPolicy",
|
|
39
|
+
"RugPullPolicy", "TraceType", "SbomFormat", "SlsaLevel", "PoisoningResult",
|
|
40
|
+
"ApprovalMethod", "ApproverIdentityType", "PrincipalType", "DataClassification",
|
|
41
|
+
"CryptoProfile", "SignatureAlgorithm", "KeyType", "RiskTier",
|
|
42
|
+
"ModelAttestationType", "OverrideMechanism", "TimeoutAction",
|
|
43
|
+
"HashValue", "ManifestId",
|
|
44
|
+
"canonicalize", "canonical_hash",
|
|
45
|
+
"SIGNED_FIELDS", "signing_pre_image",
|
|
46
|
+
"generate_ed25519", "Ed25519KeyPair", "Ed25519Signer", "Ed25519Verifier",
|
|
47
|
+
]
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"""provider='auto' attestation backend selection.
|
|
2
|
+
|
|
3
|
+
Auto-selection order (first locally-verifiable silicon wins):
|
|
4
|
+
1. SEVSNPProvider — if /dev/sev-guest exists
|
|
5
|
+
2. TDXProvider — if /dev/tdx-guest exists
|
|
6
|
+
3. TPMProvider — if tpm2_extend is in PATH
|
|
7
|
+
4. SoftwareProvider — fallback, Level 0 only (no hardware attestation)
|
|
8
|
+
|
|
9
|
+
OPAQUEProvider is explicit opt-in: selected only when OPAQUE_ATTESTATION_URL
|
|
10
|
+
is set. It is never auto-detected.
|
|
11
|
+
|
|
12
|
+
The SoftwareProvider is never selected automatically for Level 1+ contexts.
|
|
13
|
+
Callers that require Level 1+ MUST explicitly check provider.level >= 1.
|
|
14
|
+
"""
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import os
|
|
18
|
+
import shutil
|
|
19
|
+
from typing import Any, cast
|
|
20
|
+
|
|
21
|
+
from ._providers import AttestationProvider, AttestationReport, AttestationUnavailableError, TPMProvider
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class SoftwareProvider(AttestationProvider):
|
|
25
|
+
"""Level 0 software-only fallback — no hardware attestation.
|
|
26
|
+
|
|
27
|
+
Produces a manifest hash using pure software SHA-256. Suitable for
|
|
28
|
+
development and staging. MUST NOT be used for Level 1+ conformance.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
LEVEL = 0
|
|
32
|
+
|
|
33
|
+
def extend_manifest_hash(self, manifest_json: dict[str, Any]) -> None:
|
|
34
|
+
# No hardware to extend into — record the hash for report generation
|
|
35
|
+
self._manifest_hash = self.manifest_hash_value(manifest_json)
|
|
36
|
+
|
|
37
|
+
def get_attestation_report(self) -> AttestationReport:
|
|
38
|
+
if not hasattr(self, "_manifest_hash"):
|
|
39
|
+
raise AttestationUnavailableError(
|
|
40
|
+
"Call extend_manifest_hash() before get_attestation_report()."
|
|
41
|
+
)
|
|
42
|
+
return AttestationReport(platform="software", manifest_hash=self._manifest_hash)
|
|
43
|
+
|
|
44
|
+
def verify_manifest_in_report(self, report: AttestationReport, manifest_json: dict[str, Any]) -> bool:
|
|
45
|
+
return bool(report.manifest_hash == self.manifest_hash_value(manifest_json))
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def select_provider(level: int = 0) -> AttestationProvider:
|
|
49
|
+
"""Return the best available attestation provider for *level*.
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
level: Minimum conformance level required (0-3).
|
|
53
|
+
|
|
54
|
+
Raises:
|
|
55
|
+
AttestationUnavailableError: If *level* > 0 and no hardware provider
|
|
56
|
+
is available.
|
|
57
|
+
"""
|
|
58
|
+
# OPAQUE managed runtime — explicit opt-in only, not auto-detected
|
|
59
|
+
if os.environ.get("OPAQUE_ATTESTATION_URL"):
|
|
60
|
+
from ._hw_providers import OPAQUEProvider
|
|
61
|
+
return cast(AttestationProvider, OPAQUEProvider())
|
|
62
|
+
|
|
63
|
+
# AMD SEV-SNP
|
|
64
|
+
if os.path.exists("/dev/sev-guest"):
|
|
65
|
+
from ._hw_providers import SEVSNPProvider
|
|
66
|
+
return cast(AttestationProvider, SEVSNPProvider())
|
|
67
|
+
|
|
68
|
+
# Intel TDX
|
|
69
|
+
if os.path.exists("/dev/tdx-guest"):
|
|
70
|
+
from ._hw_providers import TDXProvider
|
|
71
|
+
return cast(AttestationProvider, TDXProvider())
|
|
72
|
+
|
|
73
|
+
# Generic TPM / AWS Nitro
|
|
74
|
+
if shutil.which("tpm2_extend"):
|
|
75
|
+
return TPMProvider()
|
|
76
|
+
|
|
77
|
+
# Software fallback
|
|
78
|
+
if level >= 1:
|
|
79
|
+
raise AttestationUnavailableError(
|
|
80
|
+
"No hardware attestation provider available. "
|
|
81
|
+
"Level 1+ conformance requires TPM 2.0, AMD SEV-SNP, or Intel TDX. "
|
|
82
|
+
"To use the OPAQUE managed runtime, set OPAQUE_ATTESTATION_URL. "
|
|
83
|
+
"For development use, set level=0 explicitly."
|
|
84
|
+
)
|
|
85
|
+
return SoftwareProvider()
|