witnora 0.10.0 → 0.10.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.
Files changed (74) hide show
  1. package/README.md +54 -9
  2. package/dist/assurance-contract.js +312 -0
  3. package/dist/assurance-loop-demo.js +245 -0
  4. package/dist/authorization-state-machine.js +35 -0
  5. package/dist/authorization-v02.js +60 -0
  6. package/dist/canonical-v02.js +197 -0
  7. package/dist/canonical.js +31 -0
  8. package/dist/cli.js +118 -0
  9. package/dist/command-help.js +76 -0
  10. package/dist/control-plane.js +3 -3
  11. package/dist/credentials.js +1 -1
  12. package/dist/design-partner-pilot.js +402 -0
  13. package/dist/design-partner-v02.js +449 -0
  14. package/dist/evidence-v02.js +118 -0
  15. package/dist/generic-eval.js +160 -0
  16. package/dist/github-design-partner-v02.js +399 -0
  17. package/dist/github-live-v02.js +45 -0
  18. package/dist/guided-setup.js +1 -1
  19. package/dist/index.js +1 -0
  20. package/dist/offline-verifier.js +375 -0
  21. package/dist/onboard.js +132 -0
  22. package/dist/onboarding-templates.js +3 -3
  23. package/dist/outcome-evaluator.js +51 -0
  24. package/dist/privacy-manifest.js +273 -0
  25. package/dist/probe-protocol-v02.js +101 -0
  26. package/dist/sandbox.js +1 -1
  27. package/dist/trust-v02.js +111 -0
  28. package/dist/try.js +1 -1
  29. package/dist/vendor/design-partner/failure-exercises.mjs +353 -0
  30. package/dist/vendor/onegent-runtime/browser-enforcement-runtime.d.ts +8 -0
  31. package/dist/vendor/onegent-runtime/browser-enforcement-runtime.d.ts.map +1 -1
  32. package/dist/vendor/onegent-runtime/browser-enforcement-runtime.js +43 -1
  33. package/dist/vendor/witnora-probe/canonical.d.ts +3 -0
  34. package/dist/vendor/witnora-probe/canonical.js +39 -0
  35. package/dist/vendor/witnora-probe/cli.d.ts +2 -0
  36. package/dist/vendor/witnora-probe/cli.js +36 -0
  37. package/dist/vendor/witnora-probe/config.d.ts +2 -0
  38. package/dist/vendor/witnora-probe/config.js +63 -0
  39. package/dist/vendor/witnora-probe/credential-resolver.d.ts +6 -0
  40. package/dist/vendor/witnora-probe/credential-resolver.js +17 -0
  41. package/dist/vendor/witnora-probe/crypto.d.ts +2 -0
  42. package/dist/vendor/witnora-probe/crypto.js +14 -0
  43. package/dist/vendor/witnora-probe/emulator.d.ts +51 -0
  44. package/dist/vendor/witnora-probe/emulator.js +164 -0
  45. package/dist/vendor/witnora-probe/index.d.ts +11 -0
  46. package/dist/vendor/witnora-probe/index.js +11 -0
  47. package/dist/vendor/witnora-probe/logger.d.ts +3 -0
  48. package/dist/vendor/witnora-probe/logger.js +26 -0
  49. package/dist/vendor/witnora-probe/metrics.d.ts +12 -0
  50. package/dist/vendor/witnora-probe/metrics.js +31 -0
  51. package/dist/vendor/witnora-probe/probe.d.ts +22 -0
  52. package/dist/vendor/witnora-probe/probe.js +208 -0
  53. package/dist/vendor/witnora-probe/request-verifier.d.ts +9 -0
  54. package/dist/vendor/witnora-probe/request-verifier.js +84 -0
  55. package/dist/vendor/witnora-probe/server.d.ts +9 -0
  56. package/dist/vendor/witnora-probe/server.js +85 -0
  57. package/dist/vendor/witnora-probe/storage.d.ts +16 -0
  58. package/dist/vendor/witnora-probe/storage.js +114 -0
  59. package/dist/vendor/witnora-probe/types.d.ts +126 -0
  60. package/dist/vendor/witnora-probe/types.js +2 -0
  61. package/dist/vendor/witnora-verifier-python/README.md +43 -0
  62. package/dist/vendor/witnora-verifier-python/pyproject.toml +23 -0
  63. package/dist/vendor/witnora-verifier-python/src/witnora_verifier/__init__.py +33 -0
  64. package/dist/vendor/witnora-verifier-python/src/witnora_verifier/canonical.py +218 -0
  65. package/dist/vendor/witnora-verifier-python/src/witnora_verifier/cli.py +75 -0
  66. package/dist/vendor/witnora-verifier-python/src/witnora_verifier/conformance.py +124 -0
  67. package/dist/vendor/witnora-verifier-python/src/witnora_verifier/crypto.py +139 -0
  68. package/dist/vendor/witnora-verifier-python/src/witnora_verifier/errors.py +15 -0
  69. package/dist/vendor/witnora-verifier-python/src/witnora_verifier/event_chain.py +80 -0
  70. package/dist/vendor/witnora-verifier-python/src/witnora_verifier/evidence.py +336 -0
  71. package/dist/vendor/witnora-verifier-python/src/witnora_verifier/probe.py +188 -0
  72. package/dist/vendor/witnora-verifier-python/src/witnora_verifier/producer.py +127 -0
  73. package/dist/vendor/witnora-verifier-python/src/witnora_verifier/trust.py +337 -0
  74. package/package.json +4 -4
@@ -0,0 +1,353 @@
1
+ import { spawn } from "node:child_process";
2
+ import { createPrivateKey, sign } from "node:crypto";
3
+ import { createServer } from "node:net";
4
+ import { existsSync } from "node:fs";
5
+ import { cp, mkdtemp, mkdir, readFile, readdir, rm, stat, writeFile } from "node:fs/promises";
6
+ import { delimiter, join, resolve } from "node:path";
7
+ import { tmpdir } from "node:os";
8
+ import { pathToFileURL } from "node:url";
9
+
10
+ const standaloneRoot = resolve(import.meta.dirname, "..");
11
+ const standalone = existsSync(join(standaloneRoot, "docker", "runtime", "dist", "cli.js"));
12
+ const root = standalone ? standaloneRoot : resolve(import.meta.dirname, "..");
13
+ const cli = standalone ? join(root, "docker", "runtime", "dist", "cli.js") : join(root, "packages", "witnora-cli", "dist", "cli.js");
14
+ const probe = standalone ? join(root, "docker", "runtime", "dist", "vendor", "witnora-probe", "cli.js") : join(root, "packages", "witnora-probe", "dist", "cli.js");
15
+ const pythonPackage = standalone ? join(root, "verifiers", "python", "src") : join(root, "packages", "witnora-verifier-python", "src");
16
+ const cliDist = standalone ? join(root, "docker", "runtime", "dist") : join(root, "packages", "witnora-cli", "dist");
17
+ const { canonicalBytesV02 } = await import(pathToFileURL(join(cliDist, "canonical-v02.js")).href);
18
+ const { signProbeAttestation } = await import(pathToFileURL(join(cliDist, "probe-protocol-v02.js")).href);
19
+ const readCredential = "e2e-read-only-credential";
20
+ const writeCredential = "e2e-write-only-credential";
21
+ const storageKey = Buffer.alloc(32, 7).toString("base64");
22
+ const temp = await mkdtemp(join(tmpdir(), "witnora-design-partner-v02-"));
23
+ const kit = join(temp, "kit");
24
+ const children = [];
25
+ const privacyCanaries = [
26
+ "CANARY_PR_TITLE_customer_private_7af9",
27
+ "CANARY_COMMIT_MESSAGE_customer_private_83b2",
28
+ "CANARY_WEBHOOK_PAYLOAD_customer_private_91cc",
29
+ "CANARY_TARGET_RESPONSE_customer_private_a12e",
30
+ ];
31
+
32
+ try {
33
+ if (standalone) {
34
+ await cp(root, kit, {
35
+ recursive: true,
36
+ filter: (source) => !["acceptance", "claims", "support-bundle", "failure-exercises"].some((name) => source.includes(`${join(root, name)}`)),
37
+ });
38
+ process.stdout.write("[standalone kit copy] PASS\n");
39
+ } else {
40
+ await runNode([cli, "design-partner", "init", "github-pr-merge", "--out", kit], {}, "kit init");
41
+ }
42
+ await injectPrivacyCanaries(kit);
43
+ const [targetPort, probePort] = await Promise.all([freePort(), freePort()]);
44
+ await configureProbe(kit, targetPort, probePort);
45
+ await issueAuthorization();
46
+
47
+ const target = startNode([cli, "design-partner", "target-emulator", "--dir", kit, "--state", join(kit, "target-state.json"), "--port", String(targetPort)], {
48
+ WITNORA_GITHUB_READ_CREDENTIAL: readCredential,
49
+ WITNORA_GITHUB_WRITE_CREDENTIAL: writeCredential,
50
+ }, "target");
51
+ children.push(target);
52
+ await waitFor(`http://127.0.0.1:${targetPort}/health`);
53
+
54
+ let probeProcess = startNode([probe], {
55
+ WITNORA_PROBE_CONFIG: join(kit, "probe", "config.json"),
56
+ WITNORA_PROBE_STORAGE_KEY_BASE64: storageKey,
57
+ WITNORA_GITHUB_READ_CREDENTIAL: readCredential,
58
+ WITNORA_GITHUB_WRITE_CREDENTIAL: undefined,
59
+ }, "probe");
60
+ children.push(probeProcess);
61
+ await waitFor(`http://127.0.0.1:${probePort}/ready`);
62
+
63
+ await runNode([cli, "design-partner", "doctor", "--dir", kit], {
64
+ WITNORA_GITHUB_READ_CREDENTIAL: readCredential,
65
+ WITNORA_GITHUB_WRITE_CREDENTIAL: writeCredential,
66
+ }, "doctor");
67
+ await runNode([cli, "design-partner", "dry-run", "--dir", kit, "--target-url", `http://127.0.0.1:${targetPort}`], {
68
+ WITNORA_GITHUB_READ_CREDENTIAL: readCredential,
69
+ WITNORA_GITHUB_WRITE_CREDENTIAL: undefined,
70
+ }, "dry-run");
71
+
72
+ const firstOut = join(temp, "acceptance-normal");
73
+ const firstAcceptance = await runNode([cli, "design-partner", "run-acceptance", "--dir", kit, "--out", firstOut, "--target-url", `http://127.0.0.1:${targetPort}`, "--probe-url", `http://127.0.0.1:${probePort}`], {
74
+ WITNORA_GITHUB_READ_CREDENTIAL: undefined,
75
+ WITNORA_GITHUB_WRITE_CREDENTIAL: writeCredential,
76
+ }, "gateway acceptance");
77
+ const acceptanceMetrics = parseAcceptanceMetrics(firstAcceptance.stdout);
78
+ const packetPath = join(firstOut, "witnora-evidence-packet-v0.2.json");
79
+ const rootPath = join(firstOut, "pinned-trust-root-v0.2.json");
80
+ const packet = JSON.parse(await readFile(packetPath, "utf8"));
81
+ assert(packet.executionAttempt.dispatchCount === 1, "normal acceptance dispatched exactly once");
82
+ assert(packet.executionAttempt.state === "RECONCILED_SUCCESS", "normal acceptance reconciled successfully");
83
+
84
+ const grantReplayOut = join(temp, "acceptance-grant-replay");
85
+ await expectFailure(() => runNode([cli, "design-partner", "run-acceptance", "--dir", kit, "--out", grantReplayOut, "--target-url", `http://127.0.0.1:${targetPort}`, "--probe-url", `http://127.0.0.1:${probePort}`], {
86
+ WITNORA_GITHUB_READ_CREDENTIAL: undefined,
87
+ WITNORA_GITHUB_WRITE_CREDENTIAL: writeCredential,
88
+ }, "Grant replay"), "Exercise B: a consumed one-use Grant is rejected");
89
+ assert((await readTarget(targetPort)).targetVersion === 2, "Exercise B: Grant replay produced no second target write");
90
+
91
+ const firstJournalPath = join(firstOut, "revocation-journal-v0.2.json");
92
+ await runNode([cli, "design-partner", "verify-offline", "--packet", packetPath, "--root", rootPath, "--revocation-journal", firstJournalPath], {}, "TypeScript verifier");
93
+ await runPython(["-m", "witnora_verifier.cli", "evidence", packetPath, "--root", rootPath, "--revocation-journal", firstJournalPath], {}, "Python verifier");
94
+ const liveBindingPath = join(firstOut, "live-gateway-binding-packet.json");
95
+ const { signature: _probeSignature, protocolVersion: _probeProtocol, ...probeAttestationInput } = packet.probeAttestation;
96
+ const liveProbeAttestation = signProbeAttestation({
97
+ ...probeAttestationInput,
98
+ normalizedObservation: Object.fromEntries(Object.entries(packet.probeAttestation.normalizedObservation).filter(([key]) => key !== "consumedGrantId")),
99
+ }, await readFile(join(kit, "secrets", "probe-private.pem"), "utf8"));
100
+ const liveBindingPacket = await resignGatewayPacket({
101
+ ...packet,
102
+ reconciliation: { ...packet.reconciliation, authorizationBindingSource: "GATEWAY_DISPATCH_RECORD" },
103
+ probeAttestation: liveProbeAttestation,
104
+ separation: { ...packet.separation, probeDeploymentMode: "customer_network" },
105
+ evidenceStrength: { ...packet.evidenceStrength, authorizationBinding: "GATEWAY_DISPATCH_BOUND", operatorSeparation: "CUSTOMER_NETWORK_SEPARATED" },
106
+ }, join(kit, "secrets", "gateway-private.pem"));
107
+ await writeFile(liveBindingPath, `${JSON.stringify(liveBindingPacket, null, 2)}\n`);
108
+ await runNode([cli, "design-partner", "verify-offline", "--packet", liveBindingPath, "--root", rootPath, "--revocation-journal", firstJournalPath], {}, "live-binding TypeScript verifier");
109
+ await runPython(["-m", "witnora_verifier.cli", "evidence", liveBindingPath, "--root", rootPath, "--revocation-journal", firstJournalPath], {}, "live-binding Python verifier");
110
+ await assertReplayRejected(packet, probePort);
111
+
112
+ const tamperedPath = join(firstOut, "tampered-packet.json");
113
+ await writeFile(tamperedPath, `${JSON.stringify({ ...packet, actionDigest: `${packet.actionDigest}-tampered` }, null, 2)}\n`);
114
+ await expectFailure(() => runNode([cli, "design-partner", "verify-offline", "--packet", tamperedPath, "--root", rootPath, "--revocation-journal", firstJournalPath], {}, "tampered TypeScript verifier"), "TypeScript rejects packet tampering");
115
+ await expectFailure(() => runPython(["-m", "witnora_verifier.cli", "evidence", tamperedPath, "--root", rootPath, "--revocation-journal", firstJournalPath], {}, "tampered Python verifier"), "Python rejects packet tampering");
116
+
117
+ const externalReviewOverclaimPath = join(firstOut, "external-review-overclaim.json");
118
+ const externalReviewOverclaim = await resignGatewayPacket({ ...packet, evidenceStrength: { ...packet.evidenceStrength, review: "EXTERNAL" } }, join(kit, "secrets", "gateway-private.pem"));
119
+ await writeFile(externalReviewOverclaimPath, `${JSON.stringify(externalReviewOverclaim, null, 2)}\n`);
120
+ await expectFailure(() => runNode([cli, "design-partner", "verify-offline", "--packet", externalReviewOverclaimPath, "--root", rootPath, "--revocation-journal", firstJournalPath], {}, "external-review overclaim TypeScript verifier"), "TypeScript rejects unsigned external-review overclaim");
121
+ await expectFailure(() => runPython(["-m", "witnora_verifier.cli", "evidence", externalReviewOverclaimPath, "--root", rootPath, "--revocation-journal", firstJournalPath], {}, "external-review overclaim Python verifier"), "Python rejects unsigned external-review overclaim");
122
+
123
+ await resetTarget(kit);
124
+ await issueAuthorization();
125
+ await assertParameterMutationRejected(targetPort, kit);
126
+ await resetTarget(kit);
127
+ await issueAuthorization();
128
+ const crashOut = join(temp, "acceptance-crash-recovery");
129
+ await expectFailure(() => runNode([cli, "design-partner", "run-acceptance", "--dir", kit, "--out", crashOut, "--target-url", `http://127.0.0.1:${targetPort}`, "--probe-url", `http://127.0.0.1:${probePort}`, "--crash-after-target-success"], {
130
+ WITNORA_GITHUB_READ_CREDENTIAL: undefined,
131
+ WITNORA_GITHUB_WRITE_CREDENTIAL: writeCredential,
132
+ }, "crashing Gateway process"), "Gateway process exits after target success");
133
+ await runNode([cli, "design-partner", "recover-acceptance", "--dir", kit, "--out", crashOut, "--target-url", `http://127.0.0.1:${targetPort}`, "--probe-url", `http://127.0.0.1:${probePort}`], {
134
+ WITNORA_GITHUB_READ_CREDENTIAL: undefined,
135
+ WITNORA_GITHUB_WRITE_CREDENTIAL: writeCredential,
136
+ }, "new Gateway recovery process");
137
+ const crashPacket = JSON.parse(await readFile(join(crashOut, "witnora-evidence-packet-v0.2.json"), "utf8"));
138
+ const states = crashPacket.executionAttempt.recoveryHistory.map((entry) => entry.state);
139
+ assert(states.includes("DISPATCH_UNKNOWN"), "crash path records DISPATCH_UNKNOWN");
140
+ assert(states.at(-1) === "RECONCILED_SUCCESS", "crash path reconciles target state");
141
+ assert(crashPacket.executionAttempt.dispatchCount === 1, "crash recovery does not duplicate dispatch");
142
+
143
+ const revocationEffectiveAt = new Date(Date.now() + 100).toISOString();
144
+ await runNode([cli, "design-partner", "trust", "revoke-probe", "--dir", kit, "--effective-at", revocationEffectiveAt, "--reason", "E2E rotation rehearsal"], {}, "revoke Probe certificate");
145
+ const latestJournal = join(kit, "trust", "revocation-journal.json");
146
+ await runNode([cli, "design-partner", "verify-offline", "--packet", packetPath, "--root", rootPath, "--revocation-journal", latestJournal], {}, "historical TypeScript verification after non-retroactive revocation");
147
+ await runPython(["-m", "witnora_verifier.cli", "evidence", packetPath, "--root", rootPath, "--revocation-journal", latestJournal], {}, "historical Python verification after non-retroactive revocation");
148
+ await new Promise((ok) => setTimeout(ok, 150));
149
+ await resetTarget(kit);
150
+ await issueAuthorization();
151
+ const revokedOut = join(temp, "acceptance-revoked-probe");
152
+ await expectFailure(() => runNode([cli, "design-partner", "run-acceptance", "--dir", kit, "--out", revokedOut, "--target-url", `http://127.0.0.1:${targetPort}`, "--probe-url", `http://127.0.0.1:${probePort}`], {
153
+ WITNORA_GITHUB_READ_CREDENTIAL: undefined,
154
+ WITNORA_GITHUB_WRITE_CREDENTIAL: writeCredential,
155
+ }, "revoked Probe acceptance"), "revoked Probe blocks a new covered dispatch");
156
+ assert((await readTarget(targetPort)).merged === false, "revoked Probe failure occurs before target dispatch");
157
+
158
+ await runNode([cli, "design-partner", "trust", "rotate-probe", "--dir", kit], {}, "rotate Probe certificate");
159
+ probeProcess.kill("SIGTERM");
160
+ await onceExit(probeProcess, 2_000);
161
+ probeProcess = startNode([probe], {
162
+ WITNORA_PROBE_CONFIG: join(kit, "probe", "config.json"),
163
+ WITNORA_PROBE_STORAGE_KEY_BASE64: storageKey,
164
+ WITNORA_GITHUB_READ_CREDENTIAL: readCredential,
165
+ WITNORA_GITHUB_WRITE_CREDENTIAL: undefined,
166
+ }, "probe-rotated");
167
+ children.push(probeProcess);
168
+ await waitFor(`http://127.0.0.1:${probePort}/ready`);
169
+ await issueAuthorization();
170
+ const rotatedOut = join(temp, "acceptance-rotated-probe");
171
+ await runNode([cli, "design-partner", "run-acceptance", "--dir", kit, "--out", rotatedOut, "--target-url", `http://127.0.0.1:${targetPort}`, "--probe-url", `http://127.0.0.1:${probePort}`], {
172
+ WITNORA_GITHUB_READ_CREDENTIAL: undefined,
173
+ WITNORA_GITHUB_WRITE_CREDENTIAL: writeCredential,
174
+ }, "rotated Probe acceptance");
175
+
176
+ const config = JSON.parse(await readFile(join(kit, "design-partner.json"), "utf8"));
177
+ await writeFile(join(kit, "target-state.json"), `${JSON.stringify({ ...config.declaredTarget, simulateFalseSuccess: true }, null, 2)}\n`);
178
+ await issueAuthorization();
179
+ const falseSuccessOut = join(temp, "acceptance-false-success");
180
+ await expectFailure(() => runNode([cli, "design-partner", "run-acceptance", "--dir", kit, "--out", falseSuccessOut, "--target-url", `http://127.0.0.1:${targetPort}`, "--probe-url", `http://127.0.0.1:${probePort}`], {
181
+ WITNORA_GITHUB_READ_CREDENTIAL: undefined,
182
+ WITNORA_GITHUB_WRITE_CREDENTIAL: writeCredential,
183
+ }, "false-success acceptance"), "apparent target success does not become verified success");
184
+ const falsePacket = JSON.parse(await readFile(join(falseSuccessOut, "witnora-evidence-packet-v0.2.json"), "utf8"));
185
+ assert(falsePacket.probeAttestation.outcomeStatus === "NOT_VERIFIED", "false success is independently observed as NOT_VERIFIED");
186
+ assert((await readTarget(targetPort)).merged === false, "false-success target remains unmerged");
187
+ await assertNoPrivacyCanaryEgress([firstOut, crashOut, rotatedOut, falseSuccessOut], firstAcceptance.stdout);
188
+
189
+ const summary = {
190
+ protocolVersion: "witnora.design_partner_e2e_report.v0.2",
191
+ overall: "PASS",
192
+ processBoundaries: {
193
+ target: ["read_credential", "write_credential"],
194
+ probe: ["read_credential"],
195
+ gateway: ["write_credential"],
196
+ evidence: ["no_raw_credentials"],
197
+ },
198
+ assertions: [
199
+ "normal path independently reconciled",
200
+ "consumed one-use Grant replay rejected without a second target write",
201
+ "TypeScript and Python offline verifiers passed",
202
+ "replay rejected",
203
+ "tampering rejected by both verifiers",
204
+ "external-review overclaim rejected by both verifiers",
205
+ "parameter mutation rejected before dispatch",
206
+ "crash after target success recovered without duplicate dispatch",
207
+ "non-retroactive revocation preserved historical verification",
208
+ "revoked Probe blocked new dispatch",
209
+ "rotated Probe restored the covered path",
210
+ "apparent target success failed independent outcome verification",
211
+ "raw customer canaries remained outside emitted evidence and reports",
212
+ ],
213
+ acceptanceMetrics,
214
+ };
215
+ const artifactDirectory = standalone ? join(root, "failure-exercises") : join(root, ".artifacts");
216
+ await mkdir(artifactDirectory, { recursive: true });
217
+ await writeFile(join(artifactDirectory, "design-partner-v02-e2e-report.json"), `${JSON.stringify(summary, null, 2)}\n`);
218
+ process.stdout.write(`${JSON.stringify(summary, null, 2)}\n`);
219
+ } finally {
220
+ for (const child of children.reverse()) child.kill("SIGTERM");
221
+ await Promise.all(children.map((child) => onceExit(child, 2_000)));
222
+ if (process.env.WITNORA_E2E_KEEP_TEMP === "1") process.stderr.write(`[e2e] retained ${temp}\n`);
223
+ else await rm(temp, { recursive: true, force: true });
224
+ }
225
+
226
+ async function configureProbe(directory, targetPort, probePort) {
227
+ const kitConfigPath = join(directory, "design-partner.json");
228
+ const kitConfig = JSON.parse(await readFile(kitConfigPath, "utf8"));
229
+ kitConfig.targetUrl = `http://127.0.0.1:${targetPort}`;
230
+ kitConfig.probeUrl = `http://127.0.0.1:${probePort}`;
231
+ await writeFile(kitConfigPath, `${JSON.stringify(kitConfig, null, 2)}\n`);
232
+ const path = join(directory, "probe", "config.json");
233
+ const config = JSON.parse(await readFile(path, "utf8"));
234
+ config.host = "127.0.0.1";
235
+ config.port = probePort;
236
+ config.githubTarget.url = `http://127.0.0.1:${targetPort}`;
237
+ await writeFile(path, `${JSON.stringify(config, null, 2)}\n`);
238
+ }
239
+
240
+ async function injectPrivacyCanaries(directory) {
241
+ const configPath = join(directory, "design-partner.json");
242
+ const config = JSON.parse(await readFile(configPath, "utf8"));
243
+ config.declaredTarget.pullRequestTitle = privacyCanaries[0];
244
+ config.declaredTarget.commitMessage = privacyCanaries[1];
245
+ config.declaredTarget.webhookPayload = { body: privacyCanaries[2] };
246
+ config.declaredTarget.targetResponseMetadata = { private: privacyCanaries[3] };
247
+ await writeFile(configPath, `${JSON.stringify(config, null, 2)}\n`);
248
+ await writeFile(join(directory, "target-state.json"), `${JSON.stringify(config.declaredTarget, null, 2)}\n`);
249
+ }
250
+
251
+ async function assertNoPrivacyCanaryEgress(directories, stdout) {
252
+ const outputs = [stdout];
253
+ for (const directory of directories) {
254
+ for (const path of await filesRecursively(directory)) outputs.push(await readFile(path, "utf8"));
255
+ }
256
+ for (const canary of privacyCanaries) assert(outputs.every((value) => !value.includes(canary)), `${canary.split("_customer")[0]} did not egress into evidence, reports, or CLI output`);
257
+ }
258
+
259
+ async function filesRecursively(directory) {
260
+ const paths = [];
261
+ for (const entry of await readdir(directory, { withFileTypes: true })) {
262
+ const path = join(directory, entry.name);
263
+ if (entry.isDirectory()) paths.push(...await filesRecursively(path));
264
+ else if ((await stat(path)).size < 10_000_000) paths.push(path);
265
+ }
266
+ return paths;
267
+ }
268
+
269
+ async function resetTarget(directory) {
270
+ const config = JSON.parse(await readFile(join(directory, "design-partner.json"), "utf8"));
271
+ await writeFile(join(directory, "target-state.json"), `${JSON.stringify(config.declaredTarget, null, 2)}\n`);
272
+ }
273
+
274
+ async function assertReplayRejected(packet, port) {
275
+ const response = await fetch(`http://127.0.0.1:${port}/v0.2/observe`, {
276
+ method: "POST", headers: { "content-type": "application/json" },
277
+ body: JSON.stringify({
278
+ request: packet.probeRequest,
279
+ expected: packet.probeAttestation.normalizedObservation,
280
+ query: { type: "github.pull_request.read.v0.2", repository: "witnora-design-partner/assurance-sandbox", pullRequestNumber: 17 },
281
+ }),
282
+ });
283
+ assert(response.status === 409, `Probe replay rejected with 409, received ${response.status}`);
284
+ }
285
+
286
+ async function resignGatewayPacket(packet, privateKeyPath) {
287
+ const { gatewaySignature: _gatewaySignature, ...signedValue } = packet;
288
+ const privateKey = createPrivateKey(await readFile(privateKeyPath, "utf8"));
289
+ return {
290
+ ...signedValue,
291
+ gatewaySignature: {
292
+ keyId: packet.gatewaySignature.keyId,
293
+ signature: sign(null, canonicalBytesV02(signedValue), privateKey).toString("base64"),
294
+ },
295
+ };
296
+ }
297
+
298
+ async function issueAuthorization() {
299
+ await runNode([cli, "design-partner", "authorization", "issue", "--dir", kit], {}, "signed authorization issuance");
300
+ }
301
+
302
+ async function assertParameterMutationRejected(port, directory) {
303
+ const approval = JSON.parse(await readFile(join(directory, "authorization", "approval.json"), "utf8"));
304
+ const grant = JSON.parse(await readFile(join(directory, "authorization", "grant.json"), "utf8"));
305
+ const response = await fetch(`http://127.0.0.1:${port}/v0.2/github/pull-request`, {
306
+ method: "POST", headers: { authorization: `Bearer ${writeCredential}`, "content-type": "application/json" },
307
+ body: JSON.stringify({ idempotencyKey: grant.grantId, approval, grant, identity: {
308
+ protocolVersion: "witnora.github_pull_request_merge.v0.2", owner: "witnora-design-partner", repository: "assurance-sandbox",
309
+ pullRequestNumber: 17, baseBranch: "acceptance", approvedBaseSha: "base-a", headBranch: "agent-change", approvedHeadSha: "head-mutated",
310
+ mergeMethod: "squash", requiredChecks: ["build", "policy"], agentRef: "agent:design-partner", agentBuildDigest: "build",
311
+ contractDigest: "contract", policyVersion: "policy", mandateVersion: "mandate", resourceCommitment: "resource", parameterCommitment: "params",
312
+ } }),
313
+ });
314
+ assert(response.status === 403, `Mutated action rejected with 403, received ${response.status}`);
315
+ const state = await readTarget(port);
316
+ assert(state.merged === false, "parameter mutation produced no target write");
317
+ }
318
+
319
+ async function readTarget(port) {
320
+ const response = await fetch(`http://127.0.0.1:${port}/v0.2/github/pull-request`, { headers: { authorization: `Bearer ${readCredential}` } });
321
+ return response.json();
322
+ }
323
+
324
+ function startNode(args, overrides, label) {
325
+ const child = spawn(process.execPath, args, { cwd: root, env: cleanEnv(overrides), stdio: ["ignore", "pipe", "pipe"] });
326
+ child.stdout.on("data", (data) => process.stdout.write(`[${label}] ${data}`));
327
+ child.stderr.on("data", (data) => process.stderr.write(`[${label}] ${data}`));
328
+ return child;
329
+ }
330
+
331
+ async function runNode(args, overrides, label) { return runProcess(process.execPath, args, cleanEnv(overrides), label); }
332
+ async function runPython(args, overrides, label) {
333
+ const env = cleanEnv(overrides); env.PYTHONPATH = [pythonPackage, env.PYTHONPATH].filter(Boolean).join(delimiter);
334
+ return runProcess(process.env.PYTHON ?? "python", args, env, label);
335
+ }
336
+ async function runProcess(command, args, env, label) {
337
+ const child = spawn(command, args, { cwd: root, env, stdio: ["ignore", "pipe", "pipe"] });
338
+ let stdout = ""; let stderr = ""; child.stdout.on("data", (data) => { stdout += data; }); child.stderr.on("data", (data) => { stderr += data; });
339
+ const code = await new Promise((resolveExit, reject) => { child.once("error", reject); child.once("exit", resolveExit); });
340
+ if (code !== 0) throw new Error(`${label} failed (${code}).\n${stdout}\n${stderr}`);
341
+ process.stdout.write(`[${label}] PASS\n`); return { stdout, stderr };
342
+ }
343
+ function cleanEnv(overrides) { const env = { ...process.env, ...overrides }; for (const [key, value] of Object.entries(env)) if (value === undefined) delete env[key]; return env; }
344
+ async function freePort() { const server = createServer(); await new Promise((ok, fail) => server.once("error", fail).listen(0, "127.0.0.1", ok)); const port = server.address().port; await new Promise((ok) => server.close(ok)); return port; }
345
+ async function waitFor(url) { const deadline = Date.now() + 10_000; while (Date.now() < deadline) { try { const response = await fetch(url); if (response.ok) return; } catch {} await new Promise((ok) => setTimeout(ok, 100)); } throw new Error(`Timed out waiting for ${url}`); }
346
+ function assert(condition, message) { if (!condition) throw new Error(`Assertion failed: ${message}`); process.stdout.write(`[assert] PASS ${message}\n`); }
347
+ function parseAcceptanceMetrics(stdout) {
348
+ const line = stdout.split(/\r?\n/u).find((entry) => entry.startsWith("Metrics: "));
349
+ if (!line) throw new Error("Acceptance command did not emit setup and verification metrics.");
350
+ return JSON.parse(line.slice("Metrics: ".length));
351
+ }
352
+ async function expectFailure(operation, message) { try { await operation(); } catch { process.stdout.write(`[assert] PASS ${message}\n`); return; } throw new Error(`Assertion failed: ${message}`); }
353
+ async function onceExit(child, timeoutMs) { if (child.exitCode !== null) return; await Promise.race([new Promise((ok) => child.once("exit", ok)), new Promise((ok) => setTimeout(ok, timeoutMs))]); if (child.exitCode === null) child.kill("SIGKILL"); }
@@ -157,10 +157,18 @@ export interface BrowserEnforcementExecutionOptions {
157
157
  status: "CLAIMED";
158
158
  claimedAt: string;
159
159
  }>;
160
+ recordExecutionAttempt(executionSessionId: string, update: {
161
+ phase: "DISPATCH_STARTED" | "DISPATCH_ACKNOWLEDGED" | "DISPATCH_UNKNOWN" | "RECONCILED_SUCCESS" | "RECONCILED_FAILURE" | "CONFLICT";
162
+ writeResponseCommitment?: string;
163
+ targetOperationId?: string;
164
+ stableErrorCode?: string;
165
+ }): Promise<void>;
160
166
  markConsumed(executionGrantId: string, executionSessionId: string): Promise<void>;
167
+ failpoint?: (name: BrowserEnforcementFailpoint) => void | Promise<void>;
161
168
  now?: () => Date;
162
169
  clockSkewMs?: number;
163
170
  }
171
+ export type BrowserEnforcementFailpoint = "AFTER_GRANT_CLAIM" | "AFTER_EXECUTION_ATTEMPT_PERSISTENCE" | "IMMEDIATELY_BEFORE_TARGET_REQUEST" | "IMMEDIATELY_AFTER_TARGET_ACCEPTS_REQUEST" | "AFTER_TARGET_RESPONSE_BEFORE_LOCAL_RECORD" | "AFTER_LOCAL_RECORD_BEFORE_GRANT_CONSUME" | "DURING_GRANT_CONSUME" | "BEFORE_OUTCOME_OBSERVATION" | "DURING_RECONCILIATION";
164
172
  export interface BrowserEnforcementRuntimeBundle {
165
173
  protocolVersion: typeof BROWSER_ENFORCEMENT_PROTOCOL;
166
174
  executionGrant: SignedExecutionGrantWire;
@@ -1 +1 @@
1
- {"version":3,"file":"browser-enforcement-runtime.d.ts","sourceRoot":"","sources":["../../../../onegent-runtime/src/browser-enforcement-runtime.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"browser-enforcement-runtime.d.ts","sourceRoot":"","sources":["../../../../onegent-runtime/src/browser-enforcement-runtime.ts"],"names":[],"mappings":"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"}
@@ -39,6 +39,10 @@ export async function executeBrowserEnforcement(options) {
39
39
  idempotencyKey: `claim:${grant.jti}`,
40
40
  }, options.runtime.signer);
41
41
  await options.claimGrant(runtimeClaim);
42
+ await options.failpoint?.("AFTER_GRANT_CLAIM");
43
+ // Claim and attempt reservation are one Hosted transaction. A returned claim
44
+ // therefore proves the RESERVED attempt is durable as well.
45
+ await options.failpoint?.("AFTER_EXECUTION_ATTEMPT_PERSISTENCE");
42
46
  const credentialLeaseId = options.credentialLease.credentialLeaseId ?? randomUUID();
43
47
  const startedAt = now().toISOString();
44
48
  const genesis = sha256(canonicalJson({ executionSessionId, executionGrantDigest: options.grant.payloadSha256, runtimeIdentityId: options.runtime.runtimeIdentityId }));
@@ -106,6 +110,8 @@ export async function executeBrowserEnforcement(options) {
106
110
  status: "ACTIVE",
107
111
  };
108
112
  let leaseRevoked = false;
113
+ let dispatchStarted = false;
114
+ let dispatchAcknowledged = false;
109
115
  const revokeCredentialLease = async () => {
110
116
  if (leaseRevoked)
111
117
  return;
@@ -138,7 +144,22 @@ export async function executeBrowserEnforcement(options) {
138
144
  }
139
145
  await append("FINAL_PARAMETERS_VERIFIED", { parametersDigest: finalParametersDigest });
140
146
  await append("HIGH_RISK_SUBMISSION_STARTED", { actionId: grant.actionId });
141
- const adapterResult = await options.adapter.execute(options.action, { idempotencyKey: executionSessionId, attempt: 1 });
147
+ await options.recordExecutionAttempt(executionSessionId, { phase: "DISPATCH_STARTED" });
148
+ dispatchStarted = true;
149
+ let adapterResult;
150
+ try {
151
+ await options.failpoint?.("IMMEDIATELY_BEFORE_TARGET_REQUEST");
152
+ adapterResult = await options.adapter.execute(options.action, { idempotencyKey: executionSessionId, attempt: 1 });
153
+ await options.failpoint?.("IMMEDIATELY_AFTER_TARGET_ACCEPTS_REQUEST");
154
+ await options.failpoint?.("AFTER_TARGET_RESPONSE_BEFORE_LOCAL_RECORD");
155
+ }
156
+ catch (error) {
157
+ await options.recordExecutionAttempt(executionSessionId, {
158
+ phase: "DISPATCH_UNKNOWN",
159
+ stableErrorCode: "TARGET_RESULT_UNKNOWN",
160
+ });
161
+ throw error;
162
+ }
142
163
  const execution = {
143
164
  method: adapterResult.method ?? "LOCAL_ADAPTER",
144
165
  status: "COMPLETED",
@@ -147,10 +168,18 @@ export async function executeBrowserEnforcement(options) {
147
168
  observedState: adapterResult.observedState,
148
169
  rollbackToken: adapterResult.rollbackToken,
149
170
  };
171
+ await options.recordExecutionAttempt(executionSessionId, {
172
+ phase: "DISPATCH_ACKNOWLEDGED",
173
+ writeResponseCommitment: sha256(canonicalJson(adapterResult)),
174
+ });
175
+ dispatchAcknowledged = true;
176
+ await options.failpoint?.("AFTER_LOCAL_RECORD_BEFORE_GRANT_CONSUME");
177
+ await options.failpoint?.("DURING_GRANT_CONSUME");
150
178
  await options.markConsumed(grant.executionGrantId, executionSessionId);
151
179
  await append("HIGH_RISK_SUBMISSION_COMPLETED", { targetSystem: execution.targetSystem });
152
180
  await append("TARGET_RESPONSE_OBSERVED", { observedStateDigest: sha256(canonicalJson(execution.observedState ?? {})) });
153
181
  await append("OUTCOME_PROBE_STARTED", { probe: options.outcomeProbe.name });
182
+ await options.failpoint?.("BEFORE_OUTCOME_OBSERVATION");
154
183
  const observation = await options.outcomeProbe.observe(options.action, execution);
155
184
  await append("OUTCOME_OBSERVED", { observationId: observation.observationId, source: observation.source, observedStateDigest: sha256(canonicalJson(observation.observedState)) });
156
185
  const predicateDigest = sha256(canonicalJson(options.outcomePredicate));
@@ -185,10 +214,15 @@ export async function executeBrowserEnforcement(options) {
185
214
  await revokeCredentialLease();
186
215
  await append("EXECUTION_SESSION_COMPLETED", { outcomeAttestationDigest: outcomeAttestation.payloadSha256 });
187
216
  const auditEvents = await options.targetAuditSource.listEvents(startedAt, now().toISOString());
217
+ await options.failpoint?.("DURING_RECONCILIATION");
188
218
  const matching = auditEvents.filter((event) => event.actionId === grant.actionId && event.executionSessionId === executionSessionId && event.operation === grant.allowedOperation && event.resource === grant.allowedResource && event.parametersDigest === grant.parametersDigest);
189
219
  const unmatchedTargetEvents = auditEvents.filter((event) => !matching.includes(event)).map((event) => event.targetEventId);
190
220
  const duplicateMatches = matching.length > 1 ? matching.slice(1).map((event) => event.targetEventId) : [];
191
221
  const reconciliationResult = options.targetAuditSource.exclusiveCredential && matching.length === 1 && !unmatchedTargetEvents.length && !duplicateMatches.length ? "PASSED" : unmatchedTargetEvents.length || duplicateMatches.length ? "BYPASS_DETECTED" : "INCOMPLETE";
222
+ await options.recordExecutionAttempt(executionSessionId, {
223
+ phase: reconciliationResult === "PASSED" ? "RECONCILED_SUCCESS" : reconciliationResult === "BYPASS_DETECTED" ? "CONFLICT" : "RECONCILED_FAILURE",
224
+ stableErrorCode: reconciliationResult === "PASSED" ? undefined : reconciliationResult === "BYPASS_DETECTED" ? "TARGET_RECONCILIATION_CONFLICT" : "TARGET_RECONCILIATION_INCOMPLETE",
225
+ });
192
226
  const reconciliationReport = signRuntimeObject({
193
227
  protocolVersion: BROWSER_ENFORCEMENT_PROTOCOL,
194
228
  objectType: "ReconciliationReport",
@@ -240,6 +274,14 @@ export async function executeBrowserEnforcement(options) {
240
274
  };
241
275
  }
242
276
  catch (error) {
277
+ if (dispatchStarted && !dispatchAcknowledged) {
278
+ try {
279
+ await options.recordExecutionAttempt(executionSessionId, { phase: "DISPATCH_UNKNOWN", stableErrorCode: "TARGET_RESULT_UNKNOWN" });
280
+ }
281
+ catch {
282
+ // The authoritative attempt remains DISPATCH_STARTED and recovery must reconcile it.
283
+ }
284
+ }
243
285
  try {
244
286
  await append("EXECUTION_SESSION_FAILED", { reasonCode: error instanceof Error ? error.message.slice(0, 200) : "EXECUTION_FAILED" });
245
287
  }
@@ -0,0 +1,3 @@
1
+ export declare const CANONICALIZATION_VERSION: "witnora.canonical_json.v0.2";
2
+ export declare function canonicalJson(value: unknown): string;
3
+ export declare function sha256Canonical(value: unknown): string;
@@ -0,0 +1,39 @@
1
+ import { createHash } from "node:crypto";
2
+ export const CANONICALIZATION_VERSION = "witnora.canonical_json.v0.2";
3
+ const MAX_DEPTH = 64;
4
+ export function canonicalJson(value) {
5
+ return JSON.stringify(canonicalValue(value, "$", 0));
6
+ }
7
+ export function sha256Canonical(value) {
8
+ return createHash("sha256").update(canonicalJson(value), "utf8").digest("hex");
9
+ }
10
+ function canonicalValue(value, path, depth) {
11
+ if (depth > MAX_DEPTH)
12
+ throw new Error(`${path} exceeds the v0.2 nesting limit of ${MAX_DEPTH}.`);
13
+ if (value === null || typeof value === "string" || typeof value === "boolean")
14
+ return value;
15
+ if (typeof value === "number") {
16
+ if (!Number.isFinite(value))
17
+ throw new Error(`${path} contains a non-finite number.`);
18
+ if (Object.is(value, -0))
19
+ throw new Error(`${path} contains negative zero.`);
20
+ if (!Number.isSafeInteger(value)) {
21
+ throw new Error(`${path} must be a safe integer; encode decimals as normalized strings.`);
22
+ }
23
+ return value;
24
+ }
25
+ if (Array.isArray(value)) {
26
+ return value.map((item, index) => canonicalValue(item, `${path}[${index}]`, depth + 1));
27
+ }
28
+ if (value && typeof value === "object" && Object.getPrototypeOf(value) === Object.prototype) {
29
+ const source = value;
30
+ const output = {};
31
+ for (const key of Object.keys(source).sort()) {
32
+ if (source[key] === undefined)
33
+ throw new Error(`${path}.${key} is undefined.`);
34
+ output[key] = canonicalValue(source[key], `${path}.${key}`, depth + 1);
35
+ }
36
+ return output;
37
+ }
38
+ throw new Error(`${path} contains unsupported ${typeof value}.`);
39
+ }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env node
2
+ import { loadProbeConfig } from "./config.js";
3
+ import { createJsonLogger } from "./logger.js";
4
+ import { WitnoraProbe } from "./probe.js";
5
+ import { createProbeServer } from "./server.js";
6
+ const logger = createJsonLogger();
7
+ const configPath = process.env.WITNORA_PROBE_CONFIG;
8
+ if (!configPath) {
9
+ logger.error("probe.startup_failed", { reason: "WITNORA_PROBE_CONFIG is required." });
10
+ process.exitCode = 1;
11
+ }
12
+ else {
13
+ try {
14
+ const config = await loadProbeConfig(configPath);
15
+ const probe = new WitnoraProbe(config, logger);
16
+ probe.start();
17
+ const http = createProbeServer(probe, logger, config.requestBodyLimitBytes);
18
+ const address = await http.listen(config.host, config.port);
19
+ logger.info("probe.started", { host: address.address, port: address.port, probeId: config.bindings.probeId });
20
+ let stopping = false;
21
+ const stop = async (signal) => {
22
+ if (stopping)
23
+ return;
24
+ stopping = true;
25
+ logger.info("probe.shutdown_requested", { signal });
26
+ await http.close();
27
+ await probe.shutdown();
28
+ };
29
+ process.on("SIGTERM", () => void stop("SIGTERM"));
30
+ process.on("SIGINT", () => void stop("SIGINT"));
31
+ }
32
+ catch (error) {
33
+ logger.error("probe.startup_failed", { reason: error instanceof Error ? error.message : "Unknown startup error." });
34
+ process.exitCode = 1;
35
+ }
36
+ }
@@ -0,0 +1,2 @@
1
+ import type { ProbeConfig } from "./types.js";
2
+ export declare function loadProbeConfig(path: string, environment?: NodeJS.ProcessEnv): Promise<ProbeConfig>;