@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,127 @@
|
|
|
1
|
+
// @fitness-ignore-file env-secret-exposure -- Fitness check definition references process.env patterns in longDescription, not actual secret exposure
|
|
2
|
+
// @fitness-ignore-file logging-standards -- Suggestion strings contain logger call examples that match the logging-standards pattern
|
|
3
|
+
// @fitness-ignore-file duplicate-implementation-detection -- similar patterns across diagnostic modules
|
|
4
|
+
// @fitness-ignore-file fitness-ignore-validation -- Fitness-ignore directives reference internal check IDs that may not be statically resolvable
|
|
5
|
+
/**
|
|
6
|
+
* @fileoverview Detect secrets exposed through env vars in logs/errors
|
|
7
|
+
*/
|
|
8
|
+
import { logger } from '@opensip-cli/core';
|
|
9
|
+
import { defineCheck, isTestFile } from '@opensip-cli/fitness';
|
|
10
|
+
/**
|
|
11
|
+
* Creates a pre-compiled RegExp for pattern matching.
|
|
12
|
+
* These patterns operate on trusted source code files, not user input,
|
|
13
|
+
* and use bounded character classes to prevent ReDoS.
|
|
14
|
+
* @param pattern - The regex pattern string
|
|
15
|
+
* @param flags - Optional regex flags
|
|
16
|
+
* @returns Compiled RegExp object
|
|
17
|
+
*/
|
|
18
|
+
function createPattern(pattern, flags) {
|
|
19
|
+
// @fitness-ignore-next-line semgrep-scan -- non-literal RegExp is intentional; patterns are hardcoded string constants for code analysis, not user input
|
|
20
|
+
return new RegExp(pattern, flags);
|
|
21
|
+
}
|
|
22
|
+
// Patterns that indicate potential secret exposure
|
|
23
|
+
// Note: These regex patterns operate on trusted source code files, not user input.
|
|
24
|
+
// The patterns use bounded character classes (e.g., [^)], [^;], [^`]) to prevent ReDoS.
|
|
25
|
+
const EXPOSURE_PATTERNS = [
|
|
26
|
+
// Logging all env vars - uses [^)]* which is bounded by closing paren
|
|
27
|
+
{
|
|
28
|
+
regex: createPattern(String.raw `(?:logger|console|log)\.\w+\s*\([^)]*process\.env(?!\.\w+)[^)]*\)`, 'g'),
|
|
29
|
+
message: 'Logging entire process.env exposes all secrets',
|
|
30
|
+
suggestion: 'Never log the entire process.env object. Log specific, non-sensitive values individually: logger.info({ nodeEnv: process.env.NODE_ENV }).',
|
|
31
|
+
severity: 'error',
|
|
32
|
+
},
|
|
33
|
+
// Env vars in error messages with interpolation - uses [^;]* which is bounded by semicolon
|
|
34
|
+
{
|
|
35
|
+
regex: createPattern(String.raw `(?:Error|throw)[^;]*process\.env\.\w*(?:SECRET|KEY|PASSWORD|TOKEN|CREDENTIAL)`, 'gi'),
|
|
36
|
+
message: 'Sensitive environment variable in error message may expose secrets',
|
|
37
|
+
suggestion: 'Do not include secret values in error messages. Log only that the secret was missing or invalid, not its value: throw new Error("API key validation failed");',
|
|
38
|
+
severity: 'error',
|
|
39
|
+
},
|
|
40
|
+
// Stringifying env vars (JSON.stringify(process.env)) - fixed pattern, no variable repetition
|
|
41
|
+
{
|
|
42
|
+
regex: createPattern(String.raw `JSON\.stringify\s*\(\s*process\.env\s*\)`, 'g'),
|
|
43
|
+
message: 'JSON.stringify(process.env) exposes all secrets',
|
|
44
|
+
suggestion: 'Select specific non-sensitive env vars to stringify: JSON.stringify({ NODE_ENV: process.env.NODE_ENV, PORT: process.env.PORT }).',
|
|
45
|
+
severity: 'error',
|
|
46
|
+
},
|
|
47
|
+
// Spreading env into object that might be logged - fixed pattern
|
|
48
|
+
{
|
|
49
|
+
regex: createPattern(String.raw `\{\s*\.\.\.process\.env`, 'g'),
|
|
50
|
+
message: 'Spreading process.env may expose secrets if object is logged',
|
|
51
|
+
suggestion: 'Explicitly pick non-sensitive values instead of spreading: { NODE_ENV: process.env.NODE_ENV, PORT: process.env.PORT }.',
|
|
52
|
+
severity: 'warning',
|
|
53
|
+
},
|
|
54
|
+
// Template literal with secret env var - uses [^`]* which is bounded by backtick
|
|
55
|
+
{
|
|
56
|
+
regex: createPattern('`[^`]*\\$\\{process\\.env\\.\\w*(?:SECRET|KEY|PASSWORD|TOKEN|CREDENTIAL)[^`]*`', 'gi'),
|
|
57
|
+
message: 'Sensitive environment variable in template literal may be exposed',
|
|
58
|
+
suggestion: 'Do not interpolate secret values into strings that may be logged or displayed. Use the value directly for authentication without exposing it.',
|
|
59
|
+
severity: 'warning',
|
|
60
|
+
},
|
|
61
|
+
];
|
|
62
|
+
/**
|
|
63
|
+
* Check: security/env-secret-exposure
|
|
64
|
+
*
|
|
65
|
+
* Detects secrets that might be exposed through environment variables
|
|
66
|
+
* in logs or error messages.
|
|
67
|
+
*/
|
|
68
|
+
export const envSecretExposure = defineCheck({
|
|
69
|
+
id: '6833b667-cc72-465d-9f1e-2b6b6060faef',
|
|
70
|
+
slug: 'env-secret-exposure',
|
|
71
|
+
scope: { languages: ['json', 'typescript', 'yaml'], concerns: ['config'] },
|
|
72
|
+
description: 'Detect secrets exposed through environment variables in logs or errors',
|
|
73
|
+
longDescription: `**Purpose:** Detects patterns where sensitive environment variables may be inadvertently exposed through logging, error messages, or serialization.
|
|
74
|
+
|
|
75
|
+
**Detects:**
|
|
76
|
+
- Logging entire \`process.env\` object: \`logger.info(process.env)\`
|
|
77
|
+
- Sensitive env vars (SECRET, KEY, PASSWORD, TOKEN, CREDENTIAL) in error/throw statements
|
|
78
|
+
- \`JSON.stringify(process.env)\` which serializes all secrets
|
|
79
|
+
- Spreading \`{ ...process.env }\` into objects that may be logged
|
|
80
|
+
- Template literals interpolating sensitive env vars: \`\${process.env.SECRET_KEY}\`
|
|
81
|
+
|
|
82
|
+
**Why it matters:** Leaked secrets in logs or error reports can be harvested from log aggregators, monitoring dashboards, or error tracking services, leading to credential compromise.
|
|
83
|
+
|
|
84
|
+
**Scope:** General best practice. Analyzes each file individually.`,
|
|
85
|
+
tags: ['security', 'secrets', 'logging', 'errors'],
|
|
86
|
+
fileTypes: ['ts'],
|
|
87
|
+
contentFilter: 'strip-strings',
|
|
88
|
+
confidence: 'medium',
|
|
89
|
+
analyze(content, filePath) {
|
|
90
|
+
// Test fixtures intentionally spread/serialize process.env to verify
|
|
91
|
+
// detection logic — skip tests to avoid noise.
|
|
92
|
+
if (isTestFile(filePath))
|
|
93
|
+
return [];
|
|
94
|
+
logger.debug({
|
|
95
|
+
evt: 'fitness.checks.env_secret_exposure.analyze',
|
|
96
|
+
msg: 'Analyzing file for environment secret exposure',
|
|
97
|
+
});
|
|
98
|
+
const violations = [];
|
|
99
|
+
const lines = content.split('\n');
|
|
100
|
+
for (const [lineNum, line_] of lines.entries()) {
|
|
101
|
+
const line = line_ ?? '';
|
|
102
|
+
// Skip comments
|
|
103
|
+
const trimmed = line.trim();
|
|
104
|
+
if (trimmed.startsWith('//') || trimmed.startsWith('*')) {
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
for (const pattern of EXPOSURE_PATTERNS) {
|
|
108
|
+
// Reset regex state
|
|
109
|
+
pattern.regex.lastIndex = 0;
|
|
110
|
+
const match = pattern.regex.exec(line);
|
|
111
|
+
if (match) {
|
|
112
|
+
violations.push({
|
|
113
|
+
line: lineNum + 1,
|
|
114
|
+
column: match.index,
|
|
115
|
+
message: pattern.message,
|
|
116
|
+
severity: pattern.severity,
|
|
117
|
+
suggestion: pattern.suggestion,
|
|
118
|
+
match: match[0],
|
|
119
|
+
filePath,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return violations;
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
//# sourceMappingURL=env-secret-exposure.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env-secret-exposure.js","sourceRoot":"","sources":["../../../src/checks/security/env-secret-exposure.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Verify Hasura production security settings
|
|
3
|
+
*
|
|
4
|
+
* Validates that production docker-compose files include required Hasura security settings:
|
|
5
|
+
* - Introspection disabled
|
|
6
|
+
* - Allow-list enabled
|
|
7
|
+
* - Dev mode disabled
|
|
8
|
+
* - Console disabled
|
|
9
|
+
*/
|
|
10
|
+
export declare const hasuraProductionConfig: import("@opensip-cli/fitness").Check;
|
|
11
|
+
//# sourceMappingURL=hasura-production-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hasura-production-config.d.ts","sourceRoot":"","sources":["../../../src/checks/security/hasura-production-config.ts"],"names":[],"mappings":"AACA;;;;;;;;GAQG;AA4EH,eAAO,MAAM,sBAAsB,sCAoDjC,CAAC"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
// @fitness-ignore-file batch-operation-limits -- Promise.all is bounded to production docker-compose files (typically 1-3)
|
|
2
|
+
/**
|
|
3
|
+
* @fileoverview Verify Hasura production security settings
|
|
4
|
+
*
|
|
5
|
+
* Validates that production docker-compose files include required Hasura security settings:
|
|
6
|
+
* - Introspection disabled
|
|
7
|
+
* - Allow-list enabled
|
|
8
|
+
* - Dev mode disabled
|
|
9
|
+
* - Console disabled
|
|
10
|
+
*/
|
|
11
|
+
import { logger } from '@opensip-cli/core';
|
|
12
|
+
import { defineCheck } from '@opensip-cli/fitness';
|
|
13
|
+
const REQUIRED_SETTINGS = [
|
|
14
|
+
{
|
|
15
|
+
envVar: 'HASURA_GRAPHQL_ENABLE_INTROSPECTION',
|
|
16
|
+
expectedValue: '"false"',
|
|
17
|
+
description: 'Introspection must be disabled in production to prevent schema discovery',
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
envVar: 'HASURA_GRAPHQL_ENABLE_ALLOWLIST',
|
|
21
|
+
expectedValue: '"true"',
|
|
22
|
+
description: 'Allow-list must be enabled in production to restrict queries to known operations',
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
envVar: 'HASURA_GRAPHQL_DEV_MODE',
|
|
26
|
+
expectedValue: '"false"',
|
|
27
|
+
description: 'Dev mode must be disabled in production to hide detailed error messages',
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
envVar: 'HASURA_GRAPHQL_ENABLE_CONSOLE',
|
|
31
|
+
expectedValue: '"false"',
|
|
32
|
+
description: 'Console must be disabled in production to prevent unauthorized schema access',
|
|
33
|
+
},
|
|
34
|
+
];
|
|
35
|
+
function findHasuraEnvLine(content) {
|
|
36
|
+
const lines = content.split('\n');
|
|
37
|
+
for (const [i, line] of lines.entries()) {
|
|
38
|
+
if ((line ?? '').includes('HASURA_GRAPHQL_')) {
|
|
39
|
+
return i + 1;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return 1;
|
|
43
|
+
}
|
|
44
|
+
function checkMissingSettings(filePath, content) {
|
|
45
|
+
if (!content.includes('hasura') || !content.includes('HASURA_GRAPHQL_'))
|
|
46
|
+
return [];
|
|
47
|
+
const violations = [];
|
|
48
|
+
for (const setting of REQUIRED_SETTINGS) {
|
|
49
|
+
const presencePattern = new RegExp(String.raw `${setting.envVar}\s*:`);
|
|
50
|
+
const escapedValue = setting.expectedValue.replaceAll(/[.*+?^${}()|[\]\\]/g, String.raw `\$&`);
|
|
51
|
+
const correctValuePattern = new RegExp(String.raw `${setting.envVar}\s*:\s*${escapedValue}`);
|
|
52
|
+
if (!presencePattern.test(content)) {
|
|
53
|
+
violations.push({
|
|
54
|
+
filePath,
|
|
55
|
+
line: findHasuraEnvLine(content),
|
|
56
|
+
severity: 'warning',
|
|
57
|
+
message: `Missing ${setting.envVar}: ${setting.expectedValue}. ${setting.description}.`,
|
|
58
|
+
suggestion: `Add \`${setting.envVar}: ${setting.expectedValue}\` to the hasura environment section.`,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
else if (!correctValuePattern.test(content)) {
|
|
62
|
+
const lines = content.split('\n');
|
|
63
|
+
const settingLine = lines.findIndex((l) => presencePattern.test(l));
|
|
64
|
+
violations.push({
|
|
65
|
+
filePath,
|
|
66
|
+
line: settingLine === -1 ? findHasuraEnvLine(content) : settingLine + 1,
|
|
67
|
+
severity: 'warning',
|
|
68
|
+
message: `${setting.envVar} has incorrect value. Expected: ${setting.expectedValue}. ${setting.description}.`,
|
|
69
|
+
suggestion: `Change to \`${setting.envVar}: ${setting.expectedValue}\`.`,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return violations;
|
|
74
|
+
}
|
|
75
|
+
export const hasuraProductionConfig = defineCheck({
|
|
76
|
+
id: '54cc4b96-2cb3-4a43-9405-550e6b25bbb9',
|
|
77
|
+
slug: 'hasura-production-config',
|
|
78
|
+
disabled: true,
|
|
79
|
+
scope: { languages: ['json', 'typescript', 'yaml'], concerns: ['config'] },
|
|
80
|
+
contentFilter: 'raw',
|
|
81
|
+
confidence: 'medium',
|
|
82
|
+
description: 'Verify Hasura production docker-compose has required security settings',
|
|
83
|
+
longDescription: `**Purpose:** Ensures production docker-compose files include all required Hasura GraphQL Engine security settings.
|
|
84
|
+
|
|
85
|
+
**Detects:**
|
|
86
|
+
- Missing \`HASURA_GRAPHQL_ENABLE_INTROSPECTION: "false"\` (prevents schema discovery)
|
|
87
|
+
- Missing \`HASURA_GRAPHQL_ENABLE_ALLOWLIST: "true"\` (restricts queries to known operations)
|
|
88
|
+
- Missing \`HASURA_GRAPHQL_DEV_MODE: "false"\` (hides detailed error messages)
|
|
89
|
+
- Missing \`HASURA_GRAPHQL_ENABLE_CONSOLE: "false"\` (prevents unauthorized schema access)
|
|
90
|
+
|
|
91
|
+
**Why it matters:** Hasura defaults are permissive for development. In production, exposed introspection, console, and dev mode leak schema details and enable unauthorized query exploration.
|
|
92
|
+
|
|
93
|
+
**Scope:** Codebase-specific convention. Cross-file analysis on production docker-compose files (\`*prod*\`).`,
|
|
94
|
+
tags: ['security', 'hasura', 'graphql', 'infrastructure'],
|
|
95
|
+
fileTypes: ['yml', 'yaml'],
|
|
96
|
+
async analyzeAll(files) {
|
|
97
|
+
logger.debug({
|
|
98
|
+
evt: 'fitness.checks.hasura_production_config.analyze_all',
|
|
99
|
+
msg: 'Analyzing production docker-compose files for Hasura security settings',
|
|
100
|
+
});
|
|
101
|
+
const prodFiles = files.paths.filter((p) => {
|
|
102
|
+
/* v8 ignore next -- defensive: split + pop on a non-empty string never returns undefined */
|
|
103
|
+
const filename = p.split('/').pop() ?? '';
|
|
104
|
+
return filename.includes('prod');
|
|
105
|
+
});
|
|
106
|
+
// Read all prod files in parallel to avoid sequential async in loop
|
|
107
|
+
// @fitness-ignore-next-line no-unbounded-concurrency -- Bounded to production docker-compose files (typically 1-3)
|
|
108
|
+
const fileEntries = await Promise.all(prodFiles.map(async (filePath) => {
|
|
109
|
+
const content = await files.read(filePath);
|
|
110
|
+
return { filePath, content };
|
|
111
|
+
}));
|
|
112
|
+
const violations = [];
|
|
113
|
+
for (const { filePath, content } of fileEntries) {
|
|
114
|
+
// @lazy-ok -- result validation depends on preceding file read operation
|
|
115
|
+
if (!content)
|
|
116
|
+
continue;
|
|
117
|
+
violations.push(...checkMissingSettings(filePath, content));
|
|
118
|
+
}
|
|
119
|
+
return violations;
|
|
120
|
+
},
|
|
121
|
+
});
|
|
122
|
+
//# sourceMappingURL=hasura-production-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hasura-production-config.js","sourceRoot":"","sources":["../../../src/checks/security/hasura-production-config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export * from './api-key-rotation.js';
|
|
2
|
+
export * from './auth-middleware-coverage.js';
|
|
3
|
+
export * from './auth-route-guard.js';
|
|
4
|
+
export * from './cors-configuration.js';
|
|
5
|
+
export * from './csp-headers.js';
|
|
6
|
+
export * from './dependency-vulnerability-audit.js';
|
|
7
|
+
export * from './env-secret-exposure.js';
|
|
8
|
+
export * from './hasura-production-config.js';
|
|
9
|
+
export * from './jwt-validation.js';
|
|
10
|
+
export * from './no-eval.js';
|
|
11
|
+
export * from './no-hardcoded-secrets.js';
|
|
12
|
+
export * from './package-supply-chain-policy.js';
|
|
13
|
+
export * from './rate-limit-coverage.js';
|
|
14
|
+
export * from './semgrep-scan.js';
|
|
15
|
+
export * from './use-centralized-crypto.js';
|
|
16
|
+
export * from './webhook-signature-verification.js';
|
|
17
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/checks/security/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,kBAAkB,CAAC;AACjC,cAAc,qCAAqC,CAAC;AACpD,cAAc,0BAA0B,CAAC;AACzC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,qBAAqB,CAAC;AACpC,cAAc,cAAc,CAAC;AAC7B,cAAc,2BAA2B,CAAC;AAC1C,cAAc,kCAAkC,CAAC;AACjD,cAAc,0BAA0B,CAAC;AACzC,cAAc,mBAAmB,CAAC;AAClC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,qCAAqC,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export * from './api-key-rotation.js';
|
|
2
|
+
export * from './auth-middleware-coverage.js';
|
|
3
|
+
export * from './auth-route-guard.js';
|
|
4
|
+
export * from './cors-configuration.js';
|
|
5
|
+
export * from './csp-headers.js';
|
|
6
|
+
export * from './dependency-vulnerability-audit.js';
|
|
7
|
+
export * from './env-secret-exposure.js';
|
|
8
|
+
export * from './hasura-production-config.js';
|
|
9
|
+
export * from './jwt-validation.js';
|
|
10
|
+
export * from './no-eval.js';
|
|
11
|
+
export * from './no-hardcoded-secrets.js';
|
|
12
|
+
export * from './package-supply-chain-policy.js';
|
|
13
|
+
export * from './rate-limit-coverage.js';
|
|
14
|
+
export * from './semgrep-scan.js';
|
|
15
|
+
export * from './use-centralized-crypto.js';
|
|
16
|
+
export * from './webhook-signature-verification.js';
|
|
17
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/checks/security/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,kBAAkB,CAAC;AACjC,cAAc,qCAAqC,CAAC;AACpD,cAAc,0BAA0B,CAAC;AACzC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,qBAAqB,CAAC;AACpC,cAAc,cAAc,CAAC;AAC7B,cAAc,2BAA2B,CAAC;AAC1C,cAAc,kCAAkC,CAAC;AACjD,cAAc,0BAA0B,CAAC;AACzC,cAAc,mBAAmB,CAAC;AAClC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,qCAAqC,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Validate JWT handling follows security best practices
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Check: security/jwt-validation
|
|
6
|
+
*
|
|
7
|
+
* Validates JWT handling follows security best practices including
|
|
8
|
+
* algorithm specification, proper verification, and strong secrets.
|
|
9
|
+
*/
|
|
10
|
+
export declare const jwtValidation: import("@opensip-cli/fitness").Check;
|
|
11
|
+
//# sourceMappingURL=jwt-validation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jwt-validation.d.ts","sourceRoot":"","sources":["../../../src/checks/security/jwt-validation.ts"],"names":[],"mappings":"AAEA;;GAEG;AA+RH;;;;;GAKG;AACH,eAAO,MAAM,aAAa,sCAgExB,CAAC"}
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
// @fitness-ignore-file file-length-limit -- reviewed: tightly coupled JWT validation logic with pattern detection, AST analysis, and violation reporting requires single-file cohesion
|
|
2
|
+
// @fitness-ignore-file error-handling-quality -- reviewed: false positive; String.prototype.match() at line 141 is regex matching, not Result.match() error handling
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview Validate JWT handling follows security best practices
|
|
5
|
+
*/
|
|
6
|
+
import { logger } from '@opensip-cli/core';
|
|
7
|
+
import { defineCheck } from '@opensip-cli/fitness';
|
|
8
|
+
/**
|
|
9
|
+
* Check if line contains jwt.verify without algorithm option.
|
|
10
|
+
* Uses simple string matching to avoid ReDoS.
|
|
11
|
+
*
|
|
12
|
+
* @param line - Line to check
|
|
13
|
+
* @returns Match result
|
|
14
|
+
*/
|
|
15
|
+
function checkJwtVerifyWithoutAlgorithm(line) {
|
|
16
|
+
logger.debug({
|
|
17
|
+
evt: 'fitness.checks.jwt_validation.check_jwt_verify_without_algorithm',
|
|
18
|
+
msg: 'Checking for JWT verify without algorithm option',
|
|
19
|
+
});
|
|
20
|
+
const idx = line.indexOf('jwt.verify');
|
|
21
|
+
if (idx === -1)
|
|
22
|
+
return { matched: false, matchIndex: -1, matchText: '' };
|
|
23
|
+
// Find the end of the verify call
|
|
24
|
+
const afterVerify = line.slice(Math.max(0, idx));
|
|
25
|
+
const parenStart = afterVerify.indexOf('(');
|
|
26
|
+
if (parenStart === -1)
|
|
27
|
+
return { matched: false, matchIndex: -1, matchText: '' };
|
|
28
|
+
// Count parentheses to find end of call
|
|
29
|
+
let depth = 0;
|
|
30
|
+
let parenEnd = -1;
|
|
31
|
+
for (let i = parenStart; i < afterVerify.length; i++) {
|
|
32
|
+
const char = afterVerify[i];
|
|
33
|
+
if (char === '(') {
|
|
34
|
+
depth++;
|
|
35
|
+
}
|
|
36
|
+
else if (char === ')') {
|
|
37
|
+
depth--;
|
|
38
|
+
if (depth === 0) {
|
|
39
|
+
parenEnd = i;
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
// Other characters are ignored during parenthesis counting
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if (parenEnd === -1)
|
|
48
|
+
return { matched: false, matchIndex: -1, matchText: '' };
|
|
49
|
+
const callContent = afterVerify.slice(parenStart, parenEnd + 1);
|
|
50
|
+
// Check if there are 2 args (no options) - simple comma count for basic calls
|
|
51
|
+
const commaCount = (callContent.match(/,/g) ?? []).length;
|
|
52
|
+
// jwt.verify(token, secret) has 1 comma, jwt.verify(token, secret, options) has 2+
|
|
53
|
+
// Also check if 'algorithms' is mentioned
|
|
54
|
+
if (commaCount === 1 && !callContent.toLowerCase().includes('algorithm')) {
|
|
55
|
+
return { matched: true, matchIndex: idx, matchText: 'jwt.verify' + callContent };
|
|
56
|
+
}
|
|
57
|
+
return { matched: false, matchIndex: -1, matchText: '' };
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Check if line uses jwt.decode for authentication context.
|
|
61
|
+
*
|
|
62
|
+
* @param line - Line to check
|
|
63
|
+
* @returns Match result
|
|
64
|
+
*/
|
|
65
|
+
function checkJwtDecodeForAuth(line) {
|
|
66
|
+
logger.debug({
|
|
67
|
+
evt: 'fitness.checks.jwt_validation.check_jwt_decode_for_auth',
|
|
68
|
+
msg: 'Checking for JWT decode used for authentication',
|
|
69
|
+
});
|
|
70
|
+
const idx = line.indexOf('jwt.decode');
|
|
71
|
+
if (idx === -1)
|
|
72
|
+
return { matched: false, matchIndex: -1, matchText: '' };
|
|
73
|
+
// Check if line contains auth-related keywords
|
|
74
|
+
const lowerLine = line.toLowerCase();
|
|
75
|
+
const authKeywords = ['user', 'auth', 'session', 'token'];
|
|
76
|
+
const hasAuthKeyword = authKeywords.some((kw) => lowerLine.includes(kw));
|
|
77
|
+
if (hasAuthKeyword) {
|
|
78
|
+
return { matched: true, matchIndex: idx, matchText: 'jwt.decode' };
|
|
79
|
+
}
|
|
80
|
+
return { matched: false, matchIndex: -1, matchText: '' };
|
|
81
|
+
}
|
|
82
|
+
/* v8 ignore start -- secret-detection helpers iterate keywords and apply regex; covered indirectly via fixtures */
|
|
83
|
+
/**
|
|
84
|
+
* Check if line has a weak JWT secret (short string literal).
|
|
85
|
+
*
|
|
86
|
+
* @param line - Line to check
|
|
87
|
+
* @returns Match result
|
|
88
|
+
*/
|
|
89
|
+
function checkWeakJwtSecret(line) {
|
|
90
|
+
logger.debug({
|
|
91
|
+
evt: 'fitness.checks.jwt_validation.check_weak_jwt_secret',
|
|
92
|
+
msg: 'Checking for weak JWT secret',
|
|
93
|
+
});
|
|
94
|
+
const lowerLine = line.toLowerCase();
|
|
95
|
+
const secretKeywords = ['jwtsecret', 'jwt_secret', 'jwt-secret', 'secret'];
|
|
96
|
+
for (const keyword of secretKeywords) {
|
|
97
|
+
const idx = lowerLine.indexOf(keyword);
|
|
98
|
+
if (idx === -1)
|
|
99
|
+
continue;
|
|
100
|
+
// Look for assignment after keyword - simple check for short strings
|
|
101
|
+
const afterKeyword = line.slice(Math.max(0, idx + keyword.length));
|
|
102
|
+
// Match patterns like: = 'short' or : "short"
|
|
103
|
+
// @fitness-ignore-next-line sonarjs-regular-expr -- Simple pattern with bounded quantifier {0,20} and negated class [^'"`]; no backtracking risk
|
|
104
|
+
const assignMatch = /^\s*[:=]\s*['"`]([^'"`]{0,20})['"`]/.exec(afterKeyword);
|
|
105
|
+
if (assignMatch?.[1] !== undefined && assignMatch[1].length <= 20) {
|
|
106
|
+
return { matched: true, matchIndex: idx, matchText: keyword + assignMatch[0] };
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return { matched: false, matchIndex: -1, matchText: '' };
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Check if line allows algorithm 'none'.
|
|
113
|
+
*
|
|
114
|
+
* @param line - Line to check
|
|
115
|
+
* @returns Match result
|
|
116
|
+
*/
|
|
117
|
+
function checkAlgorithmNone(line) {
|
|
118
|
+
logger.debug({
|
|
119
|
+
evt: 'fitness.checks.jwt_validation.check_algorithm_none',
|
|
120
|
+
msg: 'Checking for insecure algorithm none',
|
|
121
|
+
});
|
|
122
|
+
const lowerLine = line.toLowerCase();
|
|
123
|
+
// Look for algorithms: ['none'] or algorithm: ['none']
|
|
124
|
+
const patterns = ['algorithms', 'algorithm'];
|
|
125
|
+
for (const pattern of patterns) {
|
|
126
|
+
const idx = lowerLine.indexOf(pattern);
|
|
127
|
+
if (idx === -1)
|
|
128
|
+
continue;
|
|
129
|
+
const afterPattern = lowerLine.slice(Math.max(0, idx));
|
|
130
|
+
// Check for assignment to array containing 'none'
|
|
131
|
+
const hasNone = afterPattern.includes('[') &&
|
|
132
|
+
(afterPattern.includes("'none'") ||
|
|
133
|
+
afterPattern.includes('"none"') ||
|
|
134
|
+
afterPattern.includes('`none`'));
|
|
135
|
+
if (hasNone) {
|
|
136
|
+
const matchEnd = line.slice(Math.max(0, idx)).indexOf(']') + 1;
|
|
137
|
+
return { matched: true, matchIndex: idx, matchText: line.slice(idx, idx + matchEnd) };
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return { matched: false, matchIndex: -1, matchText: '' };
|
|
141
|
+
}
|
|
142
|
+
/* v8 ignore stop */
|
|
143
|
+
/**
|
|
144
|
+
* Check if .verify( call is missing issuer/audience validation.
|
|
145
|
+
* Only matches actual method calls (.verify() with opening paren),
|
|
146
|
+
* not method names that contain 'verify' as a substring (e.g., verifyEventSignature).
|
|
147
|
+
*
|
|
148
|
+
* @param line - Line to check
|
|
149
|
+
* @returns Match result
|
|
150
|
+
*/
|
|
151
|
+
function checkMissingIssuerAudience(line) {
|
|
152
|
+
logger.debug({
|
|
153
|
+
evt: 'fitness.checks.jwt_validation.check_missing_issuer_audience',
|
|
154
|
+
msg: 'Checking for missing issuer or audience validation',
|
|
155
|
+
});
|
|
156
|
+
// Look for .verify( specifically to match method calls, not substrings like verifyEventSignature
|
|
157
|
+
const idx = line.indexOf('.verify(');
|
|
158
|
+
if (idx === -1)
|
|
159
|
+
return { matched: false, matchIndex: -1, matchText: '' };
|
|
160
|
+
// Check if there's an options object
|
|
161
|
+
const afterVerify = line.slice(Math.max(0, idx));
|
|
162
|
+
if (!afterVerify.includes('{'))
|
|
163
|
+
return { matched: false, matchIndex: -1, matchText: '' };
|
|
164
|
+
// Check if issuer/audience/iss/aud is present
|
|
165
|
+
const lowerAfter = afterVerify.toLowerCase();
|
|
166
|
+
const hasValidation = lowerAfter.includes('issuer') ||
|
|
167
|
+
lowerAfter.includes('audience') ||
|
|
168
|
+
lowerAfter.includes('iss') ||
|
|
169
|
+
lowerAfter.includes('aud');
|
|
170
|
+
if (!hasValidation) {
|
|
171
|
+
return { matched: true, matchIndex: idx, matchText: '.verify(...)' };
|
|
172
|
+
}
|
|
173
|
+
return { matched: false, matchIndex: -1, matchText: '' };
|
|
174
|
+
}
|
|
175
|
+
const JWT_SECURITY_PATTERNS = [
|
|
176
|
+
{
|
|
177
|
+
// @fitness-ignore-next-line fitness-check-standards -- This is an internal pattern ID for violation grouping, not the check ID
|
|
178
|
+
id: 'jwt-verify-no-algorithm',
|
|
179
|
+
message: 'JWT verification without algorithm restriction - specify algorithms option',
|
|
180
|
+
suggestion: 'Add algorithms option to prevent algorithm substitution attacks: jwt.verify(token, secret, { algorithms: ["HS256"] }). This ensures only the expected algorithm is accepted.',
|
|
181
|
+
severity: 'error',
|
|
182
|
+
check: checkJwtVerifyWithoutAlgorithm,
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
id: 'jwt-decode-for-auth',
|
|
186
|
+
message: 'jwt.decode used for authentication - use jwt.verify instead',
|
|
187
|
+
suggestion: 'jwt.decode does not verify the signature! Use jwt.verify() for authentication: const payload = jwt.verify(token, secret, { algorithms: ["HS256"] });',
|
|
188
|
+
severity: 'error',
|
|
189
|
+
check: checkJwtDecodeForAuth,
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
id: 'weak-jwt-secret',
|
|
193
|
+
message: 'JWT secret appears weak (too short) - use a strong random secret',
|
|
194
|
+
suggestion: 'Use a cryptographically strong random secret of at least 256 bits (32 bytes). Generate with: openssl rand -base64 32. Store in environment variable, not in code.',
|
|
195
|
+
severity: 'warning',
|
|
196
|
+
check: checkWeakJwtSecret,
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
id: 'algorithm-none',
|
|
200
|
+
message: 'JWT algorithm "none" is insecure - never allow unsigned tokens',
|
|
201
|
+
suggestion: 'Remove "none" from allowed algorithms. This would allow unsigned tokens to bypass authentication. Use only secure algorithms like HS256, RS256, or ES256.',
|
|
202
|
+
severity: 'error',
|
|
203
|
+
check: checkAlgorithmNone,
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
id: 'missing-issuer-audience',
|
|
207
|
+
message: 'Consider adding issuer/audience validation for enhanced security',
|
|
208
|
+
suggestion: 'Add issuer and audience validation: jwt.verify(token, secret, { issuer: "your-issuer", audience: "your-api" }). This prevents token reuse across different services.',
|
|
209
|
+
severity: 'warning',
|
|
210
|
+
check: checkMissingIssuerAudience,
|
|
211
|
+
},
|
|
212
|
+
];
|
|
213
|
+
/**
|
|
214
|
+
* Check if content contains JWT-related keywords.
|
|
215
|
+
* Uses simple string matching to avoid regex issues.
|
|
216
|
+
*
|
|
217
|
+
* @param content - Content to check
|
|
218
|
+
* @returns True if JWT keywords found
|
|
219
|
+
*/
|
|
220
|
+
function hasJwtKeywords(content) {
|
|
221
|
+
logger.debug({
|
|
222
|
+
evt: 'fitness.checks.jwt_validation.has_jwt_keywords',
|
|
223
|
+
msg: 'Checking if content contains JWT-related keywords',
|
|
224
|
+
});
|
|
225
|
+
const lowerContent = content.toLowerCase();
|
|
226
|
+
return (lowerContent.includes('jwt') ||
|
|
227
|
+
lowerContent.includes('jsonwebtoken') ||
|
|
228
|
+
lowerContent.includes('jose'));
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Check: security/jwt-validation
|
|
232
|
+
*
|
|
233
|
+
* Validates JWT handling follows security best practices including
|
|
234
|
+
* algorithm specification, proper verification, and strong secrets.
|
|
235
|
+
*/
|
|
236
|
+
export const jwtValidation = defineCheck({
|
|
237
|
+
id: '2f5c06d9-4b94-4dbf-a071-5ae021819d61',
|
|
238
|
+
slug: 'jwt-validation',
|
|
239
|
+
disabled: true,
|
|
240
|
+
scope: { languages: ['typescript'], concerns: ['backend', 'server'] },
|
|
241
|
+
contentFilter: 'strip-strings',
|
|
242
|
+
confidence: 'medium',
|
|
243
|
+
description: 'Validate JWT handling follows security best practices',
|
|
244
|
+
longDescription: `**Purpose:** Validates that JWT handling code follows security best practices for token verification, algorithm selection, and secret strength.
|
|
245
|
+
|
|
246
|
+
**Detects:**
|
|
247
|
+
- \`jwt.verify(token, secret)\` with only 2 arguments (missing algorithms option) — enables algorithm substitution attacks
|
|
248
|
+
- \`jwt.decode\` used in auth context (decode does not verify signatures)
|
|
249
|
+
- Weak JWT secrets: short string literals (<=20 chars) assigned to jwt_secret/jwt-secret/secret variables
|
|
250
|
+
- Algorithm \`"none"\` in algorithms array — allows unsigned tokens
|
|
251
|
+
- \`.verify()\` calls with options object but missing issuer/audience validation
|
|
252
|
+
|
|
253
|
+
**Why it matters:** JWT misconfigurations are a top authentication bypass vector. Missing algorithm restriction, unverified tokens, and weak secrets can all lead to complete auth bypass.
|
|
254
|
+
|
|
255
|
+
**Scope:** General best practice. Analyzes each file individually. Only scans files containing jwt, jsonwebtoken, or jose references.`,
|
|
256
|
+
tags: ['security', 'jwt', 'authentication'],
|
|
257
|
+
fileTypes: ['ts'],
|
|
258
|
+
analyze(content, filePath) {
|
|
259
|
+
logger.debug({
|
|
260
|
+
evt: 'fitness.checks.jwt_validation.analyze',
|
|
261
|
+
msg: 'Analyzing file for JWT validation best practices',
|
|
262
|
+
});
|
|
263
|
+
// Skip files that don't deal with JWT
|
|
264
|
+
if (!hasJwtKeywords(content)) {
|
|
265
|
+
return [];
|
|
266
|
+
}
|
|
267
|
+
const violations = [];
|
|
268
|
+
const lines = content.split('\n');
|
|
269
|
+
for (const [lineNum, line_] of lines.entries()) {
|
|
270
|
+
const line = line_ ?? '';
|
|
271
|
+
// Skip comments
|
|
272
|
+
const trimmed = line.trim();
|
|
273
|
+
if (trimmed.startsWith('//') || trimmed.startsWith('*')) {
|
|
274
|
+
continue;
|
|
275
|
+
}
|
|
276
|
+
for (const pattern of JWT_SECURITY_PATTERNS) {
|
|
277
|
+
const result = pattern.check(line);
|
|
278
|
+
if (result.matched) {
|
|
279
|
+
violations.push({
|
|
280
|
+
line: lineNum + 1,
|
|
281
|
+
column: result.matchIndex,
|
|
282
|
+
message: pattern.message,
|
|
283
|
+
severity: pattern.severity,
|
|
284
|
+
suggestion: pattern.suggestion,
|
|
285
|
+
match: result.matchText,
|
|
286
|
+
filePath,
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
return violations;
|
|
292
|
+
},
|
|
293
|
+
});
|
|
294
|
+
//# sourceMappingURL=jwt-validation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jwt-validation.js","sourceRoot":"","sources":["../../../src/checks/security/jwt-validation.ts"],"names":[],"mappings":"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"}
|