@zanii/cli 0.1.0 → 0.2.0

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.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @zanii/cli
2
2
 
3
- The Zanii command line — generate identities, sign delegations, record and verify
3
+ The Zanii command line: generate identities, sign delegations, record and verify
4
4
  proofs, and export audit bundles from the terminal, no code required.
5
5
 
6
6
  ```sh
@@ -19,19 +19,64 @@ zanii delegate --owner owner.json --to <agent-did> \
19
19
  zanii verify <hash> # fetch + verify a proof, offline (exit 1 if it fails)
20
20
  zanii bundle bundle.json # verify an exported audit bundle, offline
21
21
  zanii export <did> --out bundle.json # download an agent's full history
22
+ zanii audit <tag> --out evidence.json # audit a data subject's slice; writes the evidence bundle
23
+ zanii audit <tag> --bundle evidence.json # offline audit of a bundle: zero network calls
22
24
  zanii stats # ledger counters
23
25
  zanii agent <did> # an agent's trust summary
24
26
  ```
25
27
 
26
28
  Global flags: `--server <url>` (or `ZANII_SERVER`; default `https://ledger.zanii.agency`)
27
- and `--json` for machine-readable output on any command. `verify` / `bundle` exit
28
- non-zero on failure, so they drop straight into CI.
29
+ and `--json` for machine-readable output on any command. `verify` / `bundle` / `audit`
30
+ exit non-zero on failure, so they drop straight into CI.
31
+
32
+ ## Auditing a data subject (the offline third party)
33
+
34
+ `zanii audit <tag>` fetches the subject's receipt slice (`GET /v1/subjects/{tag}`),
35
+ verifies every receipt **offline** (signature, delegation, scope, via
36
+ `@zanii/subject`), and prints the five custody verdict rows computed by
37
+ `computeVerdicts` from `@zanii/custody-verdicts`, the exact function the subject
38
+ page calls, never a second implementation. The four states print unmistakably
39
+ (`✓ PROVEN` / `○ NOT COVERED` / `✘ FAILED` / `? CANNOT DETERMINE`) with each row's
40
+ detail string verbatim; a `not covered` row never claims "never". Exit code is `1`
41
+ when any row is `failed`, else `0`; auditors script this.
42
+
43
+ With `--out <file>` the run also writes the **evidence bundle**:
44
+
45
+ ```json
46
+ {
47
+ "v": 1,
48
+ "tag": "<subject tag>",
49
+ "server": "https://ledger.zanii.agency",
50
+ "fetched_at": "<ISO8601>",
51
+ "receipts": [{ "receipt": { "…": "as served, custody payload embedded" }, "hash": "…", "index": 0 }],
52
+ "sth": { "…": "signed tree head as served" }
53
+ }
54
+ ```
55
+
56
+ ### The offline recipe: verify with networking disabled
57
+
58
+ ```sh
59
+ # 1. on a networked machine: download the bundle (or export it from the subject page)
60
+ zanii audit <tag> --out evidence.json
61
+
62
+ # 2. disable networking (airplane mode, firewall, air-gapped machine), then:
63
+ zanii audit <tag> --bundle evidence.json
64
+ ```
65
+
66
+ Offline mode serves the bundle to the same `fetchSubjectHistory` verifier through
67
+ an inert `fetchImpl`: the identical receipt-verification code runs in both modes,
68
+ and any attempted network call fails the run. The output prints
69
+ `offline: 0 network calls` as the assertion. Compare the rows with the subject
70
+ page: they must be identical. `--out` is live-mode-only (the bundle is the input)
71
+ and `--bundle` always requires a file. Both mistakes are usage errors, never
72
+ silent fallbacks.
29
73
 
30
74
  Also exported as a library: `import { run } from '@zanii/cli'`.
31
75
 
32
76
  ## Changelog
33
77
 
34
- - **0.1.0** — initial release: `keygen`, `did`, `delegate`, `revoke`, `verify`, `bundle`, `export`, `stats`, `agent`.
78
+ - **0.2.0**: `audit`: live + offline (zero-network) data-subject audits over evidence bundles, via `@zanii/subject` + `@zanii/custody-verdicts`.
79
+ - **0.1.0**: initial release: `keygen`, `did`, `delegate`, `revoke`, `verify`, `bundle`, `export`, `stats`, `agent`.
35
80
 
36
81
  ## License
37
82
 
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAUA,MAAM,MAAM,SAAS,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;AA4CjF,wBAAsB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,GAAE;IAAE,GAAG,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAAC,SAAS,CAAC,EAAE,SAAS,CAAA;CAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAkF1H"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAaA,MAAM,MAAM,SAAS,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;AA2IjF,wBAAsB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,GAAE;IAAE,GAAG,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAAC,SAAS,CAAC,EAAE,SAAS,CAAA;CAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAwJ1H"}
package/dist/index.js CHANGED
@@ -1,14 +1,77 @@
1
1
  /**
2
- * @zanii/cli — the Zanii command line. Generate identities, sign delegations,
2
+ * @zanii/cli: the Zanii command line. Generate identities, sign delegations,
3
3
  * record + verify proofs, and export audit bundles from the terminal, no code.
4
4
  *
5
5
  * `run()` is exported and testable; the `zanii` bin just calls it with process.argv.
6
6
  */
7
7
  import { readFileSync, writeFileSync } from 'node:fs';
8
8
  import { createCert, createRevocation, generateKeypair, verifyAuditBundle } from '@zanii/core';
9
+ import { computeVerdicts } from '@zanii/custody-verdicts';
9
10
  import { fetchAndVerifyProof } from '@zanii/sdk';
11
+ import { fetchSubjectHistory } from '@zanii/subject';
12
+ import { proveAbsence } from '@zanii/train';
10
13
  const hex = (b) => Buffer.from(b).toString('hex');
11
14
  const unhex = (s) => new Uint8Array(Buffer.from(s, 'hex'));
15
+ function asPayload(p) {
16
+ return p !== null && typeof p === 'object' && !Array.isArray(p)
17
+ ? p
18
+ : undefined;
19
+ }
20
+ function buildExtraEvidence(manifestHistory, tag, reader) {
21
+ const extra = {};
22
+ if (reader.jurisdiction)
23
+ extra.jurisdiction = reader.jurisdiction;
24
+ if (reader.declaredSubprocessors)
25
+ extra.declaredSubprocessors = reader.declaredSubprocessors;
26
+ if (reader.trustedSigners) {
27
+ // Reader-side trust root for coverage attestations. A partial CoverageEvidence
28
+ // object is honest: without a signed attestation the row stays not-covered.
29
+ extra.coverage = { trustedSigners: reader.trustedSigners };
30
+ }
31
+ const declarations = manifestHistory.receipts
32
+ .map((sr) => ({ sr, payload: asPayload(sr.receipt.payload) }))
33
+ .filter((x) => x.payload?.type === 'training.manifest.declaration');
34
+ if (declarations.length === 0)
35
+ return extra;
36
+ const latest = declarations
37
+ .slice()
38
+ .sort((a, b) => Date.parse(b.sr.receipt.ts) - Date.parse(a.sr.receipt.ts))[0];
39
+ if (!latest)
40
+ return extra;
41
+ const payload = latest.payload;
42
+ const manifest = asPayload(payload.manifest);
43
+ if (!manifest || manifest.v !== 1 || manifest.type !== 'training.manifest')
44
+ return extra;
45
+ const refs = Array.isArray(payload.refs)
46
+ ? payload.refs
47
+ : manifest.size === 0
48
+ ? []
49
+ : undefined;
50
+ if (refs === undefined)
51
+ return extra;
52
+ try {
53
+ const absenceProof = proveAbsence(manifest, refs, tag);
54
+ const anchoredAt = latest.sr.receipt.ts;
55
+ const training = {
56
+ manifest,
57
+ anchoredAt,
58
+ runAttestedAt: anchoredAt,
59
+ absenceProof,
60
+ };
61
+ extra.training = training;
62
+ }
63
+ catch {
64
+ // If training evidence cannot be built, honestly omit it.
65
+ }
66
+ return extra;
67
+ }
68
+ /** The four verdict states, unmistakable in a terminal. Detail strings print verbatim. */
69
+ const STATE_MARK = {
70
+ proven: '✓ PROVEN',
71
+ 'not covered': '○ NOT COVERED',
72
+ failed: '✘ FAILED',
73
+ 'cannot determine': '? CANNOT DETERMINE',
74
+ };
12
75
  function parse(args) {
13
76
  const positional = [];
14
77
  const flags = {};
@@ -28,7 +91,13 @@ function parse(args) {
28
91
  }
29
92
  return { positional, flags };
30
93
  }
31
- const HELP = `zanii — verifiable identity & proof-of-action for AI agents
94
+ function parseList(flag) {
95
+ if (typeof flag !== 'string' || !flag)
96
+ return undefined;
97
+ const parts = flag.split(',').map((s) => s.trim()).filter(Boolean);
98
+ return parts.length > 0 ? parts : undefined;
99
+ }
100
+ const HELP = `zanii: verifiable identity & proof-of-action for AI agents
32
101
 
33
102
  zanii keygen [--out identity.json] generate an agent identity (did:key)
34
103
  zanii did <identity.json> print an identity's DID
@@ -38,6 +107,9 @@ const HELP = `zanii — verifiable identity & proof-of-action for AI agents
38
107
  zanii verify <hash> [--server <url>] fetch + verify a proof, offline
39
108
  zanii bundle <bundle.json> verify an audit bundle, offline
40
109
  zanii export <did> [--server <url>] [--out bundle.json]
110
+ zanii audit <tag> [--out bundle.json] audit a data subject's slice; writes the evidence bundle
111
+ (8 custody verdict rows; pass --jurisdiction, --declared-subprocessors, --trusted-signers)
112
+ zanii audit <tag> --bundle <file> offline audit of a bundle: zero network calls
41
113
  zanii stats [--server <url>] ledger counters
42
114
  zanii agent <did> [--server <url>] an agent's trust summary
43
115
 
@@ -63,10 +135,10 @@ export async function run(argv, opts = {}) {
63
135
  const id = { did: kp.did, privateKey: hex(kp.privateKey), publicKey: hex(kp.publicKey) };
64
136
  if (out) {
65
137
  writeFileSync(out, JSON.stringify(id, null, 2));
66
- ctx.log(`identity written to ${out} — keep the private key secret`);
138
+ ctx.log(`identity written to ${out}. Keep the private key secret`);
67
139
  }
68
140
  else
69
- emit(id, `did: ${id.did}\nprivateKey: ${id.privateKey} (secret — store securely)`);
141
+ emit(id, `did: ${id.did}\nprivateKey: ${id.privateKey} (secret, store securely)`);
70
142
  return 0;
71
143
  }
72
144
  case 'did': {
@@ -119,6 +191,90 @@ export async function run(argv, opts = {}) {
119
191
  ctx.log(JSON.stringify(bundle));
120
192
  return 0;
121
193
  }
194
+ case 'audit': {
195
+ const tag = positional[0];
196
+ if (!tag)
197
+ throw new Error('usage: zanii audit <tag> [--out bundle.json] or zanii audit <tag> --bundle <file>');
198
+ // A valueless or empty --bundle must NEVER fall through to the live, networked
199
+ // path. parse() is equals-blind (`--bundle=<file>` lands in flags literally
200
+ // named "bundle=<file>"), so scan the raw argv for the equals form, here only.
201
+ const eqForm = rest.find((a) => a.startsWith('--bundle='));
202
+ const eqFile = eqForm === undefined ? undefined : eqForm.slice('--bundle='.length);
203
+ if (eqForm !== undefined && !eqFile)
204
+ throw new Error('usage: zanii audit <tag> --bundle <file>: --bundle requires a bundle file');
205
+ if (flags.bundle === true || flags.bundle === '')
206
+ throw new Error('usage: zanii audit <tag> --bundle <file>: --bundle requires a bundle file');
207
+ const bundleFile = (typeof flags.bundle === 'string' ? flags.bundle : undefined) ?? eqFile;
208
+ const jurisdiction = parseList(flags.jurisdiction);
209
+ const declaredSubprocessors = parseList(flags['declared-subprocessors']);
210
+ const trustedSigners = parseList(flags['trusted-signers']);
211
+ let rows;
212
+ let note;
213
+ let payload;
214
+ if (bundleFile) {
215
+ // Offline mode: the bundle is served to fetchSubjectHistory through an inert
216
+ // fetchImpl, so the SAME receipt-verification code runs as in the live path.
217
+ // Zero network is enforced, not trusted: the fetchImpl only answers the
218
+ // sentinel bundle origin; any other URL throws, failing the run.
219
+ if (out)
220
+ throw new Error('--out cannot be combined with --bundle');
221
+ let b;
222
+ try {
223
+ b = JSON.parse(readFileSync(bundleFile, 'utf8'));
224
+ }
225
+ catch (e) {
226
+ throw new Error(`cannot read evidence bundle ${bundleFile}: ${e instanceof Error ? e.message : String(e)}`);
227
+ }
228
+ if (b?.v !== 1 || typeof b?.tag !== 'string' || !Array.isArray(b?.receipts))
229
+ throw new Error(`${bundleFile} is not a v1 evidence bundle`);
230
+ if (b.tag !== tag)
231
+ throw new Error(`bundle is for tag ${b.tag}, not ${tag}`);
232
+ const ORIGIN = 'offline://bundle';
233
+ let networkCalls = 0;
234
+ const offlineFetch = async (input) => {
235
+ const url = String(input);
236
+ if (!url.startsWith(`${ORIGIN}/`)) {
237
+ networkCalls++;
238
+ throw new Error(`offline audit attempted a network call: ${url}`);
239
+ }
240
+ return new Response(JSON.stringify({ receipts: b.receipts, sth: b.sth ?? undefined }), { status: 200 });
241
+ };
242
+ const history = await fetchSubjectHistory(tag, { server: ORIGIN, fetchImpl: offlineFetch })
243
+ ?? { tag, receipts: [], verified: true, failures: [] };
244
+ if (networkCalls !== 0)
245
+ throw new Error(`offline audit made ${networkCalls} network call(s)`);
246
+ const extra = b.extra ?? {};
247
+ rows = await computeVerdicts(history, extra);
248
+ note = `offline: 0 network calls, verified against ${bundleFile} alone (fetched at ${b.fetched_at} from ${b.server}); the rows must match the subject page exactly`;
249
+ payload = { mode: 'offline', tag, bundle: bundleFile, networkCalls, rows, extra };
250
+ }
251
+ else {
252
+ const history = await fetchSubjectHistory(tag, { server, fetchImpl: ctx.fetchImpl })
253
+ ?? { tag, receipts: [], verified: true, failures: [] };
254
+ const manifestHistory = await fetchSubjectHistory('zanii:training-manifests', { server, fetchImpl: ctx.fetchImpl })
255
+ ?? { tag: 'zanii:training-manifests', receipts: [], verified: true, failures: [] };
256
+ const extra = buildExtraEvidence(manifestHistory, tag, { jurisdiction, declaredSubprocessors, trustedSigners });
257
+ if (history.receipts.length === 0)
258
+ ctx.log(`no receipts on ${server} for tag ${tag}`);
259
+ const bundle = {
260
+ v: 1, tag, server, fetched_at: new Date().toISOString(),
261
+ receipts: history.receipts.map(({ receipt, hash, index }) => ({ receipt, hash, index })),
262
+ sth: history.sth ?? null,
263
+ extra,
264
+ };
265
+ rows = await computeVerdicts(history, extra);
266
+ if (out) {
267
+ writeFileSync(out, JSON.stringify(bundle, null, 2));
268
+ note = `evidence bundle written to ${out}. Audit it offline later with: zanii audit ${tag} --bundle ${out}`;
269
+ }
270
+ else
271
+ note = JSON.stringify(bundle);
272
+ payload = { mode: 'live', tag, rows, bundle };
273
+ }
274
+ const human = rows.map((r) => `${STATE_MARK[r.state]} · ${r.label}\n ${r.detail}`).join('\n') + `\n${note}`;
275
+ emit(payload, human);
276
+ return rows.some((r) => r.state === 'failed') ? 1 : 0;
277
+ }
122
278
  case 'stats': {
123
279
  const s = await get('/v1/stats');
124
280
  emit(s, `${s.receipts} proofs · ${s.agents} agents · ${s.anchors} anchors`);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@zanii/cli",
3
- "version": "0.1.0",
4
- "description": "The Zanii command line: generate identities, sign delegations, record + verify proofs, and export audit bundles — no code required.",
3
+ "version": "0.2.0",
4
+ "description": "The Zanii command line: generate identities, sign delegations, record + verify proofs, and export audit bundles, no code required.",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://ledger.zanii.agency",
7
7
  "type": "module",
@@ -29,14 +29,23 @@
29
29
  "node": ">=18"
30
30
  },
31
31
  "dependencies": {
32
- "@zanii/core": "0.2.0",
33
- "@zanii/sdk": "0.2.1"
32
+ "@zanii/core": "0.4.0",
33
+ "@zanii/minimization": "0.1.1",
34
+ "@zanii/custody-verdicts": "0.1.0",
35
+ "@zanii/sdk": "0.4.0",
36
+ "@zanii/residency": "0.2.0",
37
+ "@zanii/subprocessor": "0.2.0",
38
+ "@zanii/train": "0.2.0",
39
+ "@zanii/subject": "0.1.1"
34
40
  },
35
41
  "devDependencies": {
42
+ "@noble/curves": "^1.8.1",
43
+ "@noble/hashes": "^1.7.1",
36
44
  "@types/node": "^26.1.0",
45
+ "@zanii/data-custody": "^0.1.0",
37
46
  "typescript": "^5.8.2",
38
47
  "vitest": "^3.0.9",
39
- "@zanii/testing": "0.1.0"
48
+ "@zanii/testing": "0.1.1"
40
49
  },
41
50
  "scripts": {
42
51
  "build": "tsc -p tsconfig.build.json",
package/src/index.ts CHANGED
@@ -1,12 +1,15 @@
1
1
  /**
2
- * @zanii/cli — the Zanii command line. Generate identities, sign delegations,
2
+ * @zanii/cli: the Zanii command line. Generate identities, sign delegations,
3
3
  * record + verify proofs, and export audit bundles from the terminal, no code.
4
4
  *
5
5
  * `run()` is exported and testable; the `zanii` bin just calls it with process.argv.
6
6
  */
7
7
  import { readFileSync, writeFileSync } from 'node:fs';
8
- import { createCert, createRevocation, generateKeypair, verifyAuditBundle } from '@zanii/core';
8
+ import { createCert, createRevocation, generateKeypair, verifyAuditBundle, type Receipt } from '@zanii/core';
9
+ import { computeVerdicts, type ExtraEvidence, type TrainingEvidence, type CoverageEvidence, type VerdictRow, type VerdictState } from '@zanii/custody-verdicts';
9
10
  import { fetchAndVerifyProof } from '@zanii/sdk';
11
+ import { fetchSubjectHistory, type SubjectHistory } from '@zanii/subject';
12
+ import { proveAbsence, type TrainingManifest } from '@zanii/train';
10
13
 
11
14
  export type FetchLike = (input: string, init?: RequestInit) => Promise<Response>;
12
15
 
@@ -24,6 +27,92 @@ interface IdentityFile {
24
27
  publicKey?: string;
25
28
  }
26
29
 
30
+ /**
31
+ * The custody evidence bundle: exactly what the subject page emits and what
32
+ * `audit --bundle` consumes. `receipts`/`sth` are the `GET /v1/subjects/{tag}`
33
+ * body as served (receipts carry their custody payloads embedded); the rest is
34
+ * provenance. Never strip or recompute fields: the offline audit re-verifies
35
+ * the bundle through the same code path as the live fetch.
36
+ */
37
+ interface EvidenceBundle {
38
+ v: 1;
39
+ tag: string;
40
+ server: string;
41
+ fetched_at: string; // ISO8601
42
+ receipts: Array<{ receipt: Receipt; hash: string; index: number }>;
43
+ sth?: Record<string, unknown> | null;
44
+ extra?: ExtraEvidence;
45
+ }
46
+
47
+ type ReceiptWithPayload = Receipt & { payload?: unknown };
48
+
49
+ function asPayload(p: unknown): Record<string, unknown> | undefined {
50
+ return p !== null && typeof p === 'object' && !Array.isArray(p)
51
+ ? (p as Record<string, unknown>)
52
+ : undefined;
53
+ }
54
+
55
+ function buildExtraEvidence(
56
+ manifestHistory: SubjectHistory,
57
+ tag: string,
58
+ reader: { jurisdiction?: string[]; declaredSubprocessors?: string[]; trustedSigners?: string[] },
59
+ ): ExtraEvidence {
60
+ const extra: ExtraEvidence = {};
61
+ if (reader.jurisdiction) extra.jurisdiction = reader.jurisdiction;
62
+ if (reader.declaredSubprocessors) extra.declaredSubprocessors = reader.declaredSubprocessors;
63
+ if (reader.trustedSigners) {
64
+ // Reader-side trust root for coverage attestations. A partial CoverageEvidence
65
+ // object is honest: without a signed attestation the row stays not-covered.
66
+ extra.coverage = { trustedSigners: reader.trustedSigners } as CoverageEvidence;
67
+ }
68
+
69
+ const declarations = manifestHistory.receipts
70
+ .map((sr) => ({ sr, payload: asPayload((sr.receipt as ReceiptWithPayload).payload) }))
71
+ .filter((x): x is { sr: typeof manifestHistory.receipts[0]; payload: Record<string, unknown> } => x.payload?.type === 'training.manifest.declaration');
72
+
73
+ if (declarations.length === 0) return extra;
74
+
75
+ const latest = declarations
76
+ .slice()
77
+ .sort((a, b) => Date.parse(b.sr.receipt.ts) - Date.parse(a.sr.receipt.ts))[0];
78
+ if (!latest) return extra;
79
+
80
+ const payload = latest.payload;
81
+ const manifest = asPayload(payload.manifest) as TrainingManifest | undefined;
82
+ if (!manifest || manifest.v !== 1 || manifest.type !== 'training.manifest') return extra;
83
+
84
+ const refs: string[] | undefined = Array.isArray(payload.refs)
85
+ ? (payload.refs as string[])
86
+ : manifest.size === 0
87
+ ? []
88
+ : undefined;
89
+ if (refs === undefined) return extra;
90
+
91
+ try {
92
+ const absenceProof = proveAbsence(manifest, refs, tag);
93
+ const anchoredAt = latest.sr.receipt.ts;
94
+ const training: TrainingEvidence = {
95
+ manifest,
96
+ anchoredAt,
97
+ runAttestedAt: anchoredAt,
98
+ absenceProof,
99
+ };
100
+ extra.training = training;
101
+ } catch {
102
+ // If training evidence cannot be built, honestly omit it.
103
+ }
104
+
105
+ return extra;
106
+ }
107
+
108
+ /** The four verdict states, unmistakable in a terminal. Detail strings print verbatim. */
109
+ const STATE_MARK: Record<VerdictState, string> = {
110
+ proven: '✓ PROVEN',
111
+ 'not covered': '○ NOT COVERED',
112
+ failed: '✘ FAILED',
113
+ 'cannot determine': '? CANNOT DETERMINE',
114
+ };
115
+
27
116
  function parse(args: string[]): { positional: string[]; flags: Record<string, string | boolean> } {
28
117
  const positional: string[] = [];
29
118
  const flags: Record<string, string | boolean> = {};
@@ -37,7 +126,13 @@ function parse(args: string[]): { positional: string[]; flags: Record<string, st
37
126
  return { positional, flags };
38
127
  }
39
128
 
40
- const HELP = `zanii — verifiable identity & proof-of-action for AI agents
129
+ function parseList(flag: unknown): string[] | undefined {
130
+ if (typeof flag !== 'string' || !flag) return undefined;
131
+ const parts = flag.split(',').map((s) => s.trim()).filter(Boolean);
132
+ return parts.length > 0 ? parts : undefined;
133
+ }
134
+
135
+ const HELP = `zanii: verifiable identity & proof-of-action for AI agents
41
136
 
42
137
  zanii keygen [--out identity.json] generate an agent identity (did:key)
43
138
  zanii did <identity.json> print an identity's DID
@@ -47,6 +142,9 @@ const HELP = `zanii — verifiable identity & proof-of-action for AI agents
47
142
  zanii verify <hash> [--server <url>] fetch + verify a proof, offline
48
143
  zanii bundle <bundle.json> verify an audit bundle, offline
49
144
  zanii export <did> [--server <url>] [--out bundle.json]
145
+ zanii audit <tag> [--out bundle.json] audit a data subject's slice; writes the evidence bundle
146
+ (8 custody verdict rows; pass --jurisdiction, --declared-subprocessors, --trusted-signers)
147
+ zanii audit <tag> --bundle <file> offline audit of a bundle: zero network calls
50
148
  zanii stats [--server <url>] ledger counters
51
149
  zanii agent <did> [--server <url>] an agent's trust summary
52
150
 
@@ -71,8 +169,8 @@ export async function run(argv: string[], opts: { log?: (s: string) => void; fet
71
169
  case 'keygen': {
72
170
  const kp = generateKeypair();
73
171
  const id: IdentityFile = { did: kp.did, privateKey: hex(kp.privateKey), publicKey: hex(kp.publicKey) };
74
- if (out) { writeFileSync(out, JSON.stringify(id, null, 2)); ctx.log(`identity written to ${out} — keep the private key secret`); }
75
- else emit(id, `did: ${id.did}\nprivateKey: ${id.privateKey} (secret — store securely)`);
172
+ if (out) { writeFileSync(out, JSON.stringify(id, null, 2)); ctx.log(`identity written to ${out}. Keep the private key secret`); }
173
+ else emit(id, `did: ${id.did}\nprivateKey: ${id.privateKey} (secret, store securely)`);
76
174
  return 0;
77
175
  }
78
176
  case 'did': {
@@ -113,6 +211,76 @@ export async function run(argv: string[], opts: { log?: (s: string) => void; fet
113
211
  else ctx.log(JSON.stringify(bundle));
114
212
  return 0;
115
213
  }
214
+ case 'audit': {
215
+ const tag = positional[0];
216
+ if (!tag) throw new Error('usage: zanii audit <tag> [--out bundle.json] or zanii audit <tag> --bundle <file>');
217
+ // A valueless or empty --bundle must NEVER fall through to the live, networked
218
+ // path. parse() is equals-blind (`--bundle=<file>` lands in flags literally
219
+ // named "bundle=<file>"), so scan the raw argv for the equals form, here only.
220
+ const eqForm = rest.find((a) => a.startsWith('--bundle='));
221
+ const eqFile = eqForm === undefined ? undefined : eqForm.slice('--bundle='.length);
222
+ if (eqForm !== undefined && !eqFile) throw new Error('usage: zanii audit <tag> --bundle <file>: --bundle requires a bundle file');
223
+ if (flags.bundle === true || flags.bundle === '') throw new Error('usage: zanii audit <tag> --bundle <file>: --bundle requires a bundle file');
224
+ const bundleFile = (typeof flags.bundle === 'string' ? flags.bundle : undefined) ?? eqFile;
225
+ const jurisdiction = parseList(flags.jurisdiction);
226
+ const declaredSubprocessors = parseList(flags['declared-subprocessors']);
227
+ const trustedSigners = parseList(flags['trusted-signers']);
228
+ let rows: VerdictRow[];
229
+ let note: string;
230
+ let payload: Record<string, unknown>;
231
+ if (bundleFile) {
232
+ // Offline mode: the bundle is served to fetchSubjectHistory through an inert
233
+ // fetchImpl, so the SAME receipt-verification code runs as in the live path.
234
+ // Zero network is enforced, not trusted: the fetchImpl only answers the
235
+ // sentinel bundle origin; any other URL throws, failing the run.
236
+ if (out) throw new Error('--out cannot be combined with --bundle');
237
+ let b: EvidenceBundle;
238
+ try {
239
+ b = JSON.parse(readFileSync(bundleFile, 'utf8')) as EvidenceBundle;
240
+ } catch (e) {
241
+ throw new Error(`cannot read evidence bundle ${bundleFile}: ${e instanceof Error ? e.message : String(e)}`);
242
+ }
243
+ if (b?.v !== 1 || typeof b?.tag !== 'string' || !Array.isArray(b?.receipts)) throw new Error(`${bundleFile} is not a v1 evidence bundle`);
244
+ if (b.tag !== tag) throw new Error(`bundle is for tag ${b.tag}, not ${tag}`);
245
+ const ORIGIN = 'offline://bundle';
246
+ let networkCalls = 0;
247
+ const offlineFetch: FetchLike = async (input) => {
248
+ const url = String(input);
249
+ if (!url.startsWith(`${ORIGIN}/`)) {
250
+ networkCalls++;
251
+ throw new Error(`offline audit attempted a network call: ${url}`);
252
+ }
253
+ return new Response(JSON.stringify({ receipts: b.receipts, sth: b.sth ?? undefined }), { status: 200 });
254
+ };
255
+ const history = await fetchSubjectHistory(tag, { server: ORIGIN, fetchImpl: offlineFetch })
256
+ ?? { tag, receipts: [], verified: true, failures: [] };
257
+ if (networkCalls !== 0) throw new Error(`offline audit made ${networkCalls} network call(s)`);
258
+ const extra = b.extra ?? {};
259
+ rows = await computeVerdicts(history, extra);
260
+ note = `offline: 0 network calls, verified against ${bundleFile} alone (fetched at ${b.fetched_at} from ${b.server}); the rows must match the subject page exactly`;
261
+ payload = { mode: 'offline', tag, bundle: bundleFile, networkCalls, rows, extra };
262
+ } else {
263
+ const history = await fetchSubjectHistory(tag, { server, fetchImpl: ctx.fetchImpl })
264
+ ?? { tag, receipts: [], verified: true, failures: [] };
265
+ const manifestHistory = await fetchSubjectHistory('zanii:training-manifests', { server, fetchImpl: ctx.fetchImpl })
266
+ ?? { tag: 'zanii:training-manifests', receipts: [], verified: true, failures: [] };
267
+ const extra = buildExtraEvidence(manifestHistory, tag, { jurisdiction, declaredSubprocessors, trustedSigners });
268
+ if (history.receipts.length === 0) ctx.log(`no receipts on ${server} for tag ${tag}`);
269
+ const bundle: EvidenceBundle = {
270
+ v: 1, tag, server, fetched_at: new Date().toISOString(),
271
+ receipts: history.receipts.map(({ receipt, hash, index }) => ({ receipt, hash, index })),
272
+ sth: history.sth ?? null,
273
+ extra,
274
+ };
275
+ rows = await computeVerdicts(history, extra);
276
+ if (out) { writeFileSync(out, JSON.stringify(bundle, null, 2)); note = `evidence bundle written to ${out}. Audit it offline later with: zanii audit ${tag} --bundle ${out}`; }
277
+ else note = JSON.stringify(bundle);
278
+ payload = { mode: 'live', tag, rows, bundle };
279
+ }
280
+ const human = rows.map((r) => `${STATE_MARK[r.state]} · ${r.label}\n ${r.detail}`).join('\n') + `\n${note}`;
281
+ emit(payload, human);
282
+ return rows.some((r) => r.state === 'failed') ? 1 : 0;
283
+ }
116
284
  case 'stats': {
117
285
  const s = await get('/v1/stats');
118
286
  emit(s, `${s.receipts} proofs · ${s.agents} agents · ${s.anchors} anchors`);