@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,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview No raw fetch check — flags direct `fetch()` calls that should
|
|
3
|
+
* use a wrapped HTTP client.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Check: resilience/no-raw-fetch
|
|
7
|
+
*
|
|
8
|
+
* Detects direct use of fetch() without retry/timeout wrapper.
|
|
9
|
+
*/
|
|
10
|
+
export declare const noRawFetch: import("@opensip-cli/fitness").Check;
|
|
11
|
+
//# sourceMappingURL=no-raw-fetch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-raw-fetch.d.ts","sourceRoot":"","sources":["../../../src/checks/resilience/no-raw-fetch.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAoBH;;;;GAIG;AACH,eAAO,MAAM,UAAU,sCAoGrB,CAAC"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview No raw fetch check — flags direct `fetch()` calls that should
|
|
3
|
+
* use a wrapped HTTP client.
|
|
4
|
+
*/
|
|
5
|
+
import { defineCheck, isCommentLine, isTestFile } from '@opensip-cli/fitness';
|
|
6
|
+
/**
|
|
7
|
+
* Pattern for detecting raw fetch() calls.
|
|
8
|
+
*
|
|
9
|
+
* Safe regex: bounded whitespace + a single negative lookbehind that
|
|
10
|
+
* rejects any identifier-char or `.` immediately before `fetch`. The
|
|
11
|
+
* lookbehind excludes both larger identifiers ending in `fetch`
|
|
12
|
+
* (`prefetch`, `recordReconcilerPrefetch`, `MyClass.fetch`) AND any
|
|
13
|
+
* dotted call (`this.fetch`, `cacheGit.fetch`, `httpClient.fetch`) in
|
|
14
|
+
* one rule — there's no need for a separate `this.` exclusion.
|
|
15
|
+
*
|
|
16
|
+
* The previous form `(?<!this\.)fetch...` had no word-boundary on the
|
|
17
|
+
* left, so anything ending in `fetch(` matched (false positives on
|
|
18
|
+
* `prefetch(`, `recordReconcilerPrefetch(`, etc.).
|
|
19
|
+
*/
|
|
20
|
+
const RAW_FETCH_PATTERN = /(?<![\w$.])fetch\s{0,10}\(/g;
|
|
21
|
+
/**
|
|
22
|
+
* Check: resilience/no-raw-fetch
|
|
23
|
+
*
|
|
24
|
+
* Detects direct use of fetch() without retry/timeout wrapper.
|
|
25
|
+
*/
|
|
26
|
+
export const noRawFetch = defineCheck({
|
|
27
|
+
id: 'cfeba2d8-0f62-4b64-b625-f5ba8a0f3b11',
|
|
28
|
+
slug: 'no-raw-fetch',
|
|
29
|
+
fileTypes: ['ts', 'tsx', 'js', 'jsx'],
|
|
30
|
+
description: 'Detect direct fetch() calls that should use wrapped HTTP clients',
|
|
31
|
+
longDescription: `**Purpose:** Enforces use of the platform HTTP client wrapper instead of raw \`fetch()\` calls.
|
|
32
|
+
|
|
33
|
+
**Detects:**
|
|
34
|
+
- Bare \`fetch(\` calls via regex \`(?<![\\w$.])fetch\\s{0,10}\\(\` (excludes any \`<ident>.fetch\` method call AND any larger identifier ending in \`fetch\`, e.g. \`prefetch\`)
|
|
35
|
+
- Skips comment lines
|
|
36
|
+
|
|
37
|
+
**Why it matters:** Raw \`fetch()\` lacks built-in retry, timeout, observability, and error normalization that the canonical HttpClient provides.
|
|
38
|
+
|
|
39
|
+
**Scope:** Codebase-specific convention. Analyzes each file individually via regex.`,
|
|
40
|
+
tags: ['resilience', 'http', 'fetch'],
|
|
41
|
+
analyze(content, filePath) {
|
|
42
|
+
const violations = [];
|
|
43
|
+
// Quick check: skip files that don't contain fetch
|
|
44
|
+
if (!content.includes('fetch(')) {
|
|
45
|
+
return violations;
|
|
46
|
+
}
|
|
47
|
+
// Skip the resilient fetch wrapper itself — this IS the raw fetch implementation
|
|
48
|
+
if (filePath.includes('resilient-fetch') || filePath.includes('resilient_fetch')) {
|
|
49
|
+
return violations;
|
|
50
|
+
}
|
|
51
|
+
// Skip test files — tests legitimately invoke `fetch(` directly to
|
|
52
|
+
// exercise the wrapper, mock the global, or hit a localhost test
|
|
53
|
+
// server. Routing those through the wrapper would defeat the test.
|
|
54
|
+
if (isTestFile(filePath)) {
|
|
55
|
+
return violations;
|
|
56
|
+
}
|
|
57
|
+
// Skip fitness check definitions that reference fetch in string/regex patterns
|
|
58
|
+
if (filePath.includes('/fitness/src/checks/')) {
|
|
59
|
+
return violations;
|
|
60
|
+
}
|
|
61
|
+
// Skip LLM adapter files — infrastructure boundary making direct API calls
|
|
62
|
+
if (filePath.includes('/llm/') || filePath.includes('/llm-adapter')) {
|
|
63
|
+
return violations;
|
|
64
|
+
}
|
|
65
|
+
// Skip SSE/streaming implementations that require raw fetch for stream parsing
|
|
66
|
+
if (content.includes('ReadableStream') ||
|
|
67
|
+
content.includes('text/event-stream') ||
|
|
68
|
+
content.includes('EventSource') ||
|
|
69
|
+
content.includes('getReader()')) {
|
|
70
|
+
return violations;
|
|
71
|
+
}
|
|
72
|
+
// Skip files where fetch() is invoked through a retry wrapper AND
|
|
73
|
+
// every fetch call passes an abort signal / timeout. This is the
|
|
74
|
+
// canonical "wrapped" pattern: `withRetry(() => fetch(url, { signal:
|
|
75
|
+
// AbortSignal.timeout(...) }))`. The check exists to flag the bare
|
|
76
|
+
// primitive, not legitimate library code that already adds the
|
|
77
|
+
// missing affordances around it.
|
|
78
|
+
const fetchCallCount = (content.match(/(?<![\w$.])fetch\s{0,10}\(/g) ?? []).length;
|
|
79
|
+
const signalCount = (content.match(/\bsignal\s*:/g) ?? []).length;
|
|
80
|
+
const usesRetryWrapper = content.includes('withRetry(') ||
|
|
81
|
+
content.includes('withRetries(') ||
|
|
82
|
+
content.includes('retryFetch(');
|
|
83
|
+
if (usesRetryWrapper && signalCount >= fetchCallCount) {
|
|
84
|
+
return violations;
|
|
85
|
+
}
|
|
86
|
+
const lines = content.split('\n');
|
|
87
|
+
for (const [lineNum, line_] of lines.entries()) {
|
|
88
|
+
const line = line_ ?? '';
|
|
89
|
+
// Skip comment lines
|
|
90
|
+
if (isCommentLine(line)) {
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
RAW_FETCH_PATTERN.lastIndex = 0;
|
|
94
|
+
let match;
|
|
95
|
+
while ((match = RAW_FETCH_PATTERN.exec(line)) !== null) {
|
|
96
|
+
violations.push({
|
|
97
|
+
line: lineNum + 1,
|
|
98
|
+
column: match.index,
|
|
99
|
+
message: 'Raw fetch() usage detected',
|
|
100
|
+
severity: 'warning',
|
|
101
|
+
suggestion: 'Use a shared HTTP client wrapper with built-in retry, timeout, and error handling instead of raw fetch()',
|
|
102
|
+
match: match[0],
|
|
103
|
+
filePath,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return violations;
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
//# sourceMappingURL=no-raw-fetch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-raw-fetch.js","sourceRoot":"","sources":["../../../src/checks/resilience/no-raw-fetch.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,UAAU,EAAuB,MAAM,sBAAsB,CAAC;AAEnG;;;;;;;;;;;;;GAaG;AACH,MAAM,iBAAiB,GAAG,6BAA6B,CAAC;AAExD;;;;GAIG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,WAAW,CAAC;IACpC,EAAE,EAAE,sCAAsC;IAC1C,IAAI,EAAE,cAAc;IACpB,SAAS,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC;IACrC,WAAW,EAAE,kEAAkE;IAC/E,eAAe,EAAE;;;;;;;;oFAQiE;IAClF,IAAI,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,CAAC;IAErC,OAAO,CAAC,OAAe,EAAE,QAAgB;QACvC,MAAM,UAAU,GAAqB,EAAE,CAAC;QAExC,mDAAmD;QACnD,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;YAChC,OAAO,UAAU,CAAC;QACpB,CAAC;QAED,iFAAiF;QACjF,IAAI,QAAQ,CAAC,QAAQ,CAAC,iBAAiB,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,CAAC;YACjF,OAAO,UAAU,CAAC;QACpB,CAAC;QAED,mEAAmE;QACnE,iEAAiE;QACjE,mEAAmE;QACnE,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YACzB,OAAO,UAAU,CAAC;QACpB,CAAC;QAED,+EAA+E;QAC/E,IAAI,QAAQ,CAAC,QAAQ,CAAC,sBAAsB,CAAC,EAAE,CAAC;YAC9C,OAAO,UAAU,CAAC;QACpB,CAAC;QAED,2EAA2E;QAC3E,IAAI,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;YACpE,OAAO,UAAU,CAAC;QACpB,CAAC;QAED,+EAA+E;QAC/E,IACE,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC;YAClC,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAC;YACrC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC;YAC/B,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,EAC/B,CAAC;YACD,OAAO,UAAU,CAAC;QACpB,CAAC;QAED,kEAAkE;QAClE,iEAAiE;QACjE,qEAAqE;QACrE,mEAAmE;QACnE,+DAA+D;QAC/D,iCAAiC;QACjC,MAAM,cAAc,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,6BAA6B,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC;QACnF,MAAM,WAAW,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,eAAe,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC;QAClE,MAAM,gBAAgB,GACpB,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC;YAC9B,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC;YAChC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;QAClC,IAAI,gBAAgB,IAAI,WAAW,IAAI,cAAc,EAAE,CAAC;YACtD,OAAO,UAAU,CAAC;QACpB,CAAC;QAED,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAElC,KAAK,MAAM,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;YAC/C,MAAM,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;YAEzB,qBAAqB;YACrB,IAAI,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC;gBACxB,SAAS;YACX,CAAC;YAED,iBAAiB,CAAC,SAAS,GAAG,CAAC,CAAC;YAChC,IAAI,KAAK,CAAC;YACV,OAAO,CAAC,KAAK,GAAG,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;gBACvD,UAAU,CAAC,IAAI,CAAC;oBACd,IAAI,EAAE,OAAO,GAAG,CAAC;oBACjB,MAAM,EAAE,KAAK,CAAC,KAAK;oBACnB,OAAO,EAAE,4BAA4B;oBACrC,QAAQ,EAAE,SAAS;oBACnB,UAAU,EACR,0GAA0G;oBAC5G,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;oBACf,QAAQ;iBACT,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,OAAO,UAAU,CAAC;IACpB,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview No unbounded concurrency check — flags `Promise.all(arr.map(...))`
|
|
3
|
+
* patterns without nearby concurrency controls.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Check: resilience/no-unbounded-concurrency
|
|
7
|
+
*
|
|
8
|
+
* Detects Promise.all with .map() that may spawn unbounded concurrent operations.
|
|
9
|
+
*/
|
|
10
|
+
export declare const noUnboundedConcurrency: import("@opensip-cli/fitness").Check;
|
|
11
|
+
//# sourceMappingURL=no-unbounded-concurrency.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-unbounded-concurrency.d.ts","sourceRoot":"","sources":["../../../src/checks/resilience/no-unbounded-concurrency.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAkCH;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,sCAqFjC,CAAC"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview No unbounded concurrency check — flags `Promise.all(arr.map(...))`
|
|
3
|
+
* patterns without nearby concurrency controls.
|
|
4
|
+
*/
|
|
5
|
+
import { defineCheck, getLineNumber, isTestFile, stripStringsAndCommentsPreservingPositions, } from '@opensip-cli/fitness';
|
|
6
|
+
/**
|
|
7
|
+
* Pattern indicating unbounded Promise.all usage.
|
|
8
|
+
* Safe regex: uses word boundaries and explicit character classes, no nested quantifiers.
|
|
9
|
+
*/
|
|
10
|
+
const UNBOUNDED_PROMISE_ALL_PATTERN = /Promise\.all\s*\(\s*[a-zA-Z_$][a-zA-Z0-9_$]*\.map\s*\(/g;
|
|
11
|
+
/**
|
|
12
|
+
* Check if content contains bounded concurrency patterns.
|
|
13
|
+
* @param {string} content - The content to check
|
|
14
|
+
* @returns {boolean} True if bounded patterns found
|
|
15
|
+
*/
|
|
16
|
+
function hasBoundedConcurrencyPattern(content) {
|
|
17
|
+
const lowerContent = content.toLowerCase();
|
|
18
|
+
// Check simple string patterns first (faster)
|
|
19
|
+
if (lowerContent.includes('plimit'))
|
|
20
|
+
return true;
|
|
21
|
+
if (lowerContent.includes('p-limit'))
|
|
22
|
+
return true;
|
|
23
|
+
if (content.includes('Promise.allSettled'))
|
|
24
|
+
return true;
|
|
25
|
+
// Check regex patterns
|
|
26
|
+
if (/concurrency:\s*\d+/i.test(content))
|
|
27
|
+
return true;
|
|
28
|
+
if (/\b(?:chunk|batch)\b/i.test(content))
|
|
29
|
+
return true;
|
|
30
|
+
if (/\b(?:throttle|rateLimit)\b/i.test(content))
|
|
31
|
+
return true;
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Check: resilience/no-unbounded-concurrency
|
|
36
|
+
*
|
|
37
|
+
* Detects Promise.all with .map() that may spawn unbounded concurrent operations.
|
|
38
|
+
*/
|
|
39
|
+
export const noUnboundedConcurrency = defineCheck({
|
|
40
|
+
id: 'fc2a0fee-8374-432b-a7ef-763aea867855',
|
|
41
|
+
slug: 'no-unbounded-concurrency',
|
|
42
|
+
description: 'Detect Promise.all with unbounded concurrency',
|
|
43
|
+
longDescription: `**Purpose:** Prevents unbounded parallel execution that can overwhelm downstream services or exhaust system resources.
|
|
44
|
+
|
|
45
|
+
**Detects:**
|
|
46
|
+
- \`Promise.all(items.map(\` pattern without nearby concurrency controls
|
|
47
|
+
- Skips files containing bounded concurrency indicators: \`plimit\`, \`p-limit\`, \`Promise.allSettled\`, \`concurrency: N\`, \`chunk\`, \`batch\`, \`throttle\`, \`rateLimit\`
|
|
48
|
+
|
|
49
|
+
**Why it matters:** Mapping an unbounded array into concurrent promises can spawn thousands of simultaneous operations, causing connection exhaustion or OOM.
|
|
50
|
+
|
|
51
|
+
**Scope:** General best practice. Analyzes each file individually via regex.`,
|
|
52
|
+
tags: ['resilience', 'async', 'concurrency'],
|
|
53
|
+
analyze(content, filePath) {
|
|
54
|
+
const violations = [];
|
|
55
|
+
// Skip test files — bounded by fixture data, not external load. A
|
|
56
|
+
// partial mock of bounded-concurrency helpers that fans out via
|
|
57
|
+
// Promise.all is a deliberate test seam; the production callers it
|
|
58
|
+
// replaces ARE bounded.
|
|
59
|
+
if (isTestFile(filePath))
|
|
60
|
+
return violations;
|
|
61
|
+
// Skip files that don't use Promise.all
|
|
62
|
+
if (!content.includes('Promise.all')) {
|
|
63
|
+
return violations;
|
|
64
|
+
}
|
|
65
|
+
// Strip strings and comments before pattern-match scanning so
|
|
66
|
+
// doc-block prose describing the pattern (e.g. JSDoc that says
|
|
67
|
+
// "`Promise.all(arr.map(asyncFn))` fans out one promise per
|
|
68
|
+
// element") doesn't produce a false positive that's impossible to
|
|
69
|
+
// suppress without a pragma in user code. Use the position-
|
|
70
|
+
// preserving variant so match indexes still map onto the original
|
|
71
|
+
// source line numbers.
|
|
72
|
+
//
|
|
73
|
+
// Bounded-pattern detection (`hasBoundedConcurrencyPattern`)
|
|
74
|
+
// intentionally runs on the ORIGINAL content — comments often carry
|
|
75
|
+
// intent ("// Batch failed", "// chunked at 4 in flight") that
|
|
76
|
+
// operators expect to suppress the warning. Stripping them there
|
|
77
|
+
// would surface previously-passing files as new positives every
|
|
78
|
+
// time we tighten the regex, so keep the file-level escape hatch
|
|
79
|
+
// generous and only narrow the per-match scan.
|
|
80
|
+
const codeOnly = stripStringsAndCommentsPreservingPositions(content);
|
|
81
|
+
if (!codeOnly.includes('Promise.all')) {
|
|
82
|
+
return violations;
|
|
83
|
+
}
|
|
84
|
+
// Check if file has bounded concurrency patterns (uses original content)
|
|
85
|
+
if (hasBoundedConcurrencyPattern(content)) {
|
|
86
|
+
return violations;
|
|
87
|
+
}
|
|
88
|
+
UNBOUNDED_PROMISE_ALL_PATTERN.lastIndex = 0;
|
|
89
|
+
let match;
|
|
90
|
+
while ((match = UNBOUNDED_PROMISE_ALL_PATTERN.exec(codeOnly)) !== null) {
|
|
91
|
+
// @lazy-ok -- 'await' appears in suggestion string literal, not actual await
|
|
92
|
+
// Check context around match for bounded patterns. Use the
|
|
93
|
+
// ORIGINAL content here — adjacent comments like
|
|
94
|
+
// `// chunked, batch=N` or `// see batchWithConcurrency above`
|
|
95
|
+
// are deliberate hints that operators expect to suppress the
|
|
96
|
+
// warning. Same rationale as the file-level bounded check.
|
|
97
|
+
const start = Math.max(0, match.index - 200);
|
|
98
|
+
const end = Math.min(content.length, match.index + 200);
|
|
99
|
+
const context = content.slice(start, end);
|
|
100
|
+
if (!hasBoundedConcurrencyPattern(context)) {
|
|
101
|
+
const lineNumber = getLineNumber(content, match.index);
|
|
102
|
+
violations.push({
|
|
103
|
+
line: lineNumber,
|
|
104
|
+
column: 0,
|
|
105
|
+
message: 'Promise.all with .map() may spawn unbounded concurrent operations',
|
|
106
|
+
severity: 'warning',
|
|
107
|
+
suggestion: 'Use p-limit or batch processing to limit concurrency. Example: const limit = pLimit(10); await Promise.all(items.map(item => limit(() => process(item))))',
|
|
108
|
+
match: match[0],
|
|
109
|
+
type: 'unbounded-promise-all',
|
|
110
|
+
filePath,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return violations;
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
//# sourceMappingURL=no-unbounded-concurrency.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-unbounded-concurrency.js","sourceRoot":"","sources":["../../../src/checks/resilience/no-unbounded-concurrency.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Regression tests for `sql-injection` check FP fixes.
|
|
3
|
+
*
|
|
4
|
+
* The 1.0.7 release tightened arm-3 (right-side string concat with
|
|
5
|
+
* SQL clause keyword) to:
|
|
6
|
+
* - case-sensitive `WHERE|AND|OR|SET|VALUES` (no longer matches
|
|
7
|
+
* lowercase English words)
|
|
8
|
+
* - require the concat chain to contain a real SQL keyword
|
|
9
|
+
* (`SELECT|INSERT|UPDATE|...`) somewhere
|
|
10
|
+
* - skip arguments to known output methods (cli.info/log/error,
|
|
11
|
+
* console.log, logger.warn, etc.)
|
|
12
|
+
*
|
|
13
|
+
* These tests pin the FP cases that previously fired so future
|
|
14
|
+
* refactors don't reintroduce them.
|
|
15
|
+
*/
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=sql-injection.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sql-injection.test.d.ts","sourceRoot":"","sources":["../../../../src/checks/security/__tests__/sql-injection.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Regression tests for `sql-injection` check FP fixes.
|
|
3
|
+
*
|
|
4
|
+
* The 1.0.7 release tightened arm-3 (right-side string concat with
|
|
5
|
+
* SQL clause keyword) to:
|
|
6
|
+
* - case-sensitive `WHERE|AND|OR|SET|VALUES` (no longer matches
|
|
7
|
+
* lowercase English words)
|
|
8
|
+
* - require the concat chain to contain a real SQL keyword
|
|
9
|
+
* (`SELECT|INSERT|UPDATE|...`) somewhere
|
|
10
|
+
* - skip arguments to known output methods (cli.info/log/error,
|
|
11
|
+
* console.log, logger.warn, etc.)
|
|
12
|
+
*
|
|
13
|
+
* These tests pin the FP cases that previously fired so future
|
|
14
|
+
* refactors don't reintroduce them.
|
|
15
|
+
*/
|
|
16
|
+
import { describe, expect, it } from 'vitest';
|
|
17
|
+
import { analyzeSqlInjection } from '../sql-injection.js';
|
|
18
|
+
function analyze(src) {
|
|
19
|
+
return analyzeSqlInjection(src, 'test.ts');
|
|
20
|
+
}
|
|
21
|
+
describe('sql-injection — FP regression suite (1.0.7)', () => {
|
|
22
|
+
it('does NOT flag CLI help text with lowercase "and" between concatenated strings', () => {
|
|
23
|
+
// Pre-1.0.7 this fired because /\bAND\b/i matched "and" in plain
|
|
24
|
+
// English inside `cli.info('...\n' + '... and ...\n')`.
|
|
25
|
+
const src = String.raw `
|
|
26
|
+
import { cli } from './cli'
|
|
27
|
+
cli.info(
|
|
28
|
+
'Usage: opensip foo --tenant <id>\n\n' +
|
|
29
|
+
'Verifies the chain hash and surfaces every seal row.\n' +
|
|
30
|
+
'Exits 0 on a clean pass.\n',
|
|
31
|
+
)
|
|
32
|
+
`;
|
|
33
|
+
expect(analyze(src)).toHaveLength(0);
|
|
34
|
+
});
|
|
35
|
+
it('does NOT flag CLI help text with lowercase "or" between concatenated strings', () => {
|
|
36
|
+
const src = String.raw `
|
|
37
|
+
const cli = { info: (_: string) => {} }
|
|
38
|
+
cli.info(
|
|
39
|
+
'Pick a strategy: shadow or apply.\n' +
|
|
40
|
+
' shadow — log only\n' +
|
|
41
|
+
' apply — write the change\n',
|
|
42
|
+
)
|
|
43
|
+
`;
|
|
44
|
+
expect(analyze(src)).toHaveLength(0);
|
|
45
|
+
});
|
|
46
|
+
it('does NOT flag logger.warn argument with concatenation', () => {
|
|
47
|
+
const src = `
|
|
48
|
+
const logger = { warn: (_: object) => {} }
|
|
49
|
+
logger.warn({
|
|
50
|
+
msg: 'phase ' + name + ' will retry and continue',
|
|
51
|
+
})
|
|
52
|
+
`;
|
|
53
|
+
expect(analyze(src)).toHaveLength(0);
|
|
54
|
+
});
|
|
55
|
+
it('does NOT flag console.log with English-text concatenation', () => {
|
|
56
|
+
const src = String.raw `
|
|
57
|
+
console.log('Tables: ' + tables.join(', ') + '\n' + 'audit_log and chain_seals are checked')
|
|
58
|
+
`;
|
|
59
|
+
expect(analyze(src)).toHaveLength(0);
|
|
60
|
+
});
|
|
61
|
+
it('STILL flags real SQL concatenation with WHERE', () => {
|
|
62
|
+
// Pre-1.0.7 caught this via arm-1 (left-side SELECT keyword); the
|
|
63
|
+
// 1.0.7 changes must preserve that detection.
|
|
64
|
+
const src = `
|
|
65
|
+
const q = 'SELECT * FROM users WHERE id = ' + userId
|
|
66
|
+
db.execute(q)
|
|
67
|
+
`;
|
|
68
|
+
expect(analyze(src).length).toBeGreaterThanOrEqual(1);
|
|
69
|
+
});
|
|
70
|
+
it('STILL flags right-side WHERE/AND continuation when chain has a SQL keyword', () => {
|
|
71
|
+
// Build-up pattern: prefix + variable + suffix where the suffix
|
|
72
|
+
// contains a clause keyword. The chain has "SELECT * FROM " on
|
|
73
|
+
// the left, so arm-3 should fire.
|
|
74
|
+
const src = `
|
|
75
|
+
const q = 'SELECT * FROM users WHERE id = ' + userId + ' AND status = $1'
|
|
76
|
+
db.execute(q)
|
|
77
|
+
`;
|
|
78
|
+
expect(analyze(src).length).toBeGreaterThanOrEqual(1);
|
|
79
|
+
});
|
|
80
|
+
it('does NOT flag uppercase AND/OR inside an output call even when the chain looks SQL-ish', () => {
|
|
81
|
+
// Edge case: even if the help text uses uppercase "AND" /
|
|
82
|
+
// "OR", the output-call filter should skip it because
|
|
83
|
+
// cli.info(...) is never SQL.
|
|
84
|
+
const src = String.raw `
|
|
85
|
+
const cli = { info: (_: string) => {} }
|
|
86
|
+
cli.info(
|
|
87
|
+
'Pick a mode:\n' +
|
|
88
|
+
' shadow - log only\n' +
|
|
89
|
+
' apply - write\n' +
|
|
90
|
+
'\n' +
|
|
91
|
+
'BOTH are safe to run; SHADOW is read-only.\n',
|
|
92
|
+
)
|
|
93
|
+
`;
|
|
94
|
+
expect(analyze(src)).toHaveLength(0);
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
//# sourceMappingURL=sql-injection.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sql-injection.test.js","sourceRoot":"","sources":["../../../../src/checks/security/__tests__/sql-injection.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE1D,SAAS,OAAO,CAAC,GAAW;IAC1B,OAAO,mBAAmB,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;AAC7C,CAAC;AAED,QAAQ,CAAC,6CAA6C,EAAE,GAAG,EAAE;IAC3D,EAAE,CAAC,+EAA+E,EAAE,GAAG,EAAE;QACvF,iEAAiE;QACjE,wDAAwD;QACxD,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;;KAOrB,CAAC;QACF,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8EAA8E,EAAE,GAAG,EAAE;QACtF,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;;KAOrB,CAAC;QACF,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uDAAuD,EAAE,GAAG,EAAE;QAC/D,MAAM,GAAG,GAAG;;;;;KAKX,CAAC;QACF,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2DAA2D,EAAE,GAAG,EAAE;QACnE,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAA;;KAErB,CAAC;QACF,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;QACvD,kEAAkE;QAClE,8CAA8C;QAC9C,MAAM,GAAG,GAAG;;;KAGX,CAAC;QACF,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4EAA4E,EAAE,GAAG,EAAE;QACpF,gEAAgE;QAChE,+DAA+D;QAC/D,kCAAkC;QAClC,MAAM,GAAG,GAAG;;;KAGX,CAAC;QACF,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wFAAwF,EAAE,GAAG,EAAE;QAChG,0DAA0D;QAC1D,sDAAsD;QACtD,8BAA8B;QAC9B,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;;;;KASrB,CAAC;QACF,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/checks/security/index.ts"],"names":[],"mappings":"AAAA,cAAc,yBAAyB,CAAC;AACxC,cAAc,oBAAoB,CAAC;AACnC,cAAc,+BAA+B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/checks/security/index.ts"],"names":[],"mappings":"AAAA,cAAc,yBAAyB,CAAC;AACxC,cAAc,oBAAoB,CAAC;AACnC,cAAc,+BAA+B,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Detect unsanitized user input usage
|
|
3
|
+
*
|
|
4
|
+
* Uses AST analysis to detect unsanitized user input in HTML injection,
|
|
5
|
+
* command injection, and path traversal contexts. AST context eliminates
|
|
6
|
+
* false positives from regex definitions, string constants, and comments.
|
|
7
|
+
*
|
|
8
|
+
*
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Check: security/input-sanitization
|
|
12
|
+
*
|
|
13
|
+
* Detects user input used without proper sanitization using AST analysis.
|
|
14
|
+
* Walks the AST to find actual innerHTML assignments, exec/spawn calls,
|
|
15
|
+
* and file operations with user input references.
|
|
16
|
+
*
|
|
17
|
+
*
|
|
18
|
+
*/
|
|
19
|
+
export declare const inputSanitization: import("@opensip-cli/fitness").Check;
|
|
20
|
+
//# sourceMappingURL=input-sanitization.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"input-sanitization.d.ts","sourceRoot":"","sources":["../../../src/checks/security/input-sanitization.ts"],"names":[],"mappings":"AACA;;;;;;;;GAQG;AA6MH;;;;;;;;GAQG;AACH,eAAO,MAAM,iBAAiB,sCA8E5B,CAAC"}
|