@engramx/client 0.15.0 → 0.16.0-rc.2
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 +255 -26
- package/dist/EngramClient.d.ts +235 -229
- package/dist/EngramClient.js +446 -1247
- package/dist/EngramClient.js.map +1 -1
- package/dist/MarketClient.d.ts +137 -0
- package/dist/MarketClient.js +228 -0
- package/dist/MarketClient.js.map +1 -0
- package/dist/ProfileManager.d.ts +4 -4
- package/dist/SessionManager.d.ts +3 -3
- package/dist/SessionManager.js +1 -1
- package/dist/SessionManager.js.map +1 -1
- package/dist/actionReceipt.d.ts +59 -0
- package/dist/actionReceipt.js +68 -2
- package/dist/actionReceipt.js.map +1 -1
- package/dist/auth.d.ts +16 -0
- package/dist/auth.js +38 -5
- package/dist/auth.js.map +1 -1
- package/dist/certifiedAudit.d.ts +32 -6
- package/dist/certifiedAudit.js +75 -14
- package/dist/certifiedAudit.js.map +1 -1
- package/dist/cli.js +95 -26
- package/dist/cli.js.map +1 -1
- package/dist/encryption.d.ts +26 -12
- package/dist/encryption.js +13 -15
- package/dist/encryption.js.map +1 -1
- package/dist/generated/engram.idl.d.ts +6 -0
- package/dist/generated/engram.idl.js +1366 -0
- package/dist/generated/engram.idl.js.map +1 -0
- package/dist/generated/market.idl.d.ts +6 -0
- package/dist/generated/market.idl.js +557 -0
- package/dist/generated/market.idl.js.map +1 -0
- package/dist/generated/registry.idl.d.ts +6 -0
- package/dist/generated/registry.idl.js +510 -0
- package/dist/generated/registry.idl.js.map +1 -0
- package/dist/idl.d.ts +66 -0
- package/dist/idl.js +227 -0
- package/dist/idl.js.map +1 -0
- package/dist/index.d.ts +12 -18
- package/dist/index.js +54 -9
- package/dist/index.js.map +1 -1
- package/dist/ledgerfsHash.js +1 -1
- package/dist/ledgerfsHash.js.map +1 -1
- package/dist/lineage.js +8 -5
- package/dist/lineage.js.map +1 -1
- package/dist/memoryArchive.d.ts +384 -0
- package/dist/memoryArchive.js +477 -0
- package/dist/memoryArchive.js.map +1 -0
- package/dist/migrate.js +31 -4
- package/dist/migrate.js.map +1 -1
- package/dist/openEngram.d.ts +48 -0
- package/dist/openEngram.js +161 -0
- package/dist/openEngram.js.map +1 -0
- package/dist/pair.d.ts +33 -2
- package/dist/pair.js +56 -9
- package/dist/pair.js.map +1 -1
- package/dist/types.d.ts +244 -307
- package/dist/version.d.ts +8 -0
- package/dist/version.js +45 -0
- package/dist/version.js.map +1 -0
- package/dist/wire.d.ts +76 -0
- package/dist/wire.js +79 -0
- package/dist/wire.js.map +1 -0
- package/package.json +3 -13
- package/dist/bootstrap.d.ts +0 -21
- package/dist/bootstrap.js +0 -71
- package/dist/bootstrap.js.map +0 -1
package/dist/ProfileManager.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* reading/writing user identity, preferences, and accumulated knowledge
|
|
6
6
|
* without callers needing to know the path layout.
|
|
7
7
|
*/
|
|
8
|
-
import type { EngramClient } from './EngramClient.js';
|
|
8
|
+
import type { EngramClient, MemoryReceipt } from './EngramClient.js';
|
|
9
9
|
export interface Profile {
|
|
10
10
|
/** Agent personality (SOUL.md) — may be null if not yet set */
|
|
11
11
|
soul: string | null;
|
|
@@ -40,16 +40,16 @@ export declare class ProfileManager {
|
|
|
40
40
|
/**
|
|
41
41
|
* Save a preference. Appends a timestamped entry to identity/preferences.md.
|
|
42
42
|
*/
|
|
43
|
-
savePreference(preference: string): Promise<
|
|
43
|
+
savePreference(preference: string): Promise<MemoryReceipt | null>;
|
|
44
44
|
/**
|
|
45
45
|
* Save an insight or lesson learned. Appends to knowledge/lessons.md,
|
|
46
46
|
* or to a domain-specific file if topic is provided.
|
|
47
47
|
*/
|
|
48
|
-
saveInsight(insight: Insight): Promise<
|
|
48
|
+
saveInsight(insight: Insight): Promise<MemoryReceipt | null>;
|
|
49
49
|
/**
|
|
50
50
|
* Save a decision with rationale. Appends to knowledge/decisions.md.
|
|
51
51
|
*/
|
|
52
|
-
saveDecision(decision: string, rationale: string): Promise<
|
|
52
|
+
saveDecision(decision: string, rationale: string): Promise<MemoryReceipt | null>;
|
|
53
53
|
/**
|
|
54
54
|
* Read the lessons file. Returns null if it doesn't exist.
|
|
55
55
|
*/
|
package/dist/SessionManager.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* summaries to its own namespace (sessions/{platform}/), enabling
|
|
6
6
|
* cross-platform continuity ("what was I working on with OpenClaw?").
|
|
7
7
|
*/
|
|
8
|
-
import type { EngramClient } from './EngramClient.js';
|
|
8
|
+
import type { EngramClient, MemoryReceipt } from './EngramClient.js';
|
|
9
9
|
export interface SessionSummary {
|
|
10
10
|
platform: string;
|
|
11
11
|
date: string;
|
|
@@ -15,7 +15,7 @@ export interface SessionEntry {
|
|
|
15
15
|
path: string;
|
|
16
16
|
platform: string;
|
|
17
17
|
date: string;
|
|
18
|
-
|
|
18
|
+
lastModifiedAtNs: bigint;
|
|
19
19
|
}
|
|
20
20
|
export declare class SessionManager {
|
|
21
21
|
private readonly client;
|
|
@@ -23,7 +23,7 @@ export declare class SessionManager {
|
|
|
23
23
|
/**
|
|
24
24
|
* Write or append a session summary for the current platform and date.
|
|
25
25
|
*/
|
|
26
|
-
writeSummary(platform: string, content: string, date?: string): Promise<
|
|
26
|
+
writeSummary(platform: string, content: string, date?: string): Promise<MemoryReceipt | null>;
|
|
27
27
|
/**
|
|
28
28
|
* Read a specific session summary.
|
|
29
29
|
*/
|
package/dist/SessionManager.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SessionManager.js","sourceRoot":"","sources":["../src/SessionManager.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAe/D,MAAM,OAAO,cAAc;IACzB,YAA6B,MAAoB;QAApB,WAAM,GAAN,MAAM,CAAc;IAAG,CAAC;IAErD;;OAEG;IACH,KAAK,CAAC,YAAY,
|
|
1
|
+
{"version":3,"file":"SessionManager.js","sourceRoot":"","sources":["../src/SessionManager.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAe/D,MAAM,OAAO,cAAc;IACzB,YAA6B,MAAoB;QAApB,WAAM,GAAN,MAAM,CAAc;IAAG,CAAC;IAErD;;OAEG;IACH,KAAK,CAAC,YAAY,CAChB,QAAgB,EAChB,OAAe,EACf,IAAa;QAEb,MAAM,CAAC,GAAG,IAAI,IAAI,KAAK,EAAE,CAAC;QAC1B,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;QAC3C,OAAO,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,EAAE,mBAAmB,CAAC,CAAC;IACtE,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,WAAW,CAAC,QAAgB,EAAE,IAAY;QAC9C,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC;YAC5E,OAAO,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC;QAC9B,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,YAAY,CAAC,QAAiB;QAClC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,eAAe,EAAE,CAAC;QACrD,MAAM,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC;QAEvE,OAAO,QAAQ;aACZ,MAAM,CAAC,CAAC,CAAiB,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;aACxD,GAAG,CAAC,CAAC,CAAiB,EAAE,EAAE;YACzB,MAAM,IAAI,GAAG,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YACrC,MAAM,SAAS,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC;YAC3D,OAAO;gBACL,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,QAAQ,EAAE,IAAI,IAAI,SAAS;gBAC3B,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,SAAS;gBAC3C,gBAAgB,EAAE,CAAC,CAAC,gBAAgB;aACrC,CAAC;QACJ,CAAC,CAAC;aACD,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;YACb,yCAAyC;YACzC,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI;gBAAE,OAAO,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACvD,OAAO,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;QAC9C,CAAC,CAAC,CAAC;IACP,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,UAAU,CAAC,QAAgB,CAAC;QAChC,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,YAAY,EAAE,CAAC;QAC1C,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;QAEvC,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACxC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,CAAC;QAElC,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;QAEzD,OAAO,MAAM;aACV,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;YACb,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,CAAC;YACvD,IAAI,CAAC,MAAM;gBAAE,OAAO,IAAI,CAAC;YACzB,MAAM,CAAC,EAAE,WAAW,CAAC,GAAG,MAAM,CAAC;YAC/B,IAAI,WAAW,YAAY,KAAK;gBAAE,OAAO,IAAI,CAAC;YAC9C,OAAO;gBACL,QAAQ,EAAE,KAAK,CAAC,QAAQ;gBACxB,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,OAAO,EAAE,WAAW,CAAC,OAAO;aAC7B,CAAC;QACJ,CAAC,CAAC;aACD,MAAM,CAAC,CAAC,CAAC,EAAuB,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;IACpD,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,iBAAiB,CAAC,eAAuB,EAAE,QAAgB,CAAC;QAChE,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,YAAY,EAAE,CAAC;QAC1C,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,eAAe,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;QAEpF,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACvC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,CAAC;QAElC,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;QAEzD,OAAO,KAAK;aACT,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;YACb,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,CAAC;YACvD,IAAI,CAAC,MAAM;gBAAE,OAAO,IAAI,CAAC;YACzB,MAAM,CAAC,EAAE,WAAW,CAAC,GAAG,MAAM,CAAC;YAC/B,IAAI,WAAW,YAAY,KAAK;gBAAE,OAAO,IAAI,CAAC;YAC9C,OAAO;gBACL,QAAQ,EAAE,KAAK,CAAC,QAAQ;gBACxB,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,OAAO,EAAE,WAAW,CAAC,OAAO;aAC7B,CAAC;QACJ,CAAC,CAAC;aACD,MAAM,CAAC,CAAC,CAAC,EAAuB,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;IACpD,CAAC;CACF"}
|
package/dist/actionReceipt.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Ed25519KeyIdentity } from '@icp-sdk/core/identity';
|
|
2
|
+
import { Principal } from '@icp-sdk/core/principal';
|
|
2
3
|
/** The `ownerAuth` argument to the money-path methods (Candid: opt ActionAuth). */
|
|
3
4
|
export interface ActionAuth {
|
|
4
5
|
/** 32-byte raw Ed25519 public key of the owner's identity. */
|
|
@@ -24,6 +25,43 @@ export declare const actionFields: {
|
|
|
24
25
|
* `canisterId` MUST be the target engram's principal text (the receipt is bound to it).
|
|
25
26
|
*/
|
|
26
27
|
export declare function signAction(identity: Ed25519KeyIdentity, canisterId: string, operation: string, fields: string, nonce: bigint): Promise<ActionAuth>;
|
|
28
|
+
/**
|
|
29
|
+
* The purpose an enrolment statement names. MUST match src/shared/IdentityBinding.mo
|
|
30
|
+
* `ENROL_OPERATION`.
|
|
31
|
+
*/
|
|
32
|
+
export declare const ENROL_OPERATION = "agent.enrol";
|
|
33
|
+
/**
|
|
34
|
+
* The message an agent's ROOT key signs to enrol one per-client key on one engram — the owner's
|
|
35
|
+
* decision of 2026-09-28: one root key per agent, with an enrolled key per client. It is
|
|
36
|
+
* `actionMessage` with a fixed purpose, bound to the engram, the enrolled key and the invite code
|
|
37
|
+
* being redeemed (the invite is what makes a statement single-use: the engram burns it). The nonce
|
|
38
|
+
* is free and is NOT a replay guard — see `pairEnrolled` for why it exists.
|
|
39
|
+
* ⟨CORRECTED 2026-09-29, ic402 2.16.1⟩ `pairEnrolled` is gone: the engram's verifier no longer
|
|
40
|
+
* refuses valid signatures, so pairing sends one statement (`EngramClient.pairAgent`).
|
|
41
|
+
* ⟨CORRECTED 2026-09-29, later⟩ The nonce is gone too — it existed only for that re-signing — so
|
|
42
|
+
* the message is `engramx.action.v1|<engram>|agent.enrol|enrolled=<key>|invite=<code>`: the
|
|
43
|
+
* `actionMessage` prefix and parts with no `|nonce=` suffix, built directly here.
|
|
44
|
+
* MUST match src/shared/IdentityBinding.mo `enrolmentMessage` byte-for-byte; the Motoko test
|
|
45
|
+
* test/enrolment.test.mo verifies a signature produced by `signEnrolment` below.
|
|
46
|
+
*/
|
|
47
|
+
export declare function enrolmentMessage(canisterId: string, enrolledKey: string, inviteCode: string): Uint8Array;
|
|
48
|
+
/** The `enrolment` field of `pairAgent`'s argument (Candid: Enrolment). */
|
|
49
|
+
export interface Enrolment {
|
|
50
|
+
/** 32-byte raw Ed25519 public key of the agent's root. */
|
|
51
|
+
rootPubkey: Uint8Array;
|
|
52
|
+
/** The engram the statement is for. */
|
|
53
|
+
engram: Principal;
|
|
54
|
+
/** The per-client key being enrolled — the principal that will call `pairAgent`. */
|
|
55
|
+
enrolledKey: Principal;
|
|
56
|
+
/** 64-byte Ed25519 signature by the root over `enrolmentMessage`. */
|
|
57
|
+
signature: Uint8Array;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Sign an enrolment statement with the agent's root key. `root` must be an Ed25519 identity (the
|
|
61
|
+
* statement is Ed25519 by construction); `enrolledKey` is the per-client key's principal and
|
|
62
|
+
* `inviteCode` the code that key is about to redeem on `canisterId`.
|
|
63
|
+
*/
|
|
64
|
+
export declare function signEnrolment(root: Ed25519KeyIdentity, canisterId: string, enrolledKey: Principal, inviteCode: string): Promise<Enrolment>;
|
|
27
65
|
/** Encode an ActionAuth for the Candid `opt ActionAuth` argument. */
|
|
28
66
|
export declare function toCandidActionAuth(a: ActionAuth): [{
|
|
29
67
|
pubkey: number[];
|
|
@@ -34,6 +72,27 @@ export declare function toCandidActionAuth(a: ActionAuth): [{
|
|
|
34
72
|
* Verify a receipt without trusting EngramX: confirm the signature is by `pubkey` over the exact
|
|
35
73
|
* canonical action, and return the self-authenticating principal that key maps to — i.e. WHO
|
|
36
74
|
* authorized the action. A relying party compares that principal to the engram's known owner.
|
|
75
|
+
*
|
|
76
|
+
* ⟨2026-09-29⟩ MORE PERMISSIVE THAN THE ENGRAM. `Ed25519KeyIdentity.verify` uses @noble/curves in
|
|
77
|
+
* its ZIP-215 mode, which checks the cofactored equation and accepts small-order keys and some
|
|
78
|
+
* non-canonical encodings; the engram's check (ic402 2.16.1) is strict RFC 8032 and refuses them.
|
|
79
|
+
* So every receipt the engram accepted verifies here, but not every receipt that verifies here
|
|
80
|
+
* would have been accepted. A receipt under a small-order key derives a principal that is not the
|
|
81
|
+
* owner's, so the comparison above still refuses it. Making this strict needs @noble/curves as a
|
|
82
|
+
* direct dependency (`{ zip215: false }`); that is open.
|
|
83
|
+
*
|
|
84
|
+
* ⟨2026-10-01, the owner's ruling 6 A — supersedes the paragraph above, which stays as the record⟩
|
|
85
|
+
* AS STRICT AS THE ENGRAM. Verified with @noble/curves (a direct dependency of this package) in
|
|
86
|
+
* strict RFC 8032 mode (`zip215: false`): a small-order key, a non-canonical point encoding or a
|
|
87
|
+
* signature with S ≥ L is refused here exactly as the engram's check (ic402 2.16.1) refuses it.
|
|
88
|
+
* Every receipt the engram accepted verifies here, and every receipt that verifies here the engram
|
|
89
|
+
* would have accepted. The principal comparison the relying party makes is now a second check, not
|
|
90
|
+
* the only one. Measured 2026-10-01 with @noble/curves 1.9.7: the all-zero key with R = that key and
|
|
91
|
+
* S = 0 verifies under ZIP-215 (and under `Ed25519KeyIdentity.verify`) for ANY message, and is
|
|
92
|
+
* refused here — test/action-receipt.test.ts pins it. WHAT WOULD MAKE THIS WRONG: the engram's
|
|
93
|
+
* verifier loosening (a newer ic402), or @noble/curves changing what `zip215: false` means.
|
|
94
|
+
* A malformed key or signature (wrong length, a point that does not decode) is `verified: false`,
|
|
95
|
+
* never a throw — a relying party reads one boolean.
|
|
37
96
|
*/
|
|
38
97
|
export declare function verifyActionReceipt(canisterId: string, operation: string, fields: string, receipt: ActionAuth): {
|
|
39
98
|
verified: boolean;
|
package/dist/actionReceipt.js
CHANGED
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
// Scope + honesty: this only works for a DIRECT Ed25519 self-authenticating identity (the SDK/CLI
|
|
11
11
|
// session key). An Internet-Identity-delegated or secp256k1 owner cannot produce a matching receipt —
|
|
12
12
|
// they omit `ownerAuth` and the action proceeds as before (owner calls are already IC-authenticated).
|
|
13
|
-
import { Ed25519KeyIdentity } from '@icp-sdk/core/identity';
|
|
14
13
|
import { Principal } from '@icp-sdk/core/principal';
|
|
14
|
+
import { ed25519 } from '@noble/curves/ed25519.js';
|
|
15
15
|
// DER-SPKI prefix for an Ed25519 public key (RFC 8410); DER = this ‖ 32-byte raw key. Kept here so
|
|
16
16
|
// principal derivation needs no extra API surface and matches IdentityBinding.mo exactly.
|
|
17
17
|
const ED25519_SPKI_PREFIX = Uint8Array.from([
|
|
@@ -49,18 +49,84 @@ export async function signAction(identity, canisterId, operation, fields, nonce)
|
|
|
49
49
|
const pubkey = new Uint8Array(identity.getPublicKey().toRaw());
|
|
50
50
|
return { pubkey, signature, nonce };
|
|
51
51
|
}
|
|
52
|
+
/**
|
|
53
|
+
* The purpose an enrolment statement names. MUST match src/shared/IdentityBinding.mo
|
|
54
|
+
* `ENROL_OPERATION`.
|
|
55
|
+
*/
|
|
56
|
+
export const ENROL_OPERATION = 'agent.enrol';
|
|
57
|
+
/**
|
|
58
|
+
* The message an agent's ROOT key signs to enrol one per-client key on one engram — the owner's
|
|
59
|
+
* decision of 2026-09-28: one root key per agent, with an enrolled key per client. It is
|
|
60
|
+
* `actionMessage` with a fixed purpose, bound to the engram, the enrolled key and the invite code
|
|
61
|
+
* being redeemed (the invite is what makes a statement single-use: the engram burns it). The nonce
|
|
62
|
+
* is free and is NOT a replay guard — see `pairEnrolled` for why it exists.
|
|
63
|
+
* ⟨CORRECTED 2026-09-29, ic402 2.16.1⟩ `pairEnrolled` is gone: the engram's verifier no longer
|
|
64
|
+
* refuses valid signatures, so pairing sends one statement (`EngramClient.pairAgent`).
|
|
65
|
+
* ⟨CORRECTED 2026-09-29, later⟩ The nonce is gone too — it existed only for that re-signing — so
|
|
66
|
+
* the message is `engramx.action.v1|<engram>|agent.enrol|enrolled=<key>|invite=<code>`: the
|
|
67
|
+
* `actionMessage` prefix and parts with no `|nonce=` suffix, built directly here.
|
|
68
|
+
* MUST match src/shared/IdentityBinding.mo `enrolmentMessage` byte-for-byte; the Motoko test
|
|
69
|
+
* test/enrolment.test.mo verifies a signature produced by `signEnrolment` below.
|
|
70
|
+
*/
|
|
71
|
+
export function enrolmentMessage(canisterId, enrolledKey, inviteCode) {
|
|
72
|
+
return new TextEncoder().encode(`engramx.action.v1|${canisterId}|${ENROL_OPERATION}|enrolled=${enrolledKey}|invite=${inviteCode}`);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Sign an enrolment statement with the agent's root key. `root` must be an Ed25519 identity (the
|
|
76
|
+
* statement is Ed25519 by construction); `enrolledKey` is the per-client key's principal and
|
|
77
|
+
* `inviteCode` the code that key is about to redeem on `canisterId`.
|
|
78
|
+
*/
|
|
79
|
+
export async function signEnrolment(root, canisterId, enrolledKey, inviteCode) {
|
|
80
|
+
const message = enrolmentMessage(canisterId, enrolledKey.toText(), inviteCode);
|
|
81
|
+
return {
|
|
82
|
+
rootPubkey: new Uint8Array(root.getPublicKey().toRaw()),
|
|
83
|
+
engram: Principal.fromText(canisterId),
|
|
84
|
+
enrolledKey,
|
|
85
|
+
signature: new Uint8Array(await root.sign(message)),
|
|
86
|
+
};
|
|
87
|
+
}
|
|
52
88
|
/** Encode an ActionAuth for the Candid `opt ActionAuth` argument. */
|
|
53
89
|
export function toCandidActionAuth(a) {
|
|
54
90
|
return [{ pubkey: Array.from(a.pubkey), signature: Array.from(a.signature), nonce: a.nonce }];
|
|
55
91
|
}
|
|
92
|
+
/** Strict RFC 8032 Ed25519 verification; a key or signature that does not decode is `false`. */
|
|
93
|
+
function strictVerify(signature, message, pubkey) {
|
|
94
|
+
try {
|
|
95
|
+
return ed25519.verify(signature, message, pubkey, { zip215: false });
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
56
101
|
/**
|
|
57
102
|
* Verify a receipt without trusting EngramX: confirm the signature is by `pubkey` over the exact
|
|
58
103
|
* canonical action, and return the self-authenticating principal that key maps to — i.e. WHO
|
|
59
104
|
* authorized the action. A relying party compares that principal to the engram's known owner.
|
|
105
|
+
*
|
|
106
|
+
* ⟨2026-09-29⟩ MORE PERMISSIVE THAN THE ENGRAM. `Ed25519KeyIdentity.verify` uses @noble/curves in
|
|
107
|
+
* its ZIP-215 mode, which checks the cofactored equation and accepts small-order keys and some
|
|
108
|
+
* non-canonical encodings; the engram's check (ic402 2.16.1) is strict RFC 8032 and refuses them.
|
|
109
|
+
* So every receipt the engram accepted verifies here, but not every receipt that verifies here
|
|
110
|
+
* would have been accepted. A receipt under a small-order key derives a principal that is not the
|
|
111
|
+
* owner's, so the comparison above still refuses it. Making this strict needs @noble/curves as a
|
|
112
|
+
* direct dependency (`{ zip215: false }`); that is open.
|
|
113
|
+
*
|
|
114
|
+
* ⟨2026-10-01, the owner's ruling 6 A — supersedes the paragraph above, which stays as the record⟩
|
|
115
|
+
* AS STRICT AS THE ENGRAM. Verified with @noble/curves (a direct dependency of this package) in
|
|
116
|
+
* strict RFC 8032 mode (`zip215: false`): a small-order key, a non-canonical point encoding or a
|
|
117
|
+
* signature with S ≥ L is refused here exactly as the engram's check (ic402 2.16.1) refuses it.
|
|
118
|
+
* Every receipt the engram accepted verifies here, and every receipt that verifies here the engram
|
|
119
|
+
* would have accepted. The principal comparison the relying party makes is now a second check, not
|
|
120
|
+
* the only one. Measured 2026-10-01 with @noble/curves 1.9.7: the all-zero key with R = that key and
|
|
121
|
+
* S = 0 verifies under ZIP-215 (and under `Ed25519KeyIdentity.verify`) for ANY message, and is
|
|
122
|
+
* refused here — test/action-receipt.test.ts pins it. WHAT WOULD MAKE THIS WRONG: the engram's
|
|
123
|
+
* verifier loosening (a newer ic402), or @noble/curves changing what `zip215: false` means.
|
|
124
|
+
* A malformed key or signature (wrong length, a point that does not decode) is `verified: false`,
|
|
125
|
+
* never a throw — a relying party reads one boolean.
|
|
60
126
|
*/
|
|
61
127
|
export function verifyActionReceipt(canisterId, operation, fields, receipt) {
|
|
62
128
|
const message = actionMessage(canisterId, operation, fields, receipt.nonce);
|
|
63
|
-
const verified =
|
|
129
|
+
const verified = strictVerify(receipt.signature, message, receipt.pubkey);
|
|
64
130
|
const principal = Principal.selfAuthenticating(derOf(receipt.pubkey)).toText();
|
|
65
131
|
return { verified, principal };
|
|
66
132
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"actionReceipt.js","sourceRoot":"","sources":["../src/actionReceipt.ts"],"names":[],"mappings":"AAAA,mFAAmF;AACnF,EAAE;AACF,sGAAsG;AACtG,sGAAsG;AACtG,iGAAiG;AACjG,uGAAuG;AACvG,sGAAsG;AACtG,sCAAsC;AACtC,EAAE;AACF,kGAAkG;AAClG,sGAAsG;AACtG,sGAAsG;
|
|
1
|
+
{"version":3,"file":"actionReceipt.js","sourceRoot":"","sources":["../src/actionReceipt.ts"],"names":[],"mappings":"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"}
|
package/dist/auth.d.ts
CHANGED
|
@@ -15,3 +15,19 @@ export declare function identityFromSeed(seed: Uint8Array): Ed25519KeyIdentity;
|
|
|
15
15
|
* Returns the identity.
|
|
16
16
|
*/
|
|
17
17
|
export declare function generateSessionKey(keyPath: string): Ed25519KeyIdentity;
|
|
18
|
+
/**
|
|
19
|
+
* Load the agent's ROOT key, or create it the first time. ⟨2026-09-28, owner decision: one root key
|
|
20
|
+
* per agent, with an enrolled key per client⟩
|
|
21
|
+
*
|
|
22
|
+
* The root is the agent's lasting identity: the registry keeps its track record under this key's
|
|
23
|
+
* principal, and it signs one enrolment statement per client. So, unlike a per-client session key,
|
|
24
|
+
* it is NEVER regenerated once it exists — a new root is a new agent with an empty record. Same
|
|
25
|
+
* 32-byte seed file format and the same refusals (symlink, loose permissions, wrong size) as a
|
|
26
|
+
* session key, because it is the more valuable of the two.
|
|
27
|
+
* WHAT WOULD MAKE THIS WRONG: a caller that deletes and re-creates this file to "fix" an error —
|
|
28
|
+
* that silently starts a new agent.
|
|
29
|
+
*/
|
|
30
|
+
export declare function loadOrCreateRootKey(rootKeyPath: string): {
|
|
31
|
+
identity: Ed25519KeyIdentity;
|
|
32
|
+
created: boolean;
|
|
33
|
+
};
|
package/dist/auth.js
CHANGED
|
@@ -2,6 +2,7 @@ import { Ed25519KeyIdentity } from '@icp-sdk/core/identity';
|
|
|
2
2
|
import * as fs from 'fs';
|
|
3
3
|
import * as path from 'path';
|
|
4
4
|
import * as crypto from 'crypto';
|
|
5
|
+
import { VERSION } from './version.js';
|
|
5
6
|
/**
|
|
6
7
|
* Load or create an Ed25519 session key identity.
|
|
7
8
|
*
|
|
@@ -17,23 +18,23 @@ export function loadSessionKey(keyPath) {
|
|
|
17
18
|
// Refuse to load symlinked key files
|
|
18
19
|
const lstat = fs.lstatSync(resolvedPath);
|
|
19
20
|
if (lstat.isSymbolicLink()) {
|
|
20
|
-
throw new Error(`
|
|
21
|
+
throw new Error(`The key for this engram cannot be a symlink: ${resolvedPath}`);
|
|
21
22
|
}
|
|
22
23
|
// Refuse to load key files with overly permissive permissions
|
|
23
24
|
const stats = fs.statSync(resolvedPath);
|
|
24
25
|
const mode = stats.mode & 0o777;
|
|
25
26
|
if (mode & 0o077) {
|
|
26
|
-
throw new Error(`
|
|
27
|
+
throw new Error(`The key for this engram (${resolvedPath}) has insecure permissions (${mode.toString(8)}). ` +
|
|
27
28
|
`Expected 0600. Fix with: chmod 600 ${resolvedPath}`);
|
|
28
29
|
}
|
|
29
30
|
const seed = fs.readFileSync(resolvedPath);
|
|
30
31
|
if (seed.length !== 32) {
|
|
31
|
-
throw new Error(`Invalid
|
|
32
|
+
throw new Error(`Invalid key for this engram: expected 32 bytes, got ${seed.length}`);
|
|
32
33
|
}
|
|
33
34
|
return Ed25519KeyIdentity.generate(seed);
|
|
34
35
|
}
|
|
35
|
-
throw new Error(`
|
|
36
|
-
`Run 'pnpm dlx @engramx/client pair <invite-code> --engram <canister-id>' to create one.`);
|
|
36
|
+
throw new Error(`The key for this engram was not found. ` +
|
|
37
|
+
`Run 'pnpm dlx @engramx/client@${VERSION} pair <invite-code> --engram <canister-id>' to create one.`);
|
|
37
38
|
}
|
|
38
39
|
/**
|
|
39
40
|
* Create an Ed25519 identity from a raw 32-byte seed.
|
|
@@ -62,4 +63,36 @@ export function generateSessionKey(keyPath) {
|
|
|
62
63
|
fs.writeFileSync(resolvedPath, seed, { mode: 0o600 });
|
|
63
64
|
return Ed25519KeyIdentity.generate(seed);
|
|
64
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* Load the agent's ROOT key, or create it the first time. ⟨2026-09-28, owner decision: one root key
|
|
68
|
+
* per agent, with an enrolled key per client⟩
|
|
69
|
+
*
|
|
70
|
+
* The root is the agent's lasting identity: the registry keeps its track record under this key's
|
|
71
|
+
* principal, and it signs one enrolment statement per client. So, unlike a per-client session key,
|
|
72
|
+
* it is NEVER regenerated once it exists — a new root is a new agent with an empty record. Same
|
|
73
|
+
* 32-byte seed file format and the same refusals (symlink, loose permissions, wrong size) as a
|
|
74
|
+
* session key, because it is the more valuable of the two.
|
|
75
|
+
* WHAT WOULD MAKE THIS WRONG: a caller that deletes and re-creates this file to "fix" an error —
|
|
76
|
+
* that silently starts a new agent.
|
|
77
|
+
*/
|
|
78
|
+
export function loadOrCreateRootKey(rootKeyPath) {
|
|
79
|
+
const home = process.env['HOME'];
|
|
80
|
+
if (rootKeyPath.startsWith('~') && !home)
|
|
81
|
+
throw new Error('HOME environment variable is not set');
|
|
82
|
+
const resolvedPath = rootKeyPath.startsWith('~')
|
|
83
|
+
? path.join(home, rootKeyPath.slice(1))
|
|
84
|
+
: rootKeyPath;
|
|
85
|
+
// lstat, not exists: a dangling symlink must reach loadSessionKey's symlink refusal rather than
|
|
86
|
+
// read as "no root yet" and be overwritten by a fresh one.
|
|
87
|
+
let present = true;
|
|
88
|
+
try {
|
|
89
|
+
fs.lstatSync(resolvedPath);
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
present = false;
|
|
93
|
+
}
|
|
94
|
+
if (present)
|
|
95
|
+
return { identity: loadSessionKey(rootKeyPath), created: false };
|
|
96
|
+
return { identity: generateSessionKey(rootKeyPath), created: true };
|
|
97
|
+
}
|
|
65
98
|
//# sourceMappingURL=auth.js.map
|
package/dist/auth.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
|
package/dist/certifiedAudit.d.ts
CHANGED
|
@@ -32,16 +32,38 @@ export interface CertifiedLeaf {
|
|
|
32
32
|
why: string;
|
|
33
33
|
}
|
|
34
34
|
/** Verify one leaf of a certified tree (registry format). */
|
|
35
|
+
/**
|
|
36
|
+
* Unwrap a Candid `opt blob` as agent-js delivers it — 0- or 1-element array, or bare bytes.
|
|
37
|
+
*
|
|
38
|
+
* THE DEFECT THIS EXISTS FOR. `certificate` AND `witness` are both `opt blob` on the wire
|
|
39
|
+
* (`CertifiedAuditHead` in registry.did and engram.did). This unwrap was applied to `certificate`
|
|
40
|
+
* only; `witness` was passed straight to `Uint8Array.from(witness as number[])`. That does not
|
|
41
|
+
* throw. `Uint8Array.from([<Uint8Array>])` coerces its one element with `Number()`, which is NaN
|
|
42
|
+
* for a typed array, and NaN clamps to 0 — so a perfectly good witness became the ONE-BYTE array
|
|
43
|
+
* `[0]`. `Cbor.decode` reads 0x00 as the integer 0 and SUCCEEDS, so the "witness is not decodable
|
|
44
|
+
* CBOR" guard passed it, and `reconstruct(0)` fell out of its NodeType switch into
|
|
45
|
+
* `throw UNREACHABLE_ERROR`. The whole failure reached the caller as a bare `Error: unreachable`
|
|
46
|
+
* with an async stack vitest could not map. Measured 2026-08-25.
|
|
47
|
+
*
|
|
48
|
+
* The lesson generalises past this file: an opt read as bare bytes fails SILENTLY here rather than
|
|
49
|
+
* at the decoder, because every step downstream accepts the corrupted value. Unwrap at one place,
|
|
50
|
+
* for every opt-blob field, or the next field added repeats it.
|
|
51
|
+
*
|
|
52
|
+
* WHAT WOULD MAKE THIS WRONG: it tells a wrapper from bare bytes by the FIRST ELEMENT — a wrapper
|
|
53
|
+
* is empty, or holds an array/Uint8Array; bare bytes hold a number. A `number[][]` would be read
|
|
54
|
+
* as a wrapper, but no opt-blob field on this wire has that shape.
|
|
55
|
+
*/
|
|
56
|
+
export declare function optBytes(v: unknown): Uint8Array | number[] | null;
|
|
35
57
|
export declare function verifyCertifiedLeaf(agent: HttpAgent, canisterId: Principal | string, reply: {
|
|
36
58
|
certificate: [] | [Uint8Array | number[]] | Uint8Array | number[];
|
|
37
|
-
witness: Uint8Array | number[];
|
|
59
|
+
witness: [] | [Uint8Array | number[]] | Uint8Array | number[];
|
|
38
60
|
}, path: Uint8Array[]): Promise<CertifiedLeaf>;
|
|
39
61
|
/** Registry audit head, tree format — pair with the registry's getCertifiedHead(). */
|
|
40
62
|
export declare function verifyCertifiedRegistryHead(agent: HttpAgent, canisterId: Principal | string, reply: {
|
|
41
63
|
headHash: Uint8Array | number[];
|
|
42
64
|
size: bigint;
|
|
43
65
|
certificate: [] | [Uint8Array | number[]];
|
|
44
|
-
witness: Uint8Array | number[];
|
|
66
|
+
witness: [] | [Uint8Array | number[]] | Uint8Array | number[];
|
|
45
67
|
}): Promise<{
|
|
46
68
|
head: Uint8Array | null;
|
|
47
69
|
size: bigint;
|
|
@@ -52,13 +74,17 @@ export declare function verifyCertifiedRegistryHead(agent: HttpAgent, canisterId
|
|
|
52
74
|
* An engram's latest anchor, certified — pair with the registry's getCertifiedAnchor(engramId).
|
|
53
75
|
*
|
|
54
76
|
* The proven leaf bytes decode (standard Candid) to CertifiedAnchorLeaf v2:
|
|
55
|
-
* { version: nat (=2); engram: principal; total: nat; head: blob;
|
|
56
|
-
* wasmHash: text ("" = never installed by this registry); conflicts: nat; disputed: bool
|
|
57
|
-
*
|
|
77
|
+
* { version: nat (=2); engram: principal; total: nat; head: blob; atNs: int;
|
|
78
|
+
* wasmHash: text ("" = never installed by this registry); conflicts: nat; disputed: bool;
|
|
79
|
+
* refusedConflicts: nat }
|
|
80
|
+
* `disputed` says whether THIS head is the contradicted one; `refusedConflicts` counts the
|
|
81
|
+
* contradictory pushes refused once the engram reached the registry's per-engram cap (every
|
|
82
|
+
* recorded contradiction is kept forever — added 2026-09-28, owner decision on contradiction
|
|
83
|
+
* records); `wasmHash` attests the registry's own
|
|
58
84
|
* install record (not a live probe), refreshed at each leaf write.
|
|
59
85
|
*/
|
|
60
86
|
export declare function verifyCertifiedAnchor(agent: HttpAgent, registryId: Principal | string, engramId: Principal | string, reply: {
|
|
61
87
|
leaf: unknown;
|
|
62
88
|
certificate: [] | [Uint8Array | number[]];
|
|
63
|
-
witness: Uint8Array | number[];
|
|
89
|
+
witness: [] | [Uint8Array | number[]] | Uint8Array | number[];
|
|
64
90
|
}): Promise<CertifiedLeaf>;
|
package/dist/certifiedAudit.js
CHANGED
|
@@ -63,18 +63,44 @@ export async function verifyCertifiedAuditHead(agent, canisterId, claimed) {
|
|
|
63
63
|
import { Cbor, reconstruct, lookup_path } from '@icp-sdk/core/agent';
|
|
64
64
|
const utf8 = (s) => new TextEncoder().encode(s);
|
|
65
65
|
/** Verify one leaf of a certified tree (registry format). */
|
|
66
|
+
/**
|
|
67
|
+
* Unwrap a Candid `opt blob` as agent-js delivers it — 0- or 1-element array, or bare bytes.
|
|
68
|
+
*
|
|
69
|
+
* THE DEFECT THIS EXISTS FOR. `certificate` AND `witness` are both `opt blob` on the wire
|
|
70
|
+
* (`CertifiedAuditHead` in registry.did and engram.did). This unwrap was applied to `certificate`
|
|
71
|
+
* only; `witness` was passed straight to `Uint8Array.from(witness as number[])`. That does not
|
|
72
|
+
* throw. `Uint8Array.from([<Uint8Array>])` coerces its one element with `Number()`, which is NaN
|
|
73
|
+
* for a typed array, and NaN clamps to 0 — so a perfectly good witness became the ONE-BYTE array
|
|
74
|
+
* `[0]`. `Cbor.decode` reads 0x00 as the integer 0 and SUCCEEDS, so the "witness is not decodable
|
|
75
|
+
* CBOR" guard passed it, and `reconstruct(0)` fell out of its NodeType switch into
|
|
76
|
+
* `throw UNREACHABLE_ERROR`. The whole failure reached the caller as a bare `Error: unreachable`
|
|
77
|
+
* with an async stack vitest could not map. Measured 2026-08-25.
|
|
78
|
+
*
|
|
79
|
+
* The lesson generalises past this file: an opt read as bare bytes fails SILENTLY here rather than
|
|
80
|
+
* at the decoder, because every step downstream accepts the corrupted value. Unwrap at one place,
|
|
81
|
+
* for every opt-blob field, or the next field added repeats it.
|
|
82
|
+
*
|
|
83
|
+
* WHAT WOULD MAKE THIS WRONG: it tells a wrapper from bare bytes by the FIRST ELEMENT — a wrapper
|
|
84
|
+
* is empty, or holds an array/Uint8Array; bare bytes hold a number. A `number[][]` would be read
|
|
85
|
+
* as a wrapper, but no opt-blob field on this wire has that shape.
|
|
86
|
+
*/
|
|
87
|
+
// EXPORTED for the regression test in packages/client/test/certified-tree.test.ts, and NOT
|
|
88
|
+
// re-exported from index.ts — the published surface is unchanged. The witness path cannot be
|
|
89
|
+
// reached from a test without a real subnet signature (Certificate.create fails first), so
|
|
90
|
+
// testing the unwrap directly is the only coverage this defect class can actually have.
|
|
91
|
+
export function optBytes(v) {
|
|
92
|
+
return Array.isArray(v) && (v.length === 0 || Array.isArray(v[0]) || v[0] instanceof Uint8Array)
|
|
93
|
+
? v.length
|
|
94
|
+
? v[0]
|
|
95
|
+
: null
|
|
96
|
+
: v;
|
|
97
|
+
}
|
|
66
98
|
export async function verifyCertifiedLeaf(agent, canisterId, reply, path) {
|
|
67
99
|
const fail = (why) => ({ valueBytes: null, verified: false, why });
|
|
68
|
-
const
|
|
69
|
-
const certBytes = Array.isArray(raw) &&
|
|
70
|
-
(raw.length === 0 || Array.isArray(raw[0]) || raw[0] instanceof Uint8Array)
|
|
71
|
-
? raw.length
|
|
72
|
-
? raw[0]
|
|
73
|
-
: null
|
|
74
|
-
: raw;
|
|
100
|
+
const certBytes = optBytes(reply?.certificate);
|
|
75
101
|
if (!certBytes || certBytes.length === 0)
|
|
76
102
|
return fail('no certificate on the reply');
|
|
77
|
-
const witness = reply?.witness;
|
|
103
|
+
const witness = optBytes(reply?.witness);
|
|
78
104
|
if (!witness || witness.length === 0)
|
|
79
105
|
return fail('no witness on the reply');
|
|
80
106
|
const principal = typeof canisterId === 'string' ? Principal.fromText(canisterId) : canisterId;
|
|
@@ -92,7 +118,19 @@ export async function verifyCertifiedLeaf(agent, canisterId, reply, path) {
|
|
|
92
118
|
catch {
|
|
93
119
|
return fail('certificate did not verify against the root key');
|
|
94
120
|
}
|
|
95
|
-
|
|
121
|
+
// ⟨2026-08-25⟩ WRAPPED, like every other step in this function. `lookup_path` can THROW rather
|
|
122
|
+
// than return a status: @icp-sdk's `agent/certificate.ts` raises a bare `UNREACHABLE_ERROR` from
|
|
123
|
+
// its tree walk, and it was the only unguarded call here — so a malformed or unexpected tree
|
|
124
|
+
// escaped this verifier entirely and surfaced as `Error: unreachable` with an async stack vitest
|
|
125
|
+
// could not map. A verifier whose failure mode is an opaque crash cannot be used to decide
|
|
126
|
+
// whether evidence is good, which is the whole reason it exists.
|
|
127
|
+
let lookup;
|
|
128
|
+
try {
|
|
129
|
+
lookup = cert.lookup_path(['canister', principal.toUint8Array(), 'certified_data']);
|
|
130
|
+
}
|
|
131
|
+
catch (e) {
|
|
132
|
+
return fail(`certificate tree walk failed: ${e.message}`);
|
|
133
|
+
}
|
|
96
134
|
if (lookup.status !== LookupPathStatus.Found)
|
|
97
135
|
return fail('certified_data absent from certificate');
|
|
98
136
|
const certifiedData = new Uint8Array(lookupResultToBuffer(lookup));
|
|
@@ -103,12 +141,31 @@ export async function verifyCertifiedLeaf(agent, canisterId, reply, path) {
|
|
|
103
141
|
catch {
|
|
104
142
|
return fail('witness is not decodable CBOR');
|
|
105
143
|
}
|
|
106
|
-
|
|
144
|
+
// ⟨2026-08-25⟩ GUARDED. `reconstruct` and `lookup_path` are the SDK's two `UNREACHABLE_ERROR`
|
|
145
|
+
// throw sites reachable from here (certificate.ts, one in each), and both fire on a tree whose
|
|
146
|
+
// node tag they do not recognise — exactly what a witness that decoded to something other than a
|
|
147
|
+
// hash tree produces. Unguarded, that left this verifier as the one path in the client that
|
|
148
|
+
// reported neither `verified: true` nor a `why`: it threw a bare `Error: unreachable` past every
|
|
149
|
+
// caller. A verifier that cannot say why it failed to verify is the fail-to-empty class wearing
|
|
150
|
+
// the instrument's uniform, so both now come back as a refusal WITH a reason.
|
|
151
|
+
let rootHash;
|
|
152
|
+
try {
|
|
153
|
+
rootHash = new Uint8Array(await reconstruct(tree));
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
return fail('witness is decodable CBOR but not a hash tree');
|
|
157
|
+
}
|
|
107
158
|
if (rootHash.length !== certifiedData.length ||
|
|
108
159
|
!rootHash.every((b, i) => b === certifiedData[i])) {
|
|
109
160
|
return fail('witness root does not match certified_data');
|
|
110
161
|
}
|
|
111
|
-
|
|
162
|
+
let leaf;
|
|
163
|
+
try {
|
|
164
|
+
leaf = lookup_path(path, tree);
|
|
165
|
+
}
|
|
166
|
+
catch {
|
|
167
|
+
return fail('witness tree is malformed at the requested path');
|
|
168
|
+
}
|
|
112
169
|
if (leaf.status !== LookupPathStatus.Found)
|
|
113
170
|
return fail('path not found in witness');
|
|
114
171
|
return { valueBytes: new Uint8Array(lookupResultToBuffer(leaf)), verified: true, why: 'ok' };
|
|
@@ -131,9 +188,13 @@ export async function verifyCertifiedRegistryHead(agent, canisterId, reply) {
|
|
|
131
188
|
* An engram's latest anchor, certified — pair with the registry's getCertifiedAnchor(engramId).
|
|
132
189
|
*
|
|
133
190
|
* The proven leaf bytes decode (standard Candid) to CertifiedAnchorLeaf v2:
|
|
134
|
-
* { version: nat (=2); engram: principal; total: nat; head: blob;
|
|
135
|
-
* wasmHash: text ("" = never installed by this registry); conflicts: nat; disputed: bool
|
|
136
|
-
*
|
|
191
|
+
* { version: nat (=2); engram: principal; total: nat; head: blob; atNs: int;
|
|
192
|
+
* wasmHash: text ("" = never installed by this registry); conflicts: nat; disputed: bool;
|
|
193
|
+
* refusedConflicts: nat }
|
|
194
|
+
* `disputed` says whether THIS head is the contradicted one; `refusedConflicts` counts the
|
|
195
|
+
* contradictory pushes refused once the engram reached the registry's per-engram cap (every
|
|
196
|
+
* recorded contradiction is kept forever — added 2026-09-28, owner decision on contradiction
|
|
197
|
+
* records); `wasmHash` attests the registry's own
|
|
137
198
|
* install record (not a live probe), refreshed at each leaf write.
|
|
138
199
|
*/
|
|
139
200
|
export async function verifyCertifiedAnchor(agent, registryId, engramId, reply) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"certifiedAudit.js","sourceRoot":"","sources":["../src/certifiedAudit.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,EAAE;AACF,iGAAiG;AACjG,mGAAmG;AACnG,kGAAkG;AAClG,iGAAiG;AACjG,EAAE;AACF,mGAAmG;AACnG,mGAAmG;AACnG,8FAA8F;AAC9F,iGAAiG;AACjG,4EAA4E;AAE5E,OAAO,EACL,WAAW,EACX,oBAAoB,EACpB,gBAAgB,GAEjB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAqBpD;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,KAAgB,EAChB,UAA8B,EAC9B,OAA2B;IAE3B,MAAM,IAAI,GAAsB,EAAE,IAAI,EAAE,IAAI,UAAU,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;IACjG,IAAI,CAAC,OAAO,CAAC,WAAW;QAAE,OAAO,IAAI,CAAC,CAAC,yDAAyD;IAEhG,MAAM,SAAS,GAAG,OAAO,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC;IAE/F,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;IAC9B,IAAI,OAAO,IAAI,IAAI,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CACb,oGAAoG,CACrG,CAAC;IACJ,CAAC;IAED,IAAI,IAAiB,CAAC;IACtB,IAAI,CAAC;QACH,mFAAmF;QACnF,yFAAyF;QACzF,8BAA8B;QAC9B,IAAI,GAAG,MAAM,WAAW,CAAC,MAAM,CAAC;YAC9B,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,OAAO;YACP,SAAS,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE;YACpC,KAAK,EAAE,gFAAgF;SACxF,CAAC,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IAED,4EAA4E;IAC5E,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,UAAU,EAAE,SAAS,CAAC,YAAY,EAAE,EAAE,gBAAgB,CAAC,CAAC,CAAC;IAC1F,IAAI,MAAM,CAAC,MAAM,KAAK,gBAAgB,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IAC1D,MAAM,SAAS,GAAG,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAC/C,IAAI,CAAC,SAAS;QAAE,OAAO,IAAI,CAAC;IAE5B,gGAAgG;IAChG,MAAM,OAAO,GACX,OAAO,CAAC,QAAQ,CAAC,MAAM,KAAK,SAAS,CAAC,MAAM;QAC5C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;IACvD,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;AACpE,CAAC;AAED,mGAAmG;AACnG,+FAA+F;AAC/F,mGAAmG;AACnG,qGAAqG;AACrG,kGAAkG;AAClG,kGAAkG;AAElG,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAErE,MAAM,IAAI,GAAG,CAAC,CAAS,EAAc,EAAE,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAUpE,6DAA6D;AAC7D,MAAM,CAAC,KAAK,
|
|
1
|
+
{"version":3,"file":"certifiedAudit.js","sourceRoot":"","sources":["../src/certifiedAudit.ts"],"names":[],"mappings":"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"}
|