@vibecheckai/cli 3.2.2 → 3.2.4
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/bin/.generated +25 -25
- package/bin/dev/run-v2-torture.js +30 -30
- package/bin/runners/ENHANCEMENT_GUIDE.md +121 -121
- package/bin/runners/lib/__tests__/entitlements-v2.test.js +295 -295
- package/bin/runners/lib/agent-firewall/ai/false-positive-analyzer.js +474 -0
- package/bin/runners/lib/agent-firewall/claims/extractor.js +117 -28
- package/bin/runners/lib/agent-firewall/evidence/env-evidence.js +23 -14
- package/bin/runners/lib/agent-firewall/evidence/route-evidence.js +72 -1
- package/bin/runners/lib/agent-firewall/interceptor/base.js +2 -2
- package/bin/runners/lib/agent-firewall/policy/default-policy.json +6 -0
- package/bin/runners/lib/agent-firewall/policy/engine.js +34 -3
- package/bin/runners/lib/agent-firewall/policy/rules/fake-success.js +29 -4
- package/bin/runners/lib/agent-firewall/policy/rules/ghost-route.js +12 -0
- package/bin/runners/lib/agent-firewall/truthpack/loader.js +21 -0
- package/bin/runners/lib/agent-firewall/utils/ignore-checker.js +118 -0
- package/bin/runners/lib/analyzers.js +606 -325
- package/bin/runners/lib/auth-truth.js +193 -193
- package/bin/runners/lib/backup.js +62 -62
- package/bin/runners/lib/billing.js +107 -107
- package/bin/runners/lib/claims.js +118 -118
- package/bin/runners/lib/cli-ui.js +540 -540
- package/bin/runners/lib/contracts/auth-contract.js +202 -202
- package/bin/runners/lib/contracts/env-contract.js +181 -181
- package/bin/runners/lib/contracts/external-contract.js +206 -206
- package/bin/runners/lib/contracts/guard.js +168 -168
- package/bin/runners/lib/contracts/index.js +89 -89
- package/bin/runners/lib/contracts/plan-validator.js +311 -311
- package/bin/runners/lib/contracts/route-contract.js +199 -199
- package/bin/runners/lib/contracts.js +804 -804
- package/bin/runners/lib/detect.js +89 -89
- package/bin/runners/lib/doctor/autofix.js +254 -254
- package/bin/runners/lib/doctor/index.js +37 -37
- package/bin/runners/lib/doctor/modules/dependencies.js +325 -325
- package/bin/runners/lib/doctor/modules/index.js +46 -46
- package/bin/runners/lib/doctor/modules/network.js +250 -250
- package/bin/runners/lib/doctor/modules/project.js +312 -312
- package/bin/runners/lib/doctor/modules/runtime.js +224 -224
- package/bin/runners/lib/doctor/modules/security.js +348 -348
- package/bin/runners/lib/doctor/modules/system.js +213 -213
- package/bin/runners/lib/doctor/modules/vibecheck.js +394 -394
- package/bin/runners/lib/doctor/reporter.js +262 -262
- package/bin/runners/lib/doctor/service.js +262 -262
- package/bin/runners/lib/doctor/types.js +113 -113
- package/bin/runners/lib/doctor/ui.js +263 -263
- package/bin/runners/lib/doctor-v2.js +608 -608
- package/bin/runners/lib/drift.js +425 -425
- package/bin/runners/lib/enforcement.js +72 -72
- package/bin/runners/lib/engines/accessibility-engine.js +190 -0
- package/bin/runners/lib/engines/api-consistency-engine.js +162 -0
- package/bin/runners/lib/engines/ast-cache.js +99 -0
- package/bin/runners/lib/engines/code-quality-engine.js +255 -0
- package/bin/runners/lib/engines/console-logs-engine.js +115 -0
- package/bin/runners/lib/engines/cross-file-analysis-engine.js +268 -0
- package/bin/runners/lib/engines/dead-code-engine.js +198 -0
- package/bin/runners/lib/engines/deprecated-api-engine.js +226 -0
- package/bin/runners/lib/engines/empty-catch-engine.js +150 -0
- package/bin/runners/lib/engines/file-filter.js +131 -0
- package/bin/runners/lib/engines/hardcoded-secrets-engine.js +251 -0
- package/bin/runners/lib/engines/mock-data-engine.js +272 -0
- package/bin/runners/lib/engines/parallel-processor.js +71 -0
- package/bin/runners/lib/engines/performance-issues-engine.js +265 -0
- package/bin/runners/lib/engines/security-vulnerabilities-engine.js +243 -0
- package/bin/runners/lib/engines/todo-fixme-engine.js +115 -0
- package/bin/runners/lib/engines/type-aware-engine.js +152 -0
- package/bin/runners/lib/engines/unsafe-regex-engine.js +225 -0
- package/bin/runners/lib/engines/vibecheck-engines/README.md +53 -0
- package/bin/runners/lib/engines/vibecheck-engines/index.js +15 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/ast-cache.js +164 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/code-quality-engine.js +291 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/console-logs-engine.js +83 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/dead-code-engine.js +198 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/deprecated-api-engine.js +275 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/empty-catch-engine.js +167 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/file-filter.js +217 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/hardcoded-secrets-engine.js +139 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/mock-data-engine.js +140 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/parallel-processor.js +164 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/performance-issues-engine.js +234 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/type-aware-engine.js +217 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/unsafe-regex-engine.js +78 -0
- package/bin/runners/lib/engines/vibecheck-engines/package.json +13 -0
- package/bin/runners/lib/enterprise-detect.js +603 -603
- package/bin/runners/lib/enterprise-init.js +942 -942
- package/bin/runners/lib/env-resolver.js +417 -417
- package/bin/runners/lib/env-template.js +66 -66
- package/bin/runners/lib/env.js +189 -189
- package/bin/runners/lib/extractors/client-calls.js +990 -990
- package/bin/runners/lib/extractors/fastify-route-dump.js +573 -573
- package/bin/runners/lib/extractors/fastify-routes.js +426 -426
- package/bin/runners/lib/extractors/index.js +363 -363
- package/bin/runners/lib/extractors/next-routes.js +524 -524
- package/bin/runners/lib/extractors/proof-graph.js +431 -431
- package/bin/runners/lib/extractors/route-matcher.js +451 -451
- package/bin/runners/lib/extractors/truthpack-v2.js +377 -377
- package/bin/runners/lib/extractors/ui-bindings.js +547 -547
- package/bin/runners/lib/findings-schema.js +281 -281
- package/bin/runners/lib/firewall-prompt.js +50 -50
- package/bin/runners/lib/global-flags.js +213 -213
- package/bin/runners/lib/graph/graph-builder.js +265 -265
- package/bin/runners/lib/graph/html-renderer.js +413 -413
- package/bin/runners/lib/graph/index.js +32 -32
- package/bin/runners/lib/graph/runtime-collector.js +215 -215
- package/bin/runners/lib/graph/static-extractor.js +518 -518
- package/bin/runners/lib/html-report.js +650 -650
- package/bin/runners/lib/interactive-menu.js +1496 -1496
- package/bin/runners/lib/llm.js +75 -75
- package/bin/runners/lib/meter.js +61 -61
- package/bin/runners/lib/missions/evidence.js +126 -126
- package/bin/runners/lib/patch.js +40 -40
- package/bin/runners/lib/permissions/auth-model.js +213 -213
- package/bin/runners/lib/permissions/idor-prover.js +205 -205
- package/bin/runners/lib/permissions/index.js +45 -45
- package/bin/runners/lib/permissions/matrix-builder.js +198 -198
- package/bin/runners/lib/pkgjson.js +28 -28
- package/bin/runners/lib/policy.js +295 -295
- package/bin/runners/lib/preflight.js +142 -142
- package/bin/runners/lib/reality/correlation-detectors.js +359 -359
- package/bin/runners/lib/reality/index.js +318 -318
- package/bin/runners/lib/reality/request-hashing.js +416 -416
- package/bin/runners/lib/reality/request-mapper.js +453 -453
- package/bin/runners/lib/reality/safety-rails.js +463 -463
- package/bin/runners/lib/reality/semantic-snapshot.js +408 -408
- package/bin/runners/lib/reality/toast-detector.js +393 -393
- package/bin/runners/lib/reality-findings.js +84 -84
- package/bin/runners/lib/receipts.js +179 -179
- package/bin/runners/lib/redact.js +29 -29
- package/bin/runners/lib/replay/capsule-manager.js +154 -154
- package/bin/runners/lib/replay/index.js +263 -263
- package/bin/runners/lib/replay/player.js +348 -348
- package/bin/runners/lib/replay/recorder.js +331 -331
- package/bin/runners/lib/report-output.js +187 -187
- package/bin/runners/lib/report.js +135 -135
- package/bin/runners/lib/route-detection.js +1140 -1140
- package/bin/runners/lib/sandbox/index.js +59 -59
- package/bin/runners/lib/sandbox/proof-chain.js +399 -399
- package/bin/runners/lib/sandbox/sandbox-runner.js +205 -205
- package/bin/runners/lib/sandbox/worktree.js +174 -174
- package/bin/runners/lib/scan-output.js +525 -190
- package/bin/runners/lib/schema-validator.js +350 -350
- package/bin/runners/lib/schemas/contracts.schema.json +160 -160
- package/bin/runners/lib/schemas/finding.schema.json +100 -100
- package/bin/runners/lib/schemas/mission-pack.schema.json +206 -206
- package/bin/runners/lib/schemas/proof-graph.schema.json +176 -176
- package/bin/runners/lib/schemas/reality-report.schema.json +162 -162
- package/bin/runners/lib/schemas/share-pack.schema.json +180 -180
- package/bin/runners/lib/schemas/ship-report.schema.json +117 -117
- package/bin/runners/lib/schemas/truthpack-v2.schema.json +303 -303
- package/bin/runners/lib/schemas/validator.js +438 -438
- package/bin/runners/lib/score-history.js +282 -282
- package/bin/runners/lib/share-pack.js +239 -239
- package/bin/runners/lib/snippets.js +67 -67
- package/bin/runners/lib/status-output.js +253 -253
- package/bin/runners/lib/terminal-ui.js +351 -271
- package/bin/runners/lib/upsell.js +510 -510
- package/bin/runners/lib/usage.js +153 -153
- package/bin/runners/lib/validate-patch.js +156 -156
- package/bin/runners/lib/verdict-engine.js +628 -628
- package/bin/runners/reality/engine.js +917 -917
- package/bin/runners/reality/flows.js +122 -122
- package/bin/runners/reality/report.js +378 -378
- package/bin/runners/reality/session.js +193 -193
- package/bin/runners/runGuard.js +168 -168
- package/bin/runners/runProof.zip +0 -0
- package/bin/runners/runProve.js +8 -0
- package/bin/runners/runReality.js +14 -0
- package/bin/runners/runScan.js +17 -1
- package/bin/runners/runTruth.js +15 -3
- package/mcp-server/tier-auth.js +4 -4
- package/mcp-server/tools/index.js +72 -72
- package/package.json +1 -1
|
@@ -1,193 +1,193 @@
|
|
|
1
|
-
// bin/runners/lib/auth-truth.js
|
|
2
|
-
// Auth Truth v1 - Detects auth/protection patterns in Next + Fastify codebases
|
|
3
|
-
const fg = require("fast-glob");
|
|
4
|
-
const fs = require("fs");
|
|
5
|
-
const path = require("path");
|
|
6
|
-
const crypto = require("crypto");
|
|
7
|
-
|
|
8
|
-
function sha256(text) {
|
|
9
|
-
return "sha256:" + crypto.createHash("sha256").update(text).digest("hex");
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
function safeRead(fileAbs) {
|
|
13
|
-
return fs.readFileSync(fileAbs, "utf8");
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
function evidenceFromLine({ fileAbs, repoRoot, lineNo, reason }) {
|
|
17
|
-
const fileRel = path.relative(repoRoot, fileAbs).replace(/\\/g, "/");
|
|
18
|
-
const lines = safeRead(fileAbs).split(/\r?\n/);
|
|
19
|
-
const idx = Math.max(0, Math.min(lines.length - 1, lineNo - 1));
|
|
20
|
-
const snippet = lines[idx] || "";
|
|
21
|
-
return {
|
|
22
|
-
id: `ev_${crypto.randomBytes(4).toString("hex")}`,
|
|
23
|
-
file: fileRel,
|
|
24
|
-
lines: `${lineNo}-${lineNo}`,
|
|
25
|
-
snippetHash: sha256(snippet),
|
|
26
|
-
reason
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function findLineMatches(code, regex) {
|
|
31
|
-
const out = [];
|
|
32
|
-
const lines = code.split(/\r?\n/);
|
|
33
|
-
for (let i = 0; i < lines.length; i++) {
|
|
34
|
-
if (regex.test(lines[i])) out.push(i + 1);
|
|
35
|
-
}
|
|
36
|
-
return out;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
function guessAuthSignalsFromCode(code) {
|
|
40
|
-
const signals = [];
|
|
41
|
-
|
|
42
|
-
const patterns = [
|
|
43
|
-
{ key: "next_middleware", rx: /\bNextResponse\.(redirect|rewrite)\b/ },
|
|
44
|
-
{ key: "next_auth", rx: /\bgetServerSession\b|\bNextAuth\b|\bauth\(\)\b/ },
|
|
45
|
-
{ key: "clerk", rx: /\bclerkMiddleware\b|\bauthMiddleware\b|@clerk\/nextjs/ },
|
|
46
|
-
{ key: "supabase", rx: /\bcreateRouteHandlerClient\b|\bcreateServerClient\b|@supabase/ },
|
|
47
|
-
{ key: "jwt_verify", rx: /\b(jwtVerify|verifyJWT|verifyToken|authorization|bearer)\b/i },
|
|
48
|
-
{ key: "session", rx: /\b(session|cookie|setCookie|getCookie)\b/i },
|
|
49
|
-
{ key: "rbac", rx: /\b(role|roles|permissions|rbac|isAdmin|adminOnly)\b/i },
|
|
50
|
-
{ key: "fastify_hook", rx: /\.addHook\(\s*['"](onRequest|preHandler|preValidation)['"]/ },
|
|
51
|
-
{ key: "fastify_jwt", rx: /@fastify\/jwt|fastify-jwt|fastify\.jwt/i },
|
|
52
|
-
];
|
|
53
|
-
|
|
54
|
-
for (const p of patterns) {
|
|
55
|
-
if (p.rx.test(code)) signals.push(p.key);
|
|
56
|
-
}
|
|
57
|
-
return Array.from(new Set(signals));
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
async function resolveNextMiddleware(repoRoot) {
|
|
61
|
-
const candidates = await fg(
|
|
62
|
-
["middleware.@(ts|js)", "src/middleware.@(ts|js)"],
|
|
63
|
-
{ cwd: repoRoot, absolute: true, onlyFiles: true }
|
|
64
|
-
);
|
|
65
|
-
|
|
66
|
-
const middlewares = [];
|
|
67
|
-
|
|
68
|
-
for (const fileAbs of candidates) {
|
|
69
|
-
const code = safeRead(fileAbs);
|
|
70
|
-
const fileRel = path.relative(repoRoot, fileAbs).replace(/\\/g, "/");
|
|
71
|
-
|
|
72
|
-
const matcherLines = findLineMatches(code, /\bmatcher\b/);
|
|
73
|
-
const redirectLines = findLineMatches(code, /\bNextResponse\.(redirect|rewrite)\b/);
|
|
74
|
-
|
|
75
|
-
const evidence = [];
|
|
76
|
-
for (const ln of matcherLines.slice(0, 5)) {
|
|
77
|
-
evidence.push(evidenceFromLine({ fileAbs, repoRoot, lineNo: ln, reason: "Next middleware matcher config" }));
|
|
78
|
-
}
|
|
79
|
-
for (const ln of redirectLines.slice(0, 5)) {
|
|
80
|
-
evidence.push(evidenceFromLine({ fileAbs, repoRoot, lineNo: ln, reason: "Next middleware redirect/rewrite" }));
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const matcher = [];
|
|
84
|
-
const matcherBlock = code.match(/matcher\s*:\s*(\[[\s\S]*?\])/);
|
|
85
|
-
if (matcherBlock && matcherBlock[1]) {
|
|
86
|
-
const raw = matcherBlock[1];
|
|
87
|
-
const strings = Array.from(raw.matchAll(/['"`]([^'"`]+)['"`]/g)).map(m => m[1]);
|
|
88
|
-
matcher.push(...strings);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
middlewares.push({
|
|
92
|
-
file: fileRel,
|
|
93
|
-
matcher,
|
|
94
|
-
signals: guessAuthSignalsFromCode(code),
|
|
95
|
-
evidence
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
return middlewares;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
async function resolveFastifyAuthSignals(repoRoot, truthpackRoutes) {
|
|
103
|
-
const handlerFiles = new Set((truthpackRoutes || []).map(r => r.handler).filter(Boolean));
|
|
104
|
-
const signals = [];
|
|
105
|
-
const evidence = [];
|
|
106
|
-
|
|
107
|
-
for (const fileRel of handlerFiles) {
|
|
108
|
-
const fileAbs = path.join(repoRoot, fileRel);
|
|
109
|
-
if (!fs.existsSync(fileAbs)) continue;
|
|
110
|
-
|
|
111
|
-
const code = safeRead(fileAbs);
|
|
112
|
-
const sigs = guessAuthSignalsFromCode(code);
|
|
113
|
-
if (!sigs.length) continue;
|
|
114
|
-
|
|
115
|
-
for (const s of sigs) signals.push({ type: s, file: fileRel });
|
|
116
|
-
|
|
117
|
-
const authLinePatterns = [
|
|
118
|
-
{ rx: /\.addHook\(\s*['"](onRequest|preHandler|preValidation)['"]/, reason: "Fastify hook likely used for auth" },
|
|
119
|
-
{ rx: /\b(jwtVerify|authorization|bearer)\b/i, reason: "JWT/Authorization verification signal" },
|
|
120
|
-
{ rx: /@fastify\/jwt|fastify\.jwt/i, reason: "Fastify JWT plugin signal" },
|
|
121
|
-
{ rx: /\b(isAdmin|adminOnly|permissions|rbac)\b/i, reason: "RBAC/permissions signal" },
|
|
122
|
-
];
|
|
123
|
-
|
|
124
|
-
const lines = code.split(/\r?\n/);
|
|
125
|
-
for (let i = 0; i < lines.length; i++) {
|
|
126
|
-
const line = lines[i];
|
|
127
|
-
for (const p of authLinePatterns) {
|
|
128
|
-
if (p.rx.test(line)) {
|
|
129
|
-
evidence.push({
|
|
130
|
-
id: `ev_${crypto.randomBytes(4).toString("hex")}`,
|
|
131
|
-
file: fileRel,
|
|
132
|
-
lines: `${i + 1}-${i + 1}`,
|
|
133
|
-
snippetHash: sha256(line),
|
|
134
|
-
reason: p.reason
|
|
135
|
-
});
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
if (evidence.length > 30) break;
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
const uniqueTypes = Array.from(new Set(signals.map(s => s.type)));
|
|
143
|
-
|
|
144
|
-
return {
|
|
145
|
-
signalTypes: uniqueTypes,
|
|
146
|
-
signals,
|
|
147
|
-
evidence
|
|
148
|
-
};
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
function matcherCoversPath(matcherList, p) {
|
|
152
|
-
if (!Array.isArray(matcherList) || !matcherList.length) return false;
|
|
153
|
-
const pathStr = p.startsWith("/") ? p : `/${p}`;
|
|
154
|
-
|
|
155
|
-
return matcherList.some(m => {
|
|
156
|
-
if (!m) return false;
|
|
157
|
-
|
|
158
|
-
if (m.includes(":path*")) {
|
|
159
|
-
const prefix = m.split(":path*")[0].replace(/\/$/, "");
|
|
160
|
-
return pathStr.startsWith(prefix || "/");
|
|
161
|
-
}
|
|
162
|
-
if (m.includes("(.*)")) {
|
|
163
|
-
const prefix = m.split("(.*)")[0].replace(/\/$/, "");
|
|
164
|
-
return pathStr.startsWith(prefix || "/");
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
if (m === pathStr) return true;
|
|
168
|
-
if (pathStr.startsWith(m.endsWith("/") ? m : m + "/")) return true;
|
|
169
|
-
|
|
170
|
-
return false;
|
|
171
|
-
});
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
async function buildAuthTruth(repoRoot, routesServer) {
|
|
175
|
-
const middlewares = await resolveNextMiddleware(repoRoot);
|
|
176
|
-
const matchers = middlewares.flatMap(mw => mw.matcher || []);
|
|
177
|
-
const fastify = await resolveFastifyAuthSignals(repoRoot, routesServer);
|
|
178
|
-
|
|
179
|
-
return {
|
|
180
|
-
nextMiddleware: middlewares,
|
|
181
|
-
nextMatcherPatterns: matchers,
|
|
182
|
-
fastify,
|
|
183
|
-
helpers: {
|
|
184
|
-
matcherCoversPath: "runtime-only"
|
|
185
|
-
}
|
|
186
|
-
};
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
module.exports = {
|
|
190
|
-
buildAuthTruth,
|
|
191
|
-
matcherCoversPath,
|
|
192
|
-
guessAuthSignalsFromCode
|
|
193
|
-
};
|
|
1
|
+
// bin/runners/lib/auth-truth.js
|
|
2
|
+
// Auth Truth v1 - Detects auth/protection patterns in Next + Fastify codebases
|
|
3
|
+
const fg = require("fast-glob");
|
|
4
|
+
const fs = require("fs");
|
|
5
|
+
const path = require("path");
|
|
6
|
+
const crypto = require("crypto");
|
|
7
|
+
|
|
8
|
+
function sha256(text) {
|
|
9
|
+
return "sha256:" + crypto.createHash("sha256").update(text).digest("hex");
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function safeRead(fileAbs) {
|
|
13
|
+
return fs.readFileSync(fileAbs, "utf8");
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function evidenceFromLine({ fileAbs, repoRoot, lineNo, reason }) {
|
|
17
|
+
const fileRel = path.relative(repoRoot, fileAbs).replace(/\\/g, "/");
|
|
18
|
+
const lines = safeRead(fileAbs).split(/\r?\n/);
|
|
19
|
+
const idx = Math.max(0, Math.min(lines.length - 1, lineNo - 1));
|
|
20
|
+
const snippet = lines[idx] || "";
|
|
21
|
+
return {
|
|
22
|
+
id: `ev_${crypto.randomBytes(4).toString("hex")}`,
|
|
23
|
+
file: fileRel,
|
|
24
|
+
lines: `${lineNo}-${lineNo}`,
|
|
25
|
+
snippetHash: sha256(snippet),
|
|
26
|
+
reason
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function findLineMatches(code, regex) {
|
|
31
|
+
const out = [];
|
|
32
|
+
const lines = code.split(/\r?\n/);
|
|
33
|
+
for (let i = 0; i < lines.length; i++) {
|
|
34
|
+
if (regex.test(lines[i])) out.push(i + 1);
|
|
35
|
+
}
|
|
36
|
+
return out;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function guessAuthSignalsFromCode(code) {
|
|
40
|
+
const signals = [];
|
|
41
|
+
|
|
42
|
+
const patterns = [
|
|
43
|
+
{ key: "next_middleware", rx: /\bNextResponse\.(redirect|rewrite)\b/ },
|
|
44
|
+
{ key: "next_auth", rx: /\bgetServerSession\b|\bNextAuth\b|\bauth\(\)\b/ },
|
|
45
|
+
{ key: "clerk", rx: /\bclerkMiddleware\b|\bauthMiddleware\b|@clerk\/nextjs/ },
|
|
46
|
+
{ key: "supabase", rx: /\bcreateRouteHandlerClient\b|\bcreateServerClient\b|@supabase/ },
|
|
47
|
+
{ key: "jwt_verify", rx: /\b(jwtVerify|verifyJWT|verifyToken|authorization|bearer)\b/i },
|
|
48
|
+
{ key: "session", rx: /\b(session|cookie|setCookie|getCookie)\b/i },
|
|
49
|
+
{ key: "rbac", rx: /\b(role|roles|permissions|rbac|isAdmin|adminOnly)\b/i },
|
|
50
|
+
{ key: "fastify_hook", rx: /\.addHook\(\s*['"](onRequest|preHandler|preValidation)['"]/ },
|
|
51
|
+
{ key: "fastify_jwt", rx: /@fastify\/jwt|fastify-jwt|fastify\.jwt/i },
|
|
52
|
+
];
|
|
53
|
+
|
|
54
|
+
for (const p of patterns) {
|
|
55
|
+
if (p.rx.test(code)) signals.push(p.key);
|
|
56
|
+
}
|
|
57
|
+
return Array.from(new Set(signals));
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async function resolveNextMiddleware(repoRoot) {
|
|
61
|
+
const candidates = await fg(
|
|
62
|
+
["middleware.@(ts|js)", "src/middleware.@(ts|js)"],
|
|
63
|
+
{ cwd: repoRoot, absolute: true, onlyFiles: true }
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
const middlewares = [];
|
|
67
|
+
|
|
68
|
+
for (const fileAbs of candidates) {
|
|
69
|
+
const code = safeRead(fileAbs);
|
|
70
|
+
const fileRel = path.relative(repoRoot, fileAbs).replace(/\\/g, "/");
|
|
71
|
+
|
|
72
|
+
const matcherLines = findLineMatches(code, /\bmatcher\b/);
|
|
73
|
+
const redirectLines = findLineMatches(code, /\bNextResponse\.(redirect|rewrite)\b/);
|
|
74
|
+
|
|
75
|
+
const evidence = [];
|
|
76
|
+
for (const ln of matcherLines.slice(0, 5)) {
|
|
77
|
+
evidence.push(evidenceFromLine({ fileAbs, repoRoot, lineNo: ln, reason: "Next middleware matcher config" }));
|
|
78
|
+
}
|
|
79
|
+
for (const ln of redirectLines.slice(0, 5)) {
|
|
80
|
+
evidence.push(evidenceFromLine({ fileAbs, repoRoot, lineNo: ln, reason: "Next middleware redirect/rewrite" }));
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const matcher = [];
|
|
84
|
+
const matcherBlock = code.match(/matcher\s*:\s*(\[[\s\S]*?\])/);
|
|
85
|
+
if (matcherBlock && matcherBlock[1]) {
|
|
86
|
+
const raw = matcherBlock[1];
|
|
87
|
+
const strings = Array.from(raw.matchAll(/['"`]([^'"`]+)['"`]/g)).map(m => m[1]);
|
|
88
|
+
matcher.push(...strings);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
middlewares.push({
|
|
92
|
+
file: fileRel,
|
|
93
|
+
matcher,
|
|
94
|
+
signals: guessAuthSignalsFromCode(code),
|
|
95
|
+
evidence
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return middlewares;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
async function resolveFastifyAuthSignals(repoRoot, truthpackRoutes) {
|
|
103
|
+
const handlerFiles = new Set((truthpackRoutes || []).map(r => r.handler).filter(Boolean));
|
|
104
|
+
const signals = [];
|
|
105
|
+
const evidence = [];
|
|
106
|
+
|
|
107
|
+
for (const fileRel of handlerFiles) {
|
|
108
|
+
const fileAbs = path.join(repoRoot, fileRel);
|
|
109
|
+
if (!fs.existsSync(fileAbs)) continue;
|
|
110
|
+
|
|
111
|
+
const code = safeRead(fileAbs);
|
|
112
|
+
const sigs = guessAuthSignalsFromCode(code);
|
|
113
|
+
if (!sigs.length) continue;
|
|
114
|
+
|
|
115
|
+
for (const s of sigs) signals.push({ type: s, file: fileRel });
|
|
116
|
+
|
|
117
|
+
const authLinePatterns = [
|
|
118
|
+
{ rx: /\.addHook\(\s*['"](onRequest|preHandler|preValidation)['"]/, reason: "Fastify hook likely used for auth" },
|
|
119
|
+
{ rx: /\b(jwtVerify|authorization|bearer)\b/i, reason: "JWT/Authorization verification signal" },
|
|
120
|
+
{ rx: /@fastify\/jwt|fastify\.jwt/i, reason: "Fastify JWT plugin signal" },
|
|
121
|
+
{ rx: /\b(isAdmin|adminOnly|permissions|rbac)\b/i, reason: "RBAC/permissions signal" },
|
|
122
|
+
];
|
|
123
|
+
|
|
124
|
+
const lines = code.split(/\r?\n/);
|
|
125
|
+
for (let i = 0; i < lines.length; i++) {
|
|
126
|
+
const line = lines[i];
|
|
127
|
+
for (const p of authLinePatterns) {
|
|
128
|
+
if (p.rx.test(line)) {
|
|
129
|
+
evidence.push({
|
|
130
|
+
id: `ev_${crypto.randomBytes(4).toString("hex")}`,
|
|
131
|
+
file: fileRel,
|
|
132
|
+
lines: `${i + 1}-${i + 1}`,
|
|
133
|
+
snippetHash: sha256(line),
|
|
134
|
+
reason: p.reason
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
if (evidence.length > 30) break;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const uniqueTypes = Array.from(new Set(signals.map(s => s.type)));
|
|
143
|
+
|
|
144
|
+
return {
|
|
145
|
+
signalTypes: uniqueTypes,
|
|
146
|
+
signals,
|
|
147
|
+
evidence
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function matcherCoversPath(matcherList, p) {
|
|
152
|
+
if (!Array.isArray(matcherList) || !matcherList.length) return false;
|
|
153
|
+
const pathStr = p.startsWith("/") ? p : `/${p}`;
|
|
154
|
+
|
|
155
|
+
return matcherList.some(m => {
|
|
156
|
+
if (!m) return false;
|
|
157
|
+
|
|
158
|
+
if (m.includes(":path*")) {
|
|
159
|
+
const prefix = m.split(":path*")[0].replace(/\/$/, "");
|
|
160
|
+
return pathStr.startsWith(prefix || "/");
|
|
161
|
+
}
|
|
162
|
+
if (m.includes("(.*)")) {
|
|
163
|
+
const prefix = m.split("(.*)")[0].replace(/\/$/, "");
|
|
164
|
+
return pathStr.startsWith(prefix || "/");
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (m === pathStr) return true;
|
|
168
|
+
if (pathStr.startsWith(m.endsWith("/") ? m : m + "/")) return true;
|
|
169
|
+
|
|
170
|
+
return false;
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
async function buildAuthTruth(repoRoot, routesServer) {
|
|
175
|
+
const middlewares = await resolveNextMiddleware(repoRoot);
|
|
176
|
+
const matchers = middlewares.flatMap(mw => mw.matcher || []);
|
|
177
|
+
const fastify = await resolveFastifyAuthSignals(repoRoot, routesServer);
|
|
178
|
+
|
|
179
|
+
return {
|
|
180
|
+
nextMiddleware: middlewares,
|
|
181
|
+
nextMatcherPatterns: matchers,
|
|
182
|
+
fastify,
|
|
183
|
+
helpers: {
|
|
184
|
+
matcherCoversPath: "runtime-only"
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
module.exports = {
|
|
190
|
+
buildAuthTruth,
|
|
191
|
+
matcherCoversPath,
|
|
192
|
+
guessAuthSignalsFromCode
|
|
193
|
+
};
|
|
@@ -1,62 +1,62 @@
|
|
|
1
|
-
// bin/runners/lib/backup.js
|
|
2
|
-
const fs = require("fs");
|
|
3
|
-
const path = require("path");
|
|
4
|
-
|
|
5
|
-
function ensureDir(p) {
|
|
6
|
-
fs.mkdirSync(p, { recursive: true });
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
function backupFiles(repoRoot, fileRelPaths, backupRoot) {
|
|
10
|
-
ensureDir(backupRoot);
|
|
11
|
-
|
|
12
|
-
const saved = [];
|
|
13
|
-
for (const rel of fileRelPaths) {
|
|
14
|
-
const abs = path.join(repoRoot, rel);
|
|
15
|
-
if (!fs.existsSync(abs)) {
|
|
16
|
-
saved.push({ rel, existed: false });
|
|
17
|
-
continue;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const dest = path.join(backupRoot, rel);
|
|
21
|
-
ensureDir(path.dirname(dest));
|
|
22
|
-
fs.copyFileSync(abs, dest);
|
|
23
|
-
saved.push({ rel, existed: true });
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
fs.writeFileSync(
|
|
27
|
-
path.join(backupRoot, "_manifest.json"),
|
|
28
|
-
JSON.stringify({ saved }, null, 2),
|
|
29
|
-
"utf8"
|
|
30
|
-
);
|
|
31
|
-
|
|
32
|
-
return saved;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function restoreBackup(repoRoot, backupRoot) {
|
|
36
|
-
const manifestPath = path.join(backupRoot, "_manifest.json");
|
|
37
|
-
if (!fs.existsSync(manifestPath)) {
|
|
38
|
-
return { ok: false, error: "backup manifest missing" };
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
|
|
42
|
-
const saved = manifest.saved || [];
|
|
43
|
-
|
|
44
|
-
for (const s of saved) {
|
|
45
|
-
const abs = path.join(repoRoot, s.rel);
|
|
46
|
-
const bak = path.join(backupRoot, s.rel);
|
|
47
|
-
|
|
48
|
-
if (!s.existed) {
|
|
49
|
-
if (fs.existsSync(abs)) fs.rmSync(abs, { force: true });
|
|
50
|
-
continue;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
if (fs.existsSync(bak)) {
|
|
54
|
-
ensureDir(path.dirname(abs));
|
|
55
|
-
fs.copyFileSync(bak, abs);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
return { ok: true };
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
module.exports = { backupFiles, restoreBackup };
|
|
1
|
+
// bin/runners/lib/backup.js
|
|
2
|
+
const fs = require("fs");
|
|
3
|
+
const path = require("path");
|
|
4
|
+
|
|
5
|
+
function ensureDir(p) {
|
|
6
|
+
fs.mkdirSync(p, { recursive: true });
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function backupFiles(repoRoot, fileRelPaths, backupRoot) {
|
|
10
|
+
ensureDir(backupRoot);
|
|
11
|
+
|
|
12
|
+
const saved = [];
|
|
13
|
+
for (const rel of fileRelPaths) {
|
|
14
|
+
const abs = path.join(repoRoot, rel);
|
|
15
|
+
if (!fs.existsSync(abs)) {
|
|
16
|
+
saved.push({ rel, existed: false });
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const dest = path.join(backupRoot, rel);
|
|
21
|
+
ensureDir(path.dirname(dest));
|
|
22
|
+
fs.copyFileSync(abs, dest);
|
|
23
|
+
saved.push({ rel, existed: true });
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
fs.writeFileSync(
|
|
27
|
+
path.join(backupRoot, "_manifest.json"),
|
|
28
|
+
JSON.stringify({ saved }, null, 2),
|
|
29
|
+
"utf8"
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
return saved;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function restoreBackup(repoRoot, backupRoot) {
|
|
36
|
+
const manifestPath = path.join(backupRoot, "_manifest.json");
|
|
37
|
+
if (!fs.existsSync(manifestPath)) {
|
|
38
|
+
return { ok: false, error: "backup manifest missing" };
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
|
|
42
|
+
const saved = manifest.saved || [];
|
|
43
|
+
|
|
44
|
+
for (const s of saved) {
|
|
45
|
+
const abs = path.join(repoRoot, s.rel);
|
|
46
|
+
const bak = path.join(backupRoot, s.rel);
|
|
47
|
+
|
|
48
|
+
if (!s.existed) {
|
|
49
|
+
if (fs.existsSync(abs)) fs.rmSync(abs, { force: true });
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (fs.existsSync(bak)) {
|
|
54
|
+
ensureDir(path.dirname(abs));
|
|
55
|
+
fs.copyFileSync(bak, abs);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return { ok: true };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
module.exports = { backupFiles, restoreBackup };
|