@opensip-cli/checks-universal 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 +17 -0
- package/dist/__tests__/all-checks-execute.test.d.ts.map +1 -0
- package/dist/__tests__/all-checks-execute.test.js +452 -0
- package/dist/__tests__/all-checks-execute.test.js.map +1 -0
- package/dist/__tests__/behavior-fixtures-10.test.d.ts +8 -0
- package/dist/__tests__/behavior-fixtures-10.test.d.ts.map +1 -0
- package/dist/__tests__/behavior-fixtures-10.test.js +200 -0
- package/dist/__tests__/behavior-fixtures-10.test.js.map +1 -0
- package/dist/__tests__/behavior-fixtures-11.test.d.ts +8 -0
- package/dist/__tests__/behavior-fixtures-11.test.d.ts.map +1 -0
- package/dist/__tests__/behavior-fixtures-11.test.js +120 -0
- package/dist/__tests__/behavior-fixtures-11.test.js.map +1 -0
- package/dist/__tests__/behavior-fixtures-12.test.d.ts +8 -0
- package/dist/__tests__/behavior-fixtures-12.test.d.ts.map +1 -0
- package/dist/__tests__/behavior-fixtures-12.test.js +157 -0
- package/dist/__tests__/behavior-fixtures-12.test.js.map +1 -0
- package/dist/__tests__/behavior-fixtures-2.test.d.ts +8 -0
- package/dist/__tests__/behavior-fixtures-2.test.d.ts.map +1 -0
- package/dist/__tests__/behavior-fixtures-2.test.js +785 -0
- package/dist/__tests__/behavior-fixtures-2.test.js.map +1 -0
- package/dist/__tests__/behavior-fixtures-3.test.d.ts +6 -0
- package/dist/__tests__/behavior-fixtures-3.test.d.ts.map +1 -0
- package/dist/__tests__/behavior-fixtures-3.test.js +663 -0
- package/dist/__tests__/behavior-fixtures-3.test.js.map +1 -0
- package/dist/__tests__/behavior-fixtures-4.test.d.ts +5 -0
- package/dist/__tests__/behavior-fixtures-4.test.d.ts.map +1 -0
- package/dist/__tests__/behavior-fixtures-4.test.js +612 -0
- package/dist/__tests__/behavior-fixtures-4.test.js.map +1 -0
- package/dist/__tests__/behavior-fixtures-5.test.d.ts +5 -0
- package/dist/__tests__/behavior-fixtures-5.test.d.ts.map +1 -0
- package/dist/__tests__/behavior-fixtures-5.test.js +469 -0
- package/dist/__tests__/behavior-fixtures-5.test.js.map +1 -0
- package/dist/__tests__/behavior-fixtures-6.test.d.ts +8 -0
- package/dist/__tests__/behavior-fixtures-6.test.d.ts.map +1 -0
- package/dist/__tests__/behavior-fixtures-6.test.js +591 -0
- package/dist/__tests__/behavior-fixtures-6.test.js.map +1 -0
- package/dist/__tests__/behavior-fixtures-7.test.d.ts +5 -0
- package/dist/__tests__/behavior-fixtures-7.test.d.ts.map +1 -0
- package/dist/__tests__/behavior-fixtures-7.test.js +662 -0
- package/dist/__tests__/behavior-fixtures-7.test.js.map +1 -0
- package/dist/__tests__/behavior-fixtures-8.test.d.ts +11 -0
- package/dist/__tests__/behavior-fixtures-8.test.d.ts.map +1 -0
- package/dist/__tests__/behavior-fixtures-8.test.js +634 -0
- package/dist/__tests__/behavior-fixtures-8.test.js.map +1 -0
- package/dist/__tests__/behavior-fixtures-9.test.d.ts +11 -0
- package/dist/__tests__/behavior-fixtures-9.test.d.ts.map +1 -0
- package/dist/__tests__/behavior-fixtures-9.test.js +271 -0
- package/dist/__tests__/behavior-fixtures-9.test.js.map +1 -0
- package/dist/__tests__/behavior-fixtures.test.d.ts +14 -0
- package/dist/__tests__/behavior-fixtures.test.d.ts.map +1 -0
- package/dist/__tests__/behavior-fixtures.test.js +1423 -0
- package/dist/__tests__/behavior-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 +61 -0
- package/dist/__tests__/checks.test.js.map +1 -0
- package/dist/__tests__/env-var-validation.test.d.ts +14 -0
- package/dist/__tests__/env-var-validation.test.d.ts.map +1 -0
- package/dist/__tests__/env-var-validation.test.js +53 -0
- package/dist/__tests__/env-var-validation.test.js.map +1 -0
- package/dist/__tests__/file-length-limit.test.d.ts +2 -0
- package/dist/__tests__/file-length-limit.test.d.ts.map +1 -0
- package/dist/__tests__/file-length-limit.test.js +29 -0
- package/dist/__tests__/file-length-limit.test.js.map +1 -0
- package/dist/__tests__/fixture-coverage.allowlist.d.ts +18 -0
- package/dist/__tests__/fixture-coverage.allowlist.d.ts.map +1 -0
- package/dist/__tests__/fixture-coverage.allowlist.js +35 -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__/iic.test.d.ts +15 -0
- package/dist/__tests__/iic.test.d.ts.map +1 -0
- package/dist/__tests__/iic.test.js +316 -0
- package/dist/__tests__/iic.test.js.map +1 -0
- package/dist/__tests__/no-skipped-tests.test.d.ts +14 -0
- package/dist/__tests__/no-skipped-tests.test.d.ts.map +1 -0
- package/dist/__tests__/no-skipped-tests.test.js +144 -0
- package/dist/__tests__/no-skipped-tests.test.js.map +1 -0
- package/dist/__tests__/no-todo-comments.test.d.ts +2 -0
- package/dist/__tests__/no-todo-comments.test.d.ts.map +1 -0
- package/dist/__tests__/no-todo-comments.test.js +31 -0
- package/dist/__tests__/no-todo-comments.test.js.map +1 -0
- package/dist/__tests__/no-unimplemented-markers.test.d.ts +2 -0
- package/dist/__tests__/no-unimplemented-markers.test.d.ts.map +1 -0
- package/dist/__tests__/no-unimplemented-markers.test.js +140 -0
- package/dist/__tests__/no-unimplemented-markers.test.js.map +1 -0
- package/dist/__tests__/public-api-jsdoc-scope.test.d.ts +10 -0
- package/dist/__tests__/public-api-jsdoc-scope.test.d.ts.map +1 -0
- package/dist/__tests__/public-api-jsdoc-scope.test.js +176 -0
- package/dist/__tests__/public-api-jsdoc-scope.test.js.map +1 -0
- package/dist/__tests__/resilience-fp.test.d.ts +14 -0
- package/dist/__tests__/resilience-fp.test.d.ts.map +1 -0
- package/dist/__tests__/resilience-fp.test.js +110 -0
- package/dist/__tests__/resilience-fp.test.js.map +1 -0
- package/dist/checks/architecture/__tests__/no-kebab-option-indexing.test.d.ts +2 -0
- package/dist/checks/architecture/__tests__/no-kebab-option-indexing.test.d.ts.map +1 -0
- package/dist/checks/architecture/__tests__/no-kebab-option-indexing.test.js +32 -0
- package/dist/checks/architecture/__tests__/no-kebab-option-indexing.test.js.map +1 -0
- package/dist/checks/architecture/__tests__/tool-has-manifest.test.d.ts +2 -0
- package/dist/checks/architecture/__tests__/tool-has-manifest.test.d.ts.map +1 -0
- package/dist/checks/architecture/__tests__/tool-has-manifest.test.js +152 -0
- package/dist/checks/architecture/__tests__/tool-has-manifest.test.js.map +1 -0
- package/dist/checks/architecture/__tests__/vitest-config-required-with-tests.test.d.ts +2 -0
- package/dist/checks/architecture/__tests__/vitest-config-required-with-tests.test.d.ts.map +1 -0
- package/dist/checks/architecture/__tests__/vitest-config-required-with-tests.test.js +129 -0
- package/dist/checks/architecture/__tests__/vitest-config-required-with-tests.test.js.map +1 -0
- package/dist/checks/architecture/_yaml-doc-bindings.d.ts +23 -0
- package/dist/checks/architecture/_yaml-doc-bindings.d.ts.map +1 -0
- package/dist/checks/architecture/_yaml-doc-bindings.js +29 -0
- package/dist/checks/architecture/_yaml-doc-bindings.js.map +1 -0
- package/dist/checks/architecture/dependencies/index.d.ts +2 -0
- package/dist/checks/architecture/dependencies/index.d.ts.map +1 -0
- package/dist/checks/architecture/dependencies/index.js +2 -0
- package/dist/checks/architecture/dependencies/index.js.map +1 -0
- package/dist/checks/architecture/dependencies/no-duplicate-packages.d.ts +11 -0
- package/dist/checks/architecture/dependencies/no-duplicate-packages.d.ts.map +1 -0
- package/dist/checks/architecture/dependencies/no-duplicate-packages.js +171 -0
- package/dist/checks/architecture/dependencies/no-duplicate-packages.js.map +1 -0
- package/dist/checks/architecture/docker-best-practices.d.ts +23 -0
- package/dist/checks/architecture/docker-best-practices.d.ts.map +1 -0
- package/dist/checks/architecture/docker-best-practices.js +427 -0
- package/dist/checks/architecture/docker-best-practices.js.map +1 -0
- package/dist/checks/architecture/docker-ignore-validation.d.ts +18 -0
- package/dist/checks/architecture/docker-ignore-validation.d.ts.map +1 -0
- package/dist/checks/architecture/docker-ignore-validation.js +117 -0
- package/dist/checks/architecture/docker-ignore-validation.js.map +1 -0
- package/dist/checks/architecture/docker-version-sync.d.ts +16 -0
- package/dist/checks/architecture/docker-version-sync.d.ts.map +1 -0
- package/dist/checks/architecture/docker-version-sync.js +193 -0
- package/dist/checks/architecture/docker-version-sync.js.map +1 -0
- package/dist/checks/architecture/env-var-validation.d.ts +14 -0
- package/dist/checks/architecture/env-var-validation.d.ts.map +1 -0
- package/dist/checks/architecture/env-var-validation.js +289 -0
- package/dist/checks/architecture/env-var-validation.js.map +1 -0
- package/dist/checks/architecture/heavy-import-detection.d.ts +11 -0
- package/dist/checks/architecture/heavy-import-detection.d.ts.map +1 -0
- package/dist/checks/architecture/heavy-import-detection.js +91 -0
- package/dist/checks/architecture/heavy-import-detection.js.map +1 -0
- package/dist/checks/architecture/index.d.ts +16 -0
- package/dist/checks/architecture/index.d.ts.map +1 -0
- package/dist/checks/architecture/index.js +16 -0
- package/dist/checks/architecture/index.js.map +1 -0
- package/dist/checks/architecture/modules/empty-package-detection.d.ts +11 -0
- package/dist/checks/architecture/modules/empty-package-detection.d.ts.map +1 -0
- package/dist/checks/architecture/modules/empty-package-detection.js +277 -0
- package/dist/checks/architecture/modules/empty-package-detection.js.map +1 -0
- package/dist/checks/architecture/modules/index.d.ts +3 -0
- package/dist/checks/architecture/modules/index.d.ts.map +1 -0
- package/dist/checks/architecture/modules/index.js +3 -0
- package/dist/checks/architecture/modules/index.js.map +1 -0
- package/dist/checks/architecture/modules/interface-implementation-consistency.d.ts +12 -0
- package/dist/checks/architecture/modules/interface-implementation-consistency.d.ts.map +1 -0
- package/dist/checks/architecture/modules/interface-implementation-consistency.js +555 -0
- package/dist/checks/architecture/modules/interface-implementation-consistency.js.map +1 -0
- package/dist/checks/architecture/no-custom-event-emitter.d.ts +11 -0
- package/dist/checks/architecture/no-custom-event-emitter.d.ts.map +1 -0
- package/dist/checks/architecture/no-custom-event-emitter.js +123 -0
- package/dist/checks/architecture/no-custom-event-emitter.js.map +1 -0
- package/dist/checks/architecture/no-kebab-option-indexing.d.ts +33 -0
- package/dist/checks/architecture/no-kebab-option-indexing.d.ts.map +1 -0
- package/dist/checks/architecture/no-kebab-option-indexing.js +81 -0
- package/dist/checks/architecture/no-kebab-option-indexing.js.map +1 -0
- package/dist/checks/architecture/node-version-consistency.d.ts +22 -0
- package/dist/checks/architecture/node-version-consistency.d.ts.map +1 -0
- package/dist/checks/architecture/node-version-consistency.js +225 -0
- package/dist/checks/architecture/node-version-consistency.js.map +1 -0
- package/dist/checks/architecture/project-readme-existence.d.ts +13 -0
- package/dist/checks/architecture/project-readme-existence.d.ts.map +1 -0
- package/dist/checks/architecture/project-readme-existence.js +55 -0
- package/dist/checks/architecture/project-readme-existence.js.map +1 -0
- package/dist/checks/architecture/stale-build-artifacts.d.ts +10 -0
- package/dist/checks/architecture/stale-build-artifacts.d.ts.map +1 -0
- package/dist/checks/architecture/stale-build-artifacts.js +55 -0
- package/dist/checks/architecture/stale-build-artifacts.js.map +1 -0
- package/dist/checks/architecture/tool-has-manifest.d.ts +27 -0
- package/dist/checks/architecture/tool-has-manifest.d.ts.map +1 -0
- package/dist/checks/architecture/tool-has-manifest.js +135 -0
- package/dist/checks/architecture/tool-has-manifest.js.map +1 -0
- package/dist/checks/architecture/vitest-config-extends-base.d.ts +15 -0
- package/dist/checks/architecture/vitest-config-extends-base.d.ts.map +1 -0
- package/dist/checks/architecture/vitest-config-extends-base.js +104 -0
- package/dist/checks/architecture/vitest-config-extends-base.js.map +1 -0
- package/dist/checks/architecture/vitest-config-required-with-tests.d.ts +49 -0
- package/dist/checks/architecture/vitest-config-required-with-tests.d.ts.map +1 -0
- package/dist/checks/architecture/vitest-config-required-with-tests.js +199 -0
- package/dist/checks/architecture/vitest-config-required-with-tests.js.map +1 -0
- package/dist/checks/documentation/_directives/eslint.d.ts +9 -0
- package/dist/checks/documentation/_directives/eslint.d.ts.map +1 -0
- package/dist/checks/documentation/_directives/eslint.js +168 -0
- package/dist/checks/documentation/_directives/eslint.js.map +1 -0
- package/dist/checks/documentation/_directives/fitness.d.ts +9 -0
- package/dist/checks/documentation/_directives/fitness.d.ts.map +1 -0
- package/dist/checks/documentation/_directives/fitness.js +64 -0
- package/dist/checks/documentation/_directives/fitness.js.map +1 -0
- package/dist/checks/documentation/_directives/graph.d.ts +10 -0
- package/dist/checks/documentation/_directives/graph.d.ts.map +1 -0
- package/dist/checks/documentation/_directives/graph.js +65 -0
- package/dist/checks/documentation/_directives/graph.js.map +1 -0
- package/dist/checks/documentation/_directives/graph.test.d.ts +2 -0
- package/dist/checks/documentation/_directives/graph.test.d.ts.map +1 -0
- package/dist/checks/documentation/_directives/graph.test.js +54 -0
- package/dist/checks/documentation/_directives/graph.test.js.map +1 -0
- package/dist/checks/documentation/_directives/semgrep.d.ts +8 -0
- package/dist/checks/documentation/_directives/semgrep.d.ts.map +1 -0
- package/dist/checks/documentation/_directives/semgrep.js +72 -0
- package/dist/checks/documentation/_directives/semgrep.js.map +1 -0
- package/dist/checks/documentation/_directives/types.d.ts +21 -0
- package/dist/checks/documentation/_directives/types.d.ts.map +1 -0
- package/dist/checks/documentation/_directives/types.js +9 -0
- package/dist/checks/documentation/_directives/types.js.map +1 -0
- package/dist/checks/documentation/_directives/typescript.d.ts +10 -0
- package/dist/checks/documentation/_directives/typescript.d.ts.map +1 -0
- package/dist/checks/documentation/_directives/typescript.js +54 -0
- package/dist/checks/documentation/_directives/typescript.js.map +1 -0
- package/dist/checks/documentation/_public-api-graph.d.ts +30 -0
- package/dist/checks/documentation/_public-api-graph.d.ts.map +1 -0
- package/dist/checks/documentation/_public-api-graph.js +304 -0
- package/dist/checks/documentation/_public-api-graph.js.map +1 -0
- package/dist/checks/documentation/directive-audit.d.ts +26 -0
- package/dist/checks/documentation/directive-audit.d.ts.map +1 -0
- package/dist/checks/documentation/directive-audit.js +144 -0
- package/dist/checks/documentation/directive-audit.js.map +1 -0
- package/dist/checks/documentation/index.d.ts +3 -0
- package/dist/checks/documentation/index.d.ts.map +1 -0
- package/dist/checks/documentation/index.js +3 -0
- package/dist/checks/documentation/index.js.map +1 -0
- package/dist/checks/documentation/public-api-jsdoc.d.ts +10 -0
- package/dist/checks/documentation/public-api-jsdoc.d.ts.map +1 -0
- package/dist/checks/documentation/public-api-jsdoc.js +131 -0
- package/dist/checks/documentation/public-api-jsdoc.js.map +1 -0
- package/dist/checks/file-length-limit.d.ts +16 -0
- package/dist/checks/file-length-limit.d.ts.map +1 -0
- package/dist/checks/file-length-limit.js +47 -0
- package/dist/checks/file-length-limit.js.map +1 -0
- package/dist/checks/index.d.ts +16 -0
- package/dist/checks/index.d.ts.map +1 -0
- package/dist/checks/index.js +16 -0
- package/dist/checks/index.js.map +1 -0
- package/dist/checks/no-todo-comments.d.ts +18 -0
- package/dist/checks/no-todo-comments.d.ts.map +1 -0
- package/dist/checks/no-todo-comments.js +79 -0
- package/dist/checks/no-todo-comments.js.map +1 -0
- package/dist/checks/no-unimplemented-markers.d.ts +24 -0
- package/dist/checks/no-unimplemented-markers.d.ts.map +1 -0
- package/dist/checks/no-unimplemented-markers.js +198 -0
- package/dist/checks/no-unimplemented-markers.js.map +1 -0
- package/dist/checks/quality/api/graphql-offset-pagination.d.ts +9 -0
- package/dist/checks/quality/api/graphql-offset-pagination.d.ts.map +1 -0
- package/dist/checks/quality/api/graphql-offset-pagination.js +63 -0
- package/dist/checks/quality/api/graphql-offset-pagination.js.map +1 -0
- package/dist/checks/quality/api/index.d.ts +3 -0
- package/dist/checks/quality/api/index.d.ts.map +1 -0
- package/dist/checks/quality/api/index.js +3 -0
- package/dist/checks/quality/api/index.js.map +1 -0
- package/dist/checks/quality/api/zod-openapi-sync.d.ts +13 -0
- package/dist/checks/quality/api/zod-openapi-sync.d.ts.map +1 -0
- package/dist/checks/quality/api/zod-openapi-sync.js +88 -0
- package/dist/checks/quality/api/zod-openapi-sync.js.map +1 -0
- package/dist/checks/quality/code-structure/dead-code.d.ts +12 -0
- package/dist/checks/quality/code-structure/dead-code.d.ts.map +1 -0
- package/dist/checks/quality/code-structure/dead-code.js +238 -0
- package/dist/checks/quality/code-structure/dead-code.js.map +1 -0
- package/dist/checks/quality/code-structure/index.d.ts +5 -0
- package/dist/checks/quality/code-structure/index.d.ts.map +1 -0
- package/dist/checks/quality/code-structure/index.js +5 -0
- package/dist/checks/quality/code-structure/index.js.map +1 -0
- package/dist/checks/quality/code-structure/no-ai-attribution.d.ts +25 -0
- package/dist/checks/quality/code-structure/no-ai-attribution.d.ts.map +1 -0
- package/dist/checks/quality/code-structure/no-ai-attribution.js +76 -0
- package/dist/checks/quality/code-structure/no-ai-attribution.js.map +1 -0
- package/dist/checks/quality/code-structure/no-console-log.d.ts +17 -0
- package/dist/checks/quality/code-structure/no-console-log.d.ts.map +1 -0
- package/dist/checks/quality/code-structure/no-console-log.js +106 -0
- package/dist/checks/quality/code-structure/no-console-log.js.map +1 -0
- package/dist/checks/quality/code-structure/no-process-artifacts.d.ts +25 -0
- package/dist/checks/quality/code-structure/no-process-artifacts.d.ts.map +1 -0
- package/dist/checks/quality/code-structure/no-process-artifacts.js +104 -0
- package/dist/checks/quality/code-structure/no-process-artifacts.js.map +1 -0
- package/dist/checks/quality/dependency-version-consistency.d.ts +20 -0
- package/dist/checks/quality/dependency-version-consistency.d.ts.map +1 -0
- package/dist/checks/quality/dependency-version-consistency.js +266 -0
- package/dist/checks/quality/dependency-version-consistency.js.map +1 -0
- package/dist/checks/quality/fitness-ignore-hygiene.d.ts +10 -0
- package/dist/checks/quality/fitness-ignore-hygiene.d.ts.map +1 -0
- package/dist/checks/quality/fitness-ignore-hygiene.js +93 -0
- package/dist/checks/quality/fitness-ignore-hygiene.js.map +1 -0
- package/dist/checks/quality/frontend/expo-vector-icons.d.ts +13 -0
- package/dist/checks/quality/frontend/expo-vector-icons.d.ts.map +1 -0
- package/dist/checks/quality/frontend/expo-vector-icons.js +80 -0
- package/dist/checks/quality/frontend/expo-vector-icons.js.map +1 -0
- package/dist/checks/quality/frontend/image-optimization.d.ts +13 -0
- package/dist/checks/quality/frontend/image-optimization.d.ts.map +1 -0
- package/dist/checks/quality/frontend/image-optimization.js +166 -0
- package/dist/checks/quality/frontend/image-optimization.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/navigation-typing.d.ts +12 -0
- package/dist/checks/quality/frontend/navigation-typing.d.ts.map +1 -0
- package/dist/checks/quality/frontend/navigation-typing.js +77 -0
- package/dist/checks/quality/frontend/navigation-typing.js.map +1 -0
- package/dist/checks/quality/graph-ignore-hygiene.d.ts +10 -0
- package/dist/checks/quality/graph-ignore-hygiene.d.ts.map +1 -0
- package/dist/checks/quality/graph-ignore-hygiene.js +95 -0
- package/dist/checks/quality/graph-ignore-hygiene.js.map +1 -0
- package/dist/checks/quality/graph-ignore-hygiene.test.d.ts +14 -0
- package/dist/checks/quality/graph-ignore-hygiene.test.d.ts.map +1 -0
- package/dist/checks/quality/graph-ignore-hygiene.test.js +58 -0
- package/dist/checks/quality/graph-ignore-hygiene.test.js.map +1 -0
- package/dist/checks/quality/index.d.ts +16 -0
- package/dist/checks/quality/index.d.ts.map +1 -0
- package/dist/checks/quality/index.js +16 -0
- package/dist/checks/quality/index.js.map +1 -0
- package/dist/checks/quality/linting/eslint-justifications.d.ts +12 -0
- package/dist/checks/quality/linting/eslint-justifications.d.ts.map +1 -0
- package/dist/checks/quality/linting/eslint-justifications.js +328 -0
- package/dist/checks/quality/linting/eslint-justifications.js.map +1 -0
- package/dist/checks/quality/linting/index.d.ts +4 -0
- package/dist/checks/quality/linting/index.d.ts.map +1 -0
- package/dist/checks/quality/linting/index.js +4 -0
- package/dist/checks/quality/linting/index.js.map +1 -0
- package/dist/checks/quality/linting/semgrep-justifications.d.ts +16 -0
- package/dist/checks/quality/linting/semgrep-justifications.d.ts.map +1 -0
- package/dist/checks/quality/linting/semgrep-justifications.js +229 -0
- package/dist/checks/quality/linting/semgrep-justifications.js.map +1 -0
- package/dist/checks/quality/linting/typescript-directive-hygiene.d.ts +12 -0
- package/dist/checks/quality/linting/typescript-directive-hygiene.d.ts.map +1 -0
- package/dist/checks/quality/linting/typescript-directive-hygiene.js +142 -0
- package/dist/checks/quality/linting/typescript-directive-hygiene.js.map +1 -0
- package/dist/checks/quality/no-compatibility-layer-names.d.ts +13 -0
- package/dist/checks/quality/no-compatibility-layer-names.d.ts.map +1 -0
- package/dist/checks/quality/no-compatibility-layer-names.js +100 -0
- package/dist/checks/quality/no-compatibility-layer-names.js.map +1 -0
- package/dist/checks/quality/no-deprecated-tags.d.ts +11 -0
- package/dist/checks/quality/no-deprecated-tags.d.ts.map +1 -0
- package/dist/checks/quality/no-deprecated-tags.js +76 -0
- package/dist/checks/quality/no-deprecated-tags.js.map +1 -0
- package/dist/checks/quality/no-markdown-references.d.ts +16 -0
- package/dist/checks/quality/no-markdown-references.d.ts.map +1 -0
- package/dist/checks/quality/no-markdown-references.js +145 -0
- package/dist/checks/quality/no-markdown-references.js.map +1 -0
- package/dist/checks/quality/no-raw-regex-on-code.d.ts +9 -0
- package/dist/checks/quality/no-raw-regex-on-code.d.ts.map +1 -0
- package/dist/checks/quality/no-raw-regex-on-code.js +61 -0
- package/dist/checks/quality/no-raw-regex-on-code.js.map +1 -0
- package/dist/checks/quality/no-temporary-workarounds.d.ts +11 -0
- package/dist/checks/quality/no-temporary-workarounds.d.ts.map +1 -0
- package/dist/checks/quality/no-temporary-workarounds.js +69 -0
- package/dist/checks/quality/no-temporary-workarounds.js.map +1 -0
- package/dist/checks/quality/no-window-alert.d.ts +19 -0
- package/dist/checks/quality/no-window-alert.d.ts.map +1 -0
- package/dist/checks/quality/no-window-alert.js +74 -0
- package/dist/checks/quality/no-window-alert.js.map +1 -0
- package/dist/checks/quality/observability/index.d.ts +2 -0
- package/dist/checks/quality/observability/index.d.ts.map +1 -0
- package/dist/checks/quality/observability/index.js +2 -0
- package/dist/checks/quality/observability/index.js.map +1 -0
- package/dist/checks/quality/observability/pino-serializer-coverage.d.ts +15 -0
- package/dist/checks/quality/observability/pino-serializer-coverage.d.ts.map +1 -0
- package/dist/checks/quality/observability/pino-serializer-coverage.js +209 -0
- package/dist/checks/quality/observability/pino-serializer-coverage.js.map +1 -0
- package/dist/checks/quality/patterns/async-state-pattern.d.ts +14 -0
- package/dist/checks/quality/patterns/async-state-pattern.d.ts.map +1 -0
- package/dist/checks/quality/patterns/async-state-pattern.js +80 -0
- package/dist/checks/quality/patterns/async-state-pattern.js.map +1 -0
- package/dist/checks/quality/patterns/index.d.ts +4 -0
- package/dist/checks/quality/patterns/index.d.ts.map +1 -0
- package/dist/checks/quality/patterns/index.js +4 -0
- package/dist/checks/quality/patterns/index.js.map +1 -0
- package/dist/checks/quality/patterns/no-non-null-assertions.d.ts +10 -0
- package/dist/checks/quality/patterns/no-non-null-assertions.d.ts.map +1 -0
- package/dist/checks/quality/patterns/no-non-null-assertions.js +97 -0
- package/dist/checks/quality/patterns/no-non-null-assertions.js.map +1 -0
- package/dist/checks/quality/patterns/performance-anti-patterns.d.ts +16 -0
- package/dist/checks/quality/patterns/performance-anti-patterns.d.ts.map +1 -0
- package/dist/checks/quality/patterns/performance-anti-patterns.js +239 -0
- package/dist/checks/quality/patterns/performance-anti-patterns.js.map +1 -0
- package/dist/checks/resilience/_helpers/config-validation.d.ts +27 -0
- package/dist/checks/resilience/_helpers/config-validation.d.ts.map +1 -0
- package/dist/checks/resilience/_helpers/config-validation.js +61 -0
- package/dist/checks/resilience/_helpers/config-validation.js.map +1 -0
- package/dist/checks/resilience/batch-operations.d.ts +22 -0
- package/dist/checks/resilience/batch-operations.d.ts.map +1 -0
- package/dist/checks/resilience/batch-operations.js +422 -0
- package/dist/checks/resilience/batch-operations.js.map +1 -0
- package/dist/checks/resilience/cache-ttl-validation.d.ts +13 -0
- package/dist/checks/resilience/cache-ttl-validation.d.ts.map +1 -0
- package/dist/checks/resilience/cache-ttl-validation.js +222 -0
- package/dist/checks/resilience/cache-ttl-validation.js.map +1 -0
- package/dist/checks/resilience/catch-clause-safety.d.ts +12 -0
- package/dist/checks/resilience/catch-clause-safety.d.ts.map +1 -0
- package/dist/checks/resilience/catch-clause-safety.js +110 -0
- package/dist/checks/resilience/catch-clause-safety.js.map +1 -0
- package/dist/checks/resilience/dangerous-config-defaults.d.ts +11 -0
- package/dist/checks/resilience/dangerous-config-defaults.d.ts.map +1 -0
- package/dist/checks/resilience/dangerous-config-defaults.js +304 -0
- package/dist/checks/resilience/dangerous-config-defaults.js.map +1 -0
- package/dist/checks/resilience/error-code-registration.d.ts +11 -0
- package/dist/checks/resilience/error-code-registration.d.ts.map +1 -0
- package/dist/checks/resilience/error-code-registration.js +88 -0
- package/dist/checks/resilience/error-code-registration.js.map +1 -0
- package/dist/checks/resilience/event-patterns.d.ts +21 -0
- package/dist/checks/resilience/event-patterns.d.ts.map +1 -0
- package/dist/checks/resilience/event-patterns.js +232 -0
- package/dist/checks/resilience/event-patterns.js.map +1 -0
- package/dist/checks/resilience/exit-code-correctness.d.ts +12 -0
- package/dist/checks/resilience/exit-code-correctness.d.ts.map +1 -0
- package/dist/checks/resilience/exit-code-correctness.js +107 -0
- package/dist/checks/resilience/exit-code-correctness.js.map +1 -0
- package/dist/checks/resilience/index.d.ts +18 -0
- package/dist/checks/resilience/index.d.ts.map +1 -0
- package/dist/checks/resilience/index.js +18 -0
- package/dist/checks/resilience/index.js.map +1 -0
- package/dist/checks/resilience/no-hardcoded-timeouts.d.ts +10 -0
- package/dist/checks/resilience/no-hardcoded-timeouts.d.ts.map +1 -0
- package/dist/checks/resilience/no-hardcoded-timeouts.js +291 -0
- package/dist/checks/resilience/no-hardcoded-timeouts.js.map +1 -0
- package/dist/checks/resilience/no-process-exit-in-finally.d.ts +11 -0
- package/dist/checks/resilience/no-process-exit-in-finally.d.ts.map +1 -0
- package/dist/checks/resilience/no-process-exit-in-finally.js +89 -0
- package/dist/checks/resilience/no-process-exit-in-finally.js.map +1 -0
- package/dist/checks/resilience/readline-cleanup.d.ts +11 -0
- package/dist/checks/resilience/readline-cleanup.d.ts.map +1 -0
- package/dist/checks/resilience/readline-cleanup.js +107 -0
- package/dist/checks/resilience/readline-cleanup.js.map +1 -0
- package/dist/checks/resilience/recovery-patterns.d.ts +25 -0
- package/dist/checks/resilience/recovery-patterns.d.ts.map +1 -0
- package/dist/checks/resilience/recovery-patterns.js +273 -0
- package/dist/checks/resilience/recovery-patterns.js.map +1 -0
- package/dist/checks/resilience/reentrancy-guard.d.ts +12 -0
- package/dist/checks/resilience/reentrancy-guard.d.ts.map +1 -0
- package/dist/checks/resilience/reentrancy-guard.js +86 -0
- package/dist/checks/resilience/reentrancy-guard.js.map +1 -0
- package/dist/checks/resilience/retry-config-validation.d.ts +13 -0
- package/dist/checks/resilience/retry-config-validation.d.ts.map +1 -0
- package/dist/checks/resilience/retry-config-validation.js +159 -0
- package/dist/checks/resilience/retry-config-validation.js.map +1 -0
- package/dist/checks/resilience/sentry/_helpers/sentry.d.ts +25 -0
- package/dist/checks/resilience/sentry/_helpers/sentry.d.ts.map +1 -0
- package/dist/checks/resilience/sentry/_helpers/sentry.js +68 -0
- package/dist/checks/resilience/sentry/_helpers/sentry.js.map +1 -0
- package/dist/checks/resilience/sentry/index.d.ts +8 -0
- package/dist/checks/resilience/sentry/index.d.ts.map +1 -0
- package/dist/checks/resilience/sentry/index.js +8 -0
- package/dist/checks/resilience/sentry/index.js.map +1 -0
- package/dist/checks/resilience/sentry/sentry-dsn-configured.d.ts +12 -0
- package/dist/checks/resilience/sentry/sentry-dsn-configured.d.ts.map +1 -0
- package/dist/checks/resilience/sentry/sentry-dsn-configured.js +55 -0
- package/dist/checks/resilience/sentry/sentry-dsn-configured.js.map +1 -0
- package/dist/checks/resilience/sentry/sentry-environment-set.d.ts +12 -0
- package/dist/checks/resilience/sentry/sentry-environment-set.d.ts.map +1 -0
- package/dist/checks/resilience/sentry/sentry-environment-set.js +51 -0
- package/dist/checks/resilience/sentry/sentry-environment-set.js.map +1 -0
- package/dist/checks/resilience/sentry/sentry-error-boundary.d.ts +12 -0
- package/dist/checks/resilience/sentry/sentry-error-boundary.d.ts.map +1 -0
- package/dist/checks/resilience/sentry/sentry-error-boundary.js +75 -0
- package/dist/checks/resilience/sentry/sentry-error-boundary.js.map +1 -0
- package/dist/checks/resilience/sentry/sentry-pii-scrubbing.d.ts +13 -0
- package/dist/checks/resilience/sentry/sentry-pii-scrubbing.d.ts.map +1 -0
- package/dist/checks/resilience/sentry/sentry-pii-scrubbing.js +125 -0
- package/dist/checks/resilience/sentry/sentry-pii-scrubbing.js.map +1 -0
- package/dist/checks/resilience/sentry/sentry-release-set.d.ts +12 -0
- package/dist/checks/resilience/sentry/sentry-release-set.d.ts.map +1 -0
- package/dist/checks/resilience/sentry/sentry-release-set.js +51 -0
- package/dist/checks/resilience/sentry/sentry-release-set.js.map +1 -0
- package/dist/checks/resilience/sentry/sentry-sample-rate.d.ts +12 -0
- package/dist/checks/resilience/sentry/sentry-sample-rate.d.ts.map +1 -0
- package/dist/checks/resilience/sentry/sentry-sample-rate.js +78 -0
- package/dist/checks/resilience/sentry/sentry-sample-rate.js.map +1 -0
- package/dist/checks/resilience/sentry/sentry-source-maps.d.ts +12 -0
- package/dist/checks/resilience/sentry/sentry-source-maps.d.ts.map +1 -0
- package/dist/checks/resilience/sentry/sentry-source-maps.js +83 -0
- package/dist/checks/resilience/sentry/sentry-source-maps.js.map +1 -0
- package/dist/checks/resilience/service-patterns.d.ts +18 -0
- package/dist/checks/resilience/service-patterns.d.ts.map +1 -0
- package/dist/checks/resilience/service-patterns.js +230 -0
- package/dist/checks/resilience/service-patterns.js.map +1 -0
- package/dist/checks/resilience/timer-lifecycle.d.ts +10 -0
- package/dist/checks/resilience/timer-lifecycle.d.ts.map +1 -0
- package/dist/checks/resilience/timer-lifecycle.js +78 -0
- package/dist/checks/resilience/timer-lifecycle.js.map +1 -0
- package/dist/checks/resilience/transaction-patterns.d.ts +21 -0
- package/dist/checks/resilience/transaction-patterns.d.ts.map +1 -0
- package/dist/checks/resilience/transaction-patterns.js +258 -0
- package/dist/checks/resilience/transaction-patterns.js.map +1 -0
- package/dist/checks/security/__tests__/no-hardcoded-secrets.test.d.ts +9 -0
- package/dist/checks/security/__tests__/no-hardcoded-secrets.test.d.ts.map +1 -0
- package/dist/checks/security/__tests__/no-hardcoded-secrets.test.js +37 -0
- package/dist/checks/security/__tests__/no-hardcoded-secrets.test.js.map +1 -0
- package/dist/checks/security/__tests__/package-supply-chain-policy.test.d.ts +2 -0
- package/dist/checks/security/__tests__/package-supply-chain-policy.test.d.ts.map +1 -0
- package/dist/checks/security/__tests__/package-supply-chain-policy.test.js +128 -0
- package/dist/checks/security/__tests__/package-supply-chain-policy.test.js.map +1 -0
- package/dist/checks/security/api-key-rotation.d.ts +10 -0
- package/dist/checks/security/api-key-rotation.d.ts.map +1 -0
- package/dist/checks/security/api-key-rotation.js +186 -0
- package/dist/checks/security/api-key-rotation.js.map +1 -0
- package/dist/checks/security/auth-middleware-coverage.d.ts +11 -0
- package/dist/checks/security/auth-middleware-coverage.d.ts.map +1 -0
- package/dist/checks/security/auth-middleware-coverage.js +210 -0
- package/dist/checks/security/auth-middleware-coverage.js.map +1 -0
- package/dist/checks/security/auth-route-guard.d.ts +12 -0
- package/dist/checks/security/auth-route-guard.d.ts.map +1 -0
- package/dist/checks/security/auth-route-guard.js +70 -0
- package/dist/checks/security/auth-route-guard.js.map +1 -0
- package/dist/checks/security/cors-configuration.d.ts +11 -0
- package/dist/checks/security/cors-configuration.d.ts.map +1 -0
- package/dist/checks/security/cors-configuration.js +126 -0
- package/dist/checks/security/cors-configuration.js.map +1 -0
- package/dist/checks/security/csp-headers.d.ts +11 -0
- package/dist/checks/security/csp-headers.d.ts.map +1 -0
- package/dist/checks/security/csp-headers.js +192 -0
- package/dist/checks/security/csp-headers.js.map +1 -0
- package/dist/checks/security/dependency-vulnerability-audit.d.ts +15 -0
- package/dist/checks/security/dependency-vulnerability-audit.d.ts.map +1 -0
- package/dist/checks/security/dependency-vulnerability-audit.js +184 -0
- package/dist/checks/security/dependency-vulnerability-audit.js.map +1 -0
- package/dist/checks/security/env-secret-exposure.d.ts +11 -0
- package/dist/checks/security/env-secret-exposure.d.ts.map +1 -0
- package/dist/checks/security/env-secret-exposure.js +127 -0
- package/dist/checks/security/env-secret-exposure.js.map +1 -0
- package/dist/checks/security/hasura-production-config.d.ts +11 -0
- package/dist/checks/security/hasura-production-config.d.ts.map +1 -0
- package/dist/checks/security/hasura-production-config.js +122 -0
- package/dist/checks/security/hasura-production-config.js.map +1 -0
- package/dist/checks/security/index.d.ts +17 -0
- package/dist/checks/security/index.d.ts.map +1 -0
- package/dist/checks/security/index.js +17 -0
- package/dist/checks/security/index.js.map +1 -0
- package/dist/checks/security/jwt-validation.d.ts +11 -0
- package/dist/checks/security/jwt-validation.d.ts.map +1 -0
- package/dist/checks/security/jwt-validation.js +294 -0
- package/dist/checks/security/jwt-validation.js.map +1 -0
- package/dist/checks/security/no-eval.d.ts +16 -0
- package/dist/checks/security/no-eval.d.ts.map +1 -0
- package/dist/checks/security/no-eval.js +83 -0
- package/dist/checks/security/no-eval.js.map +1 -0
- package/dist/checks/security/no-hardcoded-secrets.d.ts +28 -0
- package/dist/checks/security/no-hardcoded-secrets.d.ts.map +1 -0
- package/dist/checks/security/no-hardcoded-secrets.js +209 -0
- package/dist/checks/security/no-hardcoded-secrets.js.map +1 -0
- package/dist/checks/security/package-supply-chain-policy.d.ts +12 -0
- package/dist/checks/security/package-supply-chain-policy.d.ts.map +1 -0
- package/dist/checks/security/package-supply-chain-policy.js +534 -0
- package/dist/checks/security/package-supply-chain-policy.js.map +1 -0
- package/dist/checks/security/rate-limit-coverage.d.ts +10 -0
- package/dist/checks/security/rate-limit-coverage.d.ts.map +1 -0
- package/dist/checks/security/rate-limit-coverage.js +143 -0
- package/dist/checks/security/rate-limit-coverage.js.map +1 -0
- package/dist/checks/security/semgrep-scan.d.ts +13 -0
- package/dist/checks/security/semgrep-scan.d.ts.map +1 -0
- package/dist/checks/security/semgrep-scan.js +86 -0
- package/dist/checks/security/semgrep-scan.js.map +1 -0
- package/dist/checks/security/use-centralized-crypto.d.ts +11 -0
- package/dist/checks/security/use-centralized-crypto.d.ts.map +1 -0
- package/dist/checks/security/use-centralized-crypto.js +129 -0
- package/dist/checks/security/use-centralized-crypto.js.map +1 -0
- package/dist/checks/security/webhook-signature-verification.d.ts +10 -0
- package/dist/checks/security/webhook-signature-verification.d.ts.map +1 -0
- package/dist/checks/security/webhook-signature-verification.js +183 -0
- package/dist/checks/security/webhook-signature-verification.js.map +1 -0
- package/dist/checks/testing/index.d.ts +6 -0
- package/dist/checks/testing/index.d.ts.map +1 -0
- package/dist/checks/testing/index.js +6 -0
- package/dist/checks/testing/index.js.map +1 -0
- package/dist/checks/testing/no-skipped-tests.d.ts +40 -0
- package/dist/checks/testing/no-skipped-tests.d.ts.map +1 -0
- package/dist/checks/testing/no-skipped-tests.js +174 -0
- package/dist/checks/testing/no-skipped-tests.js.map +1 -0
- package/dist/checks/testing/no-stub-tests.d.ts +11 -0
- package/dist/checks/testing/no-stub-tests.d.ts.map +1 -0
- package/dist/checks/testing/no-stub-tests.js +103 -0
- package/dist/checks/testing/no-stub-tests.js.map +1 -0
- package/dist/checks/testing/test-convention-consistency.d.ts +14 -0
- package/dist/checks/testing/test-convention-consistency.d.ts.map +1 -0
- package/dist/checks/testing/test-convention-consistency.js +93 -0
- package/dist/checks/testing/test-convention-consistency.js.map +1 -0
- package/dist/checks/testing/test-file-naming.d.ts +13 -0
- package/dist/checks/testing/test-file-naming.d.ts.map +1 -0
- package/dist/checks/testing/test-file-naming.js +218 -0
- package/dist/checks/testing/test-file-naming.js.map +1 -0
- package/dist/checks/testing/test-file-pairing.d.ts +13 -0
- package/dist/checks/testing/test-file-pairing.d.ts.map +1 -0
- package/dist/checks/testing/test-file-pairing.js +274 -0
- package/dist/checks/testing/test-file-pairing.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 +29 -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 +34 -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 +36 -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 +31 -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 +52 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Validate routes have rate limiting configured
|
|
3
|
+
*/
|
|
4
|
+
import { logger } from '@opensip-cli/core';
|
|
5
|
+
import { defineCheck } from '@opensip-cli/fitness';
|
|
6
|
+
import { stripStringLiterals, stripStringsAndComments } from '@opensip-cli/fitness';
|
|
7
|
+
/**
|
|
8
|
+
* Pre-compiled regex patterns for rate limit detection.
|
|
9
|
+
* These patterns match fixed, bounded strings with no user input - safe from ReDoS.
|
|
10
|
+
*/
|
|
11
|
+
const RATE_LIMIT_REGEX = new RegExp('rateLimit|rateLimiter|preHandler.*rateLimit|onRequest.*rateLimit', 'i');
|
|
12
|
+
const INTERNAL_ROUTE_REGEX = new RegExp('/health|/metrics|/ready|/live|internal', 'i');
|
|
13
|
+
const FASTIFY_ROUTE_REGEX = new RegExp('fastify\\.(get|post|put|patch|delete)\\s*\\(\\s*[\'"`]/api[^\'"`]*[\'"`]', 'gi');
|
|
14
|
+
const EXPRESS_ROUTE_REGEX = new RegExp('(?:app|router)\\.(get|post|put|patch|delete)\\s*\\(\\s*[\'"`]/api[^\'"`]*[\'"`]', 'gi');
|
|
15
|
+
const SENSITIVE_ENDPOINT_REGEX = new RegExp('\\.(post|put)\\s*\\(\\s*[\'"`][^\'"`]*(?:login|signin|signup|register|password|reset|auth|token)[^\'"`]*[\'"`]', 'gi');
|
|
16
|
+
const GLOBAL_RATE_LIMIT_REGISTER_REGEX = new RegExp(String.raw `register\s*\(\s*(?:rateLimit|rateLimiter)`, 'i');
|
|
17
|
+
const GLOBAL_RATE_LIMIT_USE_REGEX = new RegExp(String.raw `use\s*\(\s*(?:rateLimit|rateLimiter)`, 'i');
|
|
18
|
+
const FRAMEWORK_DETECT_REGEX = /(?:fastify|app|router)\.(get|post|put|patch|delete)\s*\(/i;
|
|
19
|
+
/**
|
|
20
|
+
* Check if context has rate limiting
|
|
21
|
+
* @param context - The code context to check
|
|
22
|
+
* @returns True if rate limiting is present
|
|
23
|
+
*/
|
|
24
|
+
function hasRateLimiting(context) {
|
|
25
|
+
logger.debug({
|
|
26
|
+
evt: 'fitness.checks.rate_limit_coverage.has_rate_limiting',
|
|
27
|
+
msg: 'Checking if context has rate limiting',
|
|
28
|
+
});
|
|
29
|
+
return RATE_LIMIT_REGEX.test(context);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Check if route is internal (health, metrics, etc.)
|
|
33
|
+
* @param context - The code context to check
|
|
34
|
+
* @returns True if the route is internal
|
|
35
|
+
*/
|
|
36
|
+
function isInternalRoute(context) {
|
|
37
|
+
logger.debug({
|
|
38
|
+
evt: 'fitness.checks.rate_limit_coverage.is_internal_route',
|
|
39
|
+
msg: 'Checking if route is internal',
|
|
40
|
+
});
|
|
41
|
+
return INTERNAL_ROUTE_REGEX.test(context);
|
|
42
|
+
}
|
|
43
|
+
// Patterns that indicate route definitions needing rate limiting
|
|
44
|
+
const ROUTE_PATTERNS = [
|
|
45
|
+
// Fastify routes
|
|
46
|
+
{
|
|
47
|
+
regex: FASTIFY_ROUTE_REGEX,
|
|
48
|
+
check: (context) => !hasRateLimiting(context) && !isInternalRoute(context),
|
|
49
|
+
message: 'API route may be missing rate limiting configuration',
|
|
50
|
+
suggestion: 'Add rate limiting middleware: fastify.register(rateLimiter, { max: 100, timeWindow: "1 minute" }). Apply per-route or globally.',
|
|
51
|
+
severity: 'warning',
|
|
52
|
+
},
|
|
53
|
+
// Express routes
|
|
54
|
+
{
|
|
55
|
+
regex: EXPRESS_ROUTE_REGEX,
|
|
56
|
+
check: (context) => !hasRateLimiting(context) && !isInternalRoute(context),
|
|
57
|
+
message: 'API route may be missing rate limiting configuration',
|
|
58
|
+
suggestion: 'Add rate limiting middleware: app.use(rateLimiter({ max: 100, windowMs: 60000 })). Apply per-route or globally.',
|
|
59
|
+
severity: 'warning',
|
|
60
|
+
},
|
|
61
|
+
// Sensitive endpoints that must have rate limiting
|
|
62
|
+
{
|
|
63
|
+
regex: SENSITIVE_ENDPOINT_REGEX,
|
|
64
|
+
check: (context) => !hasRateLimiting(context),
|
|
65
|
+
message: 'Sensitive authentication endpoint should have rate limiting',
|
|
66
|
+
suggestion: 'Authentication endpoints must have strict rate limiting to prevent brute force attacks. Apply a limit of ~5-10 requests per minute for login/password endpoints.',
|
|
67
|
+
severity: 'error',
|
|
68
|
+
},
|
|
69
|
+
];
|
|
70
|
+
/**
|
|
71
|
+
* Check: security/rate-limit-coverage
|
|
72
|
+
*
|
|
73
|
+
* Validates that routes have rate limiting configured.
|
|
74
|
+
*/
|
|
75
|
+
export const rateLimitCoverage = defineCheck({
|
|
76
|
+
id: '19382a02-5d84-4316-b0a3-906f4acd7061',
|
|
77
|
+
slug: 'rate-limit-coverage',
|
|
78
|
+
disabled: true,
|
|
79
|
+
scope: { languages: ['typescript'], concerns: ['backend', 'server'] },
|
|
80
|
+
contentFilter: 'strip-strings',
|
|
81
|
+
confidence: 'medium',
|
|
82
|
+
description: 'Validate routes have rate limiting configured',
|
|
83
|
+
longDescription: `**Purpose:** Ensures API routes have rate limiting configured to prevent abuse, with stricter enforcement on authentication endpoints.
|
|
84
|
+
|
|
85
|
+
**Detects:**
|
|
86
|
+
- Fastify routes (\`fastify.get/post/put/patch/delete('/api/...')\`) without rateLimit/rateLimiter in the surrounding context (next 8 lines)
|
|
87
|
+
- Express routes (\`app/router.get/post/put/patch/delete('/api/...')\`) without rate limiting
|
|
88
|
+
- Sensitive authentication endpoints (\`.post/.put\` with login, signin, signup, register, password, reset, auth, or token in path) missing rate limiting (elevated to error severity)
|
|
89
|
+
|
|
90
|
+
**Why it matters:** Without rate limiting, APIs are vulnerable to brute-force attacks, credential stuffing, and denial-of-service. Authentication endpoints are especially critical targets.
|
|
91
|
+
|
|
92
|
+
**Scope:** General best practice. Analyzes each file individually. Skips files with global rate limiting (\`register(rateLimit)\` or \`use(rateLimit)\`).`,
|
|
93
|
+
tags: ['security', 'rate-limiting', 'api'],
|
|
94
|
+
fileTypes: ['ts'],
|
|
95
|
+
analyze(content, filePath) {
|
|
96
|
+
logger.debug({
|
|
97
|
+
evt: 'fitness.checks.rate_limit_coverage.analyze',
|
|
98
|
+
msg: 'Analyzing file for rate limit coverage',
|
|
99
|
+
});
|
|
100
|
+
// Only check files that might define routes
|
|
101
|
+
if (!FRAMEWORK_DETECT_REGEX.test(stripStringsAndComments(content))) {
|
|
102
|
+
return [];
|
|
103
|
+
}
|
|
104
|
+
// Check if file has global rate limiting applied
|
|
105
|
+
const hasGlobalRateLimit = GLOBAL_RATE_LIMIT_REGISTER_REGEX.test(content) || GLOBAL_RATE_LIMIT_USE_REGEX.test(content);
|
|
106
|
+
// If global rate limiting is applied, skip detailed checking
|
|
107
|
+
if (hasGlobalRateLimit) {
|
|
108
|
+
return [];
|
|
109
|
+
}
|
|
110
|
+
const violations = [];
|
|
111
|
+
const lines = content.split('\n');
|
|
112
|
+
for (let lineNum = 0; lineNum < lines.length; lineNum++) {
|
|
113
|
+
const line = lines[lineNum] ?? '';
|
|
114
|
+
// Get context (current line + next few lines)
|
|
115
|
+
const context = lines.slice(lineNum, lineNum + 8).join(' ');
|
|
116
|
+
// Skip comments
|
|
117
|
+
const trimmed = line.trim();
|
|
118
|
+
if (trimmed.startsWith('//') || trimmed.startsWith('*')) {
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
const strippedLine = stripStringLiterals(line);
|
|
122
|
+
const strippedContext = stripStringLiterals(context);
|
|
123
|
+
for (const pattern of ROUTE_PATTERNS) {
|
|
124
|
+
// Reset regex state
|
|
125
|
+
pattern.regex.lastIndex = 0;
|
|
126
|
+
const match = pattern.regex.exec(strippedLine);
|
|
127
|
+
if (match && pattern.check(strippedContext)) {
|
|
128
|
+
violations.push({
|
|
129
|
+
line: lineNum + 1,
|
|
130
|
+
column: match.index,
|
|
131
|
+
message: pattern.message,
|
|
132
|
+
severity: pattern.severity,
|
|
133
|
+
suggestion: pattern.suggestion,
|
|
134
|
+
match: match[0],
|
|
135
|
+
filePath,
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return violations;
|
|
141
|
+
},
|
|
142
|
+
});
|
|
143
|
+
//# sourceMappingURL=rate-limit-coverage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limit-coverage.js","sourceRoot":"","sources":["../../../src/checks/security/rate-limit-coverage.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Semgrep static analysis security scan
|
|
3
|
+
*
|
|
4
|
+
* Runs Semgrep with auto config to detect security vulnerabilities,
|
|
5
|
+
* code injection, and other issues across all supported languages.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Check: security/semgrep-scan
|
|
9
|
+
*
|
|
10
|
+
* Runs Semgrep static analysis with curated security rules.
|
|
11
|
+
*/
|
|
12
|
+
export declare const semgrepScan: import("@opensip-cli/fitness").Check;
|
|
13
|
+
//# sourceMappingURL=semgrep-scan.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"semgrep-scan.d.ts","sourceRoot":"","sources":["../../../src/checks/security/semgrep-scan.ts"],"names":[],"mappings":"AACA;;;;;GAKG;AA4FH;;;;GAIG;AACH,eAAO,MAAM,WAAW,sCA6BtB,CAAC"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
// @fitness-ignore-file batch-operation-limits -- reviewed: pattern is architecturally justified or false positive
|
|
2
|
+
/**
|
|
3
|
+
* @fileoverview Semgrep static analysis security scan
|
|
4
|
+
*
|
|
5
|
+
* Runs Semgrep with auto config to detect security vulnerabilities,
|
|
6
|
+
* code injection, and other issues across all supported languages.
|
|
7
|
+
*/
|
|
8
|
+
import * as path from 'node:path';
|
|
9
|
+
import { defineCheck } from '@opensip-cli/fitness';
|
|
10
|
+
// =============================================================================
|
|
11
|
+
// SEVERITY MAPPING
|
|
12
|
+
// =============================================================================
|
|
13
|
+
/* v8 ignore start -- semgrep parsing helpers exercised via integration tests (requires semgrep CLI) */
|
|
14
|
+
function mapSeverity(semgrepSeverity) {
|
|
15
|
+
return semgrepSeverity === 'ERROR' ? 'error' : 'warning';
|
|
16
|
+
}
|
|
17
|
+
// =============================================================================
|
|
18
|
+
// OUTPUT PARSING
|
|
19
|
+
// =============================================================================
|
|
20
|
+
function parseSemgrepOutput(stdout, _stderr, _exitCode, _files, cwd) {
|
|
21
|
+
if (!stdout.trim())
|
|
22
|
+
return [];
|
|
23
|
+
let output;
|
|
24
|
+
try {
|
|
25
|
+
output = JSON.parse(stdout);
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
// @swallow-ok Non-JSON output from semgrep (e.g. login prompts, version warnings)
|
|
29
|
+
return [];
|
|
30
|
+
}
|
|
31
|
+
const violations = [];
|
|
32
|
+
for (const result of output.results) {
|
|
33
|
+
const meta = result.extra.metadata;
|
|
34
|
+
const cwe = meta?.cwe?.[0] ?? '';
|
|
35
|
+
const prefix = cwe ? `[${cwe.split(':')[0]}] ` : '';
|
|
36
|
+
violations.push({
|
|
37
|
+
filePath: path.isAbsolute(result.path) ? result.path : path.join(cwd, result.path),
|
|
38
|
+
line: result.start.line,
|
|
39
|
+
column: result.start.col,
|
|
40
|
+
message: `${prefix}${result.extra.message}`,
|
|
41
|
+
severity: mapSeverity(result.extra.severity),
|
|
42
|
+
suggestion: `Fix semgrep finding: ${result.check_id}`,
|
|
43
|
+
type: result.check_id,
|
|
44
|
+
match: result.check_id,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
return violations;
|
|
48
|
+
}
|
|
49
|
+
/* v8 ignore stop */
|
|
50
|
+
// =============================================================================
|
|
51
|
+
// CHECK DEFINITION
|
|
52
|
+
// =============================================================================
|
|
53
|
+
/**
|
|
54
|
+
* Check: security/semgrep-scan
|
|
55
|
+
*
|
|
56
|
+
* Runs Semgrep static analysis with curated security rules.
|
|
57
|
+
*/
|
|
58
|
+
export const semgrepScan = defineCheck({
|
|
59
|
+
id: 'b8e2f4a1-6c3d-4e5f-9a1b-7d8c2e3f4a5b',
|
|
60
|
+
slug: 'semgrep-scan',
|
|
61
|
+
scope: { languages: ['typescript'], concerns: ['backend', 'frontend', 'cli'] },
|
|
62
|
+
confidence: 'high',
|
|
63
|
+
description: 'Run Semgrep static analysis to detect security vulnerabilities',
|
|
64
|
+
longDescription: `**Purpose:** Runs Semgrep with \`--config auto\` to detect security vulnerabilities, injection flaws, and dangerous code patterns across the codebase.
|
|
65
|
+
|
|
66
|
+
**Detects:**
|
|
67
|
+
- Code injection (eval, template injection)
|
|
68
|
+
- SQL injection and command injection
|
|
69
|
+
- Insecure cryptographic usage
|
|
70
|
+
- Path traversal and SSRF
|
|
71
|
+
- Hardcoded secrets and credentials
|
|
72
|
+
- OWASP Top 10 vulnerability patterns
|
|
73
|
+
|
|
74
|
+
**Why it matters:** Semgrep performs AST-aware pattern matching that catches vulnerabilities regex-based tools miss. The \`auto\` config uses Semgrep's curated registry of security rules maintained by the community and Semgrep team.
|
|
75
|
+
|
|
76
|
+
**Requires:** \`semgrep\` CLI installed (\`pip install semgrep\` or \`brew install semgrep\`). 5-minute timeout for large codebases.`,
|
|
77
|
+
tags: ['security', 'static-analysis', 'vulnerability', 'owasp'],
|
|
78
|
+
timeout: 300_000, // 5 minutes — semgrep auto downloads rules on first run
|
|
79
|
+
command: {
|
|
80
|
+
bin: 'semgrep',
|
|
81
|
+
args: ['scan', '--json', '--config', 'auto', '--quiet', '.'],
|
|
82
|
+
expectedExitCodes: [0, 1], // 0 = clean, 1 = findings
|
|
83
|
+
parseOutput: parseSemgrepOutput,
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
//# sourceMappingURL=semgrep-scan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"semgrep-scan.js","sourceRoot":"","sources":["../../../src/checks/security/semgrep-scan.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Enforce use of centralized crypto module
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Check: security/use-centralized-crypto
|
|
6
|
+
*
|
|
7
|
+
* Enforces that services use a centralized crypto utility instead of directly
|
|
8
|
+
* using Node.js crypto, AWS KMS SDK, or other crypto libraries.
|
|
9
|
+
*/
|
|
10
|
+
export declare const useCentralizedCrypto: import("@opensip-cli/fitness").Check;
|
|
11
|
+
//# sourceMappingURL=use-centralized-crypto.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-centralized-crypto.d.ts","sourceRoot":"","sources":["../../../src/checks/security/use-centralized-crypto.ts"],"names":[],"mappings":"AACA;;GAEG;AA8KH;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,sCA8D/B,CAAC"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
// @fitness-ignore-file batch-operation-limits -- iterates bounded collections (config entries, registry items, or small analysis results)
|
|
2
|
+
/**
|
|
3
|
+
* @fileoverview Enforce use of centralized crypto module
|
|
4
|
+
*/
|
|
5
|
+
import { logger } from '@opensip-cli/core';
|
|
6
|
+
import { createPathMatcher, defineCheck, isCommentLine, } from '@opensip-cli/fitness';
|
|
7
|
+
/**
|
|
8
|
+
* Creates a crypto pattern with standard RegExp
|
|
9
|
+
* Using RegExp constructor avoids sonarjs/regular-expr warnings on literal regex
|
|
10
|
+
* @param pattern - Pattern string to match
|
|
11
|
+
* @param message - Error message to display
|
|
12
|
+
* @param suggestion - Suggested fix
|
|
13
|
+
* @param severity - Severity level
|
|
14
|
+
* @returns Pattern configuration object
|
|
15
|
+
*/
|
|
16
|
+
function createCryptoPattern(pattern, message, suggestion, severity) {
|
|
17
|
+
// @fitness-ignore-next-line semgrep-scan -- non-literal RegExp is intentional; patterns are hardcoded string constants for code analysis, not user input
|
|
18
|
+
return { regex: new RegExp(pattern, 'g'), message, suggestion, severity };
|
|
19
|
+
}
|
|
20
|
+
// Patterns indicating direct crypto usage
|
|
21
|
+
const DIRECT_CRYPTO_PATTERNS = [
|
|
22
|
+
// Node.js crypto module - symmetric/hashing
|
|
23
|
+
createCryptoPattern(String.raw `crypto\.createHash\s*\(`, 'Direct crypto.createHash usage - use hashingService.sha256() from crypto module', 'Use a centralized crypto utility instead of direct crypto.createHash calls.', 'error'),
|
|
24
|
+
createCryptoPattern(String.raw `crypto\.createHmac\s*\(`, 'Direct crypto.createHmac usage - use hashingService.hmac() from crypto module', 'Use a centralized crypto utility instead of direct crypto.createHmac calls.', 'error'),
|
|
25
|
+
createCryptoPattern(String.raw `crypto\.createCipheriv\s*\(`, 'Direct crypto.createCipheriv usage - use encryptionService.encrypt() from crypto module', 'Use a centralized crypto utility for encryption instead of direct crypto.createCipheriv calls.', 'error'),
|
|
26
|
+
createCryptoPattern(String.raw `crypto\.createDecipheriv\s*\(`, 'Direct crypto.createDecipheriv usage - use encryptionService.decrypt() from crypto module', 'Use a centralized crypto utility for decryption instead of direct crypto.createDecipheriv calls.', 'error'),
|
|
27
|
+
createCryptoPattern(String.raw `crypto\.pbkdf2(?:Sync)?\s*\(`, 'Direct crypto.pbkdf2 usage - use deriveKeyPbkdf2() from crypto module', 'Use a centralized crypto utility for key derivation instead of direct crypto.pbkdf2 calls.', 'error'),
|
|
28
|
+
createCryptoPattern(String.raw `crypto\.scrypt(?:Sync)?\s*\(`, 'Direct crypto.scrypt usage - use deriveKeyScrypt() from crypto module', 'Use a centralized crypto utility for key derivation instead of direct crypto.scrypt calls.', 'error'),
|
|
29
|
+
// Node.js crypto module - asymmetric signing
|
|
30
|
+
createCryptoPattern(String.raw `crypto\.createSign\s*\(`, 'Direct crypto.createSign usage - use signingService.sign() from crypto module', 'Use a centralized crypto utility for signing instead of direct crypto.createSign calls.', 'error'),
|
|
31
|
+
// @fitness-ignore-next-line jwt-validation -- Fitness check definition, not production code; .verify() in suggestion text
|
|
32
|
+
createCryptoPattern(String.raw `crypto\.createVerify\s*\(`, 'Direct crypto.createVerify usage - use signingService.verify() from crypto module', 'Use a centralized crypto utility for signature verification instead of direct crypto.createVerify calls.', 'error'),
|
|
33
|
+
createCryptoPattern(String.raw `crypto\.sign\s*\(`, 'Direct crypto.sign usage - use signingService.sign() from crypto module', 'Use a centralized crypto utility for signing instead of direct crypto.sign calls.', 'error'),
|
|
34
|
+
// @fitness-ignore-next-line jwt-validation -- Fitness check definition, not production code; .verify() in suggestion text
|
|
35
|
+
createCryptoPattern(String.raw `crypto\.verify\s*\(`, 'Direct crypto.verify usage - use signingService.verify() from crypto module', 'Use a centralized crypto utility for signature verification instead of direct crypto.verify calls.', 'error'),
|
|
36
|
+
// Direct createHmac import usage
|
|
37
|
+
createCryptoPattern(String.raw `\bcreateHmac\s*\(\s*['"]sha256['"]`, 'Direct createHmac usage - use hashingService.hmac() from crypto module', 'Use a centralized crypto utility instead of direct createHmac calls.', 'error'),
|
|
38
|
+
// AWS KMS direct imports
|
|
39
|
+
createCryptoPattern('@aws-sdk/client-kms', 'Direct AWS KMS SDK import - use a centralized crypto utility with KMS provider', 'Use a centralized crypto utility that handles KMS integration for key management.', 'error'),
|
|
40
|
+
createCryptoPattern(String.raw `new KMSClient\s*\(`, 'Direct KMSClient usage - use a centralized crypto utility with KMS provider', 'Use a centralized crypto utility that handles KMS integration for key management.', 'error'),
|
|
41
|
+
// bcrypt/argon2 direct imports
|
|
42
|
+
createCryptoPattern('from [\'"]bcrypt[\'"]', 'Direct bcrypt import - use hashingService.hashPassword() from crypto module', 'Use a centralized crypto utility for password hashing instead of direct bcrypt calls.', 'error'),
|
|
43
|
+
createCryptoPattern('from [\'"]argon2[\'"]', 'Direct argon2 import - use hashingService.hashPassword() from crypto module', 'Use a centralized crypto utility for password hashing instead of direct argon2 calls.', 'error'),
|
|
44
|
+
// Direct jose imports (should use ISigningService wrapper)
|
|
45
|
+
createCryptoPattern('from [\'"]jose[\'"]', 'Direct jose import - use ISigningService from crypto module', 'Use a centralized crypto utility for JWT operations instead of direct jose imports.', 'warning'),
|
|
46
|
+
createCryptoPattern(String.raw `import\s+\*\s+as\s+jose\s+from`, 'Direct jose import - use ISigningService from crypto module', 'Use a centralized crypto utility for JWT operations instead of direct jose imports.', 'warning'),
|
|
47
|
+
];
|
|
48
|
+
// Paths to exclude from checking
|
|
49
|
+
const CRYPTO_IMPL_PATTERNS = [
|
|
50
|
+
// The crypto module itself (matches /infrastructure/src/crypto/)
|
|
51
|
+
'/crypto/adapters/',
|
|
52
|
+
'/crypto/core/',
|
|
53
|
+
'/crypto/interfaces/',
|
|
54
|
+
'/crypto/types/',
|
|
55
|
+
// Foundation modules may use crypto primitives
|
|
56
|
+
'/foundation/',
|
|
57
|
+
// Security JWT module uses jose for JWT-specific operations
|
|
58
|
+
'/security/implementations/jwt/',
|
|
59
|
+
// Cognito provider uses jose for AWS Cognito-specific JWT validation
|
|
60
|
+
'/security/providers/cognito/',
|
|
61
|
+
// Webhook verifiers implement provider-specific signature algorithms
|
|
62
|
+
'/webhooks/verifiers/',
|
|
63
|
+
// Fitness check definitions contain pattern strings, not actual crypto usage
|
|
64
|
+
'/fitness/src/checks/',
|
|
65
|
+
];
|
|
66
|
+
const isExcludedCryptoPath = createPathMatcher(CRYPTO_IMPL_PATTERNS);
|
|
67
|
+
/**
|
|
68
|
+
* Check: security/use-centralized-crypto
|
|
69
|
+
*
|
|
70
|
+
* Enforces that services use a centralized crypto utility instead of directly
|
|
71
|
+
* using Node.js crypto, AWS KMS SDK, or other crypto libraries.
|
|
72
|
+
*/
|
|
73
|
+
export const useCentralizedCrypto = defineCheck({
|
|
74
|
+
id: '38c350d5-1605-4d02-811c-c76261bcbba4',
|
|
75
|
+
slug: 'use-centralized-crypto',
|
|
76
|
+
disabled: true,
|
|
77
|
+
scope: { languages: ['typescript'], concerns: ['backend', 'server'] },
|
|
78
|
+
contentFilter: 'strip-strings',
|
|
79
|
+
confidence: 'medium',
|
|
80
|
+
description: 'Enforce use of centralized crypto module instead of direct crypto operations',
|
|
81
|
+
longDescription: `**Purpose:** Enforces that services use a centralized crypto utility instead of directly calling Node.js crypto, AWS KMS, or third-party crypto libraries.
|
|
82
|
+
|
|
83
|
+
**Detects:**
|
|
84
|
+
- Direct Node.js crypto calls: \`crypto.createHash\`, \`crypto.createHmac\`, \`crypto.createCipheriv\`, \`crypto.createDecipheriv\`, \`crypto.pbkdf2\`, \`crypto.scrypt\`, \`crypto.createSign\`, \`crypto.createVerify\`, \`crypto.sign\`, \`crypto.verify\`
|
|
85
|
+
- Direct \`createHmac('sha256', ...)\` usage
|
|
86
|
+
- AWS KMS direct imports: \`@aws-sdk/client-kms\`, \`new KMSClient()\`
|
|
87
|
+
- Direct password hashing imports: \`from 'bcrypt'\`, \`from 'argon2'\`
|
|
88
|
+
- Direct JOSE imports: \`from 'jose'\`, \`import * as jose\`
|
|
89
|
+
|
|
90
|
+
**Why it matters:** Centralized crypto ensures consistent algorithm choices, key management, and makes it possible to audit or rotate cryptographic operations from a single location.
|
|
91
|
+
|
|
92
|
+
**Scope:** Codebase-specific convention. Analyzes each file individually. Excludes the crypto module itself, foundation, security JWT, Cognito provider, webhook verifiers, and fitness check definitions.`,
|
|
93
|
+
tags: ['security', 'crypto', 'centralization', 'best-practices'],
|
|
94
|
+
fileTypes: ['ts'],
|
|
95
|
+
analyze(content, filePath) {
|
|
96
|
+
logger.debug({
|
|
97
|
+
evt: 'fitness.checks.centralized_crypto.analyze',
|
|
98
|
+
msg: 'Analyzing file for direct crypto usage',
|
|
99
|
+
});
|
|
100
|
+
if (isExcludedCryptoPath(filePath)) {
|
|
101
|
+
return [];
|
|
102
|
+
}
|
|
103
|
+
const violations = [];
|
|
104
|
+
const lines = content.split('\n');
|
|
105
|
+
for (const [lineNum, line_] of lines.entries()) {
|
|
106
|
+
const line = line_ ?? '';
|
|
107
|
+
if (isCommentLine(line)) {
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
for (const pattern of DIRECT_CRYPTO_PATTERNS) {
|
|
111
|
+
pattern.regex.lastIndex = 0;
|
|
112
|
+
const match = pattern.regex.exec(line);
|
|
113
|
+
if (match) {
|
|
114
|
+
violations.push({
|
|
115
|
+
line: lineNum + 1,
|
|
116
|
+
column: match.index,
|
|
117
|
+
message: pattern.message,
|
|
118
|
+
severity: pattern.severity,
|
|
119
|
+
suggestion: pattern.suggestion,
|
|
120
|
+
match: match[0],
|
|
121
|
+
filePath,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return violations;
|
|
127
|
+
},
|
|
128
|
+
});
|
|
129
|
+
//# sourceMappingURL=use-centralized-crypto.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-centralized-crypto.js","sourceRoot":"","sources":["../../../src/checks/security/use-centralized-crypto.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Detect webhook endpoints without signature verification
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Check: security/webhook-signature-verification
|
|
6
|
+
*
|
|
7
|
+
* Detects webhook endpoints without proper signature verification.
|
|
8
|
+
*/
|
|
9
|
+
export declare const webhookSignatureVerification: import("@opensip-cli/fitness").Check;
|
|
10
|
+
//# sourceMappingURL=webhook-signature-verification.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhook-signature-verification.d.ts","sourceRoot":"","sources":["../../../src/checks/security/webhook-signature-verification.ts"],"names":[],"mappings":"AAAA;;GAEG;AAiLH;;;;GAIG;AACH,eAAO,MAAM,4BAA4B,sCAmDvC,CAAC"}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Detect webhook endpoints without signature verification
|
|
3
|
+
*/
|
|
4
|
+
import { logger } from '@opensip-cli/core';
|
|
5
|
+
import { defineCheck, isCommentLine } from '@opensip-cli/fitness';
|
|
6
|
+
/**
|
|
7
|
+
* Creates a security pattern with RegExp constructor
|
|
8
|
+
* Using RegExp constructor avoids sonarjs/regular-expr and sonarjs/slow-regex warnings
|
|
9
|
+
* @param options - The options for creating the pattern
|
|
10
|
+
* @returns Security pattern configuration
|
|
11
|
+
*/
|
|
12
|
+
function createSecurityPattern(options) {
|
|
13
|
+
const { pattern, flags, message, suggestion, severity, category } = options;
|
|
14
|
+
// @fitness-ignore-next-line semgrep-scan -- non-literal RegExp is intentional; patterns are hardcoded string constants for code analysis, not user input
|
|
15
|
+
return { regex: new RegExp(pattern, flags), message, suggestion, severity, category };
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Check if a file path is a webhook-related file
|
|
19
|
+
* @param filePath - Path to check
|
|
20
|
+
* @returns True if file is webhook-related
|
|
21
|
+
*/
|
|
22
|
+
function isWebhookRelatedFile(filePath) {
|
|
23
|
+
logger.debug({
|
|
24
|
+
evt: 'fitness.checks.webhook_signature.is_webhook_related_file',
|
|
25
|
+
msg: 'Checking if file is webhook-related',
|
|
26
|
+
});
|
|
27
|
+
const lowerPath = filePath.toLowerCase();
|
|
28
|
+
// Simple checks that are safe from ReDoS
|
|
29
|
+
if (lowerPath.includes('webhook')) {
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
// Check for /hook/ or /hooks/ path segments
|
|
33
|
+
return lowerPath.includes('/hook/') || lowerPath.includes('/hooks/');
|
|
34
|
+
}
|
|
35
|
+
// Patterns indicating proper verifier usage - simple string checks
|
|
36
|
+
const VERIFIER_STRINGS = [
|
|
37
|
+
'infrastructure/webhooks',
|
|
38
|
+
'createHmacVerifier',
|
|
39
|
+
'createStripeVerifier',
|
|
40
|
+
'createTwilioVerifier',
|
|
41
|
+
'createSendGridVerifier',
|
|
42
|
+
'verifySignature',
|
|
43
|
+
'validateSignature',
|
|
44
|
+
];
|
|
45
|
+
/**
|
|
46
|
+
* Check if content has proper verifier imports
|
|
47
|
+
* @param content - File content
|
|
48
|
+
* @returns True if content has verifier imports
|
|
49
|
+
*/
|
|
50
|
+
function hasVerifierImport(content) {
|
|
51
|
+
logger.debug({
|
|
52
|
+
evt: 'fitness.checks.webhook_signature.has_verifier_import',
|
|
53
|
+
msg: 'Checking if content has verifier imports',
|
|
54
|
+
});
|
|
55
|
+
return VERIFIER_STRINGS.some((str) => content.includes(str));
|
|
56
|
+
}
|
|
57
|
+
// Security issue patterns - using RegExp constructor to avoid sonarjs warnings
|
|
58
|
+
const SECURITY_ISSUE_PATTERNS = [
|
|
59
|
+
// Hardcoded webhook secrets - simplified non-backtracking pattern
|
|
60
|
+
createSecurityPattern({
|
|
61
|
+
pattern: String.raw `(?:webhook)?secret\s*[:=]\s*['"][^'"]{10,}['"]`,
|
|
62
|
+
flags: 'gi',
|
|
63
|
+
message: 'Hardcoded webhook secret detected - use environment variables',
|
|
64
|
+
suggestion: 'Move webhook secret to environment variable: process.env.WEBHOOK_SECRET. Never commit secrets to source control.',
|
|
65
|
+
severity: 'error',
|
|
66
|
+
category: 'hardcoded-secret',
|
|
67
|
+
}),
|
|
68
|
+
createSecurityPattern({
|
|
69
|
+
pattern: 'whsec_[a-zA-Z0-9]+',
|
|
70
|
+
flags: 'g',
|
|
71
|
+
message: 'Hardcoded Stripe webhook secret detected - use environment variables',
|
|
72
|
+
suggestion: 'Move Stripe webhook secret to process.env.STRIPE_WEBHOOK_SECRET. Rotate the secret immediately if it was exposed in git history.',
|
|
73
|
+
severity: 'error',
|
|
74
|
+
category: 'hardcoded-secret',
|
|
75
|
+
}),
|
|
76
|
+
// Direct string comparison for signatures (not timing-safe)
|
|
77
|
+
// Simplified pattern without lookahead to avoid slow-regex/backtracking
|
|
78
|
+
createSecurityPattern({
|
|
79
|
+
pattern: String.raw `signature\s*(?:===|!==|==|!=)\s*[^;]+`,
|
|
80
|
+
flags: 'gi',
|
|
81
|
+
message: 'Direct signature comparison detected - use timing-safe comparison to prevent timing attacks',
|
|
82
|
+
suggestion: 'Use crypto.timingSafeEqual() for signature comparison: crypto.timingSafeEqual(Buffer.from(a), Buffer.from(b)). Direct comparison is vulnerable to timing attacks.',
|
|
83
|
+
severity: 'warning',
|
|
84
|
+
category: 'insecure-signature',
|
|
85
|
+
}),
|
|
86
|
+
];
|
|
87
|
+
// Patterns indicating JSON parsing without verification - simplified
|
|
88
|
+
const UNSAFE_JSON_PATTERNS = [
|
|
89
|
+
createSecurityPattern({
|
|
90
|
+
pattern: String.raw `JSON\.parse\s*\([^)]*(?:req\.body|request\.body|rawBody)`,
|
|
91
|
+
flags: 'gi',
|
|
92
|
+
message: 'JSON.parse on webhook body without signature verification - use a shared webhook verification utility',
|
|
93
|
+
suggestion: 'Use webhook verifiers that handle signature verification. Example: const payload = await verifier.verify(req);',
|
|
94
|
+
severity: 'error',
|
|
95
|
+
category: 'missing-verification',
|
|
96
|
+
}),
|
|
97
|
+
];
|
|
98
|
+
/**
|
|
99
|
+
* Check if file should be skipped
|
|
100
|
+
* @param filePath - Path to check
|
|
101
|
+
* @returns True if file should be skipped
|
|
102
|
+
*/
|
|
103
|
+
function shouldSkipFile(filePath) {
|
|
104
|
+
logger.debug({
|
|
105
|
+
evt: 'fitness.checks.webhook_signature.should_skip_file',
|
|
106
|
+
msg: 'Checking if file should be skipped',
|
|
107
|
+
});
|
|
108
|
+
return !isWebhookRelatedFile(filePath);
|
|
109
|
+
}
|
|
110
|
+
function checkPatterns(patterns, line, lineNum, filePath) {
|
|
111
|
+
logger.debug({
|
|
112
|
+
evt: 'fitness.checks.webhook_signature.check_patterns',
|
|
113
|
+
msg: 'Checking line against security patterns',
|
|
114
|
+
});
|
|
115
|
+
const violations = [];
|
|
116
|
+
for (const pattern of patterns) {
|
|
117
|
+
pattern.regex.lastIndex = 0;
|
|
118
|
+
const match = pattern.regex.exec(line);
|
|
119
|
+
if (match) {
|
|
120
|
+
violations.push({
|
|
121
|
+
line: lineNum + 1,
|
|
122
|
+
column: match.index,
|
|
123
|
+
message: pattern.message,
|
|
124
|
+
severity: pattern.severity,
|
|
125
|
+
suggestion: pattern.suggestion,
|
|
126
|
+
match: match[0],
|
|
127
|
+
type: pattern.category,
|
|
128
|
+
filePath,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return violations;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Check: security/webhook-signature-verification
|
|
136
|
+
*
|
|
137
|
+
* Detects webhook endpoints without proper signature verification.
|
|
138
|
+
*/
|
|
139
|
+
export const webhookSignatureVerification = defineCheck({
|
|
140
|
+
id: '02a157b3-88a9-45d4-95da-ed754e347439',
|
|
141
|
+
slug: 'webhook-signature-verification',
|
|
142
|
+
disabled: true,
|
|
143
|
+
tags: ['security'],
|
|
144
|
+
scope: { languages: ['typescript'], concerns: ['backend', 'server'] },
|
|
145
|
+
contentFilter: 'strip-strings',
|
|
146
|
+
confidence: 'medium',
|
|
147
|
+
description: 'Detect webhook endpoints without signature verification',
|
|
148
|
+
longDescription: `**Purpose:** Detects webhook handler files that process incoming payloads without proper signature verification, and flags related security issues.
|
|
149
|
+
|
|
150
|
+
**Detects:**
|
|
151
|
+
- Hardcoded webhook secrets: \`secret: '<value>'\` or \`whsec_\` prefixed Stripe webhook secrets in source code
|
|
152
|
+
- Direct signature string comparison using \`===\`/\`!==\`/\`==\`/\`!=\` (vulnerable to timing attacks)
|
|
153
|
+
- \`JSON.parse(req.body)\` / \`JSON.parse(request.body)\` / \`JSON.parse(rawBody)\` in webhook files without verifier imports (infrastructure/webhooks, createHmacVerifier, createStripeVerifier, etc.)
|
|
154
|
+
|
|
155
|
+
**Why it matters:** Without signature verification, attackers can forge webhook payloads to trigger unauthorized actions. Direct string comparison of signatures leaks timing information.
|
|
156
|
+
|
|
157
|
+
**Scope:** General best practice. Analyzes each file individually. Only scans files in webhook/hook-related paths.`,
|
|
158
|
+
fileTypes: ['ts'],
|
|
159
|
+
analyze(content, filePath) {
|
|
160
|
+
logger.debug({
|
|
161
|
+
evt: 'fitness.checks.webhook_signature.analyze',
|
|
162
|
+
msg: 'Analyzing file for webhook signature verification',
|
|
163
|
+
});
|
|
164
|
+
if (shouldSkipFile(filePath)) {
|
|
165
|
+
return [];
|
|
166
|
+
}
|
|
167
|
+
const violations = [];
|
|
168
|
+
const fileHasVerifierImport = hasVerifierImport(content);
|
|
169
|
+
const lines = content.split('\n');
|
|
170
|
+
for (const [lineNum, line_] of lines.entries()) {
|
|
171
|
+
const line = line_ ?? '';
|
|
172
|
+
if (isCommentLine(line)) {
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
violations.push(...checkPatterns(SECURITY_ISSUE_PATTERNS, line, lineNum, filePath));
|
|
176
|
+
if (!fileHasVerifierImport) {
|
|
177
|
+
violations.push(...checkPatterns(UNSAFE_JSON_PATTERNS, line, lineNum, filePath));
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return violations;
|
|
181
|
+
},
|
|
182
|
+
});
|
|
183
|
+
//# sourceMappingURL=webhook-signature-verification.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhook-signature-verification.js","sourceRoot":"","sources":["../../../src/checks/security/webhook-signature-verification.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/checks/testing/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kCAAkC,CAAC;AACjD,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC"}
|