@howlil/ez-agents 3.4.2 → 4.0.0
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/README.md +735 -462
- package/agents/ez-architect-agent.md +267 -0
- package/agents/ez-backend-agent.md +303 -0
- package/agents/ez-chief-strategist.md +271 -0
- package/agents/ez-codebase-mapper.md +770 -770
- package/agents/ez-context-manager.md +319 -0
- package/agents/ez-debugger.md +1255 -1255
- package/agents/ez-design-expert.md +347 -0
- package/agents/ez-devops-agent.md +331 -0
- package/agents/ez-executor.md +487 -487
- package/agents/ez-frontend-agent.md +322 -0
- package/agents/ez-phase-researcher.md +553 -553
- package/agents/ez-planner.md +1307 -1307
- package/agents/ez-product-engineer.md +435 -0
- package/agents/ez-project-researcher.md +629 -629
- package/agents/ez-qa-agent.md +320 -0
- package/agents/ez-release-agent.md +333 -0
- package/agents/ez-requirements-agent.md +377 -0
- package/agents/ez-roadmapper.md +650 -650
- package/agents/ez-technical-writer.md +551 -0
- package/agents/ez-ux-expert.md +393 -0
- package/agents/ez-verifier.md +579 -579
- package/bin/guards/autonomy-guard.cjs +346 -0
- package/bin/guards/context-budget-guard.cjs +278 -0
- package/bin/guards/hallucination-guard.cjs +380 -0
- package/bin/guards/hidden-state-guard.cjs +182 -0
- package/bin/guards/team-overhead-guard.cjs +266 -0
- package/bin/guards/tool-sprawl-guard.cjs +271 -0
- package/bin/install.js +3221 -3272
- package/bin/lib/analytics/analytics-collector.cjs +86 -0
- package/bin/lib/analytics/analytics-reporter.cjs +130 -0
- package/bin/lib/analytics/cohort-analyzer.cjs +138 -0
- package/bin/lib/analytics/funnel-analyzer.cjs +147 -0
- package/bin/lib/analytics/nps-tracker.cjs +147 -0
- package/bin/lib/archetype-detector.cjs +289 -0
- package/bin/lib/assistant-adapter.cjs +361 -0
- package/bin/lib/audit-exec.cjs +175 -0
- package/bin/lib/auth.cjs +176 -0
- package/bin/lib/backup-service.cjs +422 -0
- package/bin/lib/bdd-validator.cjs +622 -0
- package/bin/lib/business-flow-mapper.cjs +429 -0
- package/bin/lib/circuit-breaker.cjs +276 -0
- package/bin/lib/code-complexity-analyzer.cjs +360 -0
- package/bin/lib/codebase-analyzer.cjs +241 -0
- package/bin/lib/commands.cjs +691 -0
- package/bin/lib/config.cjs +236 -0
- package/bin/lib/constraint-extractor.cjs +526 -0
- package/bin/lib/content-scanner.cjs +238 -0
- package/bin/lib/context-cache.cjs +154 -0
- package/bin/lib/context-compressor.cjs +102 -0
- package/bin/lib/context-deduplicator.cjs +105 -0
- package/bin/lib/context-errors.cjs +78 -0
- package/bin/lib/context-manager.cjs +338 -0
- package/bin/lib/context-metadata-tracker.cjs +140 -0
- package/bin/lib/context-relevance-scorer.cjs +99 -0
- package/bin/lib/core.cjs +507 -0
- package/bin/lib/cost-alerts.cjs +174 -0
- package/bin/lib/cost-tracker.cjs +275 -0
- package/bin/lib/crash-recovery.cjs +220 -0
- package/bin/lib/dependency-graph.cjs +319 -0
- package/bin/lib/deploy/deploy-audit-log.cjs +76 -0
- package/bin/lib/deploy/deploy-detector.cjs +69 -0
- package/bin/lib/deploy/deploy-env-manager.cjs +109 -0
- package/bin/lib/deploy/deploy-health-check.cjs +88 -0
- package/bin/lib/deploy/deploy-pre-flight.cjs +57 -0
- package/bin/lib/deploy/deploy-rollback.cjs +72 -0
- package/bin/lib/deploy/deploy-runner.cjs +97 -0
- package/bin/lib/deploy/deploy-status.cjs +74 -0
- package/bin/lib/discussion-synthesizer.cjs +439 -0
- package/bin/lib/error-cache.cjs +114 -0
- package/bin/lib/error-registry.cjs +177 -0
- package/bin/lib/file-access.cjs +207 -0
- package/bin/lib/file-lock.cjs +236 -0
- package/bin/lib/finops/budget-enforcer.cjs +126 -0
- package/bin/lib/finops/cost-reporter.cjs +132 -0
- package/bin/lib/finops/finops-analyzer.cjs +112 -0
- package/bin/lib/finops/spot-manager.cjs +118 -0
- package/bin/lib/framework-detector.cjs +396 -0
- package/bin/lib/frontmatter.cjs +313 -0
- package/bin/lib/fs-utils.cjs +153 -0
- package/bin/lib/gate-executor.cjs +272 -0
- package/bin/lib/gates/README.md +374 -0
- package/bin/lib/gates/gate-01-requirement.cjs +303 -0
- package/bin/lib/gates/gate-02-architecture.cjs +555 -0
- package/bin/lib/gates/gate-03-code.cjs +635 -0
- package/bin/lib/gates/gate-04-security.cjs +829 -0
- package/bin/lib/git-errors.cjs +83 -0
- package/bin/lib/git-utils.cjs +321 -0
- package/bin/lib/git-workflow-engine.cjs +1157 -0
- package/bin/lib/health-check.cjs +227 -0
- package/bin/lib/index.cjs +279 -0
- package/bin/lib/init.cjs +725 -0
- package/bin/lib/lock-logger.cjs +194 -0
- package/bin/lib/lock-state.cjs +263 -0
- package/bin/lib/lockfile-validator.cjs +227 -0
- package/bin/lib/log-rotation.cjs +71 -0
- package/bin/lib/logger.cjs +125 -0
- package/bin/lib/memory-compression.cjs +256 -0
- package/bin/lib/milestone.cjs +247 -0
- package/bin/lib/model-provider.cjs +241 -0
- package/bin/lib/package-manager-detector.cjs +203 -0
- package/bin/lib/package-manager-executor.cjs +385 -0
- package/bin/lib/package-manager-service.cjs +216 -0
- package/bin/lib/perf/api-monitor.cjs +88 -0
- package/bin/lib/perf/db-optimizer.cjs +78 -0
- package/bin/lib/perf/frontend-performance.cjs +56 -0
- package/bin/lib/perf/perf-analyzer.cjs +77 -0
- package/bin/lib/perf/perf-baseline.cjs +102 -0
- package/bin/lib/perf/perf-reporter.cjs +117 -0
- package/bin/lib/perf/regression-detector.cjs +92 -0
- package/bin/lib/phase.cjs +963 -0
- package/bin/lib/planning-write.cjs +123 -0
- package/bin/lib/project-reporter.cjs +565 -0
- package/bin/lib/quality-gate.cjs +332 -0
- package/bin/lib/quality-metrics.cjs +324 -0
- package/bin/lib/recovery-manager.cjs +98 -0
- package/bin/lib/release-validator.cjs +617 -0
- package/bin/lib/retry.cjs +119 -0
- package/bin/lib/roadmap.cjs +309 -0
- package/bin/lib/safe-exec.cjs +173 -0
- package/bin/lib/safe-path.cjs +130 -0
- package/bin/lib/security-errors.cjs +62 -0
- package/bin/lib/session-chain.cjs +304 -0
- package/bin/lib/session-errors.cjs +81 -0
- package/bin/lib/session-export.cjs +251 -0
- package/bin/lib/session-import.cjs +262 -0
- package/bin/lib/session-manager.cjs +280 -0
- package/bin/lib/skill-context.cjs +148 -0
- package/bin/lib/skill-matcher.cjs +236 -0
- package/bin/lib/skill-registry.cjs +360 -0
- package/bin/lib/skill-resolver.cjs +449 -0
- package/bin/lib/skill-triggers.cjs +90 -0
- package/bin/lib/skill-validator.cjs +270 -0
- package/bin/lib/skill-versioning.cjs +355 -0
- package/bin/lib/stack-detector.cjs +399 -0
- package/bin/lib/state.cjs +736 -0
- package/bin/lib/tech-debt-analyzer.cjs +309 -0
- package/bin/lib/temp-file.cjs +239 -0
- package/bin/lib/template.cjs +223 -0
- package/bin/lib/test-file-lock.cjs +112 -0
- package/bin/lib/test-graceful.cjs +93 -0
- package/bin/lib/test-logger.cjs +60 -0
- package/bin/lib/test-safe-exec.cjs +38 -0
- package/bin/lib/test-safe-path.cjs +33 -0
- package/bin/lib/test-temp-file.cjs +125 -0
- package/bin/lib/tier-manager.cjs +428 -0
- package/bin/lib/timeout-exec.cjs +63 -0
- package/bin/lib/tradeoff-analyzer.cjs +284 -0
- package/bin/lib/url-fetch.cjs +170 -0
- package/bin/lib/verify.cjs +863 -0
- package/bin/update.js +217 -214
- package/commands/deploy.cjs +53 -0
- package/commands/ez/add-tests.md +41 -41
- package/commands/ez/audit-milestone.md +36 -36
- package/commands/ez/complete-milestone.md +136 -136
- package/commands/ez/discuss-phase.md +90 -90
- package/commands/ez/execute-phase.md +52 -41
- package/commands/ez/help.md +22 -22
- package/commands/ez/map-codebase.md +71 -71
- package/commands/ez/new-milestone.md +44 -44
- package/commands/ez/new-project.md +51 -42
- package/commands/ez/plan-phase.md +53 -45
- package/commands/ez/progress.md +36 -24
- package/commands/ez/quick.md +45 -45
- package/commands/ez/resume-work.md +40 -40
- package/commands/ez/run-phase.md +580 -0
- package/commands/ez/settings.md +36 -36
- package/commands/ez/update.md +37 -37
- package/commands/ez/verify-work.md +402 -38
- package/commands/health-check.cjs +44 -0
- package/commands/rollback.cjs +47 -0
- package/ez-agents/bin/ez-tools.cjs +1692 -716
- package/ez-agents/bin/guards/autonomy-guard.cjs +346 -0
- package/ez-agents/bin/guards/context-budget-guard.cjs +247 -0
- package/ez-agents/bin/guards/hallucination-guard.cjs +271 -0
- package/ez-agents/bin/guards/hidden-state-guard.cjs +182 -0
- package/ez-agents/bin/guards/team-overhead-guard.cjs +266 -0
- package/ez-agents/bin/guards/tool-sprawl-guard.cjs +271 -0
- package/ez-agents/bin/lib/analytics/analytics-collector.cjs +86 -0
- package/ez-agents/bin/lib/analytics/analytics-reporter.cjs +130 -0
- package/ez-agents/bin/lib/analytics/cohort-analyzer.cjs +138 -0
- package/ez-agents/bin/lib/analytics/funnel-analyzer.cjs +147 -0
- package/ez-agents/bin/lib/analytics/nps-tracker.cjs +147 -0
- package/ez-agents/bin/lib/archetype-detector.cjs +289 -0
- package/ez-agents/bin/lib/audit-exec.cjs +166 -167
- package/ez-agents/bin/lib/auth.cjs +176 -176
- package/ez-agents/bin/lib/backup-service.cjs +422 -0
- package/ez-agents/bin/lib/bdd-validator.cjs +622 -0
- package/ez-agents/bin/lib/business-flow-mapper.cjs +429 -0
- package/ez-agents/bin/lib/code-complexity-analyzer.cjs +360 -0
- package/ez-agents/bin/lib/codebase-analyzer.cjs +241 -0
- package/ez-agents/bin/lib/commands.cjs +685 -685
- package/ez-agents/bin/lib/config.cjs +41 -1
- package/ez-agents/bin/lib/constraint-extractor.cjs +526 -0
- package/ez-agents/bin/lib/content-scanner.cjs +238 -0
- package/ez-agents/bin/lib/context-cache.cjs +154 -0
- package/ez-agents/bin/lib/context-errors.cjs +71 -0
- package/ez-agents/bin/lib/context-manager.cjs +220 -0
- package/ez-agents/bin/lib/core.cjs +507 -512
- package/ez-agents/bin/lib/cost-tracker.cjs +243 -0
- package/ez-agents/bin/lib/crash-recovery.cjs +172 -0
- package/ez-agents/bin/lib/dependency-graph.cjs +319 -0
- package/ez-agents/bin/lib/deploy/deploy-audit-log.cjs +76 -0
- package/ez-agents/bin/lib/deploy/deploy-detector.cjs +69 -0
- package/ez-agents/bin/lib/deploy/deploy-env-manager.cjs +109 -0
- package/ez-agents/bin/lib/deploy/deploy-health-check.cjs +88 -0
- package/ez-agents/bin/lib/deploy/deploy-pre-flight.cjs +57 -0
- package/ez-agents/bin/lib/deploy/deploy-rollback.cjs +72 -0
- package/ez-agents/bin/lib/deploy/deploy-runner.cjs +97 -0
- package/ez-agents/bin/lib/deploy/deploy-status.cjs +74 -0
- package/ez-agents/bin/lib/discussion-synthesizer.cjs +458 -0
- package/ez-agents/bin/lib/file-access.cjs +207 -0
- package/ez-agents/bin/lib/finops/budget-enforcer.cjs +126 -0
- package/ez-agents/bin/lib/finops/cost-reporter.cjs +132 -0
- package/ez-agents/bin/lib/finops/finops-analyzer.cjs +112 -0
- package/ez-agents/bin/lib/finops/spot-manager.cjs +118 -0
- package/ez-agents/bin/lib/framework-detector.cjs +396 -0
- package/ez-agents/bin/lib/frontmatter.cjs +3 -1
- package/ez-agents/bin/lib/gates/README.md +374 -0
- package/ez-agents/bin/lib/gates/gate-01-requirement.cjs +303 -0
- package/ez-agents/bin/lib/gates/gate-02-architecture.cjs +555 -0
- package/ez-agents/bin/lib/gates/gate-03-code.cjs +635 -0
- package/ez-agents/bin/lib/gates/gate-04-security.cjs +829 -0
- package/ez-agents/bin/lib/git-errors.cjs +83 -0
- package/ez-agents/bin/lib/git-utils.cjs +118 -0
- package/ez-agents/bin/lib/git-workflow-engine.cjs +1157 -0
- package/ez-agents/bin/lib/health-check.cjs +162 -162
- package/ez-agents/bin/lib/index.cjs +40 -2
- package/ez-agents/bin/lib/init.cjs +0 -2
- package/ez-agents/bin/lib/lockfile-validator.cjs +227 -0
- package/ez-agents/bin/lib/log-rotation.cjs +71 -0
- package/ez-agents/bin/lib/logger.cjs +99 -154
- package/ez-agents/bin/lib/memory-compression.cjs +256 -0
- package/ez-agents/bin/lib/package-manager-detector.cjs +203 -0
- package/ez-agents/bin/lib/package-manager-executor.cjs +385 -0
- package/ez-agents/bin/lib/package-manager-service.cjs +216 -0
- package/ez-agents/bin/lib/perf/api-monitor.cjs +88 -0
- package/ez-agents/bin/lib/perf/db-optimizer.cjs +78 -0
- package/ez-agents/bin/lib/perf/frontend-performance.cjs +56 -0
- package/ez-agents/bin/lib/perf/perf-analyzer.cjs +77 -0
- package/ez-agents/bin/lib/perf/perf-baseline.cjs +102 -0
- package/ez-agents/bin/lib/perf/perf-reporter.cjs +117 -0
- package/ez-agents/bin/lib/perf/regression-detector.cjs +92 -0
- package/ez-agents/bin/lib/project-reporter.cjs +502 -0
- package/ez-agents/bin/lib/quality-gate.cjs +332 -0
- package/ez-agents/bin/lib/recovery-manager.cjs +98 -0
- package/ez-agents/bin/lib/release-validator.cjs +617 -0
- package/ez-agents/bin/lib/safe-exec.cjs +128 -214
- package/ez-agents/bin/lib/security-errors.cjs +62 -0
- package/ez-agents/bin/lib/session-chain.cjs +304 -0
- package/ez-agents/bin/lib/session-errors.cjs +81 -0
- package/ez-agents/bin/lib/session-export.cjs +251 -0
- package/ez-agents/bin/lib/session-import.cjs +262 -0
- package/ez-agents/bin/lib/session-manager.cjs +280 -0
- package/ez-agents/bin/lib/skill-context.cjs +148 -0
- package/ez-agents/bin/lib/skill-matcher.cjs +236 -0
- package/ez-agents/bin/lib/skill-registry.cjs +341 -0
- package/ez-agents/bin/lib/skill-resolver.cjs +449 -0
- package/ez-agents/bin/lib/skill-triggers.cjs +90 -0
- package/ez-agents/bin/lib/skill-validator.cjs +270 -0
- package/ez-agents/bin/lib/skill-versioning.cjs +355 -0
- package/ez-agents/bin/lib/stack-detector.cjs +399 -0
- package/ez-agents/bin/lib/tech-debt-analyzer.cjs +309 -0
- package/ez-agents/bin/lib/tier-manager.cjs +428 -0
- package/ez-agents/bin/lib/tradeoff-analyzer.cjs +284 -0
- package/ez-agents/bin/lib/url-fetch.cjs +170 -0
- package/ez-agents/bin/lib/verify.cjs +863 -863
- package/ez-agents/references/decimal-phase-calculation.md +65 -65
- package/ez-agents/references/git-integration.md +248 -248
- package/ez-agents/references/git-planning-commit.md +38 -38
- package/ez-agents/references/metrics-schema.md +118 -0
- package/ez-agents/references/model-profile-resolution.md +34 -34
- package/ez-agents/references/model-profiles.md +93 -93
- package/ez-agents/references/phase-argument-parsing.md +61 -61
- package/ez-agents/references/planning-config.md +340 -200
- package/ez-agents/references/tier-strategy.md +103 -0
- package/ez-agents/references/ui-brand.md +160 -160
- package/ez-agents/references/verification-patterns.md +612 -612
- package/ez-agents/templates/DEBUG.md +164 -164
- package/ez-agents/templates/UAT.md +247 -247
- package/ez-agents/templates/agent-output-format.md +404 -0
- package/ez-agents/templates/bdd-feature.md +173 -0
- package/ez-agents/templates/codebase/architecture.md +255 -255
- package/ez-agents/templates/codebase/structure.md +285 -285
- package/ez-agents/templates/copilot-instructions.md +7 -7
- package/ez-agents/templates/debug-subagent-prompt.md +91 -91
- package/ez-agents/templates/discovery.md +146 -146
- package/ez-agents/templates/discussion.md +68 -0
- package/ez-agents/templates/handoff-protocol.md +294 -0
- package/ez-agents/templates/incident-runbook.md +205 -0
- package/ez-agents/templates/mode-workflow-templates.md +301 -0
- package/ez-agents/templates/phase-prompt.md +610 -610
- package/ez-agents/templates/planner-subagent-prompt.md +117 -117
- package/ez-agents/templates/project.md +184 -184
- package/ez-agents/templates/release-checklist.md +136 -0
- package/ez-agents/templates/research.md +552 -552
- package/ez-agents/templates/rollback-plan.md +201 -0
- package/ez-agents/templates/security-user-setup.md +244 -0
- package/ez-agents/templates/skill-validation-rules.md +476 -0
- package/ez-agents/templates/state.md +180 -176
- package/ez-agents/templates/summary-complex.md +59 -59
- package/ez-agents/tests/gates/gate-01-02.test.cjs +812 -0
- package/ez-agents/tests/gates/gate-03-04.test.cjs +762 -0
- package/ez-agents/tests/gates/gate-05-validator.test.cjs +145 -0
- package/ez-agents/tests/gates/gate-06-docs-validator.test.cjs +244 -0
- package/ez-agents/tests/gates/gate-07-release-validator.test.cjs +219 -0
- package/ez-agents/tests/guards/context-budget-guard.test.cjs +145 -0
- package/ez-agents/tests/guards/edge-case-guards.test.cjs +238 -0
- package/ez-agents/tests/guards/hallucination-guard.test.cjs +124 -0
- package/ez-agents/workflows/audit-milestone.md +1 -1
- package/ez-agents/workflows/autonomous.md +131 -30
- package/ez-agents/workflows/complete-milestone.md +1 -1
- package/ez-agents/workflows/discuss-phase.md +1 -1
- package/ez-agents/workflows/execute-phase.md +169 -3
- package/ez-agents/workflows/help.md +86 -133
- package/ez-agents/workflows/hotfix.md +291 -0
- package/ez-agents/workflows/new-milestone.md +340 -11
- package/ez-agents/workflows/new-project.md +294 -318
- package/ez-agents/workflows/plan-phase.md +22 -40
- package/ez-agents/workflows/progress.md +15 -25
- package/ez-agents/workflows/release.md +253 -0
- package/ez-agents/workflows/resume-session.md +215 -0
- package/ez-agents/workflows/run-phase.md +531 -0
- package/ez-agents/workflows/settings.md +2 -35
- package/hooks/dist/ez-check-update.js +81 -81
- package/hooks/dist/ez-context-monitor.js +148 -141
- package/hooks/dist/ez-statusline.js +115 -115
- package/package.json +78 -64
- package/scripts/fix-qwen-installation.js +144 -144
- package/agents/ez-integration-checker.md +0 -443
- package/agents/ez-nyquist-auditor.md +0 -176
- package/agents/ez-plan-checker.md +0 -706
- package/agents/ez-research-synthesizer.md +0 -247
- package/agents/ez-ui-auditor.md +0 -439
- package/agents/ez-ui-checker.md +0 -300
- package/agents/ez-ui-researcher.md +0 -353
- package/commands/ez/add-phase.md +0 -43
- package/commands/ez/add-todo.md +0 -47
- package/commands/ez/auth.md +0 -87
- package/commands/ez/autonomous.md +0 -41
- package/commands/ez/check-todos.md +0 -45
- package/commands/ez/cleanup.md +0 -18
- package/commands/ez/debug.md +0 -168
- package/commands/ez/health.md +0 -22
- package/commands/ez/insert-phase.md +0 -32
- package/commands/ez/join-discord.md +0 -18
- package/commands/ez/list-phase-assumptions.md +0 -46
- package/commands/ez/pause-work.md +0 -38
- package/commands/ez/plan-milestone-gaps.md +0 -34
- package/commands/ez/reapply-patches.md +0 -124
- package/commands/ez/remove-phase.md +0 -31
- package/commands/ez/research-phase.md +0 -190
- package/commands/ez/set-profile.md +0 -34
- package/commands/ez/stats.md +0 -18
- package/commands/ez/ui-phase.md +0 -34
- package/commands/ez/ui-review.md +0 -32
- package/commands/ez/validate-phase.md +0 -35
- package/ez-agents/templates/UI-SPEC.md +0 -100
- package/ez-agents/templates/VALIDATION.md +0 -76
- package/ez-agents/templates/context.md +0 -352
- package/ez-agents/templates/verification-report.md +0 -322
- package/ez-agents/workflows/research-phase.md +0 -74
- package/ez-agents/workflows/ui-phase.md +0 -290
- package/ez-agents/workflows/ui-review.md +0 -157
- package/ez-agents/workflows/validate-phase.md +0 -167
|
@@ -0,0 +1,829 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gate 4: Security Baseline
|
|
3
|
+
*
|
|
4
|
+
* Validates security implementation including authentication, input validation,
|
|
5
|
+
* secrets management, and security anti-patterns.
|
|
6
|
+
*
|
|
7
|
+
* Checks:
|
|
8
|
+
* 1. Auth checker (session management, token handling, password hashing)
|
|
9
|
+
* 2. Input validation checker (sanitization, escaping, validation schemas)
|
|
10
|
+
* 3. Secrets scanner (hardcoded API keys, passwords, tokens)
|
|
11
|
+
* 4. Security anti-pattern detector (eval, execSync with user input, SQL concatenation)
|
|
12
|
+
*
|
|
13
|
+
* @module gates/gate-04-security
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const { z } = require('zod');
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Zod schema for a code file
|
|
20
|
+
* @type {z.ZodSchema}
|
|
21
|
+
*/
|
|
22
|
+
const codeFileSchema = z.object({
|
|
23
|
+
/** File path */
|
|
24
|
+
path: z.string(),
|
|
25
|
+
/** File content */
|
|
26
|
+
content: z.string(),
|
|
27
|
+
/** File language (e.g., 'javascript', 'typescript') */
|
|
28
|
+
language: z.string().optional(),
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Zod schema for environment variables configuration
|
|
33
|
+
* @type {z.ZodSchema}
|
|
34
|
+
*/
|
|
35
|
+
const envConfigSchema = z.object({
|
|
36
|
+
/** Environment variable name */
|
|
37
|
+
name: z.string(),
|
|
38
|
+
/** Whether it's used in code */
|
|
39
|
+
isUsed: z.boolean().optional(),
|
|
40
|
+
/** Whether it has a default value */
|
|
41
|
+
hasDefault: z.boolean().optional(),
|
|
42
|
+
/** Whether it's marked as sensitive */
|
|
43
|
+
isSensitive: z.boolean().optional(),
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Zod schema for authentication configuration
|
|
48
|
+
* @type {z.ZodSchema}
|
|
49
|
+
*/
|
|
50
|
+
const authConfigSchema = z.object({
|
|
51
|
+
/** Authentication method (session, jwt, oauth, etc.) */
|
|
52
|
+
method: z.string().optional(),
|
|
53
|
+
/** Session store type (memory, redis, database) */
|
|
54
|
+
sessionStore: z.string().optional(),
|
|
55
|
+
/** Token expiration time */
|
|
56
|
+
tokenExpiration: z.string().optional(),
|
|
57
|
+
/** Password hashing algorithm */
|
|
58
|
+
hashingAlgorithm: z.string().optional(),
|
|
59
|
+
/** Whether HTTPS is enforced */
|
|
60
|
+
httpsEnforced: z.boolean().optional(),
|
|
61
|
+
/** Whether CSRF protection is enabled */
|
|
62
|
+
csrfProtection: z.boolean().optional(),
|
|
63
|
+
/** Whether rate limiting is enabled */
|
|
64
|
+
rateLimiting: z.boolean().optional(),
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Zod schema for the gate context
|
|
69
|
+
* @type {z.ZodSchema}
|
|
70
|
+
*/
|
|
71
|
+
const gateContextSchema = z.object({
|
|
72
|
+
/** Array of code files to analyze */
|
|
73
|
+
files: z.array(codeFileSchema).optional(),
|
|
74
|
+
/** Environment variable configuration */
|
|
75
|
+
envConfig: z.array(envConfigSchema).optional(),
|
|
76
|
+
/** Authentication configuration */
|
|
77
|
+
authConfig: authConfigSchema.optional(),
|
|
78
|
+
/** Input validation libraries used */
|
|
79
|
+
validationLibraries: z.array(z.string()).optional(),
|
|
80
|
+
/** Whether input validation is implemented */
|
|
81
|
+
hasInputValidation: z.boolean().optional(),
|
|
82
|
+
/** Known safe patterns (to reduce false positives) */
|
|
83
|
+
safePatterns: z.array(z.string()).optional(),
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Security anti-patterns to detect
|
|
88
|
+
*/
|
|
89
|
+
const SECURITY_ANTI_PATTERNS = {
|
|
90
|
+
/** eval() usage - allows arbitrary code execution */
|
|
91
|
+
eval: {
|
|
92
|
+
pattern: /\beval\s*\(/g,
|
|
93
|
+
severity: 'error',
|
|
94
|
+
message: 'eval() allows arbitrary code execution. Use safer alternatives like JSON.parse() or function maps.',
|
|
95
|
+
},
|
|
96
|
+
/** Function constructor - similar risks to eval */
|
|
97
|
+
functionConstructor: {
|
|
98
|
+
pattern: /\bnew\s+Function\s*\(/g,
|
|
99
|
+
severity: 'error',
|
|
100
|
+
message: 'Function constructor allows arbitrary code execution. Use safer alternatives.',
|
|
101
|
+
},
|
|
102
|
+
/** execSync with potential user input */
|
|
103
|
+
execSync: {
|
|
104
|
+
pattern: /\bexecSync\s*\([^)]*\)/g,
|
|
105
|
+
severity: 'error',
|
|
106
|
+
message: 'execSync with user input can lead to command injection. Use parameterized commands or avoid shell execution.',
|
|
107
|
+
},
|
|
108
|
+
/** exec with potential user input */
|
|
109
|
+
exec: {
|
|
110
|
+
pattern: /\bexec\s*\([^)]*\)/g,
|
|
111
|
+
severity: 'warning',
|
|
112
|
+
message: 'exec with user input can lead to command injection. Use execFile or spawn with argument arrays.',
|
|
113
|
+
},
|
|
114
|
+
/** spawn with shell option */
|
|
115
|
+
spawnShell: {
|
|
116
|
+
pattern: /\bspawn\s*\([^)]*shell\s*:\s*true/g,
|
|
117
|
+
severity: 'warning',
|
|
118
|
+
message: 'Using spawn with shell:true can lead to command injection. Avoid shell execution when possible.',
|
|
119
|
+
},
|
|
120
|
+
/** child_process exec variants */
|
|
121
|
+
childProcessExec: {
|
|
122
|
+
pattern: /child_process\s*\.\s*(exec|execSync|execFile|execFileSync)\s*\(/g,
|
|
123
|
+
severity: 'info',
|
|
124
|
+
message: 'Verify that child_process calls do not use unsanitized user input.',
|
|
125
|
+
},
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Patterns for detecting hardcoded secrets
|
|
130
|
+
*/
|
|
131
|
+
const SECRET_PATTERNS = {
|
|
132
|
+
/** AWS Access Key ID */
|
|
133
|
+
awsAccessKey: {
|
|
134
|
+
pattern: /AKIA[0-9A-Z]{16}/g,
|
|
135
|
+
message: 'Potential AWS Access Key ID detected. Use environment variables or secrets manager.',
|
|
136
|
+
severity: 'error',
|
|
137
|
+
},
|
|
138
|
+
/** AWS Secret Access Key (40 char base64) */
|
|
139
|
+
awsSecretKey: {
|
|
140
|
+
pattern: /['"]?(?:aws[_-]?secret|AWS[_-]?SECRET)[_]?[A-Z]*['"]?\s*[:=]\s*['"][A-Za-z0-9/+=]{40}['"]/gi,
|
|
141
|
+
message: 'Potential AWS Secret Access Key detected. Use environment variables or secrets manager.',
|
|
142
|
+
severity: 'error',
|
|
143
|
+
},
|
|
144
|
+
/** Generic API key patterns */
|
|
145
|
+
apiKey: {
|
|
146
|
+
pattern: /['"]?(?:api[_-]?key|apikey|API[_-]?KEY)[_]?[A-Z]*['"]?\s*[:=]\s*['"][a-zA-Z0-9_\-]{16,}['"]/gi,
|
|
147
|
+
message: 'Hardcoded API key detected. Use environment variables (e.g., process.env.API_KEY).',
|
|
148
|
+
severity: 'error',
|
|
149
|
+
},
|
|
150
|
+
/** Generic secret/token patterns */
|
|
151
|
+
secret: {
|
|
152
|
+
pattern: /['"]?(?:secret|token|auth[_-]?token|access[_-]?token|jwt|private[_-]?key)[_]?[A-Z]*['"]?\s*[:=]\s*['"][a-zA-Z0-9_\-]{8,}['"]/gi,
|
|
153
|
+
message: 'Hardcoded secret/token detected. Use environment variables or secrets manager.',
|
|
154
|
+
severity: 'error',
|
|
155
|
+
},
|
|
156
|
+
/** Password patterns */
|
|
157
|
+
password: {
|
|
158
|
+
pattern: /['"]?(?:password|passwd|pwd|PASSWORD|PASSWD)[_]?[A-Z]*['"]?\s*[:=]\s*['"][^'"]{4,}['"]/g,
|
|
159
|
+
message: 'Hardcoded password detected. Use environment variables or secrets manager.',
|
|
160
|
+
severity: 'error',
|
|
161
|
+
},
|
|
162
|
+
/** Database connection strings with credentials */
|
|
163
|
+
dbConnectionString: {
|
|
164
|
+
pattern: /(?:mongodb|postgres|mysql|redis):\/\/[^:]+:[^@]+@/gi,
|
|
165
|
+
message: 'Database connection string with embedded credentials. Use environment variables.',
|
|
166
|
+
severity: 'error',
|
|
167
|
+
},
|
|
168
|
+
/** Private key headers */
|
|
169
|
+
privateKey: {
|
|
170
|
+
pattern: /-----BEGIN\s+(?:RSA\s+)?PRIVATE\s+KEY-----/g,
|
|
171
|
+
message: 'Private key embedded in code. Store in secure secrets manager or use environment variables.',
|
|
172
|
+
severity: 'error',
|
|
173
|
+
},
|
|
174
|
+
/** GitHub/GitLab tokens */
|
|
175
|
+
githubToken: {
|
|
176
|
+
pattern: /gh[pousr]_[A-Za-z0-9_]{36,}/g,
|
|
177
|
+
message: 'GitHub token detected. Use environment variables or secrets manager.',
|
|
178
|
+
severity: 'error',
|
|
179
|
+
},
|
|
180
|
+
/** Slack tokens */
|
|
181
|
+
slackToken: {
|
|
182
|
+
pattern: /xox[baprs]-[0-9]{10,13}-[0-9]{10,13}[a-zA-Z0-9-]*/g,
|
|
183
|
+
message: 'Slack token detected. Use environment variables or secrets manager.',
|
|
184
|
+
severity: 'error',
|
|
185
|
+
},
|
|
186
|
+
/** Google API key */
|
|
187
|
+
googleApiKey: {
|
|
188
|
+
pattern: /AIza[0-9A-Za-z_-]{35}/g,
|
|
189
|
+
message: 'Google API key detected. Use environment variables or Google Secret Manager.',
|
|
190
|
+
severity: 'error',
|
|
191
|
+
},
|
|
192
|
+
/** Stripe keys */
|
|
193
|
+
stripeKey: {
|
|
194
|
+
pattern: /sk_live_[0-9a-zA-Z]{24,}/g,
|
|
195
|
+
message: 'Stripe live key detected. Use environment variables or secrets manager.',
|
|
196
|
+
severity: 'error',
|
|
197
|
+
},
|
|
198
|
+
/** Bearer token in headers */
|
|
199
|
+
bearerToken: {
|
|
200
|
+
pattern: /['"]Bearer\s+[a-zA-Z0-9_\-\.]+['"]/g,
|
|
201
|
+
message: 'Hardcoded Bearer token. Use dynamic token generation and environment variables for secrets.',
|
|
202
|
+
severity: 'warning',
|
|
203
|
+
},
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* SQL injection patterns
|
|
208
|
+
*/
|
|
209
|
+
const SQL_INJECTION_PATTERNS = {
|
|
210
|
+
/** String concatenation in SQL queries */
|
|
211
|
+
stringConcat: {
|
|
212
|
+
pattern: /(?:SELECT|INSERT|UPDATE|DELETE|FROM|WHERE)\s+[^;]*['"`]\s*\+\s*\w+/gi,
|
|
213
|
+
message: 'SQL query with string concatenation detected. Use parameterized queries or query builders.',
|
|
214
|
+
severity: 'error',
|
|
215
|
+
},
|
|
216
|
+
/** Template literal SQL */
|
|
217
|
+
templateLiteral: {
|
|
218
|
+
pattern: /`(?:SELECT|INSERT|UPDATE|DELETE|FROM|WHERE)[^`]*\$\{[^}]+\}/gi,
|
|
219
|
+
message: 'SQL query with template literal interpolation. Use parameterized queries.',
|
|
220
|
+
severity: 'error',
|
|
221
|
+
},
|
|
222
|
+
/** query() with concatenated string */
|
|
223
|
+
queryConcat: {
|
|
224
|
+
pattern: /\.query\s*\(\s*[^)]*\+[^)]*\)/g,
|
|
225
|
+
message: 'Database query with string concatenation. Use parameterized queries.',
|
|
226
|
+
severity: 'error',
|
|
227
|
+
},
|
|
228
|
+
/** execute() with concatenated string */
|
|
229
|
+
executeConcat: {
|
|
230
|
+
pattern: /\.execute\s*\(\s*[^)]*\+[^)]*\)/g,
|
|
231
|
+
message: 'Database execute with string concatenation. Use parameterized queries.',
|
|
232
|
+
severity: 'error',
|
|
233
|
+
},
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Input validation patterns to check for
|
|
238
|
+
*/
|
|
239
|
+
const INPUT_VALIDATION_CHECKS = {
|
|
240
|
+
/** Express validator usage */
|
|
241
|
+
expressValidator: {
|
|
242
|
+
pattern: /express-validator|expressValidator|validationChain|body\(\)|query\(\)|param\(\)/g,
|
|
243
|
+
library: 'express-validator',
|
|
244
|
+
},
|
|
245
|
+
/** Joi validation */
|
|
246
|
+
joi: {
|
|
247
|
+
pattern: /joi\.|Joi\.|\.validate\(|\.schema\.validate/g,
|
|
248
|
+
library: 'joi',
|
|
249
|
+
},
|
|
250
|
+
/** Yup validation */
|
|
251
|
+
yup: {
|
|
252
|
+
pattern: /yup\.|Yup\.|\.validateSync\(|\.validate\(/g,
|
|
253
|
+
library: 'yup',
|
|
254
|
+
},
|
|
255
|
+
/** Zod validation */
|
|
256
|
+
zod: {
|
|
257
|
+
pattern: /zod\.|z\.|\.parse\(|\.safeParse\(|z\.string\(\)|z\.number\(\)/g,
|
|
258
|
+
library: 'zod',
|
|
259
|
+
},
|
|
260
|
+
/** class-validator */
|
|
261
|
+
classValidator: {
|
|
262
|
+
pattern: /class-validator|@IsString|@IsNumber|@IsEmail|@ValidateNested|validateOrReject/g,
|
|
263
|
+
library: 'class-validator',
|
|
264
|
+
},
|
|
265
|
+
/** AJV validation */
|
|
266
|
+
ajv: {
|
|
267
|
+
pattern: /ajv\.|Ajv\(|\.validate\(|\.compile\(/g,
|
|
268
|
+
library: 'ajv',
|
|
269
|
+
},
|
|
270
|
+
/** express-validator sanitize */
|
|
271
|
+
sanitization: {
|
|
272
|
+
pattern: /sanitize\(|\.escape\(|\.trim\(\)|\.normalizeEmail\(\)/g,
|
|
273
|
+
library: 'sanitization',
|
|
274
|
+
},
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Secure session management patterns
|
|
279
|
+
*/
|
|
280
|
+
const SECURE_SESSION_PATTERNS = {
|
|
281
|
+
/** Express session with secure config */
|
|
282
|
+
expressSession: {
|
|
283
|
+
pattern: /session\s*\(\s*\{[^}]*(?:secure|httpOnly|sameSite)[^}]*\}/g,
|
|
284
|
+
secure: true,
|
|
285
|
+
},
|
|
286
|
+
/** Redis session store */
|
|
287
|
+
redisStore: {
|
|
288
|
+
pattern: /connect-redis|RedisStore|redis\.createClient/g,
|
|
289
|
+
secure: true,
|
|
290
|
+
},
|
|
291
|
+
/** JWT with proper config */
|
|
292
|
+
jwtSecure: {
|
|
293
|
+
pattern: /jwt\.sign\s*\([^)]*expiresIn|jwt\.verify|jsonwebtoken/g,
|
|
294
|
+
secure: true,
|
|
295
|
+
},
|
|
296
|
+
/** Insecure session config patterns */
|
|
297
|
+
insecureSession: {
|
|
298
|
+
pattern: /cookie\s*:\s*\{[^}]*(?:secure\s*:\s*false|httpOnly\s*:\s*false)/g,
|
|
299
|
+
secure: false,
|
|
300
|
+
},
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Check for eval() and similar dangerous patterns
|
|
305
|
+
* @param {string} code - Code content to analyze
|
|
306
|
+
* @returns {Array<{ path: string, message: string, severity: string }>}
|
|
307
|
+
*/
|
|
308
|
+
function detectEvalUsage(code) {
|
|
309
|
+
const issues = [];
|
|
310
|
+
|
|
311
|
+
if (!code || typeof code !== 'string') {
|
|
312
|
+
return issues;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// Check for eval()
|
|
316
|
+
const evalMatches = code.match(SECURITY_ANTI_PATTERNS.eval.pattern);
|
|
317
|
+
if (evalMatches) {
|
|
318
|
+
for (const match of evalMatches) {
|
|
319
|
+
issues.push({
|
|
320
|
+
type: 'eval',
|
|
321
|
+
message: SECURITY_ANTI_PATTERNS.eval.message,
|
|
322
|
+
severity: SECURITY_ANTI_PATTERNS.eval.severity,
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// Check for Function constructor
|
|
328
|
+
const funcMatches = code.match(SECURITY_ANTI_PATTERNS.functionConstructor.pattern);
|
|
329
|
+
if (funcMatches) {
|
|
330
|
+
for (const match of funcMatches) {
|
|
331
|
+
issues.push({
|
|
332
|
+
type: 'function-constructor',
|
|
333
|
+
message: SECURITY_ANTI_PATTERNS.functionConstructor.message,
|
|
334
|
+
severity: SECURITY_ANTI_PATTERNS.functionConstructor.severity,
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
return issues;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Check for execSync/exec with potential user input
|
|
344
|
+
* @param {string} code - Code content to analyze
|
|
345
|
+
* @returns {Array<{ type: string, message: string, severity: string }>}
|
|
346
|
+
*/
|
|
347
|
+
function detectExecUsage(code) {
|
|
348
|
+
const issues = [];
|
|
349
|
+
|
|
350
|
+
if (!code || typeof code !== 'string') {
|
|
351
|
+
return issues;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// Check for execSync
|
|
355
|
+
const execSyncMatches = code.match(SECURITY_ANTI_PATTERNS.execSync.pattern);
|
|
356
|
+
if (execSyncMatches) {
|
|
357
|
+
for (const match of execSyncMatches) {
|
|
358
|
+
// Check if it contains user input indicators
|
|
359
|
+
const userInputIndicators = ['req.', 'request.', 'params', 'query', 'body', 'input', 'userInput'];
|
|
360
|
+
const hasUserInput = userInputIndicators.some(indicator => match.toLowerCase().includes(indicator.toLowerCase()));
|
|
361
|
+
|
|
362
|
+
if (hasUserInput || match.includes('+') || match.includes('${')) {
|
|
363
|
+
issues.push({
|
|
364
|
+
type: 'execSync-user-input',
|
|
365
|
+
message: SECURITY_ANTI_PATTERNS.execSync.message,
|
|
366
|
+
severity: SECURITY_ANTI_PATTERNS.execSync.severity,
|
|
367
|
+
});
|
|
368
|
+
} else {
|
|
369
|
+
// Still warn about execSync even without obvious user input
|
|
370
|
+
issues.push({
|
|
371
|
+
type: 'execSync',
|
|
372
|
+
message: 'execSync detected. Ensure no user input is passed to shell commands.',
|
|
373
|
+
severity: 'warning',
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// Check for exec
|
|
380
|
+
const execMatches = code.match(SECURITY_ANTI_PATTERNS.exec.pattern);
|
|
381
|
+
if (execMatches) {
|
|
382
|
+
const userInputIndicators = ['req.', 'request.', 'params', 'query', 'body', 'input', 'userInput'];
|
|
383
|
+
for (const match of execMatches) {
|
|
384
|
+
const hasUserInput = userInputIndicators.some(indicator => match.toLowerCase().includes(indicator.toLowerCase()));
|
|
385
|
+
|
|
386
|
+
if (hasUserInput || match.includes('+') || match.includes('${')) {
|
|
387
|
+
issues.push({
|
|
388
|
+
type: 'exec-user-input',
|
|
389
|
+
message: SECURITY_ANTI_PATTERNS.exec.message,
|
|
390
|
+
severity: 'error',
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
return issues;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* Check for SQL injection vulnerabilities
|
|
401
|
+
* @param {string} code - Code content to analyze
|
|
402
|
+
* @returns {Array<{ type: string, message: string, severity: string }>}
|
|
403
|
+
*/
|
|
404
|
+
function detectSqlInjection(code) {
|
|
405
|
+
const issues = [];
|
|
406
|
+
|
|
407
|
+
if (!code || typeof code !== 'string') {
|
|
408
|
+
return issues;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// Check for string concatenation in SQL
|
|
412
|
+
for (const [name, config] of Object.entries(SQL_INJECTION_PATTERNS)) {
|
|
413
|
+
const matches = code.match(config.pattern);
|
|
414
|
+
if (matches) {
|
|
415
|
+
for (const match of matches) {
|
|
416
|
+
issues.push({
|
|
417
|
+
type: `sql-${name}`,
|
|
418
|
+
message: config.message,
|
|
419
|
+
severity: config.severity,
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
return issues;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* Detect hardcoded secrets in code
|
|
430
|
+
* @param {string} code - Code content to analyze
|
|
431
|
+
* @returns {Array<{ type: string, message: string, severity: string }>}
|
|
432
|
+
*/
|
|
433
|
+
function detectHardcodedSecrets(code) {
|
|
434
|
+
const issues = [];
|
|
435
|
+
|
|
436
|
+
if (!code || typeof code !== 'string') {
|
|
437
|
+
return issues;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// Check for each secret pattern
|
|
441
|
+
for (const [name, config] of Object.entries(SECRET_PATTERNS)) {
|
|
442
|
+
const matches = code.match(config.pattern);
|
|
443
|
+
if (matches && matches.length > 0) {
|
|
444
|
+
for (const match of matches) {
|
|
445
|
+
// Skip if it's clearly using environment variables
|
|
446
|
+
if (match.includes('process.env') || match.includes('process.env')) {
|
|
447
|
+
continue;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
// Skip example/placeholder values
|
|
451
|
+
if (match.includes('YOUR_') || match.includes('xxx') || match.includes('example')) {
|
|
452
|
+
continue;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
issues.push({
|
|
456
|
+
type: `secret-${name}`,
|
|
457
|
+
message: config.message,
|
|
458
|
+
severity: config.severity,
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
return issues;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
/**
|
|
468
|
+
* Check for secure session management
|
|
469
|
+
* @param {string} code - Code content to analyze
|
|
470
|
+
* @param {Object} authConfig - Authentication configuration
|
|
471
|
+
* @returns {{ secure: boolean, issues: Array<{ type: string, message: string }> }}
|
|
472
|
+
*/
|
|
473
|
+
function checkSessionSecurity(code, authConfig = {}) {
|
|
474
|
+
const issues = [];
|
|
475
|
+
let isSecure = true;
|
|
476
|
+
|
|
477
|
+
if (!code || typeof code !== 'string') {
|
|
478
|
+
return { secure: true, issues }; // No session code to check
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
// Check for insecure session configurations
|
|
482
|
+
const insecureMatches = code.match(SECURE_SESSION_PATTERNS.insecureSession.pattern);
|
|
483
|
+
if (insecureMatches) {
|
|
484
|
+
isSecure = false;
|
|
485
|
+
issues.push({
|
|
486
|
+
type: 'insecure-session',
|
|
487
|
+
message: 'Insecure session configuration detected. Ensure secure: true, httpOnly: true, sameSite: strict.',
|
|
488
|
+
});
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
// Check for secure patterns
|
|
492
|
+
const hasSecureSession = Object.values(SECURE_SESSION_PATTERNS).some(pattern =>
|
|
493
|
+
pattern.secure && code.match(pattern.pattern)
|
|
494
|
+
);
|
|
495
|
+
|
|
496
|
+
// Check auth config
|
|
497
|
+
if (authConfig) {
|
|
498
|
+
if (authConfig.sessionStore === 'memory') {
|
|
499
|
+
issues.push({
|
|
500
|
+
type: 'memory-session-store',
|
|
501
|
+
message: 'In-memory session store is not suitable for production. Use Redis or database.',
|
|
502
|
+
});
|
|
503
|
+
isSecure = false;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
if (authConfig.httpsEnforced === false) {
|
|
507
|
+
issues.push({
|
|
508
|
+
type: 'no-https',
|
|
509
|
+
message: 'HTTPS is not enforced. Always use HTTPS in production.',
|
|
510
|
+
});
|
|
511
|
+
isSecure = false;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
if (authConfig.csrfProtection === false) {
|
|
515
|
+
issues.push({
|
|
516
|
+
type: 'no-csrf',
|
|
517
|
+
message: 'CSRF protection is disabled. Enable CSRF protection for state-changing operations.',
|
|
518
|
+
});
|
|
519
|
+
isSecure = false;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
if (authConfig.hashingAlgorithm && ['md5', 'sha1', 'sha256'].includes(authConfig.hashingAlgorithm.toLowerCase())) {
|
|
523
|
+
issues.push({
|
|
524
|
+
type: 'weak-hashing',
|
|
525
|
+
message: `Weak password hashing algorithm (${authConfig.hashingAlgorithm}). Use bcrypt, scrypt, or argon2.`,
|
|
526
|
+
});
|
|
527
|
+
isSecure = false;
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
return { secure: isSecure, issues };
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
/**
|
|
535
|
+
* Check for input validation implementation
|
|
536
|
+
* @param {string} code - Code content to analyze
|
|
537
|
+
* @param {Array} validationLibraries - List of validation libraries used
|
|
538
|
+
* @returns {{ hasValidation: boolean, libraries: string[], issues: Array<{ type: string, message: string }> }}
|
|
539
|
+
*/
|
|
540
|
+
function checkInputValidation(code, validationLibraries = []) {
|
|
541
|
+
const issues = [];
|
|
542
|
+
const foundLibraries = [];
|
|
543
|
+
let hasValidation = false;
|
|
544
|
+
|
|
545
|
+
if (!code || typeof code !== 'string') {
|
|
546
|
+
return { hasValidation: false, libraries: [], issues };
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
// Check for validation library usage
|
|
550
|
+
for (const [name, config] of Object.entries(INPUT_VALIDATION_CHECKS)) {
|
|
551
|
+
if (code.match(config.pattern)) {
|
|
552
|
+
foundLibraries.push(config.library || name);
|
|
553
|
+
hasValidation = true;
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
// Check for manual validation patterns
|
|
558
|
+
const manualValidationPatterns = [
|
|
559
|
+
/typeof\s+\w+\s*===?\s*['"]string['"]/,
|
|
560
|
+
/Array\.isArray\s*\(/,
|
|
561
|
+
/Number\.isInteger\s*\(/,
|
|
562
|
+
/parseInt\s*\(/,
|
|
563
|
+
/parseFloat\s*\(/,
|
|
564
|
+
/\.test\s*\(/,
|
|
565
|
+
/\.match\s*\(/,
|
|
566
|
+
];
|
|
567
|
+
|
|
568
|
+
let manualValidationCount = 0;
|
|
569
|
+
for (const pattern of manualValidationPatterns) {
|
|
570
|
+
if (code.match(pattern)) {
|
|
571
|
+
manualValidationCount++;
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
if (manualValidationCount > 0 && !hasValidation) {
|
|
576
|
+
// Manual validation detected - this is a warning, not an error
|
|
577
|
+
issues.push({
|
|
578
|
+
type: 'manual-validation',
|
|
579
|
+
message: 'Manual input validation detected. Consider using a validation library for consistency.',
|
|
580
|
+
});
|
|
581
|
+
hasValidation = true;
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
// Check for missing validation on user input
|
|
585
|
+
const userInputPatterns = [
|
|
586
|
+
/req\.body/,
|
|
587
|
+
/req\.query/,
|
|
588
|
+
/req\.params/,
|
|
589
|
+
/request\.body/,
|
|
590
|
+
/request\.query/,
|
|
591
|
+
/request\.params/,
|
|
592
|
+
];
|
|
593
|
+
|
|
594
|
+
const hasUserInput = userInputPatterns.some(pattern => code.match(pattern));
|
|
595
|
+
|
|
596
|
+
if (hasUserInput && !hasValidation) {
|
|
597
|
+
issues.push({
|
|
598
|
+
type: 'missing-validation',
|
|
599
|
+
message: 'User input detected without validation. Add input validation using a library or manual checks.',
|
|
600
|
+
});
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
return {
|
|
604
|
+
hasValidation,
|
|
605
|
+
libraries: [...new Set(foundLibraries)],
|
|
606
|
+
issues,
|
|
607
|
+
};
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
/**
|
|
611
|
+
* Check for environment variable usage for secrets
|
|
612
|
+
* @param {string} code - Code content to analyze
|
|
613
|
+
* @param {Array} envConfig - Environment configuration
|
|
614
|
+
* @returns {{ usesEnvVars: boolean, issues: Array<{ type: string, message: string }> }}
|
|
615
|
+
*/
|
|
616
|
+
function checkEnvVarUsage(code, envConfig = []) {
|
|
617
|
+
const issues = [];
|
|
618
|
+
let usesEnvVars = false;
|
|
619
|
+
|
|
620
|
+
if (!code || typeof code !== 'string') {
|
|
621
|
+
return { usesEnvVars: false, issues };
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
// Check for process.env usage
|
|
625
|
+
const envVarUsage = code.match(/process\.env\.[A-Z_]+/g);
|
|
626
|
+
if (envVarUsage && envVarUsage.length > 0) {
|
|
627
|
+
usesEnvVars = true;
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
// Check for sensitive values that should use env vars
|
|
631
|
+
const sensitivePatterns = [
|
|
632
|
+
{ pattern: /password\s*[:=]\s*['"][^'"]+['"]/gi, name: 'password' },
|
|
633
|
+
{ pattern: /secret\s*[:=]\s*['"][^'"]+['"]/gi, name: 'secret' },
|
|
634
|
+
{ pattern: /apiKey\s*[:=]\s*['"][^'"]+['"]/gi, name: 'API key' },
|
|
635
|
+
{ pattern: /token\s*[:=]\s*['"][^'"]+['"]/gi, name: 'token' },
|
|
636
|
+
{ pattern: /privateKey\s*[:=]\s*['"][^'"]+['"]/gi, name: 'private key' },
|
|
637
|
+
];
|
|
638
|
+
|
|
639
|
+
for (const { pattern, name } of sensitivePatterns) {
|
|
640
|
+
const matches = code.match(pattern);
|
|
641
|
+
if (matches) {
|
|
642
|
+
for (const match of matches) {
|
|
643
|
+
if (!match.includes('process.env')) {
|
|
644
|
+
issues.push({
|
|
645
|
+
type: 'hardcoded-sensitive',
|
|
646
|
+
message: `Hardcoded ${name} detected. Use environment variable (e.g., process.env.${name.toUpperCase()}).`,
|
|
647
|
+
});
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
return { usesEnvVars, issues };
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
/**
|
|
657
|
+
* Analyze code file for security issues
|
|
658
|
+
* @param {Object} file - Code file object
|
|
659
|
+
* @param {Object} authConfig - Authentication configuration
|
|
660
|
+
* @returns {{ errors: Array, warnings: Array }}
|
|
661
|
+
*/
|
|
662
|
+
function analyzeSecurityFile(file, authConfig = {}) {
|
|
663
|
+
const errors = [];
|
|
664
|
+
const warnings = [];
|
|
665
|
+
|
|
666
|
+
if (!file || !file.content) {
|
|
667
|
+
return { errors, warnings };
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
const filePath = file.path || 'unknown';
|
|
671
|
+
const code = file.content;
|
|
672
|
+
|
|
673
|
+
// Check for eval() usage
|
|
674
|
+
const evalIssues = detectEvalUsage(code);
|
|
675
|
+
for (const issue of evalIssues) {
|
|
676
|
+
(issue.severity === 'error' ? errors : warnings).push({
|
|
677
|
+
path: filePath,
|
|
678
|
+
message: issue.message,
|
|
679
|
+
});
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
// Check for exec usage
|
|
683
|
+
const execIssues = detectExecUsage(code);
|
|
684
|
+
for (const issue of execIssues) {
|
|
685
|
+
(issue.severity === 'error' ? errors : warnings).push({
|
|
686
|
+
path: filePath,
|
|
687
|
+
message: issue.message,
|
|
688
|
+
});
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
// Check for SQL injection
|
|
692
|
+
const sqlIssues = detectSqlInjection(code);
|
|
693
|
+
for (const issue of sqlIssues) {
|
|
694
|
+
(issue.severity === 'error' ? errors : warnings).push({
|
|
695
|
+
path: filePath,
|
|
696
|
+
message: issue.message,
|
|
697
|
+
});
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
// Check for hardcoded secrets
|
|
701
|
+
const secretIssues = detectHardcodedSecrets(code);
|
|
702
|
+
for (const issue of secretIssues) {
|
|
703
|
+
(issue.severity === 'error' ? errors : warnings).push({
|
|
704
|
+
path: filePath,
|
|
705
|
+
message: issue.message,
|
|
706
|
+
});
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
// Check session security
|
|
710
|
+
const sessionResult = checkSessionSecurity(code, authConfig);
|
|
711
|
+
for (const issue of sessionResult.issues) {
|
|
712
|
+
errors.push({
|
|
713
|
+
path: filePath,
|
|
714
|
+
message: issue.message,
|
|
715
|
+
});
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
// Check input validation
|
|
719
|
+
const validationResult = checkInputValidation(code);
|
|
720
|
+
for (const issue of validationResult.issues) {
|
|
721
|
+
warnings.push({
|
|
722
|
+
path: filePath,
|
|
723
|
+
message: issue.message,
|
|
724
|
+
});
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
// Check environment variable usage
|
|
728
|
+
const envResult = checkEnvVarUsage(code);
|
|
729
|
+
for (const issue of envResult.issues) {
|
|
730
|
+
errors.push({
|
|
731
|
+
path: filePath,
|
|
732
|
+
message: issue.message,
|
|
733
|
+
});
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
return { errors, warnings };
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
/**
|
|
740
|
+
* Gate 4 Executor: Security Baseline Check
|
|
741
|
+
*
|
|
742
|
+
* @param {Object} context - Gate context (validated against gateContextSchema)
|
|
743
|
+
* @returns {Promise<{ passed: boolean, errors: Array<{path: string, message: string}>, warnings: string[] }>}
|
|
744
|
+
*/
|
|
745
|
+
async function executeGate4(context) {
|
|
746
|
+
const errors = [];
|
|
747
|
+
const warnings = [];
|
|
748
|
+
|
|
749
|
+
// Extract auth config
|
|
750
|
+
const authConfig = context.authConfig || {};
|
|
751
|
+
|
|
752
|
+
// Analyze each file
|
|
753
|
+
if (context.files && Array.isArray(context.files)) {
|
|
754
|
+
for (const file of context.files) {
|
|
755
|
+
const result = analyzeSecurityFile(file, authConfig);
|
|
756
|
+
errors.push(...result.errors);
|
|
757
|
+
warnings.push(...result.warnings.map(w =>
|
|
758
|
+
typeof w === 'string' ? w : `${w.path}: ${w.message}`
|
|
759
|
+
));
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
// Check for missing input validation at project level
|
|
764
|
+
if (context.hasInputValidation === false) {
|
|
765
|
+
errors.push({
|
|
766
|
+
path: 'input-validation',
|
|
767
|
+
message: 'No input validation detected. Implement input validation using a library (express-validator, joi, zod, etc.).',
|
|
768
|
+
});
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
// Check auth configuration
|
|
772
|
+
if (authConfig) {
|
|
773
|
+
// Check for weak hashing
|
|
774
|
+
if (authConfig.hashingAlgorithm && ['md5', 'sha1', 'sha256'].includes(authConfig.hashingAlgorithm.toLowerCase())) {
|
|
775
|
+
errors.push({
|
|
776
|
+
path: 'authConfig.hashingAlgorithm',
|
|
777
|
+
message: `Weak password hashing (${authConfig.hashingAlgorithm}). Use bcrypt, scrypt, or argon2.`,
|
|
778
|
+
});
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
// Check for missing HTTPS
|
|
782
|
+
if (authConfig.httpsEnforced === false) {
|
|
783
|
+
warnings.push('HTTPS is not enforced. Consider enforcing HTTPS in production.');
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
// Check for missing CSRF protection
|
|
787
|
+
if (authConfig.csrfProtection === false) {
|
|
788
|
+
warnings.push('CSRF protection is disabled. Consider enabling for state-changing operations.');
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
return {
|
|
793
|
+
passed: errors.length === 0,
|
|
794
|
+
errors,
|
|
795
|
+
warnings,
|
|
796
|
+
};
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
/**
|
|
800
|
+
* Create and register Gate 4 with a QualityGate instance
|
|
801
|
+
*
|
|
802
|
+
* @param {QualityGate} gateCoordinator - QualityGate coordinator instance
|
|
803
|
+
* @returns {void}
|
|
804
|
+
*/
|
|
805
|
+
function registerGate4(gateCoordinator) {
|
|
806
|
+
gateCoordinator.registerGate('gate-04-security', gateContextSchema, executeGate4);
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
module.exports = {
|
|
810
|
+
executeGate4,
|
|
811
|
+
registerGate4,
|
|
812
|
+
codeFileSchema,
|
|
813
|
+
envConfigSchema,
|
|
814
|
+
authConfigSchema,
|
|
815
|
+
gateContextSchema,
|
|
816
|
+
SECURITY_ANTI_PATTERNS,
|
|
817
|
+
SECRET_PATTERNS,
|
|
818
|
+
SQL_INJECTION_PATTERNS,
|
|
819
|
+
INPUT_VALIDATION_CHECKS,
|
|
820
|
+
SECURE_SESSION_PATTERNS,
|
|
821
|
+
detectEvalUsage,
|
|
822
|
+
detectExecUsage,
|
|
823
|
+
detectSqlInjection,
|
|
824
|
+
detectHardcodedSecrets,
|
|
825
|
+
checkSessionSecurity,
|
|
826
|
+
checkInputValidation,
|
|
827
|
+
checkEnvVarUsage,
|
|
828
|
+
analyzeSecurityFile,
|
|
829
|
+
};
|