witnora 0.9.3 → 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 (77) hide show
  1. package/README.md +76 -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/bundle.js +22 -0
  7. package/dist/canonical-v02.js +197 -0
  8. package/dist/canonical.js +31 -0
  9. package/dist/cli.js +132 -0
  10. package/dist/command-help.js +81 -0
  11. package/dist/control-plane.js +12 -3
  12. package/dist/credentials.js +1 -1
  13. package/dist/design-partner-pilot.js +402 -0
  14. package/dist/design-partner-v02.js +449 -0
  15. package/dist/evidence-v02.js +118 -0
  16. package/dist/generic-eval.js +160 -0
  17. package/dist/github-design-partner-v02.js +399 -0
  18. package/dist/github-live-v02.js +45 -0
  19. package/dist/guided-setup.js +1 -1
  20. package/dist/index.js +1 -0
  21. package/dist/offline-verifier.js +375 -0
  22. package/dist/onboard.js +132 -0
  23. package/dist/onboarding-templates.js +49 -6
  24. package/dist/outcome-evaluator.js +51 -0
  25. package/dist/privacy-manifest.js +273 -0
  26. package/dist/probe-protocol-v02.js +101 -0
  27. package/dist/runtime-context.js +75 -0
  28. package/dist/sandbox.js +1 -1
  29. package/dist/schema-validator.js +141 -3
  30. package/dist/trust-v02.js +111 -0
  31. package/dist/try.js +1 -1
  32. package/dist/vendor/design-partner/failure-exercises.mjs +353 -0
  33. package/dist/vendor/onegent-runtime/browser-enforcement-runtime.d.ts +8 -0
  34. package/dist/vendor/onegent-runtime/browser-enforcement-runtime.d.ts.map +1 -1
  35. package/dist/vendor/onegent-runtime/browser-enforcement-runtime.js +43 -1
  36. package/dist/vendor/witnora-probe/canonical.d.ts +3 -0
  37. package/dist/vendor/witnora-probe/canonical.js +39 -0
  38. package/dist/vendor/witnora-probe/cli.d.ts +2 -0
  39. package/dist/vendor/witnora-probe/cli.js +36 -0
  40. package/dist/vendor/witnora-probe/config.d.ts +2 -0
  41. package/dist/vendor/witnora-probe/config.js +63 -0
  42. package/dist/vendor/witnora-probe/credential-resolver.d.ts +6 -0
  43. package/dist/vendor/witnora-probe/credential-resolver.js +17 -0
  44. package/dist/vendor/witnora-probe/crypto.d.ts +2 -0
  45. package/dist/vendor/witnora-probe/crypto.js +14 -0
  46. package/dist/vendor/witnora-probe/emulator.d.ts +51 -0
  47. package/dist/vendor/witnora-probe/emulator.js +164 -0
  48. package/dist/vendor/witnora-probe/index.d.ts +11 -0
  49. package/dist/vendor/witnora-probe/index.js +11 -0
  50. package/dist/vendor/witnora-probe/logger.d.ts +3 -0
  51. package/dist/vendor/witnora-probe/logger.js +26 -0
  52. package/dist/vendor/witnora-probe/metrics.d.ts +12 -0
  53. package/dist/vendor/witnora-probe/metrics.js +31 -0
  54. package/dist/vendor/witnora-probe/probe.d.ts +22 -0
  55. package/dist/vendor/witnora-probe/probe.js +208 -0
  56. package/dist/vendor/witnora-probe/request-verifier.d.ts +9 -0
  57. package/dist/vendor/witnora-probe/request-verifier.js +84 -0
  58. package/dist/vendor/witnora-probe/server.d.ts +9 -0
  59. package/dist/vendor/witnora-probe/server.js +85 -0
  60. package/dist/vendor/witnora-probe/storage.d.ts +16 -0
  61. package/dist/vendor/witnora-probe/storage.js +114 -0
  62. package/dist/vendor/witnora-probe/types.d.ts +126 -0
  63. package/dist/vendor/witnora-probe/types.js +2 -0
  64. package/dist/vendor/witnora-verifier-python/README.md +43 -0
  65. package/dist/vendor/witnora-verifier-python/pyproject.toml +23 -0
  66. package/dist/vendor/witnora-verifier-python/src/witnora_verifier/__init__.py +33 -0
  67. package/dist/vendor/witnora-verifier-python/src/witnora_verifier/canonical.py +218 -0
  68. package/dist/vendor/witnora-verifier-python/src/witnora_verifier/cli.py +75 -0
  69. package/dist/vendor/witnora-verifier-python/src/witnora_verifier/conformance.py +124 -0
  70. package/dist/vendor/witnora-verifier-python/src/witnora_verifier/crypto.py +139 -0
  71. package/dist/vendor/witnora-verifier-python/src/witnora_verifier/errors.py +15 -0
  72. package/dist/vendor/witnora-verifier-python/src/witnora_verifier/event_chain.py +80 -0
  73. package/dist/vendor/witnora-verifier-python/src/witnora_verifier/evidence.py +336 -0
  74. package/dist/vendor/witnora-verifier-python/src/witnora_verifier/probe.py +188 -0
  75. package/dist/vendor/witnora-verifier-python/src/witnora_verifier/producer.py +127 -0
  76. package/dist/vendor/witnora-verifier-python/src/witnora_verifier/trust.py +337 -0
  77. package/package.json +5 -5
package/dist/cli.js CHANGED
@@ -28,6 +28,15 @@ import { runBrowserAdapterCommand } from "./browser-adapter.js";
28
28
  import { parseAgentTemplate, starterAdapter, starterGitHubActionWorkflow, starterInstructions, starterProfile, starterTripwireConfig, } from "./onboarding-templates.js";
29
29
  import { renderTrySummary, writeTryEvidence } from "./try.js";
30
30
  import { applyGuidedSetup } from "./guided-setup.js";
31
+ import { resolveRuntimeContext } from "./runtime-context.js";
32
+ import { compileAssuranceContract, diffAssuranceContracts, exampleAssuranceContract, readAssuranceContract, renderContractExplanation, } from "./assurance-contract.js";
33
+ import { examplePrivacyManifest, inspectPrivacy } from "./privacy-manifest.js";
34
+ import { renderOfflineVerification, verifyEvidencePacket } from "./offline-verifier.js";
35
+ import { runAssuranceLoopDemo } from "./assurance-loop-demo.js";
36
+ import { importGenericEval, renderGenericEvalReport } from "./generic-eval.js";
37
+ import { runDesignPartnerCommand } from "./design-partner-v02.js";
38
+ import { runOnboard } from "./onboard.js";
39
+ import { verifyEvidencePacketV02 } from "./evidence-v02.js";
31
40
  process.on("uncaughtException", reportFatalError);
32
41
  process.on("unhandledRejection", reportFatalError);
33
42
  const command = process.argv[2] ?? "help";
@@ -37,6 +46,115 @@ const commandHelp = process.argv.some((argument) => argument === "--help" || arg
37
46
  if (commandHelp) {
38
47
  process.stdout.write(commandHelp);
39
48
  }
49
+ else if (command === "contract") {
50
+ const action = process.argv[3] ?? "help";
51
+ if (action === "init") {
52
+ const out = resolve(readFlag("--out") ?? "witnora.assurance-contract.json");
53
+ await writeStarterFile(out, `${JSON.stringify(exampleAssuranceContract(), null, 2)}\n`, readBoolFlag("--force"));
54
+ process.stdout.write(`Wrote ${out}\n`);
55
+ }
56
+ else if (action === "validate" || action === "explain") {
57
+ const path = readFlag("--contract") ?? process.argv[4];
58
+ if (!path)
59
+ throw new Error("A contract path is required.");
60
+ process.stdout.write(renderContractExplanation(await readAssuranceContract(path)));
61
+ }
62
+ else if (action === "compile") {
63
+ const path = readFlag("--contract") ?? process.argv[4];
64
+ if (!path)
65
+ throw new Error("A contract path is required.");
66
+ const out = resolve(readFlag("--out") ?? ".witnora/contract/compiled-contract.json");
67
+ await mkdir(dirname(out), { recursive: true });
68
+ await writeFile(out, `${JSON.stringify(compileAssuranceContract(await readAssuranceContract(path)), null, 2)}\n`);
69
+ process.stdout.write(`Wrote deterministic compiler output ${out}\n`);
70
+ }
71
+ else if (action === "diff") {
72
+ const previous = readFlag("--from");
73
+ const next = readFlag("--to");
74
+ if (!previous || !next)
75
+ throw new Error("Contract diff requires --from <contract> and --to <contract>.");
76
+ process.stdout.write(`${JSON.stringify(diffAssuranceContracts(await readAssuranceContract(previous), await readAssuranceContract(next)), null, 2)}\n`);
77
+ }
78
+ else {
79
+ throw new Error("Use witnora contract init|validate|compile|diff|explain.");
80
+ }
81
+ }
82
+ else if (command === "privacy") {
83
+ const action = process.argv[3] ?? "help";
84
+ if (action === "init") {
85
+ const out = resolve(readFlag("--out") ?? "witnora.privacy-manifest.json");
86
+ await writeStarterFile(out, `${JSON.stringify(examplePrivacyManifest(), null, 2)}\n`, readBoolFlag("--force"));
87
+ process.stdout.write(`Wrote ${out}\n`);
88
+ }
89
+ else if (action === "inspect") {
90
+ const path = readFlag("--manifest") ?? process.argv[4];
91
+ if (!path)
92
+ throw new Error("A Privacy Manifest path is required.");
93
+ process.stdout.write(inspectPrivacy(await readJson(path)));
94
+ }
95
+ else {
96
+ throw new Error("Use witnora privacy init|inspect.");
97
+ }
98
+ }
99
+ else if (command === "design-partner") {
100
+ await runDesignPartnerCommand(process.argv.slice(3));
101
+ }
102
+ else if (command === "verify") {
103
+ const path = readFlag("--offline") ?? readFlag("--packet") ?? process.argv[3];
104
+ if (!path || path.startsWith("--"))
105
+ throw new Error("Use witnora verify --offline <packet.json>.");
106
+ const trustPath = readFlag("--trust");
107
+ const packet = await readJson(path);
108
+ if (packet.protocolVersion === "witnora.verifiable_evidence_packet.v0.2") {
109
+ const revocationPath = readFlag("--revocation-journal");
110
+ if (!trustPath || !revocationPath)
111
+ throw new Error("Evidence v0.2 requires --trust <pinned-root.json> and --revocation-journal <latest.json>.");
112
+ const report = verifyEvidencePacketV02(packet, await readJson(trustPath), new Date(), await readJson(revocationPath));
113
+ process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
114
+ if (report.overall !== "PASS")
115
+ process.exitCode = 1;
116
+ }
117
+ else {
118
+ const report = verifyEvidencePacket(packet, new Date(), trustPath ? await readJson(trustPath) : undefined);
119
+ process.stdout.write(readBoolFlag("--json") ? `${JSON.stringify(report, null, 2)}\n` : renderOfflineVerification(report));
120
+ if (report.overall !== "PASS")
121
+ process.exitCode = 1;
122
+ }
123
+ }
124
+ else if (command === "demo") {
125
+ if (process.argv[3] !== "assurance-loop")
126
+ throw new Error("Use witnora demo assurance-loop.");
127
+ const attack = (readFlag("--attack") ?? "none");
128
+ if (!["none", "parameter-substitution", "replay", "false-success", "event-tamper"].includes(attack))
129
+ throw new Error("Unsupported --attack value.");
130
+ const outcome = await runAssuranceLoopDemo({ outDir: readFlag("--out") ?? ".witnora/assurance-loop", attack });
131
+ process.stdout.write(renderOfflineVerification(outcome.report));
132
+ process.stdout.write(`Evidence packet: ${outcome.packetPath}\nTrust bundle: ${outcome.trustBundlePath}\nVerification report: ${outcome.reportPath}\nRevalidation diff: ${outcome.revalidationPath}\n`);
133
+ if (outcome.report.overall !== "PASS")
134
+ process.exitCode = 1;
135
+ }
136
+ else if (command === "import") {
137
+ if (readFlag("--format") !== "generic-eval")
138
+ throw new Error("Use witnora import --format generic-eval <result.json>.");
139
+ const path = process.argv.find((argument, index) => index >= 3 && !argument.startsWith("--") && process.argv[index - 1] !== "--format" && process.argv[index - 1] !== "--out");
140
+ if (!path)
141
+ throw new Error("A generic eval result path is required.");
142
+ const report = await importGenericEval(path, readBoolFlag("--dry-run") ? undefined : readFlag("--out") ?? ".witnora/import/generic-eval-report.json");
143
+ process.stdout.write(readBoolFlag("--json") ? `${JSON.stringify(report, null, 2)}\n` : renderGenericEvalReport(report));
144
+ }
145
+ else if (command === "onboard") {
146
+ const projectId = readFlag("--project") ?? brandedEnvironment("PROJECT_ID");
147
+ if (!projectId)
148
+ throw new Error("--project <project-id> is required.");
149
+ await runOnboard({
150
+ projectId,
151
+ server: readFlag("--server") ?? brandedEnvironment("BASE_URL") ?? DEFAULT_WITNORA_SERVER,
152
+ name: readFlag("--name"),
153
+ repository: readFlag("--repo") ?? process.cwd(),
154
+ template: readFlag("--template") ? parseAgentTemplate(readFlag("--template")) : undefined,
155
+ openBrowser: readBoolFlag("--no-browser") ? async () => { } : undefined,
156
+ });
157
+ }
40
158
  else if (command === "try") {
41
159
  const template = parseAgentTemplate(readFlag("--template") ?? "workflow");
42
160
  const subject = readFlag("--subject") ?? `witnora-sample-${template}`;
@@ -535,6 +653,8 @@ else if (command === "schema") {
535
653
  witnora schema validate --schema assurance-report --file assurance-report.json
536
654
  witnora schema validate --schema assurance-delivery --file assurance-delivery.json
537
655
  witnora schema validate --schema evidence-signature --file .witnora/latest/agentcert-evidence.json.sig.json
656
+ witnora schema validate --schema assurance-wallet --file assurance-wallet.json
657
+ witnora schema validate --schema payment-token-reference --file payment-token-reference.json
538
658
  `);
539
659
  }
540
660
  }
@@ -596,6 +716,7 @@ else if (command === "conformance") {
596
716
  }
597
717
  else {
598
718
  process.stdout.write(`Usage:
719
+ witnora onboard --project <project-id>
599
720
  witnora try --template workflow [--push]
600
721
  witnora init --subject my-browser-agent
601
722
  witnora connect --server https://witnora.com --project <project-id>
@@ -665,6 +786,17 @@ async function pushHostedEvidence(bundle, bytes, fileName) {
665
786
  skippedCompanionArtifacts: companions?.skipped,
666
787
  assurance,
667
788
  verifyContinuousAssurance: Boolean(assurance && (healthOut || requireCurrent)),
789
+ runtimeContext: await resolveRuntimeContext({
790
+ subject: bundle.subject.name,
791
+ framework: readFlag("--agent-framework"),
792
+ env: {
793
+ ...process.env,
794
+ ...(readFlag("--agent-id") ? { WITNORA_AGENT_ID: readFlag("--agent-id") } : {}),
795
+ ...(readFlag("--agent-name") ? { WITNORA_AGENT_NAME: readFlag("--agent-name") } : {}),
796
+ ...(readFlag("--agent-version") ? { WITNORA_AGENT_VERSION: readFlag("--agent-version") } : {}),
797
+ ...(readFlag("--environment") ? { WITNORA_ENVIRONMENT: readFlag("--environment") } : {}),
798
+ },
799
+ }),
668
800
  });
669
801
  process.stdout.write(`Hosted run: ${result.runId}\nHosted evidence: ${result.evidenceId}\n`);
670
802
  if (companions) {
@@ -1,6 +1,82 @@
1
1
  export function renderCommandHelp(command) {
2
2
  if (command === "sandbox" || command === "browser-adapter")
3
3
  return undefined;
4
+ if (command === "onboard")
5
+ return `Usage:
6
+ witnora onboard --project <project-id>
7
+ witnora onboard --project <project-id> --template <browser|coding|mcp|workflow|data>
8
+
9
+ Opens one browser authorization, saves a restricted project credential, detects the repository,
10
+ writes missing starter files, and records an isolated synthetic self-test receipt. The self-test
11
+ does not create assurance evidence or establish CURRENT status.
12
+
13
+ Options:
14
+ --server <url> Hosted server (default: https://witnora.com)
15
+ --project <id> Project to authorize (required)
16
+ --name <name> Saved connection name (default: repository name)
17
+ --repo <directory> Repository to configure (default: current directory)
18
+ --template <type> Override automatic repository detection
19
+ --no-browser Print the approval URL without opening it
20
+ `;
21
+ if (command === "design-partner")
22
+ return `Usage:
23
+ witnora design-partner init github-pr-merge [--out .witnora/design-partner]
24
+ witnora design-partner doctor [--dir .witnora/design-partner]
25
+ witnora design-partner privacy inspect
26
+ witnora design-partner trust inspect
27
+ witnora design-partner trust revoke-probe [--effective-at <timestamp>] [--retroactive]
28
+ witnora design-partner trust rotate-probe
29
+ witnora design-partner dry-run
30
+ witnora design-partner run-acceptance
31
+ witnora design-partner prepare-live-github --repository owner/sandbox-repo --pull-request 1
32
+ witnora design-partner verify-offline --packet <packet.json> --root <pinned-root.json> [--revocation-journal <latest.json>]
33
+
34
+ The v0.2 acceptance path is emulator-only. The optional live GitHub command is a
35
+ read-only preflight and cannot mutate or produce acceptance evidence for a repository.
36
+ `;
37
+ if (command === "contract")
38
+ return `Usage:
39
+ witnora contract init [--out witnora.assurance-contract.json]
40
+ witnora contract validate <contract.json>
41
+ witnora contract compile <contract.json> [--out compiled-contract.json]
42
+ witnora contract diff --from previous.json --to next.json
43
+ witnora contract explain <contract.json>
44
+
45
+ Contracts are strict JSON (also valid YAML 1.2). Unknown fields are rejected.
46
+ `;
47
+ if (command === "privacy")
48
+ return `Usage:
49
+ witnora privacy init [--out witnora.privacy-manifest.json]
50
+ witnora privacy inspect <manifest.json>
51
+
52
+ The manifest defaults to deny and classifies fields as local_only, disclose, or commit_only.
53
+ `;
54
+ if (command === "verify")
55
+ return `Usage:
56
+ witnora verify --offline <witnora-evidence-packet.json> --trust <trust-bundle.json>
57
+ witnora verify --offline <packet.json> --trust <trust-bundle.json> --json
58
+
59
+ Performs deterministic local verification without network access. Keys embedded in a packet
60
+ are never trust anchors; missing caller-supplied trust returns UNVERIFIABLE.
61
+ `;
62
+ if (command === "demo")
63
+ return `Usage:
64
+ witnora demo assurance-loop [--out .witnora/assurance-loop]
65
+ witnora demo assurance-loop --attack <parameter-substitution|replay|false-success|event-tamper>
66
+
67
+ Runs a generic local high-risk action through contract, policy, approval, single-use grant,
68
+ controlled execution, independent observation, signed evidence, and offline verification.
69
+ No external system or credential is used.
70
+ `;
71
+ if (command === "import")
72
+ return `Usage:
73
+ witnora import --format generic-eval <result.json> [--out .witnora/import/generic-eval-report.json]
74
+ witnora import --format generic-eval <result.json> --dry-run
75
+
76
+ Normalizes framework-independent evaluation results and reports apparent success,
77
+ independently verified success, Assurance Gap, explicit denominators, and exclusions.
78
+ Imported results are unreviewed and never establish CURRENT assurance.
79
+ `;
4
80
  if (command === "setup")
5
81
  return `Usage:
6
82
  witnora setup apply --plan witnora-setup-plan.json --repo .
@@ -59,6 +135,11 @@ Options:
59
135
  --project <id> Hosted project ID
60
136
  --api-key <key> Project API key (prefer WITNORA_API_KEY in CI)
61
137
  --external-id <id> Idempotent hosted run ID
138
+ --agent-id <id> Stable observed Agent identity (default: evidence subject)
139
+ --agent-name <name> Human-readable observed Agent name
140
+ --agent-version <v> Version override (default: package or CI commit)
141
+ --agent-framework <f> Framework metadata override
142
+ --environment <env> sandbox, staging, or production
62
143
  --assurance-case <id> Issued assurance case to reconcile
63
144
  --assurance-scope <p> Declared agent/model/prompt/tools/policy/suite scope JSON
64
145
  --assurance-trigger <t> auto, pull_request, release, or nightly (default: auto)
@@ -30,13 +30,13 @@ export async function verifyControlPlaneConnection(options) {
30
30
  }
31
31
  catch (error) {
32
32
  if (error instanceof ControlPlaneRequestError && error.status === 401) {
33
- throw new Error("AgentCert API key was rejected. Create a new project API key and try again.");
33
+ throw new Error("Witnora API key was rejected. Run `witnora onboard --project <project-id>` again or replace the revoked key.");
34
34
  }
35
35
  if (error instanceof ControlPlaneRequestError && error.status === 403) {
36
- throw new Error(`AgentCert API key cannot access project ${options.projectId}. Check the project ID and key scope.`);
36
+ throw new Error(`Witnora API key cannot access project ${options.projectId}. Check the project ID and key scope.`);
37
37
  }
38
38
  if (error instanceof ControlPlaneRequestError && error.status === 404) {
39
- throw new Error(`AgentCert project ${options.projectId} was not found.`);
39
+ throw new Error(`Witnora project ${options.projectId} was not found.`);
40
40
  }
41
41
  throw error;
42
42
  }
@@ -75,6 +75,15 @@ export async function pushEvidenceToControlPlane(options) {
75
75
  subject: bundle.subject,
76
76
  products: bundle.summary.products,
77
77
  },
78
+ ...(options.runtimeContext ? {
79
+ agent: {
80
+ externalId: options.runtimeContext.agentId,
81
+ name: options.runtimeContext.agentName,
82
+ version: options.runtimeContext.agentVersion,
83
+ framework: options.runtimeContext.framework,
84
+ },
85
+ environment: options.runtimeContext.environment,
86
+ } : {}),
78
87
  assurance: options.assurance,
79
88
  }),
80
89
  });
@@ -46,7 +46,7 @@ export async function resolveConnection(options = {}) {
46
46
  };
47
47
  const missing = Object.entries(candidate).filter(([, value]) => !value).map(([key]) => key);
48
48
  if (missing.length > 0) {
49
- throw new Error(`Hosted connection is incomplete (${missing.join(", ")} missing). Run \`witnora connect\` or set WITNORA_BASE_URL, WITNORA_PROJECT_ID, and WITNORA_API_KEY. Legacy AGENTCERT_* variables remain supported.`);
49
+ throw new Error(`Hosted connection is incomplete (${missing.join(", ")} missing). Run \`witnora onboard --project <project-id>\` or set WITNORA_BASE_URL, WITNORA_PROJECT_ID, and WITNORA_API_KEY. Legacy AGENTCERT_* variables remain supported.`);
50
50
  }
51
51
  return validateConnection(candidate);
52
52
  }