@treeship/verify 0.10.2 → 0.10.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
@@ -16,7 +16,7 @@ Three functions. Each accepts a parsed object, a JSON string, or a URL.
16
16
 
17
17
  ### `verifyReceipt(target)`
18
18
 
19
- Runs the JSON-level checks a Treeship Session Receipt carries: Merkle root recomputation, inclusion proof verification, leaf-count parity, timeline ordering, chain linkage.
19
+ Runs the JSON-level checks a Treeship Session Receipt carries: Merkle root recomputation, inclusion proof verification, leaf-count parity, timeline ordering.
20
20
 
21
21
  ```typescript
22
22
  import { verifyReceipt } from '@treeship/verify';
package/dist/index.d.ts CHANGED
@@ -1,3 +1,20 @@
1
+ /**
2
+ * Trust roots input shape. Mirrors the on-disk
3
+ * `~/.treeship/trust_roots.json` so the browser-side verifier sees the
4
+ * same data the CLI does.
5
+ */
6
+ export interface TrustRootInput {
7
+ key_id: string;
8
+ /** `ed25519:<base64url-no-pad>` */
9
+ public_key: string;
10
+ kind: 'hub_checkpoint' | 'ship' | 'agent_cert';
11
+ label?: string;
12
+ added_at?: string;
13
+ }
14
+ export interface TrustRootsBundle {
15
+ version: 1;
16
+ roots: TrustRootInput[];
17
+ }
1
18
  /** Accepted input shapes across all exported functions. */
2
19
  export type VerifyTarget = string | URL | Record<string, unknown>;
3
20
  export interface VerifyCheck {
@@ -48,9 +65,9 @@ export interface CrossVerifyResult {
48
65
  /**
49
66
  * Verify a Treeship Session Receipt. Runs the checks derivable from the
50
67
  * receipt JSON alone (Merkle root recomputation, inclusion proofs, leaf
51
- * count, timeline ordering, chain linkage). Signature verification on
52
- * individual envelopes requires the original envelope bytes and is out of
53
- * scope for URL-fetched receipts; use the `treeship verify` CLI for that.
68
+ * count, timeline ordering). Signature verification on individual envelopes
69
+ * requires the original envelope bytes and is out of scope for URL-fetched
70
+ * receipts; use the `treeship verify` CLI for that.
54
71
  *
55
72
  * Accepts:
56
73
  * - a parsed receipt object (best for callers that already have the JSON)
@@ -61,13 +78,19 @@ export interface CrossVerifyResult {
61
78
  export declare function verifyReceipt(target: VerifyTarget): Promise<VerifyReceiptResult>;
62
79
  /**
63
80
  * Verify an Agent Certificate. Checks the embedded Ed25519 signature
64
- * against the certificate's embedded public key, then optionally
81
+ * against a trust root the caller pins via `trustRoots`, then optionally
65
82
  * classifies the validity window relative to `now`.
66
83
  *
84
+ * `trustRoots` is REQUIRED for the signature to be accepted: as of the
85
+ * v0.10.3 trust-root audit fix, the previous self-signed behavior (trust
86
+ * the embedded pubkey) is gone. Pass the same JSON shape your CLI uses
87
+ * (`~/.treeship/trust_roots.json`) or an array of `TrustRootInput`.
88
+ * Omit it to get a deliberate fail-closed result for diagnostic UIs.
89
+ *
67
90
  * Omit `now` (or pass `undefined`) to defer validity classification
68
91
  * (signature-only). Pass a `Date` or RFC 3339 string to check expiry.
69
92
  */
70
- export declare function verifyCertificate(target: VerifyTarget, now?: Date | string): Promise<VerifyCertificateResult>;
93
+ export declare function verifyCertificate(target: VerifyTarget, now?: Date | string, trustRoots?: TrustRootsBundle | TrustRootInput[]): Promise<VerifyCertificateResult>;
71
94
  /**
72
95
  * Cross-verify a Session Receipt against an Agent Certificate. Answers
73
96
  * three questions in one call: do the receipt and certificate reference
@@ -75,6 +98,8 @@ export declare function verifyCertificate(target: VerifyTarget, now?: Date | str
75
98
  * session called authorized by the certificate?
76
99
  *
77
100
  * The `ok` field is the roll-up: true iff all three checks pass. Defaults
78
- * `now` to `Date.now()` if omitted.
101
+ * `now` to `Date.now()` if omitted. As with `verifyCertificate`,
102
+ * `trustRoots` is required for the certificate's embedded signature to
103
+ * be accepted.
79
104
  */
80
- export declare function crossVerify(receipt: VerifyTarget, certificate: VerifyTarget, now?: Date | string): Promise<CrossVerifyResult>;
105
+ export declare function crossVerify(receipt: VerifyTarget, certificate: VerifyTarget, now?: Date | string, trustRoots?: TrustRootsBundle | TrustRootInput[]): Promise<CrossVerifyResult>;
package/dist/index.js CHANGED
@@ -10,6 +10,15 @@
10
10
  // Same rules `treeship verify` applies from the CLI, same result shape.
11
11
  // If a new schema version lands in core, this package picks it up via
12
12
  // core-wasm without an API change here.
13
+ /** Empty bundle is valid input -- the verifier will fail-closed. */
14
+ function serializeTrustRoots(roots) {
15
+ if (!roots)
16
+ return '';
17
+ if (Array.isArray(roots)) {
18
+ return JSON.stringify({ version: 1, roots });
19
+ }
20
+ return JSON.stringify(roots);
21
+ }
13
22
  let wasmBindings = null;
14
23
  async function loadWasm() {
15
24
  if (wasmBindings)
@@ -36,9 +45,9 @@ async function normalizeToJson(target) {
36
45
  /**
37
46
  * Verify a Treeship Session Receipt. Runs the checks derivable from the
38
47
  * receipt JSON alone (Merkle root recomputation, inclusion proofs, leaf
39
- * count, timeline ordering, chain linkage). Signature verification on
40
- * individual envelopes requires the original envelope bytes and is out of
41
- * scope for URL-fetched receipts; use the `treeship verify` CLI for that.
48
+ * count, timeline ordering). Signature verification on individual envelopes
49
+ * requires the original envelope bytes and is out of scope for URL-fetched
50
+ * receipts; use the `treeship verify` CLI for that.
42
51
  *
43
52
  * Accepts:
44
53
  * - a parsed receipt object (best for callers that already have the JSON)
@@ -53,17 +62,23 @@ export async function verifyReceipt(target) {
53
62
  }
54
63
  /**
55
64
  * Verify an Agent Certificate. Checks the embedded Ed25519 signature
56
- * against the certificate's embedded public key, then optionally
65
+ * against a trust root the caller pins via `trustRoots`, then optionally
57
66
  * classifies the validity window relative to `now`.
58
67
  *
68
+ * `trustRoots` is REQUIRED for the signature to be accepted: as of the
69
+ * v0.10.3 trust-root audit fix, the previous self-signed behavior (trust
70
+ * the embedded pubkey) is gone. Pass the same JSON shape your CLI uses
71
+ * (`~/.treeship/trust_roots.json`) or an array of `TrustRootInput`.
72
+ * Omit it to get a deliberate fail-closed result for diagnostic UIs.
73
+ *
59
74
  * Omit `now` (or pass `undefined`) to defer validity classification
60
75
  * (signature-only). Pass a `Date` or RFC 3339 string to check expiry.
61
76
  */
62
- export async function verifyCertificate(target, now) {
77
+ export async function verifyCertificate(target, now, trustRoots) {
63
78
  const json = await normalizeToJson(target);
64
79
  const nowStr = now === undefined ? '' : now instanceof Date ? now.toISOString() : now;
65
80
  const wasm = await loadWasm();
66
- return JSON.parse(wasm.verify_certificate(json, nowStr));
81
+ return JSON.parse(wasm.verify_certificate(json, nowStr, serializeTrustRoots(trustRoots)));
67
82
  }
68
83
  /**
69
84
  * Cross-verify a Session Receipt against an Agent Certificate. Answers
@@ -72,9 +87,11 @@ export async function verifyCertificate(target, now) {
72
87
  * session called authorized by the certificate?
73
88
  *
74
89
  * The `ok` field is the roll-up: true iff all three checks pass. Defaults
75
- * `now` to `Date.now()` if omitted.
90
+ * `now` to `Date.now()` if omitted. As with `verifyCertificate`,
91
+ * `trustRoots` is required for the certificate's embedded signature to
92
+ * be accepted.
76
93
  */
77
- export async function crossVerify(receipt, certificate, now) {
94
+ export async function crossVerify(receipt, certificate, now, trustRoots) {
78
95
  const [receiptJson, certJson] = await Promise.all([
79
96
  normalizeToJson(receipt),
80
97
  normalizeToJson(certificate),
@@ -85,5 +102,5 @@ export async function crossVerify(receipt, certificate, now) {
85
102
  ? now.toISOString()
86
103
  : now;
87
104
  const wasm = await loadWasm();
88
- return JSON.parse(wasm.cross_verify(receiptJson, certJson, nowStr));
105
+ return JSON.parse(wasm.cross_verify(receiptJson, certJson, nowStr, serializeTrustRoots(trustRoots)));
89
106
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@treeship/verify",
3
- "version": "0.10.2",
3
+ "version": "0.10.4",
4
4
  "description": "Zero-dependency cryptographic verification for Treeship receipts and certificates. Runs anywhere WASM runs: Node, browser, Vercel Edge, Cloudflare Workers, AWS Lambda.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -40,7 +40,7 @@
40
40
  "test": "vitest run"
41
41
  },
42
42
  "dependencies": {
43
- "@treeship/core-wasm": "0.10.2"
43
+ "@treeship/core-wasm": "0.10.4"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@types/node": "^25.5.0",