@vorim/verify 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Vorim AI
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,135 @@
1
+ # @vorim/verify
2
+
3
+ **Offline verifier for Vorim audit bundles.** No network. No Vorim API call. No telemetry.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/@vorim/verify.svg)](https://www.npmjs.com/package/@vorim/verify)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
7
+ [![Zero Dependencies](https://img.shields.io/badge/Dependencies-0-brightgreen.svg)]()
8
+ [![Node](https://img.shields.io/badge/Node.js-18%2B-green.svg)](https://nodejs.org/)
9
+
10
+ `vorim-verify` checks that a Vorim audit bundle is authentic and untampered, using only Node's built-in cryptography. The verifier never contacts Vorim — every public key needed to verify a signature is embedded in the bundle itself.
11
+
12
+ ## Install
13
+
14
+ ```bash
15
+ npm install -g @vorim/verify
16
+ ```
17
+
18
+ Or run without installing:
19
+
20
+ ```bash
21
+ npx @vorim/verify bundle.json
22
+ ```
23
+
24
+ ## Usage
25
+
26
+ ```bash
27
+ vorim-verify bundle.json # verify a bundle file
28
+ cat bundle.json | vorim-verify - # read from stdin
29
+ vorim-verify --explain bundle.json # per-event verdicts
30
+ vorim-verify --json bundle.json # machine-readable JSON output
31
+ ```
32
+
33
+ Exit codes: `0` ok, `1` verification failed, `2` CLI / IO error.
34
+
35
+ Example output:
36
+
37
+ ```text
38
+ vorim-verify: OK
39
+
40
+ bundle_version : vaip-v0
41
+ manifest : OK (sha256:8ff556a7222f...)
42
+
43
+ events total : 247
44
+ verified : 247
45
+ unsigned : 0
46
+ bad signature : 0
47
+ unknown agent : 0
48
+ malformed : 0
49
+ ```
50
+
51
+ ## What verification proves
52
+
53
+ For every event marked `verified`:
54
+
55
+ 1. **The bundle has not been edited since the API exported it.** The bundle's SHA-256 manifest must match the bytes of `events + agents` exactly.
56
+ 2. **The agent identified in the event is the one that authored the bytes recorded.** The event's `ed25519` signature verifies under the agent's public key (embedded in the bundle's `agents[]`).
57
+ 3. **The bytes signed are exactly the bytes recorded.** Tampering with any of `event_type`, `action`, `resource`, `input_hash`, `output_hash`, or `result` invalidates the signature.
58
+
59
+ ## What verification does NOT prove
60
+
61
+ Be honest about the limits:
62
+
63
+ - **It does not prove the agent's identity is who it claims to be.** That requires a separate trust anchor (the Vorim trust API, an IdP, a public key directory). The verifier confirms the *binding* between the signature and the public key in the bundle.
64
+ - **It does not prove the bundle is recent.** Add a timestamp authority or an externally-witnessed hash chain if freshness matters.
65
+ - **It does not detect missing events.** A bundle with N signed events is a true record of those N events. Whether other events were dropped before export is outside the verifier's scope. Pair with the Vorim `audit_events` count for that.
66
+ - **`unsigned` and `unknown_agent` events are reported but do not fail the bundle.** Operator's call: a fresh bundle from a v3.1+ SDK should be 100% signed; an older bundle may not be. The CLI surfaces the count; the operator decides what the threshold is.
67
+
68
+ ## Bundle format
69
+
70
+ The verifier expects the JSON shape produced by `POST /v1/audit/export` on Vorim API (`bundle_version: "vaip-v0"`). Minimum required:
71
+
72
+ ```json
73
+ {
74
+ "bundle_version": "vaip-v0",
75
+ "events": [
76
+ {
77
+ "event_id": "evt_...",
78
+ "agent_id_str": "agid_...",
79
+ "event_type": "tool_call",
80
+ "action": "transfer_funds",
81
+ "resource": "acct-1",
82
+ "input_hash": null,
83
+ "output_hash": null,
84
+ "result": "success",
85
+ "signature": "ed25519:..."
86
+ }
87
+ ],
88
+ "agents": [
89
+ { "agent_id": "agid_...", "public_key": "-----BEGIN PUBLIC KEY-----\n..." }
90
+ ],
91
+ "manifest": "sha256:..."
92
+ }
93
+ ```
94
+
95
+ ## Canonical bytes signed
96
+
97
+ ```
98
+ event_type|action|resource|input_hash|output_hash|result
99
+ ```
100
+
101
+ Pipe-joined, empty string for missing optional fields. The verifier exposes `canonicalPayloadV0()` so you can reproduce the bytes yourself.
102
+
103
+ ## Programmatic use
104
+
105
+ ```typescript
106
+ import { verifyBundle } from '@vorim/verify';
107
+
108
+ const bundle = JSON.parse(fs.readFileSync('bundle.json', 'utf-8'));
109
+ const report = verifyBundle(bundle);
110
+
111
+ if (!report.ok) {
112
+ console.error('bundle failed verification', report);
113
+ process.exit(1);
114
+ }
115
+ ```
116
+
117
+ Returns a `VerifyReport` with per-event verdicts and aggregate counts.
118
+
119
+ ## Auditing this code
120
+
121
+ The verifier is small and intentionally has no runtime dependencies. To audit it from source:
122
+
123
+ ```bash
124
+ git clone https://github.com/Kzino/vorim-protocol
125
+ cd vorim-protocol/packages/verify
126
+ npm install
127
+ npm test # 23 unit tests
128
+ npm run build # produces dist/cli.js
129
+ ```
130
+
131
+ Read `src/index.ts` for the verification logic (≈220 lines) and `src/cli.ts` for the CLI shim.
132
+
133
+ ## License
134
+
135
+ MIT — see [LICENSE](LICENSE).
package/dist/cli.d.ts ADDED
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * vorim-verify — Offline verifier for Vorim audit bundles.
4
+ *
5
+ * Usage:
6
+ * vorim-verify <path/to/bundle.json>
7
+ * cat bundle.json | vorim-verify -
8
+ * vorim-verify --explain <path> # per-event verdict list
9
+ * vorim-verify --json <path> # machine-readable report
10
+ * vorim-verify --help
11
+ * vorim-verify --version
12
+ *
13
+ * Exit codes:
14
+ * 0 bundle ok (no bad/malformed signatures, manifest checks if present)
15
+ * 1 bundle failed verification (at least one bad/malformed sig or wrong manifest)
16
+ * 2 CLI usage error / unreadable input
17
+ */
18
+ export {};
19
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;GAeG"}
package/dist/cli.js ADDED
@@ -0,0 +1,149 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * vorim-verify — Offline verifier for Vorim audit bundles.
4
+ *
5
+ * Usage:
6
+ * vorim-verify <path/to/bundle.json>
7
+ * cat bundle.json | vorim-verify -
8
+ * vorim-verify --explain <path> # per-event verdict list
9
+ * vorim-verify --json <path> # machine-readable report
10
+ * vorim-verify --help
11
+ * vorim-verify --version
12
+ *
13
+ * Exit codes:
14
+ * 0 bundle ok (no bad/malformed signatures, manifest checks if present)
15
+ * 1 bundle failed verification (at least one bad/malformed sig or wrong manifest)
16
+ * 2 CLI usage error / unreadable input
17
+ */
18
+ import { readFileSync } from 'node:fs';
19
+ import { verifyBundle } from './index.js';
20
+ const VERSION = '0.1.0';
21
+ function printUsage(stream) {
22
+ stream.write(`vorim-verify ${VERSION} — offline verifier for Vorim audit bundles
23
+
24
+ Usage:
25
+ vorim-verify <bundle.json> verify a bundle file
26
+ vorim-verify - read bundle from stdin
27
+ vorim-verify --explain <bundle.json> list per-event verdicts
28
+ vorim-verify --json <bundle.json> emit JSON report (no human formatting)
29
+ vorim-verify --help show this help
30
+ vorim-verify --version print version
31
+
32
+ Exit codes:
33
+ 0 = OK, 1 = verification failed, 2 = CLI / IO error
34
+
35
+ This tool makes NO network calls. It reads the bundle and verifies
36
+ Ed25519 signatures against the public keys embedded in the bundle.
37
+ `);
38
+ }
39
+ function readSource(arg) {
40
+ if (arg === '-') {
41
+ return readFileSync(0, 'utf-8');
42
+ }
43
+ try {
44
+ return readFileSync(arg, 'utf-8');
45
+ }
46
+ catch (e) {
47
+ process.stderr.write(`vorim-verify: cannot read ${arg}: ${e.message}\n`);
48
+ process.exit(2);
49
+ }
50
+ }
51
+ function parseBundle(src) {
52
+ try {
53
+ return JSON.parse(src);
54
+ }
55
+ catch (e) {
56
+ process.stderr.write(`vorim-verify: invalid JSON: ${e.message}\n`);
57
+ process.exit(2);
58
+ }
59
+ }
60
+ function formatHuman(report, explain) {
61
+ const lines = [];
62
+ const status = report.ok ? 'OK' : 'FAILED';
63
+ lines.push(`vorim-verify: ${status}`);
64
+ lines.push('');
65
+ lines.push(`bundle_version : ${report.bundle_version ?? '(unspecified)'}`);
66
+ if (report.manifest_ok === null) {
67
+ lines.push('manifest : (no manifest field — bundle pre-dates v0)');
68
+ }
69
+ else if (report.manifest_ok) {
70
+ lines.push(`manifest : OK (${report.manifest_actual})`);
71
+ }
72
+ else {
73
+ lines.push(`manifest : MISMATCH`);
74
+ lines.push(` expected: ${report.manifest_expected}`);
75
+ lines.push(` actual : ${report.manifest_actual}`);
76
+ }
77
+ lines.push('');
78
+ lines.push(`events total : ${report.event_count}`);
79
+ lines.push(` verified : ${report.verified}`);
80
+ lines.push(` unsigned : ${report.unsigned}`);
81
+ lines.push(` bad signature : ${report.bad_signature}`);
82
+ lines.push(` unknown agent : ${report.unknown_agent}`);
83
+ lines.push(` malformed : ${report.malformed_signature}`);
84
+ if (explain && report.events.length > 0) {
85
+ lines.push('');
86
+ lines.push('per-event verdicts:');
87
+ for (const e of report.events) {
88
+ const id = e.event_id ?? '(no id)';
89
+ const reason = e.reason ? ` — ${e.reason}` : '';
90
+ lines.push(` [${e.verdict.padEnd(12, ' ')}] ${id} agent=${e.agent_id ?? '?'} action=${e.action}${reason}`);
91
+ }
92
+ }
93
+ if (!report.ok) {
94
+ lines.push('');
95
+ lines.push('Bundle did NOT verify cleanly. See verdicts above.');
96
+ }
97
+ return lines.join('\n') + '\n';
98
+ }
99
+ function main() {
100
+ const argv = process.argv.slice(2);
101
+ if (argv.length === 0 || argv.includes('--help') || argv.includes('-h')) {
102
+ printUsage(argv.length === 0 ? process.stderr : process.stdout);
103
+ process.exit(argv.length === 0 ? 2 : 0);
104
+ }
105
+ if (argv.includes('--version') || argv.includes('-v')) {
106
+ process.stdout.write(`${VERSION}\n`);
107
+ process.exit(0);
108
+ }
109
+ let json = false;
110
+ let explain = false;
111
+ const positional = [];
112
+ for (const a of argv) {
113
+ if (a === '--json')
114
+ json = true;
115
+ else if (a === '--explain')
116
+ explain = true;
117
+ else if (a.startsWith('--')) {
118
+ process.stderr.write(`vorim-verify: unknown flag ${a}\n`);
119
+ process.exit(2);
120
+ }
121
+ else {
122
+ positional.push(a);
123
+ }
124
+ }
125
+ if (positional.length === 0) {
126
+ process.stderr.write(`vorim-verify: missing bundle path. Use - for stdin.\n`);
127
+ process.exit(2);
128
+ }
129
+ if (positional.length > 1) {
130
+ process.stderr.write(`vorim-verify: expected one bundle path, got ${positional.length}\n`);
131
+ process.exit(2);
132
+ }
133
+ const src = readSource(positional[0]);
134
+ const parsed = parseBundle(src);
135
+ if (!parsed || typeof parsed !== 'object') {
136
+ process.stderr.write(`vorim-verify: bundle must be a JSON object\n`);
137
+ process.exit(2);
138
+ }
139
+ const report = verifyBundle(parsed);
140
+ if (json) {
141
+ process.stdout.write(JSON.stringify(report, null, 2) + '\n');
142
+ }
143
+ else {
144
+ process.stdout.write(formatHuman(report, explain));
145
+ }
146
+ process.exit(report.ok ? 0 : 1);
147
+ }
148
+ main();
149
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * @vorim/verify — Offline verifier for Vorim audit bundles.
3
+ *
4
+ * Pure Node.js (built-in `crypto` only). No network calls, no Vorim API
5
+ * dependency, no telemetry. Designed to be reproduced from scratch by any
6
+ * counterparty who wants to convince themselves the bundle is authentic
7
+ * without trusting Vorim.
8
+ */
9
+ import type { AuditBundle, BundleEvent, VerifyReport } from './types.js';
10
+ export type { AuditBundle, BundleAgent, BundleEvent, EventResult, EventVerdict, VerifyReport, } from './types.js';
11
+ /**
12
+ * VAIP v0 canonical bytes for audit-event signing.
13
+ *
14
+ * Pipe-joined content fields with empty-string substitution for missing
15
+ * values. Must produce byte-identical output to:
16
+ * - @vorim/sdk `canonicalPayloadV0` (TypeScript SDK)
17
+ * - vorim Python SDK `canonical_payload_v0`
18
+ * - @vorim/shared-types `canonicalPayloadV0` (server)
19
+ *
20
+ * This is intentionally duplicated here so the verifier has zero
21
+ * dependencies. The test suite for each implementation cross-checks them
22
+ * against the same fixture matrix.
23
+ */
24
+ export declare function canonicalPayloadV0(event: {
25
+ event_type: string;
26
+ action: string;
27
+ resource?: string | null;
28
+ input_hash?: string | null;
29
+ output_hash?: string | null;
30
+ result: string;
31
+ }): string;
32
+ /**
33
+ * Verify the SHA-256 manifest over `{ events, agents }`. Returns null if
34
+ * the bundle has no manifest field (older exports). Manifest format is
35
+ * `sha256:<hex>` to match the server's `exportAuditBundle`.
36
+ */
37
+ export declare function verifyManifest(bundle: AuditBundle): {
38
+ ok: boolean | null;
39
+ expected: string | null;
40
+ actual: string | null;
41
+ };
42
+ /**
43
+ * Verify a single Ed25519 signature against `canonicalPayloadV0(event)`.
44
+ * `signature` is the `ed25519:<base64>` form the SDK produces; the prefix
45
+ * is stripped before decoding.
46
+ */
47
+ export declare function verifyEventSignature(event: BundleEvent, publicKeyPem: string): {
48
+ ok: boolean;
49
+ reason?: string;
50
+ };
51
+ /**
52
+ * Verify every event in the bundle. Each event ends up in exactly one of
53
+ * five buckets:
54
+ *
55
+ * - `verified` — signature present, agent's public key found, sig valid
56
+ * - `unsigned` — no signature in the event (acceptable; just unverifiable)
57
+ * - `bad_signature` — signature present but does not verify
58
+ * - `unknown_agent` — signature present but no public key in `agents[]`
59
+ * - `malformed_signature` — signature present but unparseable / wrong key format
60
+ *
61
+ * The whole report is `ok` iff `bad_signature` and `malformed_signature`
62
+ * are both zero, AND the manifest verifies (or is absent). Unsigned and
63
+ * unknown-agent events do NOT fail the report — they are surfaced so the
64
+ * reader can make their own call.
65
+ */
66
+ export declare function verifyBundle(bundle: AuditBundle): VerifyReport;
67
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EACV,WAAW,EAEX,WAAW,EAEX,YAAY,EACb,MAAM,YAAY,CAAC;AAEpB,YAAY,EACV,WAAW,EACX,WAAW,EACX,WAAW,EACX,WAAW,EACX,YAAY,EACZ,YAAY,GACb,MAAM,YAAY,CAAC;AAEpB;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE;IACxC,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,MAAM,CAST;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,WAAW,GAAG;IACnD,EAAE,EAAE,OAAO,GAAG,IAAI,CAAC;IACnB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB,CAKA;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,WAAW,EAClB,YAAY,EAAE,MAAM,GACnB;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CA6BlC;AAYD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,WAAW,GAAG,YAAY,CAyG9D"}
package/dist/index.js ADDED
@@ -0,0 +1,199 @@
1
+ /**
2
+ * @vorim/verify — Offline verifier for Vorim audit bundles.
3
+ *
4
+ * Pure Node.js (built-in `crypto` only). No network calls, no Vorim API
5
+ * dependency, no telemetry. Designed to be reproduced from scratch by any
6
+ * counterparty who wants to convince themselves the bundle is authentic
7
+ * without trusting Vorim.
8
+ */
9
+ import { createHash, createPublicKey, verify as cryptoVerify } from 'node:crypto';
10
+ /**
11
+ * VAIP v0 canonical bytes for audit-event signing.
12
+ *
13
+ * Pipe-joined content fields with empty-string substitution for missing
14
+ * values. Must produce byte-identical output to:
15
+ * - @vorim/sdk `canonicalPayloadV0` (TypeScript SDK)
16
+ * - vorim Python SDK `canonical_payload_v0`
17
+ * - @vorim/shared-types `canonicalPayloadV0` (server)
18
+ *
19
+ * This is intentionally duplicated here so the verifier has zero
20
+ * dependencies. The test suite for each implementation cross-checks them
21
+ * against the same fixture matrix.
22
+ */
23
+ export function canonicalPayloadV0(event) {
24
+ return [
25
+ event.event_type,
26
+ event.action,
27
+ event.resource ?? '',
28
+ event.input_hash ?? '',
29
+ event.output_hash ?? '',
30
+ event.result,
31
+ ].join('|');
32
+ }
33
+ /**
34
+ * Verify the SHA-256 manifest over `{ events, agents }`. Returns null if
35
+ * the bundle has no manifest field (older exports). Manifest format is
36
+ * `sha256:<hex>` to match the server's `exportAuditBundle`.
37
+ */
38
+ export function verifyManifest(bundle) {
39
+ if (!bundle.manifest)
40
+ return { ok: null, expected: null, actual: null };
41
+ const body = JSON.stringify({ events: bundle.events, agents: bundle.agents });
42
+ const actual = 'sha256:' + createHash('sha256').update(body).digest('hex');
43
+ return { ok: actual === bundle.manifest, expected: bundle.manifest, actual };
44
+ }
45
+ /**
46
+ * Verify a single Ed25519 signature against `canonicalPayloadV0(event)`.
47
+ * `signature` is the `ed25519:<base64>` form the SDK produces; the prefix
48
+ * is stripped before decoding.
49
+ */
50
+ export function verifyEventSignature(event, publicKeyPem) {
51
+ const sig = event.signature;
52
+ if (!sig)
53
+ return { ok: false, reason: 'no signature' };
54
+ const stripped = sig.startsWith('ed25519:') ? sig.slice('ed25519:'.length) : sig;
55
+ let sigBytes;
56
+ try {
57
+ sigBytes = Buffer.from(stripped, 'base64');
58
+ }
59
+ catch {
60
+ return { ok: false, reason: 'malformed base64 signature' };
61
+ }
62
+ if (sigBytes.length === 0)
63
+ return { ok: false, reason: 'empty signature' };
64
+ let pubKey;
65
+ try {
66
+ pubKey = createPublicKey(publicKeyPem);
67
+ }
68
+ catch (e) {
69
+ return {
70
+ ok: false,
71
+ reason: `unparseable public key: ${e.message}`,
72
+ };
73
+ }
74
+ const payload = Buffer.from(canonicalPayloadV0(event), 'utf-8');
75
+ try {
76
+ return { ok: cryptoVerify(null, payload, pubKey, sigBytes) };
77
+ }
78
+ catch (e) {
79
+ return { ok: false, reason: `verify error: ${e.message}` };
80
+ }
81
+ }
82
+ function eventAgentId(event) {
83
+ // The export joins agents and stores the public-facing agent_id as
84
+ // `agent_id_str`. Fall back to `agent_id` for hand-crafted bundles.
85
+ return ((typeof event.agent_id_str === 'string' && event.agent_id_str) ||
86
+ (typeof event.agent_id === 'string' && event.agent_id) ||
87
+ null);
88
+ }
89
+ /**
90
+ * Verify every event in the bundle. Each event ends up in exactly one of
91
+ * five buckets:
92
+ *
93
+ * - `verified` — signature present, agent's public key found, sig valid
94
+ * - `unsigned` — no signature in the event (acceptable; just unverifiable)
95
+ * - `bad_signature` — signature present but does not verify
96
+ * - `unknown_agent` — signature present but no public key in `agents[]`
97
+ * - `malformed_signature` — signature present but unparseable / wrong key format
98
+ *
99
+ * The whole report is `ok` iff `bad_signature` and `malformed_signature`
100
+ * are both zero, AND the manifest verifies (or is absent). Unsigned and
101
+ * unknown-agent events do NOT fail the report — they are surfaced so the
102
+ * reader can make their own call.
103
+ */
104
+ export function verifyBundle(bundle) {
105
+ const agentMap = new Map((bundle.agents ?? []).map(a => [a.agent_id, a]));
106
+ const events = (bundle.events ?? []).map(e => {
107
+ const agentId = eventAgentId(e);
108
+ const baseId = typeof e.event_id === 'string' ? e.event_id : undefined;
109
+ if (!e.signature) {
110
+ return {
111
+ event_id: baseId,
112
+ agent_id: agentId,
113
+ action: e.action,
114
+ verdict: 'unsigned',
115
+ };
116
+ }
117
+ if (!agentId) {
118
+ return {
119
+ event_id: baseId,
120
+ agent_id: null,
121
+ action: e.action,
122
+ verdict: 'unknown_agent',
123
+ reason: 'event has no agent_id',
124
+ };
125
+ }
126
+ const agent = agentMap.get(agentId);
127
+ if (!agent) {
128
+ return {
129
+ event_id: baseId,
130
+ agent_id: agentId,
131
+ action: e.action,
132
+ verdict: 'unknown_agent',
133
+ reason: `bundle.agents[] does not contain ${agentId}`,
134
+ };
135
+ }
136
+ const v = verifyEventSignature(e, agent.public_key);
137
+ if (v.ok) {
138
+ return {
139
+ event_id: baseId,
140
+ agent_id: agentId,
141
+ action: e.action,
142
+ verdict: 'verified',
143
+ };
144
+ }
145
+ if (v.reason && v.reason.startsWith('unparseable public key')) {
146
+ return {
147
+ event_id: baseId,
148
+ agent_id: agentId,
149
+ action: e.action,
150
+ verdict: 'malformed_signature',
151
+ reason: v.reason,
152
+ };
153
+ }
154
+ if (v.reason && (v.reason.includes('base64') || v.reason.includes('verify error'))) {
155
+ return {
156
+ event_id: baseId,
157
+ agent_id: agentId,
158
+ action: e.action,
159
+ verdict: 'malformed_signature',
160
+ reason: v.reason,
161
+ };
162
+ }
163
+ return {
164
+ event_id: baseId,
165
+ agent_id: agentId,
166
+ action: e.action,
167
+ verdict: 'bad_signature',
168
+ reason: v.reason,
169
+ };
170
+ });
171
+ const counts = {
172
+ verified: 0,
173
+ unsigned: 0,
174
+ bad_signature: 0,
175
+ unknown_agent: 0,
176
+ malformed_signature: 0,
177
+ };
178
+ for (const r of events)
179
+ counts[r.verdict]++;
180
+ const manifest = verifyManifest(bundle);
181
+ const ok = counts.bad_signature === 0 &&
182
+ counts.malformed_signature === 0 &&
183
+ manifest.ok !== false;
184
+ return {
185
+ bundle_version: typeof bundle.bundle_version === 'string' ? bundle.bundle_version : null,
186
+ manifest_ok: manifest.ok,
187
+ manifest_expected: manifest.expected,
188
+ manifest_actual: manifest.actual,
189
+ event_count: events.length,
190
+ verified: counts.verified,
191
+ unsigned: counts.unsigned,
192
+ bad_signature: counts.bad_signature,
193
+ unknown_agent: counts.unknown_agent,
194
+ malformed_signature: counts.malformed_signature,
195
+ events,
196
+ ok,
197
+ };
198
+ }
199
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Shape of a Vorim audit bundle as produced by the API's
3
+ * `POST /v1/audit/export` endpoint (bundle_version: "vaip-v0").
4
+ *
5
+ * The verifier only depends on the fields it inspects; extra fields are
6
+ * preserved so future bundle revisions remain readable.
7
+ */
8
+ export interface AuditBundle {
9
+ bundle_version?: string;
10
+ canonical_form?: string;
11
+ manifest?: string;
12
+ events: BundleEvent[];
13
+ agents: BundleAgent[];
14
+ event_count?: number;
15
+ agent_count?: number;
16
+ from?: string;
17
+ to?: string;
18
+ org_id?: string;
19
+ generated_at?: string;
20
+ [key: string]: unknown;
21
+ }
22
+ export interface BundleEvent {
23
+ event_id?: string;
24
+ agent_id_str?: string;
25
+ agent_id?: string | number;
26
+ event_type: string;
27
+ action: string;
28
+ resource?: string | null;
29
+ input_hash?: string | null;
30
+ output_hash?: string | null;
31
+ result: string;
32
+ signature?: string | null;
33
+ timestamp?: string;
34
+ [key: string]: unknown;
35
+ }
36
+ export interface BundleAgent {
37
+ agent_id: string;
38
+ public_key: string;
39
+ key_fingerprint?: string;
40
+ status?: string;
41
+ name?: string;
42
+ }
43
+ export type EventVerdict = 'verified' | 'unsigned' | 'bad_signature' | 'unknown_agent' | 'malformed_signature';
44
+ export interface EventResult {
45
+ event_id?: string;
46
+ agent_id: string | null;
47
+ action: string;
48
+ verdict: EventVerdict;
49
+ reason?: string;
50
+ }
51
+ export interface VerifyReport {
52
+ bundle_version: string | null;
53
+ manifest_ok: boolean | null;
54
+ manifest_expected: string | null;
55
+ manifest_actual: string | null;
56
+ event_count: number;
57
+ verified: number;
58
+ unsigned: number;
59
+ bad_signature: number;
60
+ unknown_agent: number;
61
+ malformed_signature: number;
62
+ events: EventResult[];
63
+ ok: boolean;
64
+ }
65
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,WAAW,WAAW;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,MAAM,YAAY,GACpB,UAAU,GACV,UAAU,GACV,eAAe,GACf,eAAe,GACf,qBAAqB,CAAC;AAE1B,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,YAAY,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,WAAW,EAAE,OAAO,GAAG,IAAI,CAAC;IAC5B,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,EAAE,EAAE,OAAO,CAAC;CACb"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "@vorim/verify",
3
+ "version": "0.1.0",
4
+ "description": "Offline verifier for Vorim audit bundles — no network, no Vorim API call, no telemetry.",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "default": "./dist/index.js"
12
+ }
13
+ },
14
+ "bin": {
15
+ "vorim-verify": "dist/cli.js"
16
+ },
17
+ "files": [
18
+ "dist",
19
+ "README.md",
20
+ "LICENSE"
21
+ ],
22
+ "scripts": {
23
+ "build": "tsc",
24
+ "test": "vitest run",
25
+ "typecheck": "tsc --noEmit"
26
+ },
27
+ "dependencies": {},
28
+ "devDependencies": {
29
+ "@types/node": "^22.0.0",
30
+ "typescript": "^5.4.0",
31
+ "vitest": "^2.0.0"
32
+ },
33
+ "keywords": [
34
+ "vorim",
35
+ "audit",
36
+ "verifier",
37
+ "ed25519",
38
+ "offline",
39
+ "agent-identity",
40
+ "ai-agents"
41
+ ],
42
+ "repository": {
43
+ "type": "git",
44
+ "url": "https://github.com/Kzino/vorim-protocol",
45
+ "directory": "packages/verify"
46
+ },
47
+ "homepage": "https://vorim.ai",
48
+ "bugs": {
49
+ "url": "https://github.com/Kzino/vorim-protocol/issues"
50
+ },
51
+ "author": "Vorim AI <hello@vorim.ai>",
52
+ "license": "MIT",
53
+ "engines": {
54
+ "node": ">=18.0.0"
55
+ }
56
+ }