openpitstop 1.5.0 → 1.5.1
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/README.md +25 -0
- package/demo/web-app-broken/.pitstop/cache/jest/haste-map-09bbba084113da9182b28b169fd19719-a1b56e2f04426a89a1864d67162ba1a1-48d4752caf3bc581fc945eb44175e230 +0 -0
- package/demo/web-app-broken/.pitstop/cache/jest/jest-transform-cache-09bbba084113da9182b28b169fd19719-79ef2876fae7ca75eedb2aa53dc48338/5e/config_5ea59c6b3000eadfbaecbc2e78a03802 +113 -0
- package/demo/web-app-broken/.pitstop/cache/jest/jest-transform-cache-09bbba084113da9182b28b169fd19719-79ef2876fae7ca75eedb2aa53dc48338/5e/config_5ea59c6b3000eadfbaecbc2e78a03802.map +1 -0
- package/demo/web-app-broken/.pitstop/cache/jest/perf-cache-09bbba084113da9182b28b169fd19719-da39a3ee5e6b4b0d3255bfef95601890 +1 -1
- package/demo/web-app-broken/.pitstop/pen/run-2026-08-18T06-12-11-576Z/app.out.log +22 -0
- package/demo/web-app-broken/.pitstop/pen-2026-08-18T06-12-11-787Z.json +162 -0
- package/demo/web-app-broken/.pitstop/pen-latest.json +162 -0
- package/demo/web-app-broken/.pitstop/verify-2026-08-18T06-11-59-327Z.json +73 -0
- package/demo/web-app-broken/PITSTOP_BADGE.svg +12 -0
- package/dist/commands/report.js +17 -1
- package/dist/commands/report.js.map +1 -1
- package/dist/commands/verify.d.ts +3 -0
- package/dist/commands/verify.js +53 -21
- package/dist/commands/verify.js.map +1 -1
- package/dist/pen/dynamic.js +130 -3
- package/dist/pen/dynamic.js.map +1 -1
- package/dist/pen/proof.js +6 -0
- package/dist/pen/proof.js.map +1 -1
- package/dist/pen/static.js +120 -0
- package/dist/pen/static.js.map +1 -1
- package/dist/report/format.d.ts +16 -0
- package/dist/report/format.js +62 -9
- package/dist/report/format.js.map +1 -1
- package/dist/report/sarif.d.ts +29 -0
- package/dist/report/sarif.js +161 -0
- package/dist/report/sarif.js.map +1 -0
- package/dist/repro/pen.js +19 -0
- package/dist/repro/pen.js.map +1 -1
- package/dist/verify/honesty.d.ts +21 -0
- package/dist/verify/honesty.js +40 -0
- package/dist/verify/honesty.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -50,6 +50,31 @@ your agent.
|
|
|
50
50
|
|
|
51
51
|
---
|
|
52
52
|
|
|
53
|
+
## OpenPitStop vs Strix — why teams pick the referee
|
|
54
|
+
|
|
55
|
+
Strix is a great *finder*. OpenPitStop is the *referee*. Both pen-test your app; the
|
|
56
|
+
difference is what happens after a vulnerability is found:
|
|
57
|
+
|
|
58
|
+
> **Strix finds. OpenPitStop proves.**
|
|
59
|
+
|
|
60
|
+
| | [Strix](https://github.com/usestrix/strix) | **OpenPitStop** |
|
|
61
|
+
|---|---|---|
|
|
62
|
+
| What it produces | Findings + a PoC *report* | Findings + a **failing-first regression test** (`pitstop pen --fix`) |
|
|
63
|
+
| Trust in the fix | One-click auto-fix PR | **Honesty Score (0–100)** + integrity gate that catches deleted tests, hardcoded passes, reverted baselines |
|
|
64
|
+
| How it runs | Docker + LLM key, non-deterministic | **Zero infra, deterministic, no LLM bill** — runs in any CI |
|
|
65
|
+
| Evidence | `strix_runs/` logs | **Tamper-evident, signed `.pitstop/` artifacts** you can audit |
|
|
66
|
+
| Secret exfiltration | not emphasized | **Ledger mode** proves the app doesn't phone home with your keys |
|
|
67
|
+
| DevSecOps | Cloud platform (paid tiers) | **Free SARIF → GitHub Security tab** + one-number `pitstop gate` |
|
|
68
|
+
| Proof coverage | — | **`PITSTOP_PROOF` badge**: % of findings that ship a permanent repro test |
|
|
69
|
+
| Bug classes covered | strong general set | **40+ classes** — race/TOCTOU, IDOR/BOLA, price-tampering, XXE, insecure deserialization, JWT alg-confusion/weak-secret, SSRF, SQL/NoSQLi, command-injection, path traversal, XSS, secrets, CORS, missing headers, rate-limit, and more |
|
|
70
|
+
|
|
71
|
+
The honest pitch: a pen-test that only reports is a list of things to argue about. A
|
|
72
|
+
pen-test that ships the regression test, signs the evidence, and scores the fix on a
|
|
73
|
+
gate your CI can block on is something you can actually ship. That's the OpenPitStop
|
|
74
|
+
loop — and it's the reason to choose the referee over the hacker.
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
53
78
|
## Feature tour
|
|
54
79
|
|
|
55
80
|
Every clip below is real opencode output, captured from a live agent session —
|
|
Binary file
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
b9e26b5a20d1b5508146e54c87fb8c88
|
|
2
|
+
/* istanbul ignore next */
|
|
3
|
+
function cov_e86xmt8qo() {
|
|
4
|
+
var path = "D:\\OpenPitStop cli\\demo\\web-app-broken\\src\\config.js";
|
|
5
|
+
var hash = "b8ce36803606bd246d8daa8c315e078307e95d46";
|
|
6
|
+
var global = new Function("return this")();
|
|
7
|
+
var gcv = "__coverage__";
|
|
8
|
+
var coverageData = {
|
|
9
|
+
path: "D:\\OpenPitStop cli\\demo\\web-app-broken\\src\\config.js",
|
|
10
|
+
statementMap: {
|
|
11
|
+
"0": {
|
|
12
|
+
start: {
|
|
13
|
+
line: 4,
|
|
14
|
+
column: 26
|
|
15
|
+
},
|
|
16
|
+
end: {
|
|
17
|
+
line: 4,
|
|
18
|
+
column: 62
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"1": {
|
|
22
|
+
start: {
|
|
23
|
+
line: 5,
|
|
24
|
+
column: 26
|
|
25
|
+
},
|
|
26
|
+
end: {
|
|
27
|
+
line: 5,
|
|
28
|
+
column: 62
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"2": {
|
|
32
|
+
start: {
|
|
33
|
+
line: 6,
|
|
34
|
+
column: 19
|
|
35
|
+
},
|
|
36
|
+
end: {
|
|
37
|
+
line: 6,
|
|
38
|
+
column: 48
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"3": {
|
|
42
|
+
start: {
|
|
43
|
+
line: 7,
|
|
44
|
+
column: 20
|
|
45
|
+
},
|
|
46
|
+
end: {
|
|
47
|
+
line: 7,
|
|
48
|
+
column: 50
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
"4": {
|
|
52
|
+
start: {
|
|
53
|
+
line: 9,
|
|
54
|
+
column: 0
|
|
55
|
+
},
|
|
56
|
+
end: {
|
|
57
|
+
line: 9,
|
|
58
|
+
column: 83
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
fnMap: {},
|
|
63
|
+
branchMap: {},
|
|
64
|
+
s: {
|
|
65
|
+
"0": 0,
|
|
66
|
+
"1": 0,
|
|
67
|
+
"2": 0,
|
|
68
|
+
"3": 0,
|
|
69
|
+
"4": 0
|
|
70
|
+
},
|
|
71
|
+
f: {},
|
|
72
|
+
b: {},
|
|
73
|
+
_coverageSchema: "1a1c01bbd47fc00a2c39e90264f33305004495a9",
|
|
74
|
+
hash: "b8ce36803606bd246d8daa8c315e078307e95d46"
|
|
75
|
+
};
|
|
76
|
+
var coverage = global[gcv] || (global[gcv] = {});
|
|
77
|
+
if (!coverage[path] || coverage[path].hash !== hash) {
|
|
78
|
+
coverage[path] = coverageData;
|
|
79
|
+
}
|
|
80
|
+
var actualCoverage = coverage[path];
|
|
81
|
+
{
|
|
82
|
+
// @ts-ignore
|
|
83
|
+
cov_e86xmt8qo = function () {
|
|
84
|
+
return actualCoverage;
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
return actualCoverage;
|
|
88
|
+
}
|
|
89
|
+
cov_e86xmt8qo();
|
|
90
|
+
// Hardcoded secrets in source — flagged by the secret analyzer even without .env.
|
|
91
|
+
// NOTE: values are obvious FAKE placeholders (no real AKIA/sk_live prefixes) so the
|
|
92
|
+
// repo passes GitHub push protection; OpenPitStop still flags them by variable name.
|
|
93
|
+
const AWS_ACCESS_KEY_ID =
|
|
94
|
+
/* istanbul ignore next */
|
|
95
|
+
(cov_e86xmt8qo().s[0]++, "example-aws-access-key-id-not-real");
|
|
96
|
+
const STRIPE_SECRET_KEY =
|
|
97
|
+
/* istanbul ignore next */
|
|
98
|
+
(cov_e86xmt8qo().s[1]++, "example-stripe-secret-key-not-real");
|
|
99
|
+
const JWT_SECRET =
|
|
100
|
+
/* istanbul ignore next */
|
|
101
|
+
(cov_e86xmt8qo().s[2]++, "example-jwt-secret-not-real");
|
|
102
|
+
const DB_PASSWORD =
|
|
103
|
+
/* istanbul ignore next */
|
|
104
|
+
(cov_e86xmt8qo().s[3]++, "example-db-password-not-real");
|
|
105
|
+
/* istanbul ignore next */
|
|
106
|
+
cov_e86xmt8qo().s[4]++;
|
|
107
|
+
module.exports = {
|
|
108
|
+
AWS_ACCESS_KEY_ID,
|
|
109
|
+
STRIPE_SECRET_KEY,
|
|
110
|
+
JWT_SECRET,
|
|
111
|
+
DB_PASSWORD
|
|
112
|
+
};
|
|
113
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJjb3ZfZTg2eG10OHFvIiwiYWN0dWFsQ292ZXJhZ2UiLCJBV1NfQUNDRVNTX0tFWV9JRCIsInMiLCJTVFJJUEVfU0VDUkVUX0tFWSIsIkpXVF9TRUNSRVQiLCJEQl9QQVNTV09SRCIsIm1vZHVsZSIsImV4cG9ydHMiXSwic291cmNlcyI6WyJjb25maWcuanMiXSwic291cmNlc0NvbnRlbnQiOlsiLy8gSGFyZGNvZGVkIHNlY3JldHMgaW4gc291cmNlIOKAlCBmbGFnZ2VkIGJ5IHRoZSBzZWNyZXQgYW5hbHl6ZXIgZXZlbiB3aXRob3V0IC5lbnYuXG4vLyBOT1RFOiB2YWx1ZXMgYXJlIG9idmlvdXMgRkFLRSBwbGFjZWhvbGRlcnMgKG5vIHJlYWwgQUtJQS9za19saXZlIHByZWZpeGVzKSBzbyB0aGVcbi8vIHJlcG8gcGFzc2VzIEdpdEh1YiBwdXNoIHByb3RlY3Rpb247IE9wZW5QaXRTdG9wIHN0aWxsIGZsYWdzIHRoZW0gYnkgdmFyaWFibGUgbmFtZS5cbmNvbnN0IEFXU19BQ0NFU1NfS0VZX0lEID0gXCJleGFtcGxlLWF3cy1hY2Nlc3Mta2V5LWlkLW5vdC1yZWFsXCI7XG5jb25zdCBTVFJJUEVfU0VDUkVUX0tFWSA9IFwiZXhhbXBsZS1zdHJpcGUtc2VjcmV0LWtleS1ub3QtcmVhbFwiO1xuY29uc3QgSldUX1NFQ1JFVCA9IFwiZXhhbXBsZS1qd3Qtc2VjcmV0LW5vdC1yZWFsXCI7XG5jb25zdCBEQl9QQVNTV09SRCA9IFwiZXhhbXBsZS1kYi1wYXNzd29yZC1ub3QtcmVhbFwiO1xuXG5tb2R1bGUuZXhwb3J0cyA9IHsgQVdTX0FDQ0VTU19LRVlfSUQsIFNUUklQRV9TRUNSRVRfS0VZLCBKV1RfU0VDUkVULCBEQl9QQVNTV09SRCB9O1xuIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztJQWVZO0lBQUFBLGFBQUEsWUFBQUEsQ0FBQTtNQUFBLE9BQUFDLGNBQUE7SUFBQTtFQUFBO0VBQUEsT0FBQUEsY0FBQTtBQUFBO0FBQUFELGFBQUE7QUFmWjtBQUNBO0FBQ0E7QUFDQSxNQUFNRSxpQkFBaUI7QUFBQTtBQUFBLENBQUFGLGFBQUEsR0FBQUcsQ0FBQSxPQUFHLG9DQUFvQztBQUM5RCxNQUFNQyxpQkFBaUI7QUFBQTtBQUFBLENBQUFKLGFBQUEsR0FBQUcsQ0FBQSxPQUFHLG9DQUFvQztBQUM5RCxNQUFNRSxVQUFVO0FBQUE7QUFBQSxDQUFBTCxhQUFBLEdBQUFHLENBQUEsT0FBRyw2QkFBNkI7QUFDaEQsTUFBTUcsV0FBVztBQUFBO0FBQUEsQ0FBQU4sYUFBQSxHQUFBRyxDQUFBLE9BQUcsOEJBQThCO0FBQUM7QUFBQUgsYUFBQSxHQUFBRyxDQUFBO0FBRW5ESSxNQUFNLENBQUNDLE9BQU8sR0FBRztFQUFFTixpQkFBaUI7RUFBRUUsaUJBQWlCO0VBQUVDLFVBQVU7RUFBRUM7QUFBWSxDQUFDIiwiaWdub3JlTGlzdCI6W119
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["cov_e86xmt8qo","actualCoverage","AWS_ACCESS_KEY_ID","s","STRIPE_SECRET_KEY","JWT_SECRET","DB_PASSWORD","module","exports"],"sources":["config.js"],"sourcesContent":["// Hardcoded secrets in source — flagged by the secret analyzer even without .env.\n// NOTE: values are obvious FAKE placeholders (no real AKIA/sk_live prefixes) so the\n// repo passes GitHub push protection; OpenPitStop still flags them by variable name.\nconst AWS_ACCESS_KEY_ID = \"example-aws-access-key-id-not-real\";\nconst STRIPE_SECRET_KEY = \"example-stripe-secret-key-not-real\";\nconst JWT_SECRET = \"example-jwt-secret-not-real\";\nconst DB_PASSWORD = \"example-db-password-not-real\";\n\nmodule.exports = { AWS_ACCESS_KEY_ID, STRIPE_SECRET_KEY, JWT_SECRET, DB_PASSWORD };\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAeY;IAAAA,aAAA,YAAAA,CAAA;MAAA,OAAAC,cAAA;IAAA;EAAA;EAAA,OAAAA,cAAA;AAAA;AAAAD,aAAA;AAfZ;AACA;AACA;AACA,MAAME,iBAAiB;AAAA;AAAA,CAAAF,aAAA,GAAAG,CAAA,OAAG,oCAAoC;AAC9D,MAAMC,iBAAiB;AAAA;AAAA,CAAAJ,aAAA,GAAAG,CAAA,OAAG,oCAAoC;AAC9D,MAAME,UAAU;AAAA;AAAA,CAAAL,aAAA,GAAAG,CAAA,OAAG,6BAA6B;AAChD,MAAMG,WAAW;AAAA;AAAA,CAAAN,aAAA,GAAAG,CAAA,OAAG,8BAA8B;AAAC;AAAAH,aAAA,GAAAG,CAAA;AAEnDI,MAAM,CAACC,OAAO,GAAG;EAAEN,iBAAiB;EAAEE,iBAAiB;EAAEC,UAAU;EAAEC;AAAY,CAAC","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"D:\\OpenPitStop cli\\demo\\web-app-broken\\test\\app.test.js":[0,
|
|
1
|
+
{"D:\\OpenPitStop cli\\demo\\web-app-broken\\test\\app.test.js":[0,1820]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
node:internal/modules/cjs/loader:1252
|
|
2
|
+
throw err;
|
|
3
|
+
^
|
|
4
|
+
|
|
5
|
+
Error: Cannot find module 'D:\OpenPitStop'
|
|
6
|
+
Require stack:
|
|
7
|
+
- internal/preload
|
|
8
|
+
at Function._resolveFilename (node:internal/modules/cjs/loader:1249:15)
|
|
9
|
+
at Function._load (node:internal/modules/cjs/loader:1075:27)
|
|
10
|
+
at TracingChannel.traceSync (node:diagnostics_channel:322:14)
|
|
11
|
+
at wrapModuleLoad (node:internal/modules/cjs/loader:219:24)
|
|
12
|
+
at Module.require (node:internal/modules/cjs/loader:1340:12)
|
|
13
|
+
at node:internal/modules/cjs/loader:1843:12
|
|
14
|
+
at loadPreloadModules (node:internal/process/pre_execution:727:5)
|
|
15
|
+
at setupUserModules (node:internal/process/pre_execution:206:5)
|
|
16
|
+
at prepareExecution (node:internal/process/pre_execution:159:5)
|
|
17
|
+
at prepareMainThreadExecution (node:internal/process/pre_execution:54:10) {
|
|
18
|
+
code: 'MODULE_NOT_FOUND',
|
|
19
|
+
requireStack: [ 'internal/preload' ]
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
Node.js v22.12.0
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
{
|
|
2
|
+
"timestamp": "2026-08-18T06:12:11.785Z",
|
|
3
|
+
"repo": "D:\\OpenPitStop cli\\demo\\web-app-broken",
|
|
4
|
+
"mode": "pen",
|
|
5
|
+
"staticEnabled": true,
|
|
6
|
+
"dynamicEnabled": true,
|
|
7
|
+
"dynamic": {
|
|
8
|
+
"status": "aborted",
|
|
9
|
+
"note": "app did not come up within 25s (start: \"node src/server.js\")",
|
|
10
|
+
"routesProbed": 0,
|
|
11
|
+
"attacks": 0,
|
|
12
|
+
"bootMs": 198,
|
|
13
|
+
"durationMs": 209,
|
|
14
|
+
"outboundEvents": 0
|
|
15
|
+
},
|
|
16
|
+
"staticProof": {
|
|
17
|
+
"proven": 0,
|
|
18
|
+
"indicated": 0,
|
|
19
|
+
"unproven": 0,
|
|
20
|
+
"notTested": 8
|
|
21
|
+
},
|
|
22
|
+
"packages": [
|
|
23
|
+
"express",
|
|
24
|
+
"lodash",
|
|
25
|
+
"jsonwebtoken",
|
|
26
|
+
"mysql2",
|
|
27
|
+
"cors",
|
|
28
|
+
"jest"
|
|
29
|
+
],
|
|
30
|
+
"findings": [
|
|
31
|
+
{
|
|
32
|
+
"id": "pen-62be9b7b",
|
|
33
|
+
"source": "pen-static",
|
|
34
|
+
"type": "sql-injection",
|
|
35
|
+
"severity": "critical",
|
|
36
|
+
"confidence": "indicated",
|
|
37
|
+
"title": "SQL built by string interpolation",
|
|
38
|
+
"description": "A query string is assembled by concatenating or interpolating variables into SQL. Any route feeding these variables becomes a live injection point. (src/server.js:24)",
|
|
39
|
+
"file": "D:\\OpenPitStop cli\\demo\\web-app-broken\\src\\server.js",
|
|
40
|
+
"line": 24,
|
|
41
|
+
"repro": "open src/server.js:24",
|
|
42
|
+
"fix": "Use parameterized queries (?, $1 placeholders) or an ORM. Never interpolate values into SQL text.",
|
|
43
|
+
"runtimeProof": "not-tested",
|
|
44
|
+
"runtimeNote": "no runtime verification: the dynamic phase did not run (app did not come up within 25s (start: \"node src/server.js\"))"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"id": "pen-654abdce",
|
|
48
|
+
"source": "pen-static",
|
|
49
|
+
"type": "sql-injection",
|
|
50
|
+
"severity": "critical",
|
|
51
|
+
"confidence": "indicated",
|
|
52
|
+
"title": "SQL built by string interpolation",
|
|
53
|
+
"description": "A query string is assembled by concatenating or interpolating variables into SQL. Any route feeding these variables becomes a live injection point. (src/users.js:16)",
|
|
54
|
+
"file": "D:\\OpenPitStop cli\\demo\\web-app-broken\\src\\users.js",
|
|
55
|
+
"line": 16,
|
|
56
|
+
"repro": "open src/users.js:16",
|
|
57
|
+
"fix": "Use parameterized queries (?, $1 placeholders) or an ORM. Never interpolate values into SQL text.",
|
|
58
|
+
"runtimeProof": "not-tested",
|
|
59
|
+
"runtimeNote": "no runtime verification: the dynamic phase did not run (app did not come up within 25s (start: \"node src/server.js\"))"
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"id": "pen-81855543",
|
|
63
|
+
"source": "pen-static",
|
|
64
|
+
"type": "command-injection",
|
|
65
|
+
"severity": "critical",
|
|
66
|
+
"confidence": "indicated",
|
|
67
|
+
"title": "child_process called with request-derived input",
|
|
68
|
+
"description": "exec/spawn/execFile is called with a value that can trace back to request data (query, params, body). If the shell interprets it, that is remote code execution. (src/server.js:24)",
|
|
69
|
+
"file": "D:\\OpenPitStop cli\\demo\\web-app-broken\\src\\server.js",
|
|
70
|
+
"line": 24,
|
|
71
|
+
"repro": "open src/server.js:24",
|
|
72
|
+
"fix": "Do not shell out with user input. If unavoidable: execFile with a fixed command, no shell, and validate input against a strict allowlist (e.g. /^[a-z0-9-]{1,64}$/).",
|
|
73
|
+
"runtimeProof": "not-tested",
|
|
74
|
+
"runtimeNote": "no runtime verification: the dynamic phase did not run (app did not come up within 25s (start: \"node src/server.js\"))"
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"id": "pen-6d14fd91",
|
|
78
|
+
"source": "pen-static",
|
|
79
|
+
"type": "arbitrary-code-execution",
|
|
80
|
+
"severity": "high",
|
|
81
|
+
"confidence": "heuristic",
|
|
82
|
+
"title": "eval / new Function in application code",
|
|
83
|
+
"description": "`eval` or `new Function` turns attacker-influenced strings into executable code. It is never needed for this; replace with a lookup table or JSON.parse. (src/server.js:59)",
|
|
84
|
+
"file": "D:\\OpenPitStop cli\\demo\\web-app-broken\\src\\server.js",
|
|
85
|
+
"line": 59,
|
|
86
|
+
"repro": "open src/server.js:59",
|
|
87
|
+
"fix": "Remove eval/new Function. If a template engine is genuinely required, use a sandboxed one (e.g. a compiled template with no global access).",
|
|
88
|
+
"runtimeProof": "not-tested",
|
|
89
|
+
"runtimeNote": "no runtime verification: the dynamic phase did not run (app did not come up within 25s (start: \"node src/server.js\"))"
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"id": "pen-e02320ba",
|
|
93
|
+
"source": "pen-static",
|
|
94
|
+
"type": "cookie-without-httponly",
|
|
95
|
+
"severity": "medium",
|
|
96
|
+
"confidence": "indicated",
|
|
97
|
+
"title": "cookie set without httpOnly",
|
|
98
|
+
"description": "A session/security cookie is being set without `httpOnly` (and likely without `secure`), so an XSS in any page can steal it via document.cookie.",
|
|
99
|
+
"file": "D:\\OpenPitStop cli\\demo\\web-app-broken\\src\\auth.js",
|
|
100
|
+
"line": 31,
|
|
101
|
+
"fix": "Set `{ httpOnly: true, secure: true, sameSite: \"strict\" }` on every session/auth cookie.",
|
|
102
|
+
"runtimeProof": "not-tested",
|
|
103
|
+
"runtimeNote": "no runtime verification: the dynamic phase did not run (app did not come up within 25s (start: \"node src/server.js\"))"
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
"id": "pen-c3f2b7cf",
|
|
107
|
+
"source": "pen-static",
|
|
108
|
+
"type": "insecure-cors",
|
|
109
|
+
"severity": "high",
|
|
110
|
+
"confidence": "indicated",
|
|
111
|
+
"title": "CORS allows any origin",
|
|
112
|
+
"description": "CORS is wide open — either a bare `cors()` (defaults to origin: * with credentials off) or an explicit `origin: \"*\"`. Any website can read the responses of this endpoint from a victim's browser.",
|
|
113
|
+
"file": "D:\\OpenPitStop cli\\demo\\web-app-broken\\src\\server.js",
|
|
114
|
+
"line": 13,
|
|
115
|
+
"fix": "Restrict origins to an explicit allowlist: `cors({ origin: [/^https?:\\/\\/(localhost|127\\.0\\.0\\.1)(:\\d+)?$/, ...] })` — or better, list only your real production origins and never combine `origin: *` with credentials.",
|
|
116
|
+
"runtimeProof": "not-tested",
|
|
117
|
+
"runtimeNote": "no runtime verification: the dynamic phase did not run (app did not come up within 25s (start: \"node src/server.js\"))"
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
"id": "pen-c55906fe",
|
|
121
|
+
"source": "pen-static",
|
|
122
|
+
"type": "missing-security-headers",
|
|
123
|
+
"severity": "medium",
|
|
124
|
+
"confidence": "indicated",
|
|
125
|
+
"title": "no helmet / security headers middleware",
|
|
126
|
+
"description": "An Express app without helmet() (or manual CSP / X-Frame-Options / X-Content-Type-Options headers). Clickjacking, MIME sniffing and mixed-content protections are all off.",
|
|
127
|
+
"file": "D:\\OpenPitStop cli\\demo\\web-app-broken\\src\\server.js",
|
|
128
|
+
"line": 10,
|
|
129
|
+
"fix": "Install helmet and `app.use(helmet());` after app creation (deterministic patch generated by `pitstop pen --fix` when helmet is already installed).",
|
|
130
|
+
"runtimeProof": "not-tested",
|
|
131
|
+
"runtimeNote": "no runtime verification: the dynamic phase did not run (app did not come up within 25s (start: \"node src/server.js\"))"
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
"id": "pen-295619f9",
|
|
135
|
+
"source": "pen-static",
|
|
136
|
+
"type": "no-rate-limit",
|
|
137
|
+
"severity": "medium",
|
|
138
|
+
"confidence": "heuristic",
|
|
139
|
+
"title": "no rate limiting on authentication paths",
|
|
140
|
+
"description": "express-rate-limit is not installed and login-ish routes exist — credential stuffing / brute force is unthrottled. The dynamic phase verifies this live. Login-ish routes: POST /login.",
|
|
141
|
+
"fix": "Add express-rate-limit and apply a strict limiter to /login /verify /otp /token routes (e.g. 5 requests / 15 min per IP).",
|
|
142
|
+
"runtimeProof": "not-tested",
|
|
143
|
+
"runtimeNote": "no runtime verification: the dynamic phase did not run (app did not come up within 25s (start: \"node src/server.js\"))"
|
|
144
|
+
}
|
|
145
|
+
],
|
|
146
|
+
"summary": {
|
|
147
|
+
"critical": 3,
|
|
148
|
+
"high": 2,
|
|
149
|
+
"medium": 3,
|
|
150
|
+
"low": 0,
|
|
151
|
+
"info": 0,
|
|
152
|
+
"proven": 0,
|
|
153
|
+
"indicated": 6,
|
|
154
|
+
"heuristic": 2
|
|
155
|
+
},
|
|
156
|
+
"evidence": {
|
|
157
|
+
"scheme": "pitstop-canonical-sha256-v1",
|
|
158
|
+
"digest": "e4ce8e1e6534ee152c199374a4de6ca6c2dec036c3a487554c215a9c0fedf2bd",
|
|
159
|
+
"of": "pitstop pen result for D:\\OpenPitStop cli\\demo\\web-app-broken",
|
|
160
|
+
"signedAt": "2026-08-18T06:12:11.786Z"
|
|
161
|
+
}
|
|
162
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
{
|
|
2
|
+
"timestamp": "2026-08-18T06:12:11.785Z",
|
|
3
|
+
"repo": "D:\\OpenPitStop cli\\demo\\web-app-broken",
|
|
4
|
+
"mode": "pen",
|
|
5
|
+
"staticEnabled": true,
|
|
6
|
+
"dynamicEnabled": true,
|
|
7
|
+
"dynamic": {
|
|
8
|
+
"status": "aborted",
|
|
9
|
+
"note": "app did not come up within 25s (start: \"node src/server.js\")",
|
|
10
|
+
"routesProbed": 0,
|
|
11
|
+
"attacks": 0,
|
|
12
|
+
"bootMs": 198,
|
|
13
|
+
"durationMs": 209,
|
|
14
|
+
"outboundEvents": 0
|
|
15
|
+
},
|
|
16
|
+
"staticProof": {
|
|
17
|
+
"proven": 0,
|
|
18
|
+
"indicated": 0,
|
|
19
|
+
"unproven": 0,
|
|
20
|
+
"notTested": 8
|
|
21
|
+
},
|
|
22
|
+
"packages": [
|
|
23
|
+
"express",
|
|
24
|
+
"lodash",
|
|
25
|
+
"jsonwebtoken",
|
|
26
|
+
"mysql2",
|
|
27
|
+
"cors",
|
|
28
|
+
"jest"
|
|
29
|
+
],
|
|
30
|
+
"findings": [
|
|
31
|
+
{
|
|
32
|
+
"id": "pen-62be9b7b",
|
|
33
|
+
"source": "pen-static",
|
|
34
|
+
"type": "sql-injection",
|
|
35
|
+
"severity": "critical",
|
|
36
|
+
"confidence": "indicated",
|
|
37
|
+
"title": "SQL built by string interpolation",
|
|
38
|
+
"description": "A query string is assembled by concatenating or interpolating variables into SQL. Any route feeding these variables becomes a live injection point. (src/server.js:24)",
|
|
39
|
+
"file": "D:\\OpenPitStop cli\\demo\\web-app-broken\\src\\server.js",
|
|
40
|
+
"line": 24,
|
|
41
|
+
"repro": "open src/server.js:24",
|
|
42
|
+
"fix": "Use parameterized queries (?, $1 placeholders) or an ORM. Never interpolate values into SQL text.",
|
|
43
|
+
"runtimeProof": "not-tested",
|
|
44
|
+
"runtimeNote": "no runtime verification: the dynamic phase did not run (app did not come up within 25s (start: \"node src/server.js\"))"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"id": "pen-654abdce",
|
|
48
|
+
"source": "pen-static",
|
|
49
|
+
"type": "sql-injection",
|
|
50
|
+
"severity": "critical",
|
|
51
|
+
"confidence": "indicated",
|
|
52
|
+
"title": "SQL built by string interpolation",
|
|
53
|
+
"description": "A query string is assembled by concatenating or interpolating variables into SQL. Any route feeding these variables becomes a live injection point. (src/users.js:16)",
|
|
54
|
+
"file": "D:\\OpenPitStop cli\\demo\\web-app-broken\\src\\users.js",
|
|
55
|
+
"line": 16,
|
|
56
|
+
"repro": "open src/users.js:16",
|
|
57
|
+
"fix": "Use parameterized queries (?, $1 placeholders) or an ORM. Never interpolate values into SQL text.",
|
|
58
|
+
"runtimeProof": "not-tested",
|
|
59
|
+
"runtimeNote": "no runtime verification: the dynamic phase did not run (app did not come up within 25s (start: \"node src/server.js\"))"
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"id": "pen-81855543",
|
|
63
|
+
"source": "pen-static",
|
|
64
|
+
"type": "command-injection",
|
|
65
|
+
"severity": "critical",
|
|
66
|
+
"confidence": "indicated",
|
|
67
|
+
"title": "child_process called with request-derived input",
|
|
68
|
+
"description": "exec/spawn/execFile is called with a value that can trace back to request data (query, params, body). If the shell interprets it, that is remote code execution. (src/server.js:24)",
|
|
69
|
+
"file": "D:\\OpenPitStop cli\\demo\\web-app-broken\\src\\server.js",
|
|
70
|
+
"line": 24,
|
|
71
|
+
"repro": "open src/server.js:24",
|
|
72
|
+
"fix": "Do not shell out with user input. If unavoidable: execFile with a fixed command, no shell, and validate input against a strict allowlist (e.g. /^[a-z0-9-]{1,64}$/).",
|
|
73
|
+
"runtimeProof": "not-tested",
|
|
74
|
+
"runtimeNote": "no runtime verification: the dynamic phase did not run (app did not come up within 25s (start: \"node src/server.js\"))"
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"id": "pen-6d14fd91",
|
|
78
|
+
"source": "pen-static",
|
|
79
|
+
"type": "arbitrary-code-execution",
|
|
80
|
+
"severity": "high",
|
|
81
|
+
"confidence": "heuristic",
|
|
82
|
+
"title": "eval / new Function in application code",
|
|
83
|
+
"description": "`eval` or `new Function` turns attacker-influenced strings into executable code. It is never needed for this; replace with a lookup table or JSON.parse. (src/server.js:59)",
|
|
84
|
+
"file": "D:\\OpenPitStop cli\\demo\\web-app-broken\\src\\server.js",
|
|
85
|
+
"line": 59,
|
|
86
|
+
"repro": "open src/server.js:59",
|
|
87
|
+
"fix": "Remove eval/new Function. If a template engine is genuinely required, use a sandboxed one (e.g. a compiled template with no global access).",
|
|
88
|
+
"runtimeProof": "not-tested",
|
|
89
|
+
"runtimeNote": "no runtime verification: the dynamic phase did not run (app did not come up within 25s (start: \"node src/server.js\"))"
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"id": "pen-e02320ba",
|
|
93
|
+
"source": "pen-static",
|
|
94
|
+
"type": "cookie-without-httponly",
|
|
95
|
+
"severity": "medium",
|
|
96
|
+
"confidence": "indicated",
|
|
97
|
+
"title": "cookie set without httpOnly",
|
|
98
|
+
"description": "A session/security cookie is being set without `httpOnly` (and likely without `secure`), so an XSS in any page can steal it via document.cookie.",
|
|
99
|
+
"file": "D:\\OpenPitStop cli\\demo\\web-app-broken\\src\\auth.js",
|
|
100
|
+
"line": 31,
|
|
101
|
+
"fix": "Set `{ httpOnly: true, secure: true, sameSite: \"strict\" }` on every session/auth cookie.",
|
|
102
|
+
"runtimeProof": "not-tested",
|
|
103
|
+
"runtimeNote": "no runtime verification: the dynamic phase did not run (app did not come up within 25s (start: \"node src/server.js\"))"
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
"id": "pen-c3f2b7cf",
|
|
107
|
+
"source": "pen-static",
|
|
108
|
+
"type": "insecure-cors",
|
|
109
|
+
"severity": "high",
|
|
110
|
+
"confidence": "indicated",
|
|
111
|
+
"title": "CORS allows any origin",
|
|
112
|
+
"description": "CORS is wide open — either a bare `cors()` (defaults to origin: * with credentials off) or an explicit `origin: \"*\"`. Any website can read the responses of this endpoint from a victim's browser.",
|
|
113
|
+
"file": "D:\\OpenPitStop cli\\demo\\web-app-broken\\src\\server.js",
|
|
114
|
+
"line": 13,
|
|
115
|
+
"fix": "Restrict origins to an explicit allowlist: `cors({ origin: [/^https?:\\/\\/(localhost|127\\.0\\.0\\.1)(:\\d+)?$/, ...] })` — or better, list only your real production origins and never combine `origin: *` with credentials.",
|
|
116
|
+
"runtimeProof": "not-tested",
|
|
117
|
+
"runtimeNote": "no runtime verification: the dynamic phase did not run (app did not come up within 25s (start: \"node src/server.js\"))"
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
"id": "pen-c55906fe",
|
|
121
|
+
"source": "pen-static",
|
|
122
|
+
"type": "missing-security-headers",
|
|
123
|
+
"severity": "medium",
|
|
124
|
+
"confidence": "indicated",
|
|
125
|
+
"title": "no helmet / security headers middleware",
|
|
126
|
+
"description": "An Express app without helmet() (or manual CSP / X-Frame-Options / X-Content-Type-Options headers). Clickjacking, MIME sniffing and mixed-content protections are all off.",
|
|
127
|
+
"file": "D:\\OpenPitStop cli\\demo\\web-app-broken\\src\\server.js",
|
|
128
|
+
"line": 10,
|
|
129
|
+
"fix": "Install helmet and `app.use(helmet());` after app creation (deterministic patch generated by `pitstop pen --fix` when helmet is already installed).",
|
|
130
|
+
"runtimeProof": "not-tested",
|
|
131
|
+
"runtimeNote": "no runtime verification: the dynamic phase did not run (app did not come up within 25s (start: \"node src/server.js\"))"
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
"id": "pen-295619f9",
|
|
135
|
+
"source": "pen-static",
|
|
136
|
+
"type": "no-rate-limit",
|
|
137
|
+
"severity": "medium",
|
|
138
|
+
"confidence": "heuristic",
|
|
139
|
+
"title": "no rate limiting on authentication paths",
|
|
140
|
+
"description": "express-rate-limit is not installed and login-ish routes exist — credential stuffing / brute force is unthrottled. The dynamic phase verifies this live. Login-ish routes: POST /login.",
|
|
141
|
+
"fix": "Add express-rate-limit and apply a strict limiter to /login /verify /otp /token routes (e.g. 5 requests / 15 min per IP).",
|
|
142
|
+
"runtimeProof": "not-tested",
|
|
143
|
+
"runtimeNote": "no runtime verification: the dynamic phase did not run (app did not come up within 25s (start: \"node src/server.js\"))"
|
|
144
|
+
}
|
|
145
|
+
],
|
|
146
|
+
"summary": {
|
|
147
|
+
"critical": 3,
|
|
148
|
+
"high": 2,
|
|
149
|
+
"medium": 3,
|
|
150
|
+
"low": 0,
|
|
151
|
+
"info": 0,
|
|
152
|
+
"proven": 0,
|
|
153
|
+
"indicated": 6,
|
|
154
|
+
"heuristic": 2
|
|
155
|
+
},
|
|
156
|
+
"evidence": {
|
|
157
|
+
"scheme": "pitstop-canonical-sha256-v1",
|
|
158
|
+
"digest": "e4ce8e1e6534ee152c199374a4de6ca6c2dec036c3a487554c215a9c0fedf2bd",
|
|
159
|
+
"of": "pitstop pen result for D:\\OpenPitStop cli\\demo\\web-app-broken",
|
|
160
|
+
"signedAt": "2026-08-18T06:12:11.786Z"
|
|
161
|
+
}
|
|
162
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
{
|
|
2
|
+
"timestamp": "2026-08-18T06:11:59.328Z",
|
|
3
|
+
"repo": "D:\\OpenPitStop cli\\demo\\web-app-broken",
|
|
4
|
+
"baselineTimestamp": "2026-08-18T04:07:42.300Z",
|
|
5
|
+
"risk": "Low",
|
|
6
|
+
"blocked": false,
|
|
7
|
+
"stale": true,
|
|
8
|
+
"staleNote": "baseline is STALE — .env changed 2026-08-18T05:21:00.275Z, after the baseline scan (2026-08-18T04:07:42.300Z). Score delta vs baseline is approximate; re-run `pitstop scan` for a fresh baseline.",
|
|
9
|
+
"evidence": {
|
|
10
|
+
"scheme": "pitstop-canonical-sha256-v1",
|
|
11
|
+
"digest": "297e93ba61700be8a7614c9abb32a888cc07a59008a57e60cc729efd444feb29",
|
|
12
|
+
"of": "pitstop verify result for D:\\OpenPitStop cli\\demo\\web-app-broken",
|
|
13
|
+
"signedAt": "2026-08-18T06:11:59.328Z"
|
|
14
|
+
},
|
|
15
|
+
"status": "OK",
|
|
16
|
+
"exitCode": 0,
|
|
17
|
+
"integrity": {
|
|
18
|
+
"verdict": "CLEAN",
|
|
19
|
+
"findings": [],
|
|
20
|
+
"summary": {
|
|
21
|
+
"confirmed": 0,
|
|
22
|
+
"suspicious": 0,
|
|
23
|
+
"total": 0
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"deltas": {
|
|
27
|
+
"passed": 0,
|
|
28
|
+
"failed": 0,
|
|
29
|
+
"durationMs": -2912,
|
|
30
|
+
"coverage": 0,
|
|
31
|
+
"buildTimeMs": 0,
|
|
32
|
+
"bundleSizeBytes": 0,
|
|
33
|
+
"security": -2,
|
|
34
|
+
"duplication": 0
|
|
35
|
+
},
|
|
36
|
+
"baseline": {
|
|
37
|
+
"tests": {
|
|
38
|
+
"total": 5,
|
|
39
|
+
"passed": 0,
|
|
40
|
+
"failed": 5,
|
|
41
|
+
"durationMs": 6283,
|
|
42
|
+
"coverage": 62.02
|
|
43
|
+
},
|
|
44
|
+
"perf": {},
|
|
45
|
+
"securityCount": 45,
|
|
46
|
+
"duplicationCount": 0
|
|
47
|
+
},
|
|
48
|
+
"current": {
|
|
49
|
+
"tests": {
|
|
50
|
+
"total": 5,
|
|
51
|
+
"passed": 0,
|
|
52
|
+
"failed": 5,
|
|
53
|
+
"durationMs": 3371,
|
|
54
|
+
"coverage": 62.02
|
|
55
|
+
},
|
|
56
|
+
"perf": {},
|
|
57
|
+
"securityCount": 43,
|
|
58
|
+
"duplicationCount": 0
|
|
59
|
+
},
|
|
60
|
+
"score": {
|
|
61
|
+
"baseline": 35,
|
|
62
|
+
"current": 35,
|
|
63
|
+
"delta": 0,
|
|
64
|
+
"grade": "F"
|
|
65
|
+
},
|
|
66
|
+
"honesty": {
|
|
67
|
+
"score": 90,
|
|
68
|
+
"rating": "TRUSTWORTHY",
|
|
69
|
+
"reasons": [
|
|
70
|
+
"baseline is stale — the score delta is approximate, not exact"
|
|
71
|
+
]
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="139" height="20" role="img" aria-label="OpenPitStop score 35/100 (F)">
|
|
2
|
+
<linearGradient id="g" x1="0" y1="0" x2="1" y2="0">
|
|
3
|
+
<stop offset="0%" stop-color="#5c5c5c" stop-opacity="0.95"/>
|
|
4
|
+
<stop offset="100%" stop-color="#3a3a3a" stop-opacity="0.95"/>
|
|
5
|
+
</linearGradient>
|
|
6
|
+
<rect width="139" height="20" rx="3" fill="url(#g)"/>
|
|
7
|
+
<rect x="66" width="73" height="20" fill="#E53935"/>
|
|
8
|
+
<g fill="#fff" font-family="Verdana,DejaVu Sans,sans-serif" font-size="11" text-anchor="middle">
|
|
9
|
+
<text x="33" y="14">PITSTOP</text>
|
|
10
|
+
<text x="102.5" y="14">35/100 F</text>
|
|
11
|
+
</g>
|
|
12
|
+
</svg>
|
package/dist/commands/report.js
CHANGED
|
@@ -2,12 +2,14 @@ import { Command } from "commander";
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import fs from "node:fs";
|
|
4
4
|
import chalk from "chalk";
|
|
5
|
-
import { buildModel, renderTerminal, renderMarkdown, renderHtml } from "../report/format.js";
|
|
5
|
+
import { buildModel, renderTerminal, renderMarkdown, renderHtml, renderProofBadgeSvg } from "../report/format.js";
|
|
6
6
|
import { computeScore, renderBadgeSvg } from "../report/score.js";
|
|
7
|
+
import { buildSarif } from "../report/sarif.js";
|
|
7
8
|
export const report = new Command("report")
|
|
8
9
|
.description("Generate a repository analysis report from scan/verify history")
|
|
9
10
|
.argument("[repo]", "path to the repo to report on", ".")
|
|
10
11
|
.option("--html", "also write a self-contained PITSTOP_REPORT.html (zero external assets)")
|
|
12
|
+
.option("--sarif", "also write PITSTOP_REPORT.sarif — upload to GitHub code scanning (Security tab)")
|
|
11
13
|
.option("--badge-json", "also write PITSTOP_BADGE.json — a shields.io `endpoint`-schema badge you can host " +
|
|
12
14
|
"(https://img.shields.io/endpoint?url=<hosted.json>)")
|
|
13
15
|
.action(async (repoArg, options) => {
|
|
@@ -38,7 +40,21 @@ export const report = new Command("report")
|
|
|
38
40
|
chalk.dim(` host it and use: https://img.shields.io/endpoint?url=<url>/PITSTOP_BADGE.json\n`));
|
|
39
41
|
}
|
|
40
42
|
}
|
|
43
|
+
// Proof-coverage badge — the "we prove, not just report" signal for README/CI.
|
|
44
|
+
if (model.proofCoverage?.hasPen) {
|
|
45
|
+
const proofBadge = path.join(repo, "PITSTOP_PROOF.svg");
|
|
46
|
+
fs.writeFileSync(proofBadge, renderProofBadgeSvg(model.proofCoverage.pct));
|
|
47
|
+
console.log(chalk.dim(`Proof-coverage badge written to ${proofBadge}`) +
|
|
48
|
+
chalk.dim(` — embed: \n`));
|
|
49
|
+
}
|
|
41
50
|
console.log(chalk.dim(`\nReport written to ${mdPath}\n`));
|
|
51
|
+
if (options.sarif) {
|
|
52
|
+
const sarif = buildSarif(repo, model);
|
|
53
|
+
const sarifPath = path.join(repo, "PITSTOP_REPORT.sarif");
|
|
54
|
+
fs.writeFileSync(sarifPath, JSON.stringify(sarif, null, 2));
|
|
55
|
+
console.log(chalk.dim(`SARIF written to ${sarifPath}`) +
|
|
56
|
+
chalk.dim(` — upload to GitHub: gh api /repos/<owner>/<repo>/code-scanning/sarifs\n`));
|
|
57
|
+
}
|
|
42
58
|
if (options.html) {
|
|
43
59
|
const htmlPath = path.join(repo, "PITSTOP_REPORT.html");
|
|
44
60
|
fs.writeFileSync(htmlPath, renderHtml(model));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"report.js","sourceRoot":"","sources":["../../src/commands/report.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"report.js","sourceRoot":"","sources":["../../src/commands/report.ts"],"names":[],"mappings":"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"}
|