openpitstop 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +512 -0
- package/demo-repo/README.md +24 -0
- package/demo-repo/package-lock.json +4483 -0
- package/demo-repo/package.json +17 -0
- package/demo-repo/src/config.js +5 -0
- package/demo-repo/src/db.js +31 -0
- package/demo-repo/src/server.js +13 -0
- package/demo-repo/src/userController.js +22 -0
- package/demo-repo/src/userRepo.js +18 -0
- package/demo-repo/src/userService.js +59 -0
- package/demo-repo/test/user.test.js +12 -0
- package/demo-repo-fintech/README.md +27 -0
- package/demo-repo-fintech/package-lock.json +1023 -0
- package/demo-repo-fintech/package.json +14 -0
- package/demo-repo-fintech/pitstop-repro-ledger-order-ord-conc-1-charged-2.test.mjs +175 -0
- package/demo-repo-fintech/pitstop-repro-ledger-order-ord-retry-2-charged-2.test.mjs +175 -0
- package/demo-repo-fintech/pitstop-repro-ledger-order-ord-webhook-3-charged-2.test.mjs +175 -0
- package/demo-repo-fintech/src/gateway.js +26 -0
- package/demo-repo-fintech/src/server.js +61 -0
- package/demo-repo-generators/package-lock.json +1508 -0
- package/demo-repo-generators/package.json +17 -0
- package/demo-repo-generators/public/index.html +10 -0
- package/demo-repo-generators/scripts/build.js +17 -0
- package/demo-repo-generators/src/counter.js +16 -0
- package/demo-repo-integrity/README.md +49 -0
- package/demo-repo-integrity/package.json +12 -0
- package/demo-repo-integrity/src/money.js +19 -0
- package/demo-repo-integrity/test/money.test.js +17 -0
- package/dist/analyzers/accessibility.d.ts +18 -0
- package/dist/analyzers/accessibility.js +248 -0
- package/dist/analyzers/accessibility.js.map +1 -0
- package/dist/analyzers/dependencyGraph.d.ts +14 -0
- package/dist/analyzers/dependencyGraph.js +206 -0
- package/dist/analyzers/dependencyGraph.js.map +1 -0
- package/dist/analyzers/devex.d.ts +19 -0
- package/dist/analyzers/devex.js +301 -0
- package/dist/analyzers/devex.js.map +1 -0
- package/dist/analyzers/duplication.d.ts +2 -0
- package/dist/analyzers/duplication.js +47 -0
- package/dist/analyzers/duplication.js.map +1 -0
- package/dist/analyzers/index.d.ts +12 -0
- package/dist/analyzers/index.js +38 -0
- package/dist/analyzers/index.js.map +1 -0
- package/dist/analyzers/integrity/assertionLiteralTamper.d.ts +2 -0
- package/dist/analyzers/integrity/assertionLiteralTamper.js +164 -0
- package/dist/analyzers/integrity/assertionLiteralTamper.js.map +1 -0
- package/dist/analyzers/integrity/exceptionSwallow.d.ts +2 -0
- package/dist/analyzers/integrity/exceptionSwallow.js +198 -0
- package/dist/analyzers/integrity/exceptionSwallow.js.map +1 -0
- package/dist/analyzers/integrity/exitCheat.d.ts +2 -0
- package/dist/analyzers/integrity/exitCheat.js +31 -0
- package/dist/analyzers/integrity/exitCheat.js.map +1 -0
- package/dist/analyzers/integrity/git.d.ts +10 -0
- package/dist/analyzers/integrity/git.js +181 -0
- package/dist/analyzers/integrity/git.js.map +1 -0
- package/dist/analyzers/integrity/hardcodedMatch.d.ts +2 -0
- package/dist/analyzers/integrity/hardcodedMatch.js +93 -0
- package/dist/analyzers/integrity/hardcodedMatch.js.map +1 -0
- package/dist/analyzers/integrity/helpers.d.ts +21 -0
- package/dist/analyzers/integrity/helpers.js +66 -0
- package/dist/analyzers/integrity/helpers.js.map +1 -0
- package/dist/analyzers/integrity/index.d.ts +10 -0
- package/dist/analyzers/integrity/index.js +27 -0
- package/dist/analyzers/integrity/index.js.map +1 -0
- package/dist/analyzers/integrity/mockOverreach.d.ts +2 -0
- package/dist/analyzers/integrity/mockOverreach.js +72 -0
- package/dist/analyzers/integrity/mockOverreach.js.map +1 -0
- package/dist/analyzers/integrity/suppressionCreep.d.ts +2 -0
- package/dist/analyzers/integrity/suppressionCreep.js +27 -0
- package/dist/analyzers/integrity/suppressionCreep.js.map +1 -0
- package/dist/analyzers/integrity/testTamper.d.ts +2 -0
- package/dist/analyzers/integrity/testTamper.js +153 -0
- package/dist/analyzers/integrity/testTamper.js.map +1 -0
- package/dist/analyzers/integrity/types.d.ts +63 -0
- package/dist/analyzers/integrity/types.js +13 -0
- package/dist/analyzers/integrity/types.js.map +1 -0
- package/dist/analyzers/ledger/attacks.d.ts +17 -0
- package/dist/analyzers/ledger/attacks.js +135 -0
- package/dist/analyzers/ledger/attacks.js.map +1 -0
- package/dist/analyzers/ledger/discover.d.ts +15 -0
- package/dist/analyzers/ledger/discover.js +122 -0
- package/dist/analyzers/ledger/discover.js.map +1 -0
- package/dist/analyzers/ledger/evidence.d.ts +22 -0
- package/dist/analyzers/ledger/evidence.js +127 -0
- package/dist/analyzers/ledger/evidence.js.map +1 -0
- package/dist/analyzers/ledger/harness.d.ts +4 -0
- package/dist/analyzers/ledger/harness.js +270 -0
- package/dist/analyzers/ledger/harness.js.map +1 -0
- package/dist/analyzers/ledger/index.d.ts +14 -0
- package/dist/analyzers/ledger/index.js +116 -0
- package/dist/analyzers/ledger/index.js.map +1 -0
- package/dist/analyzers/ledger/types.d.ts +31 -0
- package/dist/analyzers/ledger/types.js +2 -0
- package/dist/analyzers/ledger/types.js.map +1 -0
- package/dist/analyzers/perf.d.ts +2 -0
- package/dist/analyzers/perf.js +106 -0
- package/dist/analyzers/perf.js.map +1 -0
- package/dist/analyzers/reliability.d.ts +22 -0
- package/dist/analyzers/reliability.js +339 -0
- package/dist/analyzers/reliability.js.map +1 -0
- package/dist/analyzers/routes.d.ts +17 -0
- package/dist/analyzers/routes.js +115 -0
- package/dist/analyzers/routes.js.map +1 -0
- package/dist/analyzers/security.d.ts +2 -0
- package/dist/analyzers/security.js +302 -0
- package/dist/analyzers/security.js.map +1 -0
- package/dist/analyzers/suiteRunner.d.ts +64 -0
- package/dist/analyzers/suiteRunner.js +381 -0
- package/dist/analyzers/suiteRunner.js.map +1 -0
- package/dist/analyzers/tests.d.ts +2 -0
- package/dist/analyzers/tests.js +215 -0
- package/dist/analyzers/tests.js.map +1 -0
- package/dist/analyzers/types.d.ts +203 -0
- package/dist/analyzers/types.js +2 -0
- package/dist/analyzers/types.js.map +1 -0
- package/dist/analyzers/util.d.ts +35 -0
- package/dist/analyzers/util.js +209 -0
- package/dist/analyzers/util.js.map +1 -0
- package/dist/ciCheckA.d.ts +2 -0
- package/dist/ciCheckA.js +5 -0
- package/dist/ciCheckA.js.map +1 -0
- package/dist/ciCheckB.d.ts +2 -0
- package/dist/ciCheckB.js +6 -0
- package/dist/ciCheckB.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +65 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/budget.d.ts +33 -0
- package/dist/commands/budget.js +108 -0
- package/dist/commands/budget.js.map +1 -0
- package/dist/commands/ci.d.ts +14 -0
- package/dist/commands/ci.js +157 -0
- package/dist/commands/ci.js.map +1 -0
- package/dist/commands/demo.d.ts +2 -0
- package/dist/commands/demo.js +163 -0
- package/dist/commands/demo.js.map +1 -0
- package/dist/commands/digest.d.ts +8 -0
- package/dist/commands/digest.js +189 -0
- package/dist/commands/digest.js.map +1 -0
- package/dist/commands/doctor.d.ts +2 -0
- package/dist/commands/doctor.js +98 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/drive.d.ts +3 -0
- package/dist/commands/drive.js +170 -0
- package/dist/commands/drive.js.map +1 -0
- package/dist/commands/gate.d.ts +2 -0
- package/dist/commands/gate.js +136 -0
- package/dist/commands/gate.js.map +1 -0
- package/dist/commands/honesty.d.ts +2 -0
- package/dist/commands/honesty.js +182 -0
- package/dist/commands/honesty.js.map +1 -0
- package/dist/commands/inspect.d.ts +2 -0
- package/dist/commands/inspect.js +244 -0
- package/dist/commands/inspect.js.map +1 -0
- package/dist/commands/install.d.ts +2 -0
- package/dist/commands/install.js +81 -0
- package/dist/commands/install.js.map +1 -0
- package/dist/commands/integrity.d.ts +2 -0
- package/dist/commands/integrity.js +74 -0
- package/dist/commands/integrity.js.map +1 -0
- package/dist/commands/memory.d.ts +6 -0
- package/dist/commands/memory.js +90 -0
- package/dist/commands/memory.js.map +1 -0
- package/dist/commands/pen.d.ts +17 -0
- package/dist/commands/pen.js +158 -0
- package/dist/commands/pen.js.map +1 -0
- package/dist/commands/prompt.d.ts +2 -0
- package/dist/commands/prompt.js +37 -0
- package/dist/commands/prompt.js.map +1 -0
- package/dist/commands/readyCheck.d.ts +21 -0
- package/dist/commands/readyCheck.js +68 -0
- package/dist/commands/readyCheck.js.map +1 -0
- package/dist/commands/report.d.ts +2 -0
- package/dist/commands/report.js +48 -0
- package/dist/commands/report.js.map +1 -0
- package/dist/commands/repro.d.ts +3 -0
- package/dist/commands/repro.js +61 -0
- package/dist/commands/repro.js.map +1 -0
- package/dist/commands/scan.d.ts +27 -0
- package/dist/commands/scan.js +348 -0
- package/dist/commands/scan.js.map +1 -0
- package/dist/commands/share.d.ts +2 -0
- package/dist/commands/share.js +163 -0
- package/dist/commands/share.js.map +1 -0
- package/dist/commands/trends.d.ts +2 -0
- package/dist/commands/trends.js +103 -0
- package/dist/commands/trends.js.map +1 -0
- package/dist/commands/try.d.ts +12 -0
- package/dist/commands/try.js +208 -0
- package/dist/commands/try.js.map +1 -0
- package/dist/commands/verify.d.ts +44 -0
- package/dist/commands/verify.js +381 -0
- package/dist/commands/verify.js.map +1 -0
- package/dist/commands/watch.d.ts +10 -0
- package/dist/commands/watch.js +70 -0
- package/dist/commands/watch.js.map +1 -0
- package/dist/evidence.d.ts +37 -0
- package/dist/evidence.js +61 -0
- package/dist/evidence.js.map +1 -0
- package/dist/graph/correlate.d.ts +7 -0
- package/dist/graph/correlate.js +246 -0
- package/dist/graph/correlate.js.map +1 -0
- package/dist/graph/integrity.d.ts +22 -0
- package/dist/graph/integrity.js +39 -0
- package/dist/graph/integrity.js.map +1 -0
- package/dist/installer/targets.d.ts +23 -0
- package/dist/installer/targets.js +162 -0
- package/dist/installer/targets.js.map +1 -0
- package/dist/memory/store.d.ts +33 -0
- package/dist/memory/store.js +131 -0
- package/dist/memory/store.js.map +1 -0
- package/dist/pen/dynamic.d.ts +36 -0
- package/dist/pen/dynamic.js +622 -0
- package/dist/pen/dynamic.js.map +1 -0
- package/dist/pen/fix.d.ts +35 -0
- package/dist/pen/fix.js +239 -0
- package/dist/pen/fix.js.map +1 -0
- package/dist/pen/proof.d.ts +46 -0
- package/dist/pen/proof.js +112 -0
- package/dist/pen/proof.js.map +1 -0
- package/dist/pen/report.d.ts +11 -0
- package/dist/pen/report.js +258 -0
- package/dist/pen/report.js.map +1 -0
- package/dist/pen/static.d.ts +17 -0
- package/dist/pen/static.js +565 -0
- package/dist/pen/static.js.map +1 -0
- package/dist/pen/store.d.ts +11 -0
- package/dist/pen/store.js +36 -0
- package/dist/pen/store.js.map +1 -0
- package/dist/pen/types.d.ts +112 -0
- package/dist/pen/types.js +53 -0
- package/dist/pen/types.js.map +1 -0
- package/dist/report/format.d.ts +126 -0
- package/dist/report/format.js +706 -0
- package/dist/report/format.js.map +1 -0
- package/dist/report/score.d.ts +47 -0
- package/dist/report/score.js +164 -0
- package/dist/report/score.js.map +1 -0
- package/dist/repro/framework.d.ts +26 -0
- package/dist/repro/framework.js +224 -0
- package/dist/repro/framework.js.map +1 -0
- package/dist/repro/generate.d.ts +14 -0
- package/dist/repro/generate.js +669 -0
- package/dist/repro/generate.js.map +1 -0
- package/dist/repro/ids.d.ts +32 -0
- package/dist/repro/ids.js +175 -0
- package/dist/repro/ids.js.map +1 -0
- package/dist/repro/index.d.ts +24 -0
- package/dist/repro/index.js +69 -0
- package/dist/repro/index.js.map +1 -0
- package/dist/repro/pen.d.ts +26 -0
- package/dist/repro/pen.js +321 -0
- package/dist/repro/pen.js.map +1 -0
- package/dist/repro/run.d.ts +18 -0
- package/dist/repro/run.js +36 -0
- package/dist/repro/run.js.map +1 -0
- package/dist/sandbox/proxy.d.ts +41 -0
- package/dist/sandbox/proxy.js +231 -0
- package/dist/sandbox/proxy.js.map +1 -0
- package/dist/sandbox/startCmd.d.ts +24 -0
- package/dist/sandbox/startCmd.js +71 -0
- package/dist/sandbox/startCmd.js.map +1 -0
- package/dist/ui/spinner.d.ts +18 -0
- package/dist/ui/spinner.js +26 -0
- package/dist/ui/spinner.js.map +1 -0
- package/dist/verify/metrics.d.ts +13 -0
- package/dist/verify/metrics.js +72 -0
- package/dist/verify/metrics.js.map +1 -0
- package/package.json +68 -0
- package/scripts/cheat-demo.cjs +102 -0
- package/templates/ledger/preload.cjs +331 -0
- package/templates/pen/preload.cjs +196 -0
- package/templates/pitstop.prompt.md +371 -0
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import boxen from "boxen";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { runVerify } from "./verify.js";
|
|
6
|
+
/**
|
|
7
|
+
* `pitstop gate` — the agentless, CI-usable gate. One command answers "is this
|
|
8
|
+
* change safe to commit?" with a plain exit code:
|
|
9
|
+
*
|
|
10
|
+
* exit 0 PASS — score >= threshold, integrity clean, evidence chain intact
|
|
11
|
+
* exit 1 FAIL — score below threshold, High regression risk, SUSPICIOUS
|
|
12
|
+
* integrity, or tampered evidence
|
|
13
|
+
* exit 2 FAIL-HARD — CONFIRMED_CHEAT integrity violation
|
|
14
|
+
*
|
|
15
|
+
* No AI tool, no `/pitstop` loop, no config: scan (or try) once for the
|
|
16
|
+
* baseline, then `pitstop gate` every step of a fix loop — also usable as a
|
|
17
|
+
* pre-commit hook or the last line of a CI job.
|
|
18
|
+
*/
|
|
19
|
+
function gateOutcome(o, threshold) {
|
|
20
|
+
if (o.missingBaseline) {
|
|
21
|
+
return {
|
|
22
|
+
pass: false,
|
|
23
|
+
exitCode: 1,
|
|
24
|
+
reasons: ["no baseline — run `pitstop scan` (or `pitstop try`) once to create one"],
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
const reasons = [];
|
|
28
|
+
let exitCode = 0;
|
|
29
|
+
if (o.blocked) {
|
|
30
|
+
if (o.integrity.verdict === "CONFIRMED_CHEAT") {
|
|
31
|
+
reasons.push(`integrity gate CONFIRMED_CHEAT (${o.integrity.summary.confirmed} confirmed findings)`);
|
|
32
|
+
exitCode = 2;
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
reasons.push(`integrity gate ${o.integrity.verdict} — needs human review before committing`);
|
|
36
|
+
exitCode = 1;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
if (o.evidence?.status === "tampered") {
|
|
40
|
+
reasons.push("evidence chain broken — baseline was edited after OpenPitStop signed it; re-run `pitstop scan`");
|
|
41
|
+
exitCode = Math.max(exitCode, 1);
|
|
42
|
+
}
|
|
43
|
+
if (o.risk === "High") {
|
|
44
|
+
reasons.push("regression risk High — suite or perf regressed vs baseline");
|
|
45
|
+
exitCode = Math.max(exitCode, 1);
|
|
46
|
+
}
|
|
47
|
+
if (o.currentScore.score < threshold) {
|
|
48
|
+
reasons.push(`OpenPitStop Score ${o.currentScore.score}/100 is below the ${threshold}/100 gate`);
|
|
49
|
+
exitCode = Math.max(exitCode, 1);
|
|
50
|
+
}
|
|
51
|
+
if (o.stale) {
|
|
52
|
+
reasons.push(`⚠ ${o.staleNote}`);
|
|
53
|
+
}
|
|
54
|
+
return { pass: exitCode === 0, exitCode, reasons };
|
|
55
|
+
}
|
|
56
|
+
function renderGateBox(o, gate, threshold) {
|
|
57
|
+
const score = o.currentScore;
|
|
58
|
+
const scorePaint = score.score >= threshold ? chalk.greenBright : chalk.red;
|
|
59
|
+
const lines = [];
|
|
60
|
+
lines.push(`${chalk.bold("OpenPitStop Score")}: ${scorePaint.bold(`${score.score}/100 (${score.grade})`)} — gate at ${threshold}/100`);
|
|
61
|
+
lines.push(`${chalk.bold("Integrity")}: ${o.blocked
|
|
62
|
+
? chalk.red(o.integrity.verdict)
|
|
63
|
+
: chalk.green(o.integrity.verdict)} · ${o.integrity.summary.total} finding(s)`);
|
|
64
|
+
lines.push(`${chalk.bold("Evidence")}: ${o.evidence?.status === "verified"
|
|
65
|
+
? chalk.green(`verified ${o.evidence.digest.slice(0, 12)}…`)
|
|
66
|
+
: o.evidence?.status === "tampered"
|
|
67
|
+
? chalk.red("TAMPERED")
|
|
68
|
+
: chalk.yellow("untracked (pre-0.6.0 baseline)")}`);
|
|
69
|
+
lines.push(`${chalk.bold("Risk")}: ${o.risk === "High" ? chalk.red("HIGH") : o.risk === "Medium" ? chalk.yellow("MEDIUM") : chalk.green("LOW")}`);
|
|
70
|
+
if (gate.reasons.length > 0) {
|
|
71
|
+
lines.push("");
|
|
72
|
+
for (const r of gate.reasons)
|
|
73
|
+
lines.push(r.startsWith("⚠") ? chalk.yellow(r) : chalk.red(`✗ ${r}`));
|
|
74
|
+
}
|
|
75
|
+
if (gate.pass) {
|
|
76
|
+
lines.push("");
|
|
77
|
+
lines.push(chalk.green("PASS — safe to commit."));
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
lines.push("");
|
|
81
|
+
lines.push(chalk.red("FAIL — do not commit this state."));
|
|
82
|
+
}
|
|
83
|
+
return boxen(lines.join("\n"), {
|
|
84
|
+
title: ` PITSTOP — GATE ${gate.pass ? "PASS" : "FAIL"} `,
|
|
85
|
+
titleAlignment: "center",
|
|
86
|
+
borderStyle: gate.pass ? "round" : "double",
|
|
87
|
+
padding: 1,
|
|
88
|
+
borderColor: gate.pass ? "green" : exitCodeColor(gate.exitCode),
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
function exitCodeColor(code) {
|
|
92
|
+
return code >= 2 ? "red" : "yellow";
|
|
93
|
+
}
|
|
94
|
+
export const gate = new Command("gate")
|
|
95
|
+
.description("Agentless commit gate: verifies score vs threshold, regression risk, integrity diff and " +
|
|
96
|
+
"the baseline evidence signature — exit 0=PASS, 1=FAIL, 2=CONFIRMED_CHEAT. CI and " +
|
|
97
|
+
"pre-commit ready; no AI tool required.")
|
|
98
|
+
.argument("[repo]", "path to the repo to gate (default: current dir)", ".")
|
|
99
|
+
.option("--score <n>", "minimum OpenPitStop Score required to pass (default 60; 0 disables the score check)", "60")
|
|
100
|
+
.option("--json", "print a machine-readable gate result")
|
|
101
|
+
.action(async (repoArg, options) => {
|
|
102
|
+
const repo = path.resolve(repoArg);
|
|
103
|
+
const threshold = Math.max(0, Math.min(100, Math.floor(Number(options.score) || 60)));
|
|
104
|
+
if (!options.json) {
|
|
105
|
+
console.log(chalk.cyan(`\nGating ${repo} (score >= ${threshold}/100) ...\n`));
|
|
106
|
+
}
|
|
107
|
+
const outcome = await runVerify(repo);
|
|
108
|
+
const gateResult = gateOutcome(outcome, threshold);
|
|
109
|
+
if (options.json) {
|
|
110
|
+
console.log(JSON.stringify({
|
|
111
|
+
repo,
|
|
112
|
+
pass: gateResult.pass,
|
|
113
|
+
exitCode: gateResult.exitCode,
|
|
114
|
+
reasons: gateResult.reasons,
|
|
115
|
+
threshold,
|
|
116
|
+
score: outcome.missingBaseline ? null : outcome.currentScore.score,
|
|
117
|
+
grade: outcome.missingBaseline ? null : outcome.currentScore.grade,
|
|
118
|
+
risk: outcome.missingBaseline ? null : outcome.risk,
|
|
119
|
+
integrity: outcome.missingBaseline ? null : outcome.integrity.verdict,
|
|
120
|
+
evidence: outcome.evidence?.status ?? "missing",
|
|
121
|
+
stale: outcome.stale,
|
|
122
|
+
baselineTimestamp: outcome.baselineTimestamp ?? null,
|
|
123
|
+
}, null, 2));
|
|
124
|
+
}
|
|
125
|
+
else if (outcome.missingBaseline) {
|
|
126
|
+
console.log(chalk.red(`no baseline found — run \`pitstop scan\` (or \`pitstop try\`) once to create one`));
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
console.log(renderGateBox(outcome, gateResult, threshold));
|
|
130
|
+
if (outcome.file) {
|
|
131
|
+
console.log(chalk.dim(`\nVerify report written to ${outcome.file}\n`));
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
process.exitCode = gateResult.exitCode;
|
|
135
|
+
});
|
|
136
|
+
//# sourceMappingURL=gate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gate.js","sourceRoot":"","sources":["../../src/commands/gate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import boxen from "boxen";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import fs from "node:fs";
|
|
6
|
+
import { buildModel, escapeHtml, loadHistory, loadProofs } from "../report/format.js";
|
|
7
|
+
import { computeScore, gradeHex } from "../report/score.js";
|
|
8
|
+
import { checkEvidence } from "../evidence.js";
|
|
9
|
+
import { enumerateFindings } from "../repro/ids.js";
|
|
10
|
+
/**
|
|
11
|
+
* `pitstop honesty` — the proof that the AI agent did honest work.
|
|
12
|
+
*
|
|
13
|
+
* Combines the evidence chain (signed baselines), the integrity gate history
|
|
14
|
+
* (cheat attempts caught + self-corrected), the verify delta, and the
|
|
15
|
+
* committed repro tests — and states, plainly, whether the recorded work is
|
|
16
|
+
* trustworthy. `--html` writes a self-contained shareable certificate.
|
|
17
|
+
*/
|
|
18
|
+
function honestyVerdict(args) {
|
|
19
|
+
const reasons = [];
|
|
20
|
+
if (args.confirmedCheats > 0) {
|
|
21
|
+
reasons.push("a CONFIRMED_CHEAT integrity violation is on record");
|
|
22
|
+
return { label: "UNDER REVIEW — cheating attempted", color: "red", reasons };
|
|
23
|
+
}
|
|
24
|
+
if (args.evidence === "tampered") {
|
|
25
|
+
reasons.push("the baseline evidence chain is broken — reports were edited after OpenPitStop signed them");
|
|
26
|
+
return { label: "SUSPICIOUS — evidence edited", color: "red", reasons };
|
|
27
|
+
}
|
|
28
|
+
if (args.latestVerify?.risk === "High") {
|
|
29
|
+
reasons.push("latest verify shows High regression risk");
|
|
30
|
+
return { label: "HONEST BUT RISKY", color: "yellow", reasons };
|
|
31
|
+
}
|
|
32
|
+
if (args.integrityChecks > 0 && args.integrityCatches > 0) {
|
|
33
|
+
reasons.push(`${args.integrityCatches} attempted cheat(s) caught and blocked — the gate worked`);
|
|
34
|
+
}
|
|
35
|
+
if (args.evidence === "untracked") {
|
|
36
|
+
reasons.push("baseline predates evidence signing (pre-0.6.0) — re-scan for a signed chain");
|
|
37
|
+
return { label: "HONEST (unsigned evidence)", color: "yellow", reasons };
|
|
38
|
+
}
|
|
39
|
+
if (args.proofs === 0) {
|
|
40
|
+
reasons.push("no committed repro tests — fixes were not captured as failing-then-passing proof");
|
|
41
|
+
}
|
|
42
|
+
reasons.push("all checks passed: evidence verified, integrity clean, no regressions");
|
|
43
|
+
return { label: "HONEST ✓", color: "green", reasons };
|
|
44
|
+
}
|
|
45
|
+
export const honesty = new Command("honesty")
|
|
46
|
+
.description("The AI-honesty proof report: evidence chain + integrity gate history + verify delta + committed " +
|
|
47
|
+
"repro tests, distilled into one verdict. --html writes a self-contained shareable certificate.")
|
|
48
|
+
.argument("[repo]", "path to the repo (default: current dir)", ".")
|
|
49
|
+
.option("--html", "also write a self-contained PITSTOP_HONESTY.html certificate")
|
|
50
|
+
.action((repoArg, options) => {
|
|
51
|
+
const repo = path.resolve(repoArg);
|
|
52
|
+
const model = buildModel(repo);
|
|
53
|
+
const hist = loadHistory(repo);
|
|
54
|
+
if (!model.latestScan) {
|
|
55
|
+
console.log(chalk.yellow(`no scan history in ${path.join(repo, ".pitstop")} — run \`pitstop scan\` first.`));
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
const sc = computeScore(model.latestScan);
|
|
59
|
+
const ev = checkEvidence(model.latestScan);
|
|
60
|
+
const proofs = loadProofs(repo);
|
|
61
|
+
// Which committed repro tests are still needed? A finding that no longer
|
|
62
|
+
// appears in the latest scan is permanently proven fixed; one that still
|
|
63
|
+
// appears means the proof exists but the fix is not in yet.
|
|
64
|
+
const liveIds = new Set(enumerateFindings(model.latestScan).map((f) => f.id));
|
|
65
|
+
const proved = proofs.filter((p) => p.findingId && !liveIds.has(p.findingId));
|
|
66
|
+
const pending = proofs.filter((p) => p.findingId && liveIds.has(p.findingId));
|
|
67
|
+
const integ = model.integrity;
|
|
68
|
+
const confirmedCheats = integ?.events.filter((e) => e.verdict === "CONFIRMED_CHEAT").length ?? 0;
|
|
69
|
+
const verdict = honestyVerdict({
|
|
70
|
+
evidence: ev.status,
|
|
71
|
+
latestVerify: model.latestVerify,
|
|
72
|
+
integrityChecks: integ?.checks ?? 0,
|
|
73
|
+
integrityCatches: integ?.catches ?? 0,
|
|
74
|
+
confirmedCheats,
|
|
75
|
+
proofs: proofs.length,
|
|
76
|
+
});
|
|
77
|
+
const vpaint = verdict.color === "green" ? chalk.green : verdict.color === "yellow" ? chalk.yellow : chalk.red;
|
|
78
|
+
const lines = [];
|
|
79
|
+
lines.push(`${chalk.bold("Verdict")}: ${vpaint.bold(verdict.label)}`);
|
|
80
|
+
lines.push("");
|
|
81
|
+
lines.push(`${chalk.bold("Evidence chain")}: ${ev.status === "verified" ? chalk.green(`verified — ${ev.digest.slice(0, 16)}…`) : ev.status === "tampered" ? chalk.red("TAMPERED") : chalk.yellow("untracked")}`);
|
|
82
|
+
lines.push(`${chalk.bold("Integrity gate")}: ${integ
|
|
83
|
+
? `${integ.checks} check(s) · ${integ.catches} catch(es) · ${chalk.green(`${integ.selfCorrected} self-corrected`)}${confirmedCheats > 0 ? ` · ${chalk.red(`${confirmedCheats} CONFIRMED_CHEAT`)}` : ""}`
|
|
84
|
+
: chalk.dim("no checks recorded")}`);
|
|
85
|
+
lines.push(`${chalk.bold("Score")}: ${vpaint(`${sc.score}/100 (${sc.grade})`)}${model.latestVerify?.score
|
|
86
|
+
? ` · verify delta ${model.latestVerify.score.delta > 0 ? "+" : ""}${model.latestVerify.score.delta} pts · risk ${model.latestVerify.risk}`
|
|
87
|
+
: ""}`);
|
|
88
|
+
lines.push(`${chalk.bold("Permanent proof")}: ${proved.length > 0
|
|
89
|
+
? chalk.green(`${proved.length} finding(s) proven fixed (repro test committed, finding gone)`)
|
|
90
|
+
: chalk.yellow("none proven fixed yet")}${pending.length > 0 ? chalk.dim(` · ${pending.length} repro test(s) with the finding still open`) : ""}`);
|
|
91
|
+
lines.push("");
|
|
92
|
+
lines.push(chalk.bold("Why:"));
|
|
93
|
+
for (const r of verdict.reasons)
|
|
94
|
+
lines.push(` · ${r.startsWith("all checks") ? chalk.green(r) : chalk.yellow(r)}`);
|
|
95
|
+
lines.push("");
|
|
96
|
+
lines.push(chalk.dim("every figure is read from .pitstop/scan-*.json, verify-*.json and the committed pitstop-repro-*.test.* files"));
|
|
97
|
+
const color = verdict.color === "green" ? "green" : "yellow";
|
|
98
|
+
console.log(boxen(lines.join("\n"), {
|
|
99
|
+
title: ` PITSTOP — Honesty ${verdict.label.split(" ")[0]} `,
|
|
100
|
+
titleAlignment: "center",
|
|
101
|
+
borderStyle: verdict.color === "green" ? "round" : "double",
|
|
102
|
+
padding: 1,
|
|
103
|
+
borderColor: verdict.color === "red" ? "red" : color,
|
|
104
|
+
}));
|
|
105
|
+
if (options.html) {
|
|
106
|
+
const accent = gradeHex(sc.grade);
|
|
107
|
+
const badge = `background:${accent};color:#0d1117;font-weight:800;font-size:56px;padding:18px 30px;border-radius:16px`;
|
|
108
|
+
const html = `<!DOCTYPE html>
|
|
109
|
+
<html lang="en">
|
|
110
|
+
<head>
|
|
111
|
+
<meta charset="utf-8"/>
|
|
112
|
+
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
|
113
|
+
<title>PITSTOP — Honesty report for ${escapeHtml(repo)}</title>
|
|
114
|
+
<style>
|
|
115
|
+
:root{color-scheme:dark}
|
|
116
|
+
*{box-sizing:border-box;margin:0;padding:0}
|
|
117
|
+
body{background:#0d1117;color:#e6edf3;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;padding:48px 24px}
|
|
118
|
+
.wrap{max-width:760px;margin:0 auto}
|
|
119
|
+
h1{font-size:22px;margin-bottom:4px}
|
|
120
|
+
.sub{color:#8b949e;font-size:13px;margin-bottom:28px}
|
|
121
|
+
.card{background:#161b22;border:1px solid #30363d;border-radius:14px;padding:24px;margin-bottom:18px}
|
|
122
|
+
.verdict{font-size:28px;font-weight:800;color:${verdict.color === "green" ? "#3fb950" : verdict.color === "yellow" ? "#d29922" : "#f85149"};margin-bottom:10px}
|
|
123
|
+
.scoreline{display:flex;align-items:center;gap:22px;flex-wrap:wrap}
|
|
124
|
+
.score{${badge}}
|
|
125
|
+
.meta{color:#8b949e;font-size:14px;line-height:1.7}
|
|
126
|
+
.meta b{color:#e6edf3}
|
|
127
|
+
table{width:100%;border-collapse:collapse;font-size:14px}
|
|
128
|
+
th,td{text-align:left;padding:9px 12px;border-bottom:1px solid #21262d}
|
|
129
|
+
th{color:#8b949e;font-weight:600;font-size:12px;text-transform:uppercase;letter-spacing:0.4px}
|
|
130
|
+
.ok{color:#3fb950;font-weight:600}
|
|
131
|
+
.warn{color:#d29922;font-weight:600}
|
|
132
|
+
.bad{color:#f85149;font-weight:600}
|
|
133
|
+
ul{list-style:none;padding:0}
|
|
134
|
+
li{padding:7px 0;border-bottom:1px solid #21262d;font-size:14px}
|
|
135
|
+
li:last-child{border-bottom:none}
|
|
136
|
+
.footer{color:#8b949e;font-size:12px;margin-top:28px;text-align:center}
|
|
137
|
+
code{background:#21262d;padding:1px 6px;border-radius:5px;font-size:12px}
|
|
138
|
+
</style>
|
|
139
|
+
</head>
|
|
140
|
+
<body><div class="wrap">
|
|
141
|
+
<h1>PITSTOP — AI Honesty Report</h1>
|
|
142
|
+
<p class="sub">${escapeHtml(repo)} · generated ${escapeHtml(model.generatedAt.slice(0, 19).replace("T", " "))} · ${hist.scans.length} scan(s), ${hist.verifies.length} verify(ies)</p>
|
|
143
|
+
|
|
144
|
+
<div class="card">
|
|
145
|
+
<div class="verdict">${escapeHtml(verdict.label)}</div>
|
|
146
|
+
<div class="scoreline">
|
|
147
|
+
<div class="score">${sc.score}/100</div>
|
|
148
|
+
<div class="meta">
|
|
149
|
+
<div>grade <b>${sc.grade}</b></div>
|
|
150
|
+
${model.latestVerify?.score ? `<div>verify delta <b>${model.latestVerify.score.delta > 0 ? "+" : ""}${model.latestVerify.score.delta} pts</b> · risk <b>${model.latestVerify.risk}</b></div>` : ""}
|
|
151
|
+
<div>evidence chain: <b>${ev.status === "verified" ? "verified" : ev.status}</b></div>
|
|
152
|
+
</div>
|
|
153
|
+
</div>
|
|
154
|
+
</div>
|
|
155
|
+
|
|
156
|
+
<div class="card">
|
|
157
|
+
<table>
|
|
158
|
+
<thead><tr><th>Check</th><th>Result</th></tr></thead>
|
|
159
|
+
<tbody>
|
|
160
|
+
<tr><td>Evidence signature</td><td class="${ev.status === "verified" ? "ok" : ev.status === "tampered" ? "bad" : "warn"}">${ev.status === "verified" ? "✓ verified — " + ev.digest.slice(0, 12) + "…" : ev.status === "tampered" ? "✗ TAMPERED" : "untracked (pre-0.6.0)"}</td></tr>
|
|
161
|
+
<tr><td>Integrity gate checks</td><td>${integ?.checks ?? 0}</td></tr>
|
|
162
|
+
<tr><td>Cheat attempts caught</td><td class="${confirmedCheats > 0 ? "bad" : integ && integ.catches > 0 ? "warn" : "ok"}">${integ?.catches ?? 0}${confirmedCheats > 0 ? " · CONFIRMED_CHEAT on record" : ""}</td></tr>
|
|
163
|
+
<tr><td>Self-corrected by the loop</td><td class="ok">${integ?.selfCorrected ?? 0}</td></tr>
|
|
164
|
+
<tr><td>Findings proven fixed</td><td class="${proved.length > 0 ? "ok" : "warn"}">${proved.length}${pending.length > 0 ? ` · ${pending.length} repro test(s) with finding still open` : ""}</td></tr>
|
|
165
|
+
<tr><td>Committed repro tests</td><td>${proofs.length}</td></tr>
|
|
166
|
+
</tbody>
|
|
167
|
+
</table>
|
|
168
|
+
</div>
|
|
169
|
+
|
|
170
|
+
<div class="card">
|
|
171
|
+
<h2 style="font-size:15px;margin-bottom:10px">Why this verdict</h2>
|
|
172
|
+
<ul>${verdict.reasons.map((r) => `<li>${escapeHtml(r)}</li>`).join("")}</ul>
|
|
173
|
+
</div>
|
|
174
|
+
|
|
175
|
+
<div class="footer">Every figure read from .pitstop/scan-*.json, .pitstop/verify-*.json and the committed pitstop-repro-*.test.* files · sealed with pitstop-sha256-canonical-v1</div>
|
|
176
|
+
</div></body></html>`;
|
|
177
|
+
const out = path.join(repo, "PITSTOP_HONESTY.html");
|
|
178
|
+
fs.writeFileSync(out, html);
|
|
179
|
+
console.log(chalk.dim(`\nCertificate written to ${out}\n`));
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
//# sourceMappingURL=honesty.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"honesty.js","sourceRoot":"","sources":["../../src/commands/honesty.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import boxen from "boxen";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import fs from "node:fs";
|
|
6
|
+
import { resolveFinding } from "../repro/ids.js";
|
|
7
|
+
import { loadProofs } from "../report/format.js";
|
|
8
|
+
import { relevantEntriesForFiles } from "../memory/store.js";
|
|
9
|
+
import { loadPenLatest, resolvePenFinding } from "../pen/store.js";
|
|
10
|
+
/**
|
|
11
|
+
* `pitstop inspect <finding-id>` — deep dive on a single finding.
|
|
12
|
+
*
|
|
13
|
+
* Shows the exact code, the cluster it belongs to, whether a permanent repro
|
|
14
|
+
* test exists, and the memory OpenPitStop has about the files involved. One
|
|
15
|
+
* command from the scan box to a fully actionable picture.
|
|
16
|
+
*/
|
|
17
|
+
function latestScan(repo) {
|
|
18
|
+
const p = path.join(repo, ".pitstop", "scan-latest.json");
|
|
19
|
+
if (!fs.existsSync(p))
|
|
20
|
+
return null;
|
|
21
|
+
try {
|
|
22
|
+
return JSON.parse(fs.readFileSync(p, "utf8"));
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function severityPaint(sev) {
|
|
29
|
+
switch (sev) {
|
|
30
|
+
case "critical":
|
|
31
|
+
case "high":
|
|
32
|
+
return chalk.red;
|
|
33
|
+
case "medium":
|
|
34
|
+
return chalk.yellow;
|
|
35
|
+
default:
|
|
36
|
+
return chalk.dim;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function rel(repo, p) {
|
|
40
|
+
if (!p)
|
|
41
|
+
return "";
|
|
42
|
+
// Cluster files are stored relative to the repo; issue files are absolute.
|
|
43
|
+
if (!path.isAbsolute(p))
|
|
44
|
+
return p.replace(/\\/g, "/");
|
|
45
|
+
try {
|
|
46
|
+
return path.relative(repo, p).replace(/\\/g, "/");
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return p;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function resolve(repo, p) {
|
|
53
|
+
if (!p)
|
|
54
|
+
return null;
|
|
55
|
+
return path.isAbsolute(p) ? p : path.resolve(repo, p);
|
|
56
|
+
}
|
|
57
|
+
/** ±6 lines around the finding, target line highlighted. */
|
|
58
|
+
function codeSnippet(repo, f) {
|
|
59
|
+
const abs = resolve(repo, f.file);
|
|
60
|
+
if (!abs || !fs.existsSync(abs))
|
|
61
|
+
return [];
|
|
62
|
+
let content;
|
|
63
|
+
try {
|
|
64
|
+
content = fs.readFileSync(abs, "utf8");
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
return [];
|
|
68
|
+
}
|
|
69
|
+
const lines = content.split(/\r?\n/);
|
|
70
|
+
const hasLine = f.line != null;
|
|
71
|
+
const target = f.line ?? 1;
|
|
72
|
+
const start = Math.max(1, target - 6);
|
|
73
|
+
const end = Math.min(lines.length, target + 6);
|
|
74
|
+
const width = String(end).length;
|
|
75
|
+
const out = [];
|
|
76
|
+
for (let i = start; i <= end; i++) {
|
|
77
|
+
const gut = String(i).padStart(width);
|
|
78
|
+
const raw = lines[i - 1] ?? "";
|
|
79
|
+
const body = raw.length > 100 ? raw.slice(0, 100) + " …" : raw;
|
|
80
|
+
const isTarget = hasLine && i === target;
|
|
81
|
+
out.push(isTarget
|
|
82
|
+
? `${chalk.dim(gut + " │")} ${chalk.bgRed(chalk.black("►"))} ${chalk.bold(body)}`
|
|
83
|
+
: `${chalk.dim(gut + " │")} ${chalk.dim(body)}`);
|
|
84
|
+
}
|
|
85
|
+
return out;
|
|
86
|
+
}
|
|
87
|
+
function clusterOf(r, id) {
|
|
88
|
+
for (const c of r.clusters ?? []) {
|
|
89
|
+
const ids = [c.rootCause.id, ...c.symptoms.map((s) => s.id)].filter(Boolean);
|
|
90
|
+
if (ids.includes(id))
|
|
91
|
+
return c;
|
|
92
|
+
}
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
function memoryLines(repo, f, c) {
|
|
96
|
+
const files = c ? c.sharedFiles : f.file ? [f.file] : [];
|
|
97
|
+
if (files.length === 0)
|
|
98
|
+
return [];
|
|
99
|
+
const entries = relevantEntriesForFiles(repo, files);
|
|
100
|
+
if (entries.length === 0)
|
|
101
|
+
return [];
|
|
102
|
+
const typeColor = (e) => {
|
|
103
|
+
switch (e.type) {
|
|
104
|
+
case "decision": return chalk.cyan;
|
|
105
|
+
case "fix": return chalk.green;
|
|
106
|
+
case "rejection": return chalk.red;
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
const out = [chalk.bold("OpenPitStop memory:")];
|
|
110
|
+
for (const e of entries.slice(0, 5)) {
|
|
111
|
+
out.push(` ${typeColor(e)(e.type.toUpperCase().padEnd(9))} ${e.summary}`);
|
|
112
|
+
if (e.context)
|
|
113
|
+
out.push(` ${chalk.dim("why: " + e.context)}`);
|
|
114
|
+
}
|
|
115
|
+
return out;
|
|
116
|
+
}
|
|
117
|
+
/** Pen-finding deep dive: attack, response, sandbox evidence, fix. */
|
|
118
|
+
function renderPenInspect(repo, f) {
|
|
119
|
+
const paint = severityPaint(f.severity);
|
|
120
|
+
const lines = [];
|
|
121
|
+
lines.push(`${chalk.bold("Finding")}: ${paint(f.severity.toUpperCase())} ${chalk.bold(f.type)} · ${chalk.bold(f.confidence.toUpperCase())} · ${chalk.dim(f.id)}`);
|
|
122
|
+
const where = f.file
|
|
123
|
+
? `${rel(repo, f.file)}${f.line ? ":" + f.line : ""}`
|
|
124
|
+
: f.route
|
|
125
|
+
? `${f.route} [${f.method ?? ""}]`
|
|
126
|
+
: "no location";
|
|
127
|
+
lines.push(`${chalk.bold("Location")}: ${chalk.cyan(where)}`);
|
|
128
|
+
lines.push("");
|
|
129
|
+
lines.push(f.title);
|
|
130
|
+
lines.push("");
|
|
131
|
+
lines.push(f.description);
|
|
132
|
+
lines.push("");
|
|
133
|
+
if (f.attack) {
|
|
134
|
+
lines.push(chalk.bold("Attack fired:"), ` ${chalk.cyan(`${f.attack.method} ${f.attack.path}`)}`, f.attack.payload !== undefined ? ` payload: ${chalk.dim(JSON.stringify(f.attack.payload).slice(0, 200))}` : "");
|
|
135
|
+
}
|
|
136
|
+
if (f.response) {
|
|
137
|
+
lines.push(chalk.bold("Observed response:"), ` HTTP ${f.response.status ?? "—"}${f.response.snippet ? ` — ${f.response.snippet}` : ""}`);
|
|
138
|
+
}
|
|
139
|
+
if (f.outbound?.length) {
|
|
140
|
+
lines.push(chalk.bold("Sandbox evidence:"), ...f.outbound.map((e) => ` ${chalk.red(e)}`));
|
|
141
|
+
}
|
|
142
|
+
if (f.repro) {
|
|
143
|
+
lines.push("", chalk.bold("Reproduce by hand:"), ` ${chalk.dim(f.repro)}`);
|
|
144
|
+
}
|
|
145
|
+
lines.push("");
|
|
146
|
+
if (f.fix) {
|
|
147
|
+
lines.push(chalk.bold("Fix:"), ` ${f.fix}`);
|
|
148
|
+
}
|
|
149
|
+
lines.push("");
|
|
150
|
+
lines.push(chalk.dim(`next: ${chalk.cyan(`pitstop repro ${f.id}`)} captures this as a permanent failing-then-passing test`));
|
|
151
|
+
console.log(boxen(lines.join("\n"), {
|
|
152
|
+
title: ` PITSTOP — Inspect ${f.id} `,
|
|
153
|
+
titleAlignment: "center",
|
|
154
|
+
borderStyle: "round",
|
|
155
|
+
padding: 1,
|
|
156
|
+
borderColor: paint === chalk.red ? "red" : paint === chalk.yellow ? "yellow" : "cyan",
|
|
157
|
+
}));
|
|
158
|
+
}
|
|
159
|
+
export const inspect = new Command("inspect")
|
|
160
|
+
.description("Deep-dive on a single finding id: code location, cluster context, repro proof, and OpenPitStop's memory of the files.")
|
|
161
|
+
.argument("<id>", "finding id from a scan box or .pitstop/scan-latest.json (e.g. security-19c390c6)")
|
|
162
|
+
.option("--repo <path>", "repo to inspect (defaults to cwd)", ".")
|
|
163
|
+
.action((idArg, options) => {
|
|
164
|
+
const repo = path.resolve(options.repo);
|
|
165
|
+
const id = (idArg.match(/[A-Za-z0-9]+-[A-Za-z0-9]{6,}/)?.[0] ?? idArg).trim();
|
|
166
|
+
if (!id) {
|
|
167
|
+
console.log(chalk.red(`could not parse a finding id from "${idArg}"`));
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
const result = latestScan(repo);
|
|
171
|
+
const penResult = loadPenLatest(repo);
|
|
172
|
+
if (!result && !penResult) {
|
|
173
|
+
console.log(chalk.red(`no scan found — run \`pitstop scan\` first to create .pitstop/scan-latest.json`));
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
const f = result ? resolveFinding(result, id) : null;
|
|
177
|
+
if (!f && penResult) {
|
|
178
|
+
const pf = resolvePenFinding(penResult, id);
|
|
179
|
+
if (pf) {
|
|
180
|
+
renderPenInspect(repo, pf);
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
if (!f) {
|
|
185
|
+
console.log(chalk.red(`finding "${id}" not found in scan-latest.json or pen-latest.json\n`) +
|
|
186
|
+
chalk.dim(`hint: ids look like ${chalk.cyan("security-19c390c6")}; run \`pitstop scan\` to refresh.`));
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
const c = result ? clusterOf(result, id) : null;
|
|
190
|
+
const paint = severityPaint(f.severity);
|
|
191
|
+
const loc = f.file ? `${rel(repo, f.file)}${f.line ? ":" + f.line : ""}` : "no file location";
|
|
192
|
+
const reproCapable = ["security", "a11y", "reliability", "devex", "ledger", "perf", "graph"].includes(f.source);
|
|
193
|
+
const proofs = loadProofs(repo).filter((p) => p.findingId === id);
|
|
194
|
+
const proofLines = proofs.length > 0
|
|
195
|
+
? [
|
|
196
|
+
chalk.bold("Permanent proof:"),
|
|
197
|
+
...proofs.map((p) => ` ${chalk.green("✓")} committed repro test: ${chalk.cyan(p.file)}`),
|
|
198
|
+
]
|
|
199
|
+
: [
|
|
200
|
+
`${chalk.bold("Permanent proof:")} ${chalk.yellow("none committed yet")} — run \`pitstop repro ${id}\` to capture a failing-then-passing regression test.`,
|
|
201
|
+
];
|
|
202
|
+
const lines = [];
|
|
203
|
+
lines.push(`${chalk.bold("Finding")}: ${paint(f.severity.toUpperCase())} ${chalk.bold(f.type)}`);
|
|
204
|
+
lines.push(`${chalk.bold("Location")}: ${chalk.cyan(loc)}`);
|
|
205
|
+
lines.push("");
|
|
206
|
+
lines.push(f.description);
|
|
207
|
+
lines.push("");
|
|
208
|
+
const snip = codeSnippet(repo, f);
|
|
209
|
+
if (snip.length > 0) {
|
|
210
|
+
lines.push(chalk.bold("Code:"), ...snip, "");
|
|
211
|
+
}
|
|
212
|
+
if (c) {
|
|
213
|
+
const isRoot = c.rootCause.id === id;
|
|
214
|
+
lines.push(chalk.bold("Cluster context:"), isRoot
|
|
215
|
+
? ` this is the ROOT CAUSE → ${c.symptoms.length} symptom(s) across ${c.sharedFiles.length} shared file(s)`
|
|
216
|
+
: ` symptom of → ${chalk.red(c.rootCause.severity.toUpperCase() + " " + c.rootCause.type)}: ${c.rootCause.description}`, ` shared: ${chalk.dim(c.sharedFiles.map((x) => rel(repo, x)).join(", "))}`, "");
|
|
217
|
+
}
|
|
218
|
+
if (f.source === "ledger" && f.data) {
|
|
219
|
+
const ev = f.data;
|
|
220
|
+
lines.push(chalk.bold("Ledger evidence:"), ` scenario: ${ev.scenario ?? "?"} · order: ${ev.orderId ?? "?"} · key: ${ev.idempotencyKey ?? "?"} · double-charged: ${ev.doubleCharged ? chalk.red("YES") : chalk.green("no")}`, ` gateway calls: ${ev.chargeCalls?.length ?? 0}`, "");
|
|
221
|
+
}
|
|
222
|
+
if (f.source === "perf" && f.data) {
|
|
223
|
+
const p = f.data;
|
|
224
|
+
lines.push(chalk.bold("Performance baseline:"), ` build: ${p.buildTimeMs != null ? p.buildTimeMs + " ms" : "—"} · bundle: ${p.bundleSizeBytes != null ? (p.bundleSizeBytes / 1024).toFixed(1) + " KB" : "—"}`, "");
|
|
225
|
+
}
|
|
226
|
+
lines.push(...proofLines, "");
|
|
227
|
+
const mem = memoryLines(repo, f, c);
|
|
228
|
+
if (mem.length > 0)
|
|
229
|
+
lines.push(...mem, "");
|
|
230
|
+
if (reproCapable) {
|
|
231
|
+
lines.push(chalk.dim(`next: ${chalk.cyan(`pitstop repro ${id}`)} captures this as a permanent failing-then-passing test`));
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
lines.push(chalk.dim("this finding type is diagnostic-only (no repro generator)."));
|
|
235
|
+
}
|
|
236
|
+
console.log(boxen(lines.join("\n"), {
|
|
237
|
+
title: ` PITSTOP — Inspect ${id} `,
|
|
238
|
+
titleAlignment: "center",
|
|
239
|
+
borderStyle: "round",
|
|
240
|
+
padding: 1,
|
|
241
|
+
borderColor: paint === chalk.red ? "red" : paint === chalk.yellow ? "yellow" : "cyan",
|
|
242
|
+
}));
|
|
243
|
+
});
|
|
244
|
+
//# sourceMappingURL=inspect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inspect.js","sourceRoot":"","sources":["../../src/commands/inspect.ts"],"names":[],"mappings":"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"}
|