@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,193 @@
|
|
|
1
|
+
// @fitness-ignore-file fitness-check-standards -- Uses fs for package.json reading, not source file content
|
|
2
|
+
// @fitness-ignore-file duplicate-implementation-detection -- similar patterns across diagnostic modules
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview Docker version sync fitness check
|
|
5
|
+
* @invariants
|
|
6
|
+
* - Node major version in FROM directives must match engines.node from root package.json
|
|
7
|
+
* - pnpm version should be derived dynamically from package.json packageManager field
|
|
8
|
+
* - Hardcoded pnpm versions that don't match packageManager are errors
|
|
9
|
+
*/
|
|
10
|
+
import * as fs from 'node:fs';
|
|
11
|
+
import * as path from 'node:path';
|
|
12
|
+
import { defineCheck } from '@opensip-cli/fitness';
|
|
13
|
+
// =============================================================================
|
|
14
|
+
// REGEX PATTERNS
|
|
15
|
+
// =============================================================================
|
|
16
|
+
/** Matches FROM node:XX or FROM node:XX-alpine etc. */
|
|
17
|
+
const FROM_NODE_PATTERN = /^FROM\s+node:(\d+)/i;
|
|
18
|
+
/** Matches corepack prepare pnpm@X.Y.Z or pnpm@X */
|
|
19
|
+
const PNPM_HARDCODED_PATTERN = /corepack\s+prepare\s+pnpm@([\d.]+)/;
|
|
20
|
+
/** Matches the dynamic self-read pattern */
|
|
21
|
+
const PNPM_DYNAMIC_PATTERN = /require\(['"]\.\/package\.json['"]\)\.packageManager/;
|
|
22
|
+
// =============================================================================
|
|
23
|
+
// HELPERS
|
|
24
|
+
// =============================================================================
|
|
25
|
+
/**
|
|
26
|
+
* Read and parse root package.json.
|
|
27
|
+
* @throws {Error} When the file exceeds 10MB
|
|
28
|
+
*/
|
|
29
|
+
function readRootPackageJson(cwd) {
|
|
30
|
+
const pkgPath = path.join(cwd, 'package.json');
|
|
31
|
+
const stats = fs.statSync(pkgPath);
|
|
32
|
+
if (stats.size > 10_000_000)
|
|
33
|
+
throw new Error(`File too large: ${pkgPath}`);
|
|
34
|
+
const raw = fs.readFileSync(pkgPath, 'utf8');
|
|
35
|
+
return JSON.parse(raw);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Extract major Node version from engines.node constraint.
|
|
39
|
+
* e.g. ">=20.0.0" → 20
|
|
40
|
+
*/
|
|
41
|
+
function extractNodeMajor(constraint) {
|
|
42
|
+
const match = /(\d+)/.exec(constraint);
|
|
43
|
+
const digit = match?.[1];
|
|
44
|
+
// @fitness-ignore-next-line numeric-validation -- regex (\d+) guarantees digit-only string
|
|
45
|
+
return digit ? Number.parseInt(digit, 10) : null;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Extract pnpm version from packageManager field.
|
|
49
|
+
* e.g. "pnpm@10.28.2+sha512.abc..." → "10.28.2"
|
|
50
|
+
*/
|
|
51
|
+
function extractPnpmVersion(packageManager) {
|
|
52
|
+
const match = /^pnpm@([\d.]+)/.exec(packageManager);
|
|
53
|
+
/* v8 ignore next -- defensive: regex ([\d.]+) capture is guaranteed when match succeeds */
|
|
54
|
+
return match?.[1] ?? null;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Extract major version from a version string.
|
|
58
|
+
* e.g. "10.28.2" → 10
|
|
59
|
+
*/
|
|
60
|
+
function extractMajor(version) {
|
|
61
|
+
/* v8 ignore next -- defensive: split always returns at least one element */
|
|
62
|
+
const major = version.split('.')[0] ?? '0';
|
|
63
|
+
const parsed = Number.parseInt(major, 10);
|
|
64
|
+
/* v8 ignore next -- defensive: parseInt on digit-only string is always finite */
|
|
65
|
+
return Number.isFinite(parsed) ? parsed : 0;
|
|
66
|
+
}
|
|
67
|
+
function checkNodeVersion(line, lineNum, expectedNodeMajor, ctx) {
|
|
68
|
+
const { filePath, violations } = ctx;
|
|
69
|
+
const nodeMatch = FROM_NODE_PATTERN.exec(line);
|
|
70
|
+
const nodeVersion = nodeMatch?.[1];
|
|
71
|
+
if (!nodeVersion)
|
|
72
|
+
return;
|
|
73
|
+
// @fitness-ignore-next-line numeric-validation -- regex (\d+) guarantees digit-only string
|
|
74
|
+
const dockerNodeMajor = Number.parseInt(nodeVersion, 10);
|
|
75
|
+
if (dockerNodeMajor !== expectedNodeMajor) {
|
|
76
|
+
violations.push({
|
|
77
|
+
line: lineNum,
|
|
78
|
+
filePath,
|
|
79
|
+
message: `Node major version mismatch: Dockerfile uses node:${dockerNodeMajor} but package.json engines.node requires ${expectedNodeMajor}`,
|
|
80
|
+
severity: 'error',
|
|
81
|
+
suggestion: `Change FROM node:${dockerNodeMajor} to FROM node:${expectedNodeMajor}`,
|
|
82
|
+
type: 'node-version-mismatch',
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
function checkPnpmVersion(line, lineNum, expectedPnpmVersion, ctx) {
|
|
87
|
+
const { filePath, relPath, violations } = ctx;
|
|
88
|
+
const hardcodedMatch = PNPM_HARDCODED_PATTERN.exec(line);
|
|
89
|
+
const hardcodedVersion = hardcodedMatch?.[1];
|
|
90
|
+
if (!hardcodedVersion)
|
|
91
|
+
return false;
|
|
92
|
+
if (PNPM_DYNAMIC_PATTERN.test(line)) {
|
|
93
|
+
// Dynamic pattern is used — this is the preferred approach, no violation
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
const hardcodedMajor = extractMajor(hardcodedVersion);
|
|
97
|
+
const expectedMajor = extractMajor(expectedPnpmVersion);
|
|
98
|
+
const isVersionMismatch = hardcodedMajor !== expectedMajor || hardcodedVersion !== expectedPnpmVersion;
|
|
99
|
+
if (isVersionMismatch) {
|
|
100
|
+
violations.push({
|
|
101
|
+
line: lineNum,
|
|
102
|
+
filePath,
|
|
103
|
+
message: `pnpm version mismatch: Dockerfile uses pnpm@${hardcodedVersion} but package.json declares pnpm@${expectedPnpmVersion}`,
|
|
104
|
+
severity: 'error',
|
|
105
|
+
suggestion: `Use dynamic version extraction: corepack prepare $(node -e "process.stdout.write(require('./package.json').packageManager.split('+')[0])") --activate`,
|
|
106
|
+
type: 'pnpm-version-mismatch',
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
// Version matches but is hardcoded — warn to use dynamic pattern
|
|
111
|
+
violations.push({
|
|
112
|
+
line: lineNum,
|
|
113
|
+
filePath,
|
|
114
|
+
message: `Hardcoded pnpm version pnpm@${hardcodedVersion} in ${relPath} — prefer dynamic extraction from package.json`,
|
|
115
|
+
severity: 'warning',
|
|
116
|
+
suggestion: `Use dynamic version extraction: corepack prepare $(node -e "process.stdout.write(require('./package.json').packageManager.split('+')[0])") --activate`,
|
|
117
|
+
type: 'pnpm-hardcoded-version',
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
function analyzeDockerfileLines(lines, expectedNodeMajor, expectedPnpmVersion, ctx) {
|
|
123
|
+
for (const [i, rawLine] of lines.entries()) {
|
|
124
|
+
if (!rawLine)
|
|
125
|
+
continue;
|
|
126
|
+
const line = rawLine.trim();
|
|
127
|
+
const lineNum = i + 1;
|
|
128
|
+
if (expectedNodeMajor !== null) {
|
|
129
|
+
checkNodeVersion(line, lineNum, expectedNodeMajor, ctx);
|
|
130
|
+
}
|
|
131
|
+
if (expectedPnpmVersion !== null) {
|
|
132
|
+
const shouldSkipLine = checkPnpmVersion(line, lineNum, expectedPnpmVersion, ctx);
|
|
133
|
+
if (shouldSkipLine)
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
// =============================================================================
|
|
139
|
+
// CHECK DEFINITION
|
|
140
|
+
// =============================================================================
|
|
141
|
+
/**
|
|
142
|
+
* Check: architecture/docker-version-sync
|
|
143
|
+
*
|
|
144
|
+
* Validates that Dockerfiles keep Node and pnpm versions in sync with package.json:
|
|
145
|
+
* 1. FROM node:XX major version matches engines.node
|
|
146
|
+
* 2. pnpm version is either dynamically derived (preferred) or hardcoded consistently
|
|
147
|
+
*/
|
|
148
|
+
export const dockerVersionSync = defineCheck({
|
|
149
|
+
id: '15680f1a-134d-4247-b4c2-ca6c6ed9c43d',
|
|
150
|
+
slug: 'docker-version-sync',
|
|
151
|
+
disabled: true,
|
|
152
|
+
scope: { languages: ['json', 'typescript', 'yaml'], concerns: ['config'] },
|
|
153
|
+
contentFilter: 'raw',
|
|
154
|
+
confidence: 'medium',
|
|
155
|
+
description: 'Validate Docker Node/pnpm versions match package.json',
|
|
156
|
+
longDescription: `**Purpose:** Ensures Dockerfiles keep Node.js and pnpm versions synchronized with the root \`package.json\` to prevent version drift.
|
|
157
|
+
|
|
158
|
+
**Detects:**
|
|
159
|
+
- \`FROM node:XX\` major version mismatches against \`engines.node\` in root \`package.json\`
|
|
160
|
+
- Hardcoded \`corepack prepare pnpm@X.Y.Z\` that differs from \`packageManager\` field
|
|
161
|
+
- Hardcoded pnpm versions even when matching (prefers dynamic extraction via \`require('./package.json').packageManager\`)
|
|
162
|
+
|
|
163
|
+
**Why it matters:** Version mismatches between Dockerfiles and package.json cause inconsistent runtime behavior and hard-to-diagnose production bugs.
|
|
164
|
+
|
|
165
|
+
**Scope:** Codebase-specific convention. Cross-file analysis via \`analyzeAll\`.`,
|
|
166
|
+
tags: ['docker', 'version-sync', 'architecture'],
|
|
167
|
+
async analyzeAll(files) {
|
|
168
|
+
const violations = [];
|
|
169
|
+
// Read root package.json for version truth
|
|
170
|
+
const rootPkg = readRootPackageJson(process.cwd());
|
|
171
|
+
const expectedNodeMajor = rootPkg.engines?.node ? extractNodeMajor(rootPkg.engines.node) : null;
|
|
172
|
+
const expectedPnpmVersion = rootPkg.packageManager
|
|
173
|
+
? extractPnpmVersion(rootPkg.packageManager)
|
|
174
|
+
: null;
|
|
175
|
+
for (const filePath of files.paths) {
|
|
176
|
+
// @fitness-ignore-next-line performance-anti-patterns -- sequential file reading to control memory; FileAccessor is lazy
|
|
177
|
+
const content = await files.read(filePath);
|
|
178
|
+
const lines = content.split('\n');
|
|
179
|
+
const relPath = path.relative(process.cwd(), filePath);
|
|
180
|
+
// Skip non-Node Dockerfiles (e.g. Hasura)
|
|
181
|
+
const hasNodeFrom = lines.some((line) => FROM_NODE_PATTERN.test(line.trim()));
|
|
182
|
+
if (!hasNodeFrom)
|
|
183
|
+
continue;
|
|
184
|
+
void analyzeDockerfileLines(lines, expectedNodeMajor, expectedPnpmVersion, {
|
|
185
|
+
filePath,
|
|
186
|
+
relPath,
|
|
187
|
+
violations,
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
return violations;
|
|
191
|
+
},
|
|
192
|
+
});
|
|
193
|
+
//# sourceMappingURL=docker-version-sync.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"docker-version-sync.js","sourceRoot":"","sources":["../../../src/checks/architecture/docker-version-sync.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Environment Variable Validation check
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Check: architecture/env-var-validation
|
|
6
|
+
*
|
|
7
|
+
* Detects environment variable access without validation:
|
|
8
|
+
* - process.env.X without null check
|
|
9
|
+
* - Missing default values
|
|
10
|
+
* - Type coercion issues
|
|
11
|
+
* - Direct access outside config modules
|
|
12
|
+
*/
|
|
13
|
+
export declare const envVarValidation: import("@opensip-cli/fitness").Check;
|
|
14
|
+
//# sourceMappingURL=env-var-validation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env-var-validation.d.ts","sourceRoot":"","sources":["../../../src/checks/architecture/env-var-validation.ts"],"names":[],"mappings":"AACA;;GAEG;AAwUH;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB,sCA2C3B,CAAC"}
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
// @fitness-ignore-file semgrep-scan -- non-literal RegExp patterns use envVarName extracted from process.env.\w+ regex match on source code, not user input; regex operates on bounded, trusted codebase files
|
|
2
|
+
/**
|
|
3
|
+
* @fileoverview Environment Variable Validation check
|
|
4
|
+
*/
|
|
5
|
+
import { createPathMatcher, defineCheck } from '@opensip-cli/fitness';
|
|
6
|
+
// =============================================================================
|
|
7
|
+
// PRE-COMPILED REGEX PATTERNS
|
|
8
|
+
// =============================================================================
|
|
9
|
+
// Excluded path patterns
|
|
10
|
+
const TEST_FILE_PATTERN = /\.test\.[jt]s$/;
|
|
11
|
+
const SPEC_FILE_PATTERN = /\.spec\.[jt]s$/;
|
|
12
|
+
const TESTS_DIR_PATTERN = /__tests__\//;
|
|
13
|
+
const BENCH_FILE_PATTERN = /\.bench\.[jt]s$/;
|
|
14
|
+
const CONFIG_DIR_PATTERN = /config\//;
|
|
15
|
+
const CONFIG_FILE_PATTERN = /\.config\.[jt]s$/;
|
|
16
|
+
// Safe access patterns
|
|
17
|
+
const NULLISH_COALESCING_PATTERN = /process\.env\.\w+\s*\?\?/;
|
|
18
|
+
const LOGICAL_OR_PATTERN = /process\.env\.\w+\s*\|\|/;
|
|
19
|
+
const NON_NULL_ASSERTION_PATTERN = /process\.env\.\w+\s*!\s*[,;)]/;
|
|
20
|
+
const GET_ENV_PATTERN = /getEnv\s*\(/;
|
|
21
|
+
const CONFIG_ACCESS_PATTERN = /config\.\w+/;
|
|
22
|
+
// A validated env-object access (e.g. `env.PORT` from a typed config) is safe —
|
|
23
|
+
// but NOT `process.env.X`, whose own text contains the substring `env.X`. The
|
|
24
|
+
// negative lookbehind stops this pattern from matching the access it's meant to
|
|
25
|
+
// flag (which otherwise made every process.env access "safe" — the check never
|
|
26
|
+
// fired).
|
|
27
|
+
const ENV_ACCESS_PATTERN = /(?<!process\.)\benv\.\w+/;
|
|
28
|
+
const REQUIRE_ENV_PATTERN = /requireEnv\s*\(/;
|
|
29
|
+
const OPTIONAL_ENV_PATTERN = /optionalEnv\s*\(/;
|
|
30
|
+
// Boolean coercion is a safe read: `!!process.env.X` / `Boolean(process.env.X)`
|
|
31
|
+
// can never be `undefined`.
|
|
32
|
+
const BOOLEAN_COERCION_PATTERN = /(?:!!|Boolean\s*\(\s*)process\.env\.\w+/;
|
|
33
|
+
// A comparison is null-safe: `process.env.X === '1'` / `!== ...` evaluates to a
|
|
34
|
+
// boolean regardless of whether the var is set.
|
|
35
|
+
const COMPARISON_PATTERN = /process\.env\.\w+\s*[=!]==?|[=!]==?\s*process\.env\.\w+/;
|
|
36
|
+
// A truthy guard reads the var defensively: `if (process.env.X)` / `if (!process.env.X)`.
|
|
37
|
+
// `(?:!\s*)?` keeps the optional negation unambiguous (no adjacent `\s*` runs).
|
|
38
|
+
const IF_GUARD_PATTERN = /\bif\s*\(\s*(?:!\s*)?process\.env\.\w+/;
|
|
39
|
+
// Captures the variable an env read is assigned to, so a guard on that variable
|
|
40
|
+
// (possibly on a following line) can be recognised as safe. The gap is bounded
|
|
41
|
+
// to a single statement (no `=`, no newline) to keep matching linear.
|
|
42
|
+
// eslint-disable-next-line sonarjs/slow-regex -- gap class [^=\n] excludes the delimiters, so the lazy quantifier is single-pass over a bounded window of trusted source
|
|
43
|
+
const ENV_CAPTURE_PATTERN = /(?:const|let|var)\s+(\w+)\s*=\s*[^=\n]*?process\.env\.\w+/;
|
|
44
|
+
// Env var extraction pattern
|
|
45
|
+
const ENV_VAR_PATTERN = /process\.env\.(\w+)/g;
|
|
46
|
+
const NON_RUNTIME_PATTERNS = [
|
|
47
|
+
TEST_FILE_PATTERN,
|
|
48
|
+
SPEC_FILE_PATTERN,
|
|
49
|
+
TESTS_DIR_PATTERN,
|
|
50
|
+
BENCH_FILE_PATTERN,
|
|
51
|
+
CONFIG_DIR_PATTERN,
|
|
52
|
+
CONFIG_FILE_PATTERN,
|
|
53
|
+
];
|
|
54
|
+
const SAFE_PATTERNS = [
|
|
55
|
+
NULLISH_COALESCING_PATTERN,
|
|
56
|
+
LOGICAL_OR_PATTERN,
|
|
57
|
+
NON_NULL_ASSERTION_PATTERN,
|
|
58
|
+
GET_ENV_PATTERN,
|
|
59
|
+
CONFIG_ACCESS_PATTERN,
|
|
60
|
+
ENV_ACCESS_PATTERN,
|
|
61
|
+
REQUIRE_ENV_PATTERN,
|
|
62
|
+
OPTIONAL_ENV_PATTERN,
|
|
63
|
+
BOOLEAN_COERCION_PATTERN,
|
|
64
|
+
COMPARISON_PATTERN,
|
|
65
|
+
IF_GUARD_PATTERN,
|
|
66
|
+
];
|
|
67
|
+
// =============================================================================
|
|
68
|
+
// HELPER FUNCTIONS
|
|
69
|
+
// =============================================================================
|
|
70
|
+
const isExcludedEnvPath = createPathMatcher(NON_RUNTIME_PATTERNS);
|
|
71
|
+
/**
|
|
72
|
+
* A read captured into a variable is safe when that variable is guarded nearby,
|
|
73
|
+
* e.g. `const endpoint = process.env.X; if (!endpoint) return;`. Looks within the
|
|
74
|
+
* provided window (the access line plus a couple of following lines).
|
|
75
|
+
*/
|
|
76
|
+
function isCapturedAndGuarded(window) {
|
|
77
|
+
const capture = ENV_CAPTURE_PATTERN.exec(window);
|
|
78
|
+
const varName = capture?.[1];
|
|
79
|
+
if (!varName) {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
// The captured name appears in an if-guard / return-guard, or alongside a
|
|
83
|
+
// null-ish / boolean / comparison operator.
|
|
84
|
+
const guard = new RegExp(String.raw `(?:\bif\s*\(|\breturn\b|[!(])[^\n]*\b${varName}\b|\b${varName}\b\s*(?:\?\??|\|\||&&|===|!==|==|!=)`);
|
|
85
|
+
return guard.test(window);
|
|
86
|
+
}
|
|
87
|
+
function isSafeContext(context) {
|
|
88
|
+
return SAFE_PATTERNS.some((p) => p.test(context)) || isCapturedAndGuarded(context);
|
|
89
|
+
}
|
|
90
|
+
function hasNullCheck(context) {
|
|
91
|
+
return context.includes('??') || context.includes('||') || context.includes('?');
|
|
92
|
+
}
|
|
93
|
+
function getMatchContext(line, matchIndex, matchLength) {
|
|
94
|
+
const start = Math.max(0, matchIndex - 20);
|
|
95
|
+
const end = Math.min(line.length, matchIndex + matchLength + 50);
|
|
96
|
+
return line.slice(start, end);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Check for type coercion issues using dynamic patterns
|
|
100
|
+
*/
|
|
101
|
+
function hasTypeCoercionIssue(context, envVarName) {
|
|
102
|
+
const numericOpPattern = new RegExp(String.raw `process\.env\.${envVarName}\s*[+\-*/<>]=?\s*\d`);
|
|
103
|
+
const reverseOpPattern = new RegExp(String.raw `\d\s*[+\-*/<>]=?\s*process\.env\.${envVarName}`);
|
|
104
|
+
const portPattern = `port`;
|
|
105
|
+
const timeoutPattern = `timeout`;
|
|
106
|
+
const envAccess = `process.env.${envVarName}`;
|
|
107
|
+
if (numericOpPattern.test(context) || reverseOpPattern.test(context)) {
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
// Check for port/timeout without parseInt
|
|
111
|
+
if ((context.toLowerCase().includes(portPattern) ||
|
|
112
|
+
context.toLowerCase().includes(timeoutPattern)) &&
|
|
113
|
+
context.includes(envAccess) &&
|
|
114
|
+
!context.includes('parseInt')) {
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
function analyzeMatch(line, match, window) {
|
|
120
|
+
const envVarName = match[1];
|
|
121
|
+
if (!envVarName) {
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
const matchIndex = match.index ?? 0;
|
|
125
|
+
const context = getMatchContext(line, matchIndex, match[0].length);
|
|
126
|
+
return { envVarName, context, window, matchIndex };
|
|
127
|
+
}
|
|
128
|
+
/* v8 ignore start -- switch over issue types; only some cases fire in test fixtures */
|
|
129
|
+
function createIssue(filePath, lineNumber, type, envVarName) {
|
|
130
|
+
switch (type) {
|
|
131
|
+
case 'direct-access-outside-config': {
|
|
132
|
+
return {
|
|
133
|
+
file: filePath,
|
|
134
|
+
line: lineNumber,
|
|
135
|
+
type,
|
|
136
|
+
message: `Direct process.env.${envVarName} access outside config module`,
|
|
137
|
+
suggestion: 'Access environment variables through config module instead',
|
|
138
|
+
severity: 'warning',
|
|
139
|
+
envVarName,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
case 'type-coercion': {
|
|
143
|
+
return {
|
|
144
|
+
file: filePath,
|
|
145
|
+
line: lineNumber,
|
|
146
|
+
type,
|
|
147
|
+
message: `process.env.${envVarName} used without type conversion`,
|
|
148
|
+
suggestion: 'Parse env var: parseInt(process.env.X, 10) or Boolean(process.env.X)',
|
|
149
|
+
severity: 'warning',
|
|
150
|
+
envVarName,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
case 'unvalidated-access': {
|
|
154
|
+
return {
|
|
155
|
+
file: filePath,
|
|
156
|
+
line: lineNumber,
|
|
157
|
+
type,
|
|
158
|
+
message: `process.env.${envVarName} accessed without null check`,
|
|
159
|
+
suggestion: 'Add default: process.env.X ?? "default" or validate with requireEnv()',
|
|
160
|
+
severity: 'warning',
|
|
161
|
+
envVarName,
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
default: {
|
|
165
|
+
return {
|
|
166
|
+
file: filePath,
|
|
167
|
+
line: lineNumber,
|
|
168
|
+
type,
|
|
169
|
+
message: `Issue with process.env.${envVarName}`,
|
|
170
|
+
suggestion: 'Validate environment variable access',
|
|
171
|
+
severity: 'warning',
|
|
172
|
+
envVarName,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
/* v8 ignore stop */
|
|
178
|
+
function analyzeMatchForIssues(analysis, filePath, lineNumber, isConfigFile) {
|
|
179
|
+
const { envVarName, context, window } = analysis;
|
|
180
|
+
// Skip if in safe context (idiomatic guards may sit on a following line, so
|
|
181
|
+
// the safe-context test uses the multi-line window, not just the access line).
|
|
182
|
+
if (isSafeContext(window)) {
|
|
183
|
+
return null;
|
|
184
|
+
}
|
|
185
|
+
// Check for direct access outside config
|
|
186
|
+
if (!isConfigFile) {
|
|
187
|
+
return createIssue(filePath, lineNumber, 'direct-access-outside-config', envVarName);
|
|
188
|
+
}
|
|
189
|
+
// Check for type coercion issues
|
|
190
|
+
if (hasTypeCoercionIssue(context, envVarName)) {
|
|
191
|
+
return createIssue(filePath, lineNumber, 'type-coercion', envVarName);
|
|
192
|
+
}
|
|
193
|
+
// Check for missing null check
|
|
194
|
+
if (!hasNullCheck(window)) {
|
|
195
|
+
return createIssue(filePath, lineNumber, 'unvalidated-access', envVarName);
|
|
196
|
+
}
|
|
197
|
+
return null;
|
|
198
|
+
}
|
|
199
|
+
// How many following lines to include in the guard-detection window.
|
|
200
|
+
const GUARD_WINDOW_LINES = 2;
|
|
201
|
+
function processLine(lines, lineIndex, filePath, isConfigFile) {
|
|
202
|
+
const line = lines[lineIndex] ?? '';
|
|
203
|
+
const issues = [];
|
|
204
|
+
// Guard idioms (`if (!x) return`) may sit just below the access; include a
|
|
205
|
+
// small forward window so capture-then-guard reads are recognised as safe.
|
|
206
|
+
const window = lines.slice(lineIndex, lineIndex + 1 + GUARD_WINDOW_LINES).join('\n');
|
|
207
|
+
// Reset regex lastIndex for global patterns
|
|
208
|
+
ENV_VAR_PATTERN.lastIndex = 0;
|
|
209
|
+
const matches = line.matchAll(ENV_VAR_PATTERN);
|
|
210
|
+
for (const match of matches) {
|
|
211
|
+
const analysis = analyzeMatch(line, match, window);
|
|
212
|
+
if (!analysis) {
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
215
|
+
const issue = analyzeMatchForIssues(analysis, filePath, lineIndex + 1, isConfigFile);
|
|
216
|
+
if (issue) {
|
|
217
|
+
issues.push(issue);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return issues;
|
|
221
|
+
}
|
|
222
|
+
function analyzeFile(filePath, content) {
|
|
223
|
+
if (isExcludedEnvPath(filePath)) {
|
|
224
|
+
return [];
|
|
225
|
+
}
|
|
226
|
+
const lines = content.split('\n');
|
|
227
|
+
const isConfigFile = filePath.includes('config');
|
|
228
|
+
const issues = [];
|
|
229
|
+
for (let i = 0; i < lines.length; i++) {
|
|
230
|
+
if (!lines[i]) {
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
issues.push(...processLine(lines, i, filePath, isConfigFile));
|
|
234
|
+
}
|
|
235
|
+
return issues;
|
|
236
|
+
}
|
|
237
|
+
// =============================================================================
|
|
238
|
+
// CHECK DEFINITION
|
|
239
|
+
// =============================================================================
|
|
240
|
+
/**
|
|
241
|
+
* Check: architecture/env-var-validation
|
|
242
|
+
*
|
|
243
|
+
* Detects environment variable access without validation:
|
|
244
|
+
* - process.env.X without null check
|
|
245
|
+
* - Missing default values
|
|
246
|
+
* - Type coercion issues
|
|
247
|
+
* - Direct access outside config modules
|
|
248
|
+
*/
|
|
249
|
+
export const envVarValidation = defineCheck({
|
|
250
|
+
id: '47d3e7c7-7dc0-4fd7-bcd6-950837e091df',
|
|
251
|
+
slug: 'env-var-validation',
|
|
252
|
+
scope: { languages: ['typescript'], concerns: ['backend', 'server'] },
|
|
253
|
+
// Strip strings/comments so `process.env.X` appearing inside a string literal,
|
|
254
|
+
// template literal, or comment (e.g. a detection pattern or doc example in
|
|
255
|
+
// analyzer source) is not mistaken for a real env access — only live code is
|
|
256
|
+
// scanned. Real `process.env.X` member access is code and is preserved.
|
|
257
|
+
contentFilter: 'strip-strings-and-comments',
|
|
258
|
+
confidence: 'medium',
|
|
259
|
+
description: 'Detects environment variable access without proper validation',
|
|
260
|
+
longDescription: `**Purpose:** Enforces safe environment variable access by detecting unvalidated \`process.env\` usage outside config modules.
|
|
261
|
+
|
|
262
|
+
**Detects:**
|
|
263
|
+
- \`process.env.X\` access without null check (\`??\`, \`||\`, or \`?\`)
|
|
264
|
+
- \`process.env.X\` used in numeric operations without \`parseInt()\` (type coercion)
|
|
265
|
+
- Direct \`process.env.X\` access outside config modules (should use \`getEnv()\`, \`requireEnv()\`, or config objects)
|
|
266
|
+
- Recognizes safe patterns: \`??\`, \`||\`, \`getEnv()\`, \`requireEnv()\`, \`optionalEnv()\`, \`config.*\`
|
|
267
|
+
|
|
268
|
+
**Why it matters:** Unvalidated env var access causes silent \`undefined\` values and type coercion bugs that surface only at runtime.
|
|
269
|
+
|
|
270
|
+
**Scope:** General best practice. Analyzes each file individually.`,
|
|
271
|
+
tags: ['architecture', 'best-practices'],
|
|
272
|
+
fileTypes: ['ts'],
|
|
273
|
+
analyze(content, filePath) {
|
|
274
|
+
// Skip files without process.env
|
|
275
|
+
if (!content.includes('process.env')) {
|
|
276
|
+
return [];
|
|
277
|
+
}
|
|
278
|
+
const issues = analyzeFile(filePath, content);
|
|
279
|
+
return issues.map((issue) => ({
|
|
280
|
+
line: issue.line,
|
|
281
|
+
message: `${issue.message}. ${issue.suggestion}`,
|
|
282
|
+
severity: issue.severity,
|
|
283
|
+
suggestion: issue.suggestion,
|
|
284
|
+
match: `process.env.${issue.envVarName ?? ''}`,
|
|
285
|
+
type: issue.type,
|
|
286
|
+
}));
|
|
287
|
+
},
|
|
288
|
+
});
|
|
289
|
+
//# sourceMappingURL=env-var-validation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env-var-validation.js","sourceRoot":"","sources":["../../../src/checks/architecture/env-var-validation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Heavy import detection
|
|
3
|
+
* @module checks-builtin/checks/architecture/heavy-import-detection
|
|
4
|
+
*
|
|
5
|
+
* Detects imports that unnecessarily bloat bundle size:
|
|
6
|
+
* - Full/namespace imports of tree-shakeable libraries (import * as _ from 'lodash')
|
|
7
|
+
* - Deprecated library usage (moment -> date-fns/dayjs, aws-sdk v2 -> v3)
|
|
8
|
+
* - Excessive named imports from a single module (>15 items)
|
|
9
|
+
*/
|
|
10
|
+
export declare const heavyImportDetection: import("@opensip-cli/fitness").Check;
|
|
11
|
+
//# sourceMappingURL=heavy-import-detection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"heavy-import-detection.d.ts","sourceRoot":"","sources":["../../../src/checks/architecture/heavy-import-detection.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAyCH,eAAO,MAAM,oBAAoB,sCA2D/B,CAAC"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Heavy import detection
|
|
3
|
+
* @module checks-builtin/checks/architecture/heavy-import-detection
|
|
4
|
+
*
|
|
5
|
+
* Detects imports that unnecessarily bloat bundle size:
|
|
6
|
+
* - Full/namespace imports of tree-shakeable libraries (import * as _ from 'lodash')
|
|
7
|
+
* - Deprecated library usage (moment -> date-fns/dayjs, aws-sdk v2 -> v3)
|
|
8
|
+
* - Excessive named imports from a single module (>15 items)
|
|
9
|
+
*/
|
|
10
|
+
import { defineCheck } from '@opensip-cli/fitness';
|
|
11
|
+
const HEAVY_LIBRARIES = [
|
|
12
|
+
{
|
|
13
|
+
pattern: /import\s+\*\s+as\s+\w+\s+from\s+['"]lodash['"]/,
|
|
14
|
+
message: 'Namespace import of lodash pulls in the entire library (~70KB)',
|
|
15
|
+
suggestion: "Use named imports: import { debounce } from 'lodash' or import debounce from 'lodash/debounce'",
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
pattern: /import\s+(?:\w+|\{[^}]+\})\s+from\s+['"]moment['"]/,
|
|
19
|
+
message: 'moment.js is deprecated and heavy (~300KB). Use date-fns or dayjs instead',
|
|
20
|
+
suggestion: "Replace with: import { format } from 'date-fns' or import dayjs from 'dayjs'",
|
|
21
|
+
deprecated: true,
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
pattern: /import\s+(?:\w+|\{[^}]+\})\s+from\s+['"]aws-sdk['"]/,
|
|
25
|
+
message: 'aws-sdk v2 is deprecated and heavy. Use modular v3 packages',
|
|
26
|
+
suggestion: "Replace with modular import: import { S3Client } from '@aws-sdk/client-s3'",
|
|
27
|
+
deprecated: true,
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
pattern: /import\s+\*\s+as\s+\w+\s+from\s+['"]rxjs['"]/,
|
|
31
|
+
message: 'Namespace import of rxjs pulls in the entire library. Use specific imports',
|
|
32
|
+
suggestion: "Use: import { Observable, map } from 'rxjs' or import { map } from 'rxjs/operators'",
|
|
33
|
+
},
|
|
34
|
+
];
|
|
35
|
+
const EXCESSIVE_NAMED_IMPORT_THRESHOLD = 15;
|
|
36
|
+
const NAMED_IMPORT_PATTERN = /import\s+\{([^}]+)\}\s+from\s+['"]([^'"]+)['"]/;
|
|
37
|
+
export const heavyImportDetection = defineCheck({
|
|
38
|
+
id: 'ebd495d1-ae48-478d-a1cc-4823a18cada6',
|
|
39
|
+
slug: 'heavy-import-detection',
|
|
40
|
+
scope: { languages: ['typescript', 'javascript'], concerns: ['backend', 'frontend'] },
|
|
41
|
+
confidence: 'high',
|
|
42
|
+
description: 'Detects heavy/deprecated library imports and excessive named imports that bloat bundle size',
|
|
43
|
+
tags: ['architecture', 'performance', 'bundle-size'],
|
|
44
|
+
fileTypes: ['ts', 'tsx', 'js', 'jsx'],
|
|
45
|
+
// eslint-disable-next-line sonarjs/cognitive-complexity -- bundler-aware heuristic: each branch detects a distinct heavy-import pattern (deprecated, namespace, deep-path, named-import-explosion)
|
|
46
|
+
analyze(content, filePath) {
|
|
47
|
+
if (filePath.includes('.test.') || filePath.includes('__tests__'))
|
|
48
|
+
return [];
|
|
49
|
+
const violations = [];
|
|
50
|
+
const lines = content.split('\n');
|
|
51
|
+
for (const [i, line] of lines.entries()) {
|
|
52
|
+
if (!line)
|
|
53
|
+
continue;
|
|
54
|
+
const trimmed = line.trim();
|
|
55
|
+
if (trimmed.startsWith('//') || trimmed.startsWith('*'))
|
|
56
|
+
continue;
|
|
57
|
+
// Check heavy library patterns
|
|
58
|
+
for (const lib of HEAVY_LIBRARIES) {
|
|
59
|
+
if (lib.pattern.test(line)) {
|
|
60
|
+
violations.push({
|
|
61
|
+
line: i + 1,
|
|
62
|
+
message: lib.message,
|
|
63
|
+
severity: lib.deprecated ? 'error' : 'warning',
|
|
64
|
+
suggestion: lib.suggestion,
|
|
65
|
+
type: lib.deprecated ? 'DEPRECATED_LIBRARY' : 'HEAVY_IMPORT',
|
|
66
|
+
match: trimmed,
|
|
67
|
+
filePath,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
// Check excessive named imports
|
|
72
|
+
const namedMatch = NAMED_IMPORT_PATTERN.exec(line);
|
|
73
|
+
if (namedMatch?.[1]) {
|
|
74
|
+
const names = namedMatch[1].split(',').filter((n) => n.trim().length > 0);
|
|
75
|
+
if (names.length > EXCESSIVE_NAMED_IMPORT_THRESHOLD) {
|
|
76
|
+
violations.push({
|
|
77
|
+
line: i + 1,
|
|
78
|
+
message: `Excessive named imports: ${names.length} items from '${namedMatch[2]}'. Consider splitting into multiple import groups.`,
|
|
79
|
+
severity: 'warning',
|
|
80
|
+
suggestion: 'Split into multiple focused imports or evaluate if all imports are needed.',
|
|
81
|
+
type: 'EXCESSIVE_NAMED_IMPORTS',
|
|
82
|
+
match: `${names.length} imports from ${namedMatch[2]}`,
|
|
83
|
+
filePath,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return violations;
|
|
89
|
+
},
|
|
90
|
+
});
|
|
91
|
+
//# sourceMappingURL=heavy-import-detection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"heavy-import-detection.js","sourceRoot":"","sources":["../../../src/checks/architecture/heavy-import-detection.ts"],"names":[],"mappings":"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"}
|