@melra/receipt-schema 0.3.0-alpha.11 → 0.3.0-alpha.13

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
@@ -9,7 +9,7 @@ npm install @melra/receipt-schema
9
9
  ```
10
10
 
11
11
  ```ts
12
- import { createCertificate, redactStructuredValue, sha256 } from "@melra/receipt-schema";
12
+ import { createCertificate, redactSecrets, redactStructuredValue, sha256 } from "@melra/receipt-schema";
13
13
  ```
14
14
 
15
15
  A receipt records one action: the operation, the policy decision, the evidence
@@ -20,8 +20,14 @@ rather than trusted.
20
20
  `canonicalJson` sorts keys and normalises formatting before hashing, so the same
21
21
  logical value always produces the same digest across processes and platforms.
22
22
 
23
- `redactStructuredValue` strips credential-shaped values — tokens, keys, auth
24
- headers, connection strings — from anything before it is persisted. Raw output
23
+ `redactStructuredValue` strips credential-shaped values from anything before
24
+ it is persisted: fields named like secrets (`authorization`, `headers`,
25
+ `cookie`, `token`, `password`, `env`, `content`, `stdout`, …) are replaced
26
+ whole, URL query strings and fragments are dropped, and every other string goes
27
+ through `redactSecrets`. `SECRET_PATTERNS` — PEM private keys, AWS key IDs,
28
+ JWTs, Slack and GitHub tokens, common API keys, bearer tokens, and
29
+ password/secret assignments — is the one list memory and terminal output use
30
+ too, so a new secret format is added here once. Raw output
25
31
  goes to the live caller only; the durable copy is the redacted one. A new field
26
32
  that can carry a secret must pass through this, or through the memory package's
27
33
  equivalent, before it reaches storage.
package/dist/index.d.ts CHANGED
@@ -1,3 +1,30 @@
1
+ /**
2
+ * Secret shapes redacted wherever MELRA persists free text: receipts and task
3
+ * records here, memory values, and terminal output. One list, exported, because
4
+ * three private copies had drifted apart and none of them knew a PEM private
5
+ * key or an AWS access key id; GovBench found memory storing both verbatim.
6
+ *
7
+ * Only high-confidence shapes belong here. A pattern that fires on ordinary
8
+ * text corrupts the record it was meant to protect, so a secret without a
9
+ * recognisable shape is left to the field-name rule in redactStructuredValue.
10
+ */
11
+ export declare const SECRET_PATTERNS: ReadonlyArray<readonly [RegExp, string]>;
12
+ /** Every SECRET_PATTERNS match in `text` replaced, and which kinds were found. */
13
+ export declare function redactSecrets(text: string): {
14
+ value: string;
15
+ redactions: string[];
16
+ };
17
+ /**
18
+ * A command's arguments with the credentials taken out and everything else
19
+ * kept, so a receipt still says what ran (#122). A credential-named flag loses
20
+ * its value, attached or as the next argument; so do `-pPASSWORD`, the password
21
+ * half of `-u user:pass`, credential-named `NAME=value` assignments, auth
22
+ * headers, and URL userinfo. Every argument then goes through SECRET_PATTERNS.
23
+ */
24
+ export declare function redactArgv(argv: readonly string[], command?: string): {
25
+ value: string[];
26
+ redactions: string[];
27
+ };
1
28
  export type CertificateResult = "VERIFIED_SUCCESS" | "PARTIAL" | "FAILED" | "CANCELLED" | "WAITING_APPROVAL" | "WAITING_USER" | "POLICY_BLOCKED" | "BUDGET_EXHAUSTED"
2
29
  /** The effect may or may not have happened. Neither claim is available yet. */
3
30
  | "RECOVERY_REQUIRED";
@@ -74,6 +101,13 @@ export interface ActionReceipt {
74
101
  outcome: "allow" | "deny" | "confirm";
75
102
  policyVersion: string;
76
103
  approvalId?: string;
104
+ /** Who approved, through which channel, having been shown what. */
105
+ approval?: {
106
+ channel: string;
107
+ renderDigest: string;
108
+ approver: string;
109
+ decidedAt: string;
110
+ };
77
111
  };
78
112
  target: string;
79
113
  inputDigest: string;
@@ -95,6 +129,16 @@ export interface ExecutionCertificate {
95
129
  receiptIds: string[];
96
130
  evidence: EvidenceItem[];
97
131
  createdAt: string;
132
+ /** The deployment mode the task ran under, as on its receipts. */
133
+ mode?: string;
134
+ /**
135
+ * How the task's effect was authorised: `not_required` (a read),
136
+ * `bypassed` (a mutation allowed with no challenge, which only
137
+ * developer-mode unsafe-local permits), `in_band`, or `out_of_band`. One
138
+ * certificate covers one task, so this is that task's channel. Absent when
139
+ * nothing was authorised. Covered by `digest`, like every other field.
140
+ */
141
+ approvalChannel?: string;
98
142
  digest: string;
99
143
  }
100
144
  export declare function redactStructuredValue(value: unknown): {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAcA,MAAM,MAAM,iBAAiB,GACzB,kBAAkB,GAClB,SAAS,GACT,QAAQ,GACR,WAAW,GACX,kBAAkB,GAClB,cAAc,GACd,gBAAgB,GAChB,kBAAkB;AACpB,+EAA+E;GAC7E,mBAAmB,CAAC;AAExB;;;;;;;;GAQG;AACH,MAAM,MAAM,gBAAgB;AAC1B,mEAAmE;AACjE,WAAW;AACb,oDAAoD;GAClD,OAAO;AACT,qEAAqE;GACnE,aAAa;AACf,8FAA8F;GAC5F,UAAU,CAAC;AAoBf,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,CAE/D;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B;;;;;;;;OAQG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B,aAAa,EAAE,OAAO,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,GAAG,QAAQ,GAAG,aAAa,CAAC;IAC1C;;;;;;OAMG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;;;;;OAKG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,cAAc,EAAE;QACd,OAAO,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC;QACtC,aAAa,EAAE,MAAM,CAAC;QACtB,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC;IACF,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACxC,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,oBAAoB;IACnC,aAAa,EAAE,OAAO,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,iBAAiB,CAAC;IAC1B,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG;IACrD,KAAK,EAAE,OAAO,CAAC;IACf,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB,CAyDA;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAYpD;AAED,wBAAgB,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAE7C;AAED,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAED,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,IAAI,CAAC,oBAAoB,EAAE,eAAe,GAAG,eAAe,GAAG,QAAQ,CAAC,GAC9E,oBAAoB,CAQtB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,13 +1,124 @@
1
1
  // Copyright 2026 XAGI Labs Private Limited
2
2
  // SPDX-License-Identifier: Apache-2.0
3
3
  import { createHash, randomUUID } from "node:crypto";
4
- const SENSITIVE_KEY = /^(?:args?|authorization|constraints|content|cookie|env|goal|headers?|pass(?:word|wd)?|secret|std(?:out|err)|text|token|api[_-]?key|values?)$/i;
5
- const SECRET_PATTERNS = [
4
+ const SENSITIVE_KEY = /^(?:arg|authorization|constraints|content|cookie|env|goal|headers?|input|pass(?:word|wd)?|secret|std(?:out|err)|text|token|api[_-]?key|values?)$/i;
5
+ /**
6
+ * Secret shapes redacted wherever MELRA persists free text: receipts and task
7
+ * records here, memory values, and terminal output. One list, exported, because
8
+ * three private copies had drifted apart and none of them knew a PEM private
9
+ * key or an AWS access key id; GovBench found memory storing both verbatim.
10
+ *
11
+ * Only high-confidence shapes belong here. A pattern that fires on ordinary
12
+ * text corrupts the record it was meant to protect, so a secret without a
13
+ * recognisable shape is left to the field-name rule in redactStructuredValue.
14
+ */
15
+ export const SECRET_PATTERNS = [
16
+ // A whole PEM private key block, and a truncated one (output cut mid-key).
17
+ [
18
+ /-----BEGIN (?:[A-Z0-9]+ )*PRIVATE KEY-----[\s\S]*?-----END (?:[A-Z0-9]+ )*PRIVATE KEY-----/g,
19
+ "[REDACTED_PRIVATE_KEY]",
20
+ ],
21
+ [/-----BEGIN (?:[A-Z0-9]+ )*PRIVATE KEY-----[\s\S]*/g, "[REDACTED_PRIVATE_KEY]"],
22
+ [/\b(?:AKIA|ASIA)[A-Z0-9]{16}\b/g, "[REDACTED_AWS_KEY_ID]"],
23
+ [/\beyJ[A-Za-z0-9_-]{8,}\.eyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g, "[REDACTED_JWT]"],
24
+ [/\bxox[abposr]-[A-Za-z0-9-]{10,}\b/g, "[REDACTED_SLACK_TOKEN]"],
6
25
  [/\bgh[opurs]_[A-Za-z0-9]{20,}\b/g, "[REDACTED_GITHUB_TOKEN]"],
7
26
  [/\b(?:sk|pk|api)[-_][a-z0-9_-]{16,}\b/gi, "[REDACTED_API_KEY]"],
8
27
  [/\bBearer\s+[A-Za-z0-9._~+/-]+=*\b/gi, "Bearer [REDACTED_TOKEN]"],
9
- [/\b(password|passwd|secret)\s*[:=]\s*\S+/gi, "$1=[REDACTED]"],
28
+ // `password=x`, and the spellings that hide the word inside a longer name or
29
+ // behind a quote: `DB_PASSWORD=x`, `AWS_SECRET_ACCESS_KEY: x`, `"password": "x"`.
30
+ [
31
+ /(?<![A-Za-z0-9])((?:[A-Za-z0-9]+_)*(?:password|passwd|passphrase|secret)(?:_[A-Za-z0-9]+)*)(["']?)\s*[:=]\s*["']?[^\s"',;}]+/gi,
32
+ "$1$2=[REDACTED]",
33
+ ],
34
+ // Userinfo in a URL or connection string anywhere in text: `postgres://app:pw@db`.
35
+ [/\b([a-z][a-z0-9+.-]*:\/\/)[^\s/@:]*:[^\s/@]+@/gi, "$1[REDACTED_URL_CREDENTIALS]@"],
10
36
  ];
37
+ /** Every SECRET_PATTERNS match in `text` replaced, and which kinds were found. */
38
+ export function redactSecrets(text) {
39
+ let value = text;
40
+ const redactions = [];
41
+ for (const [pattern, replacement] of SECRET_PATTERNS) {
42
+ const before = value;
43
+ value = value.replace(pattern, replacement);
44
+ if (value !== before && !redactions.includes(replacement))
45
+ redactions.push(replacement);
46
+ }
47
+ return { value, redactions };
48
+ }
49
+ // A flag whose value is a credential, `--token x` or `--token=x`, matched on
50
+ // the flag's name because the value itself may have no recognisable shape.
51
+ // The credential word may lead a longer name too: `--secret-key`,
52
+ // `--s3-secret-access-key`, `--passphrase`.
53
+ const SECRET_FLAG = /^(--?(?:[a-z0-9]+[-_])*(?:token|password|passwd|passphrase|pass|secret|api[-_]?key|apikey|auth|authorization|credentials?|cookie|private[-_]?key)(?:[-_][a-z0-9]+)*)(?:=([\s\S]*))?$/i;
54
+ // `-u user:pass` / `--user user:pass` (curl, wget), and curl's proxy forms:
55
+ // only the part after the colon is a secret, and `sort -u`, `git add -u` take
56
+ // no value at all.
57
+ const USER_FLAG = /^(?:-u|--user|-U|--proxy-user)$/;
58
+ // The same, attached: `-ualice:pw`.
59
+ const ATTACHED_USER = /^(-u[^:\s]+):[\s\S]+$/;
60
+ // `-pPASSWORD` (mysql and friends). Never the next argument: `mkdir -p dir`,
61
+ // `ssh -p 22`. Only after a mysql-family program, because `find -print` and
62
+ // `gcc -pthread` have the same shape. A remainder under three characters is
63
+ // read as bundled short flags (`-pv`, `-pr`), not a password.
64
+ const ATTACHED_PASSWORD = /^-p(.{3,})$/s;
65
+ const MYSQL_FAMILY = /^(?:mysql[a-z]*|mariadb[a-z-]*)(?:\.exe)?$/i;
66
+ // `NAME=value` with a credential-like name, as `env FOO_TOKEN=x cmd` passes it.
67
+ const SECRET_ASSIGNMENT = /^([A-Za-z_][A-Za-z0-9_]*(?:KEY|TOKEN|SECRET|PASSWORD|PASSWD|PASS|AUTH|CREDENTIALS?))=[\s\S]*$/i;
68
+ // A header given as one argument, as `curl -H 'Authorization: Bearer x'` does.
69
+ const SECRET_HEADER = /^((?:--header=|-H)?(?:(?:proxy-)?authorization|cookie|[a-z0-9-]*(?:token|api-?key|secret)))\s*:[\s\S]*$/i;
70
+ // Credentials inside a URL or connection string: `postgres://user:pass@host`,
71
+ // and `redis://:pass@host`, whose username is usually empty.
72
+ const URL_CREDENTIALS = /(\/\/)[^\s/@:]*:[^\s/@]+@/g;
73
+ const REDACTED_ARG = "[REDACTED_SENSITIVE_ARG]";
74
+ function redactOneArg(arg, previous, mysql) {
75
+ if (previous !== undefined) {
76
+ const flag = SECRET_FLAG.exec(previous);
77
+ if (flag !== null && flag[2] === undefined)
78
+ return REDACTED_ARG;
79
+ if (USER_FLAG.test(previous) && arg.includes(":")) {
80
+ return `${arg.slice(0, arg.indexOf(":"))}:${REDACTED_ARG}`;
81
+ }
82
+ }
83
+ const flag = SECRET_FLAG.exec(arg);
84
+ if (flag?.[2] !== undefined)
85
+ return `${flag[1]}=${REDACTED_ARG}`;
86
+ if (mysql && ATTACHED_PASSWORD.test(arg))
87
+ return `-p${REDACTED_ARG}`;
88
+ if (ATTACHED_USER.test(arg))
89
+ return arg.replace(ATTACHED_USER, `$1:${REDACTED_ARG}`);
90
+ if (SECRET_ASSIGNMENT.test(arg))
91
+ return arg.replace(SECRET_ASSIGNMENT, `$1=${REDACTED_ARG}`);
92
+ if (SECRET_HEADER.test(arg))
93
+ return arg.replace(SECRET_HEADER, `$1: ${REDACTED_ARG}`);
94
+ return arg.replace(URL_CREDENTIALS, `$1${REDACTED_ARG}@`);
95
+ }
96
+ /**
97
+ * A command's arguments with the credentials taken out and everything else
98
+ * kept, so a receipt still says what ran (#122). A credential-named flag loses
99
+ * its value, attached or as the next argument; so do `-pPASSWORD`, the password
100
+ * half of `-u user:pass`, credential-named `NAME=value` assignments, auth
101
+ * headers, and URL userinfo. Every argument then goes through SECRET_PATTERNS.
102
+ */
103
+ export function redactArgv(argv, command) {
104
+ const redactions = new Set();
105
+ // Unknown program: read `-pXXXX` as a password, the cautious side.
106
+ const program = (name) => MYSQL_FAMILY.test(name.split(/[\\/]/).pop() ?? "");
107
+ let mysql = command === undefined || program(command);
108
+ const value = argv.map((arg, index) => {
109
+ // `env`, `sudo` and friends put the program among the arguments.
110
+ if (program(arg))
111
+ mysql = true;
112
+ const out = redactOneArg(arg, index === 0 ? undefined : argv[index - 1], mysql);
113
+ if (out !== arg)
114
+ redactions.add(REDACTED_ARG);
115
+ const redacted = redactSecrets(out);
116
+ for (const kind of redacted.redactions)
117
+ redactions.add(kind);
118
+ return redacted.value;
119
+ });
120
+ return { value, redactions: [...redactions] };
121
+ }
11
122
  /**
12
123
  * Only the types that outrank `execution` are listed. An unrecognised type —
13
124
  * an older receipt, a predicate added without a decision here — reads as the
@@ -43,10 +154,23 @@ export function redactStructuredValue(value) {
43
154
  }
44
155
  return "[REDACTED_SENSITIVE_FIELD]";
45
156
  };
46
- const visit = (current, key) => {
157
+ const visit = (current, key, parent) => {
47
158
  if (key !== undefined && SENSITIVE_KEY.test(key)) {
48
159
  return redactWholeValue(current);
49
160
  }
161
+ if (key === "args") {
162
+ // Arguments are what a receipt most needs to show, so only their
163
+ // credentials go; anything that is not a list of strings goes whole.
164
+ if (!Array.isArray(current) || !current.every((item) => typeof item === "string")) {
165
+ return redactWholeValue(current);
166
+ }
167
+ // The program sits beside its arguments, as `command`.
168
+ const command = typeof parent?.command === "string" ? parent.command : undefined;
169
+ const redacted = redactArgv(current, command);
170
+ for (const kind of redacted.redactions)
171
+ redactions.add(kind);
172
+ return redacted.value;
173
+ }
50
174
  if (key === "url" && typeof current === "string") {
51
175
  try {
52
176
  const url = new URL(current);
@@ -55,21 +179,26 @@ export function redactStructuredValue(value) {
55
179
  url.search = "";
56
180
  url.hash = "";
57
181
  }
58
- return url.toString();
182
+ if (url.username !== "" || url.password !== "") {
183
+ redactions.add("[REDACTED_URL_CREDENTIALS]");
184
+ url.username = "";
185
+ url.password = "";
186
+ }
187
+ // Then the shapes any string gets: a token in the path is still a token.
188
+ const redacted = redactSecrets(url.toString());
189
+ for (const kind of redacted.redactions)
190
+ redactions.add(kind);
191
+ return redacted.value;
59
192
  }
60
193
  catch {
61
194
  // Non-URL strings continue through normal pattern redaction.
62
195
  }
63
196
  }
64
197
  if (typeof current === "string") {
65
- let redacted = current;
66
- for (const [pattern, replacement] of SECRET_PATTERNS) {
67
- const before = redacted;
68
- redacted = redacted.replace(pattern, replacement);
69
- if (redacted !== before)
70
- redactions.add(replacement);
71
- }
72
- return redacted;
198
+ const redacted = redactSecrets(current);
199
+ for (const kind of redacted.redactions)
200
+ redactions.add(kind);
201
+ return redacted.value;
73
202
  }
74
203
  if (Array.isArray(current)) {
75
204
  return current.map((item) => visit(item));
@@ -77,7 +206,7 @@ export function redactStructuredValue(value) {
77
206
  if (current !== null && typeof current === "object") {
78
207
  return Object.fromEntries(Object.entries(current).map(([entryKey, entryValue]) => [
79
208
  entryKey,
80
- visit(entryValue, entryKey),
209
+ visit(entryValue, entryKey, current),
81
210
  ]));
82
211
  }
83
212
  return current;
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,6 +1,6 @@
1
1
  {
2
2
  "name": "@melra/receipt-schema",
3
- "version": "0.3.0-alpha.11",
3
+ "version": "0.3.0-alpha.13",
4
4
  "description": "Canonical receipts, redaction, and execution certificates for MELRA.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -24,6 +24,6 @@
24
24
  "build": "tsc -p tsconfig.json",
25
25
  "clean": "rm -rf dist",
26
26
  "test": "vitest run --passWithNoTests",
27
- "typecheck": "tsc -p tsconfig.json --noEmit"
27
+ "typecheck": "tsc -p tsconfig.test.json"
28
28
  }
29
29
  }
@@ -1,2 +0,0 @@
1
- export {};
2
- //# 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":""}
@@ -1,49 +0,0 @@
1
- // Copyright 2026 XAGI Labs Private Limited
2
- // SPDX-License-Identifier: Apache-2.0
3
- import { describe, expect, it } from "vitest";
4
- import { canonicalJson, createCertificate, evidenceStrength, redactStructuredValue, sha256, } from "./index.js";
5
- describe("receipt and certificate primitives", () => {
6
- it("canonicalizes object keys before hashing", () => {
7
- expect(canonicalJson({ b: 2, a: { d: 4, c: 3 } })).toBe('{"a":{"c":3,"d":4},"b":2}');
8
- expect(sha256({ b: 2, a: 1 })).toBe(sha256({ a: 1, b: 2 }));
9
- });
10
- it("binds the certificate digest to every public field", () => {
11
- const certificate = createCertificate({
12
- taskId: "cff6c496-88b9-442b-b6ef-6f63f57364a3",
13
- goal: "Verify a deterministic outcome",
14
- result: "VERIFIED_SUCCESS",
15
- policyVersion: "1",
16
- receiptIds: ["3f5676d5-1c17-4670-8fa1-ddd55170d5a0"],
17
- evidence: [
18
- { type: "result_equals", passed: true, summary: "matched" },
19
- ],
20
- createdAt: "2026-07-28T00:00:00.000Z",
21
- });
22
- const { digest, ...unsigned } = certificate;
23
- expect(digest).toBe(sha256(unsigned));
24
- expect(digest).toMatch(/^[a-f0-9]{64}$/);
25
- });
26
- it("redacts secret-shaped strings and sensitive fields recursively", () => {
27
- const redacted = redactStructuredValue({
28
- page: "password=hunter2",
29
- nested: { authorization: "Bearer should-never-persist" },
30
- values: ["ghp_123456789012345678901234"],
31
- });
32
- expect(redacted.value.page).not.toContain("hunter2");
33
- expect(redacted.value.nested.authorization).toBe("[REDACTED_SENSITIVE_FIELD]");
34
- expect(redacted.value.values[0]).not.toContain("ghp_");
35
- expect(redacted.redactions.length).toBeGreaterThanOrEqual(2);
36
- });
37
- it("ranks re-read state above the adapter's own report", () => {
38
- // The distinction the field exists for: a file the kernel went back and
39
- // looked at outranks the adapter saying the call returned.
40
- expect(evidenceStrength("file_hash")).toBe("state");
41
- expect(evidenceStrength("operation_completed")).toBe("execution");
42
- });
43
- it("reads an unknown evidence type as the weakest claim", () => {
44
- // A predicate added without a decision in the table, or a type from a
45
- // future version, must not inherit a strength it never earned.
46
- expect(evidenceStrength("predicate_from_a_later_version")).toBe("execution");
47
- });
48
- });
49
- //# 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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"}