@complior/engine 0.9.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/.well-known/ai-compliance.json +16 -0
- package/COMPLIANCE.md +64 -0
- package/data/data-integrity.test.ts +75 -0
- package/data/eval/eval-mappings.json +33 -0
- package/data/llm/model-pricing.json +15 -0
- package/data/llm/model-routing.json +36 -0
- package/data/onboarding/risk-profile.json +17 -0
- package/data/regulations/eu-ai-act/README.md +245 -0
- package/data/regulations/eu-ai-act/applicability-tree.json +160 -0
- package/data/regulations/eu-ai-act/cross-mapping.json +175 -0
- package/data/regulations/eu-ai-act/localization.json +186 -0
- package/data/regulations/eu-ai-act/obligations.json +3981 -0
- package/data/regulations/eu-ai-act/regulation-meta.json +482 -0
- package/data/regulations/eu-ai-act/scoring.json +342 -0
- package/data/regulations/eu-ai-act/technical-requirements.json +2590 -0
- package/data/regulations/eu-ai-act/timeline.json +160 -0
- package/data/regulations/jurisdictions/at.json +15 -0
- package/data/regulations/jurisdictions/be.json +15 -0
- package/data/regulations/jurisdictions/bg.json +15 -0
- package/data/regulations/jurisdictions/cy.json +15 -0
- package/data/regulations/jurisdictions/cz.json +15 -0
- package/data/regulations/jurisdictions/de.json +15 -0
- package/data/regulations/jurisdictions/dk.json +15 -0
- package/data/regulations/jurisdictions/ee.json +15 -0
- package/data/regulations/jurisdictions/es.json +15 -0
- package/data/regulations/jurisdictions/fi.json +15 -0
- package/data/regulations/jurisdictions/fr.json +15 -0
- package/data/regulations/jurisdictions/gr.json +15 -0
- package/data/regulations/jurisdictions/hr.json +15 -0
- package/data/regulations/jurisdictions/hu.json +15 -0
- package/data/regulations/jurisdictions/ie.json +15 -0
- package/data/regulations/jurisdictions/is.json +15 -0
- package/data/regulations/jurisdictions/it.json +15 -0
- package/data/regulations/jurisdictions/li.json +15 -0
- package/data/regulations/jurisdictions/lt.json +15 -0
- package/data/regulations/jurisdictions/lu.json +15 -0
- package/data/regulations/jurisdictions/lv.json +15 -0
- package/data/regulations/jurisdictions/mt.json +15 -0
- package/data/regulations/jurisdictions/nl.json +15 -0
- package/data/regulations/jurisdictions/no.json +15 -0
- package/data/regulations/jurisdictions/pl.json +15 -0
- package/data/regulations/jurisdictions/pt.json +15 -0
- package/data/regulations/jurisdictions/ro.json +15 -0
- package/data/regulations/jurisdictions/se.json +15 -0
- package/data/regulations/jurisdictions/si.json +15 -0
- package/data/regulations/jurisdictions/sk.json +15 -0
- package/data/scanner/check-id-categories.json +81 -0
- package/data/scanner/confidence-params.json +16 -0
- package/data/scanner/limits.json +4 -0
- package/data/schemas/http-contract-sample.json +79 -0
- package/data/schemas/http-contract.json +144 -0
- package/data/semgrep-rules/bare-call.yaml +37 -0
- package/data/semgrep-rules/injection.yaml +73 -0
- package/data/semgrep-rules/missing-error-handling.yaml +58 -0
- package/data/semgrep-rules/unsafe-deser.yaml +65 -0
- package/data/templates/eu-ai-act/ai-literacy.md +184 -0
- package/data/templates/eu-ai-act/art5-screening.md +131 -0
- package/data/templates/eu-ai-act/data-governance.md +145 -0
- package/data/templates/eu-ai-act/declaration-of-conformity.md +161 -0
- package/data/templates/eu-ai-act/fria.md +127 -0
- package/data/templates/eu-ai-act/gpai-systemic-risk.md +150 -0
- package/data/templates/eu-ai-act/gpai-transparency.md +166 -0
- package/data/templates/eu-ai-act/incident-report.md +188 -0
- package/data/templates/eu-ai-act/instructions-for-use.md +202 -0
- package/data/templates/eu-ai-act/monitoring-policy.md +110 -0
- package/data/templates/eu-ai-act/qms.md +180 -0
- package/data/templates/eu-ai-act/risk-management-system.md +123 -0
- package/data/templates/eu-ai-act/technical-documentation.md +287 -0
- package/data/templates/eu-ai-act/worker-notification.md +143 -0
- package/data/templates/policies/biometrics-ai-policy.md +214 -0
- package/data/templates/policies/critical-infra-ai-policy.md +228 -0
- package/data/templates/policies/education-ai-policy.md +184 -0
- package/data/templates/policies/finance-ai-policy.md +191 -0
- package/data/templates/policies/healthcare-ai-policy.md +197 -0
- package/data/templates/policies/hr-ai-policy.md +178 -0
- package/data/templates/policies/legal-ai-policy.md +189 -0
- package/data/templates/policies/migration-ai-policy.md +239 -0
- package/engine.log +7 -0
- package/package.json +74 -0
- package/src/composition-root.ts +791 -0
- package/src/data/eval/conformity-tests.test.ts +122 -0
- package/src/data/eval/ct-1-transparency.ts +106 -0
- package/src/data/eval/ct-10-gpai.ts +25 -0
- package/src/data/eval/ct-11-industry.ts +42 -0
- package/src/data/eval/ct-2-oversight.ts +41 -0
- package/src/data/eval/ct-3-explanation.ts +14 -0
- package/src/data/eval/ct-4-bias.ts +83 -0
- package/src/data/eval/ct-5-accuracy.ts +41 -0
- package/src/data/eval/ct-6-robustness.ts +81 -0
- package/src/data/eval/ct-7-prohibited.ts +52 -0
- package/src/data/eval/ct-8-logging.ts +68 -0
- package/src/data/eval/ct-9-risk-awareness.ts +33 -0
- package/src/data/eval/deterministic-evaluator.ts +120 -0
- package/src/data/eval/index.ts +55 -0
- package/src/data/eval/judge-prompts.ts +146 -0
- package/src/data/eval/llm-judged-tests.ts +279 -0
- package/src/data/eval/llm-tests.test.ts +83 -0
- package/src/data/eval/remediation/ct-1-transparency.ts +91 -0
- package/src/data/eval/remediation/ct-10-gpai.ts +94 -0
- package/src/data/eval/remediation/ct-11-industry.ts +94 -0
- package/src/data/eval/remediation/ct-2-oversight.ts +71 -0
- package/src/data/eval/remediation/ct-3-explanation.ts +70 -0
- package/src/data/eval/remediation/ct-4-bias.ts +70 -0
- package/src/data/eval/remediation/ct-5-accuracy.ts +70 -0
- package/src/data/eval/remediation/ct-6-robustness.ts +70 -0
- package/src/data/eval/remediation/ct-7-prohibited.ts +94 -0
- package/src/data/eval/remediation/ct-8-logging.ts +94 -0
- package/src/data/eval/remediation/ct-9-risk-awareness.ts +94 -0
- package/src/data/eval/remediation/index.ts +89 -0
- package/src/data/eval/remediation/owasp-art5.ts +15 -0
- package/src/data/eval/remediation/owasp-llm01.ts +72 -0
- package/src/data/eval/remediation/owasp-llm02.ts +72 -0
- package/src/data/eval/remediation/owasp-llm03.ts +15 -0
- package/src/data/eval/remediation/owasp-llm04.ts +15 -0
- package/src/data/eval/remediation/owasp-llm05.ts +15 -0
- package/src/data/eval/remediation/owasp-llm06.ts +15 -0
- package/src/data/eval/remediation/owasp-llm07.ts +15 -0
- package/src/data/eval/remediation/owasp-llm08.ts +15 -0
- package/src/data/eval/remediation/owasp-llm09.ts +15 -0
- package/src/data/eval/remediation/owasp-llm10.ts +15 -0
- package/src/data/eval/remediation/remediation.test.ts +229 -0
- package/src/data/eval/remediation/test-mapping.ts +290 -0
- package/src/data/eval/security-rubrics.ts +381 -0
- package/src/data/finding-explanations.json +453 -0
- package/src/data/industry-patterns.ts +161 -0
- package/src/data/registry-cards.ts +368 -0
- package/src/data/regulation/index.ts +5 -0
- package/src/data/regulation/jurisdiction-data.test.ts +73 -0
- package/src/data/regulation/jurisdiction-data.ts +65 -0
- package/src/data/regulation/regulation-data.ts +19 -0
- package/src/data/regulation/regulation-loader.test.ts +107 -0
- package/src/data/regulation/regulation-loader.ts +56 -0
- package/src/data/scanner-constants.ts +46 -0
- package/src/data/schemas/schemas-core.ts +140 -0
- package/src/data/schemas/schemas-supplementary.ts +211 -0
- package/src/data/schemas/schemas.ts +28 -0
- package/src/data/security/attack-probes.test.ts +62 -0
- package/src/data/security/attack-probes.ts +496 -0
- package/src/data/security/eu-ai-act-security.ts +40 -0
- package/src/data/security/index.ts +19 -0
- package/src/data/security/mitre-atlas.test.ts +43 -0
- package/src/data/security/mitre-atlas.ts +93 -0
- package/src/data/security/nist-ai-rmf.ts +43 -0
- package/src/data/security/owasp-llm-top10.test.ts +60 -0
- package/src/data/security/owasp-llm-top10.ts +138 -0
- package/src/data/template-registry.ts +53 -0
- package/src/data/tool-versions.json +22 -0
- package/src/domain/audit/audit-package.test.ts +152 -0
- package/src/domain/audit/audit-package.ts +166 -0
- package/src/domain/audit/audit-trail.test.ts +121 -0
- package/src/domain/audit/audit-trail.ts +174 -0
- package/src/domain/audit/index.ts +8 -0
- package/src/domain/audit/permissions-matrix.test.ts +136 -0
- package/src/domain/audit/permissions-matrix.ts +121 -0
- package/src/domain/certification/adversarial/bias-tests.ts +95 -0
- package/src/domain/certification/adversarial/evaluators.ts +304 -0
- package/src/domain/certification/adversarial/index.ts +11 -0
- package/src/domain/certification/adversarial/prompt-injection.ts +103 -0
- package/src/domain/certification/adversarial/safety-boundary.ts +132 -0
- package/src/domain/certification/aiuc1-readiness.test.ts +236 -0
- package/src/domain/certification/aiuc1-readiness.ts +298 -0
- package/src/domain/certification/aiuc1-requirements.ts +235 -0
- package/src/domain/certification/index.ts +10 -0
- package/src/domain/certification/redteam-runner.test.ts +97 -0
- package/src/domain/certification/redteam-runner.ts +205 -0
- package/src/domain/certification/test-runner.test.ts +232 -0
- package/src/domain/certification/test-runner.ts +289 -0
- package/src/domain/cost/cost-estimator.test.ts +187 -0
- package/src/domain/cost/cost-estimator.ts +133 -0
- package/src/domain/disclaimer.test.ts +52 -0
- package/src/domain/disclaimer.ts +39 -0
- package/src/domain/documents/ai-enricher.test.ts +120 -0
- package/src/domain/documents/ai-enricher.ts +159 -0
- package/src/domain/documents/document-generator.test.ts +318 -0
- package/src/domain/documents/document-generator.ts +239 -0
- package/src/domain/documents/index.ts +9 -0
- package/src/domain/documents/passport-helpers.ts +25 -0
- package/src/domain/documents/policy-generator.test.ts +252 -0
- package/src/domain/documents/policy-generator.ts +94 -0
- package/src/domain/documents/worker-notification-generator.test.ts +162 -0
- package/src/domain/documents/worker-notification-generator.ts +141 -0
- package/src/domain/eval/adapters/adapter-port.ts +94 -0
- package/src/domain/eval/adapters/adapters.test.ts +303 -0
- package/src/domain/eval/adapters/anthropic-adapter.ts +57 -0
- package/src/domain/eval/adapters/auto-detect.ts +104 -0
- package/src/domain/eval/adapters/create-chat-adapter.ts +106 -0
- package/src/domain/eval/adapters/custom-adapter.ts +74 -0
- package/src/domain/eval/adapters/http-adapter.ts +66 -0
- package/src/domain/eval/adapters/index.ts +7 -0
- package/src/domain/eval/adapters/ollama-adapter.ts +48 -0
- package/src/domain/eval/adapters/openai-adapter.ts +58 -0
- package/src/domain/eval/adapters/with-timeout.ts +25 -0
- package/src/domain/eval/conformity-score.test.ts +161 -0
- package/src/domain/eval/conformity-score.ts +135 -0
- package/src/domain/eval/eval-constants.ts +55 -0
- package/src/domain/eval/eval-evidence.test.ts +85 -0
- package/src/domain/eval/eval-evidence.ts +103 -0
- package/src/domain/eval/eval-fix-generator.test.ts +421 -0
- package/src/domain/eval/eval-fix-generator.ts +205 -0
- package/src/domain/eval/eval-passport.test.ts +82 -0
- package/src/domain/eval/eval-passport.ts +89 -0
- package/src/domain/eval/eval-remediation-report.test.ts +682 -0
- package/src/domain/eval/eval-remediation-report.ts +170 -0
- package/src/domain/eval/eval-report.ts +108 -0
- package/src/domain/eval/eval-runner.test.ts +609 -0
- package/src/domain/eval/eval-runner.ts +593 -0
- package/src/domain/eval/eval-to-findings.test.ts +293 -0
- package/src/domain/eval/eval-to-findings.ts +83 -0
- package/src/domain/eval/index.ts +31 -0
- package/src/domain/eval/llm-judge.test.ts +139 -0
- package/src/domain/eval/llm-judge.ts +168 -0
- package/src/domain/eval/remediation-types.ts +90 -0
- package/src/domain/eval/security-integration.test.ts +196 -0
- package/src/domain/eval/security-integration.ts +136 -0
- package/src/domain/eval/types.test.ts +173 -0
- package/src/domain/eval/types.ts +244 -0
- package/src/domain/eval/verdict-utils.ts +45 -0
- package/src/domain/fixer/create-fixer.ts +101 -0
- package/src/domain/fixer/diff.ts +70 -0
- package/src/domain/fixer/fix-history.ts +23 -0
- package/src/domain/fixer/fixer.test.ts +306 -0
- package/src/domain/fixer/index.ts +9 -0
- package/src/domain/fixer/strategies/bandit-fix.ts +61 -0
- package/src/domain/fixer/strategies/bias-testing.ts +49 -0
- package/src/domain/fixer/strategies/ci-compliance.ts +57 -0
- package/src/domain/fixer/strategies/content-marking.ts +45 -0
- package/src/domain/fixer/strategies/cve-upgrade.ts +66 -0
- package/src/domain/fixer/strategies/data-governance.ts +65 -0
- package/src/domain/fixer/strategies/disclosure.ts +69 -0
- package/src/domain/fixer/strategies/doc-code-sync.ts +53 -0
- package/src/domain/fixer/strategies/documentation.ts +59 -0
- package/src/domain/fixer/strategies/error-handler.ts +63 -0
- package/src/domain/fixer/strategies/hitl-gate.ts +67 -0
- package/src/domain/fixer/strategies/index.ts +61 -0
- package/src/domain/fixer/strategies/kill-switch-test.ts +85 -0
- package/src/domain/fixer/strategies/kill-switch.ts +53 -0
- package/src/domain/fixer/strategies/license-fix.ts +57 -0
- package/src/domain/fixer/strategies/log-retention.ts +40 -0
- package/src/domain/fixer/strategies/logging.ts +59 -0
- package/src/domain/fixer/strategies/metadata.ts +45 -0
- package/src/domain/fixer/strategies/permission-guard.ts +84 -0
- package/src/domain/fixer/strategies/record-keeping.ts +69 -0
- package/src/domain/fixer/strategies/secret-rotation.ts +52 -0
- package/src/domain/fixer/strategies.test.ts +341 -0
- package/src/domain/fixer/template-engine.test.ts +64 -0
- package/src/domain/fixer/template-engine.ts +38 -0
- package/src/domain/fixer/types.ts +88 -0
- package/src/domain/frameworks/aiuc1-framework.test.ts +159 -0
- package/src/domain/frameworks/aiuc1-framework.ts +126 -0
- package/src/domain/frameworks/collect-foundation-metrics.test.ts +96 -0
- package/src/domain/frameworks/collect-foundation-metrics.ts +34 -0
- package/src/domain/frameworks/eu-ai-act-framework.test.ts +117 -0
- package/src/domain/frameworks/eu-ai-act-framework.ts +100 -0
- package/src/domain/frameworks/framework-registry.test.ts +91 -0
- package/src/domain/frameworks/framework-registry.ts +38 -0
- package/src/domain/frameworks/index.ts +8 -0
- package/src/domain/frameworks/mitre-atlas-framework.test.ts +53 -0
- package/src/domain/frameworks/mitre-atlas-framework.ts +53 -0
- package/src/domain/frameworks/owasp-llm-framework.test.ts +77 -0
- package/src/domain/frameworks/owasp-llm-framework.ts +54 -0
- package/src/domain/frameworks/score-plugin-framework.ts +117 -0
- package/src/domain/fria/fria-generator.test.ts +273 -0
- package/src/domain/fria/fria-generator.ts +366 -0
- package/src/domain/import/promptfoo-importer.test.ts +103 -0
- package/src/domain/import/promptfoo-importer.ts +151 -0
- package/src/domain/onboarding/guided-onboarding.test.ts +144 -0
- package/src/domain/onboarding/guided-onboarding.ts +135 -0
- package/src/domain/passport/builder/domain-mapper.ts +9 -0
- package/src/domain/passport/builder/manifest-builder.test.ts +546 -0
- package/src/domain/passport/builder/manifest-builder.ts +535 -0
- package/src/domain/passport/builder/manifest-diff.test.ts +105 -0
- package/src/domain/passport/builder/manifest-diff.ts +89 -0
- package/src/domain/passport/builder/manifest-files.ts +17 -0
- package/src/domain/passport/crypto-signer.test.ts +93 -0
- package/src/domain/passport/crypto-signer.ts +157 -0
- package/src/domain/passport/discovery/agent-discovery.test.ts +296 -0
- package/src/domain/passport/discovery/agent-discovery.ts +325 -0
- package/src/domain/passport/discovery/autonomy-analyzer.test.ts +141 -0
- package/src/domain/passport/discovery/autonomy-analyzer.ts +113 -0
- package/src/domain/passport/discovery/permission-scanner.test.ts +191 -0
- package/src/domain/passport/discovery/permission-scanner.ts +414 -0
- package/src/domain/passport/export/a2a-mapper.ts +75 -0
- package/src/domain/passport/export/aiuc1-mapper.ts +126 -0
- package/src/domain/passport/export/export.test.ts +207 -0
- package/src/domain/passport/export/index.ts +41 -0
- package/src/domain/passport/export/nist-mapper.ts +227 -0
- package/src/domain/passport/import/a2a-importer.test.ts +133 -0
- package/src/domain/passport/import/a2a-importer.ts +156 -0
- package/src/domain/passport/import/index.ts +2 -0
- package/src/domain/passport/index.ts +32 -0
- package/src/domain/passport/obligation-field-map.test.ts +113 -0
- package/src/domain/passport/obligation-field-map.ts +117 -0
- package/src/domain/passport/passport-validator.test.ts +156 -0
- package/src/domain/passport/passport-validator.ts +126 -0
- package/src/domain/passport/scan-to-compliance.test.ts +336 -0
- package/src/domain/passport/scan-to-compliance.ts +166 -0
- package/src/domain/passport/test-generator.test.ts +93 -0
- package/src/domain/passport/test-generator.ts +136 -0
- package/src/domain/proxy/index.ts +11 -0
- package/src/domain/proxy/json-rpc.test.ts +72 -0
- package/src/domain/proxy/json-rpc.ts +53 -0
- package/src/domain/proxy/policy-engine.test.ts +259 -0
- package/src/domain/proxy/policy-engine.ts +137 -0
- package/src/domain/proxy/proxy-bridge.ts +125 -0
- package/src/domain/proxy/proxy-interceptor.test.ts +184 -0
- package/src/domain/proxy/proxy-interceptor.ts +120 -0
- package/src/domain/proxy/proxy-types.ts +35 -0
- package/src/domain/registry/compute-agent-score.test.ts +279 -0
- package/src/domain/registry/compute-agent-score.ts +162 -0
- package/src/domain/reporter/audit-report.test.ts +87 -0
- package/src/domain/reporter/audit-report.ts +116 -0
- package/src/domain/reporter/badge-generator.test.ts +54 -0
- package/src/domain/reporter/badge-generator.ts +40 -0
- package/src/domain/reporter/compliance-md.ts +45 -0
- package/src/domain/reporter/index.ts +7 -0
- package/src/domain/reporter/pdf-renderer.ts +282 -0
- package/src/domain/reporter/share.test.ts +92 -0
- package/src/domain/reporter/share.ts +80 -0
- package/src/domain/scanner/ast/swc-analyzer.test.ts +49 -0
- package/src/domain/scanner/ast/swc-analyzer.ts +124 -0
- package/src/domain/scanner/attestations.ts +97 -0
- package/src/domain/scanner/checks/ai-disclosure.test.ts +90 -0
- package/src/domain/scanner/checks/ai-disclosure.ts +54 -0
- package/src/domain/scanner/checks/ai-literacy.ts +163 -0
- package/src/domain/scanner/checks/behavioral-constraints.test.ts +167 -0
- package/src/domain/scanner/checks/behavioral-constraints.ts +86 -0
- package/src/domain/scanner/checks/compliance-metadata.ts +63 -0
- package/src/domain/scanner/checks/content-marking.ts +74 -0
- package/src/domain/scanner/checks/dep-deep-scan.test.ts +318 -0
- package/src/domain/scanner/checks/dep-deep-scan.ts +137 -0
- package/src/domain/scanner/checks/documentation.test.ts +88 -0
- package/src/domain/scanner/checks/documentation.ts +79 -0
- package/src/domain/scanner/checks/git-history.test.ts +120 -0
- package/src/domain/scanner/checks/git-history.ts +163 -0
- package/src/domain/scanner/checks/gpai-systemic-risk.test.ts +84 -0
- package/src/domain/scanner/checks/gpai-systemic-risk.ts +98 -0
- package/src/domain/scanner/checks/gpai-transparency.ts +94 -0
- package/src/domain/scanner/checks/index.ts +28 -0
- package/src/domain/scanner/checks/industry/index.ts +40 -0
- package/src/domain/scanner/checks/industry/industry.test.ts +287 -0
- package/src/domain/scanner/checks/interaction-logging.test.ts +113 -0
- package/src/domain/scanner/checks/interaction-logging.ts +142 -0
- package/src/domain/scanner/checks/nhi-scanner.test.ts +158 -0
- package/src/domain/scanner/checks/nhi-scanner.ts +78 -0
- package/src/domain/scanner/checks/passport-completeness.test.ts +127 -0
- package/src/domain/scanner/checks/passport-completeness.ts +82 -0
- package/src/domain/scanner/checks/passport-presence.test.ts +56 -0
- package/src/domain/scanner/checks/passport-presence.ts +78 -0
- package/src/domain/scanner/checks/pattern-check-factory.ts +70 -0
- package/src/domain/scanner/checks/permission-scanner.test.ts +279 -0
- package/src/domain/scanner/checks/permission-scanner.ts +90 -0
- package/src/domain/scanner/checks/presence-check-factory.test.ts +124 -0
- package/src/domain/scanner/checks/presence-check-factory.ts +275 -0
- package/src/domain/scanner/compliance-diff.test.ts +165 -0
- package/src/domain/scanner/compliance-diff.ts +138 -0
- package/src/domain/scanner/confidence.test.ts +235 -0
- package/src/domain/scanner/confidence.ts +156 -0
- package/src/domain/scanner/constants.ts +13 -0
- package/src/domain/scanner/create-scanner.ts +573 -0
- package/src/domain/scanner/cross-layer.test.ts +372 -0
- package/src/domain/scanner/cross-layer.ts +232 -0
- package/src/domain/scanner/data/ai-packages.ts +82 -0
- package/src/domain/scanner/debt-calculator.test.ts +89 -0
- package/src/domain/scanner/debt-calculator.ts +111 -0
- package/src/domain/scanner/drift.test.ts +191 -0
- package/src/domain/scanner/drift.ts +73 -0
- package/src/domain/scanner/evidence-store.test.ts +207 -0
- package/src/domain/scanner/evidence-store.ts +195 -0
- package/src/domain/scanner/evidence.test.ts +104 -0
- package/src/domain/scanner/evidence.ts +71 -0
- package/src/domain/scanner/external/bandit-runner.test.ts +45 -0
- package/src/domain/scanner/external/bandit-runner.ts +90 -0
- package/src/domain/scanner/external/checks.ts +321 -0
- package/src/domain/scanner/external/dedup.test.ts +79 -0
- package/src/domain/scanner/external/dedup.ts +94 -0
- package/src/domain/scanner/external/detect-secrets-runner.test.ts +58 -0
- package/src/domain/scanner/external/detect-secrets-runner.ts +81 -0
- package/src/domain/scanner/external/external-scanner.test.ts +221 -0
- package/src/domain/scanner/external/external-scanner.ts +36 -0
- package/src/domain/scanner/external/finding-mapper.test.ts +95 -0
- package/src/domain/scanner/external/finding-mapper.ts +138 -0
- package/src/domain/scanner/external/index.ts +15 -0
- package/src/domain/scanner/external/mappings.ts +93 -0
- package/src/domain/scanner/external/modelscan-runner.test.ts +35 -0
- package/src/domain/scanner/external/modelscan-runner.ts +101 -0
- package/src/domain/scanner/external/path-utils.ts +8 -0
- package/src/domain/scanner/external/runner-port.ts +45 -0
- package/src/domain/scanner/external/semgrep-runner.test.ts +52 -0
- package/src/domain/scanner/external/semgrep-runner.ts +94 -0
- package/src/domain/scanner/external/types.ts +32 -0
- package/src/domain/scanner/finding-attribution.test.ts +444 -0
- package/src/domain/scanner/finding-attribution.ts +195 -0
- package/src/domain/scanner/finding-explainer.test.ts +157 -0
- package/src/domain/scanner/finding-explainer.ts +73 -0
- package/src/domain/scanner/fix-diff-builder.test.ts +272 -0
- package/src/domain/scanner/fix-diff-builder.ts +477 -0
- package/src/domain/scanner/import-graph.test.ts +162 -0
- package/src/domain/scanner/import-graph.ts +198 -0
- package/src/domain/scanner/languages/adapter.test.ts +105 -0
- package/src/domain/scanner/languages/adapter.ts +239 -0
- package/src/domain/scanner/layers/index.ts +24 -0
- package/src/domain/scanner/layers/layer1-files.ts +54 -0
- package/src/domain/scanner/layers/layer2-docs.test.ts +1207 -0
- package/src/domain/scanner/layers/layer2-docs.ts +297 -0
- package/src/domain/scanner/layers/layer2-parsing.ts +217 -0
- package/src/domain/scanner/layers/layer3-config.test.ts +187 -0
- package/src/domain/scanner/layers/layer3-config.ts +279 -0
- package/src/domain/scanner/layers/layer3-parsers.ts +73 -0
- package/src/domain/scanner/layers/layer4-patterns.test.ts +397 -0
- package/src/domain/scanner/layers/layer4-patterns.ts +216 -0
- package/src/domain/scanner/layers/layer5-docs.test.ts +99 -0
- package/src/domain/scanner/layers/layer5-docs.ts +250 -0
- package/src/domain/scanner/layers/layer5-llm.test.ts +146 -0
- package/src/domain/scanner/layers/layer5-llm.ts +262 -0
- package/src/domain/scanner/layers/layer5-targeted.test.ts +93 -0
- package/src/domain/scanner/layers/layer5-targeted.ts +233 -0
- package/src/domain/scanner/layers/lockfile-parsers.test.ts +320 -0
- package/src/domain/scanner/layers/lockfile-parsers.ts +184 -0
- package/src/domain/scanner/regulation-version.test.ts +54 -0
- package/src/domain/scanner/regulation-version.ts +23 -0
- package/src/domain/scanner/role-filter.test.ts +116 -0
- package/src/domain/scanner/role-filter.ts +51 -0
- package/src/domain/scanner/rules/banned-packages-data.ts +553 -0
- package/src/domain/scanner/rules/banned-packages-sdk.ts +65 -0
- package/src/domain/scanner/rules/banned-packages.test.ts +249 -0
- package/src/domain/scanner/rules/banned-packages.ts +55 -0
- package/src/domain/scanner/rules/comment-filter.test.ts +115 -0
- package/src/domain/scanner/rules/comment-filter.ts +297 -0
- package/src/domain/scanner/rules/index.ts +9 -0
- package/src/domain/scanner/rules/nhi-patterns.test.ts +128 -0
- package/src/domain/scanner/rules/nhi-patterns.ts +60 -0
- package/src/domain/scanner/rules/pattern-rules.ts +1152 -0
- package/src/domain/scanner/sbom.test.ts +136 -0
- package/src/domain/scanner/sbom.ts +103 -0
- package/src/domain/scanner/scan-cache.test.ts +136 -0
- package/src/domain/scanner/scan-cache.ts +115 -0
- package/src/domain/scanner/scanner.test.ts +125 -0
- package/src/domain/scanner/score-calculator.test.ts +363 -0
- package/src/domain/scanner/score-calculator.ts +189 -0
- package/src/domain/scanner/security-score.test.ts +107 -0
- package/src/domain/scanner/security-score.ts +116 -0
- package/src/domain/scanner/source-filter.ts +24 -0
- package/src/domain/scanner/validators.ts +223 -0
- package/src/domain/shared/compliance-constants.ts +48 -0
- package/src/domain/shared/disclosure-patterns.ts +16 -0
- package/src/domain/shared/index.ts +6 -0
- package/src/domain/shared/parse-dependencies.ts +21 -0
- package/src/domain/supply-chain/dependency-analyzer.ts +138 -0
- package/src/domain/supply-chain/index.ts +3 -0
- package/src/domain/supply-chain/supply-chain.test.ts +211 -0
- package/src/domain/supply-chain/types.ts +32 -0
- package/src/domain/whatif/config-fixer.ts +187 -0
- package/src/domain/whatif/index.ts +6 -0
- package/src/domain/whatif/scenario-engine.ts +121 -0
- package/src/domain/whatif/simulate-actions.test.ts +161 -0
- package/src/domain/whatif/simulate-actions.ts +114 -0
- package/src/domain/whatif/whatif.test.ts +135 -0
- package/src/e2e/gaps-e2e.test.ts +259 -0
- package/src/e2e/smoke.test.ts +101 -0
- package/src/hooks/hooks-export.test.ts +81 -0
- package/src/hooks/installer.ts +113 -0
- package/src/http/cors.test.ts +38 -0
- package/src/http/create-router.ts +259 -0
- package/src/http/routes/agent.route.ts +380 -0
- package/src/http/routes/audit.route.ts +66 -0
- package/src/http/routes/badge.route.ts +23 -0
- package/src/http/routes/cert.route.ts +66 -0
- package/src/http/routes/chat.route.ts +228 -0
- package/src/http/routes/cost.route.ts +33 -0
- package/src/http/routes/debt.route.ts +29 -0
- package/src/http/routes/disclaimer.route.ts +64 -0
- package/src/http/routes/eval.route.ts +161 -0
- package/src/http/routes/events.route.test.ts +108 -0
- package/src/http/routes/events.route.ts +71 -0
- package/src/http/routes/external-scan.route.ts +24 -0
- package/src/http/routes/file.route.ts +54 -0
- package/src/http/routes/fix.route.ts +219 -0
- package/src/http/routes/frameworks.route.test.ts +66 -0
- package/src/http/routes/frameworks.route.ts +36 -0
- package/src/http/routes/git.route.ts +27 -0
- package/src/http/routes/guided-onboarding.route.ts +65 -0
- package/src/http/routes/import.route.ts +64 -0
- package/src/http/routes/jurisdiction.route.ts +22 -0
- package/src/http/routes/obligations.route.test.ts +122 -0
- package/src/http/routes/obligations.route.ts +110 -0
- package/src/http/routes/onboarding.route.ts +53 -0
- package/src/http/routes/provider.route.ts +42 -0
- package/src/http/routes/proxy.route.ts +40 -0
- package/src/http/routes/redteam.route.ts +84 -0
- package/src/http/routes/report.route.ts +29 -0
- package/src/http/routes/scan.route.ts +104 -0
- package/src/http/routes/share.route.ts +44 -0
- package/src/http/routes/shell.route.ts +27 -0
- package/src/http/routes/status.route.ts +66 -0
- package/src/http/routes/supply-chain.route.ts +121 -0
- package/src/http/routes/sync.route.ts +328 -0
- package/src/http/routes/tools.route.ts +29 -0
- package/src/http/routes/whatif.route.ts +96 -0
- package/src/http/utils/validation.ts +31 -0
- package/src/index.ts +1 -0
- package/src/infra/bundle-fetcher.ts +77 -0
- package/src/infra/cache-storage.ts +34 -0
- package/src/infra/event-bus.ts +31 -0
- package/src/infra/file-collector.ts +61 -0
- package/src/infra/file-ops-adapter.ts +95 -0
- package/src/infra/file-watcher.test.ts +90 -0
- package/src/infra/file-watcher.ts +106 -0
- package/src/infra/git-adapter.ts +93 -0
- package/src/infra/git-history-adapter.ts +41 -0
- package/src/infra/headless-browser.ts +178 -0
- package/src/infra/llm-adapter.test.ts +83 -0
- package/src/infra/llm-adapter.ts +86 -0
- package/src/infra/logger.ts +27 -0
- package/src/infra/project-config.test.ts +74 -0
- package/src/infra/project-config.ts +35 -0
- package/src/infra/rate-limiter.test.ts +36 -0
- package/src/infra/rate-limiter.ts +34 -0
- package/src/infra/retry.ts +46 -0
- package/src/infra/saas-client.ts +123 -0
- package/src/infra/search-adapter.ts +113 -0
- package/src/infra/shell-adapter.ts +68 -0
- package/src/infra/tool-manager.test.ts +99 -0
- package/src/infra/tool-manager.ts +197 -0
- package/src/llm/agents/agent-modes.test.ts +44 -0
- package/src/llm/agents/modes.ts +68 -0
- package/src/llm/routing/cost-routing.test.ts +37 -0
- package/src/llm/routing/cost-tracker.ts +74 -0
- package/src/llm/routing/model-routing.test.ts +79 -0
- package/src/llm/routing/model-routing.ts +38 -0
- package/src/llm/routing/pricing.ts +19 -0
- package/src/llm/sse-protocol.ts +77 -0
- package/src/llm/tool-definitions.ts +83 -0
- package/src/llm/tool-executors.ts +80 -0
- package/src/llm/tools/types.ts +13 -0
- package/src/mcp/create-mcp-stack.ts +82 -0
- package/src/mcp/handlers.ts +245 -0
- package/src/mcp/index.ts +28 -0
- package/src/mcp/mcp-server.test.ts +80 -0
- package/src/mcp/server.ts +79 -0
- package/src/mcp/tools.ts +48 -0
- package/src/onboarding/auto-detect.ts +164 -0
- package/src/onboarding/onboarding.test.ts +89 -0
- package/src/onboarding/profile.ts +169 -0
- package/src/onboarding/questions.ts +112 -0
- package/src/onboarding/wizard.ts +66 -0
- package/src/output/github-issue.ts +32 -0
- package/src/output/json-output.ts +67 -0
- package/src/ports/browser.port.ts +23 -0
- package/src/ports/events.port.ts +28 -0
- package/src/ports/llm.port.ts +23 -0
- package/src/ports/logger.port.ts +6 -0
- package/src/ports/process.port.ts +6 -0
- package/src/ports/scanner.port.ts +15 -0
- package/src/server.ts +134 -0
- package/src/services/badge-service.ts +67 -0
- package/src/services/chat-service.test.ts +162 -0
- package/src/services/chat-service.ts +152 -0
- package/src/services/cost-service.ts +52 -0
- package/src/services/debt-service.ts +65 -0
- package/src/services/eval-integration.test.ts +132 -0
- package/src/services/eval-service.test.ts +373 -0
- package/src/services/eval-service.ts +463 -0
- package/src/services/external-scan-service.ts +60 -0
- package/src/services/file-service.ts +37 -0
- package/src/services/fix-service.test.ts +470 -0
- package/src/services/fix-service.ts +648 -0
- package/src/services/framework-service.test.ts +159 -0
- package/src/services/framework-service.ts +67 -0
- package/src/services/onboarding-service.ts +165 -0
- package/src/services/passport-audit.ts +244 -0
- package/src/services/passport-documents.ts +258 -0
- package/src/services/passport-service-utils.ts +72 -0
- package/src/services/passport-service.test.ts +251 -0
- package/src/services/passport-service.ts +339 -0
- package/src/services/proxy-service.ts +81 -0
- package/src/services/report-service.ts +72 -0
- package/src/services/scan-service.test.ts +470 -0
- package/src/services/scan-service.ts +335 -0
- package/src/services/share-service.ts +108 -0
- package/src/services/shared/backup.ts +23 -0
- package/src/services/status-service.ts +38 -0
- package/src/services/undo-service.test.ts +190 -0
- package/src/services/undo-service.ts +144 -0
- package/src/test-helpers/factories.ts +116 -0
- package/src/types/common.schemas.ts +147 -0
- package/src/types/common.types.ts +292 -0
- package/src/types/contract.test.ts +217 -0
- package/src/types/errors.ts +52 -0
- package/src/types/framework.types.ts +87 -0
- package/src/types/passport-schemas.ts +241 -0
- package/src/types/passport.types.ts +296 -0
- package/src/version.ts +1 -0
- package/tsconfig.json +20 -0
- package/vitest.config.ts +9 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { QUESTION_BLOCKS, getAllBlockIds } from './questions.js';
|
|
3
|
+
import { buildProfile, computeRiskLevel, computeApplicableObligations, validateProfile } from './profile.js';
|
|
4
|
+
import type { AutoDetectResult } from './auto-detect.js';
|
|
5
|
+
|
|
6
|
+
const mockAutoDetect: AutoDetectResult = {
|
|
7
|
+
language: 'TypeScript',
|
|
8
|
+
framework: 'Next.js',
|
|
9
|
+
cicd: 'github-actions',
|
|
10
|
+
deployment: 'Docker',
|
|
11
|
+
aiLibraries: ['OpenAI SDK', 'Vercel AI SDK'],
|
|
12
|
+
hasDockerCompose: true,
|
|
13
|
+
hasEnvExample: true,
|
|
14
|
+
detectedModels: ['gpt-4o'],
|
|
15
|
+
confidence: 0.83,
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
describe('Onboarding Questions', () => {
|
|
19
|
+
it('has 3 question blocks', () => {
|
|
20
|
+
expect(QUESTION_BLOCKS).toHaveLength(3);
|
|
21
|
+
expect(getAllBlockIds()).toEqual(['role', 'business', 'data']);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('every block has at least one question', () => {
|
|
25
|
+
for (const block of QUESTION_BLOCKS) {
|
|
26
|
+
expect(block.questions.length).toBeGreaterThan(0);
|
|
27
|
+
for (const q of block.questions) {
|
|
28
|
+
expect(q.id).toBeTruthy();
|
|
29
|
+
expect(q.text).toBeTruthy();
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
describe('Profile Builder', () => {
|
|
36
|
+
it('builds complete profile with computed fields', () => {
|
|
37
|
+
const profile = buildProfile(mockAutoDetect, {
|
|
38
|
+
org_role: 'deployer',
|
|
39
|
+
domain: 'healthcare',
|
|
40
|
+
data_types: ['personal', 'health'],
|
|
41
|
+
data_storage: 'eu',
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
expect(profile.version).toBe('1.0');
|
|
45
|
+
expect(profile.autoDetected.language).toBe('TypeScript');
|
|
46
|
+
expect(profile.aiSystem.type).toBe('feature'); // default
|
|
47
|
+
expect(profile.jurisdiction.primary).toBe('EU'); // default
|
|
48
|
+
expect(profile.business.domain).toBe('healthcare');
|
|
49
|
+
expect(profile.computed.riskLevel).toBe('high');
|
|
50
|
+
expect(profile.computed.applicableObligations.length).toBeGreaterThan(15);
|
|
51
|
+
expect(profile.computed.estimatedScore).toBe(25);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('validates correct profile', () => {
|
|
55
|
+
const profile = buildProfile(mockAutoDetect, { domain: 'general' });
|
|
56
|
+
const result = validateProfile(profile);
|
|
57
|
+
expect(result.valid).toBe(true);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('rejects invalid profile', () => {
|
|
61
|
+
const result = validateProfile({ version: '2.0', invalid: true });
|
|
62
|
+
expect(result.valid).toBe(false);
|
|
63
|
+
expect(result.errors).toBeDefined();
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
describe('Risk Level Computation', () => {
|
|
68
|
+
it('healthcare domain → high', () => {
|
|
69
|
+
expect(computeRiskLevel('healthcare', ['personal'], 'feature')).toBe('high');
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('biometric data → high', () => {
|
|
73
|
+
expect(computeRiskLevel('general', ['biometric'], 'feature')).toBe('high');
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('general + public data → limited', () => {
|
|
77
|
+
expect(computeRiskLevel('general', ['public'], 'feature')).toBe('limited');
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('internal + public data → minimal', () => {
|
|
81
|
+
expect(computeRiskLevel('general', ['public'], 'internal')).toBe('minimal');
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('high-risk adds extra obligations', () => {
|
|
85
|
+
const high = computeApplicableObligations('healthcare', 'high');
|
|
86
|
+
const limited = computeApplicableObligations('general', 'limited');
|
|
87
|
+
expect(high.length).toBeGreaterThan(limited.length);
|
|
88
|
+
});
|
|
89
|
+
});
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { AutoDetectResult } from './auto-detect.js';
|
|
3
|
+
import riskProfileData from '../../data/onboarding/risk-profile.json' with { type: 'json' };
|
|
4
|
+
|
|
5
|
+
// ── Zod validation for obligation IDs from JSON ─────────────
|
|
6
|
+
const OblIdSchema = z.string().regex(/^OBL-\d{3}$/);
|
|
7
|
+
const validatedRiskProfile = z.object({
|
|
8
|
+
high_risk_domains: z.array(z.string()),
|
|
9
|
+
domain_obligations: z.record(z.array(OblIdSchema)),
|
|
10
|
+
base_obligations: z.array(OblIdSchema),
|
|
11
|
+
high_risk_extra_obligations: z.array(OblIdSchema),
|
|
12
|
+
}).parse(riskProfileData);
|
|
13
|
+
|
|
14
|
+
export const ProjectProfileSchema = z.object({
|
|
15
|
+
version: z.literal('1.0'),
|
|
16
|
+
createdAt: z.string(),
|
|
17
|
+
updatedAt: z.string(),
|
|
18
|
+
autoDetected: z.object({
|
|
19
|
+
language: z.string(),
|
|
20
|
+
framework: z.string(),
|
|
21
|
+
cicd: z.string(),
|
|
22
|
+
deployment: z.string(),
|
|
23
|
+
aiLibraries: z.array(z.string()),
|
|
24
|
+
hasDockerCompose: z.boolean(),
|
|
25
|
+
hasEnvExample: z.boolean(),
|
|
26
|
+
detectedModels: z.array(z.string()),
|
|
27
|
+
confidence: z.number(),
|
|
28
|
+
}),
|
|
29
|
+
aiSystem: z.object({
|
|
30
|
+
type: z.enum(['feature', 'standalone', 'platform', 'internal']).default('feature'),
|
|
31
|
+
outputTypes: z.array(z.string()).default(['text']),
|
|
32
|
+
}).default({ type: 'feature', outputTypes: ['text'] }),
|
|
33
|
+
jurisdiction: z.object({
|
|
34
|
+
primary: z.string().default('EU'),
|
|
35
|
+
regulations: z.array(z.string()).default(['eu-ai-act']),
|
|
36
|
+
}).default({ primary: 'EU', regulations: ['eu-ai-act'] }),
|
|
37
|
+
organization: z.object({
|
|
38
|
+
role: z.enum(['provider', 'deployer', 'both']),
|
|
39
|
+
}),
|
|
40
|
+
business: z.object({
|
|
41
|
+
domain: z.string(),
|
|
42
|
+
companySize: z.enum(['startup', 'sme', 'enterprise']).default('startup'),
|
|
43
|
+
}),
|
|
44
|
+
data: z.object({
|
|
45
|
+
types: z.array(z.string()),
|
|
46
|
+
storage: z.enum(['eu', 'us', 'mixed']),
|
|
47
|
+
}),
|
|
48
|
+
goals: z.object({
|
|
49
|
+
priority: z.string().default('full'),
|
|
50
|
+
budget: z.enum(['minimal', 'moderate', 'full']).default('moderate'),
|
|
51
|
+
}).default({ priority: 'full', budget: 'moderate' }),
|
|
52
|
+
computed: z.object({
|
|
53
|
+
riskLevel: z.enum(['minimal', 'limited', 'high', 'unacceptable']),
|
|
54
|
+
applicableObligations: z.array(z.string()),
|
|
55
|
+
estimatedScore: z.number(),
|
|
56
|
+
}),
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
export type OnboardingProfile = z.infer<typeof ProjectProfileSchema>;
|
|
60
|
+
|
|
61
|
+
export type OnboardingAnswers = Record<string, string | string[]>;
|
|
62
|
+
|
|
63
|
+
const HIGH_RISK_DOMAINS = new Set(validatedRiskProfile.high_risk_domains);
|
|
64
|
+
|
|
65
|
+
const DOMAIN_OBLIGATIONS: Record<string, readonly string[]> = validatedRiskProfile.domain_obligations;
|
|
66
|
+
|
|
67
|
+
const BASE_OBLIGATIONS = validatedRiskProfile.base_obligations;
|
|
68
|
+
|
|
69
|
+
export const computeRiskLevel = (
|
|
70
|
+
domain: string,
|
|
71
|
+
dataTypes: readonly string[],
|
|
72
|
+
systemType: string,
|
|
73
|
+
): 'minimal' | 'limited' | 'high' | 'unacceptable' => {
|
|
74
|
+
if (dataTypes.includes('biometric')) return 'high';
|
|
75
|
+
if (HIGH_RISK_DOMAINS.has(domain)) return 'high';
|
|
76
|
+
if (dataTypes.includes('health') || dataTypes.includes('financial')) return 'high';
|
|
77
|
+
if (systemType === 'platform') return 'limited';
|
|
78
|
+
if (systemType === 'internal' && dataTypes.includes('public')) return 'minimal';
|
|
79
|
+
return 'limited';
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
export const computeApplicableObligations = (
|
|
83
|
+
domain: string,
|
|
84
|
+
riskLevel: string,
|
|
85
|
+
): readonly string[] => {
|
|
86
|
+
const obligations = [...BASE_OBLIGATIONS];
|
|
87
|
+
const domainObs = DOMAIN_OBLIGATIONS[domain];
|
|
88
|
+
if (domainObs) obligations.push(...domainObs);
|
|
89
|
+
if (riskLevel === 'high') {
|
|
90
|
+
obligations.push(...validatedRiskProfile.high_risk_extra_obligations);
|
|
91
|
+
}
|
|
92
|
+
return obligations;
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const answerStr = (answers: OnboardingAnswers, key: string, fallback: string): string => {
|
|
96
|
+
const v = answers[key];
|
|
97
|
+
return typeof v === 'string' ? v : fallback;
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
const answerArr = (answers: OnboardingAnswers, key: string, fallback: string[]): string[] => {
|
|
101
|
+
const v = answers[key];
|
|
102
|
+
return Array.isArray(v) ? v : fallback;
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
const SystemTypeSchema = z.enum(['feature', 'standalone', 'platform', 'internal']);
|
|
106
|
+
const RoleSchema = z.enum(['provider', 'deployer', 'both']);
|
|
107
|
+
const CompanySizeSchema = z.enum(['startup', 'sme', 'enterprise']);
|
|
108
|
+
const StorageSchema = z.enum(['eu', 'us', 'mixed']);
|
|
109
|
+
const BudgetSchema = z.enum(['minimal', 'moderate', 'full']);
|
|
110
|
+
|
|
111
|
+
export const buildProfile = (
|
|
112
|
+
autoDetected: AutoDetectResult,
|
|
113
|
+
answers: OnboardingAnswers,
|
|
114
|
+
): OnboardingProfile => {
|
|
115
|
+
const domain = answerStr(answers, 'domain', 'general');
|
|
116
|
+
const dataTypes = answerArr(answers, 'data_types', ['public']);
|
|
117
|
+
const systemType = answerStr(answers, 'system_type', 'feature');
|
|
118
|
+
|
|
119
|
+
const riskLevel = computeRiskLevel(domain, dataTypes, systemType);
|
|
120
|
+
const applicableObligations = computeApplicableObligations(domain, riskLevel);
|
|
121
|
+
const estimatedScore = riskLevel === 'high' ? 25 : riskLevel === 'limited' ? 40 : 60;
|
|
122
|
+
|
|
123
|
+
const now = new Date().toISOString();
|
|
124
|
+
|
|
125
|
+
return {
|
|
126
|
+
version: '1.0',
|
|
127
|
+
createdAt: now,
|
|
128
|
+
updatedAt: now,
|
|
129
|
+
autoDetected: {
|
|
130
|
+
...autoDetected,
|
|
131
|
+
aiLibraries: [...autoDetected.aiLibraries],
|
|
132
|
+
detectedModels: [...autoDetected.detectedModels],
|
|
133
|
+
},
|
|
134
|
+
aiSystem: {
|
|
135
|
+
type: SystemTypeSchema.catch('feature').parse(systemType),
|
|
136
|
+
outputTypes: answerArr(answers, 'output_types', ['text']),
|
|
137
|
+
},
|
|
138
|
+
jurisdiction: {
|
|
139
|
+
primary: answerStr(answers, 'primary_jurisdiction', 'EU'),
|
|
140
|
+
regulations: ['eu-ai-act'],
|
|
141
|
+
},
|
|
142
|
+
organization: {
|
|
143
|
+
role: RoleSchema.catch('deployer').parse(answerStr(answers, 'org_role', 'deployer')),
|
|
144
|
+
},
|
|
145
|
+
business: {
|
|
146
|
+
domain,
|
|
147
|
+
companySize: CompanySizeSchema.catch('startup').parse(answerStr(answers, 'company_size', 'startup')),
|
|
148
|
+
},
|
|
149
|
+
data: {
|
|
150
|
+
types: dataTypes,
|
|
151
|
+
storage: StorageSchema.catch('eu').parse(answerStr(answers, 'data_storage', 'eu')),
|
|
152
|
+
},
|
|
153
|
+
goals: {
|
|
154
|
+
priority: answerStr(answers, 'priority', 'full'),
|
|
155
|
+
budget: BudgetSchema.catch('moderate').parse(answerStr(answers, 'budget', 'moderate')),
|
|
156
|
+
},
|
|
157
|
+
computed: {
|
|
158
|
+
riskLevel,
|
|
159
|
+
applicableObligations: [...applicableObligations],
|
|
160
|
+
estimatedScore,
|
|
161
|
+
},
|
|
162
|
+
};
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
export const validateProfile = (data: unknown): { valid: boolean; errors?: string[] } => {
|
|
166
|
+
const result = ProjectProfileSchema.safeParse(data);
|
|
167
|
+
if (result.success) return { valid: true };
|
|
168
|
+
return { valid: false, errors: result.error.errors.map((e) => `${e.path.join('.')}: ${e.message}`) };
|
|
169
|
+
};
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
export interface QuestionOption {
|
|
2
|
+
readonly value: string;
|
|
3
|
+
readonly label: string;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export interface QuestionBlock {
|
|
7
|
+
readonly id: string;
|
|
8
|
+
readonly title: string;
|
|
9
|
+
readonly questions: readonly Question[];
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface Question {
|
|
13
|
+
readonly id: string;
|
|
14
|
+
readonly text: string;
|
|
15
|
+
readonly type: 'single' | 'multi' | 'text';
|
|
16
|
+
readonly options?: readonly QuestionOption[];
|
|
17
|
+
readonly default?: string;
|
|
18
|
+
/** Per-option explanations (value → description). Shown below the option in interactive CLI. */
|
|
19
|
+
readonly descriptions?: Readonly<Record<string, string>>;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const QUESTION_BLOCKS: readonly QuestionBlock[] = [
|
|
23
|
+
{
|
|
24
|
+
id: 'role',
|
|
25
|
+
title: 'Organization Role',
|
|
26
|
+
questions: [
|
|
27
|
+
{
|
|
28
|
+
id: 'org_role',
|
|
29
|
+
text: 'Your role under EU AI Act?',
|
|
30
|
+
type: 'single',
|
|
31
|
+
options: [
|
|
32
|
+
{ value: 'deployer', label: 'Deployer — we USE AI systems' },
|
|
33
|
+
{ value: 'provider', label: 'Provider — we BUILD AI systems' },
|
|
34
|
+
{ value: 'both', label: 'Both provider and deployer' },
|
|
35
|
+
],
|
|
36
|
+
descriptions: {
|
|
37
|
+
deployer: 'You integrate AI APIs (OpenAI, Anthropic, Google) or use AI tools. ~10 obligations. Examples: SaaS with AI chatbot, internal AI tool, API-powered feature.',
|
|
38
|
+
provider: 'You develop, train, or rebrand AI systems under your name. ~30 obligations. Examples: AI SaaS product, model hosting, AI API provider. Art.25: if you put your brand on it, you are a provider.',
|
|
39
|
+
both: 'You build your own AI AND use third-party AI. Full obligation set.',
|
|
40
|
+
},
|
|
41
|
+
default: 'deployer',
|
|
42
|
+
},
|
|
43
|
+
],
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
id: 'business',
|
|
47
|
+
title: 'Business Domain',
|
|
48
|
+
questions: [
|
|
49
|
+
{
|
|
50
|
+
id: 'domain',
|
|
51
|
+
text: 'Primary business domain?',
|
|
52
|
+
type: 'single',
|
|
53
|
+
options: [
|
|
54
|
+
{ value: 'general', label: 'General / SaaS' },
|
|
55
|
+
{ value: 'healthcare', label: 'Healthcare / Medical' },
|
|
56
|
+
{ value: 'finance', label: 'Finance / Insurance' },
|
|
57
|
+
{ value: 'hr', label: 'HR / Employment' },
|
|
58
|
+
{ value: 'education', label: 'Education' },
|
|
59
|
+
{ value: 'content', label: 'Content Generation' },
|
|
60
|
+
{ value: 'customer_service', label: 'Customer Service' },
|
|
61
|
+
],
|
|
62
|
+
descriptions: {
|
|
63
|
+
healthcare: 'Triggers HIGH RISK classification under EU AI Act.',
|
|
64
|
+
finance: 'Triggers HIGH RISK classification under EU AI Act.',
|
|
65
|
+
hr: 'Triggers HIGH RISK classification under EU AI Act.',
|
|
66
|
+
education: 'Triggers HIGH RISK classification under EU AI Act.',
|
|
67
|
+
},
|
|
68
|
+
default: 'general',
|
|
69
|
+
},
|
|
70
|
+
],
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
id: 'data',
|
|
74
|
+
title: 'Data Handling',
|
|
75
|
+
questions: [
|
|
76
|
+
{
|
|
77
|
+
id: 'data_types',
|
|
78
|
+
text: 'What types of data does your AI process?',
|
|
79
|
+
type: 'multi',
|
|
80
|
+
options: [
|
|
81
|
+
{ value: 'personal', label: 'Personal data (names, emails)' },
|
|
82
|
+
{ value: 'biometric', label: 'Biometric data' },
|
|
83
|
+
{ value: 'health', label: 'Health/Medical data' },
|
|
84
|
+
{ value: 'financial', label: 'Financial data' },
|
|
85
|
+
{ value: 'public', label: 'Public/Open data only' },
|
|
86
|
+
],
|
|
87
|
+
descriptions: {
|
|
88
|
+
biometric: 'Triggers HIGH RISK classification.',
|
|
89
|
+
health: 'Triggers HIGH RISK classification.',
|
|
90
|
+
financial: 'Triggers HIGH RISK classification.',
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
id: 'data_storage',
|
|
95
|
+
text: 'Where is data stored?',
|
|
96
|
+
type: 'single',
|
|
97
|
+
options: [
|
|
98
|
+
{ value: 'eu', label: 'EU only' },
|
|
99
|
+
{ value: 'us', label: 'US only' },
|
|
100
|
+
{ value: 'mixed', label: 'Mixed / Multi-region' },
|
|
101
|
+
],
|
|
102
|
+
default: 'eu',
|
|
103
|
+
},
|
|
104
|
+
],
|
|
105
|
+
},
|
|
106
|
+
];
|
|
107
|
+
|
|
108
|
+
export const getQuestionBlock = (blockId: string): QuestionBlock | undefined =>
|
|
109
|
+
QUESTION_BLOCKS.find((b) => b.id === blockId);
|
|
110
|
+
|
|
111
|
+
export const getAllBlockIds = (): readonly string[] =>
|
|
112
|
+
QUESTION_BLOCKS.map((b) => b.id);
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { readFile, writeFile, mkdir } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { autoDetect, type AutoDetectResult } from './auto-detect.js';
|
|
4
|
+
import { QUESTION_BLOCKS } from './questions.js';
|
|
5
|
+
import { buildProfile, validateProfile, ProjectProfileSchema, type OnboardingProfile, type OnboardingAnswers } from './profile.js';
|
|
6
|
+
|
|
7
|
+
export interface WizardDeps {
|
|
8
|
+
readonly getProjectPath: () => string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface WizardResult {
|
|
12
|
+
readonly profile: OnboardingProfile;
|
|
13
|
+
readonly autoDetected: AutoDetectResult;
|
|
14
|
+
readonly profilePath: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const createOnboardingWizard = (deps: WizardDeps) => {
|
|
18
|
+
const { getProjectPath } = deps;
|
|
19
|
+
|
|
20
|
+
const detect = async (): Promise<AutoDetectResult> => {
|
|
21
|
+
return autoDetect(getProjectPath());
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const getQuestions = () => QUESTION_BLOCKS;
|
|
25
|
+
|
|
26
|
+
const complete = async (answers: OnboardingAnswers): Promise<WizardResult> => {
|
|
27
|
+
const projectPath = getProjectPath();
|
|
28
|
+
const autoDetected = await autoDetect(projectPath);
|
|
29
|
+
const profile = buildProfile(autoDetected, answers);
|
|
30
|
+
|
|
31
|
+
// Validate
|
|
32
|
+
const validation = validateProfile(profile);
|
|
33
|
+
if (!validation.valid) {
|
|
34
|
+
throw new Error(`Invalid profile: ${validation.errors?.join(', ')}`);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Save profile
|
|
38
|
+
const compliorDir = join(projectPath, '.complior');
|
|
39
|
+
await mkdir(compliorDir, { recursive: true });
|
|
40
|
+
const profilePath = join(compliorDir, 'profile.json');
|
|
41
|
+
await writeFile(profilePath, JSON.stringify(profile, null, 2), 'utf-8');
|
|
42
|
+
|
|
43
|
+
return Object.freeze({ profile, autoDetected, profilePath });
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const loadProfile = async (): Promise<OnboardingProfile | null> => {
|
|
47
|
+
const profilePath = join(getProjectPath(), '.complior', 'profile.json');
|
|
48
|
+
const content = await readFile(profilePath, 'utf-8').catch(() => null);
|
|
49
|
+
if (!content) return null;
|
|
50
|
+
|
|
51
|
+
const parsed: unknown = JSON.parse(content);
|
|
52
|
+
const result = ProjectProfileSchema.safeParse(parsed);
|
|
53
|
+
if (!result.success) return null;
|
|
54
|
+
|
|
55
|
+
return result.data;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const hasProfile = async (): Promise<boolean> => {
|
|
59
|
+
const profile = await loadProfile();
|
|
60
|
+
return profile !== null;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
return Object.freeze({ detect, getQuestions, complete, loadProfile, hasProfile });
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export type OnboardingWizard = ReturnType<typeof createOnboardingWizard>;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { ScanResult } from '../types/common.types.js';
|
|
2
|
+
|
|
3
|
+
export const toGithubIssue = (result: ScanResult): string => {
|
|
4
|
+
const failFindings = result.findings.filter((f) => f.type === 'fail');
|
|
5
|
+
const lines: string[] = [
|
|
6
|
+
'## EU AI Act Compliance Checklist',
|
|
7
|
+
'',
|
|
8
|
+
`**Score:** ${result.score.totalScore}/100 (${result.score.zone.toUpperCase()})`,
|
|
9
|
+
`**Scanned:** ${result.scannedAt}`,
|
|
10
|
+
`**Files:** ${result.filesScanned}`,
|
|
11
|
+
'',
|
|
12
|
+
'### Findings',
|
|
13
|
+
'',
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
if (failFindings.length === 0) {
|
|
17
|
+
lines.push('No violations found.');
|
|
18
|
+
} else {
|
|
19
|
+
for (const f of failFindings) {
|
|
20
|
+
const ref = f.articleReference ? ` (${f.articleReference})` : '';
|
|
21
|
+
const file = f.file ? ` — \`${f.file}\`` : '';
|
|
22
|
+
lines.push(`- [ ] **[${f.severity.toUpperCase()}]** ${f.checkId}${ref}: ${f.message}${file}`);
|
|
23
|
+
if (f.fix) {
|
|
24
|
+
lines.push(` - Fix: ${f.fix}`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
lines.push('', '---', '*Generated by [Complior](https://complior.ai)*');
|
|
30
|
+
|
|
31
|
+
return lines.join('\n');
|
|
32
|
+
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { ScanResult } from '../types/common.types.js';
|
|
2
|
+
|
|
3
|
+
export interface JsonOutput {
|
|
4
|
+
readonly scanner: string;
|
|
5
|
+
readonly version: string;
|
|
6
|
+
readonly score: number;
|
|
7
|
+
readonly zone: string;
|
|
8
|
+
readonly totalChecks: number;
|
|
9
|
+
readonly passedChecks: number;
|
|
10
|
+
readonly failedChecks: number;
|
|
11
|
+
readonly criticalCapApplied: boolean;
|
|
12
|
+
readonly findings: readonly {
|
|
13
|
+
readonly checkId: string;
|
|
14
|
+
readonly type: string;
|
|
15
|
+
readonly severity: string;
|
|
16
|
+
readonly message: string;
|
|
17
|
+
readonly obligationId?: string;
|
|
18
|
+
readonly articleReference?: string;
|
|
19
|
+
readonly file?: string;
|
|
20
|
+
readonly line?: number;
|
|
21
|
+
readonly fix?: string;
|
|
22
|
+
}[];
|
|
23
|
+
readonly categories: readonly {
|
|
24
|
+
readonly category: string;
|
|
25
|
+
readonly weight: number;
|
|
26
|
+
readonly score: number;
|
|
27
|
+
readonly passed: number;
|
|
28
|
+
readonly total: number;
|
|
29
|
+
}[];
|
|
30
|
+
readonly scannedAt: string;
|
|
31
|
+
readonly projectPath: string;
|
|
32
|
+
readonly filesScanned: number;
|
|
33
|
+
readonly duration: number;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export const toJsonOutput = (result: ScanResult, version: string): JsonOutput => ({
|
|
37
|
+
scanner: 'complior',
|
|
38
|
+
version,
|
|
39
|
+
score: result.score.totalScore,
|
|
40
|
+
zone: result.score.zone,
|
|
41
|
+
totalChecks: result.score.totalChecks,
|
|
42
|
+
passedChecks: result.score.passedChecks,
|
|
43
|
+
failedChecks: result.score.failedChecks,
|
|
44
|
+
criticalCapApplied: result.score.criticalCapApplied,
|
|
45
|
+
findings: result.findings.map((f) => ({
|
|
46
|
+
checkId: f.checkId,
|
|
47
|
+
type: f.type,
|
|
48
|
+
severity: f.severity,
|
|
49
|
+
message: f.message,
|
|
50
|
+
obligationId: f.obligationId,
|
|
51
|
+
articleReference: f.articleReference,
|
|
52
|
+
file: f.file,
|
|
53
|
+
line: f.line,
|
|
54
|
+
fix: f.fix,
|
|
55
|
+
})),
|
|
56
|
+
categories: result.score.categoryScores.map((c) => ({
|
|
57
|
+
category: c.category,
|
|
58
|
+
weight: c.weight,
|
|
59
|
+
score: c.score,
|
|
60
|
+
passed: c.passedCount,
|
|
61
|
+
total: c.obligationCount,
|
|
62
|
+
})),
|
|
63
|
+
scannedAt: result.scannedAt,
|
|
64
|
+
projectPath: result.projectPath,
|
|
65
|
+
filesScanned: result.filesScanned,
|
|
66
|
+
duration: result.duration,
|
|
67
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** PageData — the shape of data produced by a headless browser crawl */
|
|
2
|
+
export interface PageData {
|
|
3
|
+
readonly url: string;
|
|
4
|
+
readonly html: string;
|
|
5
|
+
readonly title: string;
|
|
6
|
+
readonly headers: Record<string, string>;
|
|
7
|
+
readonly metaTags: readonly { readonly name: string; readonly content: string }[];
|
|
8
|
+
readonly images: readonly { readonly src: string; readonly alt: string }[];
|
|
9
|
+
readonly links: readonly { readonly href: string; readonly text: string }[];
|
|
10
|
+
readonly scripts: readonly string[];
|
|
11
|
+
readonly hasWebSocket: boolean;
|
|
12
|
+
readonly chatInputs: readonly { readonly placeholder: string; readonly type: string }[];
|
|
13
|
+
readonly wellKnownAiCompliance: string | null;
|
|
14
|
+
readonly privacyPolicyUrl: string | null;
|
|
15
|
+
readonly privacyPolicyText: string | null;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** BrowserPort — contract for headless browser capabilities */
|
|
19
|
+
export interface BrowserPort {
|
|
20
|
+
readonly crawl: (url: string, timeout?: number) => Promise<PageData>;
|
|
21
|
+
readonly screenshot: (url: string, outputPath: string) => Promise<string>;
|
|
22
|
+
readonly close: () => Promise<void>;
|
|
23
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { ScanResult, GateResult, ScoreZone } from '../types/common.types.js';
|
|
2
|
+
import type { DriftResult } from '../domain/scanner/drift.js';
|
|
3
|
+
|
|
4
|
+
export interface EventMap {
|
|
5
|
+
readonly 'scan.completed': { readonly result: ScanResult };
|
|
6
|
+
readonly 'scan.started': { readonly projectPath: string };
|
|
7
|
+
readonly 'scan.drift': { readonly drift: DriftResult };
|
|
8
|
+
readonly 'file.changed': { readonly path: string; readonly action: 'create' | 'edit' | 'delete' };
|
|
9
|
+
readonly 'score.updated': { readonly before: number; readonly after: number };
|
|
10
|
+
readonly 'gate.checked': { readonly result: GateResult };
|
|
11
|
+
readonly 'fix.validated': { readonly checkId: string; readonly passed: boolean; readonly scoreDelta: number };
|
|
12
|
+
readonly 'fix.undone': { readonly checkId: string; readonly restoredFiles: readonly string[] };
|
|
13
|
+
readonly 'badge.generated': { readonly path: string; readonly score: number; readonly zone: ScoreZone };
|
|
14
|
+
readonly 'share.created': { readonly id: string; readonly score: number };
|
|
15
|
+
readonly 'external-scan.completed': { readonly url: string; readonly score: number };
|
|
16
|
+
readonly 'report.generated': { readonly path: string; readonly format: 'pdf' | 'markdown' };
|
|
17
|
+
readonly 'agent.scan.completed': { readonly agentName: string; readonly result: ScanResult };
|
|
18
|
+
readonly 'agent.score.updated': { readonly agentName: string; readonly before: number; readonly after: number };
|
|
19
|
+
readonly 'passport.imported': { readonly name: string; readonly format: string; readonly fieldsImported: number };
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export type EventHandler<T> = (payload: T) => void;
|
|
23
|
+
|
|
24
|
+
export interface EventBusPort {
|
|
25
|
+
readonly on: <K extends keyof EventMap>(event: K, handler: EventHandler<EventMap[K]>) => void;
|
|
26
|
+
readonly off: <K extends keyof EventMap>(event: K, handler: EventHandler<EventMap[K]>) => void;
|
|
27
|
+
readonly emit: <K extends keyof EventMap>(event: K, payload: EventMap[K]) => void;
|
|
28
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { LanguageModel } from 'ai';
|
|
2
|
+
|
|
3
|
+
export type ProviderName = 'openai' | 'anthropic' | 'openrouter';
|
|
4
|
+
|
|
5
|
+
export interface ProviderInfo {
|
|
6
|
+
readonly name: ProviderName;
|
|
7
|
+
readonly available: boolean;
|
|
8
|
+
readonly envVar: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface ModelSelection {
|
|
12
|
+
readonly provider: ProviderName;
|
|
13
|
+
readonly modelId: string;
|
|
14
|
+
readonly reason: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface LlmPort {
|
|
18
|
+
readonly getModel: (provider: ProviderName, modelId: string, apiKey?: string) => Promise<LanguageModel>;
|
|
19
|
+
readonly detectProviders: () => readonly ProviderInfo[];
|
|
20
|
+
readonly getAvailableProviders: () => readonly ProviderInfo[];
|
|
21
|
+
readonly getDefaultProvider: () => ProviderName;
|
|
22
|
+
readonly routeModel: (taskType: string, preferredProvider?: ProviderName) => ModelSelection;
|
|
23
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export interface LoggerPort {
|
|
2
|
+
readonly info: (message: string, ...args: unknown[]) => void;
|
|
3
|
+
readonly warn: (message: string, ...args: unknown[]) => void;
|
|
4
|
+
readonly error: (message: string, ...args: unknown[]) => void;
|
|
5
|
+
readonly debug: (message: string, ...args: unknown[]) => void;
|
|
6
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** Contract for running external processes (subprocess execution). */
|
|
2
|
+
export type ProcessRunner = (
|
|
3
|
+
cmd: string,
|
|
4
|
+
args: readonly string[],
|
|
5
|
+
options?: { readonly timeout?: number; readonly cwd?: string },
|
|
6
|
+
) => Promise<{ readonly stdout: string; readonly stderr: string; readonly exitCode: number }>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { CheckResult } from '../types/common.types.js';
|
|
2
|
+
|
|
3
|
+
export interface FileInfo {
|
|
4
|
+
readonly path: string;
|
|
5
|
+
readonly content: string;
|
|
6
|
+
readonly extension: string;
|
|
7
|
+
readonly relativePath: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface ScanContext {
|
|
11
|
+
readonly files: readonly FileInfo[];
|
|
12
|
+
readonly projectPath: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export type CheckFunction = (ctx: ScanContext) => readonly CheckResult[];
|