@opensip-cli/checks-typescript 0.1.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/LICENSE +202 -0
- package/NOTICE +8 -0
- package/README.md +31 -0
- package/dist/__tests__/all-checks-execute.test.d.ts +12 -0
- package/dist/__tests__/all-checks-execute.test.d.ts.map +1 -0
- package/dist/__tests__/all-checks-execute.test.js +846 -0
- package/dist/__tests__/all-checks-execute.test.js.map +1 -0
- package/dist/__tests__/behavior-fixtures-2.test.d.ts +9 -0
- package/dist/__tests__/behavior-fixtures-2.test.d.ts.map +1 -0
- package/dist/__tests__/behavior-fixtures-2.test.js +625 -0
- package/dist/__tests__/behavior-fixtures-2.test.js.map +1 -0
- package/dist/__tests__/behavior-fixtures-3.test.d.ts +7 -0
- package/dist/__tests__/behavior-fixtures-3.test.d.ts.map +1 -0
- package/dist/__tests__/behavior-fixtures-3.test.js +658 -0
- package/dist/__tests__/behavior-fixtures-3.test.js.map +1 -0
- package/dist/__tests__/behavior-fixtures-4.test.d.ts +8 -0
- package/dist/__tests__/behavior-fixtures-4.test.d.ts.map +1 -0
- package/dist/__tests__/behavior-fixtures-4.test.js +590 -0
- package/dist/__tests__/behavior-fixtures-4.test.js.map +1 -0
- package/dist/__tests__/behavior-fixtures-5.test.d.ts +7 -0
- package/dist/__tests__/behavior-fixtures-5.test.d.ts.map +1 -0
- package/dist/__tests__/behavior-fixtures-5.test.js +548 -0
- package/dist/__tests__/behavior-fixtures-5.test.js.map +1 -0
- package/dist/__tests__/behavior-fixtures-6.test.d.ts +18 -0
- package/dist/__tests__/behavior-fixtures-6.test.d.ts.map +1 -0
- package/dist/__tests__/behavior-fixtures-6.test.js +1700 -0
- package/dist/__tests__/behavior-fixtures-6.test.js.map +1 -0
- package/dist/__tests__/behavior-fixtures.test.d.ts +10 -0
- package/dist/__tests__/behavior-fixtures.test.d.ts.map +1 -0
- package/dist/__tests__/behavior-fixtures.test.js +812 -0
- package/dist/__tests__/behavior-fixtures.test.js.map +1 -0
- package/dist/__tests__/branch-fixtures-2.test.d.ts +6 -0
- package/dist/__tests__/branch-fixtures-2.test.d.ts.map +1 -0
- package/dist/__tests__/branch-fixtures-2.test.js +1369 -0
- package/dist/__tests__/branch-fixtures-2.test.js.map +1 -0
- package/dist/__tests__/branch-fixtures-3.test.d.ts +7 -0
- package/dist/__tests__/branch-fixtures-3.test.d.ts.map +1 -0
- package/dist/__tests__/branch-fixtures-3.test.js +877 -0
- package/dist/__tests__/branch-fixtures-3.test.js.map +1 -0
- package/dist/__tests__/branch-fixtures.test.d.ts +6 -0
- package/dist/__tests__/branch-fixtures.test.d.ts.map +1 -0
- package/dist/__tests__/branch-fixtures.test.js +1072 -0
- package/dist/__tests__/branch-fixtures.test.js.map +1 -0
- package/dist/__tests__/checks.test.d.ts +2 -0
- package/dist/__tests__/checks.test.d.ts.map +1 -0
- package/dist/__tests__/checks.test.js +39 -0
- package/dist/__tests__/checks.test.js.map +1 -0
- package/dist/__tests__/fixture-coverage.allowlist.d.ts +19 -0
- package/dist/__tests__/fixture-coverage.allowlist.d.ts.map +1 -0
- package/dist/__tests__/fixture-coverage.allowlist.js +27 -0
- package/dist/__tests__/fixture-coverage.allowlist.js.map +1 -0
- package/dist/__tests__/fixture-coverage.test.d.ts +13 -0
- package/dist/__tests__/fixture-coverage.test.d.ts.map +1 -0
- package/dist/__tests__/fixture-coverage.test.js +57 -0
- package/dist/__tests__/fixture-coverage.test.js.map +1 -0
- package/dist/__tests__/no-bootstrap-tool-import.test.d.ts +2 -0
- package/dist/__tests__/no-bootstrap-tool-import.test.d.ts.map +1 -0
- package/dist/__tests__/no-bootstrap-tool-import.test.js +75 -0
- package/dist/__tests__/no-bootstrap-tool-import.test.js.map +1 -0
- package/dist/__tests__/phantom-dependency-detection.test.d.ts +12 -0
- package/dist/__tests__/phantom-dependency-detection.test.d.ts.map +1 -0
- package/dist/__tests__/phantom-dependency-detection.test.js +112 -0
- package/dist/__tests__/phantom-dependency-detection.test.js.map +1 -0
- package/dist/__tests__/typescript-frontend.test.d.ts +8 -0
- package/dist/__tests__/typescript-frontend.test.d.ts.map +1 -0
- package/dist/__tests__/typescript-frontend.test.js +57 -0
- package/dist/__tests__/typescript-frontend.test.js.map +1 -0
- package/dist/checks/architecture/circular-import-detection.d.ts +14 -0
- package/dist/checks/architecture/circular-import-detection.d.ts.map +1 -0
- package/dist/checks/architecture/circular-import-detection.js +55 -0
- package/dist/checks/architecture/circular-import-detection.js.map +1 -0
- package/dist/checks/architecture/contracts-schema-consistency.d.ts +11 -0
- package/dist/checks/architecture/contracts-schema-consistency.d.ts.map +1 -0
- package/dist/checks/architecture/contracts-schema-consistency.js +75 -0
- package/dist/checks/architecture/contracts-schema-consistency.js.map +1 -0
- package/dist/checks/architecture/drizzle-orm-migration-guardrails.d.ts +12 -0
- package/dist/checks/architecture/drizzle-orm-migration-guardrails.d.ts.map +1 -0
- package/dist/checks/architecture/drizzle-orm-migration-guardrails.js +92 -0
- package/dist/checks/architecture/drizzle-orm-migration-guardrails.js.map +1 -0
- package/dist/checks/architecture/index.d.ts +10 -0
- package/dist/checks/architecture/index.d.ts.map +1 -0
- package/dist/checks/architecture/index.js +10 -0
- package/dist/checks/architecture/index.js.map +1 -0
- package/dist/checks/architecture/missing-type-exports.d.ts +13 -0
- package/dist/checks/architecture/missing-type-exports.d.ts.map +1 -0
- package/dist/checks/architecture/missing-type-exports.js +245 -0
- package/dist/checks/architecture/missing-type-exports.js.map +1 -0
- package/dist/checks/architecture/module-coupling-fan-out.d.ts +20 -0
- package/dist/checks/architecture/module-coupling-fan-out.d.ts.map +1 -0
- package/dist/checks/architecture/module-coupling-fan-out.js +120 -0
- package/dist/checks/architecture/module-coupling-fan-out.js.map +1 -0
- package/dist/checks/architecture/no-bootstrap-tool-import.d.ts +38 -0
- package/dist/checks/architecture/no-bootstrap-tool-import.d.ts.map +1 -0
- package/dist/checks/architecture/no-bootstrap-tool-import.js +95 -0
- package/dist/checks/architecture/no-bootstrap-tool-import.js.map +1 -0
- package/dist/checks/architecture/package-json-exports-field.d.ts +10 -0
- package/dist/checks/architecture/package-json-exports-field.d.ts.map +1 -0
- package/dist/checks/architecture/package-json-exports-field.js +56 -0
- package/dist/checks/architecture/package-json-exports-field.js.map +1 -0
- package/dist/checks/architecture/phantom-dependency-detection.d.ts +22 -0
- package/dist/checks/architecture/phantom-dependency-detection.d.ts.map +1 -0
- package/dist/checks/architecture/phantom-dependency-detection.js +330 -0
- package/dist/checks/architecture/phantom-dependency-detection.js.map +1 -0
- package/dist/checks/architecture/tsconfig-extends-validation.d.ts +10 -0
- package/dist/checks/architecture/tsconfig-extends-validation.d.ts.map +1 -0
- package/dist/checks/architecture/tsconfig-extends-validation.js +78 -0
- package/dist/checks/architecture/tsconfig-extends-validation.js.map +1 -0
- package/dist/checks/index.d.ts +6 -0
- package/dist/checks/index.d.ts.map +1 -0
- package/dist/checks/index.js +6 -0
- package/dist/checks/index.js.map +1 -0
- package/dist/checks/quality/api/api-contract-validation.d.ts +15 -0
- package/dist/checks/quality/api/api-contract-validation.d.ts.map +1 -0
- package/dist/checks/quality/api/api-contract-validation.js +316 -0
- package/dist/checks/quality/api/api-contract-validation.js.map +1 -0
- package/dist/checks/quality/api/api-response-validation.d.ts +14 -0
- package/dist/checks/quality/api/api-response-validation.d.ts.map +1 -0
- package/dist/checks/quality/api/api-response-validation.js +209 -0
- package/dist/checks/quality/api/api-response-validation.js.map +1 -0
- package/dist/checks/quality/api/fastify-route-validation.d.ts +14 -0
- package/dist/checks/quality/api/fastify-route-validation.d.ts.map +1 -0
- package/dist/checks/quality/api/fastify-route-validation.js +298 -0
- package/dist/checks/quality/api/fastify-route-validation.js.map +1 -0
- package/dist/checks/quality/api/fastify-schema-coverage.d.ts +11 -0
- package/dist/checks/quality/api/fastify-schema-coverage.d.ts.map +1 -0
- package/dist/checks/quality/api/fastify-schema-coverage.js +261 -0
- package/dist/checks/quality/api/fastify-schema-coverage.js.map +1 -0
- package/dist/checks/quality/api/index.d.ts +5 -0
- package/dist/checks/quality/api/index.d.ts.map +1 -0
- package/dist/checks/quality/api/index.js +5 -0
- package/dist/checks/quality/api/index.js.map +1 -0
- package/dist/checks/quality/code-structure/duplicate-utility-functions.d.ts +32 -0
- package/dist/checks/quality/code-structure/duplicate-utility-functions.d.ts.map +1 -0
- package/dist/checks/quality/code-structure/duplicate-utility-functions.js +451 -0
- package/dist/checks/quality/code-structure/duplicate-utility-functions.js.map +1 -0
- package/dist/checks/quality/code-structure/index.d.ts +3 -0
- package/dist/checks/quality/code-structure/index.d.ts.map +1 -0
- package/dist/checks/quality/code-structure/index.js +3 -0
- package/dist/checks/quality/code-structure/index.js.map +1 -0
- package/dist/checks/quality/code-structure/no-any-types.d.ts +13 -0
- package/dist/checks/quality/code-structure/no-any-types.d.ts.map +1 -0
- package/dist/checks/quality/code-structure/no-any-types.js +116 -0
- package/dist/checks/quality/code-structure/no-any-types.js.map +1 -0
- package/dist/checks/quality/data-integrity/__tests__/null-safety-fp.test.d.ts +15 -0
- package/dist/checks/quality/data-integrity/__tests__/null-safety-fp.test.d.ts.map +1 -0
- package/dist/checks/quality/data-integrity/__tests__/null-safety-fp.test.js +51 -0
- package/dist/checks/quality/data-integrity/__tests__/null-safety-fp.test.js.map +1 -0
- package/dist/checks/quality/data-integrity/array-validation.d.ts +16 -0
- package/dist/checks/quality/data-integrity/array-validation.d.ts.map +1 -0
- package/dist/checks/quality/data-integrity/array-validation.js +508 -0
- package/dist/checks/quality/data-integrity/array-validation.js.map +1 -0
- package/dist/checks/quality/data-integrity/database-index-coverage.d.ts +14 -0
- package/dist/checks/quality/data-integrity/database-index-coverage.d.ts.map +1 -0
- package/dist/checks/quality/data-integrity/database-index-coverage.js +235 -0
- package/dist/checks/quality/data-integrity/database-index-coverage.js.map +1 -0
- package/dist/checks/quality/data-integrity/database-schema-validation.d.ts +16 -0
- package/dist/checks/quality/data-integrity/database-schema-validation.d.ts.map +1 -0
- package/dist/checks/quality/data-integrity/database-schema-validation.js +328 -0
- package/dist/checks/quality/data-integrity/database-schema-validation.js.map +1 -0
- package/dist/checks/quality/data-integrity/in-memory-repository-detection.d.ts +14 -0
- package/dist/checks/quality/data-integrity/in-memory-repository-detection.d.ts.map +1 -0
- package/dist/checks/quality/data-integrity/in-memory-repository-detection.js +157 -0
- package/dist/checks/quality/data-integrity/in-memory-repository-detection.js.map +1 -0
- package/dist/checks/quality/data-integrity/index.d.ts +8 -0
- package/dist/checks/quality/data-integrity/index.d.ts.map +1 -0
- package/dist/checks/quality/data-integrity/index.js +8 -0
- package/dist/checks/quality/data-integrity/index.js.map +1 -0
- package/dist/checks/quality/data-integrity/missing-input-validation.d.ts +12 -0
- package/dist/checks/quality/data-integrity/missing-input-validation.d.ts.map +1 -0
- package/dist/checks/quality/data-integrity/missing-input-validation.js +180 -0
- package/dist/checks/quality/data-integrity/missing-input-validation.js.map +1 -0
- package/dist/checks/quality/data-integrity/null-safety.d.ts +33 -0
- package/dist/checks/quality/data-integrity/null-safety.d.ts.map +1 -0
- package/dist/checks/quality/data-integrity/null-safety.js +766 -0
- package/dist/checks/quality/data-integrity/null-safety.js.map +1 -0
- package/dist/checks/quality/data-integrity/numeric-validation.d.ts +12 -0
- package/dist/checks/quality/data-integrity/numeric-validation.d.ts.map +1 -0
- package/dist/checks/quality/data-integrity/numeric-validation.js +409 -0
- package/dist/checks/quality/data-integrity/numeric-validation.js.map +1 -0
- package/dist/checks/quality/frontend/a11y-form-labels.d.ts +14 -0
- package/dist/checks/quality/frontend/a11y-form-labels.d.ts.map +1 -0
- package/dist/checks/quality/frontend/a11y-form-labels.js +93 -0
- package/dist/checks/quality/frontend/a11y-form-labels.js.map +1 -0
- package/dist/checks/quality/frontend/a11y-semantic-html.d.ts +14 -0
- package/dist/checks/quality/frontend/a11y-semantic-html.d.ts.map +1 -0
- package/dist/checks/quality/frontend/a11y-semantic-html.js +88 -0
- package/dist/checks/quality/frontend/a11y-semantic-html.js.map +1 -0
- package/dist/checks/quality/frontend/index.d.ts +4 -0
- package/dist/checks/quality/frontend/index.d.ts.map +1 -0
- package/dist/checks/quality/frontend/index.js +4 -0
- package/dist/checks/quality/frontend/index.js.map +1 -0
- package/dist/checks/quality/frontend/test-only-frontend-modules.d.ts +13 -0
- package/dist/checks/quality/frontend/test-only-frontend-modules.d.ts.map +1 -0
- package/dist/checks/quality/frontend/test-only-frontend-modules.js +159 -0
- package/dist/checks/quality/frontend/test-only-frontend-modules.js.map +1 -0
- package/dist/checks/quality/incomplete-regex-escaping.d.ts +13 -0
- package/dist/checks/quality/incomplete-regex-escaping.d.ts.map +1 -0
- package/dist/checks/quality/incomplete-regex-escaping.js +207 -0
- package/dist/checks/quality/incomplete-regex-escaping.js.map +1 -0
- package/dist/checks/quality/index.d.ts +11 -0
- package/dist/checks/quality/index.d.ts.map +1 -0
- package/dist/checks/quality/index.js +11 -0
- package/dist/checks/quality/index.js.map +1 -0
- package/dist/checks/quality/linting/index.d.ts +2 -0
- package/dist/checks/quality/linting/index.d.ts.map +1 -0
- package/dist/checks/quality/linting/index.js +2 -0
- package/dist/checks/quality/linting/index.js.map +1 -0
- package/dist/checks/quality/linting/typescript-frontend.d.ts +25 -0
- package/dist/checks/quality/linting/typescript-frontend.d.ts.map +1 -0
- package/dist/checks/quality/linting/typescript-frontend.js +159 -0
- package/dist/checks/quality/linting/typescript-frontend.js.map +1 -0
- package/dist/checks/quality/observability/index.d.ts +5 -0
- package/dist/checks/quality/observability/index.d.ts.map +1 -0
- package/dist/checks/quality/observability/index.js +5 -0
- package/dist/checks/quality/observability/index.js.map +1 -0
- package/dist/checks/quality/observability/logger-event-name-format.d.ts +12 -0
- package/dist/checks/quality/observability/logger-event-name-format.d.ts.map +1 -0
- package/dist/checks/quality/observability/logger-event-name-format.js +124 -0
- package/dist/checks/quality/observability/logger-event-name-format.js.map +1 -0
- package/dist/checks/quality/observability/no-hardcoded-correlation-id.d.ts +5 -0
- package/dist/checks/quality/observability/no-hardcoded-correlation-id.d.ts.map +1 -0
- package/dist/checks/quality/observability/no-hardcoded-correlation-id.js +77 -0
- package/dist/checks/quality/observability/no-hardcoded-correlation-id.js.map +1 -0
- package/dist/checks/quality/observability/observability-coverage/__tests__/analyzer.test.d.ts +11 -0
- package/dist/checks/quality/observability/observability-coverage/__tests__/analyzer.test.d.ts.map +1 -0
- package/dist/checks/quality/observability/observability-coverage/__tests__/analyzer.test.js +107 -0
- package/dist/checks/quality/observability/observability-coverage/__tests__/analyzer.test.js.map +1 -0
- package/dist/checks/quality/observability/observability-coverage/__tests__/logger-detector.test.d.ts +12 -0
- package/dist/checks/quality/observability/observability-coverage/__tests__/logger-detector.test.d.ts.map +1 -0
- package/dist/checks/quality/observability/observability-coverage/__tests__/logger-detector.test.js +94 -0
- package/dist/checks/quality/observability/observability-coverage/__tests__/logger-detector.test.js.map +1 -0
- package/dist/checks/quality/observability/observability-coverage/analyzer.d.ts +13 -0
- package/dist/checks/quality/observability/observability-coverage/analyzer.d.ts.map +1 -0
- package/dist/checks/quality/observability/observability-coverage/analyzer.js +117 -0
- package/dist/checks/quality/observability/observability-coverage/analyzer.js.map +1 -0
- package/dist/checks/quality/observability/observability-coverage/index.d.ts +4 -0
- package/dist/checks/quality/observability/observability-coverage/index.d.ts.map +1 -0
- package/dist/checks/quality/observability/observability-coverage/index.js +4 -0
- package/dist/checks/quality/observability/observability-coverage/index.js.map +1 -0
- package/dist/checks/quality/observability/observability-coverage/logger-detector.d.ts +29 -0
- package/dist/checks/quality/observability/observability-coverage/logger-detector.d.ts.map +1 -0
- package/dist/checks/quality/observability/observability-coverage/logger-detector.js +111 -0
- package/dist/checks/quality/observability/observability-coverage/logger-detector.js.map +1 -0
- package/dist/checks/quality/observability/observability-coverage/types.d.ts +64 -0
- package/dist/checks/quality/observability/observability-coverage/types.d.ts.map +1 -0
- package/dist/checks/quality/observability/observability-coverage/types.js +6 -0
- package/dist/checks/quality/observability/observability-coverage/types.js.map +1 -0
- package/dist/checks/quality/observability/pii-exposure-in-logs.d.ts +22 -0
- package/dist/checks/quality/observability/pii-exposure-in-logs.d.ts.map +1 -0
- package/dist/checks/quality/observability/pii-exposure-in-logs.js +212 -0
- package/dist/checks/quality/observability/pii-exposure-in-logs.js.map +1 -0
- package/dist/checks/quality/observability/pii-exposure-in-logs.test.d.ts +11 -0
- package/dist/checks/quality/observability/pii-exposure-in-logs.test.d.ts.map +1 -0
- package/dist/checks/quality/observability/pii-exposure-in-logs.test.js +46 -0
- package/dist/checks/quality/observability/pii-exposure-in-logs.test.js.map +1 -0
- package/dist/checks/quality/patterns/__tests__/toctou-fp.test.d.ts +14 -0
- package/dist/checks/quality/patterns/__tests__/toctou-fp.test.d.ts.map +1 -0
- package/dist/checks/quality/patterns/__tests__/toctou-fp.test.js +61 -0
- package/dist/checks/quality/patterns/__tests__/toctou-fp.test.js.map +1 -0
- package/dist/checks/quality/patterns/async-waterfall-detection.d.ts +26 -0
- package/dist/checks/quality/patterns/async-waterfall-detection.d.ts.map +1 -0
- package/dist/checks/quality/patterns/async-waterfall-detection.js +410 -0
- package/dist/checks/quality/patterns/async-waterfall-detection.js.map +1 -0
- package/dist/checks/quality/patterns/dispose-pattern-completeness.d.ts +13 -0
- package/dist/checks/quality/patterns/dispose-pattern-completeness.d.ts.map +1 -0
- package/dist/checks/quality/patterns/dispose-pattern-completeness.js +220 -0
- package/dist/checks/quality/patterns/dispose-pattern-completeness.js.map +1 -0
- package/dist/checks/quality/patterns/error-handling-quality.d.ts +17 -0
- package/dist/checks/quality/patterns/error-handling-quality.d.ts.map +1 -0
- package/dist/checks/quality/patterns/error-handling-quality.js +335 -0
- package/dist/checks/quality/patterns/error-handling-quality.js.map +1 -0
- package/dist/checks/quality/patterns/index.d.ts +10 -0
- package/dist/checks/quality/patterns/index.d.ts.map +1 -0
- package/dist/checks/quality/patterns/index.js +10 -0
- package/dist/checks/quality/patterns/index.js.map +1 -0
- package/dist/checks/quality/patterns/lifecycle-cleanup-enforcement.d.ts +16 -0
- package/dist/checks/quality/patterns/lifecycle-cleanup-enforcement.d.ts.map +1 -0
- package/dist/checks/quality/patterns/lifecycle-cleanup-enforcement.js +205 -0
- package/dist/checks/quality/patterns/lifecycle-cleanup-enforcement.js.map +1 -0
- package/dist/checks/quality/patterns/result-pattern-consistency.d.ts +16 -0
- package/dist/checks/quality/patterns/result-pattern-consistency.d.ts.map +1 -0
- package/dist/checks/quality/patterns/result-pattern-consistency.js +328 -0
- package/dist/checks/quality/patterns/result-pattern-consistency.js.map +1 -0
- package/dist/checks/quality/patterns/silent-early-returns.d.ts +23 -0
- package/dist/checks/quality/patterns/silent-early-returns.d.ts.map +1 -0
- package/dist/checks/quality/patterns/silent-early-returns.js +266 -0
- package/dist/checks/quality/patterns/silent-early-returns.js.map +1 -0
- package/dist/checks/quality/patterns/stream-buffer-size-limits.d.ts +13 -0
- package/dist/checks/quality/patterns/stream-buffer-size-limits.d.ts.map +1 -0
- package/dist/checks/quality/patterns/stream-buffer-size-limits.js +163 -0
- package/dist/checks/quality/patterns/stream-buffer-size-limits.js.map +1 -0
- package/dist/checks/quality/patterns/throws-documentation.d.ts +23 -0
- package/dist/checks/quality/patterns/throws-documentation.d.ts.map +1 -0
- package/dist/checks/quality/patterns/throws-documentation.js +519 -0
- package/dist/checks/quality/patterns/throws-documentation.js.map +1 -0
- package/dist/checks/quality/patterns/toctou-race-condition.d.ts +48 -0
- package/dist/checks/quality/patterns/toctou-race-condition.d.ts.map +1 -0
- package/dist/checks/quality/patterns/toctou-race-condition.js +639 -0
- package/dist/checks/quality/patterns/toctou-race-condition.js.map +1 -0
- package/dist/checks/quality/stubbed-implementation-detection.d.ts +24 -0
- package/dist/checks/quality/stubbed-implementation-detection.d.ts.map +1 -0
- package/dist/checks/quality/stubbed-implementation-detection.js +355 -0
- package/dist/checks/quality/stubbed-implementation-detection.js.map +1 -0
- package/dist/checks/quality/unused-config-options.d.ts +12 -0
- package/dist/checks/quality/unused-config-options.d.ts.map +1 -0
- package/dist/checks/quality/unused-config-options.js +245 -0
- package/dist/checks/quality/unused-config-options.js.map +1 -0
- package/dist/checks/resilience/__tests__/callback-invocation-safe.test.d.ts +2 -0
- package/dist/checks/resilience/__tests__/callback-invocation-safe.test.d.ts.map +1 -0
- package/dist/checks/resilience/__tests__/callback-invocation-safe.test.js +79 -0
- package/dist/checks/resilience/__tests__/callback-invocation-safe.test.js.map +1 -0
- package/dist/checks/resilience/__tests__/context-leakage-fp.test.d.ts +12 -0
- package/dist/checks/resilience/__tests__/context-leakage-fp.test.d.ts.map +1 -0
- package/dist/checks/resilience/__tests__/context-leakage-fp.test.js +34 -0
- package/dist/checks/resilience/__tests__/context-leakage-fp.test.js.map +1 -0
- package/dist/checks/resilience/__tests__/context-mutation.test.d.ts +11 -0
- package/dist/checks/resilience/__tests__/context-mutation.test.d.ts.map +1 -0
- package/dist/checks/resilience/__tests__/context-mutation.test.js +54 -0
- package/dist/checks/resilience/__tests__/context-mutation.test.js.map +1 -0
- package/dist/checks/resilience/callback-invocation-safe.d.ts +34 -0
- package/dist/checks/resilience/callback-invocation-safe.d.ts.map +1 -0
- package/dist/checks/resilience/callback-invocation-safe.js +247 -0
- package/dist/checks/resilience/callback-invocation-safe.js.map +1 -0
- package/dist/checks/resilience/context-leakage.d.ts +25 -0
- package/dist/checks/resilience/context-leakage.d.ts.map +1 -0
- package/dist/checks/resilience/context-leakage.js +435 -0
- package/dist/checks/resilience/context-leakage.js.map +1 -0
- package/dist/checks/resilience/context-mutation.d.ts +21 -0
- package/dist/checks/resilience/context-mutation.d.ts.map +1 -0
- package/dist/checks/resilience/context-mutation.js +368 -0
- package/dist/checks/resilience/context-mutation.js.map +1 -0
- package/dist/checks/resilience/detached-promises.d.ts +40 -0
- package/dist/checks/resilience/detached-promises.d.ts.map +1 -0
- package/dist/checks/resilience/detached-promises.js +646 -0
- package/dist/checks/resilience/detached-promises.js.map +1 -0
- package/dist/checks/resilience/index.d.ts +7 -0
- package/dist/checks/resilience/index.d.ts.map +1 -0
- package/dist/checks/resilience/index.js +7 -0
- package/dist/checks/resilience/index.js.map +1 -0
- package/dist/checks/resilience/no-raw-fetch.d.ts +11 -0
- package/dist/checks/resilience/no-raw-fetch.d.ts.map +1 -0
- package/dist/checks/resilience/no-raw-fetch.js +110 -0
- package/dist/checks/resilience/no-raw-fetch.js.map +1 -0
- package/dist/checks/resilience/no-unbounded-concurrency.d.ts +11 -0
- package/dist/checks/resilience/no-unbounded-concurrency.d.ts.map +1 -0
- package/dist/checks/resilience/no-unbounded-concurrency.js +117 -0
- package/dist/checks/resilience/no-unbounded-concurrency.js.map +1 -0
- package/dist/checks/security/__tests__/sql-injection.test.d.ts +17 -0
- package/dist/checks/security/__tests__/sql-injection.test.d.ts.map +1 -0
- package/dist/checks/security/__tests__/sql-injection.test.js +97 -0
- package/dist/checks/security/__tests__/sql-injection.test.js.map +1 -0
- package/dist/checks/security/index.d.ts +4 -0
- package/dist/checks/security/index.d.ts.map +1 -0
- package/dist/checks/security/index.js +4 -0
- package/dist/checks/security/index.js.map +1 -0
- package/dist/checks/security/input-sanitization.d.ts +20 -0
- package/dist/checks/security/input-sanitization.d.ts.map +1 -0
- package/dist/checks/security/input-sanitization.js +255 -0
- package/dist/checks/security/input-sanitization.js.map +1 -0
- package/dist/checks/security/sql-injection.d.ts +24 -0
- package/dist/checks/security/sql-injection.d.ts.map +1 -0
- package/dist/checks/security/sql-injection.js +330 -0
- package/dist/checks/security/sql-injection.js.map +1 -0
- package/dist/checks/security/unsafe-secret-comparison.d.ts +17 -0
- package/dist/checks/security/unsafe-secret-comparison.d.ts.map +1 -0
- package/dist/checks/security/unsafe-secret-comparison.js +227 -0
- package/dist/checks/security/unsafe-secret-comparison.js.map +1 -0
- package/dist/checks/testing/index.d.ts +2 -0
- package/dist/checks/testing/index.d.ts.map +1 -0
- package/dist/checks/testing/index.js +2 -0
- package/dist/checks/testing/index.js.map +1 -0
- package/dist/checks/testing/mock-implementations-in-production.d.ts +12 -0
- package/dist/checks/testing/mock-implementations-in-production.d.ts.map +1 -0
- package/dist/checks/testing/mock-implementations-in-production.js +211 -0
- package/dist/checks/testing/mock-implementations-in-production.js.map +1 -0
- package/dist/display/architecture.d.ts +9 -0
- package/dist/display/architecture.d.ts.map +1 -0
- package/dist/display/architecture.js +18 -0
- package/dist/display/architecture.js.map +1 -0
- package/dist/display/index.d.ts +20 -0
- package/dist/display/index.d.ts.map +1 -0
- package/dist/display/index.js +30 -0
- package/dist/display/index.js.map +1 -0
- package/dist/display/quality.d.ts +7 -0
- package/dist/display/quality.d.ts.map +1 -0
- package/dist/display/quality.js +39 -0
- package/dist/display/quality.js.map +1 -0
- package/dist/display/resilience.d.ts +7 -0
- package/dist/display/resilience.d.ts.map +1 -0
- package/dist/display/resilience.js +13 -0
- package/dist/display/resilience.js.map +1 -0
- package/dist/display/security-testing.d.ts +9 -0
- package/dist/display/security-testing.d.ts.map +1 -0
- package/dist/display/security-testing.js +14 -0
- package/dist/display/security-testing.js.map +1 -0
- package/dist/display/types.d.ts +6 -0
- package/dist/display/types.d.ts.map +1 -0
- package/dist/display/types.js +6 -0
- package/dist/display/types.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/package.json +55 -0
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
// @fitness-ignore-file no-generic-error -- Generic errors appropriate in this context
|
|
2
|
+
/**
|
|
3
|
+
* @fileoverview Detect unsanitized user input usage
|
|
4
|
+
*
|
|
5
|
+
* Uses AST analysis to detect unsanitized user input in HTML injection,
|
|
6
|
+
* command injection, and path traversal contexts. AST context eliminates
|
|
7
|
+
* false positives from regex definitions, string constants, and comments.
|
|
8
|
+
*
|
|
9
|
+
*
|
|
10
|
+
*/
|
|
11
|
+
import { defineCheck } from '@opensip-cli/fitness';
|
|
12
|
+
import { parseSource, walkNodes, getLineNumber } from '@opensip-cli/lang-typescript';
|
|
13
|
+
import * as ts from 'typescript';
|
|
14
|
+
/** Names of user input sources on request objects */
|
|
15
|
+
const USER_INPUT_PROPERTIES = new Set(['body', 'params', 'query']);
|
|
16
|
+
/** Names of request objects */
|
|
17
|
+
const REQUEST_OBJECT_NAMES = new Set(['request', 'req']);
|
|
18
|
+
/** Dangerous command execution function names */
|
|
19
|
+
const EXEC_FUNCTIONS = new Set([
|
|
20
|
+
'exec',
|
|
21
|
+
'execSync',
|
|
22
|
+
'spawn',
|
|
23
|
+
'spawnSync',
|
|
24
|
+
'execFile',
|
|
25
|
+
'execFileSync',
|
|
26
|
+
]);
|
|
27
|
+
/** Dangerous file system function names */
|
|
28
|
+
const FS_FUNCTIONS = new Set([
|
|
29
|
+
'readFile',
|
|
30
|
+
'readFileSync',
|
|
31
|
+
'writeFile',
|
|
32
|
+
'writeFileSync',
|
|
33
|
+
'unlink',
|
|
34
|
+
'unlinkSync',
|
|
35
|
+
'rmdir',
|
|
36
|
+
'rmdirSync',
|
|
37
|
+
'mkdir',
|
|
38
|
+
'mkdirSync',
|
|
39
|
+
]);
|
|
40
|
+
/**
|
|
41
|
+
* Check if an expression tree references user input (req.body, req.params, req.query).
|
|
42
|
+
* Walks the subtree of the given node looking for property access chains like
|
|
43
|
+
* `request.body.field` or `req.query.param`.
|
|
44
|
+
*/
|
|
45
|
+
function referencesUserInput(node) {
|
|
46
|
+
if (ts.isPropertyAccessExpression(node)) {
|
|
47
|
+
// Check for req.body, req.params, req.query
|
|
48
|
+
if (USER_INPUT_PROPERTIES.has(node.name.text) &&
|
|
49
|
+
ts.isIdentifier(node.expression) &&
|
|
50
|
+
REQUEST_OBJECT_NAMES.has(node.expression.text)) {
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
// Check for deeper access: req.body.field
|
|
54
|
+
if (ts.isPropertyAccessExpression(node.expression)) {
|
|
55
|
+
return referencesUserInput(node.expression);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
// Check children
|
|
59
|
+
let found = false;
|
|
60
|
+
ts.forEachChild(node, (child) => {
|
|
61
|
+
if (!found && referencesUserInput(child)) {
|
|
62
|
+
found = true;
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
return found;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Check if a node is inside a string literal or regex definition,
|
|
69
|
+
* which would indicate this is a pattern definition, not actual code.
|
|
70
|
+
*/
|
|
71
|
+
function isInStringOrRegex(node) {
|
|
72
|
+
let current = node.parent;
|
|
73
|
+
while (!ts.isSourceFile(current)) {
|
|
74
|
+
/* v8 ignore next -- defensive AST/type guard */
|
|
75
|
+
if (ts.isStringLiteral(current) || ts.isRegularExpressionLiteral(current))
|
|
76
|
+
return true;
|
|
77
|
+
/* v8 ignore next -- defensive AST/type guard */
|
|
78
|
+
if (ts.isNoSubstitutionTemplateLiteral(current))
|
|
79
|
+
return true;
|
|
80
|
+
current = current.parent;
|
|
81
|
+
}
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
function truncateMatch(node, maxLength = 200) {
|
|
85
|
+
const text = node.getText();
|
|
86
|
+
/* v8 ignore next -- defensive AST/type guard */
|
|
87
|
+
return text.length > maxLength ? text.slice(0, maxLength) + '...' : text;
|
|
88
|
+
}
|
|
89
|
+
function checkInnerHtmlAssignment(node, sourceFile, filePath) {
|
|
90
|
+
if (ts.isBinaryExpression(node) &&
|
|
91
|
+
(node.operatorToken.kind === ts.SyntaxKind.EqualsToken ||
|
|
92
|
+
node.operatorToken.kind === ts.SyntaxKind.PlusEqualsToken) &&
|
|
93
|
+
ts.isPropertyAccessExpression(node.left) &&
|
|
94
|
+
node.left.name.text === 'innerHTML' &&
|
|
95
|
+
referencesUserInput(node.right)) {
|
|
96
|
+
return {
|
|
97
|
+
line: getLineNumber(node, sourceFile),
|
|
98
|
+
column: 0,
|
|
99
|
+
message: 'innerHTML with potential user input - use textContent or sanitize',
|
|
100
|
+
severity: 'error',
|
|
101
|
+
suggestion: 'Use textContent for plain text: element.textContent = userInput. For HTML, use DOMPurify: element.innerHTML = DOMPurify.sanitize(userInput);',
|
|
102
|
+
match: node.getText(),
|
|
103
|
+
filePath,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
function checkDangerouslySetInnerHTML(node, sourceFile, filePath) {
|
|
109
|
+
if (ts.isJsxAttribute(node) &&
|
|
110
|
+
ts.isIdentifier(node.name) &&
|
|
111
|
+
node.name.text === 'dangerouslySetInnerHTML') {
|
|
112
|
+
return {
|
|
113
|
+
line: getLineNumber(node, sourceFile),
|
|
114
|
+
column: 0,
|
|
115
|
+
message: 'dangerouslySetInnerHTML usage - ensure input is sanitized',
|
|
116
|
+
severity: 'warning',
|
|
117
|
+
suggestion: 'Sanitize content before using dangerouslySetInnerHTML: dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(content) }}. Consider using markdown renderers with XSS protection.',
|
|
118
|
+
match: node.getText(),
|
|
119
|
+
filePath,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
function getCallFunctionName(node) {
|
|
125
|
+
const callee = node.expression;
|
|
126
|
+
if (ts.isIdentifier(callee))
|
|
127
|
+
return callee.text;
|
|
128
|
+
/* v8 ignore next -- defensive AST/type guard */
|
|
129
|
+
if (ts.isPropertyAccessExpression(callee))
|
|
130
|
+
return callee.name.text;
|
|
131
|
+
return '';
|
|
132
|
+
}
|
|
133
|
+
function checkUnsanitizedCallArgs(node, sourceFile, filePath, rule) {
|
|
134
|
+
const { functionNames, message, suggestion } = rule;
|
|
135
|
+
const functionName = getCallFunctionName(node);
|
|
136
|
+
if (!functionNames.has(functionName))
|
|
137
|
+
return null;
|
|
138
|
+
/* v8 ignore next -- defensive AST/type guard */
|
|
139
|
+
if (isInStringOrRegex(node))
|
|
140
|
+
return null;
|
|
141
|
+
for (const arg of node.arguments) {
|
|
142
|
+
if (referencesUserInput(arg)) {
|
|
143
|
+
return {
|
|
144
|
+
line: getLineNumber(node, sourceFile),
|
|
145
|
+
column: 0,
|
|
146
|
+
message,
|
|
147
|
+
severity: 'error',
|
|
148
|
+
suggestion,
|
|
149
|
+
match: truncateMatch(node),
|
|
150
|
+
filePath,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return null;
|
|
155
|
+
}
|
|
156
|
+
function checkHtmlTemplateInterpolation(node, sourceFile, filePath) {
|
|
157
|
+
if (!ts.isTemplateExpression(node))
|
|
158
|
+
return null;
|
|
159
|
+
if (!/^\s*<[a-zA-Z]/.test(node.head.text))
|
|
160
|
+
return null;
|
|
161
|
+
for (const span of node.templateSpans) {
|
|
162
|
+
if (referencesUserInput(span.expression)) {
|
|
163
|
+
return {
|
|
164
|
+
line: getLineNumber(node, sourceFile),
|
|
165
|
+
column: 0,
|
|
166
|
+
message: 'Unsanitized user input in HTML template - use html-escaper',
|
|
167
|
+
severity: 'error',
|
|
168
|
+
suggestion: 'Use html-escaper or DOMPurify to sanitize user input before inserting into HTML: import { escape } from "html-escaper"; const safeHtml = escape(userInput);',
|
|
169
|
+
match: truncateMatch(node),
|
|
170
|
+
filePath,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Check: security/input-sanitization
|
|
178
|
+
*
|
|
179
|
+
* Detects user input used without proper sanitization using AST analysis.
|
|
180
|
+
* Walks the AST to find actual innerHTML assignments, exec/spawn calls,
|
|
181
|
+
* and file operations with user input references.
|
|
182
|
+
*
|
|
183
|
+
*
|
|
184
|
+
*/
|
|
185
|
+
export const inputSanitization = defineCheck({
|
|
186
|
+
id: '31ef5173-a102-4a37-bc14-3f5bb08f9688',
|
|
187
|
+
slug: 'input-sanitization',
|
|
188
|
+
scope: { languages: ['typescript'], concerns: ['backend', 'server'] },
|
|
189
|
+
// 'raw', not 'strip-strings': checkHtmlTemplateInterpolation classifies a
|
|
190
|
+
// template as "HTML" by testing the head.text prefix (/^\s*<[a-zA-Z]/). Under
|
|
191
|
+
// strip-strings the head content is blanked, so all such templates would be
|
|
192
|
+
// silently ignored. The main sinks use AST expression walks (unaffected).
|
|
193
|
+
contentFilter: 'raw',
|
|
194
|
+
description: 'Detect unsanitized user input usage',
|
|
195
|
+
longDescription: `**Purpose:** Detects user input from request objects (req.body, req.params, req.query) flowing unsanitized into dangerous sinks, using AST analysis to avoid false positives.
|
|
196
|
+
|
|
197
|
+
**Detects:**
|
|
198
|
+
- innerHTML assignments with user input: \`element.innerHTML = req.body.content\`
|
|
199
|
+
- \`dangerouslySetInnerHTML\` JSX attribute usage
|
|
200
|
+
- User input passed to shell commands: \`exec()\`, \`execSync()\`, \`spawn()\`, \`spawnSync()\`, \`execFile()\`, \`execFileSync()\`
|
|
201
|
+
- User input in file system operations: \`readFile()\`, \`writeFile()\`, \`unlink()\`, etc. (path traversal)
|
|
202
|
+
- User input interpolated into HTML template literals: \`\`<div>\${req.body.name}</div>\`\`
|
|
203
|
+
|
|
204
|
+
**Why it matters:** Unsanitized user input leads to XSS, command injection, and path traversal vulnerabilities. AST-level detection catches real data flow issues while ignoring string constants and comments.
|
|
205
|
+
|
|
206
|
+
**Scope:** General best practice. Analyzes each file individually using TypeScript AST.`,
|
|
207
|
+
tags: ['security', 'injection', 'sanitization'],
|
|
208
|
+
fileTypes: ['ts'],
|
|
209
|
+
confidence: 'high',
|
|
210
|
+
analyze(content, filePath) {
|
|
211
|
+
const sourceFile = parseSource(content, filePath);
|
|
212
|
+
/* v8 ignore next -- defensive guard */
|
|
213
|
+
if (!sourceFile)
|
|
214
|
+
return [];
|
|
215
|
+
const violations = [];
|
|
216
|
+
walkNodes(sourceFile, (node) => {
|
|
217
|
+
const innerHtml = checkInnerHtmlAssignment(node, sourceFile, filePath);
|
|
218
|
+
if (innerHtml) {
|
|
219
|
+
violations.push(innerHtml);
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
const dangerousHtml = checkDangerouslySetInnerHTML(node, sourceFile, filePath);
|
|
223
|
+
if (dangerousHtml) {
|
|
224
|
+
violations.push(dangerousHtml);
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
if (ts.isCallExpression(node)) {
|
|
228
|
+
const cmdInjection = checkUnsanitizedCallArgs(node, sourceFile, filePath, {
|
|
229
|
+
functionNames: EXEC_FUNCTIONS,
|
|
230
|
+
message: 'User input passed to shell command - potential command injection',
|
|
231
|
+
suggestion: 'Never pass user input directly to shell commands. Use execFile with separate arguments array, or validate input against a strict allowlist. Consider using child_process.spawn with shell: false.',
|
|
232
|
+
});
|
|
233
|
+
if (cmdInjection) {
|
|
234
|
+
violations.push(cmdInjection);
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
const pathTraversal = checkUnsanitizedCallArgs(node, sourceFile, filePath, {
|
|
238
|
+
functionNames: FS_FUNCTIONS,
|
|
239
|
+
message: 'User input in file path - potential path traversal vulnerability',
|
|
240
|
+
suggestion: 'Validate file paths with path.resolve and ensure they stay within allowed directories: const safePath = path.resolve(baseDir, userInput); if (!safePath.startsWith(baseDir)) throw new Error("Invalid path");',
|
|
241
|
+
});
|
|
242
|
+
if (pathTraversal) {
|
|
243
|
+
violations.push(pathTraversal);
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
const htmlTemplate = checkHtmlTemplateInterpolation(node, sourceFile, filePath);
|
|
248
|
+
if (htmlTemplate) {
|
|
249
|
+
violations.push(htmlTemplate);
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
return violations;
|
|
253
|
+
},
|
|
254
|
+
});
|
|
255
|
+
//# sourceMappingURL=input-sanitization.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"input-sanitization.js","sourceRoot":"","sources":["../../../src/checks/security/input-sanitization.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Detect potential SQL injection vulnerabilities
|
|
3
|
+
*
|
|
4
|
+
* Uses AST analysis to find SQL injection patterns in template literals and
|
|
5
|
+
* string concatenation. AST context eliminates false positives from suggestion
|
|
6
|
+
* text, error messages, and comments.
|
|
7
|
+
*/
|
|
8
|
+
import { type CheckViolation } from '@opensip-cli/fitness';
|
|
9
|
+
/**
|
|
10
|
+
* Check: security/sql-injection
|
|
11
|
+
*
|
|
12
|
+
* Detects potential SQL injection vulnerabilities using AST analysis.
|
|
13
|
+
* Walks template literals and string concatenation to find SQL patterns,
|
|
14
|
+
* while filtering out suggestion text, messages, and tagged templates.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Pure analysis function. Exported so unit tests can exercise the
|
|
18
|
+
* detection logic without standing up the full Check framework
|
|
19
|
+
* (defineCheck wraps `analyze` into an `execute` closure that
|
|
20
|
+
* requires an ExecutionContext to invoke).
|
|
21
|
+
*/
|
|
22
|
+
export declare function analyzeSqlInjection(content: string, filePath: string): CheckViolation[];
|
|
23
|
+
export declare const sqlInjection: import("@opensip-cli/fitness").Check;
|
|
24
|
+
//# sourceMappingURL=sql-injection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sql-injection.d.ts","sourceRoot":"","sources":["../../../src/checks/security/sql-injection.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAe,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAkTxE;;;;;;GAMG;AACH;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,cAAc,EAAE,CAcvF;AAED,eAAO,MAAM,YAAY,sCAuBvB,CAAC"}
|
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Detect potential SQL injection vulnerabilities
|
|
3
|
+
*
|
|
4
|
+
* Uses AST analysis to find SQL injection patterns in template literals and
|
|
5
|
+
* string concatenation. AST context eliminates false positives from suggestion
|
|
6
|
+
* text, error messages, and comments.
|
|
7
|
+
*/
|
|
8
|
+
import { defineCheck } from '@opensip-cli/fitness';
|
|
9
|
+
import { parseSource, walkNodes, getLineNumber } from '@opensip-cli/lang-typescript';
|
|
10
|
+
import * as ts from 'typescript';
|
|
11
|
+
/**
|
|
12
|
+
* SQL structural patterns indicating actual SQL statements (not casual English).
|
|
13
|
+
* Requires SQL keyword + structural follow-up: SELECT...FROM, INSERT INTO, etc.
|
|
14
|
+
*/
|
|
15
|
+
const SQL_STRUCTURE_PATTERN =
|
|
16
|
+
// eslint-disable-next-line sonarjs/regex-complexity -- enumerates SQL DML/DDL shapes in a single bounded alternation; splitting fragments the rule's intent
|
|
17
|
+
/\b(?:SELECT\s+[\w.*]+\s+FROM|INSERT\s+INTO|UPDATE\s+\w+\s+SET|DELETE\s+FROM|DROP\s+(?:TABLE|INDEX|DATABASE|VIEW)|ALTER\s+TABLE|CREATE\s+(?:TABLE|INDEX|DATABASE|VIEW)|TRUNCATE\s+(?:TABLE)?)\b/i;
|
|
18
|
+
/** Simpler pattern for SQL keywords at start of string concatenation */
|
|
19
|
+
const SQL_KEYWORD_PATTERN = /^\s*(?:SELECT|INSERT|UPDATE|DELETE|DROP|ALTER|CREATE|TRUNCATE)\b/i;
|
|
20
|
+
/**
|
|
21
|
+
* SQL clause keywords for detecting concatenation in WHERE/SET/VALUES clauses.
|
|
22
|
+
*
|
|
23
|
+
* Case-SENSITIVE intentionally — lowercase `and`, `or`, `set`, `values`,
|
|
24
|
+
* `where` are extremely common English words and produce massive false-
|
|
25
|
+
* positive rates against CLI help-text strings (`'Usage: ...\n' +
|
|
26
|
+
* 'AND swapped into tenant.keys'`). Real SQL keyword usage in code is
|
|
27
|
+
* conventionally uppercase; the few projects that lowercase them can
|
|
28
|
+
* either uppercase or pragma per-site. (See checkConcatenationInjection
|
|
29
|
+
* for the additional "walk the concat chain for a real SQL keyword"
|
|
30
|
+
* filter that prevents arm-3 from firing on incidental WHERE/AND inside
|
|
31
|
+
* non-SQL text.)
|
|
32
|
+
*/
|
|
33
|
+
const SQL_CLAUSE_PATTERN = /\b(?:WHERE|AND|OR|SET|VALUES)\b/;
|
|
34
|
+
/** Safe tagged template tags that use parameterized queries */
|
|
35
|
+
const SAFE_TEMPLATE_TAGS = new Set(['sql', 'query', 'raw']);
|
|
36
|
+
/** Safe object property names where SQL-like words are just messages */
|
|
37
|
+
const SUGGESTION_PROPERTY_NAMES = new Set([
|
|
38
|
+
'message',
|
|
39
|
+
'msg',
|
|
40
|
+
'suggestion',
|
|
41
|
+
'description',
|
|
42
|
+
'help',
|
|
43
|
+
'hint',
|
|
44
|
+
'detail',
|
|
45
|
+
'title',
|
|
46
|
+
'label',
|
|
47
|
+
'text',
|
|
48
|
+
'placeholder',
|
|
49
|
+
'tooltip',
|
|
50
|
+
'caption',
|
|
51
|
+
'summary',
|
|
52
|
+
]);
|
|
53
|
+
/**
|
|
54
|
+
* Check if a template expression is inside a tagged template literal.
|
|
55
|
+
* Tagged templates like sql`...` or db.query`...` use parameterized queries.
|
|
56
|
+
*/
|
|
57
|
+
function isInTaggedTemplate(node) {
|
|
58
|
+
let current = node.parent;
|
|
59
|
+
while (!ts.isSourceFile(current)) {
|
|
60
|
+
/* v8 ignore next -- defensive AST/type guard */
|
|
61
|
+
if (ts.isTaggedTemplateExpression(current)) {
|
|
62
|
+
const tag = current.tag;
|
|
63
|
+
if (ts.isIdentifier(tag) && SAFE_TEMPLATE_TAGS.has(tag.text))
|
|
64
|
+
return true;
|
|
65
|
+
if (ts.isPropertyAccessExpression(tag) && SAFE_TEMPLATE_TAGS.has(tag.name.text))
|
|
66
|
+
return true;
|
|
67
|
+
// Any tagged template is likely using parameterized queries
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
current = current.parent;
|
|
71
|
+
}
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Check if a node is inside an object literal property used for messages/suggestions.
|
|
76
|
+
* Template literals in properties like { message: `...`, suggestion: `...` } are not SQL.
|
|
77
|
+
*/
|
|
78
|
+
function isInSuggestionProperty(node) {
|
|
79
|
+
let current = node.parent;
|
|
80
|
+
while (!ts.isSourceFile(current)) {
|
|
81
|
+
if (ts.isPropertyAssignment(current) &&
|
|
82
|
+
ts.isIdentifier(current.name) &&
|
|
83
|
+
SUGGESTION_PROPERTY_NAMES.has(current.name.text.toLowerCase())) {
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
current = current.parent;
|
|
87
|
+
}
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Check if a node is a direct argument to a .query() call.
|
|
92
|
+
*/
|
|
93
|
+
function isInQueryCall(node) {
|
|
94
|
+
const parent = node.parent;
|
|
95
|
+
return (ts.isCallExpression(parent) &&
|
|
96
|
+
ts.isPropertyAccessExpression(parent.expression) &&
|
|
97
|
+
parent.expression.name.text === 'query');
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Walk the binary-`+` concat chain rooted at `node` and collect every
|
|
101
|
+
* string-literal segment's text. Used by `checkConcatenationInjection`
|
|
102
|
+
* to gate arm-3 — a right-side string containing a clause keyword
|
|
103
|
+
* (WHERE/AND/OR/SET/VALUES) is only treated as SQL when the SAME
|
|
104
|
+
* concatenation also has at least one segment that starts with a real
|
|
105
|
+
* SQL statement keyword (SELECT/INSERT/...).
|
|
106
|
+
*
|
|
107
|
+
* Why this matters: without the gate, the loose right-side check
|
|
108
|
+
* fires on `cli.info('Usage: ...\n' + 'AND continues here\n')` because
|
|
109
|
+
* "AND" appears in English help text. The gate requires the same
|
|
110
|
+
* concat chain to also contain a "SELECT * FROM" or similar real-SQL
|
|
111
|
+
* fragment, which CLI help text never has.
|
|
112
|
+
*
|
|
113
|
+
* Walks both up (ancestor +) and down (descendant +) from `node` so a
|
|
114
|
+
* mid-chain finding still sees the whole expression.
|
|
115
|
+
*/
|
|
116
|
+
function collectConcatChainStrings(node) {
|
|
117
|
+
const strings = [];
|
|
118
|
+
// Walk up to the root of the contiguous + chain.
|
|
119
|
+
let root = node;
|
|
120
|
+
while (ts.isBinaryExpression(root.parent) &&
|
|
121
|
+
root.parent.operatorToken.kind === ts.SyntaxKind.PlusToken) {
|
|
122
|
+
root = root.parent;
|
|
123
|
+
}
|
|
124
|
+
// Walk down collecting every string-literal leaf.
|
|
125
|
+
function collect(n) {
|
|
126
|
+
if (ts.isBinaryExpression(n) && n.operatorToken.kind === ts.SyntaxKind.PlusToken) {
|
|
127
|
+
collect(n.left);
|
|
128
|
+
collect(n.right);
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
if (ts.isStringLiteral(n) || ts.isNoSubstitutionTemplateLiteral(n)) {
|
|
132
|
+
strings.push(n.text);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
collect(root);
|
|
136
|
+
return strings;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* True iff the concat chain rooted at the parent of `node` contains
|
|
140
|
+
* at least one string segment that starts with a real SQL keyword
|
|
141
|
+
* (SELECT/INSERT/...). This is the "this is actually SQL" sanity check
|
|
142
|
+
* for arm-3 of checkConcatenationInjection.
|
|
143
|
+
*/
|
|
144
|
+
function concatChainHasSqlKeyword(node) {
|
|
145
|
+
for (const s of collectConcatChainStrings(node)) {
|
|
146
|
+
if (SQL_KEYWORD_PATTERN.test(s))
|
|
147
|
+
return true;
|
|
148
|
+
}
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Known CLI-output property-access call patterns: `cli.info(...)`,
|
|
153
|
+
* `cli.error(...)`, `console.log(...)`, `logger.warn(...)`, etc.
|
|
154
|
+
* Binary-string-concat arguments to these calls are never SQL.
|
|
155
|
+
*/
|
|
156
|
+
const OUTPUT_METHOD_NAMES = new Set([
|
|
157
|
+
'log',
|
|
158
|
+
'info',
|
|
159
|
+
'warn',
|
|
160
|
+
'error',
|
|
161
|
+
'debug',
|
|
162
|
+
'trace',
|
|
163
|
+
'fatal',
|
|
164
|
+
'print',
|
|
165
|
+
'println',
|
|
166
|
+
'raw',
|
|
167
|
+
'write',
|
|
168
|
+
'writeln',
|
|
169
|
+
]);
|
|
170
|
+
/**
|
|
171
|
+
* True iff `node` is an argument (direct or wrapped) to an output-style
|
|
172
|
+
* call expression (`cli.info(...)`, `console.log(...)`, `logger.warn(...)`).
|
|
173
|
+
* These call sites carry user-facing text, not SQL — concatenation
|
|
174
|
+
* inside them is help/status text composition.
|
|
175
|
+
*/
|
|
176
|
+
function isInOutputCall(node) {
|
|
177
|
+
let current = node.parent;
|
|
178
|
+
while (!ts.isSourceFile(current)) {
|
|
179
|
+
if (ts.isCallExpression(current)) {
|
|
180
|
+
const callee = current.expression;
|
|
181
|
+
return (ts.isPropertyAccessExpression(callee) &&
|
|
182
|
+
ts.isIdentifier(callee.name) &&
|
|
183
|
+
OUTPUT_METHOD_NAMES.has(callee.name.text));
|
|
184
|
+
}
|
|
185
|
+
current = current.parent;
|
|
186
|
+
}
|
|
187
|
+
return false;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Get the full text content of a template expression (head + spans).
|
|
191
|
+
*/
|
|
192
|
+
function getTemplateText(node) {
|
|
193
|
+
const parts = [node.head.text];
|
|
194
|
+
for (const span of node.templateSpans) {
|
|
195
|
+
// @fitness-ignore-next-line performance-anti-patterns -- string literal placeholder for template span, not a spread operator
|
|
196
|
+
parts.push('${...}', span.literal.text);
|
|
197
|
+
}
|
|
198
|
+
return parts.join('');
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Check a template expression node for SQL injection via interpolation.
|
|
202
|
+
*/
|
|
203
|
+
function checkTemplateInjection(node, sourceFile, filePath, violations) {
|
|
204
|
+
if (!ts.isTemplateExpression(node))
|
|
205
|
+
return;
|
|
206
|
+
/* v8 ignore next -- defensive AST/type guard */
|
|
207
|
+
if (isInTaggedTemplate(node))
|
|
208
|
+
return;
|
|
209
|
+
/* v8 ignore next -- defensive AST/type guard */
|
|
210
|
+
if (isInSuggestionProperty(node))
|
|
211
|
+
return;
|
|
212
|
+
/* v8 ignore next -- defensive AST/type guard */
|
|
213
|
+
if (isInOutputCall(node))
|
|
214
|
+
return;
|
|
215
|
+
const templateText = getTemplateText(node);
|
|
216
|
+
if (!SQL_STRUCTURE_PATTERN.test(templateText))
|
|
217
|
+
return;
|
|
218
|
+
const line = getLineNumber(node, sourceFile);
|
|
219
|
+
const matchText = node.getText();
|
|
220
|
+
const isQueryArg = isInQueryCall(node);
|
|
221
|
+
violations.push({
|
|
222
|
+
line,
|
|
223
|
+
column: 0,
|
|
224
|
+
message: isQueryArg
|
|
225
|
+
? 'Potential SQL injection: raw query with template interpolation'
|
|
226
|
+
: 'Potential SQL injection: template literal with SQL and interpolation detected',
|
|
227
|
+
severity: 'error',
|
|
228
|
+
suggestion: 'Use parameterized queries: db.query("SELECT * FROM users WHERE id = $1", [userId]). Never interpolate user input directly into SQL strings.',
|
|
229
|
+
match: matchText.length > 200 ? matchText.slice(0, 200) + '...' : matchText,
|
|
230
|
+
filePath,
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Check a binary expression node for SQL injection via string concatenation.
|
|
235
|
+
*/
|
|
236
|
+
function checkConcatenationInjection(node, sourceFile, filePath, violations) {
|
|
237
|
+
if (!ts.isBinaryExpression(node))
|
|
238
|
+
return;
|
|
239
|
+
if (node.operatorToken.kind !== ts.SyntaxKind.PlusToken)
|
|
240
|
+
return;
|
|
241
|
+
if (isInSuggestionProperty(node))
|
|
242
|
+
return;
|
|
243
|
+
if (isInOutputCall(node))
|
|
244
|
+
return;
|
|
245
|
+
const leftIsString = ts.isStringLiteral(node.left);
|
|
246
|
+
const rightIsString = ts.isStringLiteral(node.right);
|
|
247
|
+
if (!leftIsString && !rightIsString)
|
|
248
|
+
return;
|
|
249
|
+
const leftText = leftIsString ? node.left.text : '';
|
|
250
|
+
const rightText = rightIsString ? node.right.text : '';
|
|
251
|
+
if (leftIsString && SQL_KEYWORD_PATTERN.test(leftText) && !rightIsString) {
|
|
252
|
+
violations.push({
|
|
253
|
+
line: getLineNumber(node, sourceFile),
|
|
254
|
+
column: 0,
|
|
255
|
+
message: 'Potential SQL injection: SQL string concatenation detected',
|
|
256
|
+
severity: 'error',
|
|
257
|
+
suggestion: 'Use parameterized queries instead of string concatenation. With TypeORM: createQueryBuilder().where("id = :id", { id }). With raw queries: query("SELECT * FROM t WHERE x = $1", [x]).',
|
|
258
|
+
match: node.getText(),
|
|
259
|
+
filePath,
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
if (rightIsString &&
|
|
263
|
+
SQL_CLAUSE_PATTERN.test(rightText) &&
|
|
264
|
+
!leftIsString &&
|
|
265
|
+
// Gate: the concat chain must also contain a real SQL keyword
|
|
266
|
+
// somewhere (SELECT/INSERT/...). Without this, the loose clause
|
|
267
|
+
// pattern fires on incidental WHERE/AND inside non-SQL text
|
|
268
|
+
// (CLI help strings, error message composition, etc.).
|
|
269
|
+
concatChainHasSqlKeyword(node)) {
|
|
270
|
+
violations.push({
|
|
271
|
+
line: getLineNumber(node, sourceFile),
|
|
272
|
+
column: 0,
|
|
273
|
+
message: 'Potential SQL injection: string concatenation in SQL clause detected',
|
|
274
|
+
severity: 'error',
|
|
275
|
+
suggestion: 'Use parameterized queries for all user-supplied values. Never concatenate strings to build WHERE, AND, OR, SET, or VALUES clauses.',
|
|
276
|
+
match: node.getText(),
|
|
277
|
+
filePath,
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Check: security/sql-injection
|
|
283
|
+
*
|
|
284
|
+
* Detects potential SQL injection vulnerabilities using AST analysis.
|
|
285
|
+
* Walks template literals and string concatenation to find SQL patterns,
|
|
286
|
+
* while filtering out suggestion text, messages, and tagged templates.
|
|
287
|
+
*/
|
|
288
|
+
/**
|
|
289
|
+
* Pure analysis function. Exported so unit tests can exercise the
|
|
290
|
+
* detection logic without standing up the full Check framework
|
|
291
|
+
* (defineCheck wraps `analyze` into an `execute` closure that
|
|
292
|
+
* requires an ExecutionContext to invoke).
|
|
293
|
+
*/
|
|
294
|
+
export function analyzeSqlInjection(content, filePath) {
|
|
295
|
+
const sourceFile = parseSource(content, filePath);
|
|
296
|
+
/* v8 ignore next -- defensive guard */
|
|
297
|
+
if (!sourceFile)
|
|
298
|
+
return [];
|
|
299
|
+
const violations = [];
|
|
300
|
+
walkNodes(sourceFile, (node) => {
|
|
301
|
+
// @lazy-ok -- synchronous callback; no awaits in analyze(); "resolved async result" in suggestion text triggers false positive
|
|
302
|
+
checkTemplateInjection(node, sourceFile, filePath, violations);
|
|
303
|
+
checkConcatenationInjection(node, sourceFile, filePath, violations);
|
|
304
|
+
});
|
|
305
|
+
return violations;
|
|
306
|
+
}
|
|
307
|
+
export const sqlInjection = defineCheck({
|
|
308
|
+
id: '73c198ff-3d68-4e9b-a2aa-9e5d511cd89c',
|
|
309
|
+
slug: 'sql-injection',
|
|
310
|
+
scope: { languages: ['typescript'], concerns: ['backend', 'server'] },
|
|
311
|
+
contentFilter: 'raw',
|
|
312
|
+
description: 'Detect potential SQL injection vulnerabilities',
|
|
313
|
+
longDescription: `**Purpose:** Detects potential SQL injection vulnerabilities by using AST analysis to find user-supplied values interpolated or concatenated into SQL strings.
|
|
314
|
+
|
|
315
|
+
**Detects:**
|
|
316
|
+
- Template literals containing SQL structure patterns (SELECT...FROM, INSERT INTO, UPDATE...SET, DELETE FROM, DROP, ALTER, CREATE, TRUNCATE) with \`\${...}\` interpolation — excluding safe tagged templates (\`sql\`, \`query\`, \`raw\`) and message/suggestion properties
|
|
317
|
+
- String concatenation starting with SQL keywords (\`"SELECT " + variable\`)
|
|
318
|
+
- String concatenation appending SQL clause keywords (\`variable + " WHERE ..."\`)
|
|
319
|
+
|
|
320
|
+
**Why it matters:** SQL injection remains a top web vulnerability (OWASP Top 10). A single unparameterized query can expose or destroy an entire database.
|
|
321
|
+
|
|
322
|
+
**Scope:** General best practice. Analyzes each file individually using TypeScript AST. Excludes migrations and seed files.`,
|
|
323
|
+
tags: ['security', 'injection', 'sql', 'database'],
|
|
324
|
+
fileTypes: ['ts'],
|
|
325
|
+
confidence: 'high',
|
|
326
|
+
analyze(content, filePath) {
|
|
327
|
+
return analyzeSqlInjection(content, filePath);
|
|
328
|
+
},
|
|
329
|
+
});
|
|
330
|
+
//# sourceMappingURL=sql-injection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sql-injection.js","sourceRoot":"","sources":["../../../src/checks/security/sql-injection.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Detect unsafe equality comparisons on secret/token values
|
|
3
|
+
*
|
|
4
|
+
* Finds binary equality operators (=== / !==) applied to variables whose names
|
|
5
|
+
* suggest they hold cryptographic secrets (token, secret, signature, password,
|
|
6
|
+
* key). Such comparisons are vulnerable to timing attacks and must use a
|
|
7
|
+
* constant-time comparison function like safeCompare().
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Check: security/unsafe-secret-comparison
|
|
11
|
+
*
|
|
12
|
+
* Detects usage of === or !== to compare variables whose names suggest they
|
|
13
|
+
* hold cryptographic secrets. Such comparisons are vulnerable to timing
|
|
14
|
+
* side-channel attacks.
|
|
15
|
+
*/
|
|
16
|
+
export declare const unsafeSecretComparison: import("@opensip-cli/fitness").Check;
|
|
17
|
+
//# sourceMappingURL=unsafe-secret-comparison.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unsafe-secret-comparison.d.ts","sourceRoot":"","sources":["../../../src/checks/security/unsafe-secret-comparison.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AA+KH;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB,sCA2DjC,CAAC"}
|