abom-cli 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.
- abom_cli-0.1.0/.env.example +26 -0
- abom_cli-0.1.0/.gitignore +14 -0
- abom_cli-0.1.0/Dockerfile +15 -0
- abom_cli-0.1.0/MVP_SPEC.md +157 -0
- abom_cli-0.1.0/Makefile +32 -0
- abom_cli-0.1.0/PKG-INFO +108 -0
- abom_cli-0.1.0/README.md +69 -0
- abom_cli-0.1.0/charts/abom/Chart.yaml +9 -0
- abom_cli-0.1.0/charts/abom/values.yaml +36 -0
- abom_cli-0.1.0/demo/README.md +69 -0
- abom_cli-0.1.0/demo/demo.py +197 -0
- abom_cli-0.1.0/demo/sample_repo/tests.py +40 -0
- abom_cli-0.1.0/demo/sample_repo/validator.py +5 -0
- abom_cli-0.1.0/docker-compose.yml +53 -0
- abom_cli-0.1.0/pyproject.toml +61 -0
- abom_cli-0.1.0/scripts/init_db.py +18 -0
- abom_cli-0.1.0/src/abom/__init__.py +3 -0
- abom_cli-0.1.0/src/abom/agents.py +58 -0
- abom_cli-0.1.0/src/abom/api.py +177 -0
- abom_cli-0.1.0/src/abom/audit.py +122 -0
- abom_cli-0.1.0/src/abom/bom.py +147 -0
- abom_cli-0.1.0/src/abom/cli.py +130 -0
- abom_cli-0.1.0/src/abom/config.py +37 -0
- abom_cli-0.1.0/src/abom/db.py +127 -0
- abom_cli-0.1.0/src/abom/execution.py +73 -0
- abom_cli-0.1.0/src/abom/models_router.py +84 -0
- abom_cli-0.1.0/src/abom/orchestration.py +237 -0
- abom_cli-0.1.0/src/abom/policy.py +46 -0
- abom_cli-0.1.0/src/abom/scan.py +207 -0
- abom_cli-0.1.0/src/abom/schemas.py +79 -0
- abom_cli-0.1.0/src/abom/sign.py +91 -0
- abom_cli-0.1.0/tests/fixtures/sample-agent/agent.py +16 -0
- abom_cli-0.1.0/tests/fixtures/sample-agent/mcp.json +6 -0
- abom_cli-0.1.0/tests/fixtures/sample-agent/prompts/system.txt +2 -0
- abom_cli-0.1.0/tests/fixtures/sample-agent/requirements.txt +7 -0
- abom_cli-0.1.0/tests/test_audit_chain.py +73 -0
- abom_cli-0.1.0/tests/test_scan.py +67 -0
- abom_cli-0.1.0/tests/test_sign.py +32 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Copy to .env and adjust. All keys are prefixed ABOM_ (see src/abom/config.py).
|
|
2
|
+
|
|
3
|
+
ABOM_DATABASE_URL=postgresql+asyncpg://abom:abom@localhost:5432/abom
|
|
4
|
+
ABOM_TEMPORAL_HOST=localhost:7233
|
|
5
|
+
ABOM_TEMPORAL_NAMESPACE=default
|
|
6
|
+
ABOM_TASK_QUEUE=abom-cli
|
|
7
|
+
|
|
8
|
+
ABOM_S3_ENDPOINT=http://localhost:9000
|
|
9
|
+
ABOM_S3_ACCESS_KEY=minioadmin
|
|
10
|
+
ABOM_S3_SECRET_KEY=minioadmin
|
|
11
|
+
ABOM_S3_BUCKET=abom-artifacts
|
|
12
|
+
|
|
13
|
+
# Local, OpenAI-compatible model server (vLLM). Set MODEL_USE_MOCK=false to use it.
|
|
14
|
+
ABOM_MODEL_BASE_URL=http://localhost:8001/v1
|
|
15
|
+
ABOM_MODEL_NAME=local/qwen2.5-coder
|
|
16
|
+
ABOM_MODEL_USE_MOCK=true
|
|
17
|
+
|
|
18
|
+
# Auth: leave JWKS empty for dev mode (static token grants all roles).
|
|
19
|
+
ABOM_OIDC_JWKS_URL=
|
|
20
|
+
ABOM_OIDC_AUDIENCE=abom
|
|
21
|
+
ABOM_DEV_STATIC_TOKEN=dev-token
|
|
22
|
+
|
|
23
|
+
# Execution
|
|
24
|
+
ABOM_SANDBOX_IMAGE=python:3.12-slim
|
|
25
|
+
ABOM_WORKSPACE_ROOT=/tmp/abom-workspaces
|
|
26
|
+
ABOM_GATE_TIMEOUT_SECONDS=600
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
FROM python:3.12-slim
|
|
2
|
+
|
|
3
|
+
WORKDIR /app
|
|
4
|
+
ENV PYTHONUNBUFFERED=1 PYTHONPATH=/app/src
|
|
5
|
+
|
|
6
|
+
COPY pyproject.toml ./
|
|
7
|
+
RUN pip install --no-cache-dir -e "." || pip install --no-cache-dir \
|
|
8
|
+
fastapi "uvicorn[standard]" pydantic pydantic-settings "sqlalchemy[asyncio]" \
|
|
9
|
+
asyncpg alembic temporalio httpx boto3 "python-jose[cryptography]" typer
|
|
10
|
+
|
|
11
|
+
COPY src ./src
|
|
12
|
+
COPY scripts ./scripts
|
|
13
|
+
|
|
14
|
+
EXPOSE 8000
|
|
15
|
+
CMD ["uvicorn", "abom.api:app", "--host", "0.0.0.0", "--port", "8000"]
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# ABOM — Step-1 MVP Specification
|
|
2
|
+
|
|
3
|
+
*Build target for the lighthouse design partner. Detailed enough to scaffold from. Companion to the project docs (kept private) §7 and the project docs (kept private).*
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Goal
|
|
8
|
+
|
|
9
|
+
For **one real agent run, entirely inside the customer's boundary**, produce a
|
|
10
|
+
signed **Agent Bill of Materials** and verify it:
|
|
11
|
+
|
|
12
|
+
1. **Generate** — a signed **Composition Manifest** (what the agent is made of) and
|
|
13
|
+
a hash-chained **Action Provenance** chain (what it did).
|
|
14
|
+
2. **Verify** — run **abom-verify** against policy and catch a real violation a raw
|
|
15
|
+
log would let ship silently (unapproved/shadow model, confidential-data egress,
|
|
16
|
+
missing approval, composition drift).
|
|
17
|
+
3. **Prove** — show the provenance is tamper-evident: scrubbing a record breaks the
|
|
18
|
+
chain at the exact `seq`.
|
|
19
|
+
|
|
20
|
+
Guiding constraint: *nothing leaves the boundary*. The ABOM format extends
|
|
21
|
+
**CycloneDX ML-BOM**.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## 2. The workload
|
|
26
|
+
|
|
27
|
+
An agent run (the MVP exercises a developer/document agent) whose actions —
|
|
28
|
+
model calls, tool/egress calls, data access, gate results, approvals — are
|
|
29
|
+
captured as Action Provenance and bound to a signed Composition Manifest.
|
|
30
|
+
|
|
31
|
+
### Out of scope for MVP
|
|
32
|
+
Full runtime auto-capture (eBPF/framework taps) · real ed25519/cosign signing
|
|
33
|
+
(MVP uses an HMAC stand-in) · the persistent Notary registry · OPA/Rego (MVP uses
|
|
34
|
+
a JSON policy) · web console · multi-tenancy · SIEM export · air-gap bundle.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## 3. The ABOM artifacts (the core)
|
|
39
|
+
|
|
40
|
+
**Composition Manifest** — signed; `composition_sha256` is the join key.
|
|
41
|
+
```json
|
|
42
|
+
{ "abom":"0.1","extends":"CycloneDX ML-BOM","type":"CompositionManifest",
|
|
43
|
+
"agent":{"name":"…","version":"…","risk_class":"high (Annex III)"},
|
|
44
|
+
"components":[ {"type":"model","name":"…","weights_sha256":"…","egress":false},
|
|
45
|
+
{"type":"tool","name":"http_fetch","allowed_endpoints":["…"]},
|
|
46
|
+
{"type":"prompt","sha256":"…"},
|
|
47
|
+
{"type":"dataSource","classification":"confidential"},
|
|
48
|
+
{"type":"policy","engine":"OPA","sha256":"…"} ],
|
|
49
|
+
"controls":{"egress":"deny-by-default","hitl":"required-for-consequential","residency":"EU"},
|
|
50
|
+
"composition_sha256":"…","signature":{"alg":"…","value":"…"} }
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**Action Provenance Record** — hash-chained (reuses the audit chain).
|
|
54
|
+
```json
|
|
55
|
+
{ "type":"ActionProvenance","run_id":"agent@ver","seq":1,
|
|
56
|
+
"data":{ "composition_sha256":"…","decision":"…",
|
|
57
|
+
"inputs":[…],"model_calls":[{"model":"…","tokens":…}],
|
|
58
|
+
"tools_invoked":[{"name":"…","endpoint":"…"}],
|
|
59
|
+
"data_touched":[{"classification":"confidential","egress":false}],
|
|
60
|
+
"policy_decisions":[{"rule":"approval_required","result":"required"}],
|
|
61
|
+
"approval":{"by":"…","decision":"approved"} },
|
|
62
|
+
"prev_hash":"…","hash":"…" }
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Implemented in [src/abom/bom.py](src/abom/bom.py) (`build_composition`,
|
|
66
|
+
`append_action`, `sign`/`verify_signature`) over the tamper-evident chain in
|
|
67
|
+
[src/abom/audit.py](src/abom/audit.py).
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## 4. abom-verify — policy checks
|
|
72
|
+
|
|
73
|
+
`bom.verify_abom(composition, chain, policy)` → `{ok, findings[], actions}`. Rules:
|
|
74
|
+
|
|
75
|
+
| Rule | Catches |
|
|
76
|
+
|---|---|
|
|
77
|
+
| `signature` | composition signature invalid |
|
|
78
|
+
| `chain_integrity` | provenance mutated / scrubbed / reordered |
|
|
79
|
+
| `composition_match` | an action references a different composition |
|
|
80
|
+
| `model_allowlist` | a model not on the approved list was used |
|
|
81
|
+
| `composition_drift` | a runtime model not in the signed manifest (shadow model) |
|
|
82
|
+
| `residency` | confidential/restricted data egressed |
|
|
83
|
+
| `egress_allowlist` | egress to an unapproved endpoint |
|
|
84
|
+
| `approval_coverage` | a consequential action without approval |
|
|
85
|
+
|
|
86
|
+
Phase-2 swaps the JSON policy for OPA/Rego behind the same interface.
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## 5. Tech stack & substrate
|
|
91
|
+
|
|
92
|
+
Where ABOMs are captured: the agent runs through the control-plane substrate so
|
|
93
|
+
every action is observable. (Capture completeness is the product's hardest
|
|
94
|
+
property — see the project docs (kept private) §3.2.)
|
|
95
|
+
|
|
96
|
+
| Concern | Choice |
|
|
97
|
+
|---|---|
|
|
98
|
+
| Language | Python 3.12 |
|
|
99
|
+
| API | FastAPI + Pydantic v2 |
|
|
100
|
+
| Orchestration | Temporal (`temporalio`) |
|
|
101
|
+
| DB / ORM | PostgreSQL 16 + SQLAlchemy 2.0 (async) |
|
|
102
|
+
| Object store | MinIO (S3) |
|
|
103
|
+
| Model serving | vLLM (OpenAI-compatible); `MockModelClient` for laptops |
|
|
104
|
+
| Policy | JSON (MVP) → OPA/Rego |
|
|
105
|
+
| Signing | HMAC stand-in (MVP) → ed25519 / cosign |
|
|
106
|
+
| Deploy | Helm stub (`charts/abom`), any Kubernetes |
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## 6. API surface (MVP)
|
|
111
|
+
|
|
112
|
+
Bearer token; `roles` claim drives RBAC (`developer`, `operator`, `auditor`).
|
|
113
|
+
|
|
114
|
+
| Method | Path | Role | Purpose |
|
|
115
|
+
|---|---|---|---|
|
|
116
|
+
| GET | `/healthz` `/readyz` | — | liveness / readiness |
|
|
117
|
+
| POST | `/v1/runs` | developer | start an instrumented agent run |
|
|
118
|
+
| GET | `/v1/runs/{id}/abom` | auditor | the run's Composition Manifest + Action Provenance |
|
|
119
|
+
| GET | `/v1/abom/verify?run_id=` | auditor | run abom-verify → findings |
|
|
120
|
+
| GET | `/v1/abom/chain/verify?run_id=` | auditor | recompute the provenance hash chain |
|
|
121
|
+
| POST | `/v1/runs/{id}/approve` | operator | approve a consequential action |
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## 7. Definition of done
|
|
126
|
+
|
|
127
|
+
1. A run completes against a **local** model only — zero external egress, verifiable.
|
|
128
|
+
2. The run emits a **signed Composition Manifest** and a **hash-chained Action Provenance** chain.
|
|
129
|
+
3. **abom-verify** returns **clean** for a compliant run and **≥3 findings** for a violating run (shadow model + confidential egress + missing approval).
|
|
130
|
+
4. Tampering with any provenance record makes `verify_abom` report a `chain_integrity` finding at the broken `seq`.
|
|
131
|
+
5. RBAC enforced: `auditor` cannot start runs; `developer` cannot approve.
|
|
132
|
+
6. `make demo` runs the generate → verify → tamper scenario with no infrastructure.
|
|
133
|
+
|
|
134
|
+
The demo ([demo/demo.py](demo/demo.py)) already satisfies criteria 2–4 and 6.
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## 8. Milestones (≈6 weeks, one engineer)
|
|
139
|
+
|
|
140
|
+
| Wk | Deliverable |
|
|
141
|
+
|---|---|
|
|
142
|
+
| 1 | ABOM v0 schema + `bom.py` (composition, provenance, verify) + tamper test ✓ |
|
|
143
|
+
| 2 | Control API: runs, `/v1/runs/{id}/abom`, `/v1/abom/verify`, RBAC |
|
|
144
|
+
| 3 | Capture hooks in the model router + tool gateway (real model/tool/data events) |
|
|
145
|
+
| 4 | Real ed25519/cosign signing; persist to a minimal Notary (append-only table) |
|
|
146
|
+
| 5 | CycloneDX + SIEM export; second decidable verify rule hardened |
|
|
147
|
+
| 6 | docker-compose end-to-end; Helm stub; design-partner demo |
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## 9. Risk specific to the MVP
|
|
152
|
+
|
|
153
|
+
**Capture completeness.** A provenance chain is only trustworthy if *every* action
|
|
154
|
+
is recorded. The MVP supplies actions explicitly; the product earns completeness
|
|
155
|
+
by generating from inside the runtime (control-plane taps + framework hooks + an
|
|
156
|
+
eBPF egress backstop). Keep the `abom-gen` capture interface stable so those
|
|
157
|
+
sources can be added without changing the artifacts.
|
abom_cli-0.1.0/Makefile
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
.PHONY: install test scan verify demo build up down migrate lint
|
|
2
|
+
|
|
3
|
+
install:
|
|
4
|
+
pip install -e ".[dev]"
|
|
5
|
+
|
|
6
|
+
test:
|
|
7
|
+
PYTHONPATH=src pytest -q
|
|
8
|
+
|
|
9
|
+
scan:
|
|
10
|
+
PYTHONPATH=src python -m abom.cli scan . -o abom.json
|
|
11
|
+
|
|
12
|
+
verify:
|
|
13
|
+
PYTHONPATH=src python -m abom.cli verify abom.json
|
|
14
|
+
|
|
15
|
+
build:
|
|
16
|
+
rm -rf dist && python -m build && twine check dist/*
|
|
17
|
+
|
|
18
|
+
up:
|
|
19
|
+
docker compose up -d --build
|
|
20
|
+
|
|
21
|
+
down:
|
|
22
|
+
docker compose down -v
|
|
23
|
+
|
|
24
|
+
migrate:
|
|
25
|
+
PYTHONPATH=src python scripts/init_db.py
|
|
26
|
+
@echo "(MVP) tables created via metadata. For prod, switch to Alembic migrations."
|
|
27
|
+
|
|
28
|
+
demo:
|
|
29
|
+
python3 demo/demo.py
|
|
30
|
+
|
|
31
|
+
lint:
|
|
32
|
+
ruff check src tests
|
abom_cli-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: abom-cli
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: ABOM — the Agent Bill of Materials. Scan, sign, and verify what your AI agents are made of.
|
|
5
|
+
Project-URL: Homepage, https://abom.ai
|
|
6
|
+
Project-URL: Repository, https://github.com/josephassiga/abom
|
|
7
|
+
Project-URL: Specification, https://github.com/josephassiga/abom/tree/main/spec
|
|
8
|
+
Author: ABOM Contributors
|
|
9
|
+
License-Expression: Apache-2.0
|
|
10
|
+
Keywords: agent,ai,ai-security,cyclonedx,llm,ml-bom,provenance,sbom,supply-chain
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
15
|
+
Classifier: Topic :: Security
|
|
16
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
17
|
+
Requires-Python: >=3.11
|
|
18
|
+
Requires-Dist: cryptography>=42.0
|
|
19
|
+
Requires-Dist: typer>=0.12
|
|
20
|
+
Provides-Extra: dev
|
|
21
|
+
Requires-Dist: build>=1.2; extra == 'dev'
|
|
22
|
+
Requires-Dist: jsonschema>=4.21; extra == 'dev'
|
|
23
|
+
Requires-Dist: pytest>=8.3; extra == 'dev'
|
|
24
|
+
Requires-Dist: ruff>=0.7; extra == 'dev'
|
|
25
|
+
Requires-Dist: twine>=5.0; extra == 'dev'
|
|
26
|
+
Provides-Extra: server
|
|
27
|
+
Requires-Dist: alembic>=1.13; extra == 'server'
|
|
28
|
+
Requires-Dist: asyncpg>=0.30; extra == 'server'
|
|
29
|
+
Requires-Dist: boto3>=1.35; extra == 'server'
|
|
30
|
+
Requires-Dist: fastapi>=0.115; extra == 'server'
|
|
31
|
+
Requires-Dist: httpx>=0.27; extra == 'server'
|
|
32
|
+
Requires-Dist: pydantic-settings>=2.6; extra == 'server'
|
|
33
|
+
Requires-Dist: pydantic>=2.9; extra == 'server'
|
|
34
|
+
Requires-Dist: python-jose[cryptography]>=3.3; extra == 'server'
|
|
35
|
+
Requires-Dist: sqlalchemy[asyncio]>=2.0; extra == 'server'
|
|
36
|
+
Requires-Dist: temporalio>=1.8; extra == 'server'
|
|
37
|
+
Requires-Dist: uvicorn[standard]>=0.32; extra == 'server'
|
|
38
|
+
Description-Content-Type: text/markdown
|
|
39
|
+
|
|
40
|
+
# abom-cli
|
|
41
|
+
|
|
42
|
+
The reference implementation of [ABOM](../spec/) — the Agent Bill of Materials.
|
|
43
|
+
Scan a repo, emit a **signed** Composition Manifest, and **verify** it.
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
pip install abom-cli # (until published: pip install -e .)
|
|
47
|
+
abom scan . # → abom.json (signed with ed25519)
|
|
48
|
+
abom verify abom.json # check signature
|
|
49
|
+
abom verify abom.json --policy policy.json # + enforce a policy (exit 1 on violations)
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Commands
|
|
53
|
+
|
|
54
|
+
| Command | What it does |
|
|
55
|
+
|---|---|
|
|
56
|
+
| `abom scan [PATH]` | Detect agent components (models, prompts, tools, MCP servers, frameworks, vector stores, guardrails) and emit a signed Composition Manifest. `-o -` writes to stdout. |
|
|
57
|
+
| `abom verify [FILE]` | Verify the ed25519 signature; with `--policy`, enforce model allowlist / residency / egress / approval rules. Non-zero exit on findings (CI-friendly). |
|
|
58
|
+
| `abom keygen` | Show (or create) the local ed25519 signing key (`~/.abom/signing_key.pem`, override with `ABOM_KEY`). |
|
|
59
|
+
| `abom version` | Print the tool and spec versions. |
|
|
60
|
+
|
|
61
|
+
### Example
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
$ abom scan .
|
|
65
|
+
ABOM · my-agent @ 1.2.0
|
|
66
|
+
models 3 gpt-4o-mini, claude-3-5-sonnet, OpenAI (SDK)
|
|
67
|
+
frameworks 2 LangChain, LangGraph
|
|
68
|
+
MCP servers 2 filesystem, github
|
|
69
|
+
tools 1 lookup_customer
|
|
70
|
+
prompts 1 prompts/system.txt
|
|
71
|
+
signed: ed25519 · key 5846eabc738b3542
|
|
72
|
+
→ wrote abom.json
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## How detection works
|
|
76
|
+
|
|
77
|
+
`abom scan` is a static scanner (pure stdlib + `cryptography`):
|
|
78
|
+
- **Dependencies** (`requirements*.txt`, `pyproject.toml`, `package.json`) → frameworks, model SDKs, vector stores, guardrails.
|
|
79
|
+
- **Source** → concrete model names (`gpt-4o`, `claude-*`, …) and `@tool`-decorated functions.
|
|
80
|
+
- **Prompt files** (`*.prompt`, `prompts/*.txt|md`) → hashed.
|
|
81
|
+
- **MCP configs** (`mcp.json`, `claude_desktop_config.json`, …) → MCP servers.
|
|
82
|
+
|
|
83
|
+
Each component records `detected_from` so the manifest is auditable. The output
|
|
84
|
+
validates against [`spec/abom-0.1.schema.json`](../spec/abom-0.1.schema.json).
|
|
85
|
+
|
|
86
|
+
## Signing
|
|
87
|
+
|
|
88
|
+
`abom scan` signs with **ed25519** (`cryptography`). The key lives at
|
|
89
|
+
`~/.abom/signing_key.pem` (override with `ABOM_KEY`); the public key + a short
|
|
90
|
+
`key_id` are embedded so `abom verify` is self-contained. A Notary / key registry
|
|
91
|
+
pins trusted key ids in production.
|
|
92
|
+
|
|
93
|
+
## Dev
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
make install # pip install -e ".[dev]"
|
|
97
|
+
make test # pytest (audit chain, scanner, signing)
|
|
98
|
+
make scan && make verify
|
|
99
|
+
make build # wheel + sdist + twine check
|
|
100
|
+
python demo/demo.py # generate → verify → tamper-evidence walkthrough
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## What else is in this package
|
|
104
|
+
|
|
105
|
+
`src/abom/` also contains a **prototype control-plane** (`api.py`, `db.py`,
|
|
106
|
+
`orchestration.py`, the Notary) behind the optional `[server]` extra — the
|
|
107
|
+
beginnings of the commercial layer. It is **not** required for `scan`/`verify`
|
|
108
|
+
and is not part of the v0.1 spec. See [MVP_SPEC.md](MVP_SPEC.md).
|
abom_cli-0.1.0/README.md
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# abom-cli
|
|
2
|
+
|
|
3
|
+
The reference implementation of [ABOM](../spec/) — the Agent Bill of Materials.
|
|
4
|
+
Scan a repo, emit a **signed** Composition Manifest, and **verify** it.
|
|
5
|
+
|
|
6
|
+
```bash
|
|
7
|
+
pip install abom-cli # (until published: pip install -e .)
|
|
8
|
+
abom scan . # → abom.json (signed with ed25519)
|
|
9
|
+
abom verify abom.json # check signature
|
|
10
|
+
abom verify abom.json --policy policy.json # + enforce a policy (exit 1 on violations)
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Commands
|
|
14
|
+
|
|
15
|
+
| Command | What it does |
|
|
16
|
+
|---|---|
|
|
17
|
+
| `abom scan [PATH]` | Detect agent components (models, prompts, tools, MCP servers, frameworks, vector stores, guardrails) and emit a signed Composition Manifest. `-o -` writes to stdout. |
|
|
18
|
+
| `abom verify [FILE]` | Verify the ed25519 signature; with `--policy`, enforce model allowlist / residency / egress / approval rules. Non-zero exit on findings (CI-friendly). |
|
|
19
|
+
| `abom keygen` | Show (or create) the local ed25519 signing key (`~/.abom/signing_key.pem`, override with `ABOM_KEY`). |
|
|
20
|
+
| `abom version` | Print the tool and spec versions. |
|
|
21
|
+
|
|
22
|
+
### Example
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
$ abom scan .
|
|
26
|
+
ABOM · my-agent @ 1.2.0
|
|
27
|
+
models 3 gpt-4o-mini, claude-3-5-sonnet, OpenAI (SDK)
|
|
28
|
+
frameworks 2 LangChain, LangGraph
|
|
29
|
+
MCP servers 2 filesystem, github
|
|
30
|
+
tools 1 lookup_customer
|
|
31
|
+
prompts 1 prompts/system.txt
|
|
32
|
+
signed: ed25519 · key 5846eabc738b3542
|
|
33
|
+
→ wrote abom.json
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## How detection works
|
|
37
|
+
|
|
38
|
+
`abom scan` is a static scanner (pure stdlib + `cryptography`):
|
|
39
|
+
- **Dependencies** (`requirements*.txt`, `pyproject.toml`, `package.json`) → frameworks, model SDKs, vector stores, guardrails.
|
|
40
|
+
- **Source** → concrete model names (`gpt-4o`, `claude-*`, …) and `@tool`-decorated functions.
|
|
41
|
+
- **Prompt files** (`*.prompt`, `prompts/*.txt|md`) → hashed.
|
|
42
|
+
- **MCP configs** (`mcp.json`, `claude_desktop_config.json`, …) → MCP servers.
|
|
43
|
+
|
|
44
|
+
Each component records `detected_from` so the manifest is auditable. The output
|
|
45
|
+
validates against [`spec/abom-0.1.schema.json`](../spec/abom-0.1.schema.json).
|
|
46
|
+
|
|
47
|
+
## Signing
|
|
48
|
+
|
|
49
|
+
`abom scan` signs with **ed25519** (`cryptography`). The key lives at
|
|
50
|
+
`~/.abom/signing_key.pem` (override with `ABOM_KEY`); the public key + a short
|
|
51
|
+
`key_id` are embedded so `abom verify` is self-contained. A Notary / key registry
|
|
52
|
+
pins trusted key ids in production.
|
|
53
|
+
|
|
54
|
+
## Dev
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
make install # pip install -e ".[dev]"
|
|
58
|
+
make test # pytest (audit chain, scanner, signing)
|
|
59
|
+
make scan && make verify
|
|
60
|
+
make build # wheel + sdist + twine check
|
|
61
|
+
python demo/demo.py # generate → verify → tamper-evidence walkthrough
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## What else is in this package
|
|
65
|
+
|
|
66
|
+
`src/abom/` also contains a **prototype control-plane** (`api.py`, `db.py`,
|
|
67
|
+
`orchestration.py`, the Notary) behind the optional `[server]` extra — the
|
|
68
|
+
beginnings of the commercial layer. It is **not** required for `scan`/`verify`
|
|
69
|
+
and is not part of the v0.1 spec. See [MVP_SPEC.md](MVP_SPEC.md).
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
apiVersion: v2
|
|
2
|
+
name: abom
|
|
3
|
+
description: ABOM — production control plane for agentic AI (MVP Helm stub)
|
|
4
|
+
type: application
|
|
5
|
+
version: 0.1.0
|
|
6
|
+
appVersion: "0.1.0"
|
|
7
|
+
# MVP stub. Real chart adds: Operator CRDs, Temporal subchart, vLLM/KServe
|
|
8
|
+
# serving, NetworkPolicies (zero egress), Vault integration, OTel collector,
|
|
9
|
+
# and an offline/air-gap values overlay.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# MVP stub values. The production chart enforces sovereignty defaults
|
|
2
|
+
# (egressPolicy: deny-all, airgap mode, signed images only).
|
|
3
|
+
|
|
4
|
+
image:
|
|
5
|
+
repository: ghcr.io/abom/abom
|
|
6
|
+
tag: "0.1.0"
|
|
7
|
+
pullPolicy: IfNotPresent
|
|
8
|
+
|
|
9
|
+
api:
|
|
10
|
+
replicas: 2
|
|
11
|
+
port: 8000
|
|
12
|
+
|
|
13
|
+
worker:
|
|
14
|
+
replicas: 2
|
|
15
|
+
|
|
16
|
+
postgres:
|
|
17
|
+
# In prod, use CloudNativePG / customer-managed Postgres.
|
|
18
|
+
url: "postgresql+asyncpg://abom:abom@abom-postgres:5432/abom"
|
|
19
|
+
|
|
20
|
+
temporal:
|
|
21
|
+
host: "abom-temporal:7233"
|
|
22
|
+
namespace: default
|
|
23
|
+
|
|
24
|
+
modelServing:
|
|
25
|
+
# vLLM on customer GPUs (KServe in prod).
|
|
26
|
+
baseUrl: "http://abom-vllm:8000/v1"
|
|
27
|
+
model: "local/qwen2.5-coder"
|
|
28
|
+
|
|
29
|
+
sovereignty:
|
|
30
|
+
airgap: false # true => no managed control channel, offline updates only
|
|
31
|
+
egressPolicy: deny-all # NetworkPolicy posture; egress only via gated gateway
|
|
32
|
+
requireSignedImages: true
|
|
33
|
+
|
|
34
|
+
audit:
|
|
35
|
+
retentionDays: 3650
|
|
36
|
+
wormCopy: false # Phase-2: WORM object copy + periodic anchoring
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# ABOM demo — generate · verify · prove tamper-evidence
|
|
2
|
+
|
|
3
|
+
This is the demonstration that matters for ABOM: it generates an **Agent Bill of
|
|
4
|
+
Materials** for an agent run and shows **abom-verify** catching real policy
|
|
5
|
+
violations a raw log would let ship silently — then proves the record can't be
|
|
6
|
+
quietly scrubbed.
|
|
7
|
+
|
|
8
|
+
## Run it
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
cd cli
|
|
12
|
+
python3 demo/demo.py # or: make demo
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
No infrastructure required — no Temporal, Postgres, GPU. The model is a
|
|
16
|
+
deterministic mock; the **test gate is a real subprocess**, and the **signing,
|
|
17
|
+
hash-chaining, and policy verification are real** ([../src/abom/bom.py](../src/abom/bom.py),
|
|
18
|
+
[../src/abom/audit.py](../src/abom/audit.py)).
|
|
19
|
+
|
|
20
|
+
## What it does
|
|
21
|
+
|
|
22
|
+
It emits one signed **Composition Manifest** (what the agent is made of) and runs
|
|
23
|
+
an agent two ways, each producing a hash-chained **Action Provenance** chain
|
|
24
|
+
(what the agent did), then runs **abom-verify**:
|
|
25
|
+
|
|
26
|
+
| Run | What happens | abom-verify |
|
|
27
|
+
|---|---|---|
|
|
28
|
+
| **Compliant** | approved model, no bad egress, consequential action approved | **CLEAN** — 0 findings |
|
|
29
|
+
| **Violating** | shadow (unapproved) model, confidential data egressed to an unapproved endpoint, consequential action with no approval | **BLOCKED** — 5 findings |
|
|
30
|
+
|
|
31
|
+
The five findings on the violating run: `model_allowlist`, `composition_drift`,
|
|
32
|
+
`approval_coverage`, `residency`, `egress_allowlist`.
|
|
33
|
+
|
|
34
|
+
Then it tampers — edits the provenance record to **erase the egress** — and shows
|
|
35
|
+
the hash chain breaks (`chain_integrity` finding), so the evidence can't be
|
|
36
|
+
silently scrubbed.
|
|
37
|
+
|
|
38
|
+
## Expected output
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
abom-verify [compliant]: CLEAN ✓ over 2 actions
|
|
42
|
+
abom-verify [violating]: BLOCKED ✗ (5 findings) over 2 actions
|
|
43
|
+
• [high] model_allowlist (seq 0): unapproved model used: external/gpt-4o
|
|
44
|
+
• [high] composition_drift (seq 0): runtime model not in signed manifest: external/gpt-4o
|
|
45
|
+
• [high] approval_coverage (seq 0): consequential action without approval
|
|
46
|
+
• [high] residency (seq 1): confidential data egressed
|
|
47
|
+
• [medium] egress_allowlist (seq 1): egress to unapproved endpoint: telemetry.vendor.example
|
|
48
|
+
scrubbing the record → chain integrity: BROKEN (detected)
|
|
49
|
+
✓ DEMO ASSERTIONS PASSED
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Artifacts (written to `demo/out/`)
|
|
53
|
+
|
|
54
|
+
- `composition.json` — the signed Composition Manifest.
|
|
55
|
+
- `provenance_compliant.json` / `provenance_violating.json` — the hash-chained Action Provenance chains.
|
|
56
|
+
- `verify.json` — the machine-checkable abom-verify results.
|
|
57
|
+
|
|
58
|
+
## What this proves — and what it doesn't
|
|
59
|
+
|
|
60
|
+
It proves the four ABOM mechanics: **composition** is captured and signed,
|
|
61
|
+
**provenance** is recorded and tamper-evident, **verify** catches policy
|
|
62
|
+
violations that would otherwise ship silently, and scrubbing the evidence is
|
|
63
|
+
**detected**.
|
|
64
|
+
|
|
65
|
+
It does **not** prove capture *completeness* — here the actions are supplied by
|
|
66
|
+
the demo. The real product earns completeness by generating from inside the agent
|
|
67
|
+
runtime / control plane (see the project docs (kept private) §3.2),
|
|
68
|
+
which is the next thing to build and the metric to put in front of a design
|
|
69
|
+
partner.
|