@delegance/claude-autopilot 5.0.1 → 5.0.3
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/dist/src/adapters/review-engine/codex.js +13 -1
- package/dist/src/cli/index.js +39 -1
- package/dist/src/cli/preflight.js +17 -4
- package/dist/src/cli/scan.js +12 -0
- package/package.json +4 -3
- package/dist/presets/go/rules/go-sql-injection.d.ts.map +0 -1
- package/dist/presets/go/rules/go-sql-injection.js.map +0 -1
- package/dist/presets/nextjs-supabase/rules/supabase-rls-bypass.d.ts.map +0 -1
- package/dist/presets/nextjs-supabase/rules/supabase-rls-bypass.js.map +0 -1
- package/dist/presets/python-fastapi/rules/fastapi-missing-auth.d.ts.map +0 -1
- package/dist/presets/python-fastapi/rules/fastapi-missing-auth.js.map +0 -1
- package/dist/presets/rails-postgres/rules/rails-sql-injection.d.ts.map +0 -1
- package/dist/presets/rails-postgres/rules/rails-sql-injection.js.map +0 -1
- package/dist/presets/t3/rules/t3-server-only.d.ts.map +0 -1
- package/dist/presets/t3/rules/t3-server-only.js.map +0 -1
- package/dist/src/adapters/base.d.ts.map +0 -1
- package/dist/src/adapters/base.js.map +0 -1
- package/dist/src/adapters/council/claude.d.ts.map +0 -1
- package/dist/src/adapters/council/claude.js.map +0 -1
- package/dist/src/adapters/council/openai.d.ts.map +0 -1
- package/dist/src/adapters/council/openai.js.map +0 -1
- package/dist/src/adapters/council/types.d.ts.map +0 -1
- package/dist/src/adapters/council/types.js.map +0 -1
- package/dist/src/adapters/loader.d.ts.map +0 -1
- package/dist/src/adapters/loader.js.map +0 -1
- package/dist/src/adapters/migration-runner/supabase.d.ts.map +0 -1
- package/dist/src/adapters/migration-runner/supabase.js.map +0 -1
- package/dist/src/adapters/migration-runner/types.d.ts.map +0 -1
- package/dist/src/adapters/migration-runner/types.js.map +0 -1
- package/dist/src/adapters/review-bot-parser/cursor.d.ts.map +0 -1
- package/dist/src/adapters/review-bot-parser/cursor.js.map +0 -1
- package/dist/src/adapters/review-bot-parser/declarative-base.d.ts.map +0 -1
- package/dist/src/adapters/review-bot-parser/declarative-base.js.map +0 -1
- package/dist/src/adapters/review-bot-parser/types.d.ts.map +0 -1
- package/dist/src/adapters/review-bot-parser/types.js.map +0 -1
- package/dist/src/adapters/review-engine/auto.d.ts.map +0 -1
- package/dist/src/adapters/review-engine/auto.js.map +0 -1
- package/dist/src/adapters/review-engine/claude.d.ts.map +0 -1
- package/dist/src/adapters/review-engine/claude.js.map +0 -1
- package/dist/src/adapters/review-engine/codex.d.ts.map +0 -1
- package/dist/src/adapters/review-engine/codex.js.map +0 -1
- package/dist/src/adapters/review-engine/gemini.d.ts.map +0 -1
- package/dist/src/adapters/review-engine/gemini.js.map +0 -1
- package/dist/src/adapters/review-engine/openai-compatible.d.ts.map +0 -1
- package/dist/src/adapters/review-engine/openai-compatible.js.map +0 -1
- package/dist/src/adapters/review-engine/parse-output.d.ts.map +0 -1
- package/dist/src/adapters/review-engine/parse-output.js.map +0 -1
- package/dist/src/adapters/review-engine/prompt-builder.d.ts.map +0 -1
- package/dist/src/adapters/review-engine/prompt-builder.js.map +0 -1
- package/dist/src/adapters/review-engine/types.d.ts.map +0 -1
- package/dist/src/adapters/review-engine/types.js.map +0 -1
- package/dist/src/adapters/vcs-host/commit-status.d.ts.map +0 -1
- package/dist/src/adapters/vcs-host/commit-status.js.map +0 -1
- package/dist/src/adapters/vcs-host/github.d.ts.map +0 -1
- package/dist/src/adapters/vcs-host/github.js.map +0 -1
- package/dist/src/adapters/vcs-host/types.d.ts.map +0 -1
- package/dist/src/adapters/vcs-host/types.js.map +0 -1
- package/dist/src/cli/_pkg-root.d.ts.map +0 -1
- package/dist/src/cli/_pkg-root.js.map +0 -1
- package/dist/src/cli/autoregress-bridge.d.ts.map +0 -1
- package/dist/src/cli/autoregress-bridge.js.map +0 -1
- package/dist/src/cli/baseline.d.ts.map +0 -1
- package/dist/src/cli/baseline.js.map +0 -1
- package/dist/src/cli/ci.d.ts.map +0 -1
- package/dist/src/cli/ci.js.map +0 -1
- package/dist/src/cli/costs.d.ts.map +0 -1
- package/dist/src/cli/costs.js.map +0 -1
- package/dist/src/cli/council.d.ts.map +0 -1
- package/dist/src/cli/council.js.map +0 -1
- package/dist/src/cli/detector.d.ts.map +0 -1
- package/dist/src/cli/detector.js.map +0 -1
- package/dist/src/cli/explain.d.ts.map +0 -1
- package/dist/src/cli/explain.js.map +0 -1
- package/dist/src/cli/fix.d.ts.map +0 -1
- package/dist/src/cli/fix.js.map +0 -1
- package/dist/src/cli/hook.d.ts.map +0 -1
- package/dist/src/cli/hook.js.map +0 -1
- package/dist/src/cli/ignore-helper.d.ts.map +0 -1
- package/dist/src/cli/ignore-helper.js.map +0 -1
- package/dist/src/cli/index.d.ts.map +0 -1
- package/dist/src/cli/index.js.map +0 -1
- package/dist/src/cli/lsp.d.ts.map +0 -1
- package/dist/src/cli/lsp.js.map +0 -1
- package/dist/src/cli/mcp.d.ts.map +0 -1
- package/dist/src/cli/mcp.js.map +0 -1
- package/dist/src/cli/migrate-v4.d.ts.map +0 -1
- package/dist/src/cli/migrate-v4.js.map +0 -1
- package/dist/src/cli/pr-comment.d.ts.map +0 -1
- package/dist/src/cli/pr-comment.js.map +0 -1
- package/dist/src/cli/pr-desc.d.ts.map +0 -1
- package/dist/src/cli/pr-desc.js.map +0 -1
- package/dist/src/cli/pr-review-comments.d.ts.map +0 -1
- package/dist/src/cli/pr-review-comments.js.map +0 -1
- package/dist/src/cli/pr.d.ts.map +0 -1
- package/dist/src/cli/pr.js.map +0 -1
- package/dist/src/cli/preflight.d.ts.map +0 -1
- package/dist/src/cli/preflight.js.map +0 -1
- package/dist/src/cli/report.d.ts.map +0 -1
- package/dist/src/cli/report.js.map +0 -1
- package/dist/src/cli/run.d.ts.map +0 -1
- package/dist/src/cli/run.js.map +0 -1
- package/dist/src/cli/scan.d.ts.map +0 -1
- package/dist/src/cli/scan.js.map +0 -1
- package/dist/src/cli/setup.d.ts.map +0 -1
- package/dist/src/cli/setup.js.map +0 -1
- package/dist/src/cli/test-gen.d.ts.map +0 -1
- package/dist/src/cli/test-gen.js.map +0 -1
- package/dist/src/cli/triage.d.ts.map +0 -1
- package/dist/src/cli/triage.js.map +0 -1
- package/dist/src/cli/watch.d.ts.map +0 -1
- package/dist/src/cli/watch.js.map +0 -1
- package/dist/src/cli/worker.d.ts.map +0 -1
- package/dist/src/cli/worker.js.map +0 -1
- package/dist/src/core/cache/cached-engine.d.ts.map +0 -1
- package/dist/src/core/cache/cached-engine.js.map +0 -1
- package/dist/src/core/cache/review-cache.d.ts.map +0 -1
- package/dist/src/core/cache/review-cache.js.map +0 -1
- package/dist/src/core/chunking/index.d.ts.map +0 -1
- package/dist/src/core/chunking/index.js.map +0 -1
- package/dist/src/core/chunking/risk-ranker.d.ts.map +0 -1
- package/dist/src/core/chunking/risk-ranker.js.map +0 -1
- package/dist/src/core/config/loader.d.ts.map +0 -1
- package/dist/src/core/config/loader.js.map +0 -1
- package/dist/src/core/config/preset-resolver.d.ts.map +0 -1
- package/dist/src/core/config/preset-resolver.js.map +0 -1
- package/dist/src/core/config/schema.d.ts.map +0 -1
- package/dist/src/core/config/schema.js.map +0 -1
- package/dist/src/core/config/types.d.ts.map +0 -1
- package/dist/src/core/config/types.js.map +0 -1
- package/dist/src/core/council/config.d.ts.map +0 -1
- package/dist/src/core/council/config.js.map +0 -1
- package/dist/src/core/council/context.d.ts.map +0 -1
- package/dist/src/core/council/context.js.map +0 -1
- package/dist/src/core/council/runner.d.ts.map +0 -1
- package/dist/src/core/council/runner.js.map +0 -1
- package/dist/src/core/council/types.d.ts.map +0 -1
- package/dist/src/core/council/types.js.map +0 -1
- package/dist/src/core/detect/git-context.d.ts.map +0 -1
- package/dist/src/core/detect/git-context.js.map +0 -1
- package/dist/src/core/detect/llm-key.d.ts.map +0 -1
- package/dist/src/core/detect/llm-key.js.map +0 -1
- package/dist/src/core/detect/protected-paths.d.ts.map +0 -1
- package/dist/src/core/detect/protected-paths.js.map +0 -1
- package/dist/src/core/detect/provider-usage.d.ts.map +0 -1
- package/dist/src/core/detect/provider-usage.js.map +0 -1
- package/dist/src/core/detect/stack.d.ts.map +0 -1
- package/dist/src/core/detect/stack.js.map +0 -1
- package/dist/src/core/detect/workspaces.d.ts.map +0 -1
- package/dist/src/core/detect/workspaces.js.map +0 -1
- package/dist/src/core/errors.d.ts.map +0 -1
- package/dist/src/core/errors.js.map +0 -1
- package/dist/src/core/findings/dedup.d.ts.map +0 -1
- package/dist/src/core/findings/dedup.js.map +0 -1
- package/dist/src/core/findings/types.d.ts.map +0 -1
- package/dist/src/core/findings/types.js.map +0 -1
- package/dist/src/core/fix/generator.d.ts.map +0 -1
- package/dist/src/core/fix/generator.js.map +0 -1
- package/dist/src/core/git/diff-hunks.d.ts.map +0 -1
- package/dist/src/core/git/diff-hunks.js.map +0 -1
- package/dist/src/core/git/touched-files.d.ts.map +0 -1
- package/dist/src/core/git/touched-files.js.map +0 -1
- package/dist/src/core/ignore/index.d.ts.map +0 -1
- package/dist/src/core/ignore/index.js.map +0 -1
- package/dist/src/core/index.d.ts.map +0 -1
- package/dist/src/core/index.js.map +0 -1
- package/dist/src/core/logging/ndjson-writer.d.ts.map +0 -1
- package/dist/src/core/logging/ndjson-writer.js.map +0 -1
- package/dist/src/core/logging/redaction.d.ts.map +0 -1
- package/dist/src/core/logging/redaction.js.map +0 -1
- package/dist/src/core/mcp/concurrency.d.ts.map +0 -1
- package/dist/src/core/mcp/concurrency.js.map +0 -1
- package/dist/src/core/mcp/handlers/fix-finding.d.ts.map +0 -1
- package/dist/src/core/mcp/handlers/fix-finding.js.map +0 -1
- package/dist/src/core/mcp/handlers/get-capabilities.d.ts.map +0 -1
- package/dist/src/core/mcp/handlers/get-capabilities.js.map +0 -1
- package/dist/src/core/mcp/handlers/get-findings.d.ts.map +0 -1
- package/dist/src/core/mcp/handlers/get-findings.js.map +0 -1
- package/dist/src/core/mcp/handlers/review-diff.d.ts.map +0 -1
- package/dist/src/core/mcp/handlers/review-diff.js.map +0 -1
- package/dist/src/core/mcp/handlers/scan-files.d.ts.map +0 -1
- package/dist/src/core/mcp/handlers/scan-files.js.map +0 -1
- package/dist/src/core/mcp/handlers/validate-fix.d.ts.map +0 -1
- package/dist/src/core/mcp/handlers/validate-fix.js.map +0 -1
- package/dist/src/core/mcp/run-store.d.ts.map +0 -1
- package/dist/src/core/mcp/run-store.js.map +0 -1
- package/dist/src/core/mcp/workspace.d.ts.map +0 -1
- package/dist/src/core/mcp/workspace.js.map +0 -1
- package/dist/src/core/persist/baseline.d.ts.map +0 -1
- package/dist/src/core/persist/baseline.js.map +0 -1
- package/dist/src/core/persist/cost-log.d.ts.map +0 -1
- package/dist/src/core/persist/cost-log.js.map +0 -1
- package/dist/src/core/persist/findings-cache.d.ts.map +0 -1
- package/dist/src/core/persist/findings-cache.js.map +0 -1
- package/dist/src/core/persist/triage.d.ts.map +0 -1
- package/dist/src/core/persist/triage.js.map +0 -1
- package/dist/src/core/phases/static-rules.d.ts.map +0 -1
- package/dist/src/core/phases/static-rules.js.map +0 -1
- package/dist/src/core/phases/tests.d.ts.map +0 -1
- package/dist/src/core/phases/tests.js.map +0 -1
- package/dist/src/core/pipeline/review-phase.d.ts.map +0 -1
- package/dist/src/core/pipeline/review-phase.js.map +0 -1
- package/dist/src/core/pipeline/run.d.ts.map +0 -1
- package/dist/src/core/pipeline/run.js.map +0 -1
- package/dist/src/core/runtime/idempotency.d.ts.map +0 -1
- package/dist/src/core/runtime/idempotency.js.map +0 -1
- package/dist/src/core/runtime/lock.d.ts.map +0 -1
- package/dist/src/core/runtime/lock.js.map +0 -1
- package/dist/src/core/runtime/state.d.ts.map +0 -1
- package/dist/src/core/runtime/state.js.map +0 -1
- package/dist/src/core/schema-alignment/detector.d.ts.map +0 -1
- package/dist/src/core/schema-alignment/detector.js.map +0 -1
- package/dist/src/core/schema-alignment/extractor/index.d.ts.map +0 -1
- package/dist/src/core/schema-alignment/extractor/index.js.map +0 -1
- package/dist/src/core/schema-alignment/extractor/prisma.d.ts.map +0 -1
- package/dist/src/core/schema-alignment/extractor/prisma.js.map +0 -1
- package/dist/src/core/schema-alignment/extractor/sql.d.ts.map +0 -1
- package/dist/src/core/schema-alignment/extractor/sql.js.map +0 -1
- package/dist/src/core/schema-alignment/llm-check.d.ts.map +0 -1
- package/dist/src/core/schema-alignment/llm-check.js.map +0 -1
- package/dist/src/core/schema-alignment/scanner.d.ts.map +0 -1
- package/dist/src/core/schema-alignment/scanner.js.map +0 -1
- package/dist/src/core/schema-alignment/types.d.ts.map +0 -1
- package/dist/src/core/schema-alignment/types.js.map +0 -1
- package/dist/src/core/shell.d.ts.map +0 -1
- package/dist/src/core/shell.js.map +0 -1
- package/dist/src/core/static-rules/registry.d.ts.map +0 -1
- package/dist/src/core/static-rules/registry.js.map +0 -1
- package/dist/src/core/static-rules/rules/brand-tokens.d.ts.map +0 -1
- package/dist/src/core/static-rules/rules/brand-tokens.js.map +0 -1
- package/dist/src/core/static-rules/rules/console-log.d.ts.map +0 -1
- package/dist/src/core/static-rules/rules/console-log.js.map +0 -1
- package/dist/src/core/static-rules/rules/hardcoded-secrets.d.ts.map +0 -1
- package/dist/src/core/static-rules/rules/hardcoded-secrets.js.map +0 -1
- package/dist/src/core/static-rules/rules/insecure-redirect.d.ts.map +0 -1
- package/dist/src/core/static-rules/rules/insecure-redirect.js.map +0 -1
- package/dist/src/core/static-rules/rules/large-file.d.ts.map +0 -1
- package/dist/src/core/static-rules/rules/large-file.js.map +0 -1
- package/dist/src/core/static-rules/rules/missing-auth.d.ts.map +0 -1
- package/dist/src/core/static-rules/rules/missing-auth.js.map +0 -1
- package/dist/src/core/static-rules/rules/missing-tests.d.ts.map +0 -1
- package/dist/src/core/static-rules/rules/missing-tests.js.map +0 -1
- package/dist/src/core/static-rules/rules/npm-audit.d.ts.map +0 -1
- package/dist/src/core/static-rules/rules/npm-audit.js.map +0 -1
- package/dist/src/core/static-rules/rules/package-lock-sync.d.ts.map +0 -1
- package/dist/src/core/static-rules/rules/package-lock-sync.js.map +0 -1
- package/dist/src/core/static-rules/rules/schema-alignment.d.ts.map +0 -1
- package/dist/src/core/static-rules/rules/schema-alignment.js.map +0 -1
- package/dist/src/core/static-rules/rules/sql-injection.d.ts.map +0 -1
- package/dist/src/core/static-rules/rules/sql-injection.js.map +0 -1
- package/dist/src/core/static-rules/rules/ssrf.d.ts.map +0 -1
- package/dist/src/core/static-rules/rules/ssrf.js.map +0 -1
- package/dist/src/core/static-rules/rules/todo-fixme.d.ts.map +0 -1
- package/dist/src/core/static-rules/rules/todo-fixme.js.map +0 -1
- package/dist/src/core/static-rules/tailwind-extractor.d.ts.map +0 -1
- package/dist/src/core/static-rules/tailwind-extractor.js.map +0 -1
- package/dist/src/core/test-gen/coverage-analyzer.d.ts.map +0 -1
- package/dist/src/core/test-gen/coverage-analyzer.js.map +0 -1
- package/dist/src/core/test-gen/framework-detector.d.ts.map +0 -1
- package/dist/src/core/test-gen/framework-detector.js.map +0 -1
- package/dist/src/core/test-gen/test-writer.d.ts.map +0 -1
- package/dist/src/core/test-gen/test-writer.js.map +0 -1
- package/dist/src/core/ui/design-context-loader.d.ts.map +0 -1
- package/dist/src/core/ui/design-context-loader.js.map +0 -1
- package/dist/src/core/worker/client.d.ts.map +0 -1
- package/dist/src/core/worker/client.js.map +0 -1
- package/dist/src/core/worker/lockfile.d.ts.map +0 -1
- package/dist/src/core/worker/lockfile.js.map +0 -1
- package/dist/src/core/worker/server.d.ts.map +0 -1
- package/dist/src/core/worker/server.js.map +0 -1
- package/dist/src/formatters/github-annotations.d.ts.map +0 -1
- package/dist/src/formatters/github-annotations.js.map +0 -1
- package/dist/src/formatters/index.d.ts.map +0 -1
- package/dist/src/formatters/index.js.map +0 -1
- package/dist/src/formatters/junit.d.ts.map +0 -1
- package/dist/src/formatters/junit.js.map +0 -1
- package/dist/src/formatters/sarif.d.ts.map +0 -1
- package/dist/src/formatters/sarif.js.map +0 -1
- package/dist/src/index.d.ts.map +0 -1
- package/dist/src/index.js.map +0 -1
- package/src/adapters/base.ts +0 -19
- package/src/adapters/council/claude.ts +0 -41
- package/src/adapters/council/openai.ts +0 -40
- package/src/adapters/council/types.ts +0 -7
- package/src/adapters/loader.ts +0 -108
- package/src/adapters/migration-runner/supabase.ts +0 -56
- package/src/adapters/migration-runner/types.ts +0 -36
- package/src/adapters/review-bot-parser/cursor.ts +0 -13
- package/src/adapters/review-bot-parser/declarative-base.ts +0 -64
- package/src/adapters/review-bot-parser/types.ts +0 -9
- package/src/adapters/review-engine/auto.ts +0 -94
- package/src/adapters/review-engine/claude.ts +0 -100
- package/src/adapters/review-engine/codex.ts +0 -82
- package/src/adapters/review-engine/gemini.ts +0 -105
- package/src/adapters/review-engine/openai-compatible.ts +0 -100
- package/src/adapters/review-engine/parse-output.ts +0 -74
- package/src/adapters/review-engine/prompt-builder.ts +0 -19
- package/src/adapters/review-engine/types.ts +0 -19
- package/src/adapters/vcs-host/commit-status.ts +0 -39
- package/src/adapters/vcs-host/github.ts +0 -77
- package/src/adapters/vcs-host/types.ts +0 -44
- package/src/cli/_pkg-root.ts +0 -85
- package/src/cli/autoregress-bridge.ts +0 -30
- package/src/cli/baseline.ts +0 -125
- package/src/cli/ci.ts +0 -45
- package/src/cli/costs.ts +0 -80
- package/src/cli/council.ts +0 -96
- package/src/cli/detector.ts +0 -92
- package/src/cli/explain.ts +0 -197
- package/src/cli/fix.ts +0 -249
- package/src/cli/hook.ts +0 -124
- package/src/cli/ignore-helper.ts +0 -116
- package/src/cli/index.ts +0 -612
- package/src/cli/lsp.ts +0 -200
- package/src/cli/mcp.ts +0 -206
- package/src/cli/migrate-v4.ts +0 -388
- package/src/cli/pr-comment.ts +0 -139
- package/src/cli/pr-desc.ts +0 -168
- package/src/cli/pr-review-comments.ts +0 -92
- package/src/cli/pr.ts +0 -76
- package/src/cli/preflight.ts +0 -235
- package/src/cli/report.ts +0 -186
- package/src/cli/run.ts +0 -425
- package/src/cli/scan.ts +0 -233
- package/src/cli/setup.ts +0 -191
- package/src/cli/test-gen.ts +0 -125
- package/src/cli/triage.ts +0 -137
- package/src/cli/watch.ts +0 -190
- package/src/cli/worker.ts +0 -109
- package/src/core/.gitkeep +0 -0
- package/src/core/cache/cached-engine.ts +0 -32
- package/src/core/cache/review-cache.ts +0 -70
- package/src/core/chunking/index.ts +0 -113
- package/src/core/chunking/risk-ranker.ts +0 -56
- package/src/core/config/loader.ts +0 -53
- package/src/core/config/preset-resolver.ts +0 -46
- package/src/core/config/schema.ts +0 -181
- package/src/core/config/types.ts +0 -98
- package/src/core/council/config.ts +0 -71
- package/src/core/council/context.ts +0 -17
- package/src/core/council/runner.ts +0 -83
- package/src/core/council/types.ts +0 -45
- package/src/core/detect/git-context.ts +0 -27
- package/src/core/detect/llm-key.ts +0 -89
- package/src/core/detect/protected-paths.ts +0 -63
- package/src/core/detect/provider-usage.ts +0 -74
- package/src/core/detect/stack.ts +0 -153
- package/src/core/detect/workspaces.ts +0 -103
- package/src/core/errors.ts +0 -37
- package/src/core/findings/dedup.ts +0 -14
- package/src/core/findings/types.ts +0 -39
- package/src/core/fix/generator.ts +0 -149
- package/src/core/git/diff-hunks.ts +0 -86
- package/src/core/git/touched-files.ts +0 -73
- package/src/core/ignore/index.ts +0 -54
- package/src/core/index.ts +0 -1
- package/src/core/logging/ndjson-writer.ts +0 -37
- package/src/core/logging/redaction.ts +0 -19
- package/src/core/mcp/concurrency.ts +0 -16
- package/src/core/mcp/handlers/fix-finding.ts +0 -126
- package/src/core/mcp/handlers/get-capabilities.ts +0 -62
- package/src/core/mcp/handlers/get-findings.ts +0 -36
- package/src/core/mcp/handlers/review-diff.ts +0 -65
- package/src/core/mcp/handlers/scan-files.ts +0 -65
- package/src/core/mcp/handlers/validate-fix.ts +0 -41
- package/src/core/mcp/run-store.ts +0 -85
- package/src/core/mcp/workspace.ts +0 -35
- package/src/core/persist/baseline.ts +0 -112
- package/src/core/persist/cost-log.ts +0 -30
- package/src/core/persist/findings-cache.ts +0 -43
- package/src/core/persist/triage.ts +0 -112
- package/src/core/phases/static-rules.ts +0 -93
- package/src/core/phases/tests.ts +0 -51
- package/src/core/pipeline/review-phase.ts +0 -182
- package/src/core/pipeline/run.ts +0 -116
- package/src/core/runtime/idempotency.ts +0 -6
- package/src/core/runtime/lock.ts +0 -29
- package/src/core/runtime/state.ts +0 -97
- package/src/core/schema-alignment/detector.ts +0 -59
- package/src/core/schema-alignment/extractor/index.ts +0 -24
- package/src/core/schema-alignment/extractor/prisma.ts +0 -21
- package/src/core/schema-alignment/extractor/sql.ts +0 -99
- package/src/core/schema-alignment/llm-check.ts +0 -91
- package/src/core/schema-alignment/scanner.ts +0 -107
- package/src/core/schema-alignment/types.ts +0 -43
- package/src/core/shell.ts +0 -48
- package/src/core/static-rules/registry.ts +0 -59
- package/src/core/static-rules/rules/brand-tokens.ts +0 -145
- package/src/core/static-rules/rules/console-log.ts +0 -42
- package/src/core/static-rules/rules/hardcoded-secrets.ts +0 -83
- package/src/core/static-rules/rules/insecure-redirect.ts +0 -67
- package/src/core/static-rules/rules/large-file.ts +0 -37
- package/src/core/static-rules/rules/missing-auth.ts +0 -70
- package/src/core/static-rules/rules/missing-tests.ts +0 -57
- package/src/core/static-rules/rules/npm-audit.ts +0 -38
- package/src/core/static-rules/rules/package-lock-sync.ts +0 -54
- package/src/core/static-rules/rules/schema-alignment.ts +0 -132
- package/src/core/static-rules/rules/sql-injection.ts +0 -71
- package/src/core/static-rules/rules/ssrf.ts +0 -63
- package/src/core/static-rules/rules/todo-fixme.ts +0 -40
- package/src/core/static-rules/tailwind-extractor.ts +0 -38
- package/src/core/test-gen/coverage-analyzer.ts +0 -93
- package/src/core/test-gen/framework-detector.ts +0 -21
- package/src/core/test-gen/test-writer.ts +0 -33
- package/src/core/ui/design-context-loader.ts +0 -87
- package/src/core/worker/client.ts +0 -46
- package/src/core/worker/lockfile.ts +0 -38
- package/src/core/worker/server.ts +0 -81
- package/src/formatters/github-annotations.ts +0 -36
- package/src/formatters/index.ts +0 -3
- package/src/formatters/junit.ts +0 -52
- package/src/formatters/sarif.ts +0 -103
- package/src/index.ts +0 -3
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
// src/core/schema-alignment/types.ts
|
|
2
|
-
|
|
3
|
-
export interface SchemaEntity {
|
|
4
|
-
table: string;
|
|
5
|
-
column?: string;
|
|
6
|
-
operation: 'create_table' | 'add_column' | 'drop_column' | 'rename_column' | 'create_type';
|
|
7
|
-
oldName?: string; // rename_column only: the previous column name
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export interface Evidence {
|
|
11
|
-
file: string;
|
|
12
|
-
line: number;
|
|
13
|
-
snippet: string;
|
|
14
|
-
confidence: 'high' | 'medium' | 'low';
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export interface LayerScanResult {
|
|
18
|
-
entity: SchemaEntity;
|
|
19
|
-
typeLayer: Evidence | null;
|
|
20
|
-
apiLayer: Evidence | null;
|
|
21
|
-
uiLayer: Evidence | null;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export interface AlignmentFinding {
|
|
25
|
-
entity: SchemaEntity;
|
|
26
|
-
layer: 'type' | 'api' | 'ui';
|
|
27
|
-
message: string;
|
|
28
|
-
file?: string;
|
|
29
|
-
severity: 'warning' | 'error';
|
|
30
|
-
confidence: 'high' | 'medium' | 'low';
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export interface SchemaAlignmentConfig {
|
|
34
|
-
enabled?: boolean;
|
|
35
|
-
migrationGlobs?: string[];
|
|
36
|
-
layerRoots?: {
|
|
37
|
-
types?: string[];
|
|
38
|
-
api?: string[];
|
|
39
|
-
ui?: string[];
|
|
40
|
-
};
|
|
41
|
-
llmCheck?: boolean;
|
|
42
|
-
severity?: 'warning' | 'error';
|
|
43
|
-
}
|
package/src/core/shell.ts
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
// src/core/shell.ts
|
|
2
|
-
|
|
3
|
-
import { execFileSync } from 'node:child_process';
|
|
4
|
-
import { GuardrailError, type ErrorCode } from './errors.ts';
|
|
5
|
-
|
|
6
|
-
export interface RunOptions {
|
|
7
|
-
timeout?: number;
|
|
8
|
-
input?: string;
|
|
9
|
-
cwd?: string;
|
|
10
|
-
env?: NodeJS.ProcessEnv;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
/** Run a command; return stdout on success, null on any failure. Never throws. */
|
|
14
|
-
export function runSafe(cmd: string, args: string[], options: RunOptions = {}): string | null {
|
|
15
|
-
try {
|
|
16
|
-
const result = execFileSync(cmd, args, {
|
|
17
|
-
encoding: 'utf8',
|
|
18
|
-
stdio: options.input ? ['pipe', 'pipe', 'pipe'] : ['ignore', 'pipe', 'pipe'],
|
|
19
|
-
timeout: options.timeout ?? 60000,
|
|
20
|
-
input: options.input,
|
|
21
|
-
cwd: options.cwd,
|
|
22
|
-
env: options.env,
|
|
23
|
-
});
|
|
24
|
-
return result.toString();
|
|
25
|
-
} catch {
|
|
26
|
-
return null;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/** Run a command; throw GuardrailError on failure. */
|
|
31
|
-
export function runThrowing(cmd: string, args: string[], options: RunOptions & { errorCode?: ErrorCode; provider?: string } = {}): string {
|
|
32
|
-
try {
|
|
33
|
-
return execFileSync(cmd, args, {
|
|
34
|
-
encoding: 'utf8',
|
|
35
|
-
stdio: options.input ? ['pipe', 'pipe', 'pipe'] : ['ignore', 'pipe', 'pipe'],
|
|
36
|
-
timeout: options.timeout ?? 60000,
|
|
37
|
-
input: options.input,
|
|
38
|
-
cwd: options.cwd,
|
|
39
|
-
env: options.env,
|
|
40
|
-
}).toString();
|
|
41
|
-
} catch (err) {
|
|
42
|
-
throw new GuardrailError(`Command failed: ${cmd} ${args.join(' ')}`, {
|
|
43
|
-
code: options.errorCode ?? 'transient_network',
|
|
44
|
-
provider: options.provider,
|
|
45
|
-
details: { cmd, args, cause: err instanceof Error ? err.message : String(err) },
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
}
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import type { StaticRule } from '../phases/static-rules.ts';
|
|
2
|
-
import type { StaticRuleReference } from '../config/types.ts';
|
|
3
|
-
import { resolveSiblingModule } from '../../cli/_pkg-root.ts';
|
|
4
|
-
|
|
5
|
-
// Dynamic-import string literals that end in `.ts` are NOT rewritten by tsc's
|
|
6
|
-
// `rewriteRelativeImportExtensions`. resolveSiblingModule swaps `.ts` → `.js`
|
|
7
|
-
// when the caller is itself compiled, so these imports resolve correctly under
|
|
8
|
-
// both source (`tsx`) and compiled (`node dist/...`) layouts.
|
|
9
|
-
const importRule = <T>(ref: string, exportName: string): Promise<StaticRule> =>
|
|
10
|
-
import(resolveSiblingModule(ref, import.meta.url)).then((m: Record<string, T>) => m[exportName] as unknown as StaticRule);
|
|
11
|
-
|
|
12
|
-
// Built-in cross-stack rules
|
|
13
|
-
const BUILTIN: Record<string, () => Promise<StaticRule>> = {
|
|
14
|
-
'hardcoded-secrets': () => importRule('./rules/hardcoded-secrets.ts', 'hardcodedSecretsRule'),
|
|
15
|
-
'npm-audit': () => importRule('./rules/npm-audit.ts', 'npmAuditRule'),
|
|
16
|
-
'package-lock-sync': () => importRule('./rules/package-lock-sync.ts', 'packageLockSyncRule'),
|
|
17
|
-
'console-log': () => importRule('./rules/console-log.ts', 'consoleLogRule'),
|
|
18
|
-
'todo-fixme': () => importRule('./rules/todo-fixme.ts', 'todoFixmeRule'),
|
|
19
|
-
'large-file': () => importRule('./rules/large-file.ts', 'largeFileRule'),
|
|
20
|
-
'missing-tests': () => importRule('./rules/missing-tests.ts', 'missingTestsRule'),
|
|
21
|
-
// Security rules
|
|
22
|
-
'sql-injection': () => importRule('./rules/sql-injection.ts', 'sqlInjectionRule'),
|
|
23
|
-
'missing-auth': () => importRule('./rules/missing-auth.ts', 'missingAuthRule'),
|
|
24
|
-
'ssrf': () => importRule('./rules/ssrf.ts', 'ssrfRule'),
|
|
25
|
-
'insecure-redirect': () => importRule('./rules/insecure-redirect.ts', 'insecureRedirectRule'),
|
|
26
|
-
// Brand rules
|
|
27
|
-
'brand-tokens': () => importRule('./rules/brand-tokens.ts', 'brandTokensRule'),
|
|
28
|
-
// Schema alignment
|
|
29
|
-
'schema-alignment': () => importRule('./rules/schema-alignment.ts', 'schemaAlignmentRule'),
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
// Preset-specific rules registered by name
|
|
33
|
-
const PRESET: Record<string, () => Promise<StaticRule>> = {
|
|
34
|
-
'supabase-rls-bypass': () => importRule('../../../presets/nextjs-supabase/rules/supabase-rls-bypass.ts', 'supabaseRlsBypassRule'),
|
|
35
|
-
'go-sql-injection': () => importRule('../../../presets/go/rules/go-sql-injection.ts', 'goSqlInjectionRule'),
|
|
36
|
-
'fastapi-missing-auth': () => importRule('../../../presets/python-fastapi/rules/fastapi-missing-auth.ts', 'fastapiMissingAuthRule'),
|
|
37
|
-
't3-server-only': () => importRule('../../../presets/t3/rules/t3-server-only.ts', 't3ServerOnlyRule'),
|
|
38
|
-
'rails-sql-injection': () => importRule('../../../presets/rails-postgres/rules/rails-sql-injection.ts', 'railsSqlInjectionRule'),
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
const ALL = { ...BUILTIN, ...PRESET };
|
|
42
|
-
|
|
43
|
-
export async function loadRulesFromConfig(refs: StaticRuleReference[]): Promise<StaticRule[]> {
|
|
44
|
-
const rules: StaticRule[] = [];
|
|
45
|
-
for (const ref of refs) {
|
|
46
|
-
const name = typeof ref === 'string' ? ref : ref.adapter;
|
|
47
|
-
const loader = ALL[name];
|
|
48
|
-
if (loader) {
|
|
49
|
-
rules.push(await loader());
|
|
50
|
-
} else {
|
|
51
|
-
process.stderr.write(`[guardrail] Unknown static rule: "${name}" — skipping\n`);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
return rules;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export function listAvailableRules(): string[] {
|
|
58
|
-
return Object.keys(ALL);
|
|
59
|
-
}
|
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
import * as fs from 'node:fs';
|
|
2
|
-
import * as path from 'node:path';
|
|
3
|
-
import type { StaticRule } from '../../phases/static-rules.ts';
|
|
4
|
-
import type { Finding } from '../../findings/types.ts';
|
|
5
|
-
import { extractTailwindColors } from '../tailwind-extractor.ts';
|
|
6
|
-
|
|
7
|
-
const UI_EXTS = new Set(['.tsx', '.jsx', '.ts', '.js', '.css', '.scss', '.sass', '.less', '.html', '.vue', '.svelte']);
|
|
8
|
-
const HEX_RE = /#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})\b/g;
|
|
9
|
-
const TAILWIND_ARBITRARY_HEX = /(?:bg|text|border|ring|fill|stroke|from|to|via)-\[#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})\]/g;
|
|
10
|
-
// Matches the hex portion inside a Tailwind arbitrary color bracket so we can strip it before plain HEX_RE scan
|
|
11
|
-
const TAILWIND_ARBITRARY_HEX_STRIP = /(?:bg|text|border|ring|fill|stroke|from|to|via)-\[#[0-9a-fA-F]{3,6}\]/g;
|
|
12
|
-
const FONT_FAMILY_RE = /font-family\s*:\s*([^;}\n]+)/g;
|
|
13
|
-
const CSS_EXTS = new Set(['.css', '.scss', '.sass', '.less']);
|
|
14
|
-
|
|
15
|
-
function normalizeHex(hex: string): string {
|
|
16
|
-
const h = hex.toLowerCase();
|
|
17
|
-
if (h.length === 4) {
|
|
18
|
-
const r = h[1]!, g = h[2]!, b = h[3]!;
|
|
19
|
-
return `#${r}${r}${g}${g}${b}${b}`;
|
|
20
|
-
}
|
|
21
|
-
return h;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function buildPalette(
|
|
25
|
-
brandCfg: { colorsFrom?: string; colors?: string[] },
|
|
26
|
-
cwd: string,
|
|
27
|
-
): Set<string> | null {
|
|
28
|
-
const hasColorsFrom = !!brandCfg.colorsFrom;
|
|
29
|
-
const hasColors = Array.isArray(brandCfg.colors) && brandCfg.colors.length > 0;
|
|
30
|
-
if (!hasColorsFrom && !hasColors) return null;
|
|
31
|
-
|
|
32
|
-
const palette = new Set<string>();
|
|
33
|
-
if (hasColorsFrom) {
|
|
34
|
-
const cfgPath = path.isAbsolute(brandCfg.colorsFrom!)
|
|
35
|
-
? brandCfg.colorsFrom!
|
|
36
|
-
: path.resolve(cwd, brandCfg.colorsFrom!);
|
|
37
|
-
for (const c of extractTailwindColors(cfgPath)) palette.add(normalizeHex(c));
|
|
38
|
-
}
|
|
39
|
-
for (const c of brandCfg.colors ?? []) palette.add(normalizeHex(c));
|
|
40
|
-
return palette;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export const brandTokensRule: StaticRule = {
|
|
44
|
-
name: 'brand-tokens',
|
|
45
|
-
severity: 'warning',
|
|
46
|
-
|
|
47
|
-
async check(touchedFiles: string[], config: Record<string, unknown> = {}): Promise<Finding[]> {
|
|
48
|
-
const brandCfg = config.brand as
|
|
49
|
-
| { colorsFrom?: string; colors?: string[]; fonts?: string[] }
|
|
50
|
-
| undefined;
|
|
51
|
-
|
|
52
|
-
if (!brandCfg) return [];
|
|
53
|
-
|
|
54
|
-
const cwd = process.cwd();
|
|
55
|
-
const palette = buildPalette(brandCfg, cwd);
|
|
56
|
-
const canonicalFonts = brandCfg.fonts?.map(f => f.toLowerCase()) ?? [];
|
|
57
|
-
const findings: Finding[] = [];
|
|
58
|
-
|
|
59
|
-
for (const file of touchedFiles) {
|
|
60
|
-
const ext = path.extname(file);
|
|
61
|
-
if (!UI_EXTS.has(ext)) continue;
|
|
62
|
-
|
|
63
|
-
let content: string;
|
|
64
|
-
try { content = fs.readFileSync(file, 'utf8'); } catch { continue; }
|
|
65
|
-
|
|
66
|
-
const lines = content.split('\n');
|
|
67
|
-
for (let i = 0; i < lines.length; i++) {
|
|
68
|
-
const line = lines[i]!;
|
|
69
|
-
const trimmed = line.trim();
|
|
70
|
-
if (trimmed.startsWith('//') || trimmed.startsWith('*') || trimmed.startsWith('/*')) continue;
|
|
71
|
-
|
|
72
|
-
if (palette && palette.size > 0) {
|
|
73
|
-
// Check Tailwind arbitrary color classes first, then scan remaining line for plain hex
|
|
74
|
-
TAILWIND_ARBITRARY_HEX.lastIndex = 0;
|
|
75
|
-
let m: RegExpExecArray | null;
|
|
76
|
-
while ((m = TAILWIND_ARBITRARY_HEX.exec(line)) !== null) {
|
|
77
|
-
const hex = normalizeHex(`#${m[1]!}`);
|
|
78
|
-
if (!palette.has(hex)) {
|
|
79
|
-
findings.push({
|
|
80
|
-
id: `brand-tokens:tailwind:${file}:${i + 1}`,
|
|
81
|
-
source: 'static-rules',
|
|
82
|
-
severity: 'warning',
|
|
83
|
-
category: 'brand-tokens',
|
|
84
|
-
file,
|
|
85
|
-
line: i + 1,
|
|
86
|
-
message: `Off-brand Tailwind arbitrary color ${hex} is not in the canonical palette`,
|
|
87
|
-
suggestion: `Replace with a Tailwind token from your brand palette (e.g. bg-primary, text-brand)`,
|
|
88
|
-
protectedPath: false,
|
|
89
|
-
createdAt: new Date().toISOString(),
|
|
90
|
-
});
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// Strip Tailwind arbitrary color brackets before plain hex scan to avoid double-reporting
|
|
95
|
-
const lineWithoutTailwindArbitrary = line.replace(TAILWIND_ARBITRARY_HEX_STRIP, '');
|
|
96
|
-
HEX_RE.lastIndex = 0;
|
|
97
|
-
while ((m = HEX_RE.exec(lineWithoutTailwindArbitrary)) !== null) {
|
|
98
|
-
const hex = normalizeHex(m[0]!);
|
|
99
|
-
if (!palette.has(hex)) {
|
|
100
|
-
const palettePreview = [...palette].slice(0, 5).join(', ');
|
|
101
|
-
findings.push({
|
|
102
|
-
id: `brand-tokens:${file}:${i + 1}`,
|
|
103
|
-
source: 'static-rules',
|
|
104
|
-
severity: 'warning',
|
|
105
|
-
category: 'brand-tokens',
|
|
106
|
-
file,
|
|
107
|
-
line: i + 1,
|
|
108
|
-
message: `Off-brand color ${hex} is not in the canonical palette`,
|
|
109
|
-
suggestion: `Use a brand token. Canonical colors: ${palettePreview}${palette.size > 5 ? ` (+${palette.size - 5} more)` : ''}`,
|
|
110
|
-
protectedPath: false,
|
|
111
|
-
createdAt: new Date().toISOString(),
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
if (canonicalFonts.length > 0 && CSS_EXTS.has(ext)) {
|
|
118
|
-
FONT_FAMILY_RE.lastIndex = 0;
|
|
119
|
-
let fm: RegExpExecArray | null;
|
|
120
|
-
while ((fm = FONT_FAMILY_RE.exec(line)) !== null) {
|
|
121
|
-
const declaration = fm[1]!;
|
|
122
|
-
const declared = declaration.split(',').map(f => f.trim().replace(/['"]/g, '').toLowerCase());
|
|
123
|
-
const hasCanonical = declared.some(f => canonicalFonts.some(cf => f.includes(cf)));
|
|
124
|
-
if (!hasCanonical) {
|
|
125
|
-
findings.push({
|
|
126
|
-
id: `brand-tokens:font:${file}:${i + 1}`,
|
|
127
|
-
source: 'static-rules',
|
|
128
|
-
severity: 'warning',
|
|
129
|
-
category: 'brand-tokens',
|
|
130
|
-
file,
|
|
131
|
-
line: i + 1,
|
|
132
|
-
message: `Off-brand font-family "${declaration.trim()}" — not in canonical fonts list`,
|
|
133
|
-
suggestion: `Use one of the canonical fonts: ${canonicalFonts.join(', ')}`,
|
|
134
|
-
protectedPath: false,
|
|
135
|
-
createdAt: new Date().toISOString(),
|
|
136
|
-
});
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
return findings;
|
|
144
|
-
},
|
|
145
|
-
};
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import * as fs from 'node:fs';
|
|
2
|
-
import type { StaticRule } from '../../phases/static-rules.ts';
|
|
3
|
-
import type { Finding } from '../../findings/types.ts';
|
|
4
|
-
|
|
5
|
-
const CONSOLE_CALLS = /\bconsole\.(log|debug|info)\s*\(/;
|
|
6
|
-
const CODE_EXTS = new Set(['.ts', '.tsx', '.js', '.jsx', '.mts', '.cts', '.mjs', '.cjs']);
|
|
7
|
-
const TEST_PATH = /(?:__tests__|\.test\.|\.spec\.|\/test\/|\/tests\/)/;
|
|
8
|
-
|
|
9
|
-
export const consoleLogRule: StaticRule = {
|
|
10
|
-
name: 'console-log',
|
|
11
|
-
severity: 'warning',
|
|
12
|
-
|
|
13
|
-
async check(touchedFiles: string[]): Promise<Finding[]> {
|
|
14
|
-
const findings: Finding[] = [];
|
|
15
|
-
for (const file of touchedFiles) {
|
|
16
|
-
const ext = file.slice(file.lastIndexOf('.'));
|
|
17
|
-
if (!CODE_EXTS.has(ext) || TEST_PATH.test(file)) continue;
|
|
18
|
-
let content: string;
|
|
19
|
-
try { content = fs.readFileSync(file, 'utf8'); } catch { continue; }
|
|
20
|
-
const lines = content.split('\n');
|
|
21
|
-
for (let i = 0; i < lines.length; i++) {
|
|
22
|
-
const line = lines[i]!;
|
|
23
|
-
if (line.trim().startsWith('//')) continue;
|
|
24
|
-
if (CONSOLE_CALLS.test(line)) {
|
|
25
|
-
findings.push({
|
|
26
|
-
id: `console-log:${file}:${i + 1}`,
|
|
27
|
-
source: 'static-rules',
|
|
28
|
-
severity: 'warning',
|
|
29
|
-
category: 'console-log',
|
|
30
|
-
file,
|
|
31
|
-
line: i + 1,
|
|
32
|
-
message: 'console.log/debug/info left in production code',
|
|
33
|
-
suggestion: 'Remove or replace with a structured logger',
|
|
34
|
-
protectedPath: false,
|
|
35
|
-
createdAt: new Date().toISOString(),
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
return findings;
|
|
41
|
-
},
|
|
42
|
-
};
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
import * as fs from 'node:fs';
|
|
2
|
-
import type { StaticRule } from '../../phases/static-rules.ts';
|
|
3
|
-
import type { Finding } from '../../findings/types.ts';
|
|
4
|
-
|
|
5
|
-
const SECRET_PATTERNS: { regex: RegExp; label: string }[] = [
|
|
6
|
-
// Cloud provider keys
|
|
7
|
-
{ regex: /\bAKIA[0-9A-Z]{16}\b/, label: 'AWS Access Key ID' },
|
|
8
|
-
{ regex: /\b(?:aws|AWS)_?(?:secret|SECRET)_?(?:key|KEY|access|ACCESS)\s*[:=]\s*['"][A-Za-z0-9/+]{40}['"]/, label: 'AWS Secret Access Key' },
|
|
9
|
-
|
|
10
|
-
// LLM / AI providers
|
|
11
|
-
{ regex: /\bsk-ant-[a-zA-Z0-9\-_]{20,}\b/, label: 'Anthropic API key' },
|
|
12
|
-
{ regex: /\bsk-[a-zA-Z0-9]{20,}\b(?!.*placeholder)/, label: 'OpenAI API key' },
|
|
13
|
-
{ regex: /\bgsk_[a-zA-Z0-9]{20,}\b/, label: 'Groq API key' },
|
|
14
|
-
|
|
15
|
-
// Payment
|
|
16
|
-
{ regex: /\bsk_live_[a-zA-Z0-9]{24,}\b/, label: 'Stripe secret key (live)' },
|
|
17
|
-
{ regex: /\brk_live_[a-zA-Z0-9]{24,}\b/, label: 'Stripe restricted key (live)' },
|
|
18
|
-
|
|
19
|
-
// Source control / CI
|
|
20
|
-
{ regex: /\bghp_[a-zA-Z0-9]{36}\b/, label: 'GitHub personal access token' },
|
|
21
|
-
{ regex: /\bghs_[a-zA-Z0-9]{36}\b/, label: 'GitHub Actions token' },
|
|
22
|
-
{ regex: /\bgithub_pat_[a-zA-Z0-9_]{82}\b/, label: 'GitHub fine-grained PAT' },
|
|
23
|
-
|
|
24
|
-
// Communication
|
|
25
|
-
{ regex: /\bSG\.[a-zA-Z0-9\-_]{22,}\.[a-zA-Z0-9\-_]{43,}\b/, label: 'SendGrid API key' },
|
|
26
|
-
{ regex: /\bAC[a-f0-9]{32}\b/, label: 'Twilio Account SID' },
|
|
27
|
-
|
|
28
|
-
// Database / BaaS
|
|
29
|
-
{ regex: /\bservice_role\b.*\beyJ[a-zA-Z0-9._-]{100,}\b/, label: 'Supabase service role JWT' },
|
|
30
|
-
{ regex: /\beyJ[a-zA-Z0-9._-]{150,}\b/, label: 'Long JWT (possible service key)' },
|
|
31
|
-
|
|
32
|
-
// Generic patterns
|
|
33
|
-
{ regex: /(?:^|[^a-z])(?:password|passwd|pwd)\s*[:=]\s*['"](?!\/)[^'"]{6,}['"]/, label: 'Hardcoded password' },
|
|
34
|
-
{ regex: /(?:api_key|apikey|api-key)\s*[:=]\s*['"][^'"]{8,}['"]/, label: 'Hardcoded API key' },
|
|
35
|
-
{ regex: /(?:secret|secret_key|secretkey)\s*[:=]\s*['"][^'"]{8,}['"]/, label: 'Hardcoded secret' },
|
|
36
|
-
{ regex: /(?:access_token|accesstoken)\s*[:=]\s*['"][^'"]{8,}['"]/, label: 'Hardcoded access token' },
|
|
37
|
-
{ regex: /(?:private_key|privatekey)\s*[:=]\s*['"][^'"]{8,}['"]/, label: 'Hardcoded private key' },
|
|
38
|
-
{ regex: /-----BEGIN (?:RSA |EC )?PRIVATE KEY-----/, label: 'Private key block' },
|
|
39
|
-
];
|
|
40
|
-
|
|
41
|
-
// Patterns that indicate a placeholder, not a real secret
|
|
42
|
-
const PLACEHOLDER = /(?:your[-_]?|xxx|placeholder|example|test|fake|dummy|changeme|<[^>]+>|process\.env|import\.meta\.env|\$\{)/i;
|
|
43
|
-
const SKIP_EXTS = new Set(['.md', '.txt', '.yaml', '.yml', '.json', '.lock', '.snap']);
|
|
44
|
-
const TEST_PATH = /(?:__tests__|\.test\.|\.spec\.|\/test\/|\/tests\/)/;
|
|
45
|
-
|
|
46
|
-
export const hardcodedSecretsRule: StaticRule = {
|
|
47
|
-
name: 'hardcoded-secrets',
|
|
48
|
-
severity: 'critical',
|
|
49
|
-
|
|
50
|
-
async check(touchedFiles: string[]): Promise<Finding[]> {
|
|
51
|
-
const findings: Finding[] = [];
|
|
52
|
-
for (const file of touchedFiles) {
|
|
53
|
-
const ext = file.slice(file.lastIndexOf('.'));
|
|
54
|
-
if (SKIP_EXTS.has(ext) || TEST_PATH.test(file)) continue;
|
|
55
|
-
let content: string;
|
|
56
|
-
try { content = fs.readFileSync(file, 'utf8'); } catch { continue; }
|
|
57
|
-
const lines = content.split('\n');
|
|
58
|
-
for (let i = 0; i < lines.length; i++) {
|
|
59
|
-
const line = lines[i]!;
|
|
60
|
-
if (line.trim().startsWith('//') || line.trim().startsWith('#')) continue;
|
|
61
|
-
for (const { regex, label } of SECRET_PATTERNS) {
|
|
62
|
-
const match = line.match(regex);
|
|
63
|
-
if (match && !PLACEHOLDER.test(match[0])) {
|
|
64
|
-
findings.push({
|
|
65
|
-
id: `hardcoded-secrets:${file}:${i + 1}`,
|
|
66
|
-
source: 'static-rules',
|
|
67
|
-
severity: 'critical',
|
|
68
|
-
category: 'hardcoded-secrets',
|
|
69
|
-
file,
|
|
70
|
-
line: i + 1,
|
|
71
|
-
message: `${label} appears hardcoded`,
|
|
72
|
-
suggestion: 'Move to environment variable and load via process.env',
|
|
73
|
-
protectedPath: false,
|
|
74
|
-
createdAt: new Date().toISOString(),
|
|
75
|
-
});
|
|
76
|
-
break;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
return findings;
|
|
82
|
-
},
|
|
83
|
-
};
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import * as fs from 'node:fs';
|
|
2
|
-
import type { StaticRule } from '../../phases/static-rules.ts';
|
|
3
|
-
import type { Finding } from '../../findings/types.ts';
|
|
4
|
-
|
|
5
|
-
// Redirect calls in Next.js / Express / Node
|
|
6
|
-
const REDIRECT_CALL = /(?:\bredirect\s*\(|NextResponse\.redirect\s*\(|res\.redirect\s*\(|router\.push\s*\()/;
|
|
7
|
-
|
|
8
|
-
// User-controlled input sources
|
|
9
|
-
const USER_INPUT_SOURCES = /(?:req\.|request\.|params\.|query\.|body\.|searchParams\.|headers\.|getParam|getQuery|getSearchParam)/;
|
|
10
|
-
|
|
11
|
-
// Template interpolation of user input into redirect target
|
|
12
|
-
const TAINTED_REDIRECT_TEMPLATE = /`[^`]*\$\{[^}]*(?:url|redirect|return|next|callback|target|to|from|path|href|location)[^}]*\}`/i;
|
|
13
|
-
const TAINTED_REDIRECT_VAR = /(?:url|redirect|returnUrl|returnTo|next|callbackUrl|target|to|from|path|href|location)\b/;
|
|
14
|
-
|
|
15
|
-
const CODE_EXTS = new Set(['.ts', '.tsx', '.js', '.jsx', '.mts', '.cts', '.mjs', '.cjs']);
|
|
16
|
-
const TEST_PATH = /(?:__tests__|\.test\.|\.spec\.|\/test\/|\/tests\/)/;
|
|
17
|
-
|
|
18
|
-
export const insecureRedirectRule: StaticRule = {
|
|
19
|
-
name: 'insecure-redirect',
|
|
20
|
-
severity: 'warning',
|
|
21
|
-
|
|
22
|
-
async check(touchedFiles: string[]): Promise<Finding[]> {
|
|
23
|
-
const findings: Finding[] = [];
|
|
24
|
-
for (const file of touchedFiles) {
|
|
25
|
-
const ext = file.slice(file.lastIndexOf('.'));
|
|
26
|
-
if (!CODE_EXTS.has(ext) || TEST_PATH.test(file)) continue;
|
|
27
|
-
let content: string;
|
|
28
|
-
try { content = fs.readFileSync(file, 'utf8'); } catch { continue; }
|
|
29
|
-
const lines = content.split('\n');
|
|
30
|
-
|
|
31
|
-
for (let i = 0; i < lines.length; i++) {
|
|
32
|
-
const line = lines[i]!;
|
|
33
|
-
if (line.trim().startsWith('//') || line.trim().startsWith('*')) continue;
|
|
34
|
-
|
|
35
|
-
if (!REDIRECT_CALL.test(line)) continue;
|
|
36
|
-
|
|
37
|
-
// Check if the redirect target is user-controlled
|
|
38
|
-
const hasTaint = TAINTED_REDIRECT_TEMPLATE.test(line) || USER_INPUT_SOURCES.test(line);
|
|
39
|
-
if (!hasTaint) {
|
|
40
|
-
// Check if a variable with a suspicious name is passed
|
|
41
|
-
const argStr = line.replace(REDIRECT_CALL, '');
|
|
42
|
-
const hasRedirectVar = TAINTED_REDIRECT_VAR.test(line) && !/['"`]/.test(argStr);
|
|
43
|
-
if (!hasRedirectVar) continue;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// Skip if there's obvious validation nearby (startsWith, URL constructor, allowlist)
|
|
47
|
-
const context = lines.slice(Math.max(0, i - 5), i + 1).join('\n');
|
|
48
|
-
const hasValidation = /(?:startsWith\s*\(\s*['"]\/|new\s+URL|allowedRedirects|trustedOrigins|encodeURIComponent)/.test(context);
|
|
49
|
-
if (hasValidation) continue;
|
|
50
|
-
|
|
51
|
-
findings.push({
|
|
52
|
-
id: `insecure-redirect:${file}:${i + 1}`,
|
|
53
|
-
source: 'static-rules',
|
|
54
|
-
severity: 'warning',
|
|
55
|
-
category: 'insecure-redirect',
|
|
56
|
-
file,
|
|
57
|
-
line: i + 1,
|
|
58
|
-
message: 'Possible open redirect: redirect target may be user-controlled',
|
|
59
|
-
suggestion: 'Validate redirect targets — allow only relative paths (startsWith("/")) or an explicit allowlist of trusted origins',
|
|
60
|
-
protectedPath: false,
|
|
61
|
-
createdAt: new Date().toISOString(),
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
return findings;
|
|
66
|
-
},
|
|
67
|
-
};
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import * as fs from 'node:fs';
|
|
2
|
-
import type { StaticRule } from '../../phases/static-rules.ts';
|
|
3
|
-
import type { Finding } from '../../findings/types.ts';
|
|
4
|
-
|
|
5
|
-
const DEFAULT_THRESHOLD = 500;
|
|
6
|
-
const SKIP_EXTS = new Set(['.lock', '.snap', '.map', '.min.js', '.min.css']);
|
|
7
|
-
|
|
8
|
-
export const largeFileRule: StaticRule = {
|
|
9
|
-
name: 'large-file',
|
|
10
|
-
severity: 'note',
|
|
11
|
-
|
|
12
|
-
async check(touchedFiles: string[]): Promise<Finding[]> {
|
|
13
|
-
const threshold = parseInt(process.env.AUTOPILOT_LARGE_FILE_LINES ?? '', 10) || DEFAULT_THRESHOLD;
|
|
14
|
-
const findings: Finding[] = [];
|
|
15
|
-
for (const file of touchedFiles) {
|
|
16
|
-
const ext = file.slice(file.lastIndexOf('.'));
|
|
17
|
-
if (SKIP_EXTS.has(ext)) continue;
|
|
18
|
-
let content: string;
|
|
19
|
-
try { content = fs.readFileSync(file, 'utf8'); } catch { continue; }
|
|
20
|
-
const lines = content.split('\n').length;
|
|
21
|
-
if (lines > threshold) {
|
|
22
|
-
findings.push({
|
|
23
|
-
id: `large-file:${file}`,
|
|
24
|
-
source: 'static-rules',
|
|
25
|
-
severity: 'note',
|
|
26
|
-
category: 'large-file',
|
|
27
|
-
file,
|
|
28
|
-
message: `File is ${lines} lines (threshold: ${threshold})`,
|
|
29
|
-
suggestion: 'Consider splitting into smaller, focused modules',
|
|
30
|
-
protectedPath: false,
|
|
31
|
-
createdAt: new Date().toISOString(),
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
return findings;
|
|
36
|
-
},
|
|
37
|
-
};
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import * as fs from 'node:fs';
|
|
2
|
-
import * as path from 'node:path';
|
|
3
|
-
import type { StaticRule } from '../../phases/static-rules.ts';
|
|
4
|
-
import type { Finding } from '../../findings/types.ts';
|
|
5
|
-
|
|
6
|
-
// Next.js App Router API routes and pages with data mutations
|
|
7
|
-
const API_ROUTE_PATTERN = /(?:app[/\\]api[/\\].*route\.[tj]sx?|pages[/\\]api[/\\].*\.[tj]sx?)$/;
|
|
8
|
-
|
|
9
|
-
// Auth function signatures — any of these indicate auth is checked
|
|
10
|
-
const AUTH_PATTERNS = [
|
|
11
|
-
/getServerSession\s*\(/,
|
|
12
|
-
/\bauth\s*\(\s*\)/, // next-auth v5 auth()
|
|
13
|
-
/createServerSupabase\s*\(/,
|
|
14
|
-
/createServerClient\s*\(/,
|
|
15
|
-
/getSession\s*\(/,
|
|
16
|
-
/verifyToken\s*\(/,
|
|
17
|
-
/authenticate\s*\(/,
|
|
18
|
-
/requireAuth\s*\(/,
|
|
19
|
-
/currentUser\s*\(/,
|
|
20
|
-
/withAuth\s*\(/,
|
|
21
|
-
/checkAuth\s*\(/,
|
|
22
|
-
/isAuthenticated\s*\(/,
|
|
23
|
-
/useServerSession\s*\(/,
|
|
24
|
-
/jwtVerify\s*\(/,
|
|
25
|
-
/verify\s*\(.*token/i,
|
|
26
|
-
/clerkClient/,
|
|
27
|
-
/getAuth\s*\(/, // Clerk
|
|
28
|
-
/session\s*\.\s*user/,
|
|
29
|
-
/req\s*\.\s*user\b/,
|
|
30
|
-
];
|
|
31
|
-
|
|
32
|
-
// Mutation handler exports — GET-only routes are less critical
|
|
33
|
-
const MUTATION_EXPORT = /export\s+(?:async\s+)?function\s+(?:POST|PUT|PATCH|DELETE)\b/;
|
|
34
|
-
const MUTATION_HANDLER = /(?:POST|PUT|PATCH|DELETE)\s*\(/;
|
|
35
|
-
|
|
36
|
-
export const missingAuthRule: StaticRule = {
|
|
37
|
-
name: 'missing-auth',
|
|
38
|
-
severity: 'critical',
|
|
39
|
-
|
|
40
|
-
async check(touchedFiles: string[]): Promise<Finding[]> {
|
|
41
|
-
const findings: Finding[] = [];
|
|
42
|
-
for (const file of touchedFiles) {
|
|
43
|
-
if (!API_ROUTE_PATTERN.test(file)) continue;
|
|
44
|
-
let content: string;
|
|
45
|
-
try { content = fs.readFileSync(file, 'utf8'); } catch { continue; }
|
|
46
|
-
|
|
47
|
-
// Only flag mutation handlers
|
|
48
|
-
if (!MUTATION_EXPORT.test(content) && !MUTATION_HANDLER.test(content)) continue;
|
|
49
|
-
|
|
50
|
-
// Check if any auth pattern is present in the file
|
|
51
|
-
const hasAuth = AUTH_PATTERNS.some(p => p.test(content));
|
|
52
|
-
if (hasAuth) continue;
|
|
53
|
-
|
|
54
|
-
const rel = path.basename(file);
|
|
55
|
-
findings.push({
|
|
56
|
-
id: `missing-auth:${file}:1`,
|
|
57
|
-
source: 'static-rules',
|
|
58
|
-
severity: 'critical',
|
|
59
|
-
category: 'missing-auth',
|
|
60
|
-
file,
|
|
61
|
-
line: 1,
|
|
62
|
-
message: `API route ${rel} has mutation handlers (POST/PUT/PATCH/DELETE) with no visible auth check`,
|
|
63
|
-
suggestion: 'Add authentication: call getServerSession(), auth(), or equivalent before processing the request body',
|
|
64
|
-
protectedPath: false,
|
|
65
|
-
createdAt: new Date().toISOString(),
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
return findings;
|
|
69
|
-
},
|
|
70
|
-
};
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import * as fs from 'node:fs';
|
|
2
|
-
import * as path from 'node:path';
|
|
3
|
-
import type { StaticRule } from '../../phases/static-rules.ts';
|
|
4
|
-
import type { Finding } from '../../findings/types.ts';
|
|
5
|
-
|
|
6
|
-
const SOURCE_DIRS = ['src/', 'app/', 'lib/', 'utils/'];
|
|
7
|
-
const SOURCE_EXTS = new Set(['.ts', '.tsx', '.js', '.jsx']);
|
|
8
|
-
const TEST_PATH = /(?:__tests__|\.test\.|\.spec\.|\/test\/|\/tests\/)/;
|
|
9
|
-
const INDEX_FILE = /(?:^|[/\\])index\.[tj]sx?$/;
|
|
10
|
-
|
|
11
|
-
function isSourceFile(f: string): boolean {
|
|
12
|
-
const ext = f.slice(f.lastIndexOf('.'));
|
|
13
|
-
return SOURCE_EXTS.has(ext) && !TEST_PATH.test(f) && SOURCE_DIRS.some(d => f.startsWith(d));
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
function hasTestCounterpart(file: string, touchedFiles: Set<string>): boolean {
|
|
17
|
-
const base = file.replace(/\.[tj]sx?$/, '');
|
|
18
|
-
const candidates = [
|
|
19
|
-
`${base}.test.ts`, `${base}.test.tsx`, `${base}.test.js`,
|
|
20
|
-
`${base}.spec.ts`, `${base}.spec.tsx`, `${base}.spec.js`,
|
|
21
|
-
];
|
|
22
|
-
const dir = path.dirname(file);
|
|
23
|
-
const name = path.basename(base);
|
|
24
|
-
candidates.push(
|
|
25
|
-
`${dir}/__tests__/${name}.test.ts`,
|
|
26
|
-
`${dir}/__tests__/${name}.test.tsx`,
|
|
27
|
-
`${dir}/__tests__/${name}.test.js`,
|
|
28
|
-
);
|
|
29
|
-
return candidates.some(c => touchedFiles.has(c) || fs.existsSync(c));
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export const missingTestsRule: StaticRule = {
|
|
33
|
-
name: 'missing-tests',
|
|
34
|
-
severity: 'note',
|
|
35
|
-
|
|
36
|
-
async check(touchedFiles: string[]): Promise<Finding[]> {
|
|
37
|
-
const touched = new Set(touchedFiles);
|
|
38
|
-
const findings: Finding[] = [];
|
|
39
|
-
for (const file of touchedFiles) {
|
|
40
|
-
if (!isSourceFile(file) || INDEX_FILE.test(file)) continue;
|
|
41
|
-
if (!hasTestCounterpart(file, touched)) {
|
|
42
|
-
findings.push({
|
|
43
|
-
id: `missing-tests:${file}`,
|
|
44
|
-
source: 'static-rules',
|
|
45
|
-
severity: 'note',
|
|
46
|
-
category: 'missing-tests',
|
|
47
|
-
file,
|
|
48
|
-
message: 'No test file found for this changed source file',
|
|
49
|
-
suggestion: `Add tests at ${file.replace(/\.[tj]sx?$/, '.test.ts')}`,
|
|
50
|
-
protectedPath: false,
|
|
51
|
-
createdAt: new Date().toISOString(),
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
return findings;
|
|
56
|
-
},
|
|
57
|
-
};
|