@prooflane/inspector-beta 0.1.0-beta.6 → 0.1.0-beta.8
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/dist/cli.mjs +3 -3
- package/dist/server.mjs +409 -201
- package/dist/ui/assets/index-CPtCo7m6.js +69 -0
- package/dist/ui/assets/index-Dj20G-qT.css +1 -0
- package/dist/ui/index.html +2 -2
- package/package.json +1 -1
- package/dist/ui/assets/index-CHGGvbAw.js +0 -69
- package/dist/ui/assets/index-D_0fJhzv.css +0 -1
package/dist/server.mjs
CHANGED
|
@@ -1099,10 +1099,10 @@ function decodeJwt(jwt) {
|
|
|
1099
1099
|
}
|
|
1100
1100
|
|
|
1101
1101
|
// ../server/dist/app.js
|
|
1102
|
-
import { createHash as
|
|
1103
|
-
import { existsSync as
|
|
1102
|
+
import { createHash as createHash16, randomUUID as randomUUID8 } from "node:crypto";
|
|
1103
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync2 } from "node:fs";
|
|
1104
1104
|
import { fileURLToPath } from "node:url";
|
|
1105
|
-
import { dirname as dirname4, join as
|
|
1105
|
+
import { dirname as dirname4, join as join5, resolve as resolve6 } from "node:path";
|
|
1106
1106
|
|
|
1107
1107
|
// ../core/dist/transport/mcpTransport.js
|
|
1108
1108
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
@@ -1386,9 +1386,9 @@ async function startCallbackServer(path = "/callback", port = callbackPort()) {
|
|
|
1386
1386
|
res.end(PAGE("Authorized \u2713", "You can close this tab and return to Kawach Inspector.")), resolveCode(code);
|
|
1387
1387
|
});
|
|
1388
1388
|
try {
|
|
1389
|
-
await new Promise((
|
|
1389
|
+
await new Promise((resolve7, reject) => {
|
|
1390
1390
|
server.once("error", reject), server.listen(port, "127.0.0.1", () => {
|
|
1391
|
-
server.off("error", reject),
|
|
1391
|
+
server.off("error", reject), resolve7();
|
|
1392
1392
|
});
|
|
1393
1393
|
});
|
|
1394
1394
|
} catch (err) {
|
|
@@ -1902,7 +1902,7 @@ var Store = class {
|
|
|
1902
1902
|
return this.db.prepare(`UPDATE benchmark_entitlements SET state = 'AVAILABLE', reservation_key = NULL, reserved_at = NULL
|
|
1903
1903
|
WHERE id = ? AND workspace_id = ? AND state = 'RESERVED' AND reservation_key = ?`).run(entitlementId, workspaceId, reservationKey), this.getBenchmarkEntitlement(entitlementId);
|
|
1904
1904
|
}
|
|
1905
|
-
saveBenchmarkRun(
|
|
1905
|
+
saveBenchmarkRun(record7) {
|
|
1906
1906
|
this.db.prepare(`INSERT INTO benchmark_runs
|
|
1907
1907
|
(run_id, workspace_id, status, plan_json, summary_json, report_json, report_html, created_at, updated_at)
|
|
1908
1908
|
VALUES (@run_id, @workspace_id, @status, @plan_json, @summary_json, @report_json, @report_html, @created_at, @updated_at)
|
|
@@ -1912,15 +1912,15 @@ var Store = class {
|
|
|
1912
1912
|
report_json = excluded.report_json,
|
|
1913
1913
|
report_html = excluded.report_html,
|
|
1914
1914
|
updated_at = excluded.updated_at`).run({
|
|
1915
|
-
run_id:
|
|
1916
|
-
workspace_id:
|
|
1917
|
-
status:
|
|
1918
|
-
plan_json: JSON.stringify(
|
|
1919
|
-
summary_json:
|
|
1920
|
-
report_json:
|
|
1921
|
-
report_html:
|
|
1922
|
-
created_at:
|
|
1923
|
-
updated_at:
|
|
1915
|
+
run_id: record7.runId,
|
|
1916
|
+
workspace_id: record7.workspaceId,
|
|
1917
|
+
status: record7.status,
|
|
1918
|
+
plan_json: JSON.stringify(record7.plan),
|
|
1919
|
+
summary_json: record7.summary ? JSON.stringify(record7.summary) : null,
|
|
1920
|
+
report_json: record7.report ? JSON.stringify(record7.report) : null,
|
|
1921
|
+
report_html: record7.reportHtml ?? null,
|
|
1922
|
+
created_at: record7.createdAt,
|
|
1923
|
+
updated_at: record7.updatedAt
|
|
1924
1924
|
});
|
|
1925
1925
|
}
|
|
1926
1926
|
getBenchmarkRun(runId) {
|
|
@@ -3152,12 +3152,12 @@ ${http2.content}`
|
|
|
3152
3152
|
addPromptCases(cases, source = "ai") {
|
|
3153
3153
|
let saved = [], skipped = 0;
|
|
3154
3154
|
for (let item of cases) {
|
|
3155
|
-
let [
|
|
3156
|
-
if (!
|
|
3155
|
+
let [record7] = this.addPrompts([{ category: item.category, name: item.name, content: item.content, tool: item.tool }], source);
|
|
3156
|
+
if (!record7) {
|
|
3157
3157
|
skipped += 1;
|
|
3158
3158
|
continue;
|
|
3159
3159
|
}
|
|
3160
|
-
item.assertions && item.assertions.length || item.checkSchema ? (this.store.setPromptChecks(
|
|
3160
|
+
item.assertions && item.assertions.length || item.checkSchema ? (this.store.setPromptChecks(record7.id, { assertions: item.assertions, checkSchema: item.checkSchema }), saved.push({ ...record7, assertions: item.assertions, checkSchema: item.checkSchema })) : saved.push(record7);
|
|
3161
3161
|
}
|
|
3162
3162
|
return { saved, skipped };
|
|
3163
3163
|
}
|
|
@@ -4225,7 +4225,7 @@ function validateGovernedGateManifest(value) {
|
|
|
4225
4225
|
if (!record2(value))
|
|
4226
4226
|
return { ok: !1, error: "Gate manifest must be an object." };
|
|
4227
4227
|
let forbidden = findForbiddenGateManifestMaterial(value);
|
|
4228
|
-
return forbidden ? { ok: !1, error: `Gate manifest rejected: ${forbidden}.` } : exactKeys(value, ["schemaVersion", "suiteRef", "policyRef", "targetScope", "environment", "requiredPillars", "settings", "approvalRules"]) ? value.schemaVersion !== GATE_MANIFEST_VERSION ? { ok: !1, error: `Gate manifest must use ${GATE_MANIFEST_VERSION}.` } : validateSuiteReference(value.suiteRef) ? validatePolicyReference(value.policyRef) ? !record2(value.targetScope) || !exactKeys(value.targetScope, ["projectId"]) || !text2(value.targetScope.projectId, 2, 128, projectPattern) ? { ok: !1, error: "Gate targetScope must contain one stable projectId." } : text2(value.environment, 2, 64, slugPattern) ? !Array.isArray(value.requiredPillars) || value.requiredPillars.length < 1 || value.requiredPillars.length > POLICY_PILLARS.length ? { ok: !1, error: "Gate requiredPillars must contain at least one supported Policy pillar." } : value.requiredPillars.every((pillar) => POLICY_PILLARS.includes(pillar)) ? new Set(value.requiredPillars).size !== value.requiredPillars.length ? { ok: !1, error: "Gate requiredPillars must be unique." } : !record2(value.settings) || !exactKeys(value.settings, ["executionMode", "evidenceSync"]) || value.settings.executionMode !== "ALL_CONTROLS" || value.settings.evidenceSync !== "COMPACT_ONLY" ? { ok: !1, error: "Gate settings must execute all signed Suite controls and synchronize compact evidence only." } : !record2(value.approvalRules) || !exactKeys(value.approvalRules, ["minimumApprovals", "requireDistinctReviewer"]) || value.approvalRules.minimumApprovals !== 1 || value.approvalRules.requireDistinctReviewer
|
|
4228
|
+
return forbidden ? { ok: !1, error: `Gate manifest rejected: ${forbidden}.` } : exactKeys(value, ["schemaVersion", "suiteRef", "policyRef", "targetScope", "environment", "requiredPillars", "settings", "approvalRules"]) ? value.schemaVersion !== GATE_MANIFEST_VERSION ? { ok: !1, error: `Gate manifest must use ${GATE_MANIFEST_VERSION}.` } : validateSuiteReference(value.suiteRef) ? validatePolicyReference(value.policyRef) ? !record2(value.targetScope) || !exactKeys(value.targetScope, ["projectId"]) || !text2(value.targetScope.projectId, 2, 128, projectPattern) ? { ok: !1, error: "Gate targetScope must contain one stable projectId." } : text2(value.environment, 2, 64, slugPattern) ? !Array.isArray(value.requiredPillars) || value.requiredPillars.length < 1 || value.requiredPillars.length > POLICY_PILLARS.length ? { ok: !1, error: "Gate requiredPillars must contain at least one supported Policy pillar." } : value.requiredPillars.every((pillar) => POLICY_PILLARS.includes(pillar)) ? new Set(value.requiredPillars).size !== value.requiredPillars.length ? { ok: !1, error: "Gate requiredPillars must be unique." } : !record2(value.settings) || !exactKeys(value.settings, ["executionMode", "evidenceSync"]) || value.settings.executionMode !== "ALL_CONTROLS" || value.settings.evidenceSync !== "COMPACT_ONLY" ? { ok: !1, error: "Gate settings must execute all signed Suite controls and synchronize compact evidence only." } : !record2(value.approvalRules) || !exactKeys(value.approvalRules, ["minimumApprovals", "requireDistinctReviewer"]) || value.approvalRules.minimumApprovals !== 1 || typeof value.approvalRules.requireDistinctReviewer != "boolean" ? { ok: !1, error: "Gate approvalRules must require one recorded approval and a boolean reviewer policy." } : { ok: !0, manifest: value } : { ok: !1, error: "Gate requiredPillars contains an unsupported pillar." } : { ok: !1, error: "Gate environment must be a bounded lowercase slug." } : { ok: !1, error: "Gate policyRef must pin an exact Policy identity, version ID, version, and SHA-256 hash." } : { ok: !1, error: "Gate suiteRef must pin an exact Suite identity, slug, version ID, version, and SHA-256 hash." } : { ok: !1, error: "Gate manifest must contain only the frozen v1 fields." };
|
|
4229
4229
|
}
|
|
4230
4230
|
function hashGovernedGateManifest(value) {
|
|
4231
4231
|
let validated = validateGovernedGateManifest(value);
|
|
@@ -4688,13 +4688,13 @@ function fingerprintLocalSuite(suite) {
|
|
|
4688
4688
|
function executorForPillar(pillar) {
|
|
4689
4689
|
return pillar === "prompt" ? "PROMPT" : pillar === "rag" ? "RAG" : pillar === "contract" ? "CONTRACT" : pillar === "performance" ? "PERFORMANCE" : pillar === "model" ? "MODEL" : "MCP";
|
|
4690
4690
|
}
|
|
4691
|
-
function compileLegacyLocalSuiteManifest(suite,
|
|
4692
|
-
if (!/^sha256:[a-f0-9]{64}$/.test(
|
|
4691
|
+
function compileLegacyLocalSuiteManifest(suite, localFingerprint2 = fingerprintLocalSuite(suite)) {
|
|
4692
|
+
if (!/^sha256:[a-f0-9]{64}$/.test(localFingerprint2))
|
|
4693
4693
|
throw new Error("Local Suite migration fingerprint is invalid.");
|
|
4694
4694
|
let pillarCounts = {};
|
|
4695
4695
|
for (let test of suite.tests)
|
|
4696
4696
|
pillarCounts[test.pillar] = (pillarCounts[test.pillar] ?? 0) + 1;
|
|
4697
|
-
let assetName = `local-suite-${
|
|
4697
|
+
let assetName = `local-suite-${localFingerprint2.slice(7)}`, manifest = {
|
|
4698
4698
|
schemaVersion: "prooflane-suite-manifest-v1",
|
|
4699
4699
|
executionClass: "LOCAL_ONLY",
|
|
4700
4700
|
controls: PILLARS2.filter((pillar) => !!pillarCounts[pillar]).map((pillar) => ({
|
|
@@ -4707,7 +4707,7 @@ function compileLegacyLocalSuiteManifest(suite, localFingerprint = fingerprintLo
|
|
|
4707
4707
|
localRef: { kind: "PROJECT_ASSET", name: assetName },
|
|
4708
4708
|
parameters: {
|
|
4709
4709
|
schemaVersion: LOCAL_SUITE_MIGRATION_VERSION,
|
|
4710
|
-
localFingerprint,
|
|
4710
|
+
localFingerprint: localFingerprint2,
|
|
4711
4711
|
localVersion: suite.version,
|
|
4712
4712
|
testCount: pillarCounts[pillar]
|
|
4713
4713
|
}
|
|
@@ -4738,7 +4738,7 @@ function readLegacyLocalSuiteArtifact(file, cwd = process.cwd()) {
|
|
|
4738
4738
|
} catch (error) {
|
|
4739
4739
|
throw new Error(`Could not read local Suite ${basename(sourcePath)}: ${error instanceof Error ? error.message : String(error)}`);
|
|
4740
4740
|
}
|
|
4741
|
-
let suite = validateLegacyLocalSuite(parsed),
|
|
4741
|
+
let suite = validateLegacyLocalSuite(parsed), localFingerprint2 = fingerprintLocalSuite(suite), manifest = compileLegacyLocalSuiteManifest(suite, localFingerprint2), pillarCounts = {};
|
|
4742
4742
|
for (let test of suite.tests)
|
|
4743
4743
|
pillarCounts[test.pillar] = (pillarCounts[test.pillar] ?? 0) + 1;
|
|
4744
4744
|
let supported = suite.tests.filter(localSuiteTestIsGeneric).length, projectRelative = relative(cwd, sourcePath);
|
|
@@ -4748,7 +4748,7 @@ function readLegacyLocalSuiteArtifact(file, cwd = process.cwd()) {
|
|
|
4748
4748
|
projectRelativePath: projectRelative.startsWith("..") || projectRelative.startsWith("/") ? null : projectRelative,
|
|
4749
4749
|
slug: localSuiteSlug(suite.id),
|
|
4750
4750
|
displayName: localDisplayName(suite.id),
|
|
4751
|
-
localFingerprint,
|
|
4751
|
+
localFingerprint: localFingerprint2,
|
|
4752
4752
|
manifest,
|
|
4753
4753
|
migrationManifestHash: hashGovernedSuiteManifest(manifest),
|
|
4754
4754
|
suite,
|
|
@@ -4789,7 +4789,7 @@ function discoverLegacyLocalSuites(input = {}) {
|
|
|
4789
4789
|
return { suites, issues };
|
|
4790
4790
|
}
|
|
4791
4791
|
function migrationManifestHash(manifest) {
|
|
4792
|
-
let { policyRef: _policyRef, ...content } = manifest;
|
|
4792
|
+
let { policyRef: _policyRef, targetFingerprint: _targetFingerprint, requiredCapabilities: _requiredCapabilities, ...content } = manifest;
|
|
4793
4793
|
return hashGovernedSuiteManifest(content);
|
|
4794
4794
|
}
|
|
4795
4795
|
function planLegacyLocalSuiteMigration(local, cloud) {
|
|
@@ -4989,10 +4989,10 @@ function resultCount(output) {
|
|
|
4989
4989
|
return output.length;
|
|
4990
4990
|
if (!output || typeof output != "object")
|
|
4991
4991
|
return null;
|
|
4992
|
-
let
|
|
4992
|
+
let record7 = output;
|
|
4993
4993
|
for (let key of ["results", "documents", "items", "data", "matches"])
|
|
4994
|
-
if (Array.isArray(
|
|
4995
|
-
return
|
|
4994
|
+
if (Array.isArray(record7[key]))
|
|
4995
|
+
return record7[key].length;
|
|
4996
4996
|
return null;
|
|
4997
4997
|
}
|
|
4998
4998
|
function compactError(cause) {
|
|
@@ -5628,11 +5628,11 @@ async function gradeExecution(candidate, benchmarkCase, result, scorers, passThr
|
|
|
5628
5628
|
return { assertions, dimensions, score, verdict, securityBreach, criticalFailure, functionalSuccess, secureTaskSuccess };
|
|
5629
5629
|
}
|
|
5630
5630
|
async function withTimeout(promise, timeoutMs, signal) {
|
|
5631
|
-
return timeoutMs <= 0 && !signal ? promise : await new Promise((
|
|
5631
|
+
return timeoutMs <= 0 && !signal ? promise : await new Promise((resolve7, reject) => {
|
|
5632
5632
|
let settled = !1, finish = (fn) => {
|
|
5633
5633
|
settled || (settled = !0, clearTimeout(timer), signal && signal.removeEventListener("abort", onAbort), fn());
|
|
5634
5634
|
}, timer = timeoutMs > 0 ? setTimeout(() => finish(() => reject(new Error(`benchmark timeout after ${timeoutMs}ms`))), timeoutMs) : void 0, onAbort = () => finish(() => reject(new Error("benchmark cancelled")));
|
|
5635
|
-
signal && signal.addEventListener("abort", onAbort, { once: !0 }), promise.then((v) => finish(() =>
|
|
5635
|
+
signal && signal.addEventListener("abort", onAbort, { once: !0 }), promise.then((v) => finish(() => resolve7(v)), (e) => finish(() => reject(e)));
|
|
5636
5636
|
});
|
|
5637
5637
|
}
|
|
5638
5638
|
async function pool(items, limit, work) {
|
|
@@ -8663,9 +8663,9 @@ function readHuggingFaceCache(ir) {
|
|
|
8663
8663
|
recordedFiles
|
|
8664
8664
|
};
|
|
8665
8665
|
}
|
|
8666
|
-
function compareRecordedDigests(ir,
|
|
8666
|
+
function compareRecordedDigests(ir, record7) {
|
|
8667
8667
|
let onDisk = new Map(ir.files.map((f) => [f.path, f.sha256])), out = { matched: [], mismatched: [], unverifiable: [] };
|
|
8668
|
-
for (let entry of
|
|
8668
|
+
for (let entry of record7.digests) {
|
|
8669
8669
|
if (entry.algorithm !== "sha256") {
|
|
8670
8670
|
out.unverifiable.push(entry.path);
|
|
8671
8671
|
continue;
|
|
@@ -8683,25 +8683,25 @@ function compareRecordedDigests(ir, record6) {
|
|
|
8683
8683
|
// ../core/dist/modelSecurity/packs/provenance.js
|
|
8684
8684
|
var PACK2 = "model-provenance", IMMUTABLE_REVISION = /^[a-f0-9]{7,64}$/i, FLOATING_NAMES = /^(?:main|master|develop|dev|trunk|latest|head|refs\/heads\/.+|refs\/tags\/.+|v?\d+(?:\.\d+)*(?:-[a-z0-9.]+)?)$/i;
|
|
8685
8685
|
function readProvenance(ir) {
|
|
8686
|
-
let
|
|
8687
|
-
ir.target.sourceType === "huggingface" && (
|
|
8686
|
+
let record7 = { architectures: [], externalDependencies: [] };
|
|
8687
|
+
ir.target.sourceType === "huggingface" && (record7.sourceRepository = ir.target.source), ir.target.sourceType === "url" && (record7.artifactUrl = ir.target.source), (ir.target.sourceType === "url" || ir.target.sourceType === "huggingface") && (record7.downloadedFrom = ir.target.source), record7.revision = ir.target.resolvedRevision ?? ir.target.revision, record7.publisher = ir.target.publisher;
|
|
8688
8688
|
for (let file of ir.files) {
|
|
8689
|
-
(/^readme|model[_-]?card/i.test(file.path) || file.role === "documentation") && (
|
|
8689
|
+
(/^readme|model[_-]?card/i.test(file.path) || file.role === "documentation") && (record7.modelCardPath ??= file.path, file.text && (record7.license ??= file.text.match(/^(?:license|model-license)\s*:\s*["']?([^\n"']+)/im)?.[1]?.trim(), record7.sourceRepository ??= file.text.match(/^(?:base_model|base-model|source_model|repository)\s*:\s*["']?([^\n"']+)/im)?.[1]?.trim(), record7.commit ??= file.text.match(/^(?:revision|commit|sha)\s*:\s*["']?([a-f0-9]{7,64})/im)?.[1], record7.publisher ??= file.text.match(/^(?:author|publisher|organization)\s*:\s*["']?([^\n"']+)/im)?.[1]?.trim())), /^license(?:\.|$)|^copying(?:\.|$)/i.test(file.path) && file.text?.trim() && (record7.license ??= "License file present (identifier not parsed)");
|
|
8690
8690
|
for (let [key, value] of flatten(file.json))
|
|
8691
|
-
typeof value == "string" && (/(?:^|\.)model_type$/.test(key) && (
|
|
8691
|
+
typeof value == "string" && (/(?:^|\.)model_type$/.test(key) && (record7.modelType ??= value), /(?:^|\.)transformers_version$/.test(key) && (record7.libraryVersion ??= value), /(?:^|\.)license$/.test(key) && (record7.license ??= value), /(?:^|\.)_name_or_path$/.test(key) && (record7.sourceRepository ??= value), /(?:^|\.)(?:base_model_name_or_path|base_model)$/.test(key) && (record7.sourceRepository ??= value), /(?:^|\.)(?:_?commit_hash|revision|sha)$/.test(key) && (record7.commit ??= value), /(?:^|\.)(?:author|publisher|organization)$/.test(key) && (record7.publisher ??= value));
|
|
8692
8692
|
let architectures = flatten(file.json).filter(([key]) => /(?:^|\.)architectures\[\d+\]$/.test(key)).map(([, value]) => value);
|
|
8693
8693
|
for (let architecture of architectures)
|
|
8694
|
-
typeof architecture == "string" &&
|
|
8694
|
+
typeof architecture == "string" && record7.architectures.push(architecture);
|
|
8695
8695
|
if (/requirements\.txt$|pyproject\.toml$|setup\.py$|environment\.ya?ml$/i.test(file.path) && file.text)
|
|
8696
8696
|
for (let line of file.text.split(/\r?\n/)) {
|
|
8697
8697
|
let dependency = line.trim();
|
|
8698
8698
|
if (!dependency || dependency.startsWith("#"))
|
|
8699
8699
|
continue;
|
|
8700
8700
|
let name = dependency.match(/^([A-Za-z0-9._-]+)/)?.[1];
|
|
8701
|
-
name &&
|
|
8701
|
+
name && record7.externalDependencies.push(dependency.length > 80 ? name : dependency);
|
|
8702
8702
|
}
|
|
8703
8703
|
}
|
|
8704
|
-
return
|
|
8704
|
+
return record7.architectures = [...new Set(record7.architectures)], record7.externalDependencies = [...new Set(record7.externalDependencies)], record7.commit ??= record7.revision && IMMUTABLE_REVISION.test(record7.revision) ? record7.revision : void 0, record7;
|
|
8705
8705
|
}
|
|
8706
8706
|
function recordCheck(id, title, intent, read, missing) {
|
|
8707
8707
|
return {
|
|
@@ -8731,13 +8731,13 @@ function recordCheck(id, title, intent, read, missing) {
|
|
|
8731
8731
|
};
|
|
8732
8732
|
}
|
|
8733
8733
|
var PROVENANCE_RULES = [
|
|
8734
|
-
recordCheck("provenance.source-repository", "Source repository", "The artifact records the repository it was published from.", (
|
|
8734
|
+
recordCheck("provenance.source-repository", "Source repository", "The artifact records the repository it was published from.", (record7) => record7.sourceRepository, {
|
|
8735
8735
|
severity: "medium",
|
|
8736
8736
|
description: "Nothing in the artifact identifies the repository it came from.",
|
|
8737
8737
|
impact: "The artifact cannot be traced back to reviewed source, and a substitution would go unnoticed.",
|
|
8738
8738
|
remediation: "Record the publishing repository in the model card and configuration, and scan by Hugging Face repository or URL so the source is captured automatically."
|
|
8739
8739
|
}),
|
|
8740
|
-
recordCheck("provenance.artifact-url", "Artifact URL", "The location the artifact was retrieved from is recorded.", (
|
|
8740
|
+
recordCheck("provenance.artifact-url", "Artifact URL", "The location the artifact was retrieved from is recorded.", (record7) => record7.artifactUrl ?? record7.downloadedFrom, {
|
|
8741
8741
|
severity: "low",
|
|
8742
8742
|
description: "No retrieval URL was recorded for this artifact.",
|
|
8743
8743
|
impact: "Re-fetching the exact bytes later depends on undocumented tribal knowledge.",
|
|
@@ -8776,7 +8776,7 @@ var PROVENANCE_RULES = [
|
|
|
8776
8776
|
derivedFrom: "Git object naming and model-hub revision semantics",
|
|
8777
8777
|
verification: "source-metadata",
|
|
8778
8778
|
run(ctx) {
|
|
8779
|
-
let
|
|
8779
|
+
let record7 = readProvenance(ctx.ir), revision = record7.commit ?? record7.revision;
|
|
8780
8780
|
if (revision && IMMUTABLE_REVISION.test(revision)) {
|
|
8781
8781
|
ctx.clean(`Pinned to immutable revision ${revision.slice(0, 12)}\u2026`);
|
|
8782
8782
|
return;
|
|
@@ -8801,7 +8801,7 @@ var PROVENANCE_RULES = [
|
|
|
8801
8801
|
derivedFrom: "Git ref semantics; mutable tags and branches are not content-addressed",
|
|
8802
8802
|
verification: "source-metadata",
|
|
8803
8803
|
run(ctx) {
|
|
8804
|
-
let floating = [],
|
|
8804
|
+
let floating = [], record7 = readProvenance(ctx.ir), targetRevision = ctx.ir.target.revision;
|
|
8805
8805
|
ctx.ir.target.revisionIsFloating === !0 && targetRevision ? floating.push({ where: "scan target", value: targetRevision }) : targetRevision && !IMMUTABLE_REVISION.test(targetRevision) && floating.push({ where: "scan target", value: targetRevision });
|
|
8806
8806
|
for (let file of ctx.ir.files)
|
|
8807
8807
|
for (let [key, value] of flatten(file.json))
|
|
@@ -8820,26 +8820,26 @@ var PROVENANCE_RULES = [
|
|
|
8820
8820
|
});
|
|
8821
8821
|
if (floating.length)
|
|
8822
8822
|
return;
|
|
8823
|
-
if (!(!!targetRevision || !!
|
|
8823
|
+
if (!(!!targetRevision || !!record7.commit || !!record7.revision || ctx.ir.files.some((file) => [...flatten(file.json)].some(([key, value]) => typeof value == "string" && /(?:^|\.)(?:revision|base_model_revision|adapter_revision|ref|branch|tag)$/i.test(key))))) {
|
|
8824
8824
|
ctx.notApplicable("NOT MEASURED \u2014 the artifact declares no repository revision, branch or tag, and none was supplied to the scan. There is nothing to judge as floating or immutable; this is absent provenance, not a verified property.");
|
|
8825
8825
|
return;
|
|
8826
8826
|
}
|
|
8827
8827
|
ctx.clean("Every revision reference in the artifact was an immutable identifier.");
|
|
8828
8828
|
}
|
|
8829
8829
|
},
|
|
8830
|
-
recordCheck("provenance.commit-captured", "Repository commit", "The upstream repository commit is captured with the artifact.", (
|
|
8830
|
+
recordCheck("provenance.commit-captured", "Repository commit", "The upstream repository commit is captured with the artifact.", (record7) => record7.commit, {
|
|
8831
8831
|
severity: "medium",
|
|
8832
8832
|
description: "No repository commit was recorded alongside the artifact.",
|
|
8833
8833
|
impact: "The artifact cannot be reproducibly rebuilt from, or diffed against, reviewed source.",
|
|
8834
8834
|
remediation: "Emit the build commit into the model card and configuration as part of the publishing pipeline."
|
|
8835
8835
|
}),
|
|
8836
|
-
recordCheck("provenance.license-declared", "Model license", "A model license is declared.", (
|
|
8836
|
+
recordCheck("provenance.license-declared", "Model license", "A model license is declared.", (record7) => record7.license, {
|
|
8837
8837
|
severity: "medium",
|
|
8838
8838
|
description: "No model license was discovered in configuration, model card or a license file.",
|
|
8839
8839
|
impact: "Use, redistribution, fine-tuning and commercial deployment rights are undetermined.",
|
|
8840
8840
|
remediation: "Attach an SPDX-identifiable model license and have counsel review its obligations before deployment."
|
|
8841
8841
|
}),
|
|
8842
|
-
recordCheck("provenance.publisher-metadata", "Publisher metadata", "An author or publishing organization is recorded.", (
|
|
8842
|
+
recordCheck("provenance.publisher-metadata", "Publisher metadata", "An author or publishing organization is recorded.", (record7) => record7.publisher, {
|
|
8843
8843
|
severity: "low",
|
|
8844
8844
|
description: "No author or publishing organization was recorded for the artifact.",
|
|
8845
8845
|
impact: "There is no accountable owner recorded for security questions or advisories.",
|
|
@@ -8884,7 +8884,7 @@ var PROVENANCE_RULES = [
|
|
|
8884
8884
|
derivedFrom: "Python packaging manifest formats",
|
|
8885
8885
|
verification: "static-text-inspection",
|
|
8886
8886
|
run(ctx) {
|
|
8887
|
-
let
|
|
8887
|
+
let record7 = readProvenance(ctx.ir), manifests = ctx.ir.files.filter((file) => /requirements\.txt$|pyproject\.toml$|setup\.py$|environment\.ya?ml$/i.test(file.path));
|
|
8888
8888
|
if (!manifests.length) {
|
|
8889
8889
|
ctx.report({
|
|
8890
8890
|
title: "No dependency manifest accompanies the model",
|
|
@@ -8897,7 +8897,7 @@ var PROVENANCE_RULES = [
|
|
|
8897
8897
|
});
|
|
8898
8898
|
return;
|
|
8899
8899
|
}
|
|
8900
|
-
ctx.clean(`${
|
|
8900
|
+
ctx.clean(`${record7.externalDependencies.length} declared dependenc${record7.externalDependencies.length === 1 ? "y" : "ies"} across ${manifests.length} manifest(s).`);
|
|
8901
8901
|
}
|
|
8902
8902
|
},
|
|
8903
8903
|
{
|
|
@@ -8972,7 +8972,7 @@ var PROVENANCE_RULES = [
|
|
|
8972
8972
|
});
|
|
8973
8973
|
}
|
|
8974
8974
|
},
|
|
8975
|
-
recordCheck("provenance.model-card-source", "Model card", "A model card documents origin, intended use and limitations.", (
|
|
8975
|
+
recordCheck("provenance.model-card-source", "Model card", "A model card documents origin, intended use and limitations.", (record7) => record7.modelCardPath, {
|
|
8976
8976
|
severity: "medium",
|
|
8977
8977
|
description: "The artifact has no discoverable README or model card.",
|
|
8978
8978
|
impact: "Reviewers cannot establish intended use, training data, limitations or safety evaluation from the artifact itself.",
|
|
@@ -10909,11 +10909,11 @@ function sanitizeAssertions(raw) {
|
|
|
10909
10909
|
for (let item of raw) {
|
|
10910
10910
|
if (!item || typeof item != "object")
|
|
10911
10911
|
continue;
|
|
10912
|
-
let
|
|
10912
|
+
let record7 = item, op = record7.op;
|
|
10913
10913
|
if (typeof op != "string" || !ASSERT_OPS.has(op))
|
|
10914
10914
|
continue;
|
|
10915
|
-
let path = typeof
|
|
10916
|
-
if (!(needsValue &&
|
|
10915
|
+
let path = typeof record7.path == "string" ? record7.path : "", needsValue = op !== "exists" && op !== "not-exists";
|
|
10916
|
+
if (!(needsValue && record7.value === void 0) && (out.push({ path, op, ...needsValue ? { value: record7.value } : {} }), out.length >= 10))
|
|
10917
10917
|
break;
|
|
10918
10918
|
}
|
|
10919
10919
|
return out;
|
|
@@ -10940,22 +10940,22 @@ function parseGeneratedPromptCases(text6, ctx = {}) {
|
|
|
10940
10940
|
for (let raw of parsed) {
|
|
10941
10941
|
if (!raw || typeof raw != "object")
|
|
10942
10942
|
continue;
|
|
10943
|
-
let
|
|
10943
|
+
let record7 = raw, prompt = typeof record7.prompt == "string" ? record7.prompt.trim() : "";
|
|
10944
10944
|
if (!prompt || !isPromptLike(prompt))
|
|
10945
10945
|
continue;
|
|
10946
|
-
let type = typeof
|
|
10946
|
+
let type = typeof record7.type == "string" && CASE_TYPES.has(record7.type) ? record7.type : "positive", expectedTool = typeof record7.expectedTool == "string" ? record7.expectedTool.trim() : "", forbiddenTools = textList(record7.forbiddenTools).filter((t) => known ? known.has(t) : !0);
|
|
10947
10947
|
if (cases.push({
|
|
10948
10948
|
id: `${prefix}-${cases.length + 1}`,
|
|
10949
|
-
name: (typeof
|
|
10949
|
+
name: (typeof record7.name == "string" && record7.name.trim() ? record7.name.trim() : `${type} case`).slice(0, 120),
|
|
10950
10950
|
source: { kind: "ai-generated", serverId: ctx.serverId, toolName: ctx.toolName },
|
|
10951
10951
|
type,
|
|
10952
10952
|
prompt: prompt.slice(0, 8e3),
|
|
10953
|
-
expectedBehavior: typeof
|
|
10953
|
+
expectedBehavior: typeof record7.expectedBehavior == "string" && record7.expectedBehavior.trim() ? record7.expectedBehavior.trim().slice(0, 500) : void 0,
|
|
10954
10954
|
// Never let the generator invent a tool the connected server doesn't advertise.
|
|
10955
10955
|
expectedTool: expectedTool && (!known || known.has(expectedTool)) ? expectedTool : void 0,
|
|
10956
10956
|
forbiddenTools: forbiddenTools.length ? forbiddenTools : void 0,
|
|
10957
|
-
assertions: sanitizeAssertions(
|
|
10958
|
-
tags: textList(
|
|
10957
|
+
assertions: sanitizeAssertions(record7.assertions),
|
|
10958
|
+
tags: textList(record7.tags, 6)
|
|
10959
10959
|
}), cases.length >= max)
|
|
10960
10960
|
break;
|
|
10961
10961
|
}
|
|
@@ -11167,6 +11167,122 @@ async function relaySammyInferenceBoundary(options) {
|
|
|
11167
11167
|
}
|
|
11168
11168
|
}
|
|
11169
11169
|
|
|
11170
|
+
// ../server/dist/hostedSammySuiteHandoff.js
|
|
11171
|
+
import { createHash as createHash15, randomUUID as randomUUID7 } from "node:crypto";
|
|
11172
|
+
import { existsSync as existsSync2, linkSync, mkdirSync as mkdirSync2, readFileSync as readFileSync3, unlinkSync, writeFileSync } from "node:fs";
|
|
11173
|
+
import { join as join4, resolve as resolve5 } from "node:path";
|
|
11174
|
+
var GENERATION_ID = /^sammy-[a-f0-9]{12}$/, STATIC_FINGERPRINT = /^static-suite-fp-[a-f0-9]{12}$/, PROFILE_TARGET_FINGERPRINT = /^target-fp-[a-f0-9]{12}$/, GOVERNED_TARGET_FINGERPRINT = /^target-fp-[a-f0-9]{32}$/, CAPABILITY_FINGERPRINT = /^cap-fp-[a-f0-9]{32}$/, LINEAGE_KEYS = /* @__PURE__ */ new Set([
|
|
11175
|
+
"generationId",
|
|
11176
|
+
"generationStrategy",
|
|
11177
|
+
"registryVersion",
|
|
11178
|
+
"generatorModelAlias",
|
|
11179
|
+
"reviewerModelAlias",
|
|
11180
|
+
"graphVersion",
|
|
11181
|
+
"promptBundleVersion",
|
|
11182
|
+
"datasetVersionRefs",
|
|
11183
|
+
"generatorModelRef",
|
|
11184
|
+
"reviewerModelRef"
|
|
11185
|
+
]);
|
|
11186
|
+
function record6(value) {
|
|
11187
|
+
return !!value && typeof value == "object" && !Array.isArray(value);
|
|
11188
|
+
}
|
|
11189
|
+
function validateArtifact(value, generationId) {
|
|
11190
|
+
if (!record6(value) || !Object.keys(value).every((key) => ["format", "suite", "lineage", "fingerprint"].includes(key)))
|
|
11191
|
+
throw new Error("Hosted Sammy returned an invalid static Suite artifact envelope.");
|
|
11192
|
+
if (value.format !== "prooflane-static-assurance-suite-v1" || typeof value.fingerprint != "string" || !STATIC_FINGERPRINT.test(value.fingerprint))
|
|
11193
|
+
throw new Error("Hosted Sammy returned an unsupported static Suite artifact.");
|
|
11194
|
+
if (!record6(value.lineage) || !Object.keys(value.lineage).every((key) => LINEAGE_KEYS.has(key)) || value.lineage.generationId !== generationId)
|
|
11195
|
+
throw new Error("Hosted Sammy artifact lineage does not match the approved generation.");
|
|
11196
|
+
let suite = validateLegacyLocalSuite(value.suite);
|
|
11197
|
+
if (suite.status !== "APPROVED" || !suite.approvedAt)
|
|
11198
|
+
throw new Error("Only an approved Sammy Suite can enter governed authoring.");
|
|
11199
|
+
let expectedFingerprint = `static-suite-fp-${createHash15("sha256").update(canonicalizeSuiteJson({ suiteFingerprint: suite.suiteFingerprint, lineage: value.lineage }), "utf8").digest("hex").slice(0, 12)}`;
|
|
11200
|
+
if (value.fingerprint !== expectedFingerprint)
|
|
11201
|
+
throw new Error("Hosted Sammy static Suite artifact fingerprint verification failed.");
|
|
11202
|
+
return { format: value.format, suite, lineage: value.lineage, fingerprint: value.fingerprint };
|
|
11203
|
+
}
|
|
11204
|
+
function validateCapabilities(value) {
|
|
11205
|
+
if (value.length > 1e3)
|
|
11206
|
+
throw new Error("The governed capability surface is too large.");
|
|
11207
|
+
let ids = /* @__PURE__ */ new Set();
|
|
11208
|
+
return value.map((entry) => {
|
|
11209
|
+
if (!entry || typeof entry.id != "string" || entry.id.length < 1 || entry.id.length > 128 || !/^[A-Za-z0-9][A-Za-z0-9_.:/-]{0,127}$/.test(entry.id) || typeof entry.fingerprint != "string" || !CAPABILITY_FINGERPRINT.test(entry.fingerprint) || ids.has(entry.id))
|
|
11210
|
+
throw new Error("The governed capability surface is invalid.");
|
|
11211
|
+
return ids.add(entry.id), { id: entry.id, fingerprint: entry.fingerprint };
|
|
11212
|
+
}).sort((left, right) => left.id.localeCompare(right.id));
|
|
11213
|
+
}
|
|
11214
|
+
function approvedTestContentFingerprint(tests) {
|
|
11215
|
+
let content = tests.map((test) => {
|
|
11216
|
+
let { createdAt: _createdAt, ...rest } = test, intelligence = test.intelligence ? (({ generationId: _generationId, suiteId: _suiteId, suiteVersion: _suiteVersion, reviewStatus: _reviewStatus, reviewedAt: _reviewedAt, reviewedBy: _reviewedBy, ...authored }) => authored)(test.intelligence) : void 0, rag = test.rag ? {
|
|
11217
|
+
...test.rag,
|
|
11218
|
+
intelligence: test.rag.intelligence ? (({ generationId: _generationId, suiteId: _suiteId, suiteVersion: _suiteVersion, nativeTestRef: _nativeTestRef, ...trusted }) => trusted)(test.rag.intelligence) : null
|
|
11219
|
+
} : null;
|
|
11220
|
+
return { ...rest, tags: [...test.tags].sort(), intelligence: intelligence ?? null, rag };
|
|
11221
|
+
}).sort((left, right) => left.id.localeCompare(right.id));
|
|
11222
|
+
return `suite-fp-${createHash15("sha256").update(canonicalizeSuiteJson({ format: "prooflane-assurance-suite-v1", content }), "utf8").digest("hex").slice(0, 12)}`;
|
|
11223
|
+
}
|
|
11224
|
+
function runtimeSuiteId(sourceId, generationId) {
|
|
11225
|
+
let sourceSlug = localSuiteSlug(sourceId), suffix = generationId.slice(6);
|
|
11226
|
+
return `${sourceSlug.slice(0, 48)}-${suffix}`;
|
|
11227
|
+
}
|
|
11228
|
+
function localFingerprint(suite) {
|
|
11229
|
+
return `sha256:${createHash15("sha256").update(canonicalizeSuiteJson(suite), "utf8").digest("hex")}`;
|
|
11230
|
+
}
|
|
11231
|
+
function materializeHostedSammySuite(input) {
|
|
11232
|
+
if (!GENERATION_ID.test(input.generationId))
|
|
11233
|
+
throw new Error("Hosted Sammy generation id is invalid.");
|
|
11234
|
+
if (!input.expectedTarget.trim() || input.expectedTarget.length > 256 || !PROFILE_TARGET_FINGERPRINT.test(input.expectedProfileTargetFingerprint) || !GOVERNED_TARGET_FINGERPRINT.test(input.governedTargetFingerprint))
|
|
11235
|
+
throw new Error("The current hosted capability surface is invalid.");
|
|
11236
|
+
let artifact = validateArtifact(input.artifact, input.generationId);
|
|
11237
|
+
if (artifact.suite.suiteFingerprint !== approvedTestContentFingerprint(artifact.suite.tests))
|
|
11238
|
+
throw new Error("Hosted Sammy approved Suite content fingerprint verification failed.");
|
|
11239
|
+
if (artifact.suite.target !== input.expectedTarget || artifact.suite.targetFingerprint !== input.expectedProfileTargetFingerprint)
|
|
11240
|
+
throw new Error("The connected MCP target changed after Sammy approval. Generate and approve a fresh plan.");
|
|
11241
|
+
let requiredCapabilities = validateCapabilities(input.requiredCapabilities), id = runtimeSuiteId(artifact.suite.id, input.generationId), suite = validateLegacyLocalSuite({
|
|
11242
|
+
...artifact.suite,
|
|
11243
|
+
id,
|
|
11244
|
+
targetFingerprint: input.governedTargetFingerprint
|
|
11245
|
+
}), expectedLocalFingerprint = localFingerprint(suite), slug = localSuiteSlug(suite.id), directory = resolve5(input.cwd ?? process.cwd(), ".prooflane", "suites"), fileName = `${slug}-v${suite.version}.json`, file = join4(directory, fileName), bytes = `${JSON.stringify(suite, null, 2)}
|
|
11246
|
+
`, created = !1;
|
|
11247
|
+
if (mkdirSync2(directory, { recursive: !0, mode: 448 }), existsSync2(file)) {
|
|
11248
|
+
if (readLegacyLocalSuiteArtifact(file, input.cwd ?? process.cwd()).localFingerprint !== expectedLocalFingerprint)
|
|
11249
|
+
throw new Error(`A different local Suite already occupies ${fileName}; Prooflane will not overwrite it.`);
|
|
11250
|
+
} else {
|
|
11251
|
+
let temporary = join4(directory, `.${fileName}.${process.pid}.${randomUUID7()}.tmp`);
|
|
11252
|
+
try {
|
|
11253
|
+
writeFileSync(temporary, bytes, { encoding: "utf8", flag: "wx", mode: 384 });
|
|
11254
|
+
try {
|
|
11255
|
+
linkSync(temporary, file), created = !0;
|
|
11256
|
+
} catch (error) {
|
|
11257
|
+
if (!existsSync2(file))
|
|
11258
|
+
throw error;
|
|
11259
|
+
if (readLegacyLocalSuiteArtifact(file, input.cwd ?? process.cwd()).localFingerprint !== expectedLocalFingerprint)
|
|
11260
|
+
throw new Error(`A different local Suite already occupies ${fileName}; Prooflane will not overwrite it.`);
|
|
11261
|
+
}
|
|
11262
|
+
} finally {
|
|
11263
|
+
existsSync2(temporary) && unlinkSync(temporary);
|
|
11264
|
+
}
|
|
11265
|
+
}
|
|
11266
|
+
let stored = readLegacyLocalSuiteArtifact(file, input.cwd ?? process.cwd());
|
|
11267
|
+
if (stored.localFingerprint !== expectedLocalFingerprint || stored.slug !== slug || stored.suite.status !== "APPROVED")
|
|
11268
|
+
throw new Error("The materialized Sammy Suite failed local integrity verification.");
|
|
11269
|
+
if (readFileSync3(file).byteLength > 8 * 1024 * 1024)
|
|
11270
|
+
throw new Error("The materialized Sammy Suite exceeds the local artifact limit.");
|
|
11271
|
+
return {
|
|
11272
|
+
version: "prooflane-hosted-sammy-materialization-v1",
|
|
11273
|
+
generationId: input.generationId,
|
|
11274
|
+
sourceArtifactFingerprint: artifact.fingerprint,
|
|
11275
|
+
sourceTargetFingerprint: artifact.suite.targetFingerprint,
|
|
11276
|
+
governedTargetFingerprint: input.governedTargetFingerprint,
|
|
11277
|
+
requiredCapabilities,
|
|
11278
|
+
slug,
|
|
11279
|
+
localFingerprint: stored.localFingerprint,
|
|
11280
|
+
localVersion: stored.suite.version,
|
|
11281
|
+
fileName,
|
|
11282
|
+
created
|
|
11283
|
+
};
|
|
11284
|
+
}
|
|
11285
|
+
|
|
11170
11286
|
// ../server/dist/plans.js
|
|
11171
11287
|
var UNLIMITED = 1e6, PLANS = {
|
|
11172
11288
|
free: { tier: "free", label: "Free \xB7 Inspector", servers: 1, tools: 5, attacks: 0, retrievers: 0, prompts: 10, maxVus: 10, deployment: !1, historyDays: 7, ci: !1, ruleFeed: "static", core: !0, hosted: !1, security: !1, rag: !1, gates: !1 },
|
|
@@ -11218,7 +11334,7 @@ function describeToolError(output) {
|
|
|
11218
11334
|
})();
|
|
11219
11335
|
return text6.length > 500 ? `${text6.slice(0, 500)}\u2026` : text6 || "the tool reported an error";
|
|
11220
11336
|
}
|
|
11221
|
-
var sha256 = (value) =>
|
|
11337
|
+
var sha256 = (value) => createHash16("sha256").update(typeof value == "string" ? value : JSON.stringify(value)).digest("hex"), hostedRagCaseQuery = (testCase) => (testCase.userQuery ?? "").trim() || testCase.query, hostedRagCaseName = (testCase) => (testCase.name ?? "").trim() || hostedRagCaseQuery(testCase) || testCase.id, hostedRagCaseInput = (testCase) => testCase.input ?? { query: hostedRagCaseQuery(testCase) }, clampRagScore = (value) => Math.max(0, Math.min(100, Math.round(Number.isFinite(value) ? value : 0))), averageRagScore = (values) => values.length ? Math.round(values.reduce((sum, value) => sum + value, 0) / values.length) : 100;
|
|
11222
11338
|
function extractHostedRagPayload(output) {
|
|
11223
11339
|
let value = output;
|
|
11224
11340
|
if (Array.isArray(value) && value.length && value.every((block) => block && typeof block == "object" && "type" in block)) {
|
|
@@ -11492,10 +11608,10 @@ function resultCount3(value) {
|
|
|
11492
11608
|
if (Array.isArray(value))
|
|
11493
11609
|
return value.length;
|
|
11494
11610
|
if (value && typeof value == "object") {
|
|
11495
|
-
let
|
|
11611
|
+
let record7 = value;
|
|
11496
11612
|
for (let key of ["results", "items", "documents", "matches", "content"])
|
|
11497
|
-
if (Array.isArray(
|
|
11498
|
-
return
|
|
11613
|
+
if (Array.isArray(record7[key]))
|
|
11614
|
+
return record7[key].length;
|
|
11499
11615
|
return 1;
|
|
11500
11616
|
}
|
|
11501
11617
|
return value == null || value === "" ? 0 : 1;
|
|
@@ -11624,8 +11740,8 @@ function publicServerError(path) {
|
|
|
11624
11740
|
}
|
|
11625
11741
|
var HOSTED_SAMMY_AUTHORIZATION = Symbol("prooflane.hosted-sammy-authorization");
|
|
11626
11742
|
function buildApp() {
|
|
11627
|
-
let
|
|
11628
|
-
|
|
11743
|
+
let app = Fastify({ logger: !1 });
|
|
11744
|
+
app.addHook("onSend", async (request, reply, payload) => !request.url.startsWith("/api") || reply.statusCode < 500 ? payload : (reply.header("cache-control", "no-store"), reply.type("application/json; charset=utf-8"), JSON.stringify({ error: publicServerError(request.url), reference: request.id })));
|
|
11629
11745
|
let store = new Store(dbPath()), svc = new InspectorService(store), mcpManager = new McpConnectionManager(() => new InspectorService(store), store), env = (process.env.KAWACH_ENV ?? process.env.NODE_ENV ?? "production").toLowerCase(), isDev = env === "dev" || env === "development", intelligenceMode = PUBLIC_RUNNER_BUILD || process.env.KAWACH_INTELLIGENCE_MODE === "hosted" ? "hosted" : "legacy", AUTH0_DOMAIN = process.env.AUTH0_DOMAIN, AUTH0_CLIENT_ID = process.env.AUTH0_CLIENT_ID, AUTH0_AUDIENCE = process.env.AUTH0_AUDIENCE, CONTROL_PLANE_URL = process.env.KAWACH_CONTROL_PLANE_URL?.replace(/\/$/, ""), PROOFLANE_PROJECT = (process.env.PROOFLANE_PROJECT ?? "default").trim(), configuredNumber = (name, fallback, minimum, maximum) => {
|
|
11630
11746
|
let value = Number(process.env[name]);
|
|
11631
11747
|
return Number.isFinite(value) ? Math.max(minimum, Math.min(maximum, value)) : fallback;
|
|
@@ -11651,10 +11767,10 @@ function buildApp() {
|
|
|
11651
11767
|
targetTokenCeiling: Math.trunc(configuredNumber("PROOFLANE_BENCHMARK_PAID_TARGET_TOKENS", DEFAULT_BENCHMARK_PRICING_POLICY.products.PAID_SINGLE_RUN.targetTokenCeiling, 1e3, 2e7))
|
|
11652
11768
|
}
|
|
11653
11769
|
}
|
|
11654
|
-
}, localLifecycleKey =
|
|
11770
|
+
}, localLifecycleKey = randomUUID8(), activeMcpAuthMode = "unknown", activeMcpConnectionId = null, oauthFlows = /* @__PURE__ */ new Map(), assuranceGateManifest = process.env.PROOFLANE_ASSURANCE_GATES_FILE ?? resolve6(".prooflane/assurance-gates.json"), assurancePolicyRegistry = process.env.PROOFLANE_ASSURANCE_POLICIES_FILE ?? join5(dirname4(assuranceGateManifest), "assurance-policies.json"), readAssurancePolicies = async () => {
|
|
11655
11771
|
let intel = await loadLegacyIntelligence(), stored = [];
|
|
11656
|
-
if (
|
|
11657
|
-
let document = JSON.parse(
|
|
11772
|
+
if (existsSync3(assurancePolicyRegistry)) {
|
|
11773
|
+
let document = JSON.parse(readFileSync4(assurancePolicyRegistry, "utf8"));
|
|
11658
11774
|
if (document.version !== "prooflane-assurance-policy-registry-v1" || !Array.isArray(document.policies))
|
|
11659
11775
|
throw new Error("Assurance Policy registry must use prooflane-assurance-policy-registry-v1.");
|
|
11660
11776
|
stored = document.policies;
|
|
@@ -11662,7 +11778,7 @@ function buildApp() {
|
|
|
11662
11778
|
let policies = stored.map((policy) => intel.validateAssurancePolicyVersion(policy));
|
|
11663
11779
|
return policies.some((policy) => policy.id === intel.DEFAULT_ASSURANCE_POLICY.id) || policies.unshift(structuredClone(intel.DEFAULT_ASSURANCE_POLICY)), policies.sort((a, b) => b.createdAt.localeCompare(a.createdAt) || b.version - a.version || a.id.localeCompare(b.id));
|
|
11664
11780
|
}, writeAssurancePolicies = (policies) => {
|
|
11665
|
-
|
|
11781
|
+
mkdirSync3(dirname4(assurancePolicyRegistry), { recursive: !0 }), writeFileSync2(assurancePolicyRegistry, JSON.stringify({ version: "prooflane-assurance-policy-registry-v1", policies }, null, 2) + `
|
|
11666
11782
|
`, "utf8");
|
|
11667
11783
|
}, hostedSammyInference = async (request, task, context) => {
|
|
11668
11784
|
let authorization = request[HOSTED_SAMMY_AUTHORIZATION], relayRequest = buildHostedSammyRelayRequest({
|
|
@@ -11725,10 +11841,19 @@ function buildApp() {
|
|
|
11725
11841
|
method,
|
|
11726
11842
|
headers: body === void 0 ? { authorization } : { authorization, "content-type": "application/json" },
|
|
11727
11843
|
body: body === void 0 ? void 0 : JSON.stringify(body)
|
|
11728
|
-
}), text6 = await response.text(), payload =
|
|
11729
|
-
|
|
11730
|
-
|
|
11731
|
-
|
|
11844
|
+
}), text6 = await response.text(), payload = null;
|
|
11845
|
+
if (text6)
|
|
11846
|
+
try {
|
|
11847
|
+
payload = JSON.parse(text6);
|
|
11848
|
+
} catch {
|
|
11849
|
+
if (response.ok)
|
|
11850
|
+
return reply.code(502).send({ error: "Prooflane Cloud Workspace returned an invalid response." });
|
|
11851
|
+
payload = response.status === 404 ? { error: "The deployed Prooflane control plane does not support this Inspector route yet. Deploy the matching control-plane build, then retry.", upgrade: !0 } : { error: `Prooflane Cloud request failed (${response.status}).` };
|
|
11852
|
+
}
|
|
11853
|
+
let upstreamError = payload && typeof payload == "object" && typeof payload.error == "string" ? String(payload.error).trim() : "";
|
|
11854
|
+
return !response.ok && response.status === 404 && (!upstreamError || /^not found$/i.test(upstreamError) || /route.*not found/i.test(upstreamError)) && (payload = { error: "The deployed Prooflane control plane does not support this Inspector route yet. Deploy the matching control-plane build, then retry.", upgrade: !0 }), response.ok && await onSuccess?.(payload), reply.code(response.status).send(payload);
|
|
11855
|
+
} catch (error) {
|
|
11856
|
+
return error instanceof SyntaxError ? reply.code(502).send({ error: "Prooflane Cloud Workspace returned an invalid response." }) : reply.code(502).send({ error: "Prooflane Cloud Workspace could not be reached. Check KAWACH_CONTROL_PLANE_URL and your connection." });
|
|
11732
11857
|
}
|
|
11733
11858
|
}
|
|
11734
11859
|
async function requestControlPlaneJson(req, path, method = "GET", body, idempotencyKey) {
|
|
@@ -11745,9 +11870,19 @@ function buildApp() {
|
|
|
11745
11870
|
} catch {
|
|
11746
11871
|
throw new ControlPlaneRequestError(502, "Prooflane Cloud Workspace could not be reached.");
|
|
11747
11872
|
}
|
|
11748
|
-
let text6 = await response.text(), payload
|
|
11749
|
-
|
|
11750
|
-
|
|
11873
|
+
let text6 = await response.text(), payload;
|
|
11874
|
+
try {
|
|
11875
|
+
payload = text6 ? JSON.parse(text6) : {};
|
|
11876
|
+
} catch {
|
|
11877
|
+
if (response.ok)
|
|
11878
|
+
throw new ControlPlaneRequestError(502, "Prooflane Cloud Workspace returned an invalid response.");
|
|
11879
|
+
let message2 = response.status === 404 ? "The deployed Prooflane control plane does not support this Inspector route yet. Deploy the matching control-plane build, then retry." : `Prooflane Cloud request failed (${response.status}).`;
|
|
11880
|
+
throw new ControlPlaneRequestError(response.status, message2);
|
|
11881
|
+
}
|
|
11882
|
+
if (!response.ok) {
|
|
11883
|
+
let upstreamError = typeof payload.error == "string" ? String(payload.error).trim().slice(0, 300) : "", message2 = response.status === 404 && (!upstreamError || /^not found$/i.test(upstreamError) || /route.*not found/i.test(upstreamError)) ? "The deployed Prooflane control plane does not support this Inspector route yet. Deploy the matching control-plane build, then retry." : upstreamError || "Prooflane Cloud request failed.";
|
|
11884
|
+
throw new ControlPlaneRequestError(response.status, message2);
|
|
11885
|
+
}
|
|
11751
11886
|
return payload;
|
|
11752
11887
|
}
|
|
11753
11888
|
async function cloudPlan(req) {
|
|
@@ -11792,7 +11927,7 @@ function buildApp() {
|
|
|
11792
11927
|
async function resolvePlan(req) {
|
|
11793
11928
|
return (await resolvePlanState(req)).plan;
|
|
11794
11929
|
}
|
|
11795
|
-
|
|
11930
|
+
app.addHook("preHandler", async (req, reply) => {
|
|
11796
11931
|
if (req.method === "GET" || req.method === "HEAD" || req.method === "OPTIONS")
|
|
11797
11932
|
return;
|
|
11798
11933
|
let path = req.url.split("?", 1)[0] ?? req.url;
|
|
@@ -11838,17 +11973,54 @@ function buildApp() {
|
|
|
11838
11973
|
let p = await resolvePlan(req);
|
|
11839
11974
|
return { core: p.core, security: p.security, rag: p.rag, deployment: p.deployment, ci: p.ci };
|
|
11840
11975
|
}
|
|
11841
|
-
|
|
11842
|
-
if (intelligenceMode === "hosted" && (/^\/api\/intelligence\/(?:
|
|
11843
|
-
return reply.code(410).send({
|
|
11976
|
+
if (app.addHook("onRequest", async (req, reply) => {
|
|
11977
|
+
if (intelligenceMode === "hosted" && (/^\/api\/intelligence\/(?:effectiveness|learning-candidates)(?:\/|\?|$)/.test(req.url) || /^\/api\/(?:assurance|boundary)(?:\/|\?|$)/.test(req.url)) && req.raw.method !== "OPTIONS")
|
|
11978
|
+
return /^\/api\/assurance\/gates(?:\/|\?|$)/.test(req.url) && reply.header("cache-control", "no-store"), reply.code(410).send({
|
|
11844
11979
|
ok: !1,
|
|
11845
11980
|
error: "This feature uses Hosted Intelligence and is unavailable through the retired local route."
|
|
11846
11981
|
});
|
|
11847
11982
|
let plan = await resolvePlan(req);
|
|
11848
11983
|
mcpManager.reconcileEntitlement(PROOFLANE_PROJECT, mcpEntitlementForPlan(plan)), svc.setToolLimit(plan.tools), mcpManager.setToolLimit(PROOFLANE_PROJECT, plan.tools), activeMcpConnectionId && mcpManager.getConnection(PROOFLANE_PROJECT, activeMcpConnectionId)?.status === "ENTITLEMENT_LOCKED" && svc.setToolLimit(0);
|
|
11849
|
-
}),
|
|
11984
|
+
}), intelligenceMode === "hosted") {
|
|
11985
|
+
let hostedSurfaceRefreshInFlight = null, relayHostedIntelligenceSurface = async (req, reply, refresh) => {
|
|
11986
|
+
try {
|
|
11987
|
+
refresh && svc.isConnected() && (hostedSurfaceRefreshInFlight ??= svc.refreshCapabilities().finally(() => {
|
|
11988
|
+
hostedSurfaceRefreshInFlight = null;
|
|
11989
|
+
}), await hostedSurfaceRefreshInFlight);
|
|
11990
|
+
let capabilities = svc.getCapabilities();
|
|
11991
|
+
return capabilities ? proxyControlPlane(req, reply, "/v1/intelligence/surface", { capabilities }) : { connected: !1 };
|
|
11992
|
+
} catch (error) {
|
|
11993
|
+
return reply.code(503).send({ error: `MCP discovery refresh failed: ${error instanceof Error ? error.message : String(error)}` });
|
|
11994
|
+
}
|
|
11995
|
+
};
|
|
11996
|
+
app.get("/api/intelligence/surface", async (req, reply) => (reply.header("cache-control", "no-store"), relayHostedIntelligenceSurface(req, reply, !1))), app.post("/api/intelligence/surface/refresh", async (req, reply) => relayHostedIntelligenceSurface(req, reply, !0));
|
|
11997
|
+
let hostedSammyPath = `/v1/projects/${encodeURIComponent(PROOFLANE_PROJECT)}/intelligence`, hostedCapabilities = (reply) => {
|
|
11998
|
+
let capabilities = svc.getCapabilities();
|
|
11999
|
+
return capabilities || (reply.code(409).send({ error: "Connect an MCP target before using Sammy Intelligence." }), null);
|
|
12000
|
+
}, selectedBody = (value, keys) => {
|
|
12001
|
+
if (!value || typeof value != "object" || Array.isArray(value))
|
|
12002
|
+
return {};
|
|
12003
|
+
let source = value;
|
|
12004
|
+
return Object.fromEntries(keys.filter((key) => source[key] !== void 0).map((key) => [key, source[key]]));
|
|
12005
|
+
};
|
|
12006
|
+
app.post("/api/intelligence/analyze-options", async (req, reply) => {
|
|
12007
|
+
let capabilities = hostedCapabilities(reply);
|
|
12008
|
+
if (capabilities)
|
|
12009
|
+
return proxyControlPlane(req, reply, `${hostedSammyPath}/analyze-options`, { ...selectedBody(req.body, ["graphVersion"]), capabilities });
|
|
12010
|
+
}), app.post("/api/intelligence/generations", async (req, reply) => {
|
|
12011
|
+
let capabilities = hostedCapabilities(reply);
|
|
12012
|
+
if (capabilities)
|
|
12013
|
+
return proxyControlPlane(req, reply, `${hostedSammyPath}/generations`, { ...selectedBody(req.body, ["idempotencyKey", "strategy", "sammyEnabled", "selectedRecommendationIds", "datasetVersionRefs", "promptBundleVersion"]), capabilities });
|
|
12014
|
+
}), app.get("/api/intelligence/generations/:id", async (req, reply) => proxyControlPlane(req, reply, `${hostedSammyPath}/generations/${encodeURIComponent(req.params.id)}`, void 0, "GET")), app.post("/api/intelligence/generations/:id/review", async (req, reply) => proxyControlPlane(req, reply, `${hostedSammyPath}/generations/${encodeURIComponent(req.params.id)}/review`, {})), app.post("/api/intelligence/generations/:id/approve", async (req, reply) => {
|
|
12015
|
+
let capabilities = hostedCapabilities(reply);
|
|
12016
|
+
if (capabilities)
|
|
12017
|
+
return proxyControlPlane(req, reply, `${hostedSammyPath}/generations/${encodeURIComponent(req.params.id)}/approve`, { ...selectedBody(req.body, ["gateId", "name", "policyVersion"]), capabilities });
|
|
12018
|
+
}), app.post("/api/intelligence/generations/:id/compile-suite", async (req, reply) => proxyControlPlane(req, reply, `${hostedSammyPath}/generations/${encodeURIComponent(req.params.id)}/compile-suite`, {})), app.get("/api/intelligence/usage", async (req, reply) => proxyControlPlane(req, reply, `${hostedSammyPath}/usage`, void 0, "GET")), app.get("/api/intelligence/datasets", async (req, reply) => proxyControlPlane(req, reply, `${hostedSammyPath}/datasets`, void 0, "GET")), app.post("/api/intelligence/datasets", async (req, reply) => proxyControlPlane(req, reply, `${hostedSammyPath}/datasets`, selectedBody(req.body, ["name", "format", "content"]))), app.get("/api/intelligence/native-artifacts", async (req, reply) => proxyControlPlane(req, reply, `${hostedSammyPath}/native-artifacts${req.query.pillar ? `?pillar=${encodeURIComponent(req.query.pillar)}` : ""}`, void 0, "GET")), app.post("/api/intelligence/native-artifacts/:generationId/:testId/review", async (req, reply) => proxyControlPlane(req, reply, `${hostedSammyPath}/native-artifacts/${encodeURIComponent(req.params.generationId)}/${encodeURIComponent(req.params.testId)}/review`, selectedBody(req.body, ["action", "replacement", "trustedGolden"]))), app.post("/api/annotations", async (req, reply) => proxyControlPlane(req, reply, `${hostedSammyPath}/annotations`, selectedBody(req.body, ["targetType", "targetId", "labels", "text", "resolution"]))), app.get("/api/annotations/context", async (req, reply) => proxyControlPlane(req, reply, `${hostedSammyPath}/annotations${req.query.targetId ? `?targetId=${encodeURIComponent(req.query.targetId)}` : ""}`, void 0, "GET"));
|
|
12019
|
+
}
|
|
12020
|
+
app.addHook("onSend", async (_req, reply) => {
|
|
11850
12021
|
reply.header("x-content-type-options", "nosniff"), reply.header("x-frame-options", "SAMEORIGIN"), reply.header("referrer-policy", "no-referrer"), reply.header("x-permitted-cross-domain-policies", "none");
|
|
11851
|
-
}),
|
|
12022
|
+
}), app.get("/api/config", async (req, reply) => {
|
|
12023
|
+
reply.header("cache-control", "no-store");
|
|
11852
12024
|
let resolution = await resolvePlanState(req), plan = resolution.plan;
|
|
11853
12025
|
return {
|
|
11854
12026
|
env: isDev ? "dev" : "production",
|
|
@@ -11898,9 +12070,9 @@ function buildApp() {
|
|
|
11898
12070
|
project: { id: PROOFLANE_PROJECT },
|
|
11899
12071
|
intelligenceMode
|
|
11900
12072
|
};
|
|
11901
|
-
}),
|
|
12073
|
+
}), app.post("/api/workspace/consent", async (req, reply) => proxyControlPlane(req, reply, "/v1/workspace/consent", req.body ?? {})), app.post("/api/ci/token", async (req, reply) => proxyControlPlane(req, reply, "/v1/ci/token", { projectId: PROOFLANE_PROJECT }));
|
|
11902
12074
|
let githubOidcTrustPath = `/v1/projects/${encodeURIComponent(PROOFLANE_PROJECT)}/github-oidc-trust`;
|
|
11903
|
-
|
|
12075
|
+
app.get("/api/governance/github-oidc-trust", async (req, reply) => proxyControlPlane(req, reply, githubOidcTrustPath, void 0, "GET")), app.put("/api/governance/github-oidc-trust", async (req, reply) => proxyControlPlane(req, reply, githubOidcTrustPath, req.body ?? {}, "PUT")), app.delete("/api/governance/github-oidc-trust", async (req, reply) => proxyControlPlane(req, reply, githubOidcTrustPath, void 0, "DELETE")), app.post("/api/trial/start", async (req, reply) => proxyControlPlane(req, reply, "/v1/trial/start", {})), app.get("/api/workspace/status", async (req, reply) => proxyControlPlane(req, reply, "/v1/workspace", void 0, "GET")), app.get("/api/gate-runs", async (req, reply) => proxyControlPlane(req, reply, `/v1/gate-runs?limit=${encodeURIComponent(req.query.limit ?? "200")}`, void 0, "GET")), app.post("/api/gate-runs", async (req, reply) => proxyControlPlane(req, reply, "/v1/gate-runs", req.body ?? {})), app.get("/api/governed-runs", async (req, reply) => proxyControlPlane(req, reply, `/v1/projects/${encodeURIComponent(PROOFLANE_PROJECT)}/runs?limit=${encodeURIComponent(req.query.limit ?? "50")}`, void 0, "GET")), app.post("/api/intelligence/infer", async (req, reply) => {
|
|
11904
12076
|
let result = await relaySammyInferenceBoundary({
|
|
11905
12077
|
request: req.body,
|
|
11906
12078
|
controlPlaneUrl: CONTROL_PLANE_URL,
|
|
@@ -11910,7 +12082,7 @@ function buildApp() {
|
|
|
11910
12082
|
return reply.code(result.status).send(result.payload);
|
|
11911
12083
|
});
|
|
11912
12084
|
let suiteRegistryPath = `/v1/projects/${encodeURIComponent(PROOFLANE_PROJECT)}/suites`;
|
|
11913
|
-
|
|
12085
|
+
app.get("/api/suites", async (req, reply) => proxyControlPlane(req, reply, suiteRegistryPath, void 0, "GET")), app.post("/api/suites", async (req, reply) => proxyControlPlane(req, reply, suiteRegistryPath, req.body ?? {})), app.post("/api/governance/suites/:slug/drift", async (req, reply) => {
|
|
11914
12086
|
try {
|
|
11915
12087
|
let capabilities = svc.getCapabilities();
|
|
11916
12088
|
if (!capabilities)
|
|
@@ -11939,7 +12111,7 @@ function buildApp() {
|
|
|
11939
12111
|
} catch (error) {
|
|
11940
12112
|
return error instanceof ControlPlaneRequestError ? reply.code(error.status).send({ error: error.message }) : reply.code(500).send({ error: "Governed surface drift assessment could not complete." });
|
|
11941
12113
|
}
|
|
11942
|
-
}),
|
|
12114
|
+
}), app.get("/api/suites/:slug", async (req, reply) => proxyControlPlane(req, reply, `${suiteRegistryPath}/${encodeURIComponent(req.params.slug)}`, void 0, "GET")), app.patch("/api/suites/:slug", async (req, reply) => proxyControlPlane(req, reply, `${suiteRegistryPath}/${encodeURIComponent(req.params.slug)}`, req.body ?? {}, "PATCH")), app.delete("/api/suites/:slug", async (req, reply) => proxyControlPlane(req, reply, `${suiteRegistryPath}/${encodeURIComponent(req.params.slug)}`, void 0, "DELETE")), app.post("/api/suites/:slug/versions", async (req, reply) => proxyControlPlane(req, reply, `${suiteRegistryPath}/${encodeURIComponent(req.params.slug)}/versions`, req.body ?? {})), app.get("/api/suites/:slug/versions/:version", async (req, reply) => proxyControlPlane(req, reply, `${suiteRegistryPath}/${encodeURIComponent(req.params.slug)}/versions/${encodeURIComponent(req.params.version)}`, void 0, "GET")), app.put("/api/suites/:slug/versions/:version", async (req, reply) => proxyControlPlane(req, reply, `${suiteRegistryPath}/${encodeURIComponent(req.params.slug)}/versions/${encodeURIComponent(req.params.version)}`, req.body ?? {}, "PUT")), app.post("/api/suites/:slug/versions/:version/review", async (req, reply) => proxyControlPlane(req, reply, `${suiteRegistryPath}/${encodeURIComponent(req.params.slug)}/versions/${encodeURIComponent(req.params.version)}/review`, {})), app.post("/api/suites/:slug/versions/:version/approve", async (req, reply) => proxyControlPlane(req, reply, `${suiteRegistryPath}/${encodeURIComponent(req.params.slug)}/versions/${encodeURIComponent(req.params.version)}/approve`, {})), app.post("/api/suites/:slug/versions/:version/deprecate", async (req, reply) => proxyControlPlane(req, reply, `${suiteRegistryPath}/${encodeURIComponent(req.params.slug)}/versions/${encodeURIComponent(req.params.version)}/deprecate`, {})), app.get("/api/suites/:slug/aliases", async (req, reply) => proxyControlPlane(req, reply, `${suiteRegistryPath}/${encodeURIComponent(req.params.slug)}/aliases`, void 0, "GET")), app.get("/api/suite-signing-keys/:keyId", async (req, reply) => proxyControlPlane(req, reply, `/v1/projects/${encodeURIComponent(PROOFLANE_PROJECT)}/suite-signing-keys/${encodeURIComponent(req.params.keyId)}`, void 0, "GET"));
|
|
11943
12115
|
let localMigrationInspection = async (req) => {
|
|
11944
12116
|
let cloudResponse = await requestControlPlaneJson(req, suiteRegistryPath);
|
|
11945
12117
|
if (cloudResponse.projectId !== PROOFLANE_PROJECT || !Array.isArray(cloudResponse.suites))
|
|
@@ -11955,14 +12127,14 @@ function buildApp() {
|
|
|
11955
12127
|
let scan = discoverLegacyLocalSuites({ cwd: process.cwd() }), plan = planLegacyLocalSuiteMigration(scan.suites, cloud), suites = plan.map(safeLocalSuiteMigrationSummary);
|
|
11956
12128
|
return { plan, response: { version: "prooflane-local-suite-migration-status-v1", projectId: PROOFLANE_PROJECT, suites, issues: scan.issues, pending: suites.filter((suite) => suite.action === "CREATE_SUITE_DRAFT" || suite.action === "CREATE_VERSION_DRAFT").length, conflicts: scan.issues.length + suites.filter((suite) => suite.action === "CONFLICT").length } };
|
|
11957
12129
|
};
|
|
11958
|
-
|
|
12130
|
+
app.get("/api/suite-migration/status", async (req, reply) => {
|
|
11959
12131
|
try {
|
|
11960
12132
|
return (await localMigrationInspection(req)).response;
|
|
11961
12133
|
} catch (error) {
|
|
11962
12134
|
let status = error instanceof ControlPlaneRequestError ? error.status : 400;
|
|
11963
12135
|
return reply.code(status).send({ error: (error instanceof Error ? error.message : "Local Suite migration status failed.").slice(0, 300) });
|
|
11964
12136
|
}
|
|
11965
|
-
}),
|
|
12137
|
+
}), app.post("/api/suite-migration/sync", async (req, reply) => {
|
|
11966
12138
|
try {
|
|
11967
12139
|
if (!req.body || typeof req.body != "object" || Array.isArray(req.body))
|
|
11968
12140
|
return reply.code(400).send({ error: "Migration sync request must be an object." });
|
|
@@ -12009,17 +12181,47 @@ ${item.artifact.localFingerprint}`));
|
|
|
12009
12181
|
let status = error instanceof ControlPlaneRequestError ? error.status : 400;
|
|
12010
12182
|
return reply.code(status).send({ error: (error instanceof Error ? error.message : "Local Suite migration failed.").slice(0, 300) });
|
|
12011
12183
|
}
|
|
12184
|
+
}), app.post("/api/intelligence/generations/:id/materialize-suite", async (req, reply) => {
|
|
12185
|
+
if (intelligenceMode !== "hosted")
|
|
12186
|
+
return reply.code(409).send({ error: "Hosted Sammy Suite materialization is available only in hosted Intelligence mode." });
|
|
12187
|
+
if (!req.body || typeof req.body != "object" || Array.isArray(req.body) || Object.keys(req.body).length !== 0)
|
|
12188
|
+
return reply.code(400).send({ error: "Hosted Sammy Suite materialization accepts an empty body only." });
|
|
12189
|
+
if (!/^sammy-[a-f0-9]{12}$/.test(req.params.id))
|
|
12190
|
+
return reply.code(400).send({ error: "Hosted Sammy generation id is invalid." });
|
|
12191
|
+
let capabilities = svc.getCapabilities();
|
|
12192
|
+
if (!capabilities)
|
|
12193
|
+
return reply.code(409).send({ error: "Connect the same MCP target before preparing the governed Suite." });
|
|
12194
|
+
try {
|
|
12195
|
+
let surface = await requestControlPlaneJson(req, "/v1/intelligence/surface", "POST", { capabilities }), governedTargetFingerprint = fingerprintServerCapabilities(capabilities), governedCapabilities = fingerprintServerCapabilitySurface(capabilities);
|
|
12196
|
+
if (surface.connected !== !0 || typeof surface.target != "string" || typeof surface.fingerprint != "string" || surface.governedTargetFingerprint !== governedTargetFingerprint || JSON.stringify(surface.governedCapabilities) !== JSON.stringify(governedCapabilities))
|
|
12197
|
+
throw new Error("Hosted capability analysis did not preserve the current governed target identity.");
|
|
12198
|
+
let compiled = await requestControlPlaneJson(req, `/v1/projects/${encodeURIComponent(PROOFLANE_PROJECT)}/intelligence/generations/${encodeURIComponent(req.params.id)}/compile-suite`, "POST", {});
|
|
12199
|
+
if (!compiled.artifact)
|
|
12200
|
+
throw new Error("Hosted Sammy did not return an approved static Suite artifact.");
|
|
12201
|
+
return { materialized: materializeHostedSammySuite({
|
|
12202
|
+
artifact: compiled.artifact,
|
|
12203
|
+
generationId: req.params.id,
|
|
12204
|
+
expectedTarget: surface.target,
|
|
12205
|
+
expectedProfileTargetFingerprint: surface.fingerprint,
|
|
12206
|
+
governedTargetFingerprint,
|
|
12207
|
+
requiredCapabilities: governedCapabilities,
|
|
12208
|
+
cwd: process.cwd()
|
|
12209
|
+
}) };
|
|
12210
|
+
} catch (error) {
|
|
12211
|
+
let status = error instanceof ControlPlaneRequestError ? error.status : 409;
|
|
12212
|
+
return reply.code(status).send({ error: (error instanceof Error ? error.message : "The hosted Sammy Suite could not be prepared.").slice(0, 300) });
|
|
12213
|
+
}
|
|
12012
12214
|
});
|
|
12013
12215
|
let gateRegistryPath = `/v1/projects/${encodeURIComponent(PROOFLANE_PROJECT)}/gates`;
|
|
12014
|
-
|
|
12216
|
+
app.get("/api/governance/gates", async (req, reply) => proxyControlPlane(req, reply, gateRegistryPath, void 0, "GET")), app.post("/api/governance/gates", async (req, reply) => proxyControlPlane(req, reply, gateRegistryPath, req.body ?? {})), app.get("/api/governance/gates/:slug", async (req, reply) => proxyControlPlane(req, reply, `${gateRegistryPath}/${encodeURIComponent(req.params.slug)}`, void 0, "GET")), app.post("/api/governance/gates/:slug/versions", async (req, reply) => proxyControlPlane(req, reply, `${gateRegistryPath}/${encodeURIComponent(req.params.slug)}/versions`, req.body ?? {})), app.get("/api/governance/gates/:slug/versions/:version", async (req, reply) => proxyControlPlane(req, reply, `${gateRegistryPath}/${encodeURIComponent(req.params.slug)}/versions/${encodeURIComponent(req.params.version)}`, void 0, "GET")), app.put("/api/governance/gates/:slug/versions/:version", async (req, reply) => proxyControlPlane(req, reply, `${gateRegistryPath}/${encodeURIComponent(req.params.slug)}/versions/${encodeURIComponent(req.params.version)}`, req.body ?? {}, "PUT"));
|
|
12015
12217
|
for (let transition of ["review", "approve", "deprecate"])
|
|
12016
|
-
|
|
12017
|
-
|
|
12218
|
+
app.post(`/api/governance/gates/:slug/versions/:version/${transition}`, async (req, reply) => proxyControlPlane(req, reply, `${gateRegistryPath}/${encodeURIComponent(req.params.slug)}/versions/${encodeURIComponent(req.params.version)}/${transition}`, {}));
|
|
12219
|
+
app.get("/api/governance/gates/:slug/aliases", async (req, reply) => proxyControlPlane(req, reply, `${gateRegistryPath}/${encodeURIComponent(req.params.slug)}/aliases`, void 0, "GET")), app.get("/api/governance/gates/:slug/audit", async (req, reply) => proxyControlPlane(req, reply, `${gateRegistryPath}/${encodeURIComponent(req.params.slug)}/audit?limit=${encodeURIComponent(req.query.limit ?? "50")}`, void 0, "GET")), app.get("/api/governance/gates/:slug/resolve", async (req, reply) => proxyControlPlane(req, reply, `${gateRegistryPath}/${encodeURIComponent(req.params.slug)}/resolve`, void 0, "GET")), app.get("/api/governance/gate-signing-keys/:keyId", async (req, reply) => proxyControlPlane(req, reply, `/v1/projects/${encodeURIComponent(PROOFLANE_PROJECT)}/gate-signing-keys/${encodeURIComponent(req.params.keyId)}`, void 0, "GET"));
|
|
12018
12220
|
let learningRegistryPath = `/v1/projects/${encodeURIComponent(PROOFLANE_PROJECT)}/learning`, learningMutationAuthorized = (req, reply) => typeof req.headers.authorization == "string" && req.headers.authorization.startsWith("Bearer ") ? !0 : (reply.code(401).send({ error: "Sign in to your Prooflane account first." }), !1);
|
|
12019
|
-
|
|
12221
|
+
app.get("/api/governance/learning/runs/:runId/findings", async (req, reply) => proxyControlPlane(req, reply, `/v1/projects/${encodeURIComponent(PROOFLANE_PROJECT)}/runs/${encodeURIComponent(req.params.runId)}/learning-findings`, void 0, "GET")), app.get("/api/governance/learning/runs/:runId/disposition", async (req, reply) => proxyControlPlane(req, reply, `/v1/projects/${encodeURIComponent(PROOFLANE_PROJECT)}/runs/${encodeURIComponent(req.params.runId)}/learning-disposition`, void 0, "GET")), app.put("/api/governance/learning/runs/:runId/disposition", async (req, reply) => {
|
|
12020
12222
|
if (learningMutationAuthorized(req, reply))
|
|
12021
12223
|
return !isApproveLearningDispositionRequest(req.body) || findSensitiveMaterial(req.body) ? reply.code(400).send({ error: "Expected a compact prooflane-learning-disposition-request-v1 envelope." }) : proxyControlPlane(req, reply, `/v1/projects/${encodeURIComponent(PROOFLANE_PROJECT)}/runs/${encodeURIComponent(req.params.runId)}/learning-disposition`, req.body, "PUT");
|
|
12022
|
-
}),
|
|
12224
|
+
}), app.get("/api/governance/learning/generations", async (req, reply) => proxyControlPlane(req, reply, `${learningRegistryPath}/generations?limit=${encodeURIComponent(req.query.limit ?? "50")}`, void 0, "GET")), app.post("/api/governance/learning/generations", async (req, reply) => {
|
|
12023
12225
|
if (!learningMutationAuthorized(req, reply))
|
|
12024
12226
|
return;
|
|
12025
12227
|
if (!isCreateLearningGenerationRequest(req.body))
|
|
@@ -12033,15 +12235,15 @@ ${item.artifact.localFingerprint}`));
|
|
|
12033
12235
|
let status = error instanceof ControlPlaneRequestError ? error.status : 502;
|
|
12034
12236
|
return reply.code(status).send({ error: error instanceof Error ? error.message : "Governed learning generation failed." });
|
|
12035
12237
|
}
|
|
12036
|
-
}),
|
|
12238
|
+
}), app.get("/api/governance/learning/tests", async (req, reply) => proxyControlPlane(req, reply, `${learningRegistryPath}/tests?limit=${encodeURIComponent(req.query.limit ?? "100")}`, void 0, "GET"));
|
|
12037
12239
|
for (let transition of ["review", "approve"])
|
|
12038
|
-
|
|
12240
|
+
app.post(`/api/governance/learning/tests/:testId/${transition}`, async (req, reply) => {
|
|
12039
12241
|
if (learningMutationAuthorized(req, reply))
|
|
12040
12242
|
return !req.body || typeof req.body != "object" || Array.isArray(req.body) || Object.keys(req.body).length !== 0 ? reply.code(400).send({ error: "Learning lifecycle transitions accept an empty body only." }) : proxyControlPlane(req, reply, `${learningRegistryPath}/tests/${encodeURIComponent(req.params.testId)}/${transition}`, {});
|
|
12041
12243
|
});
|
|
12042
|
-
|
|
12244
|
+
app.get("/api/governance/learning/audit", async (req, reply) => proxyControlPlane(req, reply, `${learningRegistryPath}/audit?limit=${encodeURIComponent(req.query.limit ?? "100")}`, void 0, "GET"));
|
|
12043
12245
|
let runnerRegistryPath = `/v1/projects/${encodeURIComponent(PROOFLANE_PROJECT)}/runners`;
|
|
12044
|
-
|
|
12246
|
+
app.get("/api/governance/runners", async (req, reply) => proxyControlPlane(req, reply, runnerRegistryPath, void 0, "GET")), app.post("/api/governance/runners/:runnerId/revoke", async (req, reply) => proxyControlPlane(req, reply, `${runnerRegistryPath}/${encodeURIComponent(req.params.runnerId)}/revoke`, {})), app.post("/api/governance/gates/:slug/remote-runs", async (req, reply) => proxyControlPlane(req, reply, `${gateRegistryPath}/${encodeURIComponent(req.params.slug)}/remote-runs`, req.body ?? {})), app.get("/api/governance/runner-jobs/:jobId", async (req, reply) => proxyControlPlane(req, reply, `/v1/projects/${encodeURIComponent(PROOFLANE_PROJECT)}/runner-jobs/${encodeURIComponent(req.params.jobId)}`, void 0, "GET")), app.post("/api/governance/runner-jobs/:jobId/cancel", async (req, reply) => proxyControlPlane(req, reply, `/v1/projects/${encodeURIComponent(PROOFLANE_PROJECT)}/runner-jobs/${encodeURIComponent(req.params.jobId)}/cancel`, {})), app.post("/api/governance/gates/:slug/runs", async (req, reply) => {
|
|
12045
12247
|
let projectPath = `/v1/projects/${encodeURIComponent(PROOFLANE_PROJECT)}`, run, startedAt = (/* @__PURE__ */ new Date()).toISOString(), startedMs = Date.now();
|
|
12046
12248
|
try {
|
|
12047
12249
|
let resolutionPayload = await requestControlPlaneJson(req, `${gateRegistryPath}/${encodeURIComponent(req.params.slug)}/resolve`), object = (value) => !!value && typeof value == "object" && !Array.isArray(value);
|
|
@@ -12073,8 +12275,8 @@ ${item.artifact.localFingerprint}`));
|
|
|
12073
12275
|
throw new Error("Gate required pillars are not represented by the signed Suite.");
|
|
12074
12276
|
if (!svc.isConnected())
|
|
12075
12277
|
throw new Error("Connect the local MCP target before running this Gate.");
|
|
12076
|
-
let runnerId = `local_ui_${
|
|
12077
|
-
${PROOFLANE_PROJECT}`, "utf8").digest("hex").slice(0, 24)}`, idempotencyKey = `localui:${
|
|
12278
|
+
let runnerId = `local_ui_${createHash16("sha256").update(`${kawachHome()}
|
|
12279
|
+
${PROOFLANE_PROJECT}`, "utf8").digest("hex").slice(0, 24)}`, idempotencyKey = `localui:${randomUUID8().replaceAll("-", "")}`, gatePin = { gateId: gate.id, slug: gate.slug, gateVersionId: gateVersion.id, version: gateVersion.version, manifestHash: gateVersion.manifestHash }, suitePin = { suiteId: suite.id, slug: suite.slug, suiteVersionId: suiteVersion.id, version: suiteVersion.version, manifestHash: suiteVersion.manifestHash }, policyPin = { policyId: policy.id, policyVersionId: policyVersion.id, version: policyVersion.version, manifestHash: policyVersion.manifestHash }, runner = { runnerId, type: "LOCAL_UI", runnerVersion: "0.1.0", cliVersion: "ui-0.1.0" }, governedRunMatches = (candidate, targetFingerprint) => {
|
|
12078
12280
|
if (!object(candidate) || !object(candidate.gate) || !object(candidate.suite) || !object(candidate.policy) || !object(candidate.runner))
|
|
12079
12281
|
return !1;
|
|
12080
12282
|
let value = candidate;
|
|
@@ -12151,7 +12353,7 @@ ${PROOFLANE_PROJECT}`, "utf8").digest("hex").slice(0, 24)}`, idempotencyKey = `l
|
|
|
12151
12353
|
}
|
|
12152
12354
|
});
|
|
12153
12355
|
let policyRegistryPath = `/v1/projects/${encodeURIComponent(PROOFLANE_PROJECT)}/policies`;
|
|
12154
|
-
|
|
12356
|
+
app.get("/api/policies", async (req, reply) => proxyControlPlane(req, reply, policyRegistryPath, void 0, "GET")), app.post("/api/policies", async (req, reply) => proxyControlPlane(req, reply, policyRegistryPath, req.body ?? {})), app.get("/api/policies/:policyId", async (req, reply) => proxyControlPlane(req, reply, `${policyRegistryPath}/${encodeURIComponent(req.params.policyId)}`, void 0, "GET")), app.post("/api/policies/:policyId/versions", async (req, reply) => proxyControlPlane(req, reply, `${policyRegistryPath}/${encodeURIComponent(req.params.policyId)}/versions`, req.body ?? {})), app.put("/api/policies/:policyId/versions/:version", async (req, reply) => proxyControlPlane(req, reply, `${policyRegistryPath}/${encodeURIComponent(req.params.policyId)}/versions/${encodeURIComponent(req.params.version)}`, req.body ?? {}, "PUT")), app.post("/api/policies/:policyId/versions/:version/review", async (req, reply) => proxyControlPlane(req, reply, `${policyRegistryPath}/${encodeURIComponent(req.params.policyId)}/versions/${encodeURIComponent(req.params.version)}/review`, {})), app.post("/api/policies/:policyId/versions/:version/approve", async (req, reply) => proxyControlPlane(req, reply, `${policyRegistryPath}/${encodeURIComponent(req.params.policyId)}/versions/${encodeURIComponent(req.params.version)}/approve`, {})), app.post("/api/policies/:policyId/versions/:version/deprecate", async (req, reply) => proxyControlPlane(req, reply, `${policyRegistryPath}/${encodeURIComponent(req.params.policyId)}/versions/${encodeURIComponent(req.params.version)}/deprecate`, {})), app.post("/api/assure/target-snapshot", async (req, reply) => proxyControlPlane(req, reply, "/v1/assure/target-snapshot", req.body ?? {})), app.get("/api/assure/target-snapshot", async (req, reply) => proxyControlPlane(req, reply, "/v1/assure/target-snapshot", void 0, "GET")), app.post("/api/workspace/backup-preference", async (req, reply) => proxyControlPlane(req, reply, "/v1/workspace/backup-preference", req.body ?? {})), app.post("/api/workspace/backup", async (req, reply) => {
|
|
12155
12357
|
let snapshots = svc.listSnapshots().map(({ id, createdAt, kind, origin, snapshot }) => ({ id, createdAt, kind, origin, snapshot })), backup = {
|
|
12156
12358
|
version: "workspace-backup-v1",
|
|
12157
12359
|
capturedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -12167,7 +12369,7 @@ ${PROOFLANE_PROJECT}`, "utf8").digest("hex").slice(0, 24)}`, idempotencyKey = `l
|
|
|
12167
12369
|
let capturedAt = payload && typeof payload == "object" && typeof payload.capturedAt == "string" ? payload.capturedAt : backup.capturedAt;
|
|
12168
12370
|
svc.markCloudWorkspaceBackedUp(capturedAt);
|
|
12169
12371
|
});
|
|
12170
|
-
}),
|
|
12372
|
+
}), app.get("/api/workspace/backup/latest", async (req, reply) => proxyControlPlane(req, reply, `/v1/workspace/backup/latest${req.query?.restorable ? "?restorable=1" : ""}`, void 0, "GET")), app.get("/api/workspace/backup/versions", async (req, reply) => proxyControlPlane(req, reply, `/v1/workspace/backup/versions${req.query?.limit ? `?limit=${encodeURIComponent(req.query.limit)}` : ""}`, void 0, "GET")), app.post("/api/workspace/restore", async (req, reply) => {
|
|
12171
12373
|
if (!CONTROL_PLANE_URL)
|
|
12172
12374
|
return reply.code(503).send({ error: "Prooflane Cloud Workspace is not configured for this Inspector." });
|
|
12173
12375
|
let authorization = req.headers.authorization;
|
|
@@ -12186,20 +12388,20 @@ ${PROOFLANE_PROJECT}`, "utf8").digest("hex").slice(0, 24)}`, idempotencyKey = `l
|
|
|
12186
12388
|
return reply.code(404).send({ ok: !1, error: "No cloud backup was found to restore." });
|
|
12187
12389
|
let restored = svc.restoreFromBackup(backup.value), capturedAt = backup.value.capturedAt ?? backup.createdAt;
|
|
12188
12390
|
return svc.markCloudWorkspaceBackedUp(capturedAt), reply.send({ ok: !0, restored, capturedAt, backupId: backup.id });
|
|
12189
|
-
}),
|
|
12391
|
+
}), app.post("/api/workspace/local/lifecycle", async (req, reply) => {
|
|
12190
12392
|
if (req.headers["x-kawach-local-lifecycle"] !== localLifecycleKey)
|
|
12191
12393
|
return reply.code(403).send({ error: "Invalid local workspace lifecycle request." });
|
|
12192
12394
|
let subject = typeof req.body?.subject == "string" ? req.body.subject.slice(0, 320) : void 0;
|
|
12193
12395
|
await mcpManager.clearWorkspace(PROOFLANE_PROJECT);
|
|
12194
12396
|
let result = await svc.applyLocalWorkspaceLifecycle(subject);
|
|
12195
12397
|
return svc = new InspectorService(store), activeMcpConnectionId = null, activeMcpAuthMode = "unknown", oauthFlows.clear(), { ok: !0, result, reason: req.body?.reason ?? "login" };
|
|
12196
|
-
}),
|
|
12398
|
+
}), app.post("/api/intelligence/leases", async (req, reply) => proxyControlPlane(req, reply, "/v1/intelligence/leases", req.body ?? {})), app.post("/api/intelligence/evidence", async (req, reply) => proxyControlPlane(req, reply, "/v1/intelligence/evidence", req.body ?? {})), app.post("/api/intelligence/evaluations", async (req, reply) => proxyControlPlane(req, reply, "/v1/intelligence/evaluations", req.body ?? {})), app.get("/api/security/catalog", async (req, reply) => proxyControlPlane(req, reply, "/v1/security/catalog", void 0, "GET"));
|
|
12197
12399
|
for (let pillar of ["security", "rag"])
|
|
12198
|
-
|
|
12400
|
+
app.post(`/api/${pillar}/scans`, async (req, reply) => proxyControlPlane(req, reply, "/v1/scans", { pillar, ...req.body ?? {} })), app.get(`/api/${pillar}/scans/:id`, async (req, reply) => proxyControlPlane(req, reply, `/v1/scans/${encodeURIComponent(req.params.id)}`, void 0, "GET")), app.get(`/api/${pillar}/scans/:id/events`, async (req, reply) => {
|
|
12199
12401
|
let after = Math.max(0, Math.trunc(Number(req.query.after)) || 0);
|
|
12200
12402
|
return proxyControlPlane(req, reply, `/v1/scans/${encodeURIComponent(req.params.id)}/events?after=${after}`, void 0, "GET");
|
|
12201
|
-
}),
|
|
12202
|
-
|
|
12403
|
+
}), app.post(`/api/${pillar}/scans/:id/next-task`, async (req, reply) => proxyControlPlane(req, reply, `/v1/scans/${encodeURIComponent(req.params.id)}/next-task`, {})), app.post(`/api/${pillar}/scans/:id/evidence`, async (req, reply) => proxyControlPlane(req, reply, `/v1/scans/${encodeURIComponent(req.params.id)}/evidence`, req.body ?? {})), app.post(`/api/${pillar}/scans/:id/stop`, async (req, reply) => proxyControlPlane(req, reply, `/v1/scans/${encodeURIComponent(req.params.id)}/cancel`, {})), app.post(`/api/${pillar}/scans/:id/retry`, async (req, reply) => proxyControlPlane(req, reply, `/v1/scans/${encodeURIComponent(req.params.id)}/retry`, {}));
|
|
12404
|
+
app.post("/api/benchmark/evidence/generate", async (req, reply) => {
|
|
12203
12405
|
let generator = req.body?.generator, count = Math.min(20, Math.max(1, Math.trunc(req.body?.count ?? 4))), brief = req.body?.brief?.trim();
|
|
12204
12406
|
if (!generator?.model?.trim() || !generator.apiKey?.trim())
|
|
12205
12407
|
return reply.code(400).send({ error: "Configure the evidence-generator model and API key." });
|
|
@@ -12285,7 +12487,7 @@ ${existing.length ? existing.join(`
|
|
|
12285
12487
|
(run?.status === "CANCELLED" || run?.status === "FAILED") && store.releaseBenchmarkEntitlement(workspaceId, entitlement.id, entitlement.reservationKey);
|
|
12286
12488
|
}
|
|
12287
12489
|
};
|
|
12288
|
-
|
|
12490
|
+
app.get("/api/benchmark/entitlements", async () => {
|
|
12289
12491
|
let workspaceId = benchmarkWorkspaceId();
|
|
12290
12492
|
ensureFreeFastBenchmarkEntitlement(), reconcileTerminalBenchmarkReservations(workspaceId);
|
|
12291
12493
|
let entitlements = store.listBenchmarkEntitlements(workspaceId);
|
|
@@ -12297,7 +12499,7 @@ ${existing.length ? existing.join(`
|
|
|
12297
12499
|
pricingPolicy: benchmarkPricingPolicy,
|
|
12298
12500
|
purchase: { verification: "SERVER_REQUIRED", clientPaidFlagsAccepted: !1 }
|
|
12299
12501
|
};
|
|
12300
|
-
}),
|
|
12502
|
+
}), app.post("/api/benchmark/purchases/verify", async (req, reply) => {
|
|
12301
12503
|
let receipt = req.body?.receipt?.trim(), idempotencyKey = req.body?.idempotencyKey?.trim();
|
|
12302
12504
|
return !receipt || receipt.length > 65536 || !idempotencyKey || idempotencyKey.length > 120 ? reply.code(400).send({ error: "A bounded purchase receipt and idempotency key are required." }) : proxyControlPlane(req, reply, "/v1/benchmark/purchases/verify", { ...req.body, receipt, idempotencyKey, projectId: PROOFLANE_PROJECT }, "POST", (payload) => {
|
|
12303
12505
|
let response = payload, entitlement = response?.entitlement;
|
|
@@ -12305,7 +12507,7 @@ ${existing.length ? existing.join(`
|
|
|
12305
12507
|
throw new Error("Prooflane returned an invalid Benchmark purchase entitlement.");
|
|
12306
12508
|
store.saveBenchmarkEntitlement(entitlement);
|
|
12307
12509
|
});
|
|
12308
|
-
}),
|
|
12510
|
+
}), app.post("/api/benchmark/plans", async (req, reply) => {
|
|
12309
12511
|
if (intelligenceMode === "hosted")
|
|
12310
12512
|
return proxyControlPlane(req, reply, "/v1/benchmark/plans", req.body ?? {});
|
|
12311
12513
|
let body = req.body ?? {}, objective = body.objective?.trim(), targetType = body.targetType, mode = body.mode, targets = body.targets;
|
|
@@ -12402,7 +12604,7 @@ ${existing.length ? existing.join(`
|
|
|
12402
12604
|
let message2 = error instanceof Error ? error.message : String(error), status = error instanceof ControlPlaneRequestError ? error.status : /allowance|locked|not enabled/i.test(message2) ? 403 : 502;
|
|
12403
12605
|
return reply.code(status).send({ error: status < 500 ? message2 : publicIntelligenceGenerationError(message2) });
|
|
12404
12606
|
}
|
|
12405
|
-
}),
|
|
12607
|
+
}), app.post("/api/benchmark/run", async (req, reply) => {
|
|
12406
12608
|
let suppliedCandidates = req.body?.candidates, workflowPlan = req.body?.plan, suppliedCases = req.body?.cases;
|
|
12407
12609
|
if (!Array.isArray(suppliedCandidates) || suppliedCandidates.length < 2 || suppliedCandidates.length > 8)
|
|
12408
12610
|
return reply.code(400).send({ error: "Choose between 2 and 8 benchmark candidates." });
|
|
@@ -12614,16 +12816,16 @@ ${existing.length ? existing.join(`
|
|
|
12614
12816
|
} finally {
|
|
12615
12817
|
keys.clear(), prices.clear();
|
|
12616
12818
|
}
|
|
12617
|
-
}),
|
|
12819
|
+
}), app.get("/api/benchmark/history", async (req) => {
|
|
12618
12820
|
let limit = Math.max(1, Math.min(100, Number(req.query.limit) || 25));
|
|
12619
|
-
return { runs: store.listBenchmarkRuns(benchmarkWorkspaceId(), limit).map((
|
|
12620
|
-
}),
|
|
12621
|
-
let
|
|
12622
|
-
return !
|
|
12623
|
-
}),
|
|
12624
|
-
let
|
|
12625
|
-
return !
|
|
12626
|
-
}),
|
|
12821
|
+
return { runs: store.listBenchmarkRuns(benchmarkWorkspaceId(), limit).map((record7) => ({ runId: record7.runId, status: record7.status, planId: record7.plan.planId, planVersion: record7.plan.version, objective: record7.plan.objective, mode: record7.plan.mode, targetType: record7.plan.targetType, summary: record7.summary, createdAt: record7.createdAt, updatedAt: record7.updatedAt })) };
|
|
12822
|
+
}), app.get("/api/benchmark/runs/:id", async (req, reply) => {
|
|
12823
|
+
let record7 = store.getBenchmarkRun(req.params.id);
|
|
12824
|
+
return !record7 || record7.workspaceId !== benchmarkWorkspaceId() ? reply.code(404).send({ error: "Benchmark Run not found." }) : { run: record7 };
|
|
12825
|
+
}), app.get("/api/benchmark/runs/:id/report.html", async (req, reply) => {
|
|
12826
|
+
let record7 = store.getBenchmarkRun(req.params.id);
|
|
12827
|
+
return !record7 || record7.workspaceId !== benchmarkWorkspaceId() || !record7.reportHtml ? reply.code(404).send({ error: "Benchmark HTML report not found." }) : (reply.header("Content-Disposition", `attachment; filename="benchmark-report-${record7.runId}.html"`), reply.type("text/html; charset=utf-8"), record7.reportHtml);
|
|
12828
|
+
}), app.post("/api/intelligence/execute", async (req, reply) => {
|
|
12627
12829
|
if (!req.body?.lease)
|
|
12628
12830
|
return reply.code(400).send({ ok: !1, error: "A hosted Intelligence lease is required." });
|
|
12629
12831
|
let claims;
|
|
@@ -12891,10 +13093,10 @@ ${answer}`
|
|
|
12891
13093
|
severity: scanSeverity ?? (evidence.outcome === "fail" ? "high" : void 0)
|
|
12892
13094
|
} : void 0) ?? evidence, privacy: { rawDataSent: !1, next: "Submit this envelope with the original lease to the hosted Control Plane." } };
|
|
12893
13095
|
});
|
|
12894
|
-
let tagsFile = () =>
|
|
12895
|
-
|
|
13096
|
+
let tagsFile = () => join5(process.cwd(), DEFAULT_TAGS_FILE), readTagsConfig = (file) => parseTagsConfig(existsSync3(file) ? readFileSync4(file, "utf8") : ""), writeTagsConfig = (file, config) => {
|
|
13097
|
+
mkdirSync3(dirname4(file), { recursive: !0 }), writeFileSync2(file, serializeTagsConfig(config));
|
|
12896
13098
|
};
|
|
12897
|
-
|
|
13099
|
+
app.get("/api/tags", async () => ({ ok: !0, path: DEFAULT_TAGS_FILE, config: readTagsConfig(tagsFile()) })), app.post("/api/tags", async (req, reply) => {
|
|
12898
13100
|
let plan = await resolvePlan(req);
|
|
12899
13101
|
if (!plan.gates)
|
|
12900
13102
|
return reply.code(402).send({ ok: !1, upgrade: !0, feature: "gates", tier: plan.tier, error: "CI gates are part of the Scale plan. Upgrade to capture tagged tests for CI." });
|
|
@@ -12903,31 +13105,31 @@ ${answer}`
|
|
|
12903
13105
|
return reply.code(400).send({ ok: !1, error: "A valid tagged test (id, pillar, tags[]) is required." });
|
|
12904
13106
|
let file = tagsFile(), next = upsertTest(readTagsConfig(file), { ...test, createdAt: test.createdAt || (/* @__PURE__ */ new Date()).toISOString() });
|
|
12905
13107
|
return writeTagsConfig(file, next), { ok: !0, path: DEFAULT_TAGS_FILE, config: next };
|
|
12906
|
-
}),
|
|
13108
|
+
}), app.delete("/api/tags/:id", async (req, reply) => {
|
|
12907
13109
|
let plan = await resolvePlan(req);
|
|
12908
13110
|
if (!plan.gates)
|
|
12909
13111
|
return reply.code(402).send({ ok: !1, upgrade: !0, feature: "gates", tier: plan.tier, error: "CI gates are part of the Scale plan." });
|
|
12910
13112
|
let file = tagsFile(), next = removeTest(readTagsConfig(file), req.params.id);
|
|
12911
13113
|
return writeTagsConfig(file, next), { ok: !0, path: DEFAULT_TAGS_FILE, config: next };
|
|
12912
13114
|
});
|
|
12913
|
-
let gatesPath = () =>
|
|
13115
|
+
let gatesPath = () => join5(process.cwd(), ".prooflane/gates.json"), validLegacyRegressionGroup = (value) => {
|
|
12914
13116
|
if (!value || typeof value != "object" || Array.isArray(value))
|
|
12915
13117
|
return !1;
|
|
12916
13118
|
let gate = value;
|
|
12917
13119
|
return typeof gate.id == "string" && /^[a-z0-9][a-z0-9_-]{1,63}$/.test(gate.id) && typeof gate.name == "string" && gate.name.trim().length >= 2 && gate.name.length <= 80 && Array.isArray(gate.tags) && gate.tags.length > 0 && gate.tags.length <= 50 && gate.tags.every((tag2) => typeof tag2 == "string" && /^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,63}$/.test(tag2)) && typeof gate.minScore == "number" && Number.isFinite(gate.minScore) && gate.minScore >= 0 && gate.minScore <= 100 && typeof gate.repeat == "number" && Number.isInteger(gate.repeat) && gate.repeat >= 1 && gate.repeat <= 10 && typeof gate.deterministicOnly == "boolean" && typeof gate.createdAt == "string" && Number.isFinite(Date.parse(gate.createdAt)) && typeof gate.updatedAt == "string" && Number.isFinite(Date.parse(gate.updatedAt));
|
|
12918
13120
|
}, readLegacyRegressionGroups = () => {
|
|
12919
13121
|
try {
|
|
12920
|
-
let parsed = JSON.parse(
|
|
13122
|
+
let parsed = JSON.parse(readFileSync4(gatesPath(), "utf8"));
|
|
12921
13123
|
return parsed.version === "prooflane-gates-v1" && Array.isArray(parsed.gates) ? parsed.gates.filter(validLegacyRegressionGroup) : [];
|
|
12922
13124
|
} catch {
|
|
12923
13125
|
return [];
|
|
12924
13126
|
}
|
|
12925
13127
|
}, writeLegacyRegressionGroups = (gates) => {
|
|
12926
13128
|
let file = gatesPath();
|
|
12927
|
-
|
|
13129
|
+
mkdirSync3(dirname4(file), { recursive: !0 }), writeFileSync2(file, JSON.stringify({ version: "prooflane-gates-v1", gates }, null, 2) + `
|
|
12928
13130
|
`, "utf8");
|
|
12929
13131
|
};
|
|
12930
|
-
|
|
13132
|
+
app.get("/api/gates", async () => ({ ok: !0, path: ".prooflane/gates.json", gates: readLegacyRegressionGroups() })), app.put("/api/gates/:id", async (req, reply) => {
|
|
12931
13133
|
let plan = await resolvePlan(req);
|
|
12932
13134
|
if (!plan.gates)
|
|
12933
13135
|
return reply.code(402).send({ ok: !1, upgrade: !0, feature: "gates", tier: plan.tier, error: "Legacy local regression groups are part of the Scale plan." });
|
|
@@ -12935,7 +13137,7 @@ ${answer}`
|
|
|
12935
13137
|
return reply.code(400).send({ ok: !1, error: "A valid legacy local regression group with at least one tag is required." });
|
|
12936
13138
|
let current = readLegacyRegressionGroups(), existing = current.find((gate2) => gate2.id === req.params.id), gate = { ...req.body.gate, createdAt: existing?.createdAt ?? req.body.gate.createdAt }, next = [...current.filter((item) => item.id !== gate.id), gate].sort((a, b) => a.name.localeCompare(b.name));
|
|
12937
13139
|
return writeLegacyRegressionGroups(next), { ok: !0, path: ".prooflane/gates.json", gate, gates: next };
|
|
12938
|
-
}),
|
|
13140
|
+
}), app.delete("/api/gates/:id", async (req, reply) => {
|
|
12939
13141
|
let plan = await resolvePlan(req);
|
|
12940
13142
|
if (!plan.gates)
|
|
12941
13143
|
return reply.code(402).send({ ok: !1, upgrade: !0, feature: "gates", tier: plan.tier, error: "Legacy local regression groups are part of the Scale plan." });
|
|
@@ -12967,7 +13169,7 @@ ${answer}`
|
|
|
12967
13169
|
throw new Error("Connected MCP runtime was not registered.");
|
|
12968
13170
|
return runtime.setToolLimit?.(plan.tools), svc = runtime, activeMcpConnectionId = result.connection.id, activeMcpAuthMode = authModeFor(connection), result;
|
|
12969
13171
|
}
|
|
12970
|
-
|
|
13172
|
+
app.post("/api/connect", async (req, reply) => {
|
|
12971
13173
|
try {
|
|
12972
13174
|
let disconnected = mcpManager.listConnections(PROOFLANE_PROJECT).filter((connection) => connection.status === "DISCONNECTED");
|
|
12973
13175
|
if (!activeMcpConnectionId && disconnected.length === 1) {
|
|
@@ -12979,21 +13181,21 @@ ${answer}`
|
|
|
12979
13181
|
} catch (error) {
|
|
12980
13182
|
return sendMcpError(reply, error);
|
|
12981
13183
|
}
|
|
12982
|
-
}),
|
|
13184
|
+
}), app.get("/api/mcp/connections", async (req) => {
|
|
12983
13185
|
let entitlement = mcpEntitlementForPlan(await resolvePlan(req)), connections = mcpManager.reconcileEntitlement(PROOFLANE_PROJECT, entitlement);
|
|
12984
13186
|
return {
|
|
12985
13187
|
connections,
|
|
12986
13188
|
entitlement,
|
|
12987
13189
|
usage: { current: connections.length, allowed: entitlement.maxConnections }
|
|
12988
13190
|
};
|
|
12989
|
-
}),
|
|
13191
|
+
}), app.post("/api/mcp/connections", async (req, reply) => {
|
|
12990
13192
|
try {
|
|
12991
13193
|
let result = await connectMcp(req, req.body.connection, req.body.displayName ?? req.body.name);
|
|
12992
13194
|
return reply.code(201).send({ ok: !0, ...result });
|
|
12993
13195
|
} catch (error) {
|
|
12994
13196
|
return sendMcpError(reply, error);
|
|
12995
13197
|
}
|
|
12996
|
-
}),
|
|
13198
|
+
}), app.post("/api/mcp/connections/:id/reconnect", async (req, reply) => {
|
|
12997
13199
|
try {
|
|
12998
13200
|
let plan = await resolvePlan(req);
|
|
12999
13201
|
mcpManager.reconcileEntitlement(PROOFLANE_PROJECT, mcpEntitlementForPlan(plan));
|
|
@@ -13005,7 +13207,7 @@ ${answer}`
|
|
|
13005
13207
|
} catch (error) {
|
|
13006
13208
|
return sendMcpError(reply, error);
|
|
13007
13209
|
}
|
|
13008
|
-
}),
|
|
13210
|
+
}), app.post("/api/mcp/connections/:id/activate", async (req, reply) => {
|
|
13009
13211
|
try {
|
|
13010
13212
|
let plan = await resolvePlan(req);
|
|
13011
13213
|
mcpManager.reconcileEntitlement(PROOFLANE_PROJECT, mcpEntitlementForPlan(plan));
|
|
@@ -13021,32 +13223,32 @@ ${answer}`
|
|
|
13021
13223
|
} catch (error) {
|
|
13022
13224
|
return sendMcpError(reply, error);
|
|
13023
13225
|
}
|
|
13024
|
-
}),
|
|
13226
|
+
}), app.post("/api/mcp/connections/:id/refresh", async (req, reply) => {
|
|
13025
13227
|
try {
|
|
13026
13228
|
let plan = await resolvePlan(req);
|
|
13027
13229
|
return mcpManager.reconcileEntitlement(PROOFLANE_PROJECT, mcpEntitlementForPlan(plan)), { ok: !0, tools: await mcpManager.refreshTools(PROOFLANE_PROJECT, req.params.id, await requestActor(req)), connection: mcpManager.getConnection(PROOFLANE_PROJECT, req.params.id) };
|
|
13028
13230
|
} catch (error) {
|
|
13029
13231
|
return sendMcpError(reply, error);
|
|
13030
13232
|
}
|
|
13031
|
-
}),
|
|
13233
|
+
}), app.post("/api/mcp/connections/:id/disconnect", async (req, reply) => {
|
|
13032
13234
|
try {
|
|
13033
13235
|
return await mcpManager.disconnectConnection(PROOFLANE_PROJECT, req.params.id, await requestActor(req)), activeMcpConnectionId === req.params.id && (activeMcpConnectionId = null, activeMcpAuthMode = "unknown", svc = new InspectorService(store)), { ok: !0 };
|
|
13034
13236
|
} catch (error) {
|
|
13035
13237
|
return sendMcpError(reply, error);
|
|
13036
13238
|
}
|
|
13037
|
-
}),
|
|
13239
|
+
}), app.delete("/api/mcp/connections/:id", async (req, reply) => {
|
|
13038
13240
|
try {
|
|
13039
13241
|
return await mcpManager.removeConnection(PROOFLANE_PROJECT, req.params.id, await requestActor(req)), activeMcpConnectionId === req.params.id && (activeMcpConnectionId = null, activeMcpAuthMode = "unknown", svc = new InspectorService(store)), { ok: !0 };
|
|
13040
13242
|
} catch (error) {
|
|
13041
13243
|
return sendMcpError(reply, error);
|
|
13042
13244
|
}
|
|
13043
|
-
}),
|
|
13245
|
+
}), app.get("/api/mcp/tools", async (req) => {
|
|
13044
13246
|
let entitlement = mcpEntitlementForPlan(await resolvePlan(req));
|
|
13045
13247
|
return mcpManager.reconcileEntitlement(PROOFLANE_PROJECT, entitlement), { tools: mcpManager.listTools(PROOFLANE_PROJECT, req.query.connectionId) };
|
|
13046
|
-
}),
|
|
13248
|
+
}), app.get("/api/features/:featureType/:resourceId/mcp-binding", async (req, reply) => {
|
|
13047
13249
|
let featureType = parseFeatureType(req.params.featureType);
|
|
13048
13250
|
return !featureType || !validResourceId(req.params.resourceId) ? reply.code(400).send({ error: "A valid MCP feature type and resource ID are required." }) : { binding: mcpManager.getBinding(PROOFLANE_PROJECT, featureType, req.params.resourceId) };
|
|
13049
|
-
}),
|
|
13251
|
+
}), app.put("/api/features/:featureType/:resourceId/mcp-binding", async (req, reply) => {
|
|
13050
13252
|
let featureType = parseFeatureType(req.params.featureType);
|
|
13051
13253
|
if (!featureType || !validResourceId(req.params.resourceId))
|
|
13052
13254
|
return reply.code(400).send({ error: "A valid MCP feature type and resource ID are required." });
|
|
@@ -13072,10 +13274,10 @@ ${answer}`
|
|
|
13072
13274
|
} catch (error) {
|
|
13073
13275
|
return sendMcpError(reply, error);
|
|
13074
13276
|
}
|
|
13075
|
-
}),
|
|
13277
|
+
}), app.delete("/api/features/:featureType/:resourceId/mcp-binding", async (req, reply) => {
|
|
13076
13278
|
let featureType = parseFeatureType(req.params.featureType);
|
|
13077
13279
|
return !featureType || !validResourceId(req.params.resourceId) ? reply.code(400).send({ error: "A valid MCP feature type and resource ID are required." }) : { ok: mcpManager.deleteBinding(PROOFLANE_PROJECT, featureType, req.params.resourceId, await requestActor(req)) };
|
|
13078
|
-
}),
|
|
13280
|
+
}), app.post("/api/features/:featureType/:resourceId/mcp-runs", async (req, reply) => {
|
|
13079
13281
|
let featureType = parseFeatureType(req.params.featureType);
|
|
13080
13282
|
if (!featureType || !validResourceId(req.params.resourceId))
|
|
13081
13283
|
return reply.code(400).send({ error: "A valid MCP feature type and resource ID are required." });
|
|
@@ -13087,10 +13289,10 @@ ${answer}`
|
|
|
13087
13289
|
} catch (error) {
|
|
13088
13290
|
return sendMcpError(reply, error);
|
|
13089
13291
|
}
|
|
13090
|
-
}),
|
|
13292
|
+
}), app.get("/api/mcp/runs/:runId", async (req, reply) => {
|
|
13091
13293
|
let snapshot = mcpManager.getRunSnapshot(PROOFLANE_PROJECT, req.params.runId);
|
|
13092
13294
|
return snapshot ? { snapshot } : reply.code(404).send({ error: "MCP run snapshot was not found." });
|
|
13093
|
-
}),
|
|
13295
|
+
}), app.post("/api/mcp/runs/:runId/invoke", async (req, reply) => {
|
|
13094
13296
|
let controller = new AbortController(), cancel = () => controller.abort();
|
|
13095
13297
|
req.raw.once("aborted", cancel);
|
|
13096
13298
|
try {
|
|
@@ -13105,12 +13307,12 @@ ${answer}`
|
|
|
13105
13307
|
} finally {
|
|
13106
13308
|
req.raw.off("aborted", cancel);
|
|
13107
13309
|
}
|
|
13108
|
-
}),
|
|
13310
|
+
}), app.get("/api/mcp/audit", async (req) => ({
|
|
13109
13311
|
events: mcpManager.listAuditEvents(PROOFLANE_PROJECT, Number(req.query.limit ?? 100))
|
|
13110
|
-
})),
|
|
13312
|
+
})), app.get("/api/capabilities", async () => {
|
|
13111
13313
|
let capabilities = svc.getCapabilities(), searchable = capabilities ? JSON.stringify(capabilities).toLowerCase() : "", tools = capabilities?.tools ?? [], resources = capabilities?.resources ?? [], rag = tools.some((tool) => /rag|retriev|search|knowledge|vector|semantic/.test(`${tool.name} ${tool.description ?? ""}`.toLowerCase())) || resources.some((resource) => /knowledge|document|vector|search|rag/.test(`${resource.uri} ${resource.name ?? ""} ${resource.description ?? ""}`.toLowerCase())), notableTools = tools.filter((tool) => /create|update|write|delete|remove|execute|admin|push|merge|dispatch|upload/.test(`${tool.name} ${tool.description ?? ""}`.toLowerCase())).map((tool) => tool.name), sensitivitySignals = [...new Set((searchable.match(/email|phone|address|ssn|personal|secret|token|password|api[_ -]?key|user[_ -]?id|account[_ -]?id/g) ?? []).slice(0, 8))];
|
|
13112
13314
|
return { connected: svc.isConnected(), connectionId: activeMcpConnectionId, capabilities, discovery: { toolCount: tools.length, auth: { mode: activeMcpAuthMode, status: activeMcpAuthMode === "unknown" ? "UNKNOWN" : "OBSERVED" }, rag: { present: rag, status: rag ? "OBSERVED" : "NOT_OBSERVED" }, notable: { tools: notableTools, status: notableTools.length ? "CLASSIFIED" : "NONE_CLASSIFIED" }, sensitivity: { signals: sensitivitySignals, status: sensitivitySignals.length ? "INFERRED" : "NOT_INFERRED" } } };
|
|
13113
|
-
}),
|
|
13315
|
+
}), app.post("/api/connect/oauth/start", async (req, reply) => {
|
|
13114
13316
|
let { url, name } = req.body, plan = await resolvePlan(req), entitlement = mcpEntitlementForPlan(plan), actor = await requestActor(req);
|
|
13115
13317
|
try {
|
|
13116
13318
|
mcpManager.assertCanAddMcpConnection(PROOFLANE_PROJECT, entitlement);
|
|
@@ -13124,7 +13326,7 @@ ${answer}`
|
|
|
13124
13326
|
let capabilities = await candidate.adoptConnection(flow.transport, name, origin), registered = mcpManager.registerConnectedRuntime({ workspaceId: PROOFLANE_PROJECT, displayName: name ?? "MCP Server", config: origin, createdBy: actor, entitlement, authMode: "oauth" }, candidate, capabilities);
|
|
13125
13327
|
return svc = candidate, activeMcpConnectionId = registered.connection.id, activeMcpAuthMode = "oauth", { status: "connected", capabilities, connection: registered.connection };
|
|
13126
13328
|
}
|
|
13127
|
-
let flowId =
|
|
13329
|
+
let flowId = randomUUID8();
|
|
13128
13330
|
return oauthFlows.set(flowId, { status: "pending" }), flow.finish().then((transport) => candidate.adoptConnection(transport, name, origin)).then((capabilities) => {
|
|
13129
13331
|
let registered = mcpManager.registerConnectedRuntime({ workspaceId: PROOFLANE_PROJECT, displayName: name ?? "MCP Server", config: origin, createdBy: actor, entitlement, authMode: "oauth" }, candidate, capabilities);
|
|
13130
13332
|
svc = candidate, activeMcpConnectionId = registered.connection.id, activeMcpAuthMode = "oauth", oauthFlows.set(flowId, { status: "connected", capabilities });
|
|
@@ -13137,10 +13339,10 @@ ${answer}`
|
|
|
13137
13339
|
authUrl: flow.authUrl,
|
|
13138
13340
|
redirectUri: flow.redirectUri
|
|
13139
13341
|
};
|
|
13140
|
-
}),
|
|
13342
|
+
}), app.get("/api/connect/oauth/status", async (req) => {
|
|
13141
13343
|
let rec = oauthFlows.get(req.query.flowId);
|
|
13142
13344
|
return rec || { status: "error", error: "Unknown flow." };
|
|
13143
|
-
}),
|
|
13345
|
+
}), app.post("/api/disconnect", async () => (activeMcpConnectionId ? await mcpManager.disconnectConnection(PROOFLANE_PROJECT, activeMcpConnectionId, "local-user") : await svc.disconnect(), activeMcpConnectionId = null, activeMcpAuthMode = "unknown", svc = new InspectorService(store), { ok: !0 })), app.post("/api/tools/:name/call", async (req) => svc.callTool(req.params.name, req.body?.input ?? {})), app.post("/api/tools/:name/snapshot", async (req) => svc.snapshotTool(req.params.name, req.body?.input ?? {})), app.post("/api/security/verify-capability", async (req, reply) => {
|
|
13144
13346
|
let toolName = typeof req.body?.toolName == "string" ? req.body.toolName : "";
|
|
13145
13347
|
if (!toolName)
|
|
13146
13348
|
return reply.code(400).send({ error: "toolName is required." });
|
|
@@ -13193,19 +13395,19 @@ ${answer}`
|
|
|
13193
13395
|
} catch (error) {
|
|
13194
13396
|
return error instanceof ExecutionGateError ? reply.code(400).send({ error: error.message }) : reply.code(500).send({ error: error instanceof Error ? error.message : "Capability verification failed." });
|
|
13195
13397
|
}
|
|
13196
|
-
}),
|
|
13398
|
+
}), app.post("/api/diff/snapshot", async (req) => svc.diffAgainst(req.body.snapshot)), app.post("/api/diff/values", async (req) => diffTool(req.body.tool, req.body.expected, req.body.actual)), app.post("/api/resources/read", async (req) => svc.readResource(req.body.uri)), app.post("/api/prompts/:name/get", async (req) => svc.getPrompt(req.params.name, req.body?.args)), app.post("/api/drift", async (req) => {
|
|
13197
13399
|
let current = svc.getCapabilities();
|
|
13198
13400
|
if (!current)
|
|
13199
13401
|
throw new Error("Not connected.");
|
|
13200
13402
|
return detectCapabilityDrift(req.body.baseline, current);
|
|
13201
|
-
}),
|
|
13403
|
+
}), app.post("/api/record/start", async (req) => (svc.startRecording(req.body?.label), { ok: !0, recording: !0 })), app.get("/api/record/status", async () => ({ recording: svc.isRecording() })), app.post("/api/record/stop", async () => svc.stopRecording()), app.get("/api/sessions", async () => svc.listSessions()), app.get("/api/sessions/:id", async (req) => {
|
|
13202
13404
|
let session = svc.getSession(req.params.id);
|
|
13203
13405
|
if (!session)
|
|
13204
13406
|
throw new Error(`Session not found: ${req.params.id}`);
|
|
13205
13407
|
return session;
|
|
13206
|
-
}),
|
|
13408
|
+
}), app.post("/api/sessions/:id/golden", async (req) => (svc.markGolden(req.params.id, req.body?.golden ?? !0), { ok: !0 })), app.post("/api/sessions/:id/automate", async (req) => svc.automate(req.params.id, req.body.format)), app.post("/api/sessions/:id/fault", async (req) => svc.injectFault(req.params.id, req.body.step, req.body.type));
|
|
13207
13409
|
let HTTP_TIMEOUT_MS = 3e4, HTTP_BODY_CAP = 2e6;
|
|
13208
|
-
|
|
13410
|
+
app.post("/api/http/request", async (req) => {
|
|
13209
13411
|
let { method, url, headers, body } = req.body, start = Date.now(), controller = new AbortController(), timer = setTimeout(() => controller.abort(), HTTP_TIMEOUT_MS), hasBody = !["GET", "HEAD"].includes(method.toUpperCase());
|
|
13210
13412
|
try {
|
|
13211
13413
|
let res = await fetch(url, {
|
|
@@ -13236,9 +13438,9 @@ ${answer}`
|
|
|
13236
13438
|
} finally {
|
|
13237
13439
|
clearTimeout(timer);
|
|
13238
13440
|
}
|
|
13239
|
-
}),
|
|
13441
|
+
}), app.post("/api/http/snapshot", async (req) => svc.saveHttpSnapshot(req.body.request, req.body.response, req.body.origin ?? "captured")), app.get("/api/snapshots", async () => svc.listSnapshots()), app.patch("/api/snapshots/:id", async (req, reply) => svc.updateSnapshot(req.params.id, req.body) ? { ok: !0 } : reply.code(404).send({ ok: !1, error: "Contract not found." })), app.delete("/api/snapshots/:id", async (req) => (svc.deleteSnapshot(req.params.id), { ok: !0 })), app.post("/api/automate/contracts", async (req) => svc.automateSnapshots(req.body.snapshotIds, req.body.format)), app.post("/api/prompts/generate", async (req) => ({
|
|
13240
13442
|
prompts: svc.generatePromptsForTool(req.body.tool)
|
|
13241
|
-
})),
|
|
13443
|
+
})), app.get("/api/prompts/custom", async () => svc.listCustomPrompts()), app.post("/api/llm/run", async (req) => callLlm(req.body)), app.post("/api/prompts/run-agent", async (req, reply) => {
|
|
13242
13444
|
let { tool, prompt, llm } = req.body, t = svc.getCapabilities()?.tools.find((x) => x.name === tool);
|
|
13243
13445
|
return t ? runAgent({
|
|
13244
13446
|
...llm,
|
|
@@ -13249,7 +13451,7 @@ ${answer}`
|
|
|
13249
13451
|
return { output: r.output, isError: r.isError };
|
|
13250
13452
|
}
|
|
13251
13453
|
}) : reply.code(400).send({ ok: !1, toolCalls: [], error: `Tool "${tool}" isn't on the current connection \u2014 connect first.`, latencyMs: 0 });
|
|
13252
|
-
}),
|
|
13454
|
+
}), app.post("/api/rag/hosted-run", async (req, reply) => {
|
|
13253
13455
|
let cases = Array.isArray(req.body?.cases) ? req.body.cases.filter((candidate) => candidate && typeof candidate.id == "string" && hostedRagCaseQuery(candidate).trim()) : [], capabilities = svc.getCapabilities();
|
|
13254
13456
|
if (!capabilities)
|
|
13255
13457
|
return reply.code(400).send({ ok: !1, error: "Connect to an MCP server first \u2014 RAG Assurance runs against its retrieval tools." });
|
|
@@ -13406,7 +13608,7 @@ ${answer}`
|
|
|
13406
13608
|
if (req.body.recordHistory === !1)
|
|
13407
13609
|
return finish({ ok: !0, report, hostedScan });
|
|
13408
13610
|
let previous = (() => {
|
|
13409
|
-
let last = svc.listRuns(500).find((
|
|
13611
|
+
let last = svc.listRuns(500).find((record7) => record7.pillar === "rag" && record7.evidence);
|
|
13410
13612
|
if (!last?.evidence)
|
|
13411
13613
|
return null;
|
|
13412
13614
|
try {
|
|
@@ -13432,11 +13634,11 @@ ${answer}`
|
|
|
13432
13634
|
evidence: JSON.stringify(mcpSnapshot ? { ...snapshot, mcp: mcpSnapshot.mcp, hostedScanId: hostedScan.id } : { ...snapshot, hostedScanId: hostedScan.id })
|
|
13433
13635
|
}), diff = previous ? hostedRagScoreDiff(previous, snapshot) : void 0;
|
|
13434
13636
|
return finish({ ok: !0, report, diff, run, hostedScan });
|
|
13435
|
-
}),
|
|
13436
|
-
let runs = svc.listRuns(1e3).filter((
|
|
13637
|
+
}), app.get("/api/rag/hosted-diff/:id", async (req, reply) => {
|
|
13638
|
+
let runs = svc.listRuns(1e3).filter((record7) => record7.pillar === "rag"), index = runs.findIndex((record7) => record7.id === req.params.id);
|
|
13437
13639
|
if (index === -1)
|
|
13438
13640
|
return reply.code(404).send({ ok: !1, error: "Run not found." });
|
|
13439
|
-
let current = runs[index], previous = runs.slice(index + 1).find((
|
|
13641
|
+
let current = runs[index], previous = runs.slice(index + 1).find((record7) => record7.evidence);
|
|
13440
13642
|
if (!current.evidence || !previous?.evidence)
|
|
13441
13643
|
return { ok: !0, diff: null };
|
|
13442
13644
|
try {
|
|
@@ -13472,7 +13674,7 @@ ${answer}`
|
|
|
13472
13674
|
durationMs
|
|
13473
13675
|
});
|
|
13474
13676
|
}
|
|
13475
|
-
|
|
13677
|
+
app.post("/api/perf/run", async (req, reply) => {
|
|
13476
13678
|
let { target, vus, durationS, targetMs } = req.body;
|
|
13477
13679
|
if (vus > 5) {
|
|
13478
13680
|
let plan = await resolvePlan(req);
|
|
@@ -13513,7 +13715,7 @@ ${answer}`
|
|
|
13513
13715
|
};
|
|
13514
13716
|
let metrics = await runLoadTest({ fire, vus: cappedVus, durationMs, targetMs });
|
|
13515
13717
|
return mcpSnapshot ? { ok: !0, ...metrics, mcpSnapshot, mcpFact: recordBoundMcpFact(mcpSnapshot, metrics.errors === 0) } : { ok: !0, ...metrics };
|
|
13516
|
-
}),
|
|
13718
|
+
}), app.post("/api/prompts/generate-ai", async (req, reply) => {
|
|
13517
13719
|
let plan = await resolvePlan(req);
|
|
13518
13720
|
if (!plan.hosted)
|
|
13519
13721
|
return reply.code(402).send({
|
|
@@ -13542,17 +13744,17 @@ Cover a mix of: positive (valid, useful requests), negative (misuse \u2014 missi
|
|
|
13542
13744
|
skipped: parsed.length - saved.length,
|
|
13543
13745
|
tokens: (res.usage?.inputTokens ?? 0) + (res.usage?.outputTokens ?? 0)
|
|
13544
13746
|
};
|
|
13545
|
-
}),
|
|
13747
|
+
}), app.post("/api/prompts/custom/:id/golden", async (req) => (svc.setPromptGolden(req.params.id, req.body.expected, req.body.assert ?? "similar"), { ok: !0 })), app.post("/api/prompts/custom/:id/checks", async (req) => (svc.setPromptChecks(req.params.id, {
|
|
13546
13748
|
input: req.body.input,
|
|
13547
13749
|
assertions: req.body.assertions,
|
|
13548
13750
|
checkSchema: req.body.checkSchema
|
|
13549
|
-
}), { ok: !0 })),
|
|
13751
|
+
}), { ok: !0 })), app.post("/api/prompts/assert", async (req, reply) => {
|
|
13550
13752
|
try {
|
|
13551
13753
|
return { ok: !0, ...await svc.assertTool(req.body.tool, req.body.input ?? {}, req.body.assertions ?? [], req.body.checkSchema ?? !1) };
|
|
13552
13754
|
} catch (e) {
|
|
13553
13755
|
return reply.code(400).send({ ok: !1, error: e instanceof Error ? e.message : String(e) });
|
|
13554
13756
|
}
|
|
13555
|
-
}),
|
|
13757
|
+
}), app.post("/api/prompts/custom", async (req, reply) => {
|
|
13556
13758
|
let plan = await resolvePlan(req);
|
|
13557
13759
|
return !isUnlimited(plan.prompts) && svc.listCustomPrompts().length >= plan.prompts ? reply.code(402).send({
|
|
13558
13760
|
ok: !1,
|
|
@@ -13562,7 +13764,7 @@ Cover a mix of: positive (valid, useful requests), negative (misuse \u2014 missi
|
|
|
13562
13764
|
limit: plan.prompts,
|
|
13563
13765
|
error: `Your ${plan.label} plan stores up to ${plan.prompts} test prompts. Delete one or upgrade to add more.`
|
|
13564
13766
|
}) : svc.addCustomPrompt(req.body.name, req.body.content, req.body.tool);
|
|
13565
|
-
}),
|
|
13767
|
+
}), app.patch("/api/prompts/custom/:id", async (req) => (svc.updateCustomPrompt(req.params.id, req.body), { ok: !0 })), app.delete("/api/prompts/custom/:id", async (req) => (svc.deleteCustomPrompt(req.params.id), { ok: !0 })), app.post("/api/prompts/generate-cases", async (req, reply) => {
|
|
13566
13768
|
let plan = await resolvePlan(req);
|
|
13567
13769
|
if (!plan.hosted)
|
|
13568
13770
|
return reply.code(402).send({
|
|
@@ -13614,7 +13816,7 @@ Assertions must be objectively checkable against the tool's JSON response. Never
|
|
|
13614
13816
|
errorKind: "hosted-generation",
|
|
13615
13817
|
error: "The model did not return usable test cases. Retry, or choose a model that reliably follows structured-output instructions."
|
|
13616
13818
|
});
|
|
13617
|
-
}),
|
|
13819
|
+
}), app.post("/api/prompts/custom/bulk", async (req, reply) => {
|
|
13618
13820
|
let cases = (req.body?.cases ?? []).filter((c) => c && typeof c.content == "string" && c.content.trim());
|
|
13619
13821
|
if (!cases.length)
|
|
13620
13822
|
return reply.code(400).send({ ok: !1, error: "Select at least one reviewed case to save." });
|
|
@@ -13645,7 +13847,7 @@ Assertions must be objectively checkable against the tool's JSON response. Never
|
|
|
13645
13847
|
});
|
|
13646
13848
|
function pushStudioEvent(session, turnId, type, payload) {
|
|
13647
13849
|
let event = {
|
|
13648
|
-
id: `ev-${
|
|
13850
|
+
id: `ev-${randomUUID8().slice(0, 8)}`,
|
|
13649
13851
|
sessionId: session.id,
|
|
13650
13852
|
turnId,
|
|
13651
13853
|
sequence: ++session.sequence,
|
|
@@ -13666,9 +13868,9 @@ Assertions must be objectively checkable against the tool's JSON response. Never
|
|
|
13666
13868
|
let all = svc.getCapabilities()?.tools ?? [], enabled = session.config.enabledTools;
|
|
13667
13869
|
return enabled && enabled.length ? all.filter((t) => enabled.includes(t.name)) : all;
|
|
13668
13870
|
};
|
|
13669
|
-
|
|
13871
|
+
app.post("/api/prompt-studio/sessions", async (req) => {
|
|
13670
13872
|
let body = req.body ?? {}, now = (/* @__PURE__ */ new Date()).toISOString(), session = {
|
|
13671
|
-
id: `ps-${
|
|
13873
|
+
id: `ps-${randomUUID8().slice(0, 8)}`,
|
|
13672
13874
|
name: (body.name ?? "").trim().slice(0, 120) || `Session ${(/* @__PURE__ */ new Date()).toLocaleString()}`,
|
|
13673
13875
|
createdAt: now,
|
|
13674
13876
|
updatedAt: now,
|
|
@@ -13697,13 +13899,13 @@ Assertions must be objectively checkable against the tool's JSON response. Never
|
|
|
13697
13899
|
oldest && studioSessions.delete(oldest.id);
|
|
13698
13900
|
}
|
|
13699
13901
|
return { ok: !0, session: studioSummary(session), events: [] };
|
|
13700
|
-
}),
|
|
13902
|
+
}), app.get("/api/prompt-studio/sessions", async () => ({
|
|
13701
13903
|
ok: !0,
|
|
13702
13904
|
sessions: [...studioSessions.values()].sort((a, b) => b.updatedAt.localeCompare(a.updatedAt)).map(studioSummary)
|
|
13703
|
-
})),
|
|
13905
|
+
})), app.get("/api/prompt-studio/sessions/:id", async (req, reply) => {
|
|
13704
13906
|
let session = studioSessions.get(req.params.id);
|
|
13705
13907
|
return session ? { ok: !0, session: studioSummary(session), events: session.events } : reply.code(404).send({ ok: !1, error: "That Prompt Studio session is no longer available." });
|
|
13706
|
-
}),
|
|
13908
|
+
}), app.get("/api/prompt-studio/sessions/:id/suggestions", async (req, reply) => {
|
|
13707
13909
|
let session = studioSessions.get(req.params.id);
|
|
13708
13910
|
if (!session)
|
|
13709
13911
|
return reply.code(404).send({ ok: !1, error: "That Prompt Studio session is no longer available." });
|
|
@@ -13713,10 +13915,10 @@ Assertions must be objectively checkable against the tool's JSON response. Never
|
|
|
13713
13915
|
observation: { prompt: observation.prompt, answer: observation.answer, toolCalls: observation.toolCalls },
|
|
13714
13916
|
suggestions: suggestPromptTestChecks(observation)
|
|
13715
13917
|
};
|
|
13716
|
-
}),
|
|
13918
|
+
}), app.delete("/api/prompt-studio/sessions/:id", async (req) => (studioSessions.delete(req.params.id), { ok: !0 })), app.post("/api/prompt-studio/sessions/:id/stop", async (req, reply) => {
|
|
13717
13919
|
let session = studioSessions.get(req.params.id);
|
|
13718
13920
|
return session ? (session.stopRequested = !0, { ok: !0, stopping: session.running }) : reply.code(404).send({ ok: !1, error: "That Prompt Studio session is no longer available." });
|
|
13719
|
-
}),
|
|
13921
|
+
}), app.post("/api/prompt-studio/sessions/:id/messages", async (req, reply) => {
|
|
13720
13922
|
let session = studioSessions.get(req.params.id);
|
|
13721
13923
|
if (!session)
|
|
13722
13924
|
return reply.code(404).send({ ok: !1, error: "That Prompt Studio session is no longer available. Start a new session." });
|
|
@@ -13795,7 +13997,7 @@ Assertions must be objectively checkable against the tool's JSON response. Never
|
|
|
13795
13997
|
} finally {
|
|
13796
13998
|
session.running = !1, session.stopRequested = !1;
|
|
13797
13999
|
}
|
|
13798
|
-
}),
|
|
14000
|
+
}), app.post("/api/prompt-studio/sessions/:id/tools/:tool", async (req, reply) => {
|
|
13799
14001
|
let session = studioSessions.get(req.params.id);
|
|
13800
14002
|
if (!session)
|
|
13801
14003
|
return reply.code(404).send({ ok: !1, error: "That Prompt Studio session is no longer available." });
|
|
@@ -13840,7 +14042,7 @@ Assertions must be objectively checkable against the tool's JSON response. Never
|
|
|
13840
14042
|
let attributed = attributeError(error instanceof Error ? error.message : String(error), "tool");
|
|
13841
14043
|
return pushStudioEvent(session, turnId, "run-failed", { tool: tool.name, error: attributed.detail, errorKind: attributed.kind }), reply.code(502).send({ ok: !1, error: attributed.detail, errorKind: attributed.kind, errorTitle: attributed.title });
|
|
13842
14044
|
}
|
|
13843
|
-
}),
|
|
14045
|
+
}), app.post("/api/model-scans/run", async (req, reply) => {
|
|
13844
14046
|
let target = req.body?.path?.trim();
|
|
13845
14047
|
if (!target || target.length > 4096)
|
|
13846
14048
|
return reply.code(400).send({ ok: !1, error: "A valid local model file or directory path is required." });
|
|
@@ -13852,7 +14054,7 @@ Assertions must be objectively checkable against the tool's JSON response. Never
|
|
|
13852
14054
|
maxArchiveExpandedBytes: Math.round(maxArchiveMb * 1024 * 1024)
|
|
13853
14055
|
});
|
|
13854
14056
|
return store.saveModelScan(report), reply.header("Cache-Control", "no-store"), { ok: !0, report };
|
|
13855
|
-
}),
|
|
14057
|
+
}), app.get("/api/model-scans", async (req, reply) => {
|
|
13856
14058
|
let limit = Math.max(1, Math.min(200, Math.trunc(Number(req.query.limit) || 25)));
|
|
13857
14059
|
return reply.header("Cache-Control", "no-store"), store.listModelScans(limit).map((report) => ({
|
|
13858
14060
|
scanId: report.scanId,
|
|
@@ -13863,16 +14065,16 @@ Assertions must be objectively checkable against the tool's JSON response. Never
|
|
|
13863
14065
|
summary: report.summary,
|
|
13864
14066
|
artifactIdentity: report.artifactIdentity
|
|
13865
14067
|
}));
|
|
13866
|
-
}),
|
|
14068
|
+
}), app.get("/api/model-scans/:id", async (req, reply) => {
|
|
13867
14069
|
let report = store.getModelScan(req.params.id);
|
|
13868
14070
|
return report ? (reply.header("Cache-Control", "no-store"), { ok: !0, report }) : reply.code(404).send({ ok: !1, error: "Model scan not found." });
|
|
13869
|
-
}),
|
|
14071
|
+
}), app.get("/api/model-scans/:id/export", async (req, reply) => {
|
|
13870
14072
|
let report = store.getModelScan(req.params.id);
|
|
13871
14073
|
if (!report)
|
|
13872
14074
|
return reply.code(404).send({ ok: !1, error: "Model scan not found." });
|
|
13873
14075
|
let safeName = report.target.displayName.replace(/[^A-Za-z0-9._-]+/g, "-").slice(0, 100) || "model", format = String(req.query.format ?? "json").toLowerCase();
|
|
13874
14076
|
return reply.header("Cache-Control", "no-store"), format === "html" ? (reply.type("text/html; charset=utf-8").header("Content-Disposition", `attachment; filename="${safeName}-prooflane-model-scan.html"`), reply.send(modelScanToHtml(report))) : format === "sarif" ? (reply.type("application/sarif+json").header("Content-Disposition", `attachment; filename="${safeName}-prooflane-model-scan.sarif.json"`), reply.send(JSON.stringify(modelScanToSarif(report), null, 2))) : (reply.type("application/json").header("Content-Disposition", `attachment; filename="${safeName}-prooflane-model-scan.json"`), reply.send(JSON.stringify(report, null, 2)));
|
|
13875
|
-
}),
|
|
14077
|
+
}), app.delete("/api/model-scans/:id", async (req, reply) => store.deleteModelScan(req.params.id) ? { ok: !0 } : reply.code(404).send({ ok: !1, error: "Model scan not found." })), app.get("/api/model-security/packs", async (_req, reply) => (reply.header("Cache-Control", "no-store"), {
|
|
13876
14078
|
packs: MODEL_SECURITY_PACKS,
|
|
13877
14079
|
checks: MODEL_SECURITY_RULES.map((rule) => ({
|
|
13878
14080
|
id: rule.id,
|
|
@@ -13886,7 +14088,7 @@ Assertions must be objectively checkable against the tool's JSON response. Never
|
|
|
13886
14088
|
stages: MODEL_SCAN_STAGES.map((stage) => ({ id: stage, label: MODEL_SCAN_STAGE_LABEL[stage] })),
|
|
13887
14089
|
sourceTypes: SUPPORTED_MODEL_SOURCE_TYPES,
|
|
13888
14090
|
evidenceClasses: MODEL_EVIDENCE_CLASSES.map((id) => ({ id, label: MODEL_EVIDENCE_LABEL[id] }))
|
|
13889
|
-
})),
|
|
14091
|
+
})), app.post("/api/model-security/run", async (req, reply) => {
|
|
13890
14092
|
let target = req.body?.target;
|
|
13891
14093
|
if (!target?.sourceType || !target.source?.trim())
|
|
13892
14094
|
return reply.code(400).send({ ok: !1, error: "A model security scan needs a target source type and source." });
|
|
@@ -13929,19 +14131,19 @@ Assertions must be objectively checkable against the tool's JSON response. Never
|
|
|
13929
14131
|
let message2 = error instanceof Error ? error.message : String(error);
|
|
13930
14132
|
return wantStream && streamOpen ? (streamWrite({ t: "done", ok: !1, error: message2 }), reply.raw.end(), reply) : reply.code(400).send({ ok: !1, error: message2 });
|
|
13931
14133
|
}
|
|
13932
|
-
}),
|
|
14134
|
+
}), app.get("/api/model-security", async (req, reply) => {
|
|
13933
14135
|
let limit = Math.max(1, Math.min(200, Math.trunc(Number(req.query.limit) || 25)));
|
|
13934
14136
|
return reply.header("Cache-Control", "no-store"), store.listModelSecurityScans(limit).map(modelSecuritySummary);
|
|
13935
|
-
}),
|
|
14137
|
+
}), app.get("/api/model-security/:id", async (req, reply) => {
|
|
13936
14138
|
let report = store.getModelSecurityScan(req.params.id);
|
|
13937
14139
|
return report ? (reply.header("Cache-Control", "no-store"), { ok: !0, report }) : reply.code(404).send({ ok: !1, error: "Model security scan not found." });
|
|
13938
|
-
}),
|
|
14140
|
+
}), app.get("/api/model-security/:id/export", async (req, reply) => {
|
|
13939
14141
|
let report = store.getModelSecurityScan(req.params.id);
|
|
13940
14142
|
if (!report)
|
|
13941
14143
|
return reply.code(404).send({ ok: !1, error: "Model security scan not found." });
|
|
13942
14144
|
let safeName = report.target.displayName.replace(/[^A-Za-z0-9._-]+/g, "-").slice(0, 100) || "model", format = String(req.query.format ?? "json").toLowerCase();
|
|
13943
14145
|
return reply.header("Cache-Control", "no-store"), format === "html" ? (reply.type("text/html; charset=utf-8").header("Content-Disposition", `attachment; filename="${safeName}-model-supply-chain.html"`), reply.send(modelSecurityToHtml(report))) : format === "sarif" ? (reply.type("application/sarif+json").header("Content-Disposition", `attachment; filename="${safeName}-model-supply-chain.sarif.json"`), reply.send(JSON.stringify(modelSecurityToSarif(report), null, 2))) : (reply.type("application/json").header("Content-Disposition", `attachment; filename="${safeName}-model-supply-chain.json"`), reply.send(JSON.stringify(report, null, 2)));
|
|
13944
|
-
}),
|
|
14146
|
+
}), app.delete("/api/model-security/:id", async (req, reply) => store.deleteModelSecurityScan(req.params.id) ? { ok: !0 } : reply.code(404).send({ ok: !1, error: "Model security scan not found." })), app.post("/api/runs", async (req) => svc.recordRun(req.body)), app.get("/api/runs", async (req, reply) => {
|
|
13945
14147
|
let plan = await resolvePlan(req), requestedLimit = Number(req.query.limit), limit = Number.isFinite(requestedLimit) && requestedLimit > 0 ? Math.min(1e3, Math.trunc(requestedLimit)) : void 0;
|
|
13946
14148
|
reply.header("Cache-Control", "no-store");
|
|
13947
14149
|
let runs = svc.listRuns(limit);
|
|
@@ -13950,27 +14152,33 @@ Assertions must be objectively checkable against the tool's JSON response. Never
|
|
|
13950
14152
|
let oldest = Date.now() - plan.historyDays * 24 * 60 * 60 * 1e3;
|
|
13951
14153
|
return runs.filter((run) => Date.parse(run.createdAt) >= oldest);
|
|
13952
14154
|
});
|
|
13953
|
-
let uiDist = process.env.KAWACH_UI_DIST ??
|
|
13954
|
-
return
|
|
14155
|
+
let uiDist = process.env.KAWACH_UI_DIST ?? join5(__dirname, "../../ui/dist");
|
|
14156
|
+
return existsSync3(uiDist) && (app.register(fastifyStatic, { root: uiDist }), app.setNotFoundHandler((req, reply) => {
|
|
13955
14157
|
if (req.url.startsWith("/api")) {
|
|
13956
14158
|
reply.code(404).send({ error: "Not found" });
|
|
13957
14159
|
return;
|
|
13958
14160
|
}
|
|
13959
14161
|
reply.sendFile("index.html");
|
|
13960
|
-
})),
|
|
14162
|
+
})), app.setErrorHandler((err, req, reply) => {
|
|
13961
14163
|
let upstream = err instanceof KawachError ? err.statusCode : void 0;
|
|
13962
14164
|
req.log.error({ err, upstream }, "Inspector request failed"), reply.code(upstream ? 502 : 500).send({ error: publicServerError(req.url), reference: req.id });
|
|
13963
|
-
}),
|
|
14165
|
+
}), app.addHook("onClose", async () => store.close()), app;
|
|
14166
|
+
}
|
|
14167
|
+
|
|
14168
|
+
// ../server/dist/start.js
|
|
14169
|
+
var PORT = Number(process.env.KAWACH_UI_PORT ?? 7357), HOST = "127.0.0.1";
|
|
14170
|
+
async function startServer(options = {}) {
|
|
14171
|
+
let app = buildApp();
|
|
14172
|
+
options.configureApp?.(app), await app.listen({ port: PORT, host: HOST }), console.log(`Kawach Inspector UI \u2192 http://localhost:${PORT}`);
|
|
14173
|
+
for (let sig of ["SIGINT", "SIGTERM"])
|
|
14174
|
+
process.once(sig, () => {
|
|
14175
|
+
app.close().finally(() => process.exit(0));
|
|
14176
|
+
});
|
|
14177
|
+
return app;
|
|
14178
|
+
}
|
|
14179
|
+
function failServerStart(error) {
|
|
14180
|
+
console.error("Failed to start Kawach Inspector server:", error), process.exit(1);
|
|
13964
14181
|
}
|
|
13965
14182
|
|
|
13966
14183
|
// ../server/dist/index.js
|
|
13967
|
-
|
|
13968
|
-
app.listen({ port: PORT, host: HOST }).then(() => {
|
|
13969
|
-
console.log(`Kawach Inspector UI \u2192 http://localhost:${PORT}`);
|
|
13970
|
-
}).catch((err) => {
|
|
13971
|
-
console.error("Failed to start Kawach Inspector server:", err), process.exit(1);
|
|
13972
|
-
});
|
|
13973
|
-
for (let sig of ["SIGINT", "SIGTERM"])
|
|
13974
|
-
process.on(sig, () => {
|
|
13975
|
-
app.close().finally(() => process.exit(0));
|
|
13976
|
-
});
|
|
14184
|
+
startServer().catch(failServerStart);
|