@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,198 +1,198 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* AuthZ Matrix Builder
|
|
3
|
-
* Builds authorization matrix from auth model and runtime verification
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
"use strict";
|
|
7
|
-
|
|
8
|
-
const crypto = require("crypto");
|
|
9
|
-
|
|
10
|
-
function sha256(text) {
|
|
11
|
-
return crypto.createHash("sha256").update(text).digest("hex").slice(0, 16);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Build AuthZ matrix from auth model
|
|
16
|
-
*/
|
|
17
|
-
function buildAuthZMatrix(authModel, runtimeResults = null) {
|
|
18
|
-
const matrix = {
|
|
19
|
-
meta: {
|
|
20
|
-
version: "1.0.0",
|
|
21
|
-
generatedAt: new Date().toISOString()
|
|
22
|
-
},
|
|
23
|
-
roles: authModel.roles.map(r => r.name),
|
|
24
|
-
routes: [],
|
|
25
|
-
violations: []
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
for (const route of authModel.routes) {
|
|
29
|
-
const routeAuthZ = {
|
|
30
|
-
path: route.path,
|
|
31
|
-
method: route.method,
|
|
32
|
-
declared: route.declared,
|
|
33
|
-
actual: {
|
|
34
|
-
anon: null,
|
|
35
|
-
user: null,
|
|
36
|
-
admin: null
|
|
37
|
-
}
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
// Merge runtime results if available
|
|
41
|
-
if (runtimeResults) {
|
|
42
|
-
const runtimeForRoute = runtimeResults.filter(r =>
|
|
43
|
-
matchesRoute(route.path, r.path)
|
|
44
|
-
);
|
|
45
|
-
|
|
46
|
-
for (const result of runtimeForRoute) {
|
|
47
|
-
if (result.role === "anon") {
|
|
48
|
-
routeAuthZ.actual.anon = {
|
|
49
|
-
status: result.status,
|
|
50
|
-
redirected: result.redirected,
|
|
51
|
-
accessible: result.status >= 200 && result.status < 400 && !result.redirected
|
|
52
|
-
};
|
|
53
|
-
} else if (result.role === "user") {
|
|
54
|
-
routeAuthZ.actual.user = {
|
|
55
|
-
status: result.status,
|
|
56
|
-
redirected: result.redirected,
|
|
57
|
-
accessible: result.status >= 200 && result.status < 400 && !result.redirected
|
|
58
|
-
};
|
|
59
|
-
} else if (result.role === "admin") {
|
|
60
|
-
routeAuthZ.actual.admin = {
|
|
61
|
-
status: result.status,
|
|
62
|
-
redirected: result.redirected,
|
|
63
|
-
accessible: result.status >= 200 && result.status < 400 && !result.redirected
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
matrix.routes.push(routeAuthZ);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// Detect violations
|
|
73
|
-
matrix.violations = detectViolations(matrix);
|
|
74
|
-
|
|
75
|
-
return matrix;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Detect authorization violations
|
|
80
|
-
*/
|
|
81
|
-
function detectViolations(matrix) {
|
|
82
|
-
const violations = [];
|
|
83
|
-
|
|
84
|
-
for (const route of matrix.routes) {
|
|
85
|
-
// Check: protected route accessible anonymously
|
|
86
|
-
if (route.declared.protected && route.actual.anon?.accessible) {
|
|
87
|
-
violations.push({
|
|
88
|
-
id: `AUTHZ_ANON_${sha256(route.path)}`,
|
|
89
|
-
severity: "BLOCK",
|
|
90
|
-
type: "anon_access",
|
|
91
|
-
route: route.path,
|
|
92
|
-
method: route.method,
|
|
93
|
-
expected: "protected (should require auth)",
|
|
94
|
-
actual: "accessible anonymously",
|
|
95
|
-
message: `Protected route ${route.path} accessible without authentication`,
|
|
96
|
-
evidence: []
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// Check: role mismatch (admin route accessible by user)
|
|
101
|
-
if (route.declared.roles?.includes("admin") &&
|
|
102
|
-
!route.declared.roles?.includes("user") &&
|
|
103
|
-
route.actual.user?.accessible) {
|
|
104
|
-
violations.push({
|
|
105
|
-
id: `AUTHZ_ROLE_${sha256(route.path)}`,
|
|
106
|
-
severity: "BLOCK",
|
|
107
|
-
type: "role_mismatch",
|
|
108
|
-
route: route.path,
|
|
109
|
-
method: route.method,
|
|
110
|
-
expected: "admin only",
|
|
111
|
-
actual: "accessible by user role",
|
|
112
|
-
message: `Admin route ${route.path} accessible by non-admin users`,
|
|
113
|
-
evidence: []
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// Check: protected route blocked after login (broken auth)
|
|
118
|
-
if (route.declared.protected &&
|
|
119
|
-
route.actual.anon?.redirected &&
|
|
120
|
-
route.actual.user && !route.actual.user.accessible) {
|
|
121
|
-
violations.push({
|
|
122
|
-
id: `AUTHZ_BLOCKED_${sha256(route.path)}`,
|
|
123
|
-
severity: "WARN",
|
|
124
|
-
type: "blocked_after_auth",
|
|
125
|
-
route: route.path,
|
|
126
|
-
method: route.method,
|
|
127
|
-
expected: "accessible after auth",
|
|
128
|
-
actual: `blocked (status ${route.actual.user.status})`,
|
|
129
|
-
message: `Protected route ${route.path} not accessible after authentication`,
|
|
130
|
-
evidence: []
|
|
131
|
-
});
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
return violations;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* Format matrix for display
|
|
140
|
-
*/
|
|
141
|
-
function formatMatrix(matrix) {
|
|
142
|
-
const lines = [];
|
|
143
|
-
|
|
144
|
-
lines.push("# AuthZ Matrix\n");
|
|
145
|
-
lines.push(`Generated: ${matrix.meta.generatedAt}`);
|
|
146
|
-
lines.push(`Roles: ${matrix.roles.join(", ")}\n`);
|
|
147
|
-
|
|
148
|
-
// Build table header
|
|
149
|
-
const header = ["Route", "Method", "Declared", "Anon", "User", "Admin"];
|
|
150
|
-
lines.push(`| ${header.join(" | ")} |`);
|
|
151
|
-
lines.push(`| ${header.map(() => "---").join(" | ")} |`);
|
|
152
|
-
|
|
153
|
-
for (const route of matrix.routes) {
|
|
154
|
-
const declared = route.declared.protected ? "đ" : "đ";
|
|
155
|
-
const anon = formatAccess(route.actual.anon);
|
|
156
|
-
const user = formatAccess(route.actual.user);
|
|
157
|
-
const admin = formatAccess(route.actual.admin);
|
|
158
|
-
|
|
159
|
-
lines.push(`| ${route.path} | ${route.method} | ${declared} | ${anon} | ${user} | ${admin} |`);
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
if (matrix.violations.length > 0) {
|
|
163
|
-
lines.push("\n## Violations\n");
|
|
164
|
-
for (const v of matrix.violations) {
|
|
165
|
-
const icon = v.severity === "BLOCK" ? "đ" : "â ī¸";
|
|
166
|
-
lines.push(`${icon} **${v.type}**: ${v.message}`);
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
return lines.join("\n");
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
function formatAccess(result) {
|
|
174
|
-
if (!result) return "?";
|
|
175
|
-
if (result.accessible) return "â
";
|
|
176
|
-
if (result.redirected) return "âŠī¸";
|
|
177
|
-
return `â ${result.status}`;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
function matchesRoute(pattern, actual) {
|
|
181
|
-
const patternParts = pattern.split("/").filter(Boolean);
|
|
182
|
-
const actualParts = actual.split("/").filter(Boolean);
|
|
183
|
-
|
|
184
|
-
if (patternParts.length !== actualParts.length) return false;
|
|
185
|
-
|
|
186
|
-
for (let i = 0; i < patternParts.length; i++) {
|
|
187
|
-
const p = patternParts[i];
|
|
188
|
-
if (p.startsWith(":") || p.startsWith("*")) continue;
|
|
189
|
-
if (p !== actualParts[i]) return false;
|
|
190
|
-
}
|
|
191
|
-
return true;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
module.exports = {
|
|
195
|
-
buildAuthZMatrix,
|
|
196
|
-
detectViolations,
|
|
197
|
-
formatMatrix
|
|
198
|
-
};
|
|
1
|
+
/**
|
|
2
|
+
* AuthZ Matrix Builder
|
|
3
|
+
* Builds authorization matrix from auth model and runtime verification
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
"use strict";
|
|
7
|
+
|
|
8
|
+
const crypto = require("crypto");
|
|
9
|
+
|
|
10
|
+
function sha256(text) {
|
|
11
|
+
return crypto.createHash("sha256").update(text).digest("hex").slice(0, 16);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Build AuthZ matrix from auth model
|
|
16
|
+
*/
|
|
17
|
+
function buildAuthZMatrix(authModel, runtimeResults = null) {
|
|
18
|
+
const matrix = {
|
|
19
|
+
meta: {
|
|
20
|
+
version: "1.0.0",
|
|
21
|
+
generatedAt: new Date().toISOString()
|
|
22
|
+
},
|
|
23
|
+
roles: authModel.roles.map(r => r.name),
|
|
24
|
+
routes: [],
|
|
25
|
+
violations: []
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
for (const route of authModel.routes) {
|
|
29
|
+
const routeAuthZ = {
|
|
30
|
+
path: route.path,
|
|
31
|
+
method: route.method,
|
|
32
|
+
declared: route.declared,
|
|
33
|
+
actual: {
|
|
34
|
+
anon: null,
|
|
35
|
+
user: null,
|
|
36
|
+
admin: null
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
// Merge runtime results if available
|
|
41
|
+
if (runtimeResults) {
|
|
42
|
+
const runtimeForRoute = runtimeResults.filter(r =>
|
|
43
|
+
matchesRoute(route.path, r.path)
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
for (const result of runtimeForRoute) {
|
|
47
|
+
if (result.role === "anon") {
|
|
48
|
+
routeAuthZ.actual.anon = {
|
|
49
|
+
status: result.status,
|
|
50
|
+
redirected: result.redirected,
|
|
51
|
+
accessible: result.status >= 200 && result.status < 400 && !result.redirected
|
|
52
|
+
};
|
|
53
|
+
} else if (result.role === "user") {
|
|
54
|
+
routeAuthZ.actual.user = {
|
|
55
|
+
status: result.status,
|
|
56
|
+
redirected: result.redirected,
|
|
57
|
+
accessible: result.status >= 200 && result.status < 400 && !result.redirected
|
|
58
|
+
};
|
|
59
|
+
} else if (result.role === "admin") {
|
|
60
|
+
routeAuthZ.actual.admin = {
|
|
61
|
+
status: result.status,
|
|
62
|
+
redirected: result.redirected,
|
|
63
|
+
accessible: result.status >= 200 && result.status < 400 && !result.redirected
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
matrix.routes.push(routeAuthZ);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Detect violations
|
|
73
|
+
matrix.violations = detectViolations(matrix);
|
|
74
|
+
|
|
75
|
+
return matrix;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Detect authorization violations
|
|
80
|
+
*/
|
|
81
|
+
function detectViolations(matrix) {
|
|
82
|
+
const violations = [];
|
|
83
|
+
|
|
84
|
+
for (const route of matrix.routes) {
|
|
85
|
+
// Check: protected route accessible anonymously
|
|
86
|
+
if (route.declared.protected && route.actual.anon?.accessible) {
|
|
87
|
+
violations.push({
|
|
88
|
+
id: `AUTHZ_ANON_${sha256(route.path)}`,
|
|
89
|
+
severity: "BLOCK",
|
|
90
|
+
type: "anon_access",
|
|
91
|
+
route: route.path,
|
|
92
|
+
method: route.method,
|
|
93
|
+
expected: "protected (should require auth)",
|
|
94
|
+
actual: "accessible anonymously",
|
|
95
|
+
message: `Protected route ${route.path} accessible without authentication`,
|
|
96
|
+
evidence: []
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Check: role mismatch (admin route accessible by user)
|
|
101
|
+
if (route.declared.roles?.includes("admin") &&
|
|
102
|
+
!route.declared.roles?.includes("user") &&
|
|
103
|
+
route.actual.user?.accessible) {
|
|
104
|
+
violations.push({
|
|
105
|
+
id: `AUTHZ_ROLE_${sha256(route.path)}`,
|
|
106
|
+
severity: "BLOCK",
|
|
107
|
+
type: "role_mismatch",
|
|
108
|
+
route: route.path,
|
|
109
|
+
method: route.method,
|
|
110
|
+
expected: "admin only",
|
|
111
|
+
actual: "accessible by user role",
|
|
112
|
+
message: `Admin route ${route.path} accessible by non-admin users`,
|
|
113
|
+
evidence: []
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Check: protected route blocked after login (broken auth)
|
|
118
|
+
if (route.declared.protected &&
|
|
119
|
+
route.actual.anon?.redirected &&
|
|
120
|
+
route.actual.user && !route.actual.user.accessible) {
|
|
121
|
+
violations.push({
|
|
122
|
+
id: `AUTHZ_BLOCKED_${sha256(route.path)}`,
|
|
123
|
+
severity: "WARN",
|
|
124
|
+
type: "blocked_after_auth",
|
|
125
|
+
route: route.path,
|
|
126
|
+
method: route.method,
|
|
127
|
+
expected: "accessible after auth",
|
|
128
|
+
actual: `blocked (status ${route.actual.user.status})`,
|
|
129
|
+
message: `Protected route ${route.path} not accessible after authentication`,
|
|
130
|
+
evidence: []
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return violations;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Format matrix for display
|
|
140
|
+
*/
|
|
141
|
+
function formatMatrix(matrix) {
|
|
142
|
+
const lines = [];
|
|
143
|
+
|
|
144
|
+
lines.push("# AuthZ Matrix\n");
|
|
145
|
+
lines.push(`Generated: ${matrix.meta.generatedAt}`);
|
|
146
|
+
lines.push(`Roles: ${matrix.roles.join(", ")}\n`);
|
|
147
|
+
|
|
148
|
+
// Build table header
|
|
149
|
+
const header = ["Route", "Method", "Declared", "Anon", "User", "Admin"];
|
|
150
|
+
lines.push(`| ${header.join(" | ")} |`);
|
|
151
|
+
lines.push(`| ${header.map(() => "---").join(" | ")} |`);
|
|
152
|
+
|
|
153
|
+
for (const route of matrix.routes) {
|
|
154
|
+
const declared = route.declared.protected ? "đ" : "đ";
|
|
155
|
+
const anon = formatAccess(route.actual.anon);
|
|
156
|
+
const user = formatAccess(route.actual.user);
|
|
157
|
+
const admin = formatAccess(route.actual.admin);
|
|
158
|
+
|
|
159
|
+
lines.push(`| ${route.path} | ${route.method} | ${declared} | ${anon} | ${user} | ${admin} |`);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (matrix.violations.length > 0) {
|
|
163
|
+
lines.push("\n## Violations\n");
|
|
164
|
+
for (const v of matrix.violations) {
|
|
165
|
+
const icon = v.severity === "BLOCK" ? "đ" : "â ī¸";
|
|
166
|
+
lines.push(`${icon} **${v.type}**: ${v.message}`);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return lines.join("\n");
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function formatAccess(result) {
|
|
174
|
+
if (!result) return "?";
|
|
175
|
+
if (result.accessible) return "â
";
|
|
176
|
+
if (result.redirected) return "âŠī¸";
|
|
177
|
+
return `â ${result.status}`;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function matchesRoute(pattern, actual) {
|
|
181
|
+
const patternParts = pattern.split("/").filter(Boolean);
|
|
182
|
+
const actualParts = actual.split("/").filter(Boolean);
|
|
183
|
+
|
|
184
|
+
if (patternParts.length !== actualParts.length) return false;
|
|
185
|
+
|
|
186
|
+
for (let i = 0; i < patternParts.length; i++) {
|
|
187
|
+
const p = patternParts[i];
|
|
188
|
+
if (p.startsWith(":") || p.startsWith("*")) continue;
|
|
189
|
+
if (p !== actualParts[i]) return false;
|
|
190
|
+
}
|
|
191
|
+
return true;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
module.exports = {
|
|
195
|
+
buildAuthZMatrix,
|
|
196
|
+
detectViolations,
|
|
197
|
+
formatMatrix
|
|
198
|
+
};
|
|
@@ -1,28 +1,28 @@
|
|
|
1
|
-
// bin/runners/lib/pkgjson.js
|
|
2
|
-
const fs = require("fs");
|
|
3
|
-
const path = require("path");
|
|
4
|
-
|
|
5
|
-
function readPkg(root) {
|
|
6
|
-
const p = path.join(root, "package.json");
|
|
7
|
-
if (!fs.existsSync(p)) throw new Error("package.json not found");
|
|
8
|
-
return { path: p, json: JSON.parse(fs.readFileSync(p, "utf8")) };
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
function writePkg(pkgPath, json) {
|
|
12
|
-
fs.writeFileSync(pkgPath, JSON.stringify(json, null, 2) + "\n", "utf8");
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
function upsertScripts(pkg, scripts) {
|
|
16
|
-
pkg.scripts = pkg.scripts || {};
|
|
17
|
-
const changed = [];
|
|
18
|
-
|
|
19
|
-
for (const [k, v] of Object.entries(scripts)) {
|
|
20
|
-
if (pkg.scripts[k] === v) continue;
|
|
21
|
-
pkg.scripts[k] = v;
|
|
22
|
-
changed.push(k);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
return changed;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
module.exports = { readPkg, writePkg, upsertScripts };
|
|
1
|
+
// bin/runners/lib/pkgjson.js
|
|
2
|
+
const fs = require("fs");
|
|
3
|
+
const path = require("path");
|
|
4
|
+
|
|
5
|
+
function readPkg(root) {
|
|
6
|
+
const p = path.join(root, "package.json");
|
|
7
|
+
if (!fs.existsSync(p)) throw new Error("package.json not found");
|
|
8
|
+
return { path: p, json: JSON.parse(fs.readFileSync(p, "utf8")) };
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function writePkg(pkgPath, json) {
|
|
12
|
+
fs.writeFileSync(pkgPath, JSON.stringify(json, null, 2) + "\n", "utf8");
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function upsertScripts(pkg, scripts) {
|
|
16
|
+
pkg.scripts = pkg.scripts || {};
|
|
17
|
+
const changed = [];
|
|
18
|
+
|
|
19
|
+
for (const [k, v] of Object.entries(scripts)) {
|
|
20
|
+
if (pkg.scripts[k] === v) continue;
|
|
21
|
+
pkg.scripts[k] = v;
|
|
22
|
+
changed.push(k);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return changed;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
module.exports = { readPkg, writePkg, upsertScripts };
|