@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,213 +1,213 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Auth Model Extractor
|
|
3
|
-
* Extracts authorization model from code and contracts
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
"use strict";
|
|
7
|
-
|
|
8
|
-
const fs = require("fs");
|
|
9
|
-
const path = require("path");
|
|
10
|
-
const fg = require("fast-glob");
|
|
11
|
-
const parser = require("@babel/parser");
|
|
12
|
-
const traverse = require("@babel/traverse").default;
|
|
13
|
-
const t = require("@babel/types");
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Extract auth model from codebase
|
|
17
|
-
*/
|
|
18
|
-
async function extractAuthModel(repoRoot, truthpack) {
|
|
19
|
-
const model = {
|
|
20
|
-
version: "1.0.0",
|
|
21
|
-
generatedAt: new Date().toISOString(),
|
|
22
|
-
roles: [],
|
|
23
|
-
routes: [],
|
|
24
|
-
rbacPatterns: [],
|
|
25
|
-
evidence: []
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
// Extract from truthpack
|
|
29
|
-
if (truthpack?.auth) {
|
|
30
|
-
model.protectedPatterns = truthpack.auth.nextMatcherPatterns || [];
|
|
31
|
-
|
|
32
|
-
// Add middleware evidence
|
|
33
|
-
for (const mw of truthpack.auth.nextMiddleware || []) {
|
|
34
|
-
model.evidence.push({
|
|
35
|
-
type: "next_middleware",
|
|
36
|
-
file: mw.file,
|
|
37
|
-
signals: mw.signalTypes || []
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// Extract role patterns from code
|
|
43
|
-
const rolePatterns = await extractRolePatterns(repoRoot);
|
|
44
|
-
model.rbacPatterns = rolePatterns;
|
|
45
|
-
|
|
46
|
-
// Infer roles from patterns
|
|
47
|
-
model.roles = inferRoles(rolePatterns, truthpack);
|
|
48
|
-
|
|
49
|
-
// Build route auth map
|
|
50
|
-
model.routes = buildRouteAuthMap(truthpack, model.roles);
|
|
51
|
-
|
|
52
|
-
return model;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Extract RBAC patterns from code
|
|
57
|
-
*/
|
|
58
|
-
async function extractRolePatterns(repoRoot) {
|
|
59
|
-
const patterns = [];
|
|
60
|
-
|
|
61
|
-
const files = await fg(["**/*.{ts,tsx,js,jsx}"], {
|
|
62
|
-
cwd: repoRoot,
|
|
63
|
-
absolute: true,
|
|
64
|
-
ignore: ["**/node_modules/**", "**/.next/**", "**/dist/**", "**/build/**"]
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
for (const fileAbs of files) {
|
|
68
|
-
const fileRel = path.relative(repoRoot, fileAbs).replace(/\\/g, "/");
|
|
69
|
-
const code = fs.readFileSync(fileAbs, "utf8");
|
|
70
|
-
|
|
71
|
-
// Look for role-related patterns
|
|
72
|
-
const roleMatches = [
|
|
73
|
-
// role === 'admin'
|
|
74
|
-
/role\s*===?\s*['"](\w+)['"]/gi,
|
|
75
|
-
// isAdmin, isUser
|
|
76
|
-
/\b(is(?:Admin|User|Manager|Owner|Moderator))\b/gi,
|
|
77
|
-
// hasRole('admin')
|
|
78
|
-
/hasRole\s*\(\s*['"](\w+)['"]\s*\)/gi,
|
|
79
|
-
// checkPermission('edit')
|
|
80
|
-
/check(?:Permission|Auth)\s*\(\s*['"](\w+)['"]\s*\)/gi,
|
|
81
|
-
// [role: 'admin']
|
|
82
|
-
/role:\s*['"](\w+)['"]/gi
|
|
83
|
-
];
|
|
84
|
-
|
|
85
|
-
for (const pattern of roleMatches) {
|
|
86
|
-
let match;
|
|
87
|
-
while ((match = pattern.exec(code)) !== null) {
|
|
88
|
-
patterns.push({
|
|
89
|
-
type: "role_check",
|
|
90
|
-
file: fileRel,
|
|
91
|
-
role: match[1],
|
|
92
|
-
line: code.substring(0, match.index).split("\n").length
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
return patterns;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Infer roles from patterns
|
|
103
|
-
*/
|
|
104
|
-
function inferRoles(patterns, truthpack) {
|
|
105
|
-
const roleNames = new Set();
|
|
106
|
-
|
|
107
|
-
// Common roles
|
|
108
|
-
roleNames.add("user");
|
|
109
|
-
roleNames.add("admin");
|
|
110
|
-
|
|
111
|
-
// From patterns
|
|
112
|
-
for (const p of patterns) {
|
|
113
|
-
if (p.role) {
|
|
114
|
-
roleNames.add(p.role.toLowerCase());
|
|
115
|
-
}
|
|
116
|
-
// Extract from isAdmin -> admin
|
|
117
|
-
if (p.role?.startsWith("is")) {
|
|
118
|
-
roleNames.add(p.role.substring(2).toLowerCase());
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// Build role objects
|
|
123
|
-
const roles = [];
|
|
124
|
-
for (const name of roleNames) {
|
|
125
|
-
const role = {
|
|
126
|
-
name,
|
|
127
|
-
routes: [],
|
|
128
|
-
evidence: patterns.filter(p =>
|
|
129
|
-
p.role?.toLowerCase() === name ||
|
|
130
|
-
p.role?.toLowerCase() === `is${name}`
|
|
131
|
-
)
|
|
132
|
-
};
|
|
133
|
-
roles.push(role);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
return roles;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Build route auth map
|
|
141
|
-
*/
|
|
142
|
-
function buildRouteAuthMap(truthpack, roles) {
|
|
143
|
-
const routes = [];
|
|
144
|
-
const serverRoutes = truthpack?.routes?.server || [];
|
|
145
|
-
const protectedPatterns = truthpack?.auth?.nextMatcherPatterns || [];
|
|
146
|
-
|
|
147
|
-
for (const route of serverRoutes) {
|
|
148
|
-
const isProtected = protectedPatterns.some(p => matchesPattern(route.path, p));
|
|
149
|
-
|
|
150
|
-
const routeAuth = {
|
|
151
|
-
path: route.path,
|
|
152
|
-
method: route.method,
|
|
153
|
-
handler: route.handler,
|
|
154
|
-
declared: {
|
|
155
|
-
protected: isProtected,
|
|
156
|
-
roles: inferRouteRoles(route, roles),
|
|
157
|
-
public: !isProtected && isPublicRoute(route.path)
|
|
158
|
-
},
|
|
159
|
-
actual: null // Filled by runtime verification
|
|
160
|
-
};
|
|
161
|
-
|
|
162
|
-
routes.push(routeAuth);
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
return routes;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* Infer which roles can access a route
|
|
170
|
-
*/
|
|
171
|
-
function inferRouteRoles(route, roles) {
|
|
172
|
-
const routeRoles = [];
|
|
173
|
-
|
|
174
|
-
// Admin routes
|
|
175
|
-
if (route.path.includes("/admin")) {
|
|
176
|
-
routeRoles.push("admin");
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
// User routes (most authenticated routes)
|
|
180
|
-
if (!route.path.includes("/admin") && !route.path.includes("/public")) {
|
|
181
|
-
routeRoles.push("user");
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
return routeRoles;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
function isPublicRoute(path) {
|
|
188
|
-
const publicPatterns = [
|
|
189
|
-
/^\/api\/health/i,
|
|
190
|
-
/^\/api\/status/i,
|
|
191
|
-
/^\/api\/public\//i,
|
|
192
|
-
/^\/_next\//i,
|
|
193
|
-
/^\/favicon/i
|
|
194
|
-
];
|
|
195
|
-
return publicPatterns.some(p => p.test(path));
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
function matchesPattern(path, pattern) {
|
|
199
|
-
const normPattern = pattern.replace(/\*/g, ".*").replace(/\//g, "\\/");
|
|
200
|
-
try {
|
|
201
|
-
const rx = new RegExp(`^${normPattern}`, "i");
|
|
202
|
-
return rx.test(path);
|
|
203
|
-
} catch {
|
|
204
|
-
return false;
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
module.exports = {
|
|
209
|
-
extractAuthModel,
|
|
210
|
-
extractRolePatterns,
|
|
211
|
-
inferRoles,
|
|
212
|
-
buildRouteAuthMap
|
|
213
|
-
};
|
|
1
|
+
/**
|
|
2
|
+
* Auth Model Extractor
|
|
3
|
+
* Extracts authorization model from code and contracts
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
"use strict";
|
|
7
|
+
|
|
8
|
+
const fs = require("fs");
|
|
9
|
+
const path = require("path");
|
|
10
|
+
const fg = require("fast-glob");
|
|
11
|
+
const parser = require("@babel/parser");
|
|
12
|
+
const traverse = require("@babel/traverse").default;
|
|
13
|
+
const t = require("@babel/types");
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Extract auth model from codebase
|
|
17
|
+
*/
|
|
18
|
+
async function extractAuthModel(repoRoot, truthpack) {
|
|
19
|
+
const model = {
|
|
20
|
+
version: "1.0.0",
|
|
21
|
+
generatedAt: new Date().toISOString(),
|
|
22
|
+
roles: [],
|
|
23
|
+
routes: [],
|
|
24
|
+
rbacPatterns: [],
|
|
25
|
+
evidence: []
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
// Extract from truthpack
|
|
29
|
+
if (truthpack?.auth) {
|
|
30
|
+
model.protectedPatterns = truthpack.auth.nextMatcherPatterns || [];
|
|
31
|
+
|
|
32
|
+
// Add middleware evidence
|
|
33
|
+
for (const mw of truthpack.auth.nextMiddleware || []) {
|
|
34
|
+
model.evidence.push({
|
|
35
|
+
type: "next_middleware",
|
|
36
|
+
file: mw.file,
|
|
37
|
+
signals: mw.signalTypes || []
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Extract role patterns from code
|
|
43
|
+
const rolePatterns = await extractRolePatterns(repoRoot);
|
|
44
|
+
model.rbacPatterns = rolePatterns;
|
|
45
|
+
|
|
46
|
+
// Infer roles from patterns
|
|
47
|
+
model.roles = inferRoles(rolePatterns, truthpack);
|
|
48
|
+
|
|
49
|
+
// Build route auth map
|
|
50
|
+
model.routes = buildRouteAuthMap(truthpack, model.roles);
|
|
51
|
+
|
|
52
|
+
return model;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Extract RBAC patterns from code
|
|
57
|
+
*/
|
|
58
|
+
async function extractRolePatterns(repoRoot) {
|
|
59
|
+
const patterns = [];
|
|
60
|
+
|
|
61
|
+
const files = await fg(["**/*.{ts,tsx,js,jsx}"], {
|
|
62
|
+
cwd: repoRoot,
|
|
63
|
+
absolute: true,
|
|
64
|
+
ignore: ["**/node_modules/**", "**/.next/**", "**/dist/**", "**/build/**"]
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
for (const fileAbs of files) {
|
|
68
|
+
const fileRel = path.relative(repoRoot, fileAbs).replace(/\\/g, "/");
|
|
69
|
+
const code = fs.readFileSync(fileAbs, "utf8");
|
|
70
|
+
|
|
71
|
+
// Look for role-related patterns
|
|
72
|
+
const roleMatches = [
|
|
73
|
+
// role === 'admin'
|
|
74
|
+
/role\s*===?\s*['"](\w+)['"]/gi,
|
|
75
|
+
// isAdmin, isUser
|
|
76
|
+
/\b(is(?:Admin|User|Manager|Owner|Moderator))\b/gi,
|
|
77
|
+
// hasRole('admin')
|
|
78
|
+
/hasRole\s*\(\s*['"](\w+)['"]\s*\)/gi,
|
|
79
|
+
// checkPermission('edit')
|
|
80
|
+
/check(?:Permission|Auth)\s*\(\s*['"](\w+)['"]\s*\)/gi,
|
|
81
|
+
// [role: 'admin']
|
|
82
|
+
/role:\s*['"](\w+)['"]/gi
|
|
83
|
+
];
|
|
84
|
+
|
|
85
|
+
for (const pattern of roleMatches) {
|
|
86
|
+
let match;
|
|
87
|
+
while ((match = pattern.exec(code)) !== null) {
|
|
88
|
+
patterns.push({
|
|
89
|
+
type: "role_check",
|
|
90
|
+
file: fileRel,
|
|
91
|
+
role: match[1],
|
|
92
|
+
line: code.substring(0, match.index).split("\n").length
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return patterns;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Infer roles from patterns
|
|
103
|
+
*/
|
|
104
|
+
function inferRoles(patterns, truthpack) {
|
|
105
|
+
const roleNames = new Set();
|
|
106
|
+
|
|
107
|
+
// Common roles
|
|
108
|
+
roleNames.add("user");
|
|
109
|
+
roleNames.add("admin");
|
|
110
|
+
|
|
111
|
+
// From patterns
|
|
112
|
+
for (const p of patterns) {
|
|
113
|
+
if (p.role) {
|
|
114
|
+
roleNames.add(p.role.toLowerCase());
|
|
115
|
+
}
|
|
116
|
+
// Extract from isAdmin -> admin
|
|
117
|
+
if (p.role?.startsWith("is")) {
|
|
118
|
+
roleNames.add(p.role.substring(2).toLowerCase());
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Build role objects
|
|
123
|
+
const roles = [];
|
|
124
|
+
for (const name of roleNames) {
|
|
125
|
+
const role = {
|
|
126
|
+
name,
|
|
127
|
+
routes: [],
|
|
128
|
+
evidence: patterns.filter(p =>
|
|
129
|
+
p.role?.toLowerCase() === name ||
|
|
130
|
+
p.role?.toLowerCase() === `is${name}`
|
|
131
|
+
)
|
|
132
|
+
};
|
|
133
|
+
roles.push(role);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return roles;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Build route auth map
|
|
141
|
+
*/
|
|
142
|
+
function buildRouteAuthMap(truthpack, roles) {
|
|
143
|
+
const routes = [];
|
|
144
|
+
const serverRoutes = truthpack?.routes?.server || [];
|
|
145
|
+
const protectedPatterns = truthpack?.auth?.nextMatcherPatterns || [];
|
|
146
|
+
|
|
147
|
+
for (const route of serverRoutes) {
|
|
148
|
+
const isProtected = protectedPatterns.some(p => matchesPattern(route.path, p));
|
|
149
|
+
|
|
150
|
+
const routeAuth = {
|
|
151
|
+
path: route.path,
|
|
152
|
+
method: route.method,
|
|
153
|
+
handler: route.handler,
|
|
154
|
+
declared: {
|
|
155
|
+
protected: isProtected,
|
|
156
|
+
roles: inferRouteRoles(route, roles),
|
|
157
|
+
public: !isProtected && isPublicRoute(route.path)
|
|
158
|
+
},
|
|
159
|
+
actual: null // Filled by runtime verification
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
routes.push(routeAuth);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return routes;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Infer which roles can access a route
|
|
170
|
+
*/
|
|
171
|
+
function inferRouteRoles(route, roles) {
|
|
172
|
+
const routeRoles = [];
|
|
173
|
+
|
|
174
|
+
// Admin routes
|
|
175
|
+
if (route.path.includes("/admin")) {
|
|
176
|
+
routeRoles.push("admin");
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// User routes (most authenticated routes)
|
|
180
|
+
if (!route.path.includes("/admin") && !route.path.includes("/public")) {
|
|
181
|
+
routeRoles.push("user");
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return routeRoles;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function isPublicRoute(path) {
|
|
188
|
+
const publicPatterns = [
|
|
189
|
+
/^\/api\/health/i,
|
|
190
|
+
/^\/api\/status/i,
|
|
191
|
+
/^\/api\/public\//i,
|
|
192
|
+
/^\/_next\//i,
|
|
193
|
+
/^\/favicon/i
|
|
194
|
+
];
|
|
195
|
+
return publicPatterns.some(p => p.test(path));
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function matchesPattern(path, pattern) {
|
|
199
|
+
const normPattern = pattern.replace(/\*/g, ".*").replace(/\//g, "\\/");
|
|
200
|
+
try {
|
|
201
|
+
const rx = new RegExp(`^${normPattern}`, "i");
|
|
202
|
+
return rx.test(path);
|
|
203
|
+
} catch {
|
|
204
|
+
return false;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
module.exports = {
|
|
209
|
+
extractAuthModel,
|
|
210
|
+
extractRolePatterns,
|
|
211
|
+
inferRoles,
|
|
212
|
+
buildRouteAuthMap
|
|
213
|
+
};
|