@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,463 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Eval Service — application-level orchestration for `complior eval`.
|
|
3
|
+
*
|
|
4
|
+
* Wires domain modules (runner, scorer, judge, adapters, security)
|
|
5
|
+
* into a single entry point for HTTP routes and CLI.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { readFile, readdir, writeFile, mkdir } from 'node:fs/promises';
|
|
9
|
+
import { randomUUID } from 'node:crypto';
|
|
10
|
+
import { resolve, dirname } from 'node:path';
|
|
11
|
+
import { z } from 'zod';
|
|
12
|
+
import type { EvalResult, EvalOptions, EvalProgressCallback, TestResult } from '../domain/eval/types.js';
|
|
13
|
+
import type { TargetAdapter } from '../domain/eval/adapters/adapter-port.js';
|
|
14
|
+
import type { EvalRunnerDeps, EvalTestSources, EvalScorer, EvalJudge } from '../domain/eval/eval-runner.js';
|
|
15
|
+
import { createEvalRunner } from '../domain/eval/eval-runner.js';
|
|
16
|
+
import { autoDetectAdapter } from '../domain/eval/adapters/auto-detect.js';
|
|
17
|
+
import { createConformityScorer } from '../domain/eval/conformity-score.js';
|
|
18
|
+
import { createLlmJudge } from '../domain/eval/llm-judge.js';
|
|
19
|
+
import { createSecurityProbeLoader } from '../domain/eval/security-integration.js';
|
|
20
|
+
import { getSecurityRubric } from '../data/eval/security-rubrics.js';
|
|
21
|
+
import { buildPassportEvalBlock, mergeEvalIntoPassport } from '../domain/eval/eval-passport.js';
|
|
22
|
+
import { generateEvalReport } from '../domain/eval/eval-report.js';
|
|
23
|
+
import type { EvidenceStore } from '../domain/scanner/evidence-store.js';
|
|
24
|
+
import type { AuditStore } from '../domain/audit/audit-trail.js';
|
|
25
|
+
import type { RemediationAction, RemediationReport } from '../domain/eval/remediation-types.js';
|
|
26
|
+
import type { EvalFinding } from '../domain/eval/eval-to-findings.js';
|
|
27
|
+
import type { LlmPort } from '../ports/llm.port.js';
|
|
28
|
+
import type { LoggerPort } from '../ports/logger.port.js';
|
|
29
|
+
import type { EventBusPort } from '../ports/events.port.js';
|
|
30
|
+
import type { UndoService } from './undo-service.js';
|
|
31
|
+
import type { ScanResult } from '../types/common.types.js';
|
|
32
|
+
import type { AgentPassport } from '../types/passport.types.js';
|
|
33
|
+
import { createEvidence } from '../domain/scanner/evidence.js';
|
|
34
|
+
import { createLogger } from '../infra/logger.js';
|
|
35
|
+
import { backupFile } from './shared/backup.js';
|
|
36
|
+
|
|
37
|
+
// ── Service deps ─────────────────────────────────────────────────
|
|
38
|
+
|
|
39
|
+
export interface EvalServiceDeps {
|
|
40
|
+
readonly getProjectPath: () => string;
|
|
41
|
+
readonly llm?: LlmPort;
|
|
42
|
+
readonly callLlm?: (prompt: string, systemPrompt?: string) => Promise<string>;
|
|
43
|
+
readonly evidenceStore?: EvidenceStore;
|
|
44
|
+
readonly auditStore?: AuditStore;
|
|
45
|
+
/** Optional: auto-sync eval results into agent passport (US-REM-04). */
|
|
46
|
+
readonly updatePassportEval?: (result: EvalResult) => Promise<void>;
|
|
47
|
+
readonly log?: LoggerPort;
|
|
48
|
+
readonly undoService?: UndoService;
|
|
49
|
+
readonly events?: EventBusPort;
|
|
50
|
+
readonly scanService?: { scan: (path: string) => Promise<ScanResult> };
|
|
51
|
+
readonly listPassports?: () => Promise<readonly AgentPassport[]>;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export const createEvalService = (deps: EvalServiceDeps) => {
|
|
55
|
+
const log = deps.log ?? createLogger('eval');
|
|
56
|
+
|
|
57
|
+
// R9: Immutable base runner deps — callLlm resolved per-invocation inside runEval()
|
|
58
|
+
const baseRunnerDeps: Omit<EvalRunnerDeps, 'callLlm'> = {
|
|
59
|
+
getProjectPath: deps.getProjectPath,
|
|
60
|
+
evidenceStore: deps.evidenceStore,
|
|
61
|
+
auditStore: deps.auditStore,
|
|
62
|
+
getSecurityRubric,
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const baseRunner = createEvalRunner({ ...baseRunnerDeps, callLlm: deps.callLlm });
|
|
66
|
+
const scorer: EvalScorer = createConformityScorer();
|
|
67
|
+
|
|
68
|
+
// Lazy-load test sources (avoids importing large data at boot)
|
|
69
|
+
let _testSources: EvalTestSources | null = null;
|
|
70
|
+
const getTestSources = async (): Promise<EvalTestSources> => {
|
|
71
|
+
if (_testSources) return _testSources;
|
|
72
|
+
|
|
73
|
+
const { DETERMINISTIC_TESTS, LLM_JUDGED_TESTS } = await import('../data/eval/index.js');
|
|
74
|
+
const { ATTACK_PROBES } = await import('../data/security/attack-probes.js');
|
|
75
|
+
|
|
76
|
+
_testSources = {
|
|
77
|
+
getDeterministicTests: () => DETERMINISTIC_TESTS,
|
|
78
|
+
getLlmTests: () => LLM_JUDGED_TESTS,
|
|
79
|
+
getSecurityProbes: createSecurityProbeLoader(ATTACK_PROBES),
|
|
80
|
+
};
|
|
81
|
+
return _testSources;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Run a full eval against a target URL.
|
|
86
|
+
*
|
|
87
|
+
* @param options - Eval configuration (target URL, tier, categories, etc.)
|
|
88
|
+
* @param onProgress - Optional progress callback for CLI/SSE
|
|
89
|
+
* @returns Complete eval result
|
|
90
|
+
*/
|
|
91
|
+
const runEval = async (
|
|
92
|
+
options: EvalOptions,
|
|
93
|
+
onProgress?: EvalProgressCallback,
|
|
94
|
+
): Promise<EvalResult> => {
|
|
95
|
+
// Auto-resolve agent if not specified (endpoint match → single-passport fallback)
|
|
96
|
+
let resolvedOptions = options;
|
|
97
|
+
if (!options.agent && deps.listPassports) {
|
|
98
|
+
try {
|
|
99
|
+
const passports = await deps.listPassports();
|
|
100
|
+
// Strategy A: endpoint match (most specific)
|
|
101
|
+
const endpointMatch = passports.find(p =>
|
|
102
|
+
p.endpoints?.some(ep => options.target.startsWith(ep))
|
|
103
|
+
);
|
|
104
|
+
if (endpointMatch) {
|
|
105
|
+
resolvedOptions = { ...options, agent: endpointMatch.name };
|
|
106
|
+
log.info(`Auto-linked to passport: ${endpointMatch.name} (endpoint match)`);
|
|
107
|
+
}
|
|
108
|
+
// Strategy B: single passport fallback
|
|
109
|
+
else if (passports.length === 1) {
|
|
110
|
+
resolvedOptions = { ...options, agent: passports[0]!.name };
|
|
111
|
+
log.info(`Auto-linked to passport: ${passports[0]!.name} (single passport)`);
|
|
112
|
+
}
|
|
113
|
+
} catch { /* non-fatal — proceed without agent */ }
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Detect adapter from target URL
|
|
117
|
+
const adapter: TargetAdapter = await autoDetectAdapter(
|
|
118
|
+
options.target,
|
|
119
|
+
{
|
|
120
|
+
model: options.model,
|
|
121
|
+
apiKey: options.apiKey,
|
|
122
|
+
requestTemplate: options.requestTemplate,
|
|
123
|
+
responsePath: options.responsePath,
|
|
124
|
+
headers: options.headers,
|
|
125
|
+
},
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
const testSources = await getTestSources();
|
|
129
|
+
|
|
130
|
+
// Create LLM judge — priority order:
|
|
131
|
+
// 1. llm-adapter (user's configured model from .complior/.env)
|
|
132
|
+
// 2. Target adapter (same API/key as target)
|
|
133
|
+
// 3. deps.callLlm (composition-root closure)
|
|
134
|
+
let judge: EvalJudge | undefined;
|
|
135
|
+
let effectiveCallLlm = deps.callLlm;
|
|
136
|
+
|
|
137
|
+
// 1. Try llm-adapter — user's own model from .complior/.env
|
|
138
|
+
if (deps.llm) {
|
|
139
|
+
try {
|
|
140
|
+
const routing = deps.llm.routeModel('classify');
|
|
141
|
+
const model = await deps.llm.getModel(routing.provider, routing.modelId);
|
|
142
|
+
const { generateText } = await import('ai');
|
|
143
|
+
const callJudge = async (prompt: string, systemPrompt?: string): Promise<string> => {
|
|
144
|
+
const result = await generateText({ model, prompt, system: systemPrompt, maxTokens: 2048 });
|
|
145
|
+
return result.text;
|
|
146
|
+
};
|
|
147
|
+
await callJudge('Say "ok"');
|
|
148
|
+
judge = createLlmJudge({ callLlm: callJudge });
|
|
149
|
+
effectiveCallLlm = callJudge;
|
|
150
|
+
} catch (error) {
|
|
151
|
+
log.warn(`LLM judge probe failed: ${error instanceof Error ? error.message : error}`);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// 2. Fallback: target adapter (same API as eval target)
|
|
156
|
+
const callLlmViaTarget = (options.apiKey && options.model)
|
|
157
|
+
? async (prompt: string, systemPrompt?: string): Promise<string> => {
|
|
158
|
+
const resp = await adapter.send(prompt, { systemPrompt, temperature: 0, maxTokens: 2048 });
|
|
159
|
+
return resp.text;
|
|
160
|
+
}
|
|
161
|
+
: undefined;
|
|
162
|
+
|
|
163
|
+
if (!judge && callLlmViaTarget) {
|
|
164
|
+
judge = createLlmJudge({ callLlm: callLlmViaTarget });
|
|
165
|
+
effectiveCallLlm = callLlmViaTarget;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// 3. Fallback: deps.callLlm (composition-root closure)
|
|
169
|
+
if (!judge && deps.callLlm) {
|
|
170
|
+
judge = createLlmJudge({ callLlm: deps.callLlm });
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (!judge) {
|
|
174
|
+
log.warn('No LLM judge available. Set an API key in .complior/.env for LLM-judged tests.');
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// R9: Build immutable runner deps per invocation (no mutable closure state)
|
|
178
|
+
const runnerDeps: EvalRunnerDeps = Object.freeze({ ...baseRunnerDeps, callLlm: effectiveCallLlm });
|
|
179
|
+
const effectiveRunner = effectiveCallLlm !== deps.callLlm
|
|
180
|
+
? createEvalRunner(runnerDeps)
|
|
181
|
+
: baseRunner;
|
|
182
|
+
|
|
183
|
+
const result = await effectiveRunner.runEval(adapter, resolvedOptions, testSources, scorer, judge, onProgress);
|
|
184
|
+
|
|
185
|
+
// US-REM-04: Auto-sync eval results into agent passport (non-fatal)
|
|
186
|
+
if (deps.updatePassportEval) {
|
|
187
|
+
try { await deps.updatePassportEval(result); } catch { /* non-fatal */ }
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return result;
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Run eval and return a markdown report.
|
|
195
|
+
*/
|
|
196
|
+
const runEvalWithReport = async (
|
|
197
|
+
options: EvalOptions,
|
|
198
|
+
onProgress?: EvalProgressCallback,
|
|
199
|
+
): Promise<{ result: EvalResult; report: string }> => {
|
|
200
|
+
const result = await runEval(options, onProgress);
|
|
201
|
+
const report = generateEvalReport(result);
|
|
202
|
+
return { result, report };
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Get the passport eval block for a completed eval.
|
|
207
|
+
*/
|
|
208
|
+
const getPassportEvalBlock = (result: EvalResult) =>
|
|
209
|
+
buildPassportEvalBlock(result);
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Merge eval results into a passport.
|
|
213
|
+
*/
|
|
214
|
+
const updatePassportWithEval = (
|
|
215
|
+
passport: Record<string, unknown>,
|
|
216
|
+
result: EvalResult,
|
|
217
|
+
): Record<string, unknown> => {
|
|
218
|
+
const block = buildPassportEvalBlock(result);
|
|
219
|
+
return mergeEvalIntoPassport(passport, block);
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
// Minimal schema for validating persisted eval results
|
|
223
|
+
const EvalResultSchema = z.object({
|
|
224
|
+
target: z.string(),
|
|
225
|
+
overallScore: z.number(),
|
|
226
|
+
grade: z.string(),
|
|
227
|
+
totalTests: z.number(),
|
|
228
|
+
passed: z.number(),
|
|
229
|
+
failed: z.number(),
|
|
230
|
+
results: z.array(z.object({ testId: z.string(), verdict: z.string() }).passthrough()),
|
|
231
|
+
}).passthrough();
|
|
232
|
+
|
|
233
|
+
/** Get last eval result from disk. */
|
|
234
|
+
const getLastResult = async (): Promise<EvalResult | null> => {
|
|
235
|
+
try {
|
|
236
|
+
const latestPath = resolve(deps.getProjectPath(), '.complior', 'eval', 'latest.json');
|
|
237
|
+
const raw = await readFile(latestPath, 'utf-8');
|
|
238
|
+
const parsed = EvalResultSchema.safeParse(JSON.parse(raw));
|
|
239
|
+
if (!parsed.success) {
|
|
240
|
+
log.warn('Invalid eval result on disk:', parsed.error.message);
|
|
241
|
+
return null;
|
|
242
|
+
}
|
|
243
|
+
return parsed.data as unknown as EvalResult;
|
|
244
|
+
} catch {
|
|
245
|
+
return null;
|
|
246
|
+
}
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
/** List eval result filenames (newest first). */
|
|
250
|
+
const listResults = async (): Promise<string[]> => {
|
|
251
|
+
try {
|
|
252
|
+
const evalDir = resolve(deps.getProjectPath(), '.complior', 'eval');
|
|
253
|
+
const files = await readdir(evalDir);
|
|
254
|
+
return files
|
|
255
|
+
.filter((f) => f.startsWith('eval-') && f.endsWith('.json') && f !== 'latest.json')
|
|
256
|
+
.sort()
|
|
257
|
+
.reverse();
|
|
258
|
+
} catch {
|
|
259
|
+
return [];
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
// ── Remediation methods (US-REM-03..10) ─────────────────────
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Get remediation actions for specific test IDs.
|
|
267
|
+
* Lazy-loads remediation data to avoid boot-time import cost.
|
|
268
|
+
*/
|
|
269
|
+
const getRemediationForTests = async (
|
|
270
|
+
testIds: readonly string[],
|
|
271
|
+
results: readonly TestResult[],
|
|
272
|
+
): Promise<Record<string, readonly RemediationAction[]>> => {
|
|
273
|
+
const { ALL_PLAYBOOKS } = await import('../data/eval/remediation/index.js');
|
|
274
|
+
const { getRemediationForTest } = await import('../data/eval/remediation/test-mapping.js');
|
|
275
|
+
|
|
276
|
+
const out: Record<string, readonly RemediationAction[]> = {};
|
|
277
|
+
for (const id of testIds) {
|
|
278
|
+
const result = results.find((r) => r.testId === id);
|
|
279
|
+
const category = result?.category ?? '';
|
|
280
|
+
const owaspCategory = result?.owaspCategory;
|
|
281
|
+
out[id] = getRemediationForTest(id, category, ALL_PLAYBOOKS, owaspCategory);
|
|
282
|
+
}
|
|
283
|
+
return out;
|
|
284
|
+
};
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Generate a full remediation report for a completed eval.
|
|
288
|
+
*/
|
|
289
|
+
const generateRemediationReport = async (
|
|
290
|
+
evalResult: EvalResult,
|
|
291
|
+
): Promise<RemediationReport> => {
|
|
292
|
+
const { ALL_PLAYBOOKS } = await import('../data/eval/remediation/index.js');
|
|
293
|
+
const { generateRemediationReport: genReport } = await import('../domain/eval/eval-remediation-report.js');
|
|
294
|
+
|
|
295
|
+
const { isFailedVerdict } = await import('../domain/eval/verdict-utils.js');
|
|
296
|
+
// Get remediation for all failures
|
|
297
|
+
const failures = evalResult.results.filter(isFailedVerdict);
|
|
298
|
+
const failedIds = failures.map((f) => f.testId);
|
|
299
|
+
const remediation = await getRemediationForTests(failedIds, evalResult.results);
|
|
300
|
+
|
|
301
|
+
return genReport(evalResult, remediation, ALL_PLAYBOOKS);
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Convert eval failures into scanner Finding format for fix pipeline (US-REM-09).
|
|
306
|
+
*/
|
|
307
|
+
const getEvalFindings = async (
|
|
308
|
+
evalResult: EvalResult,
|
|
309
|
+
): Promise<readonly EvalFinding[]> => {
|
|
310
|
+
const { ALL_PLAYBOOKS } = await import('../data/eval/remediation/index.js');
|
|
311
|
+
const { evalToFindings } = await import('../domain/eval/eval-to-findings.js');
|
|
312
|
+
return evalToFindings(evalResult, ALL_PLAYBOOKS);
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
// R4: Render remediation report markdown via service (route should not import domain).
|
|
316
|
+
const getRemediationReportMarkdown = async (): Promise<string> => {
|
|
317
|
+
const { renderRemediationMarkdown } = await import('../domain/eval/eval-remediation-report.js');
|
|
318
|
+
const result = await getLastResult();
|
|
319
|
+
if (!result) return '# No eval results found';
|
|
320
|
+
const report = await generateRemediationReport(result);
|
|
321
|
+
return renderRemediationMarkdown(report);
|
|
322
|
+
};
|
|
323
|
+
|
|
324
|
+
// R5: Check if an LLM judge API key is configured (service reads env, not route).
|
|
325
|
+
const isJudgeConfigured = (): boolean => {
|
|
326
|
+
return !!(process.env.OPENROUTER_API_KEY || process.env.ANTHROPIC_API_KEY || process.env.OPENAI_API_KEY);
|
|
327
|
+
};
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Apply eval fixes: only Type B (config/file creation) findings.
|
|
331
|
+
* Type A (system-prompt) findings are returned as manual guidance.
|
|
332
|
+
* R1: Records undo history, evidence chain, and emits score.updated event.
|
|
333
|
+
*/
|
|
334
|
+
const applyEvalFixes = async (): Promise<{
|
|
335
|
+
applied: readonly { checkId: string; file: string; type: 'B' }[];
|
|
336
|
+
manual: readonly { checkId: string; title: string; fixDescription: string; type: 'A' }[];
|
|
337
|
+
}> => {
|
|
338
|
+
const evalResult = await getLastResult();
|
|
339
|
+
if (!evalResult) {
|
|
340
|
+
return { applied: [], manual: [] };
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
const findings = await getEvalFindings(evalResult);
|
|
344
|
+
|
|
345
|
+
const applied: { checkId: string; file: string; type: 'B' }[] = [];
|
|
346
|
+
const manual: { checkId: string; title: string; fixDescription: string; type: 'A' }[] = [];
|
|
347
|
+
const projectPath = deps.getProjectPath();
|
|
348
|
+
|
|
349
|
+
// Capture score before applying fixes
|
|
350
|
+
let scoreBefore = 0;
|
|
351
|
+
if (deps.scanService) {
|
|
352
|
+
try {
|
|
353
|
+
const scan = await deps.scanService.scan(projectPath);
|
|
354
|
+
scoreBefore = scan.score.totalScore;
|
|
355
|
+
} catch { /* non-fatal */ }
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
for (const finding of findings) {
|
|
359
|
+
if (finding.type === 'A') {
|
|
360
|
+
// System prompt patches — can't auto-apply, return as guidance
|
|
361
|
+
manual.push({
|
|
362
|
+
checkId: finding.checkId,
|
|
363
|
+
title: finding.title,
|
|
364
|
+
fixDescription: finding.fixDescription,
|
|
365
|
+
type: 'A',
|
|
366
|
+
});
|
|
367
|
+
} else {
|
|
368
|
+
// Type B — create config/fix files
|
|
369
|
+
const fullPath = resolve(projectPath, finding.file);
|
|
370
|
+
try {
|
|
371
|
+
await mkdir(dirname(fullPath), { recursive: true });
|
|
372
|
+
|
|
373
|
+
// R3: Use shared backup utility
|
|
374
|
+
await backupFile(finding.file, projectPath);
|
|
375
|
+
|
|
376
|
+
// Write the fix content
|
|
377
|
+
const content = JSON.stringify({
|
|
378
|
+
checkId: finding.checkId,
|
|
379
|
+
article: finding.article,
|
|
380
|
+
description: finding.description,
|
|
381
|
+
fixDescription: finding.fixDescription,
|
|
382
|
+
fixExample: finding.fixExample,
|
|
383
|
+
generatedAt: new Date().toISOString(),
|
|
384
|
+
}, null, 2);
|
|
385
|
+
await writeFile(fullPath, content, 'utf-8');
|
|
386
|
+
|
|
387
|
+
applied.push({
|
|
388
|
+
checkId: finding.checkId,
|
|
389
|
+
file: finding.file,
|
|
390
|
+
type: 'B',
|
|
391
|
+
});
|
|
392
|
+
} catch (err) {
|
|
393
|
+
log.warn(`Failed to apply eval fix for ${finding.checkId}: ${err instanceof Error ? err.message : err}`);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
// R1: Post-apply — re-scan, record undo history, append evidence, emit event
|
|
399
|
+
let scoreAfter = scoreBefore;
|
|
400
|
+
if (applied.length > 0 && deps.scanService) {
|
|
401
|
+
try {
|
|
402
|
+
const scan = await deps.scanService.scan(projectPath);
|
|
403
|
+
scoreAfter = scan.score.totalScore;
|
|
404
|
+
} catch { /* non-fatal */ }
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
for (const fix of applied) {
|
|
408
|
+
// Record undo history
|
|
409
|
+
if (deps.undoService) {
|
|
410
|
+
try {
|
|
411
|
+
const plan = {
|
|
412
|
+
checkId: fix.checkId,
|
|
413
|
+
obligationId: '',
|
|
414
|
+
fixType: 'config_fix' as const,
|
|
415
|
+
article: '',
|
|
416
|
+
description: 'Eval fix',
|
|
417
|
+
framework: '',
|
|
418
|
+
actions: [{ type: 'create' as const, path: fix.file }],
|
|
419
|
+
diff: '',
|
|
420
|
+
scoreImpact: 0,
|
|
421
|
+
commitMessage: '',
|
|
422
|
+
};
|
|
423
|
+
await deps.undoService.recordFix(
|
|
424
|
+
{ plan, applied: true, scoreBefore, scoreAfter, backedUpFiles: [] },
|
|
425
|
+
plan,
|
|
426
|
+
);
|
|
427
|
+
} catch { /* non-fatal */ }
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
// Append evidence
|
|
431
|
+
if (deps.evidenceStore) {
|
|
432
|
+
try {
|
|
433
|
+
const evidence = createEvidence(fix.checkId, 'eval-fix', 'fix', { file: fix.file });
|
|
434
|
+
await deps.evidenceStore.append([evidence], randomUUID());
|
|
435
|
+
} catch { /* non-fatal */ }
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// Emit score update event
|
|
440
|
+
if (applied.length > 0 && deps.events) {
|
|
441
|
+
deps.events.emit('score.updated', { before: scoreBefore, after: scoreAfter });
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
return { applied, manual };
|
|
445
|
+
};
|
|
446
|
+
|
|
447
|
+
return Object.freeze({
|
|
448
|
+
runEval,
|
|
449
|
+
runEvalWithReport,
|
|
450
|
+
getPassportEvalBlock,
|
|
451
|
+
updatePassportWithEval,
|
|
452
|
+
getLastResult,
|
|
453
|
+
listResults,
|
|
454
|
+
getRemediationForTests,
|
|
455
|
+
generateRemediationReport,
|
|
456
|
+
getEvalFindings,
|
|
457
|
+
applyEvalFixes,
|
|
458
|
+
getRemediationReportMarkdown,
|
|
459
|
+
isJudgeConfigured,
|
|
460
|
+
});
|
|
461
|
+
};
|
|
462
|
+
|
|
463
|
+
export type EvalService = ReturnType<typeof createEvalService>;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { mkdir, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
import type { EventBusPort } from '../ports/events.port.js';
|
|
4
|
+
import type { BrowserPort } from '../ports/browser.port.js';
|
|
5
|
+
import type { ExternalScanConfig, ExternalScanResult } from '../domain/scanner/external/types.js';
|
|
6
|
+
import { runL1Checks, buildExternalScanResult } from '../domain/scanner/external/external-scanner.js';
|
|
7
|
+
|
|
8
|
+
export interface ExternalScanServiceDeps {
|
|
9
|
+
readonly browser: BrowserPort;
|
|
10
|
+
readonly events: EventBusPort;
|
|
11
|
+
readonly getProjectPath: () => string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const createExternalScanService = (deps: ExternalScanServiceDeps) => {
|
|
15
|
+
const { browser, events, getProjectPath } = deps;
|
|
16
|
+
|
|
17
|
+
const scan = async (config: ExternalScanConfig): Promise<ExternalScanResult> => {
|
|
18
|
+
const start = Date.now();
|
|
19
|
+
|
|
20
|
+
// L1: Passive Crawl (L2/L3 planned for future)
|
|
21
|
+
const page = await browser.crawl(config.url, config.timeout);
|
|
22
|
+
|
|
23
|
+
const checks = runL1Checks(page);
|
|
24
|
+
|
|
25
|
+
// Save screenshot
|
|
26
|
+
const screenshots: string[] = [];
|
|
27
|
+
const scansDir = resolve(getProjectPath(), '.complior', 'external-scans');
|
|
28
|
+
await mkdir(scansDir, { recursive: true });
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
const screenshotPath = resolve(
|
|
32
|
+
config.screenshotsDir ?? scansDir,
|
|
33
|
+
`screenshot-${Date.now()}.png`,
|
|
34
|
+
);
|
|
35
|
+
await browser.screenshot(config.url, screenshotPath);
|
|
36
|
+
screenshots.push(screenshotPath);
|
|
37
|
+
} catch {
|
|
38
|
+
// screenshot is best-effort
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const duration = Date.now() - start;
|
|
42
|
+
const result = buildExternalScanResult(config.url, checks, screenshots, duration);
|
|
43
|
+
|
|
44
|
+
// Persist result
|
|
45
|
+
const resultPath = resolve(scansDir, `scan-${Date.now()}.json`);
|
|
46
|
+
await writeFile(resultPath, JSON.stringify(result, null, 2));
|
|
47
|
+
|
|
48
|
+
events.emit('external-scan.completed', { url: config.url, score: result.score });
|
|
49
|
+
|
|
50
|
+
return result;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const close = async (): Promise<void> => {
|
|
54
|
+
await browser.close();
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
return Object.freeze({ scan, close });
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export type ExternalScanService = ReturnType<typeof createExternalScanService>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { createFile, editFile, readFile, listFiles } from '../infra/file-ops-adapter.js';
|
|
2
|
+
import { search } from '../infra/search-adapter.js';
|
|
3
|
+
import type { EventBusPort } from '../ports/events.port.js';
|
|
4
|
+
|
|
5
|
+
export interface FileServiceDeps {
|
|
6
|
+
readonly events: EventBusPort;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const createFileService = (deps: FileServiceDeps) => {
|
|
10
|
+
const { events } = deps;
|
|
11
|
+
|
|
12
|
+
const create = async (path: string, content: string): Promise<void> => {
|
|
13
|
+
await createFile(path, content);
|
|
14
|
+
events.emit('file.changed', { path, action: 'create' });
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const edit = async (path: string, oldContent: string, newContent: string): Promise<void> => {
|
|
18
|
+
await editFile(path, oldContent, newContent);
|
|
19
|
+
events.emit('file.changed', { path, action: 'edit' });
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const read = async (path: string): Promise<string> => {
|
|
23
|
+
return readFile(path);
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const list = async (dirPath: string, pattern?: string): Promise<readonly string[]> => {
|
|
27
|
+
return listFiles(dirPath, pattern);
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const searchCode = async (pattern: string, searchPath: string) => {
|
|
31
|
+
return search(pattern, searchPath);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
return Object.freeze({ create, edit, read, list, searchCode });
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export type FileService = ReturnType<typeof createFileService>;
|