@vibecheckai/cli 3.5.0 → 3.5.2
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/registry.js +214 -237
- package/bin/runners/cli-utils.js +33 -2
- package/bin/runners/context/analyzer.js +52 -1
- package/bin/runners/context/generators/cursor.js +2 -49
- package/bin/runners/context/git-context.js +3 -1
- package/bin/runners/context/team-conventions.js +33 -7
- package/bin/runners/lib/analysis-core.js +25 -5
- package/bin/runners/lib/analyzers.js +431 -481
- package/bin/runners/lib/default-config.js +127 -0
- package/bin/runners/lib/doctor/modules/security.js +3 -1
- package/bin/runners/lib/engine/ast-cache.js +210 -0
- package/bin/runners/lib/engine/auth-extractor.js +211 -0
- package/bin/runners/lib/engine/billing-extractor.js +112 -0
- package/bin/runners/lib/engine/enforcement-extractor.js +100 -0
- package/bin/runners/lib/engine/env-extractor.js +207 -0
- package/bin/runners/lib/engine/express-extractor.js +208 -0
- package/bin/runners/lib/engine/extractors.js +849 -0
- package/bin/runners/lib/engine/index.js +207 -0
- package/bin/runners/lib/engine/repo-index.js +514 -0
- package/bin/runners/lib/engine/types.js +124 -0
- package/bin/runners/lib/engines/accessibility-engine.js +18 -218
- package/bin/runners/lib/engines/api-consistency-engine.js +30 -335
- package/bin/runners/lib/engines/cross-file-analysis-engine.js +27 -292
- package/bin/runners/lib/engines/empty-catch-engine.js +17 -127
- package/bin/runners/lib/engines/mock-data-engine.js +10 -53
- package/bin/runners/lib/engines/performance-issues-engine.js +36 -176
- package/bin/runners/lib/engines/security-vulnerabilities-engine.js +54 -382
- package/bin/runners/lib/engines/type-aware-engine.js +39 -263
- package/bin/runners/lib/engines/vibecheck-engines/index.js +13 -122
- 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 +73 -373
- 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/entitlements-v2.js +73 -97
- package/bin/runners/lib/error-handler.js +44 -3
- package/bin/runners/lib/error-messages.js +289 -0
- package/bin/runners/lib/evidence-pack.js +7 -1
- package/bin/runners/lib/finding-id.js +69 -0
- package/bin/runners/lib/finding-sorter.js +89 -0
- package/bin/runners/lib/html-proof-report.js +700 -350
- package/bin/runners/lib/missions/plan.js +6 -46
- package/bin/runners/lib/missions/templates.js +0 -232
- package/bin/runners/lib/next-action.js +560 -0
- package/bin/runners/lib/prerequisites.js +149 -0
- package/bin/runners/lib/route-detection.js +137 -68
- package/bin/runners/lib/scan-output.js +91 -76
- package/bin/runners/lib/scan-runner.js +135 -0
- package/bin/runners/lib/schemas/ajv-validator.js +464 -0
- package/bin/runners/lib/schemas/error-envelope.schema.json +105 -0
- package/bin/runners/lib/schemas/finding-v3.schema.json +151 -0
- package/bin/runners/lib/schemas/report-artifact.schema.json +120 -0
- package/bin/runners/lib/schemas/run-request.schema.json +108 -0
- package/bin/runners/lib/schemas/validator.js +27 -0
- package/bin/runners/lib/schemas/verdict.schema.json +140 -0
- package/bin/runners/lib/ship-output-enterprise.js +23 -23
- package/bin/runners/lib/ship-output.js +75 -31
- package/bin/runners/lib/terminal-ui.js +6 -113
- package/bin/runners/lib/truth.js +351 -10
- package/bin/runners/lib/unified-cli-output.js +430 -603
- package/bin/runners/lib/unified-output.js +13 -9
- package/bin/runners/runAIAgent.js +10 -5
- package/bin/runners/runAgent.js +0 -3
- package/bin/runners/runAllowlist.js +389 -0
- package/bin/runners/runApprove.js +0 -33
- package/bin/runners/runAuth.js +73 -45
- package/bin/runners/runCheckpoint.js +51 -11
- package/bin/runners/runClassify.js +85 -21
- package/bin/runners/runContext.js +0 -3
- package/bin/runners/runDoctor.js +41 -28
- package/bin/runners/runEvidencePack.js +362 -0
- package/bin/runners/runFirewall.js +0 -3
- package/bin/runners/runFirewallHook.js +0 -3
- package/bin/runners/runFix.js +66 -76
- package/bin/runners/runGuard.js +18 -411
- package/bin/runners/runInit.js +113 -30
- package/bin/runners/runLabs.js +424 -0
- package/bin/runners/runMcp.js +19 -25
- package/bin/runners/runPolish.js +64 -240
- package/bin/runners/runPromptFirewall.js +12 -5
- package/bin/runners/runProve.js +57 -22
- package/bin/runners/runQuickstart.js +531 -0
- package/bin/runners/runReality.js +59 -68
- package/bin/runners/runReport.js +38 -33
- package/bin/runners/runRuntime.js +8 -5
- package/bin/runners/runScan.js +1413 -190
- package/bin/runners/runShip.js +113 -719
- package/bin/runners/runTruth.js +0 -3
- package/bin/runners/runValidate.js +13 -9
- package/bin/runners/runWatch.js +23 -14
- package/bin/scan.js +6 -1
- package/bin/vibecheck.js +204 -185
- package/mcp-server/deprecation-middleware.js +282 -0
- package/mcp-server/handlers/index.ts +15 -0
- package/mcp-server/handlers/tool-handler.ts +554 -0
- package/mcp-server/index-v1.js +698 -0
- package/mcp-server/index.js +210 -238
- package/mcp-server/lib/cache-wrapper.cjs +383 -0
- package/mcp-server/lib/error-envelope.js +138 -0
- package/mcp-server/lib/executor.ts +499 -0
- package/mcp-server/lib/index.ts +19 -0
- package/mcp-server/lib/rate-limiter.js +166 -0
- package/mcp-server/lib/sandbox.test.ts +519 -0
- package/mcp-server/lib/sandbox.ts +395 -0
- package/mcp-server/lib/types.ts +267 -0
- package/mcp-server/package.json +12 -3
- package/mcp-server/registry/tool-registry.js +794 -0
- package/mcp-server/registry/tools.json +605 -0
- package/mcp-server/registry.test.ts +334 -0
- package/mcp-server/tests/tier-gating.test.js +297 -0
- package/mcp-server/tier-auth.js +378 -45
- package/mcp-server/tools-v3.js +353 -442
- package/mcp-server/tsconfig.json +37 -0
- package/mcp-server/vibecheck-2.0-tools.js +14 -1
- package/package.json +1 -1
- package/bin/runners/lib/agent-firewall/learning/learning-engine.js +0 -849
- package/bin/runners/lib/audit-logger.js +0 -532
- package/bin/runners/lib/authority/authorities/architecture.js +0 -364
- package/bin/runners/lib/authority/authorities/compliance.js +0 -341
- package/bin/runners/lib/authority/authorities/human.js +0 -343
- package/bin/runners/lib/authority/authorities/quality.js +0 -420
- package/bin/runners/lib/authority/authorities/security.js +0 -228
- package/bin/runners/lib/authority/index.js +0 -293
- package/bin/runners/lib/bundle/bundle-intelligence.js +0 -846
- package/bin/runners/lib/cli-charts.js +0 -368
- package/bin/runners/lib/cli-config-display.js +0 -405
- package/bin/runners/lib/cli-demo.js +0 -275
- package/bin/runners/lib/cli-errors.js +0 -438
- package/bin/runners/lib/cli-help-formatter.js +0 -439
- package/bin/runners/lib/cli-interactive-menu.js +0 -509
- package/bin/runners/lib/cli-prompts.js +0 -441
- package/bin/runners/lib/cli-scan-cards.js +0 -362
- package/bin/runners/lib/compliance-reporter.js +0 -710
- package/bin/runners/lib/conductor/index.js +0 -671
- package/bin/runners/lib/easy/README.md +0 -123
- package/bin/runners/lib/easy/index.js +0 -140
- package/bin/runners/lib/easy/interactive-wizard.js +0 -788
- package/bin/runners/lib/easy/one-click-firewall.js +0 -564
- package/bin/runners/lib/easy/zero-config-reality.js +0 -714
- package/bin/runners/lib/engines/async-patterns-engine.js +0 -444
- package/bin/runners/lib/engines/bundle-size-engine.js +0 -433
- package/bin/runners/lib/engines/confidence-scoring.js +0 -276
- package/bin/runners/lib/engines/context-detection.js +0 -264
- package/bin/runners/lib/engines/database-patterns-engine.js +0 -429
- package/bin/runners/lib/engines/duplicate-code-engine.js +0 -354
- package/bin/runners/lib/engines/env-variables-engine.js +0 -458
- package/bin/runners/lib/engines/error-handling-engine.js +0 -437
- package/bin/runners/lib/engines/false-positive-prevention.js +0 -630
- package/bin/runners/lib/engines/framework-adapters/index.js +0 -607
- package/bin/runners/lib/engines/framework-detection.js +0 -508
- package/bin/runners/lib/engines/import-order-engine.js +0 -429
- package/bin/runners/lib/engines/naming-conventions-engine.js +0 -544
- package/bin/runners/lib/engines/noise-reduction-engine.js +0 -452
- package/bin/runners/lib/engines/orchestrator.js +0 -334
- package/bin/runners/lib/engines/react-patterns-engine.js +0 -457
- package/bin/runners/lib/engines/vibecheck-engines/lib/ai-hallucination-engine.js +0 -806
- package/bin/runners/lib/engines/vibecheck-engines/lib/smart-fix-engine.js +0 -577
- package/bin/runners/lib/engines/vibecheck-engines/lib/vibe-score-engine.js +0 -543
- package/bin/runners/lib/engines/vibecheck-engines.js +0 -514
- package/bin/runners/lib/enhanced-features/index.js +0 -305
- package/bin/runners/lib/enhanced-output.js +0 -631
- package/bin/runners/lib/enterprise.js +0 -300
- package/bin/runners/lib/firewall/command-validator.js +0 -351
- package/bin/runners/lib/firewall/config.js +0 -341
- package/bin/runners/lib/firewall/content-validator.js +0 -519
- package/bin/runners/lib/firewall/index.js +0 -101
- package/bin/runners/lib/firewall/path-validator.js +0 -256
- package/bin/runners/lib/intelligence/cross-repo-intelligence.js +0 -817
- package/bin/runners/lib/mcp-utils.js +0 -425
- package/bin/runners/lib/output/index.js +0 -1022
- package/bin/runners/lib/policy-engine.js +0 -652
- package/bin/runners/lib/polish/autofix/accessibility-fixes.js +0 -333
- package/bin/runners/lib/polish/autofix/async-handlers.js +0 -273
- package/bin/runners/lib/polish/autofix/dead-code.js +0 -280
- package/bin/runners/lib/polish/autofix/imports-optimizer.js +0 -344
- package/bin/runners/lib/polish/autofix/index.js +0 -200
- package/bin/runners/lib/polish/autofix/remove-consoles.js +0 -209
- package/bin/runners/lib/polish/autofix/strengthen-types.js +0 -245
- package/bin/runners/lib/polish/backend-checks.js +0 -148
- package/bin/runners/lib/polish/documentation-checks.js +0 -111
- package/bin/runners/lib/polish/frontend-checks.js +0 -168
- package/bin/runners/lib/polish/index.js +0 -71
- package/bin/runners/lib/polish/infrastructure-checks.js +0 -131
- package/bin/runners/lib/polish/library-detection.js +0 -175
- package/bin/runners/lib/polish/performance-checks.js +0 -100
- package/bin/runners/lib/polish/security-checks.js +0 -148
- package/bin/runners/lib/polish/utils.js +0 -203
- package/bin/runners/lib/prompt-builder.js +0 -540
- package/bin/runners/lib/proof-certificate.js +0 -634
- package/bin/runners/lib/reality/accessibility-audit.js +0 -946
- package/bin/runners/lib/reality/api-contract-validator.js +0 -1012
- package/bin/runners/lib/reality/chaos-engineering.js +0 -1084
- package/bin/runners/lib/reality/performance-tracker.js +0 -1077
- package/bin/runners/lib/reality/scenario-generator.js +0 -1404
- package/bin/runners/lib/reality/visual-regression.js +0 -852
- package/bin/runners/lib/reality-profiler.js +0 -717
- package/bin/runners/lib/replay/flight-recorder-viewer.js +0 -1160
- package/bin/runners/lib/review/ai-code-review.js +0 -832
- package/bin/runners/lib/rules/custom-rule-engine.js +0 -985
- package/bin/runners/lib/sbom-generator.js +0 -641
- package/bin/runners/lib/scan-output-enhanced.js +0 -512
- package/bin/runners/lib/security/owasp-scanner.js +0 -939
- package/bin/runners/lib/validators/contract-validator.js +0 -283
- package/bin/runners/lib/validators/dead-export-detector.js +0 -279
- package/bin/runners/lib/validators/dep-audit.js +0 -245
- package/bin/runners/lib/validators/env-validator.js +0 -319
- package/bin/runners/lib/validators/index.js +0 -120
- package/bin/runners/lib/validators/license-checker.js +0 -252
- package/bin/runners/lib/validators/route-validator.js +0 -290
- package/bin/runners/runAuthority.js +0 -528
- package/bin/runners/runConductor.js +0 -772
- package/bin/runners/runContainer.js +0 -366
- package/bin/runners/runEasy.js +0 -410
- package/bin/runners/runIaC.js +0 -372
- package/bin/runners/runVibe.js +0 -791
- package/mcp-server/tools.js +0 -495
|
@@ -1,652 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Enterprise Policy Enforcement Engine
|
|
3
|
-
*
|
|
4
|
-
* Define and enforce security policies:
|
|
5
|
-
* - Custom rules
|
|
6
|
-
* - Threshold-based policies
|
|
7
|
-
* - Team/org policies
|
|
8
|
-
* - Branch policies
|
|
9
|
-
* - Time-based policies
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
"use strict";
|
|
13
|
-
|
|
14
|
-
const fs = require("fs");
|
|
15
|
-
const path = require("path");
|
|
16
|
-
const crypto = require("crypto");
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Policy condition operators
|
|
20
|
-
*/
|
|
21
|
-
const OPERATORS = {
|
|
22
|
-
eq: (a, b) => a === b,
|
|
23
|
-
ne: (a, b) => a !== b,
|
|
24
|
-
gt: (a, b) => a > b,
|
|
25
|
-
gte: (a, b) => a >= b,
|
|
26
|
-
lt: (a, b) => a < b,
|
|
27
|
-
lte: (a, b) => a <= b,
|
|
28
|
-
contains: (a, b) => String(a).includes(String(b)),
|
|
29
|
-
notContains: (a, b) => !String(a).includes(String(b)),
|
|
30
|
-
matches: (a, b) => new RegExp(b).test(String(a)),
|
|
31
|
-
notMatches: (a, b) => !new RegExp(b).test(String(a)),
|
|
32
|
-
in: (a, b) => Array.isArray(b) && b.includes(a),
|
|
33
|
-
notIn: (a, b) => Array.isArray(b) && !b.includes(a),
|
|
34
|
-
exists: (a) => a !== undefined && a !== null,
|
|
35
|
-
notExists: (a) => a === undefined || a === null,
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Policy actions
|
|
40
|
-
*/
|
|
41
|
-
const ACTIONS = {
|
|
42
|
-
BLOCK: "block",
|
|
43
|
-
WARN: "warn",
|
|
44
|
-
ALLOW: "allow",
|
|
45
|
-
NOTIFY: "notify",
|
|
46
|
-
REQUIRE_APPROVAL: "require_approval",
|
|
47
|
-
AUTO_FIX: "auto_fix",
|
|
48
|
-
ESCALATE: "escalate",
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Built-in policy templates
|
|
53
|
-
*/
|
|
54
|
-
const POLICY_TEMPLATES = {
|
|
55
|
-
"no-secrets": {
|
|
56
|
-
id: "no-secrets",
|
|
57
|
-
name: "No Hardcoded Secrets",
|
|
58
|
-
description: "Block deployments with hardcoded secrets",
|
|
59
|
-
enabled: true,
|
|
60
|
-
priority: 100,
|
|
61
|
-
conditions: [
|
|
62
|
-
{
|
|
63
|
-
field: "findings",
|
|
64
|
-
path: "category",
|
|
65
|
-
operator: "contains",
|
|
66
|
-
value: "secret",
|
|
67
|
-
},
|
|
68
|
-
],
|
|
69
|
-
action: ACTIONS.BLOCK,
|
|
70
|
-
message: "Hardcoded secrets detected. Remove all secrets before deploying.",
|
|
71
|
-
remediation: "Use environment variables or a secrets manager for sensitive data.",
|
|
72
|
-
tags: ["security", "secrets", "critical"],
|
|
73
|
-
},
|
|
74
|
-
|
|
75
|
-
"no-critical-vulns": {
|
|
76
|
-
id: "no-critical-vulns",
|
|
77
|
-
name: "No Critical Vulnerabilities",
|
|
78
|
-
description: "Block deployments with critical vulnerabilities",
|
|
79
|
-
enabled: true,
|
|
80
|
-
priority: 95,
|
|
81
|
-
conditions: [
|
|
82
|
-
{
|
|
83
|
-
field: "summary.critical",
|
|
84
|
-
operator: "gt",
|
|
85
|
-
value: 0,
|
|
86
|
-
},
|
|
87
|
-
],
|
|
88
|
-
action: ACTIONS.BLOCK,
|
|
89
|
-
message: "Critical vulnerabilities detected. Fix all critical issues before deploying.",
|
|
90
|
-
tags: ["security", "vulnerabilities", "critical"],
|
|
91
|
-
},
|
|
92
|
-
|
|
93
|
-
"max-high-issues": {
|
|
94
|
-
id: "max-high-issues",
|
|
95
|
-
name: "Maximum High-Severity Issues",
|
|
96
|
-
description: "Limit number of high-severity issues",
|
|
97
|
-
enabled: true,
|
|
98
|
-
priority: 80,
|
|
99
|
-
conditions: [
|
|
100
|
-
{
|
|
101
|
-
field: "summary.high",
|
|
102
|
-
operator: "gt",
|
|
103
|
-
value: 5,
|
|
104
|
-
},
|
|
105
|
-
],
|
|
106
|
-
action: ACTIONS.WARN,
|
|
107
|
-
message: "Too many high-severity issues detected (>5).",
|
|
108
|
-
tags: ["quality", "threshold"],
|
|
109
|
-
},
|
|
110
|
-
|
|
111
|
-
"minimum-score": {
|
|
112
|
-
id: "minimum-score",
|
|
113
|
-
name: "Minimum Quality Score",
|
|
114
|
-
description: "Require minimum quality score for deployment",
|
|
115
|
-
enabled: true,
|
|
116
|
-
priority: 70,
|
|
117
|
-
conditions: [
|
|
118
|
-
{
|
|
119
|
-
field: "score",
|
|
120
|
-
operator: "lt",
|
|
121
|
-
value: 70,
|
|
122
|
-
},
|
|
123
|
-
],
|
|
124
|
-
action: ACTIONS.BLOCK,
|
|
125
|
-
message: "Quality score too low. Minimum required: 70.",
|
|
126
|
-
tags: ["quality", "threshold"],
|
|
127
|
-
},
|
|
128
|
-
|
|
129
|
-
"no-mock-data": {
|
|
130
|
-
id: "no-mock-data",
|
|
131
|
-
name: "No Mock Data in Production",
|
|
132
|
-
description: "Block mock/fake data in production code",
|
|
133
|
-
enabled: true,
|
|
134
|
-
priority: 90,
|
|
135
|
-
conditions: [
|
|
136
|
-
{
|
|
137
|
-
field: "findings",
|
|
138
|
-
path: "category",
|
|
139
|
-
operator: "matches",
|
|
140
|
-
value: "mock|fake|stub|test-data",
|
|
141
|
-
},
|
|
142
|
-
],
|
|
143
|
-
action: ACTIONS.BLOCK,
|
|
144
|
-
message: "Mock data detected in production paths.",
|
|
145
|
-
tags: ["quality", "data"],
|
|
146
|
-
},
|
|
147
|
-
|
|
148
|
-
"require-tests": {
|
|
149
|
-
id: "require-tests",
|
|
150
|
-
name: "Require Test Coverage",
|
|
151
|
-
description: "Ensure test coverage meets minimum threshold",
|
|
152
|
-
enabled: false,
|
|
153
|
-
priority: 60,
|
|
154
|
-
conditions: [
|
|
155
|
-
{
|
|
156
|
-
field: "coverage",
|
|
157
|
-
operator: "lt",
|
|
158
|
-
value: 80,
|
|
159
|
-
},
|
|
160
|
-
],
|
|
161
|
-
action: ACTIONS.WARN,
|
|
162
|
-
message: "Test coverage below 80%.",
|
|
163
|
-
tags: ["quality", "testing"],
|
|
164
|
-
},
|
|
165
|
-
|
|
166
|
-
"branch-protection": {
|
|
167
|
-
id: "branch-protection",
|
|
168
|
-
name: "Main Branch Protection",
|
|
169
|
-
description: "Stricter rules for main/master branch",
|
|
170
|
-
enabled: true,
|
|
171
|
-
priority: 100,
|
|
172
|
-
conditions: [
|
|
173
|
-
{
|
|
174
|
-
field: "branch",
|
|
175
|
-
operator: "matches",
|
|
176
|
-
value: "^(main|master)$",
|
|
177
|
-
},
|
|
178
|
-
{
|
|
179
|
-
field: "summary.critical",
|
|
180
|
-
operator: "gt",
|
|
181
|
-
value: 0,
|
|
182
|
-
},
|
|
183
|
-
],
|
|
184
|
-
action: ACTIONS.BLOCK,
|
|
185
|
-
message: "Cannot merge to main/master with critical issues.",
|
|
186
|
-
tags: ["branch", "protection"],
|
|
187
|
-
},
|
|
188
|
-
|
|
189
|
-
"after-hours-approval": {
|
|
190
|
-
id: "after-hours-approval",
|
|
191
|
-
name: "After-Hours Approval Required",
|
|
192
|
-
description: "Require approval for deployments outside business hours",
|
|
193
|
-
enabled: false,
|
|
194
|
-
priority: 50,
|
|
195
|
-
conditions: [
|
|
196
|
-
{
|
|
197
|
-
field: "time.hour",
|
|
198
|
-
operator: "notIn",
|
|
199
|
-
value: [9, 10, 11, 12, 13, 14, 15, 16, 17],
|
|
200
|
-
},
|
|
201
|
-
],
|
|
202
|
-
action: ACTIONS.REQUIRE_APPROVAL,
|
|
203
|
-
message: "Deployment outside business hours requires approval.",
|
|
204
|
-
tags: ["time", "approval"],
|
|
205
|
-
},
|
|
206
|
-
|
|
207
|
-
"weekend-block": {
|
|
208
|
-
id: "weekend-block",
|
|
209
|
-
name: "Weekend Deployment Block",
|
|
210
|
-
description: "Block deployments on weekends",
|
|
211
|
-
enabled: false,
|
|
212
|
-
priority: 40,
|
|
213
|
-
conditions: [
|
|
214
|
-
{
|
|
215
|
-
field: "time.dayOfWeek",
|
|
216
|
-
operator: "in",
|
|
217
|
-
value: [0, 6], // Sunday, Saturday
|
|
218
|
-
},
|
|
219
|
-
],
|
|
220
|
-
action: ACTIONS.BLOCK,
|
|
221
|
-
message: "Deployments are not allowed on weekends.",
|
|
222
|
-
tags: ["time", "weekend"],
|
|
223
|
-
},
|
|
224
|
-
};
|
|
225
|
-
|
|
226
|
-
/**
|
|
227
|
-
* Policy evaluation result
|
|
228
|
-
*/
|
|
229
|
-
class PolicyResult {
|
|
230
|
-
constructor(policy, matched, action, message) {
|
|
231
|
-
this.policyId = policy.id;
|
|
232
|
-
this.policyName = policy.name;
|
|
233
|
-
this.matched = matched;
|
|
234
|
-
this.action = action;
|
|
235
|
-
this.message = message;
|
|
236
|
-
this.remediation = policy.remediation;
|
|
237
|
-
this.priority = policy.priority;
|
|
238
|
-
this.tags = policy.tags || [];
|
|
239
|
-
this.timestamp = new Date().toISOString();
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
/**
|
|
244
|
-
* Policy Engine class
|
|
245
|
-
*/
|
|
246
|
-
class PolicyEngine {
|
|
247
|
-
constructor(options = {}) {
|
|
248
|
-
this.options = {
|
|
249
|
-
policiesDir: options.policiesDir || path.join(process.cwd(), ".vibecheck", "policies"),
|
|
250
|
-
enableBuiltIn: options.enableBuiltIn !== false,
|
|
251
|
-
strictMode: options.strictMode || false,
|
|
252
|
-
...options,
|
|
253
|
-
};
|
|
254
|
-
|
|
255
|
-
this.policies = new Map();
|
|
256
|
-
this.customPolicies = new Map();
|
|
257
|
-
|
|
258
|
-
// Load built-in policies
|
|
259
|
-
if (this.options.enableBuiltIn) {
|
|
260
|
-
this.loadBuiltInPolicies();
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
// Load custom policies
|
|
264
|
-
this.loadCustomPolicies();
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
/**
|
|
268
|
-
* Load built-in policies
|
|
269
|
-
*/
|
|
270
|
-
loadBuiltInPolicies() {
|
|
271
|
-
for (const [id, policy] of Object.entries(POLICY_TEMPLATES)) {
|
|
272
|
-
this.policies.set(id, { ...policy, builtIn: true });
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
/**
|
|
277
|
-
* Load custom policies from directory
|
|
278
|
-
*/
|
|
279
|
-
loadCustomPolicies() {
|
|
280
|
-
if (!fs.existsSync(this.options.policiesDir)) {
|
|
281
|
-
return;
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
const files = fs.readdirSync(this.options.policiesDir)
|
|
285
|
-
.filter(f => f.endsWith(".json") || f.endsWith(".yaml") || f.endsWith(".yml"));
|
|
286
|
-
|
|
287
|
-
for (const file of files) {
|
|
288
|
-
try {
|
|
289
|
-
const content = fs.readFileSync(path.join(this.options.policiesDir, file), "utf-8");
|
|
290
|
-
const policy = JSON.parse(content);
|
|
291
|
-
|
|
292
|
-
if (this.validatePolicy(policy)) {
|
|
293
|
-
this.customPolicies.set(policy.id, { ...policy, builtIn: false });
|
|
294
|
-
}
|
|
295
|
-
} catch (error) {
|
|
296
|
-
console.error(`Failed to load policy ${file}:`, error.message);
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
/**
|
|
302
|
-
* Validate policy structure
|
|
303
|
-
*/
|
|
304
|
-
validatePolicy(policy) {
|
|
305
|
-
if (!policy.id || !policy.name || !policy.conditions || !policy.action) {
|
|
306
|
-
return false;
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
if (!Array.isArray(policy.conditions)) {
|
|
310
|
-
return false;
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
for (const condition of policy.conditions) {
|
|
314
|
-
if (!condition.field || !condition.operator) {
|
|
315
|
-
return false;
|
|
316
|
-
}
|
|
317
|
-
if (!OPERATORS[condition.operator]) {
|
|
318
|
-
return false;
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
if (!Object.values(ACTIONS).includes(policy.action)) {
|
|
323
|
-
return false;
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
return true;
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
/**
|
|
330
|
-
* Add or update a policy
|
|
331
|
-
*/
|
|
332
|
-
addPolicy(policy) {
|
|
333
|
-
if (!this.validatePolicy(policy)) {
|
|
334
|
-
throw new Error("Invalid policy structure");
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
this.customPolicies.set(policy.id, { ...policy, builtIn: false });
|
|
338
|
-
|
|
339
|
-
// Save to disk
|
|
340
|
-
const policyPath = path.join(this.options.policiesDir, `${policy.id}.json`);
|
|
341
|
-
fs.mkdirSync(this.options.policiesDir, { recursive: true });
|
|
342
|
-
fs.writeFileSync(policyPath, JSON.stringify(policy, null, 2));
|
|
343
|
-
|
|
344
|
-
return policy;
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
/**
|
|
348
|
-
* Remove a custom policy
|
|
349
|
-
*/
|
|
350
|
-
removePolicy(policyId) {
|
|
351
|
-
if (!this.customPolicies.has(policyId)) {
|
|
352
|
-
return false;
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
this.customPolicies.delete(policyId);
|
|
356
|
-
|
|
357
|
-
const policyPath = path.join(this.options.policiesDir, `${policyId}.json`);
|
|
358
|
-
if (fs.existsSync(policyPath)) {
|
|
359
|
-
fs.unlinkSync(policyPath);
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
return true;
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
/**
|
|
366
|
-
* Get all policies (built-in + custom)
|
|
367
|
-
*/
|
|
368
|
-
getAllPolicies() {
|
|
369
|
-
const all = new Map([...this.policies, ...this.customPolicies]);
|
|
370
|
-
return Array.from(all.values())
|
|
371
|
-
.filter(p => p.enabled)
|
|
372
|
-
.sort((a, b) => (b.priority || 0) - (a.priority || 0));
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
/**
|
|
376
|
-
* Evaluate a condition against context
|
|
377
|
-
*/
|
|
378
|
-
evaluateCondition(condition, context) {
|
|
379
|
-
let value = context;
|
|
380
|
-
|
|
381
|
-
// Navigate to field
|
|
382
|
-
const fieldParts = condition.field.split(".");
|
|
383
|
-
for (const part of fieldParts) {
|
|
384
|
-
if (value === undefined || value === null) break;
|
|
385
|
-
value = value[part];
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
// If path is specified, check array items
|
|
389
|
-
if (condition.path && Array.isArray(value)) {
|
|
390
|
-
return value.some(item => {
|
|
391
|
-
let itemValue = item;
|
|
392
|
-
const pathParts = condition.path.split(".");
|
|
393
|
-
for (const part of pathParts) {
|
|
394
|
-
if (itemValue === undefined || itemValue === null) break;
|
|
395
|
-
itemValue = itemValue[part];
|
|
396
|
-
}
|
|
397
|
-
return OPERATORS[condition.operator](itemValue, condition.value);
|
|
398
|
-
});
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
// Regular evaluation
|
|
402
|
-
return OPERATORS[condition.operator](value, condition.value);
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
/**
|
|
406
|
-
* Evaluate all policies against context
|
|
407
|
-
*/
|
|
408
|
-
evaluate(context) {
|
|
409
|
-
const results = [];
|
|
410
|
-
const policies = this.getAllPolicies();
|
|
411
|
-
|
|
412
|
-
// Add time context
|
|
413
|
-
const now = new Date();
|
|
414
|
-
context.time = {
|
|
415
|
-
hour: now.getHours(),
|
|
416
|
-
minute: now.getMinutes(),
|
|
417
|
-
dayOfWeek: now.getDay(),
|
|
418
|
-
date: now.toISOString().split("T")[0],
|
|
419
|
-
timestamp: now.toISOString(),
|
|
420
|
-
};
|
|
421
|
-
|
|
422
|
-
// Evaluate each policy
|
|
423
|
-
for (const policy of policies) {
|
|
424
|
-
let matched = true;
|
|
425
|
-
|
|
426
|
-
// All conditions must match (AND logic)
|
|
427
|
-
for (const condition of policy.conditions) {
|
|
428
|
-
if (!this.evaluateCondition(condition, context)) {
|
|
429
|
-
matched = false;
|
|
430
|
-
break;
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
if (matched) {
|
|
435
|
-
results.push(new PolicyResult(
|
|
436
|
-
policy,
|
|
437
|
-
true,
|
|
438
|
-
policy.action,
|
|
439
|
-
policy.message
|
|
440
|
-
));
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
return results;
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
/**
|
|
448
|
-
* Get the most severe action from results
|
|
449
|
-
*/
|
|
450
|
-
getMostSevereAction(results) {
|
|
451
|
-
const actionPriority = {
|
|
452
|
-
[ACTIONS.BLOCK]: 100,
|
|
453
|
-
[ACTIONS.REQUIRE_APPROVAL]: 80,
|
|
454
|
-
[ACTIONS.ESCALATE]: 70,
|
|
455
|
-
[ACTIONS.WARN]: 50,
|
|
456
|
-
[ACTIONS.NOTIFY]: 30,
|
|
457
|
-
[ACTIONS.AUTO_FIX]: 20,
|
|
458
|
-
[ACTIONS.ALLOW]: 0,
|
|
459
|
-
};
|
|
460
|
-
|
|
461
|
-
let mostSevere = ACTIONS.ALLOW;
|
|
462
|
-
let maxPriority = 0;
|
|
463
|
-
|
|
464
|
-
for (const result of results) {
|
|
465
|
-
const priority = actionPriority[result.action] || 0;
|
|
466
|
-
if (priority > maxPriority) {
|
|
467
|
-
maxPriority = priority;
|
|
468
|
-
mostSevere = result.action;
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
return mostSevere;
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
/**
|
|
476
|
-
* Check if deployment should be blocked
|
|
477
|
-
*/
|
|
478
|
-
shouldBlock(results) {
|
|
479
|
-
return results.some(r => r.action === ACTIONS.BLOCK);
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
/**
|
|
483
|
-
* Check if approval is required
|
|
484
|
-
*/
|
|
485
|
-
requiresApproval(results) {
|
|
486
|
-
return results.some(r => r.action === ACTIONS.REQUIRE_APPROVAL);
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
/**
|
|
490
|
-
* Generate policy enforcement summary
|
|
491
|
-
*/
|
|
492
|
-
generateSummary(results) {
|
|
493
|
-
const summary = {
|
|
494
|
-
totalPolicies: this.getAllPolicies().length,
|
|
495
|
-
evaluated: results.length,
|
|
496
|
-
blocked: results.filter(r => r.action === ACTIONS.BLOCK).length,
|
|
497
|
-
warnings: results.filter(r => r.action === ACTIONS.WARN).length,
|
|
498
|
-
requiresApproval: results.filter(r => r.action === ACTIONS.REQUIRE_APPROVAL).length,
|
|
499
|
-
finalAction: this.getMostSevereAction(results),
|
|
500
|
-
policies: results.map(r => ({
|
|
501
|
-
id: r.policyId,
|
|
502
|
-
name: r.policyName,
|
|
503
|
-
action: r.action,
|
|
504
|
-
message: r.message,
|
|
505
|
-
})),
|
|
506
|
-
};
|
|
507
|
-
|
|
508
|
-
return summary;
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
/**
|
|
512
|
-
* Create override request
|
|
513
|
-
*/
|
|
514
|
-
createOverrideRequest(results, requestedBy, reason) {
|
|
515
|
-
const request = {
|
|
516
|
-
id: crypto.randomUUID(),
|
|
517
|
-
timestamp: new Date().toISOString(),
|
|
518
|
-
requestedBy,
|
|
519
|
-
reason,
|
|
520
|
-
policies: results.filter(r => r.action === ACTIONS.BLOCK).map(r => r.policyId),
|
|
521
|
-
status: "pending",
|
|
522
|
-
approvals: [],
|
|
523
|
-
expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(), // 24 hours
|
|
524
|
-
};
|
|
525
|
-
|
|
526
|
-
// Save override request
|
|
527
|
-
const overridesDir = path.join(this.options.policiesDir, "overrides");
|
|
528
|
-
fs.mkdirSync(overridesDir, { recursive: true });
|
|
529
|
-
fs.writeFileSync(
|
|
530
|
-
path.join(overridesDir, `${request.id}.json`),
|
|
531
|
-
JSON.stringify(request, null, 2)
|
|
532
|
-
);
|
|
533
|
-
|
|
534
|
-
return request;
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
/**
|
|
538
|
-
* Approve override request
|
|
539
|
-
*/
|
|
540
|
-
approveOverride(requestId, approvedBy) {
|
|
541
|
-
const overridesDir = path.join(this.options.policiesDir, "overrides");
|
|
542
|
-
const requestPath = path.join(overridesDir, `${requestId}.json`);
|
|
543
|
-
|
|
544
|
-
if (!fs.existsSync(requestPath)) {
|
|
545
|
-
throw new Error("Override request not found");
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
const request = JSON.parse(fs.readFileSync(requestPath, "utf-8"));
|
|
549
|
-
|
|
550
|
-
if (new Date(request.expiresAt) < new Date()) {
|
|
551
|
-
request.status = "expired";
|
|
552
|
-
} else {
|
|
553
|
-
request.approvals.push({
|
|
554
|
-
approvedBy,
|
|
555
|
-
timestamp: new Date().toISOString(),
|
|
556
|
-
});
|
|
557
|
-
request.status = "approved";
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
fs.writeFileSync(requestPath, JSON.stringify(request, null, 2));
|
|
561
|
-
|
|
562
|
-
return request;
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
/**
|
|
566
|
-
* Check if override is valid
|
|
567
|
-
*/
|
|
568
|
-
isOverrideValid(requestId) {
|
|
569
|
-
const overridesDir = path.join(this.options.policiesDir, "overrides");
|
|
570
|
-
const requestPath = path.join(overridesDir, `${requestId}.json`);
|
|
571
|
-
|
|
572
|
-
if (!fs.existsSync(requestPath)) {
|
|
573
|
-
return false;
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
const request = JSON.parse(fs.readFileSync(requestPath, "utf-8"));
|
|
577
|
-
|
|
578
|
-
return request.status === "approved" && new Date(request.expiresAt) > new Date();
|
|
579
|
-
}
|
|
580
|
-
}
|
|
581
|
-
|
|
582
|
-
// Terminal UI rendering
|
|
583
|
-
let terminalUI;
|
|
584
|
-
try {
|
|
585
|
-
terminalUI = require("./terminal-ui");
|
|
586
|
-
} catch {
|
|
587
|
-
terminalUI = {
|
|
588
|
-
c: { reset: "", bold: "", dim: "" },
|
|
589
|
-
rgb: () => "",
|
|
590
|
-
};
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
const { c, rgb } = terminalUI;
|
|
594
|
-
|
|
595
|
-
const colors = {
|
|
596
|
-
block: rgb(255, 80, 80),
|
|
597
|
-
warn: rgb(255, 200, 0),
|
|
598
|
-
allow: rgb(0, 255, 150),
|
|
599
|
-
approval: rgb(255, 150, 50),
|
|
600
|
-
};
|
|
601
|
-
|
|
602
|
-
/**
|
|
603
|
-
* Render policy results for terminal
|
|
604
|
-
*/
|
|
605
|
-
function renderPolicyResults(results) {
|
|
606
|
-
const lines = [];
|
|
607
|
-
|
|
608
|
-
lines.push(` ${c.dim}╭${"─".repeat(60)}╮${c.reset}`);
|
|
609
|
-
lines.push(` ${c.dim}│${c.reset} ${rgb(0, 200, 255)}${c.bold}🛡️ POLICY ENFORCEMENT${c.reset} ${c.dim}│${c.reset}`);
|
|
610
|
-
lines.push(` ${c.dim}├${"─".repeat(60)}┤${c.reset}`);
|
|
611
|
-
|
|
612
|
-
if (results.length === 0) {
|
|
613
|
-
lines.push(` ${c.dim}│${c.reset} ${colors.allow}✓${c.reset} All policies passed ${c.dim}│${c.reset}`);
|
|
614
|
-
} else {
|
|
615
|
-
for (const result of results) {
|
|
616
|
-
const actionIcon = {
|
|
617
|
-
block: `${colors.block}✗`,
|
|
618
|
-
warn: `${colors.warn}⚠`,
|
|
619
|
-
allow: `${colors.allow}✓`,
|
|
620
|
-
require_approval: `${colors.approval}🔐`,
|
|
621
|
-
notify: `${rgb(100, 200, 255)}📢`,
|
|
622
|
-
}[result.action] || "•";
|
|
623
|
-
|
|
624
|
-
const actionColor = {
|
|
625
|
-
block: colors.block,
|
|
626
|
-
warn: colors.warn,
|
|
627
|
-
allow: colors.allow,
|
|
628
|
-
require_approval: colors.approval,
|
|
629
|
-
}[result.action] || c.dim;
|
|
630
|
-
|
|
631
|
-
lines.push(` ${c.dim}│${c.reset} ${actionIcon}${c.reset} ${result.policyName.padEnd(45)} ${actionColor}${result.action.toUpperCase().padEnd(6)}${c.reset}${c.dim}│${c.reset}`);
|
|
632
|
-
|
|
633
|
-
if (result.message) {
|
|
634
|
-
const msg = result.message.substring(0, 54);
|
|
635
|
-
lines.push(` ${c.dim}│${c.reset} ${c.dim}${msg}${c.reset}`.padEnd(73) + `${c.dim}│${c.reset}`);
|
|
636
|
-
}
|
|
637
|
-
}
|
|
638
|
-
}
|
|
639
|
-
|
|
640
|
-
lines.push(` ${c.dim}╰${"─".repeat(60)}╯${c.reset}`);
|
|
641
|
-
|
|
642
|
-
return lines.join("\n");
|
|
643
|
-
}
|
|
644
|
-
|
|
645
|
-
module.exports = {
|
|
646
|
-
PolicyEngine,
|
|
647
|
-
PolicyResult,
|
|
648
|
-
renderPolicyResults,
|
|
649
|
-
OPERATORS,
|
|
650
|
-
ACTIONS,
|
|
651
|
-
POLICY_TEMPLATES,
|
|
652
|
-
};
|