@prooflane/inspector-beta 0.1.0-beta.5 → 0.1.0-beta.6
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
CHANGED
|
@@ -14730,39 +14730,56 @@ var resultTone = (result) => {
|
|
|
14730
14730
|
return "review";
|
|
14731
14731
|
return "risk";
|
|
14732
14732
|
};
|
|
14733
|
+
var isAgentControl = (control) => control.verification?.kind === "model" || /prompt|retrieval|rag|agent|jailbreak|exfiltration/i.test(control.category);
|
|
14733
14734
|
function writeHostedCampaignGraph(outputPath, campaign, scan) {
|
|
14734
14735
|
const absolute = resolve5(outputPath);
|
|
14735
14736
|
mkdirSync2(dirname4(absolute), { recursive: true });
|
|
14736
|
-
const
|
|
14737
|
+
const controlCard = (control, index) => {
|
|
14737
14738
|
const findings = (control.findings ?? []).map((finding) => `
|
|
14738
|
-
<
|
|
14739
|
-
|
|
14740
|
-
|
|
14741
|
-
|
|
14742
|
-
|
|
14739
|
+
<article class="finding"><div class="finding-title"><strong>${escapeHtml3(finding.title)}</strong>${finding.severity ? `<span class="severity">${escapeHtml3(finding.severity)}</span>` : ""}</div><p>${escapeHtml3(finding.description)}</p>${finding.impact ? `<p><b>Impact:</b> ${escapeHtml3(finding.impact)}</p>` : ""}${finding.remediation ? `<p><b>Remediation:</b> ${escapeHtml3(finding.remediation)}</p>` : ""}</article>`).join("");
|
|
14740
|
+
const tone = resultTone(control.result);
|
|
14741
|
+
const label = control.result === "resisted" ? "BLOCKED" : String(control.result ?? control.executionState).replaceAll("_", " ").toUpperCase();
|
|
14742
|
+
return `<details class="control ${tone}" ${tone === "risk" ? "open" : ""}>
|
|
14743
|
+
<summary><span class="control-copy"><span class="category">${escapeHtml3(control.category)}</span><strong>${escapeHtml3(control.title)}</strong></span><span class="badge">${escapeHtml3(label)}</span></summary>
|
|
14744
|
+
<div class="control-detail">
|
|
14743
14745
|
<p>${escapeHtml3(control.shortDescription)}</p>
|
|
14746
|
+
<div class="facts"><div><span>Category</span><b>${escapeHtml3(control.category)}</b></div><div><span>Severity</span><b>${escapeHtml3(control.severity ?? "info")}</b></div><div><span>Execution</span><b>${escapeHtml3(control.verification?.kind === "safe_exposure" ? "not performed" : control.executionState)}</b></div><div><span>Status</span><b>${escapeHtml3(control.result ?? control.executionState)}</b></div><div><span>Duration</span><b>${escapeHtml3(control.durationMs == null ? "\u2014" : `${control.durationMs} ms`)}</b></div><div><span>Graded by</span><b>${escapeHtml3(control.verification?.kind ?? "signed hosted control")}</b></div></div>
|
|
14747
|
+
<section class="verified"><span>How this was verified</span><p>${escapeHtml3(control.verification?.description ?? "Prooflane graded the compact evidence returned for this signed hosted control.")}</p></section>
|
|
14744
14748
|
${control.message ? `<p class="message">${escapeHtml3(control.message)}</p>` : ""}
|
|
14745
|
-
${findings ? `<
|
|
14749
|
+
${findings ? `<section class="findings"><span>Capability findings</span>${findings}</section>` : ""}
|
|
14746
14750
|
</div>
|
|
14747
|
-
</
|
|
14748
|
-
}
|
|
14751
|
+
</details>`;
|
|
14752
|
+
};
|
|
14753
|
+
const graphNode = (control) => {
|
|
14754
|
+
const tone = resultTone(control.result);
|
|
14755
|
+
const label = control.result === "resisted" ? "BLOCKED" : String(control.result ?? control.executionState).replaceAll("_", " ").toUpperCase();
|
|
14756
|
+
return `<div class="node ${tone}"><span>${escapeHtml3(control.category)}</span><strong>${escapeHtml3(control.title)}</strong><b>${escapeHtml3(label)}</b></div>`;
|
|
14757
|
+
};
|
|
14758
|
+
const containment = scan.controls.filter((control) => !isAgentControl(control));
|
|
14759
|
+
const agent = scan.controls.filter(isAgentControl);
|
|
14760
|
+
const controls = scan.controls.map(controlCard).join("");
|
|
14761
|
+
const riskCount = scan.summary.exposed + scan.summary.breached + scan.summary.poisoned;
|
|
14762
|
+
const statusTone = scan.summary.breached > 0 ? "risk" : riskCount > 0 || scan.summary.inconclusive > 0 ? "review" : "safe";
|
|
14763
|
+
const statusCopy = scan.summary.breached > 0 ? `OBJECTIVE REACHED \xB7 ${campaign.objectiveLabel}` : riskCount > 0 ? `REVIEW REQUIRED \xB7 ${riskCount} exposed or poisoned control${riskCount === 1 ? "" : "s"}` : scan.summary.inconclusive > 0 ? "INCONCLUSIVE \xB7 no control verifiably failed" : "CONTAINED \xB7 every exercised control held";
|
|
14764
|
+
const tally = [`${scan.summary.breached} breached`, `${scan.summary.exposed} exposed`, `${scan.summary.inconclusive} inconclusive`, `${scan.summary.resisted} resisted`].join(" \xB7 ");
|
|
14749
14765
|
const generatedAt = scan.completedAt ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
14750
14766
|
const html = `<!doctype html>
|
|
14751
14767
|
<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
|
14752
14768
|
<title>${escapeHtml3(campaign.name)} \xB7 Prooflane campaign report</title>
|
|
14753
14769
|
<style>
|
|
14754
|
-
:root{color-scheme:
|
|
14770
|
+
:root{color-scheme:light;--bg:#f5f7f8;--card:#fff;--line:#d8e0e5;--text:#162028;--muted:#7b8d99;--gold:#bd630d;--green:#159b68;--green-bg:#e6f6ef;--red:#e04646;--red-bg:#fdeced;--amber:#b96a10;--amber-bg:#fff4d6}*{box-sizing:border-box}body{margin:0;background:linear-gradient(145deg,#fff 0,#f1f6f7 100%);color:var(--text);font:15px/1.55 Inter,ui-sans-serif,system-ui,-apple-system,sans-serif}.wrap{width:min(1180px,calc(100% - 32px));margin:32px auto 72px}.eyebrow,.category,.verified>span,.findings>span,.facts span{color:var(--muted);font:700 11px ui-monospace,monospace;letter-spacing:.08em;text-transform:uppercase}h1{font-size:28px;line-height:1.1;margin:8px 0 10px}p{color:var(--muted)}.status{margin:22px 0 12px;padding:18px 20px;border-radius:12px}.status strong{display:block}.status.safe{background:var(--green-bg);color:var(--green)}.status.risk{background:var(--red-bg);color:var(--red)}.status.review{background:var(--amber-bg);color:var(--amber)}.status span{color:var(--muted);font-size:13px}.attribution{padding:16px;border:1px solid var(--gold);border-radius:12px;background:#fffdf9}.attribution b{color:var(--gold);text-transform:uppercase;font-size:11px}.attribution p{margin:5px 0 0;color:var(--text)}.graph-group{margin-top:20px}.graph-group h2{font-size:14px;margin:0}.graph-group>p{font-size:13px;margin:3px 0 10px}.nodes{display:flex;gap:10px;align-items:stretch;flex-wrap:wrap}.node{display:grid;gap:4px;min-width:190px;max-width:280px;padding:14px;border:1px solid var(--line);border-radius:11px;background:var(--card)}.node span{color:var(--muted);font:700 10px ui-monospace,monospace;text-transform:uppercase}.node strong{font-size:13px}.node b{width:max-content;padding:2px 7px;border-radius:999px;font:700 10px ui-monospace,monospace}.node.safe{border-color:var(--green)}.node.safe b{color:var(--green);background:var(--green-bg)}.node.risk{border-color:var(--red)}.node.risk b{color:var(--red);background:var(--red-bg)}.node.review{border-color:var(--amber)}.node.review b{color:var(--amber);background:var(--amber-bg)}.objective{margin-top:20px;padding:14px;border:1px solid;border-radius:11px;font-weight:800}.objective.safe{border-color:var(--green);background:var(--green-bg);color:var(--green)}.objective.risk{border-color:var(--red);background:var(--red-bg);color:var(--red)}.details-title{margin:34px 0 12px}.control{margin-top:10px;border:1px solid var(--line);border-radius:12px;background:var(--card);overflow:hidden}.control.safe{border-color:var(--green)}.control.risk{border-color:var(--red)}.control.review{border-color:var(--amber)}summary{display:flex;justify-content:space-between;align-items:center;gap:18px;padding:16px;cursor:pointer;list-style:none}.control-copy{display:grid;gap:3px}.badge,.severity{border-radius:999px;padding:4px 9px;font:700 10px ui-monospace,monospace;text-transform:uppercase}.safe .badge{color:var(--green);background:var(--green-bg)}.risk .badge,.severity{color:var(--red);background:var(--red-bg)}.review .badge{color:var(--amber);background:var(--amber-bg)}.control-detail{padding:0 16px 18px;border-top:1px solid var(--line)}.facts{display:grid;grid-template-columns:repeat(3,minmax(140px,1fr));gap:14px;margin:14px 0;padding:14px;background:var(--bg);border-radius:10px}.facts div{display:grid;gap:3px}.verified,.findings{margin-top:14px}.verified p{margin:5px 0}.finding{margin-top:9px;padding:13px;border:1px solid var(--line);border-radius:9px}.finding-title{display:flex;justify-content:space-between;gap:10px}.finding p{margin:6px 0}.message{color:var(--text)!important}footer{margin-top:28px;padding-top:18px;border-top:1px solid var(--line);color:var(--muted);font-size:12px}@media(max-width:680px){.facts{grid-template-columns:1fr}.nodes{display:grid}.node{max-width:none}.row{display:block}}
|
|
14755
14771
|
</style></head><body><main class="wrap">
|
|
14756
14772
|
<div class="eyebrow">Prooflane \xB7 Hosted Security Campaign</div>
|
|
14757
14773
|
<h1>${escapeHtml3(campaign.name)}</h1>
|
|
14758
14774
|
<p>${escapeHtml3(campaign.objective)}</p>
|
|
14759
14775
|
<p><strong>Outcome question:</strong> ${escapeHtml3(campaign.outcomeQuestion)}</p>
|
|
14760
|
-
<section class="
|
|
14761
|
-
|
|
14762
|
-
|
|
14763
|
-
|
|
14764
|
-
|
|
14765
|
-
</section>
|
|
14776
|
+
<section class="status ${statusTone}"><strong>${escapeHtml3(statusCopy)}</strong><span>${escapeHtml3(tally)}</span></section>
|
|
14777
|
+
<p>Independent signed controls, grouped by what they test \u2014 not one execution. A held control never gates another.</p>
|
|
14778
|
+
${agent.length ? `<section class="attribution"><b>Attribution</b><p>Agent-behavior findings test the configured model with a <strong>Prooflane-synthesized probe</strong>. They are not evidence that ${escapeHtml3(scan.target.name)} supplied malicious content or that a server boundary was crossed without corresponding MCP evidence.</p></section>` : ""}
|
|
14779
|
+
${containment.length ? `<section class="graph-group"><h2>Containment controls</h2><p>Probed directly against ${escapeHtml3(scan.target.name)}. A reachable tool is exposed surface; only objective evidence is a verified breach.</p><div class="nodes">${containment.map(graphNode).join("")}</div></section>` : ""}
|
|
14780
|
+
${agent.length ? `<section class="graph-group"><h2>Agent behavior \xB7 synthetic probe</h2><p>Measures the configured model/client under a Prooflane-authored scenario. A refusal is safe behavior; a failure is a model finding.</p><div class="nodes">${agent.map(graphNode).join("")}</div></section>` : ""}
|
|
14781
|
+
<section class="objective ${scan.summary.breached > 0 ? "risk" : "safe"}">${scan.summary.breached > 0 ? "\u2717" : "\u2713"} ${escapeHtml3(campaign.objectiveLabel)} \u2014 ${scan.summary.breached > 0 ? "REACHED" : "NOT REACHED"}</section>
|
|
14782
|
+
<h2 class="details-title">Detailed security report</h2>
|
|
14766
14783
|
<section>${controls}</section>
|
|
14767
14784
|
<footer>Scan ${escapeHtml3(scan.id)} \xB7 ${escapeHtml3(scan.target.name)} \xB7 ${escapeHtml3(scan.status)} \xB7 ${escapeHtml3(generatedAt)}<br>Report contains compact signed-control results only. Raw prompts, responses, retrieved data, and credentials remained on the local Runner.</footer>
|
|
14768
14785
|
</main></body></html>`;
|