@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 @@
|
|
|
1
|
+
{"version":3,"file":"unused-config-options.js","sourceRoot":"","sources":["../../../src/checks/quality/unused-config-options.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"callback-invocation-safe.test.d.ts","sourceRoot":"","sources":["../../../../src/checks/resilience/__tests__/callback-invocation-safe.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { analyzeCallbackInvocationSafe } from '../callback-invocation-safe.js';
|
|
3
|
+
const SRC_FILE = 'packages/foo/src/notifier.ts';
|
|
4
|
+
describe('callback-invocation-safe', () => {
|
|
5
|
+
it('flags unwrapped subscribers.forEach((cb) => cb(x))', () => {
|
|
6
|
+
const src = `
|
|
7
|
+
class Notifier {
|
|
8
|
+
private subscribers: ((x: number) => void)[] = []
|
|
9
|
+
notify(x: number) {
|
|
10
|
+
this.subscribers.forEach((cb) => cb(x))
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
`;
|
|
14
|
+
const v = analyzeCallbackInvocationSafe(src, SRC_FILE);
|
|
15
|
+
expect(v.length).toBeGreaterThanOrEqual(1);
|
|
16
|
+
expect(v[0]?.message).toMatch(/Direct callback invocation/);
|
|
17
|
+
});
|
|
18
|
+
it('flags unwrapped for-of over listeners', () => {
|
|
19
|
+
const src = `
|
|
20
|
+
class Bus {
|
|
21
|
+
private listeners: (() => void)[] = []
|
|
22
|
+
fire() {
|
|
23
|
+
for (const cb of this.listeners) {
|
|
24
|
+
cb()
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
`;
|
|
29
|
+
const v = analyzeCallbackInvocationSafe(src, SRC_FILE);
|
|
30
|
+
expect(v.length).toBeGreaterThanOrEqual(1);
|
|
31
|
+
});
|
|
32
|
+
it('does NOT flag when the invocation goes through a safe<Name>() wrapper', () => {
|
|
33
|
+
const src = `
|
|
34
|
+
class Notifier {
|
|
35
|
+
private subscribers: ((x: number) => void)[] = []
|
|
36
|
+
notify(x: number) {
|
|
37
|
+
this.subscribers.forEach((cb) => this.safeInvokeSubscriber(cb, x))
|
|
38
|
+
}
|
|
39
|
+
private safeInvokeSubscriber(cb: any, x: number) {
|
|
40
|
+
try { cb(x) } catch {}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
`;
|
|
44
|
+
expect(analyzeCallbackInvocationSafe(src, SRC_FILE)).toHaveLength(0);
|
|
45
|
+
});
|
|
46
|
+
it('does NOT flag iteration over a non-callback-collection identifier', () => {
|
|
47
|
+
const src = `
|
|
48
|
+
const numbers = [1, 2, 3]
|
|
49
|
+
numbers.forEach((n) => n)
|
|
50
|
+
for (const x of numbers) { x }
|
|
51
|
+
`;
|
|
52
|
+
expect(analyzeCallbackInvocationSafe(src, SRC_FILE)).toHaveLength(0);
|
|
53
|
+
});
|
|
54
|
+
it('skips test files', () => {
|
|
55
|
+
const src = `this.subscribers.forEach((cb) => cb())\n`;
|
|
56
|
+
expect(analyzeCallbackInvocationSafe(src, 'packages/foo/src/__tests__/x.test.ts')).toHaveLength(0);
|
|
57
|
+
});
|
|
58
|
+
it('skips files outside packages/', () => {
|
|
59
|
+
const src = `this.subscribers.forEach((cb) => cb())\n`;
|
|
60
|
+
expect(analyzeCallbackInvocationSafe(src, 'apps/web/src/x.ts')).toHaveLength(0);
|
|
61
|
+
});
|
|
62
|
+
it('honors the @callback-invocation-safe-by-caller pragma with a rationale', () => {
|
|
63
|
+
const src = `
|
|
64
|
+
// @callback-invocation-safe-by-caller -- caller wraps in try/catch
|
|
65
|
+
this.subscribers.forEach((cb) => cb())
|
|
66
|
+
`;
|
|
67
|
+
expect(analyzeCallbackInvocationSafe(src, SRC_FILE)).toHaveLength(0);
|
|
68
|
+
});
|
|
69
|
+
it('flags bare pragma without rationale', () => {
|
|
70
|
+
const src = `
|
|
71
|
+
// @callback-invocation-safe-by-caller
|
|
72
|
+
this.subscribers.forEach((cb) => cb())
|
|
73
|
+
`;
|
|
74
|
+
const v = analyzeCallbackInvocationSafe(src, SRC_FILE);
|
|
75
|
+
expect(v.length).toBeGreaterThanOrEqual(1);
|
|
76
|
+
expect(v[0]?.message).toContain('Bare pragmas are rejected');
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
//# sourceMappingURL=callback-invocation-safe.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"callback-invocation-safe.test.js","sourceRoot":"","sources":["../../../../src/checks/resilience/__tests__/callback-invocation-safe.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,EAAE,6BAA6B,EAAE,MAAM,gCAAgC,CAAC;AAE/E,MAAM,QAAQ,GAAG,8BAA8B,CAAC;AAEhD,QAAQ,CAAC,0BAA0B,EAAE,GAAG,EAAE;IACxC,EAAE,CAAC,oDAAoD,EAAE,GAAG,EAAE;QAC5D,MAAM,GAAG,GAAG;;;;;;;KAOX,CAAC;QACF,MAAM,CAAC,GAAG,6BAA6B,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;QACvD,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC;QAC3C,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,OAAO,CAAC,4BAA4B,CAAC,CAAC;IAC9D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;QAC/C,MAAM,GAAG,GAAG;;;;;;;;;KASX,CAAC;QACF,MAAM,CAAC,GAAG,6BAA6B,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;QACvD,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uEAAuE,EAAE,GAAG,EAAE;QAC/E,MAAM,GAAG,GAAG;;;;;;;;;;KAUX,CAAC;QACF,MAAM,CAAC,6BAA6B,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IACvE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mEAAmE,EAAE,GAAG,EAAE;QAC3E,MAAM,GAAG,GAAG;;;;KAIX,CAAC;QACF,MAAM,CAAC,6BAA6B,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IACvE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kBAAkB,EAAE,GAAG,EAAE;QAC1B,MAAM,GAAG,GAAG,0CAA0C,CAAC;QACvD,MAAM,CAAC,6BAA6B,CAAC,GAAG,EAAE,sCAAsC,CAAC,CAAC,CAAC,YAAY,CAC7F,CAAC,CACF,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;QACvC,MAAM,GAAG,GAAG,0CAA0C,CAAC;QACvD,MAAM,CAAC,6BAA6B,CAAC,GAAG,EAAE,mBAAmB,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAClF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wEAAwE,EAAE,GAAG,EAAE;QAChF,MAAM,GAAG,GAAG;;;KAGX,CAAC;QACF,MAAM,CAAC,6BAA6B,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IACvE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;QAC7C,MAAM,GAAG,GAAG;;;KAGX,CAAC;QACF,MAAM,CAAC,GAAG,6BAA6B,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;QACvD,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC;QAC3C,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,SAAS,CAAC,2BAA2B,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Regression test for the `context-leakage` FP fix.
|
|
3
|
+
*
|
|
4
|
+
* A module-level `let parentContext: Context` holding OpenTelemetry's W3C
|
|
5
|
+
* trace-propagation context was flagged as request-context leakage because
|
|
6
|
+
* the type name ends in "Context". OTel's `Context` is process/propagation
|
|
7
|
+
* scoped, not the per-request tenant context this check targets. The fix
|
|
8
|
+
* inspects the import source: only types imported from `@opentelemetry/*`
|
|
9
|
+
* are spared, so a genuine `let activeContext: RequestContext` still fires.
|
|
10
|
+
*/
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=context-leakage-fp.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-leakage-fp.test.d.ts","sourceRoot":"","sources":["../../../../src/checks/resilience/__tests__/context-leakage-fp.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Regression test for the `context-leakage` FP fix.
|
|
3
|
+
*
|
|
4
|
+
* A module-level `let parentContext: Context` holding OpenTelemetry's W3C
|
|
5
|
+
* trace-propagation context was flagged as request-context leakage because
|
|
6
|
+
* the type name ends in "Context". OTel's `Context` is process/propagation
|
|
7
|
+
* scoped, not the per-request tenant context this check targets. The fix
|
|
8
|
+
* inspects the import source: only types imported from `@opentelemetry/*`
|
|
9
|
+
* are spared, so a genuine `let activeContext: RequestContext` still fires.
|
|
10
|
+
*/
|
|
11
|
+
import { describe, expect, it } from 'vitest';
|
|
12
|
+
import { analyzeContextLeakage } from '../context-leakage.js';
|
|
13
|
+
function analyze(src) {
|
|
14
|
+
return analyzeContextLeakage(src, 'src/cli/telemetry/sdk-init.ts');
|
|
15
|
+
}
|
|
16
|
+
describe('context-leakage — OTel Context FP regression', () => {
|
|
17
|
+
it('does NOT flag a module-level binding typed as OTel-imported Context', () => {
|
|
18
|
+
const src = `
|
|
19
|
+
import { context as otelContext, type Context } from '@opentelemetry/api';
|
|
20
|
+
let parentContext: Context | undefined;
|
|
21
|
+
export function setParent(c: Context): void { parentContext = c; }
|
|
22
|
+
`;
|
|
23
|
+
expect(analyze(src)).toHaveLength(0);
|
|
24
|
+
});
|
|
25
|
+
it('STILL flags a module-level binding typed as a non-OTel request context', () => {
|
|
26
|
+
const src = `
|
|
27
|
+
import type { RequestContext } from './http.js';
|
|
28
|
+
let activeContext: RequestContext | null = null;
|
|
29
|
+
export function setCtx(c: RequestContext): void { activeContext = c; }
|
|
30
|
+
`;
|
|
31
|
+
expect(analyze(src).length).toBeGreaterThan(0);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
//# sourceMappingURL=context-leakage-fp.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-leakage-fp.test.js","sourceRoot":"","sources":["../../../../src/checks/resilience/__tests__/context-leakage-fp.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAE9D,SAAS,OAAO,CAAC,GAAW;IAC1B,OAAO,qBAAqB,CAAC,GAAG,EAAE,+BAA+B,CAAC,CAAC;AACrE,CAAC;AAED,QAAQ,CAAC,8CAA8C,EAAE,GAAG,EAAE;IAC5D,EAAE,CAAC,qEAAqE,EAAE,GAAG,EAAE;QAC7E,MAAM,GAAG,GAAG;;;;KAIX,CAAC;QACF,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wEAAwE,EAAE,GAAG,EAAE;QAChF,MAAM,GAAG,GAAG;;;;KAIX,CAAC;QACF,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Regression tests for `context-mutation` FP fix.
|
|
3
|
+
*
|
|
4
|
+
* The 1.0.7 release added detection for locally-declared `ctx` /
|
|
5
|
+
* `context` variables — when the file declares them via `const`/`let`/
|
|
6
|
+
* `var`, subsequent `.X =` mutations are object-construction patterns
|
|
7
|
+
* (`const ctx = {}; ctx.x = ...`), NOT mutations of a shared request
|
|
8
|
+
* context. This test pins the FP that previously fired.
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=context-mutation.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-mutation.test.d.ts","sourceRoot":"","sources":["../../../../src/checks/resilience/__tests__/context-mutation.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Regression tests for `context-mutation` FP fix.
|
|
3
|
+
*
|
|
4
|
+
* The 1.0.7 release added detection for locally-declared `ctx` /
|
|
5
|
+
* `context` variables — when the file declares them via `const`/`let`/
|
|
6
|
+
* `var`, subsequent `.X =` mutations are object-construction patterns
|
|
7
|
+
* (`const ctx = {}; ctx.x = ...`), NOT mutations of a shared request
|
|
8
|
+
* context. This test pins the FP that previously fired.
|
|
9
|
+
*/
|
|
10
|
+
import { describe, expect, it } from 'vitest';
|
|
11
|
+
import { analyzeContextMutation } from '../context-mutation.js';
|
|
12
|
+
function analyze(src) {
|
|
13
|
+
return analyzeContextMutation(src, 'test.ts');
|
|
14
|
+
}
|
|
15
|
+
describe('context-mutation — FP regression suite (1.0.7)', () => {
|
|
16
|
+
it('does NOT flag mutations on a locally-declared const ctx object', () => {
|
|
17
|
+
const src = `
|
|
18
|
+
function buildContext() {
|
|
19
|
+
const ctx: { foo?: string; bar?: number } = {}
|
|
20
|
+
ctx.foo = 'value'
|
|
21
|
+
ctx.bar = 42
|
|
22
|
+
return ctx
|
|
23
|
+
}
|
|
24
|
+
`;
|
|
25
|
+
expect(analyze(src)).toHaveLength(0);
|
|
26
|
+
});
|
|
27
|
+
it('does NOT flag mutations on a locally-declared let context object', () => {
|
|
28
|
+
const src = `
|
|
29
|
+
function build() {
|
|
30
|
+
let context: Record<string, unknown> = {}
|
|
31
|
+
context.id = 'abc'
|
|
32
|
+
return context
|
|
33
|
+
}
|
|
34
|
+
`;
|
|
35
|
+
expect(analyze(src)).toHaveLength(0);
|
|
36
|
+
});
|
|
37
|
+
it('STILL flags mutations on req.context (passed request)', () => {
|
|
38
|
+
const src = `
|
|
39
|
+
function middleware(req: Request) {
|
|
40
|
+
req.context.user = 'X'
|
|
41
|
+
}
|
|
42
|
+
`;
|
|
43
|
+
expect(analyze(src).length).toBeGreaterThanOrEqual(1);
|
|
44
|
+
});
|
|
45
|
+
it('STILL flags mutations on request.context (passed request)', () => {
|
|
46
|
+
const src = `
|
|
47
|
+
function middleware(request: Request) {
|
|
48
|
+
request.context.user = 'X'
|
|
49
|
+
}
|
|
50
|
+
`;
|
|
51
|
+
expect(analyze(src).length).toBeGreaterThanOrEqual(1);
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
//# sourceMappingURL=context-mutation.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-mutation.test.js","sourceRoot":"","sources":["../../../../src/checks/resilience/__tests__/context-mutation.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAEhE,SAAS,OAAO,CAAC,GAAW;IAC1B,OAAO,sBAAsB,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;AAChD,CAAC;AAED,QAAQ,CAAC,gDAAgD,EAAE,GAAG,EAAE;IAC9D,EAAE,CAAC,gEAAgE,EAAE,GAAG,EAAE;QACxE,MAAM,GAAG,GAAG;;;;;;;KAOX,CAAC;QACF,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kEAAkE,EAAE,GAAG,EAAE;QAC1E,MAAM,GAAG,GAAG;;;;;;KAMX,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;;;;KAIX,CAAC;QACF,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2DAA2D,EAAE,GAAG,EAAE;QACnE,MAAM,GAAG,GAAG;;;;KAIX,CAAC;QACF,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview resilience/callback-invocation-safe — callbacks iterated
|
|
3
|
+
* from producer code paths (`subscribers.forEach((cb) => cb(...))`,
|
|
4
|
+
* `for (const cb of listeners) { cb(...) }`) must be wrapped in a
|
|
5
|
+
* `safe<Name>(...)` helper or a `try { ... }` block. A throw from a
|
|
6
|
+
* single subscriber must never crash the producer or skip subsequent
|
|
7
|
+
* subscribers in the same notification.
|
|
8
|
+
*
|
|
9
|
+
* Why it matters: callback iteration inside `setInterval` or async
|
|
10
|
+
* drain loops will surface a subscriber throw as `uncaughtException`
|
|
11
|
+
* — and even on a synchronous code path, an unprotected throw drops
|
|
12
|
+
* every later subscriber in the same loop iteration. The contract is
|
|
13
|
+
* "subscribers are isolated"; this check is the regression gate.
|
|
14
|
+
*
|
|
15
|
+
* Scope (deliberately narrow):
|
|
16
|
+
* - `.ts` / `.tsx` source under `packages/`.
|
|
17
|
+
* - Skips tests and `.d.ts`.
|
|
18
|
+
* - Detects only iteration over identifiers ending in
|
|
19
|
+
* `subscribers`, `listeners`, `observers`, `callbacks`, `handlers`.
|
|
20
|
+
*
|
|
21
|
+
* Per-site opt-out: `// @callback-invocation-safe-by-caller -- <reason>`
|
|
22
|
+
* on the same line or the line immediately above. A bare pragma without
|
|
23
|
+
* `-- <reason>` is itself flagged so reviewers can grep the rationale.
|
|
24
|
+
*
|
|
25
|
+
* Confidence: low. Under-flag aggressively. This is a regression guard,
|
|
26
|
+
* not a discovery tool.
|
|
27
|
+
*
|
|
28
|
+
* Inspired by `opensip-ai/opensip/opensip-cli` `arch-callback-invocation-safe`.
|
|
29
|
+
*/
|
|
30
|
+
import { type CheckViolation } from '@opensip-cli/fitness';
|
|
31
|
+
/** Exported for unit tests. */
|
|
32
|
+
export declare function analyzeCallbackInvocationSafe(content: string, filePath: string): CheckViolation[];
|
|
33
|
+
export declare const callbackInvocationSafe: import("@opensip-cli/fitness").Check;
|
|
34
|
+
//# sourceMappingURL=callback-invocation-safe.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"callback-invocation-safe.d.ts","sourceRoot":"","sources":["../../../src/checks/resilience/callback-invocation-safe.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,EAA2B,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAiKpF,+BAA+B;AAC/B,wBAAgB,6BAA6B,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,cAAc,EAAE,CA+BjG;AAED,eAAO,MAAM,sBAAsB,sCAyBjC,CAAC"}
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
// @fitness-ignore-file callback-invocation-safe -- This file IS the callback-invocation-safe check; its JSDoc and `longDescription` template literal necessarily contain example patterns (`subscribers.forEach((cb) => cb(...))`, `for (const cb of listeners)`) so the documentation can describe what the check detects. The check uses `contentFilter: 'raw'` (intentional — must see real code), so it cannot strip its own documentation. Reviewers grepping for the rationale land here.
|
|
2
|
+
// @fitness-ignore-file performance-anti-patterns -- spread patterns appear in the check's own JSDoc example strings, not real loop code
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview resilience/callback-invocation-safe — callbacks iterated
|
|
5
|
+
* from producer code paths (`subscribers.forEach((cb) => cb(...))`,
|
|
6
|
+
* `for (const cb of listeners) { cb(...) }`) must be wrapped in a
|
|
7
|
+
* `safe<Name>(...)` helper or a `try { ... }` block. A throw from a
|
|
8
|
+
* single subscriber must never crash the producer or skip subsequent
|
|
9
|
+
* subscribers in the same notification.
|
|
10
|
+
*
|
|
11
|
+
* Why it matters: callback iteration inside `setInterval` or async
|
|
12
|
+
* drain loops will surface a subscriber throw as `uncaughtException`
|
|
13
|
+
* — and even on a synchronous code path, an unprotected throw drops
|
|
14
|
+
* every later subscriber in the same loop iteration. The contract is
|
|
15
|
+
* "subscribers are isolated"; this check is the regression gate.
|
|
16
|
+
*
|
|
17
|
+
* Scope (deliberately narrow):
|
|
18
|
+
* - `.ts` / `.tsx` source under `packages/`.
|
|
19
|
+
* - Skips tests and `.d.ts`.
|
|
20
|
+
* - Detects only iteration over identifiers ending in
|
|
21
|
+
* `subscribers`, `listeners`, `observers`, `callbacks`, `handlers`.
|
|
22
|
+
*
|
|
23
|
+
* Per-site opt-out: `// @callback-invocation-safe-by-caller -- <reason>`
|
|
24
|
+
* on the same line or the line immediately above. A bare pragma without
|
|
25
|
+
* `-- <reason>` is itself flagged so reviewers can grep the rationale.
|
|
26
|
+
*
|
|
27
|
+
* Confidence: low. Under-flag aggressively. This is a regression guard,
|
|
28
|
+
* not a discovery tool.
|
|
29
|
+
*
|
|
30
|
+
* Inspired by `opensip-ai/opensip/opensip-cli` `arch-callback-invocation-safe`.
|
|
31
|
+
*/
|
|
32
|
+
import { defineCheck, isTestFile } from '@opensip-cli/fitness';
|
|
33
|
+
const SCOPE_PREFIXES = ['packages/'];
|
|
34
|
+
const PRAGMA_RE = /@callback-invocation-safe-by-caller\s*--\s*\S+/;
|
|
35
|
+
const PRAGMA_BARE_RE = /@callback-invocation-safe-by-caller\b(?!\s*--\s*\S)/;
|
|
36
|
+
const COLLECTION_NAMES = new Set([
|
|
37
|
+
'subscribers',
|
|
38
|
+
'listeners',
|
|
39
|
+
'observers',
|
|
40
|
+
'callbacks',
|
|
41
|
+
'handlers',
|
|
42
|
+
]);
|
|
43
|
+
// Two-step match — first the receiver + `.forEach(`, then the arrow
|
|
44
|
+
// parameter. Splitting the original mega-regex avoids the
|
|
45
|
+
// sonarjs/regex-complexity ceiling and makes each step easier to reason
|
|
46
|
+
// about. Both regexes are bounded — they only consume identifier chars
|
|
47
|
+
// and a few whitespace boundaries, never backtrack on user input.
|
|
48
|
+
const FOREACH_HEAD_RE = /\b([A-Za-z_$][\w$]*)\s*\.\s*forEach\s*\(\s*/g;
|
|
49
|
+
// eslint-disable-next-line sonarjs/slow-regex -- arrow header; bounded prefix optional groups, anchored at slice start
|
|
50
|
+
const FOREACH_ARROW_RE = /^(?:async\s+)?\(?\s*([A-Za-z_$][\w$]*)\s*\)?\s*=>\s*\{?\s*/;
|
|
51
|
+
// `for (const <ident> of <receiver>) { ... }`
|
|
52
|
+
const FOR_OF_INVOCATION_RE = /\bfor\s*\(\s*(?:const|let)\s+([A-Za-z_$][\w$]*)\s+of\s+(?:this\s*\.\s*)?([A-Za-z_$][\w$]*)\s*\)\s*\{/g;
|
|
53
|
+
function collectionNameMatches(name) {
|
|
54
|
+
const lower = name.toLowerCase();
|
|
55
|
+
for (const n of COLLECTION_NAMES) {
|
|
56
|
+
if (lower === n || lower.endsWith(n))
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
function lineNumberOfIndex(content, index) {
|
|
62
|
+
let line = 1;
|
|
63
|
+
for (let i = 0; i < index && i < content.length; i++) {
|
|
64
|
+
if (content[i] === '\n')
|
|
65
|
+
line++;
|
|
66
|
+
}
|
|
67
|
+
return line;
|
|
68
|
+
}
|
|
69
|
+
function inScope(normalized) {
|
|
70
|
+
return SCOPE_PREFIXES.some((p) => normalized.startsWith(p) || normalized.includes(`/${p}`));
|
|
71
|
+
}
|
|
72
|
+
function bodyInvokesIdent(body, ident) {
|
|
73
|
+
const re = new RegExp(String.raw `(?<![A-Za-z0-9_$.])` + ident + String.raw `\s*\(`);
|
|
74
|
+
return re.test(body);
|
|
75
|
+
}
|
|
76
|
+
function bodyHasSafeWrapper(body) {
|
|
77
|
+
return /\bsafe[A-Z][\w$]*\s*\(/.test(body);
|
|
78
|
+
}
|
|
79
|
+
function isInsideTryBlock(stripped, idx) {
|
|
80
|
+
const start = Math.max(0, idx - 400);
|
|
81
|
+
const slice = stripped.slice(start, idx);
|
|
82
|
+
const lastTry = slice.lastIndexOf('try');
|
|
83
|
+
if (lastTry === -1)
|
|
84
|
+
return false;
|
|
85
|
+
let depth = 0;
|
|
86
|
+
let saw = false;
|
|
87
|
+
for (let i = lastTry; i < slice.length; i++) {
|
|
88
|
+
const ch = slice[i];
|
|
89
|
+
if (ch === '{') {
|
|
90
|
+
depth++;
|
|
91
|
+
saw = true;
|
|
92
|
+
}
|
|
93
|
+
else if (ch === '}') {
|
|
94
|
+
depth--;
|
|
95
|
+
if (saw && depth <= 0)
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return saw && depth > 0;
|
|
100
|
+
}
|
|
101
|
+
function pragmaAt(lines, callLine) {
|
|
102
|
+
for (const offset of [0, -1]) {
|
|
103
|
+
const idx = callLine - 1 + offset;
|
|
104
|
+
if (idx < 0 || idx >= lines.length)
|
|
105
|
+
continue;
|
|
106
|
+
const line = lines[idx] ?? '';
|
|
107
|
+
if (PRAGMA_RE.test(line))
|
|
108
|
+
return 'honored';
|
|
109
|
+
if (PRAGMA_BARE_RE.test(line))
|
|
110
|
+
return 'bare';
|
|
111
|
+
}
|
|
112
|
+
return 'absent';
|
|
113
|
+
}
|
|
114
|
+
function fileIsInScope(filePath) {
|
|
115
|
+
if (!filePath.endsWith('.ts') && !filePath.endsWith('.tsx'))
|
|
116
|
+
return false;
|
|
117
|
+
if (filePath.endsWith('.d.ts'))
|
|
118
|
+
return false;
|
|
119
|
+
if (isTestFile(filePath))
|
|
120
|
+
return false;
|
|
121
|
+
return inScope(filePath.replaceAll('\\', '/'));
|
|
122
|
+
}
|
|
123
|
+
function contentMentionsCollection(content) {
|
|
124
|
+
for (const name of COLLECTION_NAMES) {
|
|
125
|
+
if (content.includes(name))
|
|
126
|
+
return true;
|
|
127
|
+
}
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
function shouldEmitForEachSite(content, m) {
|
|
131
|
+
const receiver = m[1] ?? '';
|
|
132
|
+
if (!collectionNameMatches(receiver))
|
|
133
|
+
return null;
|
|
134
|
+
const idx = m.index ?? 0;
|
|
135
|
+
// The match consumed up to and including the `(` of forEach; parse the
|
|
136
|
+
// arrow parameter from the slice that follows.
|
|
137
|
+
const afterParen = content.slice(idx + m[0].length, idx + m[0].length + 200);
|
|
138
|
+
const arrowMatch = FOREACH_ARROW_RE.exec(afterParen);
|
|
139
|
+
if (!arrowMatch)
|
|
140
|
+
return null;
|
|
141
|
+
const ident = arrowMatch[1] ?? '';
|
|
142
|
+
const bodyTail = afterParen.slice(arrowMatch[0].length, arrowMatch[0].length + 200);
|
|
143
|
+
if (!bodyInvokesIdent(bodyTail, ident))
|
|
144
|
+
return null;
|
|
145
|
+
if (bodyHasSafeWrapper(bodyTail))
|
|
146
|
+
return null;
|
|
147
|
+
if (isInsideTryBlock(content, idx))
|
|
148
|
+
return null;
|
|
149
|
+
return { callLine: lineNumberOfIndex(content, idx), receiver, ident };
|
|
150
|
+
}
|
|
151
|
+
function shouldEmitForOfSite(content, m) {
|
|
152
|
+
const ident = m[1] ?? '';
|
|
153
|
+
const receiver = m[2] ?? '';
|
|
154
|
+
if (!collectionNameMatches(receiver))
|
|
155
|
+
return null;
|
|
156
|
+
const idx = m.index ?? 0;
|
|
157
|
+
const blockBody = content.slice(idx, Math.min(content.length, idx + 400));
|
|
158
|
+
if (!bodyInvokesIdent(blockBody, ident))
|
|
159
|
+
return null;
|
|
160
|
+
if (bodyHasSafeWrapper(blockBody))
|
|
161
|
+
return null;
|
|
162
|
+
if (isInsideTryBlock(content, idx))
|
|
163
|
+
return null;
|
|
164
|
+
return { callLine: lineNumberOfIndex(content, idx), receiver, ident };
|
|
165
|
+
}
|
|
166
|
+
function findCallSites(content) {
|
|
167
|
+
const sites = [];
|
|
168
|
+
for (const m of content.matchAll(FOREACH_HEAD_RE)) {
|
|
169
|
+
const site = shouldEmitForEachSite(content, m);
|
|
170
|
+
if (site)
|
|
171
|
+
sites.push(site);
|
|
172
|
+
}
|
|
173
|
+
for (const m of content.matchAll(FOR_OF_INVOCATION_RE)) {
|
|
174
|
+
const site = shouldEmitForOfSite(content, m);
|
|
175
|
+
if (site)
|
|
176
|
+
sites.push(site);
|
|
177
|
+
}
|
|
178
|
+
return sites;
|
|
179
|
+
}
|
|
180
|
+
function barePragmaViolation(line) {
|
|
181
|
+
return {
|
|
182
|
+
line,
|
|
183
|
+
severity: 'error',
|
|
184
|
+
message: `Pragma '@callback-invocation-safe-by-caller' requires a '-- <rationale>' suffix. ` +
|
|
185
|
+
`Bare pragmas are rejected so reviewers can grep the rationale on every opt-out.`,
|
|
186
|
+
suggestion: `Change to '// @callback-invocation-safe-by-caller -- <one-line rationale>'.`,
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
/** Exported for unit tests. */
|
|
190
|
+
export function analyzeCallbackInvocationSafe(content, filePath) {
|
|
191
|
+
if (!fileIsInScope(filePath))
|
|
192
|
+
return [];
|
|
193
|
+
if (!contentMentionsCollection(content))
|
|
194
|
+
return [];
|
|
195
|
+
const sites = findCallSites(content);
|
|
196
|
+
if (sites.length === 0)
|
|
197
|
+
return [];
|
|
198
|
+
const lines = content.split('\n');
|
|
199
|
+
const violations = [];
|
|
200
|
+
const seen = new Set();
|
|
201
|
+
for (const site of sites) {
|
|
202
|
+
if (seen.has(site.callLine))
|
|
203
|
+
continue;
|
|
204
|
+
seen.add(site.callLine);
|
|
205
|
+
const pragma = pragmaAt(lines, site.callLine);
|
|
206
|
+
if (pragma === 'honored')
|
|
207
|
+
continue;
|
|
208
|
+
if (pragma === 'bare') {
|
|
209
|
+
violations.push(barePragmaViolation(site.callLine));
|
|
210
|
+
continue;
|
|
211
|
+
}
|
|
212
|
+
const capIdent = site.ident.charAt(0).toUpperCase() + site.ident.slice(1);
|
|
213
|
+
violations.push({
|
|
214
|
+
line: site.callLine,
|
|
215
|
+
severity: 'error',
|
|
216
|
+
message: `Direct callback invocation \`${site.ident}(...)\` inside iteration over \`${site.receiver}\` is not wrapped in try/catch or a safe<Name>(...) helper. A throw from a single subscriber will propagate out of the producer loop, dropping subsequent subscribers and (under setInterval/async drain) surfacing as uncaughtException.`,
|
|
217
|
+
suggestion: `Wrap the invocation in a private safe${capIdent}(cb, ...args) helper that catches and logs at warn, then call this.safe${capIdent}(cb, ...) instead. Per-site opt-out: '// @callback-invocation-safe-by-caller -- <rationale>'.`,
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
return violations;
|
|
221
|
+
}
|
|
222
|
+
export const callbackInvocationSafe = defineCheck({
|
|
223
|
+
id: 'd3e7b1c8-95a2-4f6d-b8e2-2c4e7a9d1f3c',
|
|
224
|
+
slug: 'callback-invocation-safe',
|
|
225
|
+
scope: { languages: ['typescript'], concerns: ['backend', 'architecture', 'resilience'] },
|
|
226
|
+
contentFilter: 'raw',
|
|
227
|
+
confidence: 'low',
|
|
228
|
+
description: 'Class-field callbacks invoked from producer code paths (subscribers.forEach, for-of over listeners, etc.) must be wrapped in a safe<Name>(...) helper or try/catch. A throw from one subscriber must not crash the producer or skip subsequent subscribers.',
|
|
229
|
+
longDescription: `**Purpose:** Subscriber/listener throws must be isolated from the producer that fires them.
|
|
230
|
+
|
|
231
|
+
**Detects:**
|
|
232
|
+
- \`subscribers.forEach((cb) => cb(...))\` and equivalents over identifiers ending in subscribers/listeners/observers/callbacks/handlers
|
|
233
|
+
- \`for (const cb of <coll>) { cb(...) }\`
|
|
234
|
+
|
|
235
|
+
**Skips when ANY hold:**
|
|
236
|
+
- The invocation is inside a \`try { ... }\` block
|
|
237
|
+
- The body of the iteration uses a \`safe<Name>(...)\` helper instead of the bare callback
|
|
238
|
+
- The opt-out pragma \`// @callback-invocation-safe-by-caller -- <rationale>\` appears on the same line or the line above
|
|
239
|
+
|
|
240
|
+
**Why it matters:** Inside \`setInterval\` or an async drain loop, a subscriber throw becomes \`uncaughtException\` and kills the producer. Even on a sync code path, a throw drops every subsequent subscriber in the same notification — silent partial-failure.
|
|
241
|
+
|
|
242
|
+
**Scope:** TypeScript source under \`packages/\`. Tests, \`.d.ts\`, and files that don't reference any of the recognised collection names are skipped via fast path. Detection is deliberately narrow (confidence: low) — this is a regression guard, not a discovery tool.`,
|
|
243
|
+
tags: ['architecture', 'resilience'],
|
|
244
|
+
fileTypes: ['ts', 'tsx'],
|
|
245
|
+
analyze: analyzeCallbackInvocationSafe,
|
|
246
|
+
});
|
|
247
|
+
//# sourceMappingURL=callback-invocation-safe.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"callback-invocation-safe.js","sourceRoot":"","sources":["../../../src/checks/resilience/callback-invocation-safe.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
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 { type CheckViolation } from '@opensip-cli/fitness';
|
|
6
|
+
/**
|
|
7
|
+
* Check: resilience/context-leakage
|
|
8
|
+
*
|
|
9
|
+
* Detects request context stored in module or class scope, which could cause
|
|
10
|
+
* cross-request pollution in multi-tenant / concurrent server environments.
|
|
11
|
+
*
|
|
12
|
+
* Implemented as a TypeScript AST walk. The previous regex implementation flagged:
|
|
13
|
+
* - type-only references (`SyncStrategy<InitialSyncContext>`),
|
|
14
|
+
* - method-parameter types (`(ctx: SomeContext) => …`),
|
|
15
|
+
* - module-level lazy-init metric instruments (`let counter: Counter | null = null`).
|
|
16
|
+
* The AST rewrite eliminates those false positives by inspecting the actual
|
|
17
|
+
* declaration shape rather than line text.
|
|
18
|
+
*/
|
|
19
|
+
export declare const contextLeakage: import("@opensip-cli/fitness").Check;
|
|
20
|
+
/**
|
|
21
|
+
* Analyze a file for request-context leakage. Exported for the FP-regression
|
|
22
|
+
* suite (see `__tests__/context-leakage-fp.test.ts`).
|
|
23
|
+
*/
|
|
24
|
+
export declare function analyzeContextLeakage(content: string, filePath: string): CheckViolation[];
|
|
25
|
+
//# sourceMappingURL=context-leakage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-leakage.d.ts","sourceRoot":"","sources":["../../../src/checks/resilience/context-leakage.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAA2B,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAkXpF;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,cAAc,sCA8BzB,CAAC;AAEH;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,cAAc,EAAE,CAmCzF"}
|