aqta-verify-receipt 1.0.1 → 1.0.4

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,63 +1,119 @@
1
1
  # aqta-verify-receipt
2
2
 
3
- Independent verifier for [AqtaCore](https://app.aqta.ai) attestation receipts.
4
- Checks the Ed25519 signature on an enforcement-attestation receipt using only
5
- the published public key: **no dependency on Aqta's servers**.
3
+ [![npm](https://img.shields.io/npm/v/aqta-verify-receipt.svg)](https://www.npmjs.com/package/aqta-verify-receipt)
4
+ [![PyPI](https://img.shields.io/pypi/v/aqta-verify-receipt.svg)](https://pypi.org/project/aqta-verify-receipt/)
5
+ [![Licence](https://img.shields.io/badge/licence-Apache--2.0-blue.svg)](LICENSE)
6
6
 
7
- ## Why this exists
7
+ Offline verifier for **Seal** receipts ([ATTESTATION-v1](https://github.com/Aqta-ai/attestation-spec/blob/main/spec/ATTESTATION-v1.md)).
8
8
 
9
- AqtaCore returns a signed receipt with every AI enforcement decision.
10
- Regulators, auditors, and internal compliance teams need to verify those
11
- receipts independently, without trusting the issuer. This package is the
12
- reference implementation of that verifier, maintained by Aqta under the open
13
- [ATTESTATION-v1](https://github.com/Aqta-ai/attestation-spec/blob/main/spec/ATTESTATION-v1.md)
14
- format specification.
9
+ Seal signs the model call at runtime. This package checks that signature
10
+ without contacting Aqta. No account. Exit code only if you want it quiet.
11
+
12
+ Same algorithm on npm and PyPI. Reference implementation, not a platform SDK.
13
+
14
+ ## 30-second check
15
+
16
+ ```bash
17
+ # download a receipt JSON, then:
18
+ npx aqta-verify-receipt@1.0.4 receipt.json \
19
+ --key gUoUhIvptKAoLTnry3VrDtOQEWggGQveLrHFVrfNqmE
20
+ ```
21
+
22
+ Or pipe a public share link body:
23
+
24
+ ```bash
25
+ curl -sS https://api.aqta.ai/r/YOUR_RECEIPT_ID | npx aqta-verify-receipt@1.0.4 - \
26
+ --key gUoUhIvptKAoLTnry3VrDtOQEWggGQveLrHFVrfNqmE
27
+ ```
28
+
29
+ `ok` + exit `0` means the Ed25519 signature verifies against the pinned key.
30
+ `fail` + exit `1` means it does not. Exit `2` is usage or IO.
31
+
32
+ Production public key (also at
33
+ [`/v1/attestation/public-key`](https://api.aqta.ai/v1/attestation/public-key),
34
+ key id `aqta-att-0a18c7c16bc18a12`):
35
+
36
+ ```
37
+ gUoUhIvptKAoLTnry3VrDtOQEWggGQveLrHFVrfNqmE
38
+ ```
39
+
40
+ Pin that string. Do not re-fetch it inside a verify loop.
15
41
 
16
42
  ## Install
17
43
 
18
44
  ```bash
19
45
  npm install aqta-verify-receipt
46
+ # or one-shot:
47
+ npx aqta-verify-receipt receipt.json --key <pinned>
20
48
  ```
21
49
 
22
- ## Usage
50
+ Two runtime deps: `tweetnacl`, `tweetnacl-util`.
51
+
52
+ ## Library
23
53
 
24
54
  ```ts
25
55
  import { verifyReceipt, fetchPublishedPublicKey } from 'aqta-verify-receipt';
26
56
 
27
- // One-time: fetch and pin the issuer's public key.
57
+ // Once per environment: fetch, then pin somewhere you control.
28
58
  const trustedPublicKey = await fetchPublishedPublicKey();
29
59
 
30
- // Per receipt:
31
60
  const result = verifyReceipt(receipt, { trustedPublicKey });
61
+ if (!result.valid) throw new Error(result.reason);
62
+ ```
63
+
64
+ ### Pin the key
65
+
66
+ `fetchPublishedPublicKey()` is for first-time setup. Calling it on every
67
+ verify collapses trust back to "trust the issuer's server right now".
68
+
69
+ 1. Fetch once.
70
+ 2. Persist (config, KMS, secret store).
71
+ 3. Pass `trustedPublicKey` on every call.
72
+ 4. Rotate only on a documented key-rotation notice.
73
+
74
+ ## CLI
32
75
 
33
- if (!result.valid) {
34
- throw new Error(`Receipt invalid: ${result.reason}`);
35
- }
36
- console.log('Receipt verified without contacting Aqta.');
76
+ ```
77
+ aqta-verify-receipt <file|-> --key <base64url> [--no-strict] [-q]
78
+ aqta-verify-receipt <file|-> --integrity-only [--no-strict] [-q]
37
79
  ```
38
80
 
39
- ## API
81
+ | Flag | Meaning |
82
+ |------|---------|
83
+ | `--key` | Pin issuer identity (required for counsel-grade). |
84
+ | `--integrity-only` | Signature vs embedded key only; returns untrusted. Anyone can self-sign. |
85
+ | `--no-strict` | Allow unknown top-level fields |
86
+ | `-q` | Silent; exit code only |
40
87
 
41
- ### `verifyReceipt(receipt, options?) → { valid, reason? }`
88
+ ## API
42
89
 
43
- Verifies an attestation receipt against the declared (or pinned) public key.
90
+ ### `verifyReceipt(receipt, options?) → { valid, reason?, keySource? }`
44
91
 
45
- Options:
46
- - `trustedPublicKey`: base64url public key. If set, the receipt's `public_key`
47
- field must match byte for byte. Strongly recommended for production.
48
- - `strictFields`: if `true` (default), any unknown top-level field causes
49
- rejection, per ATTESTATION-v1 §4.
92
+ Never throws. **Pinning is required by default.** Without `trustedPublicKey`,
93
+ returns `valid: false` unless `allowUntrustedEmbeddedKey: true` (then
94
+ `keySource: "untrusted"` on success). Default `strictFields: true` rejects
95
+ unknown top-level fields (ATTESTATION-v1 §4).
50
96
 
51
97
  ### `fetchPublishedPublicKey(url?) → Promise<string>`
52
98
 
53
- Fetches the AqtaCore public key from
54
- `https://app.aqta.ai/security/pubkey.txt`. Pass a custom URL for self-hosted
55
- issuers.
99
+ Default: `https://app.aqta.ai/security/pubkey.txt`. Same material as
100
+ `https://api.aqta.ai/v1/attestation/public-key`.
101
+
102
+ ## Test vectors
103
+
104
+ Conformance suite (6 valid + 8 invalid):
105
+ [`test-vectors/`](https://github.com/Aqta-ai/attestation-spec/tree/main/test-vectors).
106
+
107
+ ## What this is not
108
+
109
+ Not a governance dashboard. Not a cost router. Not a chain explorer.
110
+ A small verifier for one signed model-call receipt.
56
111
 
57
- ## Receipt format
112
+ ## Security
58
113
 
59
- See [ATTESTATION-v1](https://github.com/Aqta-ai/attestation-spec/blob/main/spec/ATTESTATION-v1.md).
114
+ Cryptographic issues: see [SECURITY.md](../../SECURITY.md). Prefer
115
+ security@aqta.ai over public issues for key or signature bugs.
60
116
 
61
117
  ## Licence
62
118
 
63
- Apache-2.0. See `LICENSE`.
119
+ Apache-2.0. Aqta Technologies Limited.
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ require('../dist/cli.js');
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,114 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ /**
5
+ * aqta-verify-receipt CLI.
6
+ *
7
+ * Offline check of an ATTESTATION-v1 receipt. No account. No network by
8
+ * default. Exit 0 if the signature verifies, 1 if not, 2 on usage/IO errors.
9
+ *
10
+ * npx aqta-verify-receipt receipt.json --key <base64url-ed25519-key>
11
+ * curl -sS https://api.aqta.ai/r/REC_ID | npx aqta-verify-receipt - --key <key>
12
+ * npx aqta-verify-receipt receipt.json --integrity-only
13
+ */
14
+ const fs_1 = require("fs");
15
+ const index_1 = require("./index");
16
+ const PUB_KEY_HINT = 'https://api.aqta.ai/v1/attestation/public-key';
17
+ function usage() {
18
+ console.error(`aqta-verify-receipt - offline check for ATTESTATION-v1 (Seal)
19
+
20
+ Usage:
21
+ aqta-verify-receipt <receipt.json | -> --key <base64url> [--no-strict] [-q]
22
+ aqta-verify-receipt <receipt.json | -> --integrity-only [--no-strict] [-q]
23
+
24
+ Options:
25
+ --key <key> pin the issuer public key (required for counsel-grade)
26
+ --integrity-only check signature vs embedded key only (anyone can self-sign)
27
+ --no-strict allow unknown top-level fields
28
+ -q, --quiet exit code only
29
+
30
+ Pin the production key once from ${PUB_KEY_HINT}
31
+ (field public_key). Do not re-fetch on every verify.
32
+ `);
33
+ process.exit(2);
34
+ }
35
+ function main() {
36
+ const args = process.argv.slice(2);
37
+ if (args.length === 0 || args.includes('--help') || args.includes('-h'))
38
+ usage();
39
+ let file = '';
40
+ let trustedKey;
41
+ let integrityOnly = false;
42
+ let strict = true;
43
+ let quiet = false;
44
+ for (let i = 0; i < args.length; i++) {
45
+ const a = args[i];
46
+ if (a === '--key') {
47
+ trustedKey = args[++i];
48
+ if (!trustedKey)
49
+ usage();
50
+ }
51
+ else if (a === '--integrity-only') {
52
+ integrityOnly = true;
53
+ }
54
+ else if (a === '--no-strict') {
55
+ strict = false;
56
+ }
57
+ else if (a === '--quiet' || a === '-q') {
58
+ quiet = true;
59
+ }
60
+ else if (!file) {
61
+ file = a;
62
+ }
63
+ else {
64
+ usage();
65
+ }
66
+ }
67
+ if (!file)
68
+ usage();
69
+ if (!trustedKey && !integrityOnly) {
70
+ console.error('aqta-verify-receipt: pass --key <pinned> (or --integrity-only for embedded-key checks)');
71
+ process.exit(2);
72
+ }
73
+ if (trustedKey && integrityOnly) {
74
+ console.error('aqta-verify-receipt: use --key or --integrity-only, not both');
75
+ process.exit(2);
76
+ }
77
+ let raw;
78
+ try {
79
+ raw = file === '-' ? (0, fs_1.readFileSync)(0, 'utf8') : (0, fs_1.readFileSync)(file, 'utf8');
80
+ }
81
+ catch {
82
+ console.error(`aqta-verify-receipt: cannot read ${file === '-' ? 'stdin' : file}`);
83
+ process.exit(2);
84
+ }
85
+ let receipt;
86
+ try {
87
+ receipt = JSON.parse(raw);
88
+ }
89
+ catch {
90
+ console.error('aqta-verify-receipt: input is not valid JSON');
91
+ process.exit(2);
92
+ }
93
+ const result = (0, index_1.verifyReceipt)(receipt, {
94
+ trustedPublicKey: trustedKey,
95
+ allowUntrustedEmbeddedKey: integrityOnly,
96
+ strictFields: strict,
97
+ });
98
+ if (!quiet) {
99
+ const id = typeof receipt.attestation_id === 'string' ? receipt.attestation_id : '?';
100
+ const outcome = typeof receipt.outcome === 'string' ? receipt.outcome : '?';
101
+ if (result.valid) {
102
+ const trust = result.keySource === 'pinned'
103
+ ? 'pinned key'
104
+ : 'untrusted embedded key (integrity only)';
105
+ console.log(`ok ${outcome} ${id} ${trust}`);
106
+ }
107
+ else {
108
+ console.log(`fail ${result.reason ?? 'verification failed'} ${id}`);
109
+ }
110
+ }
111
+ process.exit(result.valid ? 0 : 1);
112
+ }
113
+ main();
114
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * aqta-verify-receipt
3
3
  *
4
- * Independent verifier for AqtaCore attestation receipts (ATTESTATION-v1).
4
+ * Independent verifier for Seal attestation receipts (ATTESTATION-v1).
5
5
  * Verifies the Ed25519 signature on a receipt using only the published
6
6
  * public key: no dependency on any third-party server.
7
7
  *
@@ -24,14 +24,19 @@ export interface AttestationReceipt {
24
24
  }
25
25
  export interface VerifyOptions {
26
26
  /**
27
- * The trusted public key (base64url, no padding). If supplied, the receipt
28
- * is rejected unless its `public_key` field matches byte-for-byte. This
29
- * prevents an attacker from substituting a different key.
27
+ * Trusted issuer public key (base64url, no padding). Required for a
28
+ * counsel-grade check: the receipt must carry this key and verify under it.
30
29
  *
31
- * If omitted, the receipt is verified against whatever public key it
32
- * declares. This is lower trust but useful for offline / one-shot checks.
30
+ * Omit only with `allowUntrustedEmbeddedKey: true` for integrity-only
31
+ * checks against whatever key the receipt embeds (anyone can self-sign).
33
32
  */
34
33
  trustedPublicKey?: string;
34
+ /**
35
+ * If true, verify against the receipt's embedded `public_key` without
36
+ * pinning an issuer. Result includes `keySource: "untrusted"`. Default
37
+ * false: without `trustedPublicKey`, verification fails.
38
+ */
39
+ allowUntrustedEmbeddedKey?: boolean;
35
40
  /**
36
41
  * If true, unknown top-level fields in the receipt cause rejection. Default
37
42
  * true per spec §4: "Verifiers MUST reject receipts containing unknown
@@ -39,18 +44,24 @@ export interface VerifyOptions {
39
44
  */
40
45
  strictFields?: boolean;
41
46
  }
47
+ export type KeySource = 'pinned' | 'untrusted';
42
48
  export interface VerifyResult {
43
49
  valid: boolean;
44
50
  reason?: string;
51
+ /** Present when `valid` is true. */
52
+ keySource?: KeySource;
45
53
  }
46
54
  /**
47
- * Verify an AqtaCore attestation receipt.
55
+ * Verify a Seal attestation receipt.
56
+ *
57
+ * Pinning is required by default. A self-signed receipt must not return
58
+ * `valid: true` unless `allowUntrustedEmbeddedKey` is set.
48
59
  *
49
60
  * @param receipt The full receipt object (including `signature`).
50
- * @param options Optional verification constraints.
51
- * @returns `{ valid: true }` if the signature is valid under the
52
- * declared (and optionally pinned) public key; otherwise
53
- * `{ valid: false, reason: string }`.
61
+ * @param options Verification constraints.
62
+ * @returns `{ valid: true, keySource }` if the signature is valid under
63
+ * the pinned (or explicitly allowed embedded) public key;
64
+ * otherwise `{ valid: false, reason: string }`.
54
65
  *
55
66
  * @example
56
67
  * const result = verifyReceipt(receipt, {
@@ -60,11 +71,24 @@ export interface VerifyResult {
60
71
  */
61
72
  export declare function verifyReceipt(receipt: unknown, options?: VerifyOptions): VerifyResult;
62
73
  /**
63
- * Fetch the AqtaCore public key from the published URL and return it as a
74
+ * Fetch the Seal public key from the published URL and return it as a
64
75
  * base64url string ready to pass to `verifyReceipt` as `trustedPublicKey`.
65
76
  *
66
- * Callers SHOULD pin this value once retrieved, rather than re-fetching on
67
- * every verification.
77
+ * **PIN THE RESULT.** This helper performs a live HTTPS fetch. Calling it
78
+ * inside a verification loop collapses the trust model back to "trust the
79
+ * issuer's server right now", which is exactly what the attestation format
80
+ * is designed to avoid.
81
+ *
82
+ * Correct usage:
83
+ * 1. Call this once on first use.
84
+ * 2. Persist the returned string (configuration file, database, KMS,
85
+ * environment variable, secret manager).
86
+ * 3. Pass the persisted value as `trustedPublicKey` on every subsequent
87
+ * verification.
88
+ * 4. Rotate only in response to a documented key-rotation notice
89
+ * received via a channel you already trust.
90
+ *
91
+ * Re-fetching the key on every verification is a misuse.
68
92
  */
69
93
  export declare function fetchPublishedPublicKey(url?: string): Promise<string>;
70
94
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,8DAA8D;AAC9D,MAAM,WAAW,kBAAkB;IACjC,CAAC,EAAE,MAAM,CAAC;IACV,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,SAAS,GAAG,SAAS,GAAG,YAAY,GAAG,QAAQ,CAAC;IACzD,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B;;;;;;;OAOG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B;;;;OAIG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAoED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,OAAO,EAChB,OAAO,GAAE,aAAkB,GAC1B,YAAY,CAuEd;AAED;;;;;;GAMG;AACH,wBAAsB,uBAAuB,CAC3C,GAAG,SAA4C,GAC9C,OAAO,CAAC,MAAM,CAAC,CAMjB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,8DAA8D;AAC9D,MAAM,WAAW,kBAAkB;IACjC,CAAC,EAAE,MAAM,CAAC;IACV,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,SAAS,GAAG,SAAS,GAAG,YAAY,GAAG,QAAQ,CAAC;IACzD,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B;;;;OAIG;IACH,yBAAyB,CAAC,EAAE,OAAO,CAAC;IAEpC;;;;OAIG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,WAAW,CAAC;AAE/C,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oCAAoC;IACpC,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB;AAoED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,OAAO,EAChB,OAAO,GAAE,aAAkB,GAC1B,YAAY,CAqFd;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,uBAAuB,CAC3C,GAAG,SAA4C,GAC9C,OAAO,CAAC,MAAM,CAAC,CAMjB"}
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@
2
2
  /**
3
3
  * aqta-verify-receipt
4
4
  *
5
- * Independent verifier for AqtaCore attestation receipts (ATTESTATION-v1).
5
+ * Independent verifier for Seal attestation receipts (ATTESTATION-v1).
6
6
  * Verifies the Ed25519 signature on a receipt using only the published
7
7
  * public key: no dependency on any third-party server.
8
8
  *
@@ -78,13 +78,16 @@ function canonicalValue(v) {
78
78
  return JSON.stringify(v);
79
79
  }
80
80
  /**
81
- * Verify an AqtaCore attestation receipt.
81
+ * Verify a Seal attestation receipt.
82
+ *
83
+ * Pinning is required by default. A self-signed receipt must not return
84
+ * `valid: true` unless `allowUntrustedEmbeddedKey` is set.
82
85
  *
83
86
  * @param receipt The full receipt object (including `signature`).
84
- * @param options Optional verification constraints.
85
- * @returns `{ valid: true }` if the signature is valid under the
86
- * declared (and optionally pinned) public key; otherwise
87
- * `{ valid: false, reason: string }`.
87
+ * @param options Verification constraints.
88
+ * @returns `{ valid: true, keySource }` if the signature is valid under
89
+ * the pinned (or explicitly allowed embedded) public key;
90
+ * otherwise `{ valid: false, reason: string }`.
88
91
  *
89
92
  * @example
90
93
  * const result = verifyReceipt(receipt, {
@@ -123,9 +126,16 @@ function verifyReceipt(receipt, options = {}) {
123
126
  if (typeof r.request_hash !== 'string' || !/^[0-9a-f]{64}$/.test(r.request_hash)) {
124
127
  return { valid: false, reason: 'request_hash must be 64 lowercase hex chars' };
125
128
  }
129
+ const pinned = options.trustedPublicKey;
130
+ const allowUntrusted = options.allowUntrustedEmbeddedKey === true;
131
+ if (pinned === undefined && !allowUntrusted) {
132
+ return {
133
+ valid: false,
134
+ reason: 'trustedPublicKey required (pass allowUntrustedEmbeddedKey for integrity-only)',
135
+ };
136
+ }
126
137
  // Public-key pinning
127
- if (options.trustedPublicKey !== undefined &&
128
- options.trustedPublicKey !== r.public_key) {
138
+ if (pinned !== undefined && pinned !== r.public_key) {
129
139
  return {
130
140
  valid: false,
131
141
  reason: 'public_key does not match trusted key',
@@ -152,18 +162,37 @@ function verifyReceipt(receipt, options = {}) {
152
162
  return { valid: false, reason: 'public key length != 32 bytes' };
153
163
  }
154
164
  const ok = tweetnacl_1.default.sign.detached.verify(canonical, sig, pub);
155
- return ok ? { valid: true } : { valid: false, reason: 'signature check failed' };
165
+ if (!ok) {
166
+ return { valid: false, reason: 'signature check failed' };
167
+ }
168
+ return {
169
+ valid: true,
170
+ keySource: pinned !== undefined ? 'pinned' : 'untrusted',
171
+ };
156
172
  }
157
173
  catch (e) {
158
174
  return { valid: false, reason: `signature decode error: ${String(e)}` };
159
175
  }
160
176
  }
161
177
  /**
162
- * Fetch the AqtaCore public key from the published URL and return it as a
178
+ * Fetch the Seal public key from the published URL and return it as a
163
179
  * base64url string ready to pass to `verifyReceipt` as `trustedPublicKey`.
164
180
  *
165
- * Callers SHOULD pin this value once retrieved, rather than re-fetching on
166
- * every verification.
181
+ * **PIN THE RESULT.** This helper performs a live HTTPS fetch. Calling it
182
+ * inside a verification loop collapses the trust model back to "trust the
183
+ * issuer's server right now", which is exactly what the attestation format
184
+ * is designed to avoid.
185
+ *
186
+ * Correct usage:
187
+ * 1. Call this once on first use.
188
+ * 2. Persist the returned string (configuration file, database, KMS,
189
+ * environment variable, secret manager).
190
+ * 3. Pass the persisted value as `trustedPublicKey` on every subsequent
191
+ * verification.
192
+ * 4. Rotate only in response to a documented key-rotation notice
193
+ * received via a channel you already trust.
194
+ *
195
+ * Re-fetching the key on every verification is a misuse.
167
196
  */
168
197
  async function fetchPublishedPublicKey(url = 'https://app.aqta.ai/security/pubkey.txt') {
169
198
  const res = await fetch(url);
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,11 +1,22 @@
1
1
  {
2
2
  "name": "aqta-verify-receipt",
3
- "version": "1.0.1",
4
- "description": "Independent verifier for AqtaCore attestation receipts. Verifies the Ed25519 signature on an attestation receipt without trusting any third-party server. Reference implementation of ATTESTATION-v1.",
3
+ "version": "1.0.4",
4
+ "description": "Offline CLI and library for Seal ATTESTATION-v1 receipts. Ed25519 check of a signed model call; no account, no Aqta server required.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
+ "bin": {
8
+ "aqta-verify-receipt": "bin/aqta-verify-receipt.js"
9
+ },
7
10
  "files": [
8
- "dist/",
11
+ "bin/",
12
+ "dist/cli.js",
13
+ "dist/cli.js.map",
14
+ "dist/cli.d.ts",
15
+ "dist/cli.d.ts.map",
16
+ "dist/index.js",
17
+ "dist/index.js.map",
18
+ "dist/index.d.ts",
19
+ "dist/index.d.ts.map",
9
20
  "README.md",
10
21
  "LICENSE"
11
22
  ],
@@ -15,15 +26,15 @@
15
26
  "prepublishOnly": "npm run build"
16
27
  },
17
28
  "keywords": [
29
+ "seal",
18
30
  "aqta",
19
- "ai-governance",
20
- "attestation",
31
+ "attestation-v1",
21
32
  "ed25519",
22
- "zero-trust",
23
- "eu-ai-act",
24
- "dora",
25
- "compliance",
26
- "receipt-verification"
33
+ "offline-verification",
34
+ "ai-receipts",
35
+ "model-call",
36
+ "tamper-evident",
37
+ "cli"
27
38
  ],
28
39
  "author": "Aqta Technologies Ltd",
29
40
  "license": "Apache-2.0",
@@ -32,7 +43,7 @@
32
43
  "url": "https://github.com/Aqta-ai/attestation-spec.git",
33
44
  "directory": "packages/verify-receipt"
34
45
  },
35
- "homepage": "https://github.com/Aqta-ai/attestation-spec",
46
+ "homepage": "https://aqta.ai/verify",
36
47
  "bugs": {
37
48
  "url": "https://github.com/Aqta-ai/attestation-spec/issues"
38
49
  },
@@ -1,6 +0,0 @@
1
- /**
2
- * Interop tests: verify a receipt produced by the Python reference implementation
3
- * against this TypeScript verifier. Run: `npm run build && node --test dist/index.test.js`.
4
- */
5
- export {};
6
- //# sourceMappingURL=index.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../src/index.test.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
@@ -1,85 +0,0 @@
1
- "use strict";
2
- /**
3
- * Interop tests: verify a receipt produced by the Python reference implementation
4
- * against this TypeScript verifier. Run: `npm run build && node --test dist/index.test.js`.
5
- */
6
- var __importDefault = (this && this.__importDefault) || function (mod) {
7
- return (mod && mod.__esModule) ? mod : { "default": mod };
8
- };
9
- Object.defineProperty(exports, "__esModule", { value: true });
10
- const node_test_1 = require("node:test");
11
- const strict_1 = __importDefault(require("node:assert/strict"));
12
- const index_js_1 = require("./index.js");
13
- /**
14
- * Fixture receipt shape, used here to exercise the structural checks.
15
- * Full signature-level interop is covered by the cross-implementation
16
- * runner at `scripts/make-interop-fixture.mjs`, which generates a receipt
17
- * with the reference issuer and verifies it with this library.
18
- */
19
- const FIXTURE_RECEIPT = {
20
- v: 1,
21
- attestation_id: 'a3f2b1c4-9d87-4e6f-b012-34567890abcd',
22
- trace_id: 'trace-fixture-v1',
23
- org_id: 'org-test',
24
- request_hash: '8f3a7e2b9c4d5f6a1b0c9d8e7f6a5b4c3d2e1f0a9b8c7d6e5f4a3b2c1d0e9f8a',
25
- model: 'gpt-4o',
26
- outcome: 'ALLOWED',
27
- policy_applied: ['budget_guard', 'loop_guard'],
28
- cost_prevented_eur: 0.0,
29
- timestamp: '2026-04-23T10:15:30.123456+00:00',
30
- public_key: '', // populated by make-test-fixture.py
31
- signature: '', // populated by make-test-fixture.py
32
- };
33
- (0, node_test_1.test)('rejects empty object', () => {
34
- const res = (0, index_js_1.verifyReceipt)({});
35
- strict_1.default.equal(res.valid, false);
36
- });
37
- (0, node_test_1.test)('rejects missing required field', () => {
38
- const bad = { ...FIXTURE_RECEIPT };
39
- delete bad.outcome;
40
- const res = (0, index_js_1.verifyReceipt)(bad);
41
- strict_1.default.equal(res.valid, false);
42
- strict_1.default.match(res.reason ?? '', /missing required field/);
43
- });
44
- (0, node_test_1.test)('rejects unknown top-level field (strict mode)', () => {
45
- const bad = { ...FIXTURE_RECEIPT, extra: 'foo' };
46
- const res = (0, index_js_1.verifyReceipt)(bad);
47
- strict_1.default.equal(res.valid, false);
48
- strict_1.default.match(res.reason ?? '', /unknown top-level field/);
49
- });
50
- (0, node_test_1.test)('rejects unsupported version', () => {
51
- const bad = { ...FIXTURE_RECEIPT, v: 2 };
52
- const res = (0, index_js_1.verifyReceipt)(bad);
53
- strict_1.default.equal(res.valid, false);
54
- strict_1.default.match(res.reason ?? '', /unsupported version/);
55
- });
56
- (0, node_test_1.test)('rejects invalid outcome', () => {
57
- const bad = { ...FIXTURE_RECEIPT, outcome: 'YOLO' };
58
- const res = (0, index_js_1.verifyReceipt)(bad);
59
- strict_1.default.equal(res.valid, false);
60
- strict_1.default.match(res.reason ?? '', /invalid outcome/);
61
- });
62
- (0, node_test_1.test)('rejects malformed request_hash', () => {
63
- const bad = { ...FIXTURE_RECEIPT, request_hash: 'not-a-hash' };
64
- const res = (0, index_js_1.verifyReceipt)(bad);
65
- strict_1.default.equal(res.valid, false);
66
- strict_1.default.match(res.reason ?? '', /request_hash/);
67
- });
68
- (0, node_test_1.test)('rejects pinned-key mismatch', () => {
69
- const res = (0, index_js_1.verifyReceipt)(FIXTURE_RECEIPT, {
70
- trustedPublicKey: 'different_key_000000000000000000000000000000',
71
- });
72
- strict_1.default.equal(res.valid, false);
73
- strict_1.default.match(res.reason ?? '', /does not match trusted key/);
74
- });
75
- // Note: full signature-verification interop test requires the fixture to be
76
- // populated by `scripts/make-test-fixture.py` before running this suite.
77
- // When FIXTURE_RECEIPT.signature is empty, the signature check is skipped.
78
- (0, node_test_1.test)('signature decoder rejects empty signature', () => {
79
- const res = (0, index_js_1.verifyReceipt)(FIXTURE_RECEIPT);
80
- strict_1.default.equal(res.valid, false);
81
- // Either the empty signature fails decode or fails length check
82
- strict_1.default.ok(/signature/.test(res.reason ?? '') ||
83
- /signature length/.test(res.reason ?? ''));
84
- });
85
- //# sourceMappingURL=index.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.test.js","sourceRoot":"","sources":["../src/index.test.ts"],"names":[],"mappings":"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"}