@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,435 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Context leakage detection — flags request-scoped state stored
|
|
3
|
+
* in module or class scope that can leak between concurrent requests.
|
|
4
|
+
*/
|
|
5
|
+
import { logger } from '@opensip-cli/core';
|
|
6
|
+
import { defineCheck, isTestFile } from '@opensip-cli/fitness';
|
|
7
|
+
import { getSharedSourceFile } from '@opensip-cli/lang-typescript';
|
|
8
|
+
import * as ts from 'typescript';
|
|
9
|
+
// =============================================================================
|
|
10
|
+
// REQUEST CONTEXT LEAKAGE (AST-based)
|
|
11
|
+
// =============================================================================
|
|
12
|
+
/**
|
|
13
|
+
* Names that look like a request-scoped context variable.
|
|
14
|
+
* Matches whole-word boundaries (case-insensitive): "ctx", "context", "request"
|
|
15
|
+
* but excludes generic suffixes that aren't request state (e.g. `parserContext`
|
|
16
|
+
* is still flagged, but that is fine — it's evaluated together with the type).
|
|
17
|
+
*/
|
|
18
|
+
function variableNameLooksContextual(name) {
|
|
19
|
+
const lower = name.toLowerCase();
|
|
20
|
+
// Whole-word: ends with "context"/"ctx" or starts with "request"/"req"
|
|
21
|
+
return (lower.endsWith('context') ||
|
|
22
|
+
lower.endsWith('ctx') ||
|
|
23
|
+
lower === 'request' ||
|
|
24
|
+
lower === 'req' ||
|
|
25
|
+
lower.startsWith('request') ||
|
|
26
|
+
(lower.startsWith('req') && lower.length <= 12));
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Type-name suffixes that indicate a request-scoped context type.
|
|
30
|
+
* Matches identifier types whose name ends with "Context" or "Ctx".
|
|
31
|
+
* Excludes well-known process-scoped wrappers (`Injector<…>`, `SyncStrategy<…>`,
|
|
32
|
+
* `Promise<…>`) — those are detected by inspecting the OUTER type identifier
|
|
33
|
+
* and refusing to recurse into its generic arguments.
|
|
34
|
+
*/
|
|
35
|
+
function isContextTypeName(name) {
|
|
36
|
+
return /(?:Context|Ctx)$/.test(name);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Type identifiers that, regardless of generic arguments, are NOT request
|
|
40
|
+
* state. If the outer type is one of these, we ignore generic args entirely.
|
|
41
|
+
*/
|
|
42
|
+
const PROCESS_SCOPED_WRAPPER_TYPES = new Set([
|
|
43
|
+
'Injector',
|
|
44
|
+
'SyncStrategy',
|
|
45
|
+
'Promise',
|
|
46
|
+
'PromiseLike',
|
|
47
|
+
'Awaited',
|
|
48
|
+
'Array',
|
|
49
|
+
'ReadonlyArray',
|
|
50
|
+
'Map',
|
|
51
|
+
'ReadonlyMap',
|
|
52
|
+
'Set',
|
|
53
|
+
'ReadonlySet',
|
|
54
|
+
'Record',
|
|
55
|
+
'Partial',
|
|
56
|
+
'Required',
|
|
57
|
+
'Readonly',
|
|
58
|
+
'Pick',
|
|
59
|
+
'Omit',
|
|
60
|
+
'Result',
|
|
61
|
+
'Either',
|
|
62
|
+
'Observable',
|
|
63
|
+
'AsyncIterable',
|
|
64
|
+
'Iterable',
|
|
65
|
+
'WeakMap',
|
|
66
|
+
'WeakSet',
|
|
67
|
+
]);
|
|
68
|
+
/**
|
|
69
|
+
* OTel and project metric instrument type names. A module-level
|
|
70
|
+
* `let counter: Counter | null = null` lazy-init pattern with one of these
|
|
71
|
+
* as the declared type is process-scoped per-instrument state, not request state.
|
|
72
|
+
*/
|
|
73
|
+
const METRIC_INSTRUMENT_TYPES = new Set([
|
|
74
|
+
'Counter',
|
|
75
|
+
'Histogram',
|
|
76
|
+
'UpDownCounter',
|
|
77
|
+
'Gauge',
|
|
78
|
+
'ObservableCounter',
|
|
79
|
+
'ObservableGauge',
|
|
80
|
+
'ObservableUpDownCounter',
|
|
81
|
+
'Meter',
|
|
82
|
+
'Tracer',
|
|
83
|
+
'TracerProvider',
|
|
84
|
+
'MeterProvider',
|
|
85
|
+
]);
|
|
86
|
+
/**
|
|
87
|
+
* Path patterns where the check is structurally inappropriate.
|
|
88
|
+
* - DBOS steps register process-scoped DI via `static ctx`; that's the framework's
|
|
89
|
+
* contract, not request leakage.
|
|
90
|
+
*/
|
|
91
|
+
const SKIP_PATH_PATTERNS = [/[/\\]dbos[/\\]steps[/\\]/];
|
|
92
|
+
function isSkippedPath(filePath) {
|
|
93
|
+
return SKIP_PATH_PATTERNS.some((p) => p.test(filePath));
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Walk a TypeNode and decide whether it references a request-scoped context
|
|
97
|
+
* type *as the outer / value-shape* (not as an inner generic argument of a
|
|
98
|
+
* process-scoped wrapper like `Injector<AuditContext>`).
|
|
99
|
+
*/
|
|
100
|
+
/** Get the simple name of a type reference's `typeName` (handles qualified names). */
|
|
101
|
+
function getTypeRefName(typeName) {
|
|
102
|
+
if (ts.isIdentifier(typeName))
|
|
103
|
+
return typeName.text;
|
|
104
|
+
if (ts.isQualifiedName(typeName))
|
|
105
|
+
return typeName.right.text;
|
|
106
|
+
return '';
|
|
107
|
+
}
|
|
108
|
+
/** Outer type-reference name(s) of a TypeNode, including each union branch. */
|
|
109
|
+
function typeRefNames(type) {
|
|
110
|
+
if (!type)
|
|
111
|
+
return [];
|
|
112
|
+
if (ts.isUnionTypeNode(type))
|
|
113
|
+
return type.types.flatMap((t) => typeRefNames(t));
|
|
114
|
+
if (ts.isTypeReferenceNode(type))
|
|
115
|
+
return [getTypeRefName(type.typeName)];
|
|
116
|
+
return [];
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Collect names imported from `@opentelemetry/*` packages. OTel's `Context`
|
|
120
|
+
* (the W3C trace-propagation context) and its siblings are process-scoped SDK
|
|
121
|
+
* types — a module-level `let parentContext: Context` holding propagation
|
|
122
|
+
* state is NOT the per-request tenant context this check targets. Inspecting
|
|
123
|
+
* the import source (rather than the bare `Context`/`Ctx` name) keeps the
|
|
124
|
+
* exclusion sound: only OTel's own types are spared, not every type ending
|
|
125
|
+
* in "Context".
|
|
126
|
+
*/
|
|
127
|
+
function isOtelImport(stmt) {
|
|
128
|
+
return (ts.isImportDeclaration(stmt) &&
|
|
129
|
+
ts.isStringLiteral(stmt.moduleSpecifier) &&
|
|
130
|
+
stmt.moduleSpecifier.text.startsWith('@opentelemetry/'));
|
|
131
|
+
}
|
|
132
|
+
/** Names bound by an import clause (default + named bindings). */
|
|
133
|
+
function importClauseNames(clause) {
|
|
134
|
+
const names = [];
|
|
135
|
+
if (clause.name)
|
|
136
|
+
names.push(clause.name.text);
|
|
137
|
+
const bindings = clause.namedBindings;
|
|
138
|
+
if (bindings && ts.isNamedImports(bindings)) {
|
|
139
|
+
for (const el of bindings.elements)
|
|
140
|
+
names.push(el.name.text);
|
|
141
|
+
}
|
|
142
|
+
return names;
|
|
143
|
+
}
|
|
144
|
+
function collectOtelImportedNames(sourceFile) {
|
|
145
|
+
const names = new Set();
|
|
146
|
+
for (const stmt of sourceFile.statements) {
|
|
147
|
+
if (!isOtelImport(stmt) || !stmt.importClause)
|
|
148
|
+
continue;
|
|
149
|
+
for (const name of importClauseNames(stmt.importClause))
|
|
150
|
+
names.add(name);
|
|
151
|
+
}
|
|
152
|
+
return names;
|
|
153
|
+
}
|
|
154
|
+
function typeLooksLikeRequestContext(type) {
|
|
155
|
+
if (!type)
|
|
156
|
+
return false;
|
|
157
|
+
// Union: any branch that looks like context counts (excluding `null`/`undefined`)
|
|
158
|
+
if (ts.isUnionTypeNode(type)) {
|
|
159
|
+
return type.types.some((t) => typeLooksLikeRequestContext(t));
|
|
160
|
+
}
|
|
161
|
+
if (ts.isTypeReferenceNode(type)) {
|
|
162
|
+
const name = getTypeRefName(type.typeName);
|
|
163
|
+
// @fitness-ignore-next-line silent-early-returns -- boolean predicate function: `false` IS the contract value meaning "this wrapper is process-scoped, not request-scoped"; the caller branches on it.
|
|
164
|
+
if (PROCESS_SCOPED_WRAPPER_TYPES.has(name)) {
|
|
165
|
+
// The outer wrapper is process-scoped; ignore its generic arguments.
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
return isContextTypeName(name);
|
|
169
|
+
}
|
|
170
|
+
// Other shapes (TypeLiteral, intersection of inline shapes, etc.) — be lenient
|
|
171
|
+
// and don't flag. Inline-typed module-level state would still be caught if
|
|
172
|
+
// the variable name itself is contextual (handled separately).
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Detect the `let foo: <MetricType> | null = null` lazy-init shape that is
|
|
177
|
+
* common for OTel instruments. These declarations are process-scoped per
|
|
178
|
+
* metric, not request state, so we skip them.
|
|
179
|
+
*/
|
|
180
|
+
function isMetricLazyInit(decl) {
|
|
181
|
+
const t = decl.type;
|
|
182
|
+
if (!t)
|
|
183
|
+
return false;
|
|
184
|
+
if (decl.initializer?.kind !== ts.SyntaxKind.NullKeyword)
|
|
185
|
+
return false;
|
|
186
|
+
// Require a `<Something> | null` (or `<Something> | undefined`) shape.
|
|
187
|
+
const candidates = ts.isUnionTypeNode(t) ? [...t.types] : [t];
|
|
188
|
+
const hasNullBranch = candidates.some((c) => c.kind === ts.SyntaxKind.NullKeyword ||
|
|
189
|
+
c.kind === ts.SyntaxKind.UndefinedKeyword ||
|
|
190
|
+
(ts.isLiteralTypeNode(c) && c.literal.kind === ts.SyntaxKind.NullKeyword));
|
|
191
|
+
if (!hasNullBranch)
|
|
192
|
+
return false;
|
|
193
|
+
return candidates.some((c) => {
|
|
194
|
+
if (!ts.isTypeReferenceNode(c))
|
|
195
|
+
return false;
|
|
196
|
+
return METRIC_INSTRUMENT_TYPES.has(getTypeRefName(c.typeName));
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Detect AsyncLocalStorage-typed declarations; these are the *correct* way to
|
|
201
|
+
* store request-scoped state and should never be flagged.
|
|
202
|
+
*/
|
|
203
|
+
function isAsyncLocalStorageType(type) {
|
|
204
|
+
if (!type)
|
|
205
|
+
return false;
|
|
206
|
+
if (ts.isTypeReferenceNode(type)) {
|
|
207
|
+
return getTypeRefName(type.typeName) === 'AsyncLocalStorage';
|
|
208
|
+
}
|
|
209
|
+
if (ts.isUnionTypeNode(type)) {
|
|
210
|
+
return type.types.some(isAsyncLocalStorageType);
|
|
211
|
+
}
|
|
212
|
+
return false;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* A class is "request-scoped" if any of its public methods take a `tenantId`
|
|
216
|
+
* parameter (typed or named), or it has a `requestId` field. This is a heuristic
|
|
217
|
+
* — process-scoped DI classes (composition roots, providers) typically don't
|
|
218
|
+
* pass tenantId around as a method param; request handlers do.
|
|
219
|
+
*/
|
|
220
|
+
function classLooksRequestScoped(cls) {
|
|
221
|
+
for (const member of cls.members) {
|
|
222
|
+
// Field named requestId / correlationId
|
|
223
|
+
if (ts.isPropertyDeclaration(member) && ts.isIdentifier(member.name)) {
|
|
224
|
+
const fieldName = member.name.text;
|
|
225
|
+
if (fieldName === 'requestId' || fieldName === 'correlationId')
|
|
226
|
+
return true;
|
|
227
|
+
}
|
|
228
|
+
// Method with `tenantId` parameter
|
|
229
|
+
if ((ts.isMethodDeclaration(member) || ts.isConstructorDeclaration(member)) &&
|
|
230
|
+
member.parameters.some((p) => ts.isIdentifier(p.name) && (p.name.text === 'tenantId' || p.name.text === 'tenant_id'))) {
|
|
231
|
+
return true;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
return false;
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* A class declaration is a DBOS step host if any member carries a `@DBOS.step()`
|
|
238
|
+
* decorator (or `@DBOS.workflow()`). These are process-scoped DI containers.
|
|
239
|
+
*/
|
|
240
|
+
function classIsDbosStepHost(cls) {
|
|
241
|
+
const checkDecorators = (mods) => {
|
|
242
|
+
if (!mods)
|
|
243
|
+
return false;
|
|
244
|
+
for (const m of mods) {
|
|
245
|
+
if (!ts.isDecorator(m))
|
|
246
|
+
continue;
|
|
247
|
+
const exprText = m.expression.getText();
|
|
248
|
+
if (exprText.startsWith('DBOS.step') || exprText.startsWith('DBOS.workflow'))
|
|
249
|
+
return true;
|
|
250
|
+
}
|
|
251
|
+
return false;
|
|
252
|
+
};
|
|
253
|
+
if (checkDecorators(ts.getModifiers(cls)))
|
|
254
|
+
return true;
|
|
255
|
+
for (const member of cls.members) {
|
|
256
|
+
if (ts.canHaveDecorators(member) && checkDecorators(ts.getDecorators(member))) {
|
|
257
|
+
return true;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
return false;
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Walk top-level statements and class declarations of a SourceFile and collect
|
|
264
|
+
* findings for genuine module-level / request-scoped class-level leakage.
|
|
265
|
+
*/
|
|
266
|
+
// eslint-disable-next-line sonarjs/cognitive-complexity -- module/class-level walk; branches map to AST node kinds and are easier to read inline than as a fragmented dispatcher
|
|
267
|
+
function collectContextLeakage(sourceFile) {
|
|
268
|
+
const findings = [];
|
|
269
|
+
const otelImportedNames = collectOtelImportedNames(sourceFile);
|
|
270
|
+
// 1. Module-level `let`/`var` declarations
|
|
271
|
+
for (const stmt of sourceFile.statements) {
|
|
272
|
+
if (!ts.isVariableStatement(stmt))
|
|
273
|
+
continue;
|
|
274
|
+
const flags = stmt.declarationList.flags;
|
|
275
|
+
// Skip `const` — request-scoped state cannot be assigned more than once
|
|
276
|
+
// anyway. The leakage shape requires a re-assignable binding.
|
|
277
|
+
if (flags & ts.NodeFlags.Const)
|
|
278
|
+
continue;
|
|
279
|
+
for (const decl of stmt.declarationList.declarations) {
|
|
280
|
+
if (!ts.isIdentifier(decl.name))
|
|
281
|
+
continue;
|
|
282
|
+
const varName = decl.name.text;
|
|
283
|
+
// AsyncLocalStorage — the correct request-scoping primitive
|
|
284
|
+
if (isAsyncLocalStorageType(decl.type))
|
|
285
|
+
continue;
|
|
286
|
+
// Lazy-init metric instrument: process-scoped per metric, not per request
|
|
287
|
+
if (isMetricLazyInit(decl))
|
|
288
|
+
continue;
|
|
289
|
+
// OTel SDK types (Context, Span, …) are process/propagation scoped.
|
|
290
|
+
if (typeRefNames(decl.type).some((n) => otelImportedNames.has(n)))
|
|
291
|
+
continue;
|
|
292
|
+
const typeIsContextual = typeLooksLikeRequestContext(decl.type);
|
|
293
|
+
const nameIsContextual = variableNameLooksContextual(varName);
|
|
294
|
+
// Require BOTH name AND type to point at request context (or at least the
|
|
295
|
+
// type — the regex check used to flag "request" in metric names; we now
|
|
296
|
+
// require an explicit type-shape signal).
|
|
297
|
+
if (!typeIsContextual && !nameIsContextual)
|
|
298
|
+
continue;
|
|
299
|
+
// If the variable has a non-null initializer that's an object literal /
|
|
300
|
+
// function call producing a known process-scoped value (e.g. `new Map()`),
|
|
301
|
+
// and the type isn't contextual, skip.
|
|
302
|
+
if (!typeIsContextual && nameIsContextual) {
|
|
303
|
+
// Name-only signal is too weak by itself — require initializer to be `null`
|
|
304
|
+
// and a contextual-looking type. If the user wrote `let req = …` without a
|
|
305
|
+
// type, modern TS will infer it; we don't have type info here, so we punt.
|
|
306
|
+
continue;
|
|
307
|
+
}
|
|
308
|
+
const start = decl.getStart(sourceFile);
|
|
309
|
+
const { line, character } = sourceFile.getLineAndCharacterOfPosition(start);
|
|
310
|
+
findings.push({
|
|
311
|
+
line: line + 1,
|
|
312
|
+
column: character + 1,
|
|
313
|
+
match: `let ${varName}: <Context>`,
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
// 2. Class fields — non-readonly, non-static `PropertyDeclaration` whose
|
|
318
|
+
// type is a request-scoped context AND the class itself is request-scoped.
|
|
319
|
+
for (const stmt of sourceFile.statements) {
|
|
320
|
+
if (!ts.isClassDeclaration(stmt))
|
|
321
|
+
continue;
|
|
322
|
+
if (classIsDbosStepHost(stmt))
|
|
323
|
+
continue;
|
|
324
|
+
if (!classLooksRequestScoped(stmt))
|
|
325
|
+
continue;
|
|
326
|
+
for (const member of stmt.members) {
|
|
327
|
+
if (!ts.isPropertyDeclaration(member))
|
|
328
|
+
continue;
|
|
329
|
+
if (!ts.isIdentifier(member.name))
|
|
330
|
+
continue;
|
|
331
|
+
const mods = ts.getModifiers(member);
|
|
332
|
+
const isReadonly = mods?.some((m) => m.kind === ts.SyntaxKind.ReadonlyKeyword) ?? false;
|
|
333
|
+
const isStatic = mods?.some((m) => m.kind === ts.SyntaxKind.StaticKeyword) ?? false;
|
|
334
|
+
if (isReadonly || isStatic)
|
|
335
|
+
continue;
|
|
336
|
+
// OTel SDK types are process/propagation scoped, not request state.
|
|
337
|
+
if (typeRefNames(member.type).some((n) => otelImportedNames.has(n)))
|
|
338
|
+
continue;
|
|
339
|
+
if (!typeLooksLikeRequestContext(member.type))
|
|
340
|
+
continue;
|
|
341
|
+
const start = member.getStart(sourceFile);
|
|
342
|
+
const { line, character } = sourceFile.getLineAndCharacterOfPosition(start);
|
|
343
|
+
findings.push({
|
|
344
|
+
line: line + 1,
|
|
345
|
+
column: character + 1,
|
|
346
|
+
match: `private ${member.name.text}: <Context>`,
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
return findings;
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Check: resilience/context-leakage
|
|
354
|
+
*
|
|
355
|
+
* Detects request context stored in module or class scope, which could cause
|
|
356
|
+
* cross-request pollution in multi-tenant / concurrent server environments.
|
|
357
|
+
*
|
|
358
|
+
* Implemented as a TypeScript AST walk. The previous regex implementation flagged:
|
|
359
|
+
* - type-only references (`SyncStrategy<InitialSyncContext>`),
|
|
360
|
+
* - method-parameter types (`(ctx: SomeContext) => …`),
|
|
361
|
+
* - module-level lazy-init metric instruments (`let counter: Counter | null = null`).
|
|
362
|
+
* The AST rewrite eliminates those false positives by inspecting the actual
|
|
363
|
+
* declaration shape rather than line text.
|
|
364
|
+
*/
|
|
365
|
+
export const contextLeakage = defineCheck({
|
|
366
|
+
id: '037b58ef-7b7d-404c-896b-2d40efe02a95',
|
|
367
|
+
slug: 'context-leakage',
|
|
368
|
+
scope: { languages: ['typescript'], concerns: ['backend', 'frontend', 'cli'] },
|
|
369
|
+
description: 'Detect potential request context leakage',
|
|
370
|
+
longDescription: `**Purpose:** Detects request context stored in module or class scope, which can leak between concurrent requests.
|
|
371
|
+
|
|
372
|
+
**Detects (AST-based):**
|
|
373
|
+
- Module-level mutable bindings (\`let\`/\`var\`) whose declared type ends in \`Context\` or \`Ctx\` (e.g. \`let activeContext: RequestContext | null = null\`).
|
|
374
|
+
- Class \`PropertyDeclaration\` (non-\`readonly\`, non-\`static\`) whose type ends in \`Context\` or \`Ctx\` AND whose enclosing class is heuristically request-scoped (a method takes a \`tenantId\` parameter, or the class declares a \`requestId\` field).
|
|
375
|
+
|
|
376
|
+
**Explicitly excluded:**
|
|
377
|
+
- Type-only generic-argument references (\`SyncStrategy<InitialSyncContext>\`, \`Injector<AuditContext>\`, \`Promise<Foo>\`) — the outer wrapper identifier suppresses recursion into generics.
|
|
378
|
+
- Method-parameter types (\`(ctx: SomeContext) => …\`) — parameters are never module-level declarations.
|
|
379
|
+
- Function-local bindings — only top-level \`SourceFile.statements\` are walked.
|
|
380
|
+
- DBOS step \`static ctx\` slots — files under \`**/dbos/steps/**\` are skipped, and classes whose members carry \`@DBOS.step()\` / \`@DBOS.workflow()\` decorators are skipped.
|
|
381
|
+
- Module-level OTel lazy-init shape: \`let <name>: <MetricType> | null = null\` where \`<MetricType>\` is one of \`Counter\`, \`Histogram\`, \`UpDownCounter\`, \`Gauge\`, \`Observable*\`, \`Meter\`, \`Tracer\`, \`TracerProvider\`, \`MeterProvider\` — these are process-scoped per-instrument caches, not per-request state.
|
|
382
|
+
- \`AsyncLocalStorage\`-typed declarations — the correct request-scoping primitive.
|
|
383
|
+
|
|
384
|
+
**Why it matters:** Storing per-request context in shared scope causes cross-request pollution in multi-tenant or concurrent server environments.
|
|
385
|
+
|
|
386
|
+
**Known limitations:**
|
|
387
|
+
- The "class is request-scoped" check is a syntactic heuristic — it does not consult the type checker. A request handler that doesn't take \`tenantId\` directly (e.g. takes a \`FastifyRequest\` and reads tenant from inside) will not match. Prefer adding a \`requestId\` field on such classes if you want them in scope.
|
|
388
|
+
- Inline-typed module bindings (\`let foo = someValue\` with no annotation) are not flagged — the AST has no type information without the type checker. If you want stricter detection, declare the type explicitly.
|
|
389
|
+
|
|
390
|
+
**Scope:** General best practice. Analyzes each file individually via a single AST walk.`,
|
|
391
|
+
tags: ['resilience', 'context', 'security'],
|
|
392
|
+
fileTypes: ['ts', 'tsx'],
|
|
393
|
+
analyze: analyzeContextLeakage,
|
|
394
|
+
});
|
|
395
|
+
/**
|
|
396
|
+
* Analyze a file for request-context leakage. Exported for the FP-regression
|
|
397
|
+
* suite (see `__tests__/context-leakage-fp.test.ts`).
|
|
398
|
+
*/
|
|
399
|
+
export function analyzeContextLeakage(content, filePath) {
|
|
400
|
+
if (isTestFile(filePath))
|
|
401
|
+
return [];
|
|
402
|
+
if (isSkippedPath(filePath))
|
|
403
|
+
return [];
|
|
404
|
+
logger.debug({
|
|
405
|
+
evt: 'fitness.checks.context_leakage.context_leakage_analyze',
|
|
406
|
+
msg: 'Analyzing file for request context leakage (AST)',
|
|
407
|
+
});
|
|
408
|
+
// Quick text bail-out: if the file mentions neither "context" nor "ctx",
|
|
409
|
+
// there is nothing to find. Saves the parse-cache hit.
|
|
410
|
+
const lower = content.toLowerCase();
|
|
411
|
+
if (!lower.includes('context') && !lower.includes('ctx'))
|
|
412
|
+
return [];
|
|
413
|
+
let sourceFile;
|
|
414
|
+
try {
|
|
415
|
+
sourceFile = getSharedSourceFile(filePath, content);
|
|
416
|
+
}
|
|
417
|
+
catch {
|
|
418
|
+
// @swallow-ok Skip files that fail to parse — no signal to emit.
|
|
419
|
+
return [];
|
|
420
|
+
}
|
|
421
|
+
if (!sourceFile)
|
|
422
|
+
return [];
|
|
423
|
+
const findings = collectContextLeakage(sourceFile);
|
|
424
|
+
return findings.map((f) => ({
|
|
425
|
+
line: f.line,
|
|
426
|
+
column: f.column,
|
|
427
|
+
message: 'Request context stored in module/class scope may leak between requests',
|
|
428
|
+
severity: 'warning',
|
|
429
|
+
suggestion: 'Use AsyncLocalStorage for request-scoped context or pass context as a parameter. Storing context in module/class scope can cause cross-request pollution.',
|
|
430
|
+
match: f.match,
|
|
431
|
+
type: 'context-leakage',
|
|
432
|
+
filePath,
|
|
433
|
+
}));
|
|
434
|
+
}
|
|
435
|
+
//# sourceMappingURL=context-leakage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-leakage.js","sourceRoot":"","sources":["../../../src/checks/resilience/context-leakage.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Context mutation safety check — flags direct mutation of
|
|
3
|
+
* request/execution context objects, which causes side effects across
|
|
4
|
+
* middleware in concurrent server environments.
|
|
5
|
+
*/
|
|
6
|
+
import { type CheckViolation } from '@opensip-cli/fitness';
|
|
7
|
+
/**
|
|
8
|
+
* Pure analysis function. Exported so unit tests can exercise the
|
|
9
|
+
* detection logic without standing up the full Check framework
|
|
10
|
+
* (defineCheck wraps `analyze` into an `execute` closure that requires
|
|
11
|
+
* an ExecutionContext to invoke).
|
|
12
|
+
*/
|
|
13
|
+
export declare function analyzeContextMutation(content: string, filePath: string): CheckViolation[];
|
|
14
|
+
/**
|
|
15
|
+
* Check: resilience/context-mutation
|
|
16
|
+
*
|
|
17
|
+
* Detects potentially unsafe mutations of request/execution context objects.
|
|
18
|
+
* Context should be immutable to prevent side effects across middleware.
|
|
19
|
+
*/
|
|
20
|
+
export declare const contextMutationCheck: import("@opensip-cli/fitness").Check;
|
|
21
|
+
//# sourceMappingURL=context-mutation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-mutation.d.ts","sourceRoot":"","sources":["../../../src/checks/resilience/context-mutation.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AAGH,OAAO,EAA8B,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AA8SvF;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,cAAc,EAAE,CAwC1F;AAED;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,sCA0B/B,CAAC"}
|