witnora 0.8.1 → 0.9.0

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 (87) hide show
  1. package/README.md +275 -12
  2. package/dist/artifact-manifest.js +37 -0
  3. package/dist/artifact-validation.js +102 -0
  4. package/dist/badge.js +31 -0
  5. package/dist/browser-adapter.js +156 -0
  6. package/dist/bundle.js +100 -0
  7. package/dist/cli.js +971 -0
  8. package/dist/command-help.js +71 -0
  9. package/dist/companion-artifacts.js +170 -0
  10. package/dist/conformance.js +115 -0
  11. package/dist/control-plane.js +409 -0
  12. package/dist/corpus-governance.js +126 -0
  13. package/dist/corpus-store.js +239 -0
  14. package/dist/corpus.js +438 -0
  15. package/dist/credentials.js +127 -0
  16. package/dist/evidence-signing.js +85 -0
  17. package/dist/failure-review.js +188 -0
  18. package/dist/guided-setup.js +101 -0
  19. package/dist/index.js +16 -0
  20. package/dist/lab.js +323 -0
  21. package/dist/local-server.js +491 -0
  22. package/dist/monitor.js +100 -0
  23. package/dist/normalizers.js +265 -0
  24. package/dist/onboarding-templates.js +158 -0
  25. package/dist/release-gate.js +457 -0
  26. package/dist/report.js +165 -0
  27. package/dist/runner.js +349 -0
  28. package/dist/sandbox.js +424 -0
  29. package/dist/schema-validator.js +503 -0
  30. package/dist/try.js +135 -0
  31. package/dist/types.js +3 -0
  32. package/dist/vendor/onegent-runtime/browser-adapter-kit.d.ts +107 -0
  33. package/dist/vendor/onegent-runtime/browser-adapter-kit.d.ts.map +1 -0
  34. package/dist/vendor/onegent-runtime/browser-adapter-kit.js +187 -0
  35. package/dist/vendor/onegent-runtime/browser-enforcement-runtime.d.ts +183 -0
  36. package/dist/vendor/onegent-runtime/browser-enforcement-runtime.d.ts.map +1 -0
  37. package/dist/vendor/onegent-runtime/browser-enforcement-runtime.js +344 -0
  38. package/dist/vendor/onegent-runtime/controlled-adapter.d.ts +6 -0
  39. package/dist/vendor/onegent-runtime/controlled-adapter.d.ts.map +1 -0
  40. package/dist/vendor/onegent-runtime/controlled-adapter.js +40 -0
  41. package/dist/vendor/onegent-runtime/mock-procurement.d.ts +6 -0
  42. package/dist/vendor/onegent-runtime/mock-procurement.d.ts.map +1 -0
  43. package/dist/vendor/onegent-runtime/mock-procurement.js +33 -0
  44. package/dist/vendor/onegent-runtime/policies.d.ts +6 -0
  45. package/dist/vendor/onegent-runtime/policies.d.ts.map +1 -0
  46. package/dist/vendor/onegent-runtime/policies.js +109 -0
  47. package/dist/vendor/onegent-runtime/risk.d.ts +3 -0
  48. package/dist/vendor/onegent-runtime/risk.d.ts.map +1 -0
  49. package/dist/vendor/onegent-runtime/risk.js +54 -0
  50. package/dist/vendor/onegent-runtime/sandbox-adapter-kit.d.ts +45 -0
  51. package/dist/vendor/onegent-runtime/sandbox-adapter-kit.d.ts.map +1 -0
  52. package/dist/vendor/onegent-runtime/sandbox-adapter-kit.js +148 -0
  53. package/dist/vendor/onegent-runtime/sandbox-harness.d.ts +167 -0
  54. package/dist/vendor/onegent-runtime/sandbox-harness.d.ts.map +1 -0
  55. package/dist/vendor/onegent-runtime/sandbox-harness.js +729 -0
  56. package/dist/vendor/onegent-runtime/sandbox-hosted.d.ts +77 -0
  57. package/dist/vendor/onegent-runtime/sandbox-hosted.d.ts.map +1 -0
  58. package/dist/vendor/onegent-runtime/sandbox-hosted.js +152 -0
  59. package/dist/vendor/onegent-runtime/sdk.d.ts +29 -0
  60. package/dist/vendor/onegent-runtime/sdk.d.ts.map +1 -0
  61. package/dist/vendor/onegent-runtime/sdk.js +140 -0
  62. package/dist/vendor/onegent-runtime/service.d.ts +27 -0
  63. package/dist/vendor/onegent-runtime/service.d.ts.map +1 -0
  64. package/dist/vendor/onegent-runtime/service.js +423 -0
  65. package/dist/vendor/onegent-runtime/store.d.ts +16 -0
  66. package/dist/vendor/onegent-runtime/store.d.ts.map +1 -0
  67. package/dist/vendor/onegent-runtime/store.js +29 -0
  68. package/dist/vendor/onegent-runtime/stripe-test-readonly.d.ts +79 -0
  69. package/dist/vendor/onegent-runtime/stripe-test-readonly.d.ts.map +1 -0
  70. package/dist/vendor/onegent-runtime/stripe-test-readonly.js +163 -0
  71. package/dist/vendor/onegent-runtime/trust-crypto.d.ts +11 -0
  72. package/dist/vendor/onegent-runtime/trust-crypto.d.ts.map +1 -0
  73. package/dist/vendor/onegent-runtime/trust-crypto.js +70 -0
  74. package/dist/vendor/onegent-runtime/trust-types.d.ts +163 -0
  75. package/dist/vendor/onegent-runtime/trust-types.d.ts.map +1 -0
  76. package/dist/vendor/onegent-runtime/trust-types.js +7 -0
  77. package/dist/vendor/onegent-runtime/trusted-recorder.d.ts +49 -0
  78. package/dist/vendor/onegent-runtime/trusted-recorder.d.ts.map +1 -0
  79. package/dist/vendor/onegent-runtime/trusted-recorder.js +347 -0
  80. package/dist/vendor/onegent-runtime/types.d.ts +287 -0
  81. package/dist/vendor/onegent-runtime/types.d.ts.map +1 -0
  82. package/dist/vendor/onegent-runtime/types.js +1 -0
  83. package/dist/vendor/onegent-runtime/vendor-sandbox-egress.d.ts +49 -0
  84. package/dist/vendor/onegent-runtime/vendor-sandbox-egress.d.ts.map +1 -0
  85. package/dist/vendor/onegent-runtime/vendor-sandbox-egress.js +152 -0
  86. package/package.json +33 -13
  87. package/bin/witnora.js +0 -3
package/dist/runner.js ADDED
@@ -0,0 +1,349 @@
1
+ import { spawn } from "node:child_process";
2
+ import { createHash } from "node:crypto";
3
+ import { access, mkdir, readFile, writeFile } from "node:fs/promises";
4
+ import { renderAgentCertBadge } from "./badge.js";
5
+ import { dirname, join, resolve } from "node:path";
6
+ import { buildEvidenceBundle } from "./bundle.js";
7
+ import { recordsFromAgentCertResult, renderCorpusSummary, summarizeCorpus, writeReviewedFailureDataset, } from "./corpus.js";
8
+ import { openCorpusStore, parseCorpusStoreKind } from "./corpus-store.js";
9
+ import { applyFailureReviews, readFailureReviews } from "./failure-review.js";
10
+ import { governCorpusRecords } from "./corpus-governance.js";
11
+ import { buildMonitorSnapshot, writeMonitorSnapshot } from "./monitor.js";
12
+ import { normalizeMcpBenchResult, normalizeOnegentAuditPacket, normalizeTripwireResult } from "./normalizers.js";
13
+ import { renderHtmlReport, renderMarkdownReport } from "./report.js";
14
+ const JOB_KEYS = ["mcpbench", "tripwire", "onegent"];
15
+ export function publicDemoRunProfile() {
16
+ return {
17
+ schemaVersion: "1",
18
+ subject: {
19
+ name: "agentcert-public-demo",
20
+ type: "agent",
21
+ },
22
+ artifacts: {
23
+ mcpbench: "public-demo/lifecycle-evidence/mcpbench-passing/results.json",
24
+ tripwire: "public-demo/browser-agent-robustness/evidence/tripwire-public-demo/tripwire-result.json",
25
+ onegent: "public-demo/lifecycle-evidence/onegent-procurement/audit-packet.json",
26
+ },
27
+ outputDir: "public-demo/browser-agent-robustness/evidence/agentcert-public-demo",
28
+ run: {
29
+ corpus: {
30
+ path: "public-demo/browser-agent-robustness/evidence/agentcert-corpus.jsonl",
31
+ reviewsPath: "public-demo/browser-agent-robustness/evidence/failure-reviews.jsonl",
32
+ replace: true,
33
+ },
34
+ monitor: {
35
+ outputs: [
36
+ "packages/agentcert-dashboard/public/data/monitor.json",
37
+ "public-demo/agentcert-monitor/data/monitor.json",
38
+ ],
39
+ detailUrl: "../browser-agent-robustness/",
40
+ },
41
+ dataset: {
42
+ reviewedOutputs: ["public-demo/browser-agent-robustness/evidence/reviewed-failure-dataset.jsonl"],
43
+ },
44
+ gate: {
45
+ failOnVerdict: false,
46
+ },
47
+ },
48
+ };
49
+ }
50
+ export async function loadRunProfile(profileName, configPath) {
51
+ if (profileName === "public-demo") {
52
+ return publicDemoRunProfile();
53
+ }
54
+ if (profileName && profileName !== "public-demo") {
55
+ throw new Error(`Unknown Witnora run profile "${profileName}". Available profiles: public-demo.`);
56
+ }
57
+ if (configPath) {
58
+ return (await readJson(configPath));
59
+ }
60
+ const defaultConfigPath = "witnora.config.json";
61
+ try {
62
+ await access(resolve(defaultConfigPath));
63
+ return (await readJson(defaultConfigPath));
64
+ }
65
+ catch {
66
+ const legacyConfigPath = "agentcert.config.json";
67
+ try {
68
+ await access(resolve(legacyConfigPath));
69
+ return (await readJson(legacyConfigPath));
70
+ }
71
+ catch {
72
+ throw new Error("witnora run requires --profile public-demo, --config <path>, explicit artifact flags, witnora.config.json, or the legacy agentcert.config.json in the current directory.");
73
+ }
74
+ }
75
+ }
76
+ export function profileFromArtifactFlags(overrides) {
77
+ return {
78
+ schemaVersion: "1",
79
+ subject: {
80
+ name: overrides.subject ?? "witnora-subject",
81
+ type: "agent",
82
+ },
83
+ artifacts: {
84
+ mcpbench: overrides.mcpbench,
85
+ tripwire: overrides.tripwire,
86
+ onegent: overrides.onegent,
87
+ },
88
+ outputDir: overrides.outDir ?? ".witnora/latest",
89
+ run: {
90
+ corpus: {
91
+ path: overrides.corpusPath ?? ".witnora/corpus/corpus.jsonl",
92
+ replace: overrides.replaceCorpus ?? false,
93
+ },
94
+ monitor: {
95
+ outputs: [overrides.monitorOut ?? ".witnora/latest/monitor.json"],
96
+ },
97
+ dataset: {
98
+ reviewedOutputs: [overrides.reviewedDatasetOut ?? ".witnora/latest/reviewed-failure-dataset.jsonl"],
99
+ },
100
+ gate: {
101
+ failOnVerdict: overrides.failOnVerdict ?? false,
102
+ },
103
+ },
104
+ };
105
+ }
106
+ export function applyRunOverrides(profile, overrides = {}) {
107
+ const next = {
108
+ ...profile,
109
+ subject: {
110
+ ...profile.subject,
111
+ name: overrides.subject ?? profile.subject.name,
112
+ },
113
+ artifacts: {
114
+ ...profile.artifacts,
115
+ ...(overrides.mcpbench ? { mcpbench: overrides.mcpbench } : {}),
116
+ ...(overrides.tripwire ? { tripwire: overrides.tripwire } : {}),
117
+ ...(overrides.onegent ? { onegent: overrides.onegent } : {}),
118
+ },
119
+ outputDir: overrides.outDir ?? profile.outputDir,
120
+ run: {
121
+ ...profile.run,
122
+ corpus: {
123
+ ...profile.run?.corpus,
124
+ ...(overrides.corpusPath ? { path: overrides.corpusPath } : {}),
125
+ ...(overrides.reviewsPath ? { reviewsPath: overrides.reviewsPath } : {}),
126
+ ...(overrides.replaceCorpus === undefined ? {} : { replace: overrides.replaceCorpus }),
127
+ },
128
+ monitor: {
129
+ ...profile.run?.monitor,
130
+ ...(overrides.monitorOut ? { outputs: [overrides.monitorOut] } : {}),
131
+ },
132
+ dataset: {
133
+ ...profile.run?.dataset,
134
+ ...(overrides.reviewedDatasetOut ? { reviewedOutputs: [overrides.reviewedDatasetOut] } : {}),
135
+ },
136
+ gate: {
137
+ ...profile.run?.gate,
138
+ ...(overrides.failOnVerdict === undefined ? {} : { failOnVerdict: overrides.failOnVerdict }),
139
+ },
140
+ },
141
+ };
142
+ return next;
143
+ }
144
+ export async function runAgentCertProfile(profileInput, options = {}) {
145
+ const cwd = resolve(options.cwd ?? process.cwd());
146
+ const profile = applyRunOverrides(profileInput, options.overrides);
147
+ const steps = [];
148
+ const loaded = [];
149
+ for (const key of JOB_KEYS) {
150
+ const job = jobFor(profile, key);
151
+ if (!job.artifact && !job.command) {
152
+ steps.push({ id: key, status: "skipped", message: "No command or artifact configured." });
153
+ continue;
154
+ }
155
+ if (job.command && options.runCommands !== false) {
156
+ const step = await runJobCommand(key, job.command, cwd, options.commandStdio ?? "inherit");
157
+ steps.push(step);
158
+ if (step.status === "failed" && !job.allowCommandFailure) {
159
+ throw new Error(`${key} command failed with exit code ${step.exitCode ?? "unknown"}.`);
160
+ }
161
+ }
162
+ if (!job.artifact) {
163
+ if (job.required !== false) {
164
+ throw new Error(`${key} did not define an artifact path.`);
165
+ }
166
+ steps.push({ id: key, status: "skipped", message: "No artifact configured." });
167
+ continue;
168
+ }
169
+ const raw = await readJson(job.artifact, cwd);
170
+ loaded.push({ key, path: job.artifact, raw, result: normalizeArtifact(key, raw, job.artifact) });
171
+ steps.push({ id: key, status: "passed", artifactPath: job.artifact });
172
+ }
173
+ if (loaded.length === 0) {
174
+ throw new Error("No Witnora artifacts were loaded. Configure at least one MCPBench, Tripwire, or Onegent artifact.");
175
+ }
176
+ const bundle = buildEvidenceBundle(loaded.map((artifact) => artifact.result), profile.subject.name, profile.subject.type);
177
+ const reviewsPath = profile.run?.corpus?.reviewsPath;
178
+ const reviews = await readFailureReviews(reviewsPath ? resolve(cwd, reviewsPath) : undefined);
179
+ const records = governCorpusRecords(applyFailureReviews(loaded.flatMap(({ result, path, raw }) => recordsFromAgentCertResult(result, path, profile.subject.name, raw)), reviews), { consent: "private", consentSource: "agentcert-runner-default" });
180
+ const outputs = { monitor: [], reviewedDataset: [] };
181
+ const reportEnabled = profile.run?.report?.enabled ?? true;
182
+ const reportDir = profile.run?.report?.outDir ?? profile.outputDir;
183
+ if (reportEnabled && reportDir) {
184
+ const resolvedReportDir = resolve(cwd, reportDir);
185
+ await mkdir(resolvedReportDir, { recursive: true });
186
+ await writeFile(`${resolvedReportDir}/agentcert-evidence.json`, `${JSON.stringify(bundle, null, 2)}\n`);
187
+ await writeFile(`${resolvedReportDir}/agentcert-report.md`, renderMarkdownReport(bundle));
188
+ await writeFile(`${resolvedReportDir}/agentcert-report.html`, renderHtmlReport(bundle));
189
+ await writeFile(`${resolvedReportDir}/badge.svg`, renderAgentCertBadge(bundle));
190
+ steps.push({ id: "report", status: "passed", artifactPath: reportDir });
191
+ outputs.reportDir = reportDir;
192
+ outputs.evidenceBundle = artifactPath(reportDir, "agentcert-evidence.json");
193
+ outputs.markdownReport = artifactPath(reportDir, "agentcert-report.md");
194
+ outputs.htmlReport = artifactPath(reportDir, "agentcert-report.html");
195
+ outputs.badge = artifactPath(reportDir, "badge.svg");
196
+ }
197
+ else {
198
+ steps.push({ id: "report", status: "skipped", message: "Report output disabled." });
199
+ }
200
+ const corpusOptions = corpusStoreOptions(profile, cwd);
201
+ const store = await openCorpusStore(corpusOptions);
202
+ try {
203
+ await store.append(records, { replace: profile.run?.corpus?.replace ?? false });
204
+ const allRecords = await store.readAll();
205
+ steps.push({ id: "corpus", status: "passed", artifactPath: profile.run?.corpus?.path ?? corpusOptions.jsonlPath });
206
+ outputs.corpus = profile.run?.corpus?.path ?? corpusOptions.jsonlPath ?? store.description;
207
+ const monitorOutputs = monitorOutputsFor(profile);
208
+ for (const outPath of monitorOutputs) {
209
+ const snapshot = buildMonitorSnapshot(allRecords, {
210
+ subject: profile.run?.monitor?.subject ?? profile.subject.name,
211
+ detailUrl: profile.run?.monitor?.detailUrl,
212
+ });
213
+ await writeMonitorSnapshot(resolve(cwd, outPath), snapshot);
214
+ outputs.monitor.push(outPath);
215
+ }
216
+ const reviewedDatasetOutputs = reviewedDatasetOutputsFor(profile);
217
+ for (const outPath of reviewedDatasetOutputs) {
218
+ await writeReviewedFailureDataset(resolve(cwd, outPath), allRecords);
219
+ outputs.reviewedDataset.push(outPath);
220
+ }
221
+ steps.push({
222
+ id: "dataset",
223
+ status: reviewedDatasetOutputs.length > 0 ? "passed" : "skipped",
224
+ artifactPath: reviewedDatasetOutputs.join(", "),
225
+ message: reviewedDatasetOutputs.length > 0 ? undefined : "No reviewed dataset output configured.",
226
+ });
227
+ steps.push({
228
+ id: "monitor",
229
+ status: monitorOutputs.length > 0 ? "passed" : "skipped",
230
+ artifactPath: monitorOutputs.join(", "),
231
+ message: monitorOutputs.length > 0 ? undefined : "No monitor output configured.",
232
+ });
233
+ }
234
+ finally {
235
+ await store.close();
236
+ }
237
+ const manifestPath = profile.run?.manifest?.out ?? (profile.outputDir ? join(profile.outputDir, "agentcert-run-manifest.json") : undefined);
238
+ const manifest = {
239
+ schemaVersion: "1",
240
+ kind: "agentcert.run_manifest",
241
+ runId: stableRunId(profile, bundle),
242
+ generatedAt: new Date().toISOString(),
243
+ subject: profile.subject,
244
+ steps,
245
+ outputs,
246
+ verdict: bundle.verdict,
247
+ summary: bundle.summary,
248
+ };
249
+ if (manifestPath) {
250
+ const resolvedManifestPath = resolve(cwd, manifestPath);
251
+ await mkdir(dirname(resolvedManifestPath), { recursive: true });
252
+ manifest.outputs.manifest = normalizeArtifactPath(manifestPath);
253
+ await writeFile(resolvedManifestPath, `${JSON.stringify(manifest, null, 2)}\n`);
254
+ }
255
+ const failOnVerdict = profile.run?.gate?.failOnVerdict ?? false;
256
+ return {
257
+ exitCode: failOnVerdict && !bundle.verdict.passed ? 1 : 0,
258
+ bundle,
259
+ records,
260
+ manifest,
261
+ };
262
+ }
263
+ export function renderRunSummary(outcome) {
264
+ const lines = [
265
+ "# Witnora Run",
266
+ "",
267
+ `Subject: ${outcome.manifest.subject.name}`,
268
+ `Verdict: ${outcome.bundle.verdict.passed ? "PASS" : "FAIL"} (${outcome.bundle.verdict.score}/100)`,
269
+ `Products: ${outcome.bundle.summary.products.join(", ")}`,
270
+ `Records: ${outcome.records.length}`,
271
+ "",
272
+ "## Outputs",
273
+ ...Object.entries(outcome.manifest.outputs)
274
+ .filter(([, value]) => (Array.isArray(value) ? value.length > 0 : Boolean(value)))
275
+ .map(([key, value]) => `- ${key}: ${Array.isArray(value) ? value.join(", ") : value}`),
276
+ "",
277
+ "## Corpus Summary",
278
+ renderCorpusSummary(summarizeCorpus(outcome.records)).trim(),
279
+ ];
280
+ return `${lines.join("\n")}\n`;
281
+ }
282
+ async function runJobCommand(id, command, cwd, stdio) {
283
+ const startedAt = Date.now();
284
+ const exitCode = await new Promise((resolveExit, reject) => {
285
+ const child = spawn(command, { cwd, shell: true, stdio });
286
+ child.on("error", reject);
287
+ child.on("exit", resolveExit);
288
+ });
289
+ const durationMs = Date.now() - startedAt;
290
+ return {
291
+ id,
292
+ command,
293
+ durationMs,
294
+ exitCode: exitCode ?? undefined,
295
+ status: exitCode === 0 ? "passed" : "failed",
296
+ };
297
+ }
298
+ function jobFor(profile, key) {
299
+ const explicit = profile.run?.jobs?.[key] ?? {};
300
+ return {
301
+ required: true,
302
+ ...explicit,
303
+ artifact: explicit.artifact ?? profile.artifacts[key],
304
+ };
305
+ }
306
+ function normalizeArtifact(key, raw, artifactPath) {
307
+ if (key === "mcpbench")
308
+ return normalizeMcpBenchResult(raw, artifactPath);
309
+ if (key === "tripwire")
310
+ return normalizeTripwireResult(raw, artifactPath);
311
+ return normalizeOnegentAuditPacket(raw, artifactPath);
312
+ }
313
+ function corpusStoreOptions(profile, cwd) {
314
+ const corpus = profile.run?.corpus ?? {};
315
+ return {
316
+ kind: parseCorpusStoreKind(corpus.store),
317
+ jsonlPath: corpus.path ? resolve(cwd, corpus.path) : resolve(cwd, ".witnora/corpus/corpus.jsonl"),
318
+ sqlitePath: corpus.sqlitePath ? resolve(cwd, corpus.sqlitePath) : resolve(cwd, ".witnora/corpus/witnora.sqlite"),
319
+ databaseUrl: corpus.databaseUrl ?? process.env.WITNORA_DATABASE_URL ?? process.env.AGENTCERT_DATABASE_URL ?? process.env.DATABASE_URL,
320
+ tableName: corpus.tableName,
321
+ };
322
+ }
323
+ function monitorOutputsFor(profile) {
324
+ const monitor = profile.run?.monitor;
325
+ return [...(monitor?.outputs ?? []), ...(monitor?.out ? [monitor.out] : [])];
326
+ }
327
+ function reviewedDatasetOutputsFor(profile) {
328
+ const dataset = profile.run?.dataset;
329
+ return [...(dataset?.reviewedOutputs ?? []), ...(dataset?.reviewedOut ? [dataset.reviewedOut] : [])];
330
+ }
331
+ function artifactPath(base, file) {
332
+ return normalizeArtifactPath(`${base.replace(/[\\/]+$/, "")}/${file}`);
333
+ }
334
+ function normalizeArtifactPath(path) {
335
+ return path.replace(/\\/g, "/");
336
+ }
337
+ async function readJson(path, cwd = process.cwd()) {
338
+ const fullPath = resolve(cwd, path);
339
+ await access(fullPath);
340
+ const raw = await readFile(fullPath, "utf8");
341
+ return JSON.parse(raw);
342
+ }
343
+ function stableRunId(profile, bundle) {
344
+ const hash = createHash("sha256")
345
+ .update(`${profile.subject.name}:${bundle.runId}:${JSON.stringify(bundle.summary)}`)
346
+ .digest("hex")
347
+ .slice(0, 12);
348
+ return `agentcert_run_${hash}`;
349
+ }