@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,202 +1,202 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Auth Contract Builder
|
|
3
|
-
* Builds auth.json contract from truthpack
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
"use strict";
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Build auth contract from truthpack
|
|
10
|
-
*/
|
|
11
|
-
function buildAuthContract(truthpack) {
|
|
12
|
-
const contract = {
|
|
13
|
-
version: "1.0.0",
|
|
14
|
-
generatedAt: new Date().toISOString(),
|
|
15
|
-
protectedPatterns: [],
|
|
16
|
-
publicPatterns: [],
|
|
17
|
-
roles: [],
|
|
18
|
-
evidence: []
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
// Extract protected patterns from Next middleware
|
|
22
|
-
const nextMiddleware = truthpack?.auth?.nextMiddleware || [];
|
|
23
|
-
const matcherPatterns = truthpack?.auth?.nextMatcherPatterns || [];
|
|
24
|
-
|
|
25
|
-
contract.protectedPatterns = [...new Set(matcherPatterns)];
|
|
26
|
-
|
|
27
|
-
// Add evidence from middleware files
|
|
28
|
-
for (const mw of nextMiddleware) {
|
|
29
|
-
contract.evidence.push({
|
|
30
|
-
file: mw.file,
|
|
31
|
-
type: "next_middleware",
|
|
32
|
-
signals: mw.signalTypes || []
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// Extract Fastify auth info
|
|
37
|
-
const fastify = truthpack?.auth?.fastify || {};
|
|
38
|
-
if (fastify.hooks?.length) {
|
|
39
|
-
for (const hook of fastify.hooks) {
|
|
40
|
-
contract.evidence.push({
|
|
41
|
-
file: hook.file,
|
|
42
|
-
type: "fastify_hook",
|
|
43
|
-
hookType: hook.hookType,
|
|
44
|
-
line: hook.line
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// Infer roles from truthpack
|
|
50
|
-
contract.roles = inferRoles(truthpack);
|
|
51
|
-
|
|
52
|
-
// Default public patterns
|
|
53
|
-
contract.publicPatterns = [
|
|
54
|
-
"/api/health",
|
|
55
|
-
"/api/status",
|
|
56
|
-
"/api/public/*",
|
|
57
|
-
"/_next/*",
|
|
58
|
-
"/favicon.ico"
|
|
59
|
-
];
|
|
60
|
-
|
|
61
|
-
// Deterministic output: sort all arrays
|
|
62
|
-
contract.protectedPatterns.sort();
|
|
63
|
-
contract.publicPatterns.sort();
|
|
64
|
-
contract.roles.sort((a, b) => a.name.localeCompare(b.name));
|
|
65
|
-
for (const role of contract.roles) {
|
|
66
|
-
if (role.routes) role.routes.sort();
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
return contract;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Infer roles from truthpack
|
|
74
|
-
*/
|
|
75
|
-
function inferRoles(truthpack) {
|
|
76
|
-
const roles = [];
|
|
77
|
-
const routes = truthpack?.routes?.server || [];
|
|
78
|
-
|
|
79
|
-
// Check for admin routes
|
|
80
|
-
const adminRoutes = routes.filter(r => r.path.includes("/admin"));
|
|
81
|
-
if (adminRoutes.length > 0) {
|
|
82
|
-
roles.push({
|
|
83
|
-
name: "admin",
|
|
84
|
-
routes: adminRoutes.map(r => r.path),
|
|
85
|
-
evidence: adminRoutes.flatMap(r => r.evidence || [])
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// Check for user routes (default authenticated)
|
|
90
|
-
const userRoutes = routes.filter(r =>
|
|
91
|
-
!r.path.includes("/admin") &&
|
|
92
|
-
!r.path.includes("/public") &&
|
|
93
|
-
!r.path.includes("/health")
|
|
94
|
-
);
|
|
95
|
-
if (userRoutes.length > 0) {
|
|
96
|
-
roles.push({
|
|
97
|
-
name: "user",
|
|
98
|
-
routes: userRoutes.map(r => r.path),
|
|
99
|
-
evidence: []
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
return roles;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Validate auth coverage
|
|
108
|
-
*/
|
|
109
|
-
function validateAuthContract(contract, routes, realityResults) {
|
|
110
|
-
const violations = [];
|
|
111
|
-
|
|
112
|
-
// Check that all non-public routes are protected
|
|
113
|
-
for (const route of routes) {
|
|
114
|
-
const isPublic = contract.publicPatterns.some(p => matchesPattern(route.path, p));
|
|
115
|
-
const isProtected = contract.protectedPatterns.some(p => matchesPattern(route.path, p));
|
|
116
|
-
|
|
117
|
-
if (!isPublic && !isProtected) {
|
|
118
|
-
// Check if route looks sensitive
|
|
119
|
-
if (looksLikeSensitiveRoute(route.path)) {
|
|
120
|
-
violations.push({
|
|
121
|
-
type: "unprotected_sensitive",
|
|
122
|
-
severity: "WARN",
|
|
123
|
-
route: route.path,
|
|
124
|
-
message: `Sensitive route ${route.path} not covered by auth patterns`,
|
|
125
|
-
evidence: route.evidence || []
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// Check reality results for auth bypass
|
|
132
|
-
if (realityResults) {
|
|
133
|
-
for (const result of realityResults) {
|
|
134
|
-
if (result.type === "AuthCoverage" && result.severity === "BLOCK") {
|
|
135
|
-
violations.push({
|
|
136
|
-
type: "auth_bypass",
|
|
137
|
-
severity: "BLOCK",
|
|
138
|
-
route: result.page,
|
|
139
|
-
message: result.title,
|
|
140
|
-
evidence: []
|
|
141
|
-
});
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
return violations;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
function matchesPattern(path, pattern) {
|
|
150
|
-
const normPattern = pattern.replace(/\*/g, ".*").replace(/\//g, "\\/");
|
|
151
|
-
try {
|
|
152
|
-
const rx = new RegExp(`^${normPattern}`, "i");
|
|
153
|
-
return rx.test(path);
|
|
154
|
-
} catch {
|
|
155
|
-
return false;
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
function looksLikeSensitiveRoute(path) {
|
|
160
|
-
const sensitivePatterns = [
|
|
161
|
-
/\/api\/users/i,
|
|
162
|
-
/\/api\/billing/i,
|
|
163
|
-
/\/api\/payment/i,
|
|
164
|
-
/\/api\/subscription/i,
|
|
165
|
-
/\/api\/settings/i,
|
|
166
|
-
/\/api\/profile/i,
|
|
167
|
-
/\/api\/account/i,
|
|
168
|
-
/\/api\/admin/i,
|
|
169
|
-
/\/api\/webhook/i,
|
|
170
|
-
];
|
|
171
|
-
|
|
172
|
-
return sensitivePatterns.some(p => p.test(path));
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
/**
|
|
176
|
-
* Diff two auth contracts
|
|
177
|
-
*/
|
|
178
|
-
function diffAuthContracts(before, after) {
|
|
179
|
-
const diff = {
|
|
180
|
-
protectedAdded: [],
|
|
181
|
-
protectedRemoved: [],
|
|
182
|
-
rolesChanged: []
|
|
183
|
-
};
|
|
184
|
-
|
|
185
|
-
const beforeProtected = new Set(before.protectedPatterns);
|
|
186
|
-
const afterProtected = new Set(after.protectedPatterns);
|
|
187
|
-
|
|
188
|
-
for (const p of afterProtected) {
|
|
189
|
-
if (!beforeProtected.has(p)) diff.protectedAdded.push(p);
|
|
190
|
-
}
|
|
191
|
-
for (const p of beforeProtected) {
|
|
192
|
-
if (!afterProtected.has(p)) diff.protectedRemoved.push(p);
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
return diff;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
module.exports = {
|
|
199
|
-
buildAuthContract,
|
|
200
|
-
validateAuthContract,
|
|
201
|
-
diffAuthContracts
|
|
202
|
-
};
|
|
1
|
+
/**
|
|
2
|
+
* Auth Contract Builder
|
|
3
|
+
* Builds auth.json contract from truthpack
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
"use strict";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Build auth contract from truthpack
|
|
10
|
+
*/
|
|
11
|
+
function buildAuthContract(truthpack) {
|
|
12
|
+
const contract = {
|
|
13
|
+
version: "1.0.0",
|
|
14
|
+
generatedAt: new Date().toISOString(),
|
|
15
|
+
protectedPatterns: [],
|
|
16
|
+
publicPatterns: [],
|
|
17
|
+
roles: [],
|
|
18
|
+
evidence: []
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
// Extract protected patterns from Next middleware
|
|
22
|
+
const nextMiddleware = truthpack?.auth?.nextMiddleware || [];
|
|
23
|
+
const matcherPatterns = truthpack?.auth?.nextMatcherPatterns || [];
|
|
24
|
+
|
|
25
|
+
contract.protectedPatterns = [...new Set(matcherPatterns)];
|
|
26
|
+
|
|
27
|
+
// Add evidence from middleware files
|
|
28
|
+
for (const mw of nextMiddleware) {
|
|
29
|
+
contract.evidence.push({
|
|
30
|
+
file: mw.file,
|
|
31
|
+
type: "next_middleware",
|
|
32
|
+
signals: mw.signalTypes || []
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Extract Fastify auth info
|
|
37
|
+
const fastify = truthpack?.auth?.fastify || {};
|
|
38
|
+
if (fastify.hooks?.length) {
|
|
39
|
+
for (const hook of fastify.hooks) {
|
|
40
|
+
contract.evidence.push({
|
|
41
|
+
file: hook.file,
|
|
42
|
+
type: "fastify_hook",
|
|
43
|
+
hookType: hook.hookType,
|
|
44
|
+
line: hook.line
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Infer roles from truthpack
|
|
50
|
+
contract.roles = inferRoles(truthpack);
|
|
51
|
+
|
|
52
|
+
// Default public patterns
|
|
53
|
+
contract.publicPatterns = [
|
|
54
|
+
"/api/health",
|
|
55
|
+
"/api/status",
|
|
56
|
+
"/api/public/*",
|
|
57
|
+
"/_next/*",
|
|
58
|
+
"/favicon.ico"
|
|
59
|
+
];
|
|
60
|
+
|
|
61
|
+
// Deterministic output: sort all arrays
|
|
62
|
+
contract.protectedPatterns.sort();
|
|
63
|
+
contract.publicPatterns.sort();
|
|
64
|
+
contract.roles.sort((a, b) => a.name.localeCompare(b.name));
|
|
65
|
+
for (const role of contract.roles) {
|
|
66
|
+
if (role.routes) role.routes.sort();
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return contract;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Infer roles from truthpack
|
|
74
|
+
*/
|
|
75
|
+
function inferRoles(truthpack) {
|
|
76
|
+
const roles = [];
|
|
77
|
+
const routes = truthpack?.routes?.server || [];
|
|
78
|
+
|
|
79
|
+
// Check for admin routes
|
|
80
|
+
const adminRoutes = routes.filter(r => r.path.includes("/admin"));
|
|
81
|
+
if (adminRoutes.length > 0) {
|
|
82
|
+
roles.push({
|
|
83
|
+
name: "admin",
|
|
84
|
+
routes: adminRoutes.map(r => r.path),
|
|
85
|
+
evidence: adminRoutes.flatMap(r => r.evidence || [])
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Check for user routes (default authenticated)
|
|
90
|
+
const userRoutes = routes.filter(r =>
|
|
91
|
+
!r.path.includes("/admin") &&
|
|
92
|
+
!r.path.includes("/public") &&
|
|
93
|
+
!r.path.includes("/health")
|
|
94
|
+
);
|
|
95
|
+
if (userRoutes.length > 0) {
|
|
96
|
+
roles.push({
|
|
97
|
+
name: "user",
|
|
98
|
+
routes: userRoutes.map(r => r.path),
|
|
99
|
+
evidence: []
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return roles;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Validate auth coverage
|
|
108
|
+
*/
|
|
109
|
+
function validateAuthContract(contract, routes, realityResults) {
|
|
110
|
+
const violations = [];
|
|
111
|
+
|
|
112
|
+
// Check that all non-public routes are protected
|
|
113
|
+
for (const route of routes) {
|
|
114
|
+
const isPublic = contract.publicPatterns.some(p => matchesPattern(route.path, p));
|
|
115
|
+
const isProtected = contract.protectedPatterns.some(p => matchesPattern(route.path, p));
|
|
116
|
+
|
|
117
|
+
if (!isPublic && !isProtected) {
|
|
118
|
+
// Check if route looks sensitive
|
|
119
|
+
if (looksLikeSensitiveRoute(route.path)) {
|
|
120
|
+
violations.push({
|
|
121
|
+
type: "unprotected_sensitive",
|
|
122
|
+
severity: "WARN",
|
|
123
|
+
route: route.path,
|
|
124
|
+
message: `Sensitive route ${route.path} not covered by auth patterns`,
|
|
125
|
+
evidence: route.evidence || []
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Check reality results for auth bypass
|
|
132
|
+
if (realityResults) {
|
|
133
|
+
for (const result of realityResults) {
|
|
134
|
+
if (result.type === "AuthCoverage" && result.severity === "BLOCK") {
|
|
135
|
+
violations.push({
|
|
136
|
+
type: "auth_bypass",
|
|
137
|
+
severity: "BLOCK",
|
|
138
|
+
route: result.page,
|
|
139
|
+
message: result.title,
|
|
140
|
+
evidence: []
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return violations;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function matchesPattern(path, pattern) {
|
|
150
|
+
const normPattern = pattern.replace(/\*/g, ".*").replace(/\//g, "\\/");
|
|
151
|
+
try {
|
|
152
|
+
const rx = new RegExp(`^${normPattern}`, "i");
|
|
153
|
+
return rx.test(path);
|
|
154
|
+
} catch {
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function looksLikeSensitiveRoute(path) {
|
|
160
|
+
const sensitivePatterns = [
|
|
161
|
+
/\/api\/users/i,
|
|
162
|
+
/\/api\/billing/i,
|
|
163
|
+
/\/api\/payment/i,
|
|
164
|
+
/\/api\/subscription/i,
|
|
165
|
+
/\/api\/settings/i,
|
|
166
|
+
/\/api\/profile/i,
|
|
167
|
+
/\/api\/account/i,
|
|
168
|
+
/\/api\/admin/i,
|
|
169
|
+
/\/api\/webhook/i,
|
|
170
|
+
];
|
|
171
|
+
|
|
172
|
+
return sensitivePatterns.some(p => p.test(path));
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Diff two auth contracts
|
|
177
|
+
*/
|
|
178
|
+
function diffAuthContracts(before, after) {
|
|
179
|
+
const diff = {
|
|
180
|
+
protectedAdded: [],
|
|
181
|
+
protectedRemoved: [],
|
|
182
|
+
rolesChanged: []
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
const beforeProtected = new Set(before.protectedPatterns);
|
|
186
|
+
const afterProtected = new Set(after.protectedPatterns);
|
|
187
|
+
|
|
188
|
+
for (const p of afterProtected) {
|
|
189
|
+
if (!beforeProtected.has(p)) diff.protectedAdded.push(p);
|
|
190
|
+
}
|
|
191
|
+
for (const p of beforeProtected) {
|
|
192
|
+
if (!afterProtected.has(p)) diff.protectedRemoved.push(p);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return diff;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
module.exports = {
|
|
199
|
+
buildAuthContract,
|
|
200
|
+
validateAuthContract,
|
|
201
|
+
diffAuthContracts
|
|
202
|
+
};
|