@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,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for detectWeakSections() and buildL2Feedback() pure functions.
|
|
3
|
+
*/
|
|
4
|
+
import { describe, it, expect } from 'vitest';
|
|
5
|
+
import { detectWeakSections, buildL2Feedback } from './ai-enricher.js';
|
|
6
|
+
|
|
7
|
+
const STRONG_DOC = `## Risk Identification
|
|
8
|
+
|
|
9
|
+
We have identified 15 key risks through our systematic risk assessment process conducted in Q1 2026.
|
|
10
|
+
Each risk was evaluated using the ISO 31000:2018 framework, with probability scores assigned on a 1-5 scale.
|
|
11
|
+
The top 3 risks relate to bias (P=0.4, I=High), data quality (P=0.3, I=Medium), and model drift (P=0.25, I=High).
|
|
12
|
+
Under Art. 9 of the EU AI Act (Regulation 2024/1689), providers must maintain a risk management system.
|
|
13
|
+
|
|
14
|
+
## Mitigation Measures
|
|
15
|
+
|
|
16
|
+
For each identified risk, we implement specific mitigation controls:
|
|
17
|
+
- Bias: Monthly fairness audits using Aequitas toolkit, targeting <2% demographic parity gap
|
|
18
|
+
- Data quality: Automated data validation pipeline with 99.5% accuracy threshold
|
|
19
|
+
- Model drift: Weekly model monitoring with KL-divergence alerts at >0.05
|
|
20
|
+
|
|
21
|
+
## Monitoring Plan
|
|
22
|
+
|
|
23
|
+
Continuous monitoring via Prometheus dashboards with the following KPIs:
|
|
24
|
+
1. False positive rate: target <5% (current: 3.2%)
|
|
25
|
+
2. Latency p99: target <200ms (current: 145ms)
|
|
26
|
+
3. Drift score: target <0.05 (current: 0.02)
|
|
27
|
+
Reviews conducted quarterly per Art. 9(8) requirements.
|
|
28
|
+
`;
|
|
29
|
+
|
|
30
|
+
const WEAK_DOC = `## Risk Identification
|
|
31
|
+
|
|
32
|
+
We assess risks.
|
|
33
|
+
|
|
34
|
+
## Mitigation Measures
|
|
35
|
+
|
|
36
|
+
[TODO: Add mitigation measures]
|
|
37
|
+
|
|
38
|
+
## Monitoring Plan
|
|
39
|
+
|
|
40
|
+
Monitoring will be done.
|
|
41
|
+
`;
|
|
42
|
+
|
|
43
|
+
const MIXED_DOC = `## System Description
|
|
44
|
+
|
|
45
|
+
Our AI system processes customer support tickets using a fine-tuned GPT-4 model.
|
|
46
|
+
It classifies tickets into 12 categories with 94.2% accuracy (validated on 10,000 test samples).
|
|
47
|
+
The system handles approximately 50,000 tickets per day with p99 latency of 180ms.
|
|
48
|
+
Deployed on AWS eu-west-1 region per Art. 11 requirements.
|
|
49
|
+
|
|
50
|
+
## Intended Purpose
|
|
51
|
+
|
|
52
|
+
This system helps with customer support.
|
|
53
|
+
|
|
54
|
+
## Performance Metrics
|
|
55
|
+
|
|
56
|
+
[TODO: Fill in performance benchmarks]
|
|
57
|
+
`;
|
|
58
|
+
|
|
59
|
+
describe('detectWeakSections', () => {
|
|
60
|
+
it('returns empty array for fully-populated document', () => {
|
|
61
|
+
const weak = detectWeakSections(STRONG_DOC);
|
|
62
|
+
expect(weak).toEqual([]);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('detects weak sections in placeholder-heavy document', () => {
|
|
66
|
+
const weak = detectWeakSections(WEAK_DOC);
|
|
67
|
+
expect(weak.length).toBeGreaterThan(0);
|
|
68
|
+
// Should detect sections with placeholders or very short content
|
|
69
|
+
expect(weak.some(s => s.toLowerCase().includes('mitigation'))).toBe(true);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('detects mix of strong and weak sections', () => {
|
|
73
|
+
const weak = detectWeakSections(MIXED_DOC);
|
|
74
|
+
// System Description is strong, others are weak
|
|
75
|
+
expect(weak.some(s => s.toLowerCase().includes('intended purpose') || s.toLowerCase().includes('performance'))).toBe(true);
|
|
76
|
+
// System Description should NOT be in weak list
|
|
77
|
+
expect(weak.some(s => s.toLowerCase() === 'system description')).toBe(false);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('returns empty for empty content', () => {
|
|
81
|
+
const weak = detectWeakSections('');
|
|
82
|
+
expect(weak).toEqual([]);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('returns empty for content with no headings', () => {
|
|
86
|
+
const weak = detectWeakSections('Just a paragraph with no markdown headings at all.');
|
|
87
|
+
expect(weak).toEqual([]);
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
describe('buildL2Feedback', () => {
|
|
92
|
+
it('returns "All sections appear adequate" for strong document', () => {
|
|
93
|
+
const feedback = buildL2Feedback(STRONG_DOC);
|
|
94
|
+
expect(feedback).toBe('All sections appear adequate.');
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('lists specific issues for weak document', () => {
|
|
98
|
+
const feedback = buildL2Feedback(WEAK_DOC);
|
|
99
|
+
expect(feedback).not.toBe('All sections appear adequate.');
|
|
100
|
+
// Should contain bullet points with section names
|
|
101
|
+
expect(feedback).toContain('-');
|
|
102
|
+
expect(feedback).toContain('"');
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('mentions placeholder count for sections with TODOs', () => {
|
|
106
|
+
const feedback = buildL2Feedback(WEAK_DOC);
|
|
107
|
+
expect(feedback).toMatch(/placeholder/i);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it('mentions word count for very short sections', () => {
|
|
111
|
+
const feedback = buildL2Feedback(WEAK_DOC);
|
|
112
|
+
expect(feedback).toMatch(/words/i);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('returns feedback only for weak sections in mixed doc', () => {
|
|
116
|
+
const feedback = buildL2Feedback(MIXED_DOC);
|
|
117
|
+
// Should have feedback for weak sections but not System Description
|
|
118
|
+
expect(feedback).not.toBe('All sections appear adequate.');
|
|
119
|
+
});
|
|
120
|
+
});
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LLM-enriched document generation.
|
|
3
|
+
* Two modes:
|
|
4
|
+
* 1. Scaffold enrichment — fill [TODO] placeholders in freshly generated docs
|
|
5
|
+
* 2. Draft enhancement — improve existing user-edited docs using L2 quality feedback
|
|
6
|
+
* Extracted from document-generator.ts for SRP compliance.
|
|
7
|
+
*/
|
|
8
|
+
import type { LanguageModel } from 'ai';
|
|
9
|
+
import type { AgentPassport } from '../../types/passport.types.js';
|
|
10
|
+
import type { DocResult } from './document-generator.js';
|
|
11
|
+
import { extractSectionContents, measureSemanticDepth } from '../scanner/layers/layer2-parsing.js';
|
|
12
|
+
|
|
13
|
+
export interface AiEnrichInput {
|
|
14
|
+
readonly baseResult: DocResult;
|
|
15
|
+
readonly manifest: AgentPassport;
|
|
16
|
+
readonly model: LanguageModel;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface AiEnrichedResult extends DocResult {
|
|
20
|
+
readonly aiEnriched: true;
|
|
21
|
+
readonly aiFieldsCount: number;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Analyze existing document content to find weak sections via L2 semantic depth.
|
|
26
|
+
* Returns section names + actionable feedback for sections scoring below threshold.
|
|
27
|
+
*/
|
|
28
|
+
export const detectWeakSections = (content: string): readonly string[] => {
|
|
29
|
+
const sections = extractSectionContents(content);
|
|
30
|
+
const weak: string[] = [];
|
|
31
|
+
for (const [heading, body] of sections) {
|
|
32
|
+
const depth = measureSemanticDepth(body, heading);
|
|
33
|
+
if (depth.isShallow || depth.placeholderCount > 0) {
|
|
34
|
+
weak.push(heading);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return weak;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Build L2-informed feedback for the LLM prompt.
|
|
42
|
+
* Tells the LLM exactly which sections need improvement and why.
|
|
43
|
+
*/
|
|
44
|
+
export const buildL2Feedback = (content: string): string => {
|
|
45
|
+
const sections = extractSectionContents(content);
|
|
46
|
+
const feedback: string[] = [];
|
|
47
|
+
for (const [heading, body] of sections) {
|
|
48
|
+
const depth = measureSemanticDepth(body, heading);
|
|
49
|
+
if (depth.isShallow || depth.placeholderCount > 0) {
|
|
50
|
+
const reasons: string[] = [];
|
|
51
|
+
if (depth.placeholderCount > 0) reasons.push(`${depth.placeholderCount} placeholder(s) to fill`);
|
|
52
|
+
if (depth.wordCount < 50) reasons.push(`only ${depth.wordCount} words (min 50)`);
|
|
53
|
+
if (!depth.hasNumericMetrics) reasons.push('no numeric metrics');
|
|
54
|
+
if (!depth.hasLegalReferences) reasons.push('no legal references');
|
|
55
|
+
if (!depth.hasMeasurableTargets) reasons.push('no measurable targets');
|
|
56
|
+
feedback.push(`- "${heading}": ${reasons.join(', ')}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return feedback.length > 0 ? feedback.join('\n') : 'All sections appear adequate.';
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const buildPassportContext = (manifest: AgentPassport): string =>
|
|
63
|
+
[
|
|
64
|
+
`System: ${manifest.display_name}`,
|
|
65
|
+
`Description: ${manifest.description}`,
|
|
66
|
+
`Risk class: ${manifest.compliance?.eu_ai_act?.risk_class ?? 'unknown'}`,
|
|
67
|
+
`Autonomy: ${manifest.autonomy_level}`,
|
|
68
|
+
`Provider: ${manifest.model?.provider ?? 'unknown'}`,
|
|
69
|
+
`Model: ${manifest.model?.model_id ?? 'unknown'}`,
|
|
70
|
+
manifest.owner?.team ? `Organization: ${manifest.owner.team}` : '',
|
|
71
|
+
manifest.oversight?.responsible_person ? `Oversight: ${manifest.oversight.responsible_person} (${manifest.oversight.role})` : '',
|
|
72
|
+
manifest.permissions?.tools ? `Tools: ${(manifest.permissions.tools as readonly string[]).join(', ')}` : '',
|
|
73
|
+
manifest.constraints?.prohibited_actions ? `Prohibited: ${(manifest.constraints.prohibited_actions as readonly string[]).join(', ')}` : '',
|
|
74
|
+
].filter(Boolean).join('\n');
|
|
75
|
+
|
|
76
|
+
const buildSystemPrompt = (docType: string, mode: 'scaffold' | 'enhance'): string => {
|
|
77
|
+
const modeRules = mode === 'scaffold'
|
|
78
|
+
? `- Fill in placeholder sections (marked with <!-- GUIDANCE --> comments or containing generic "[...]" placeholders) with specific content based on the passport data
|
|
79
|
+
- Keep all existing filled content intact — do NOT modify already pre-filled fields`
|
|
80
|
+
: `- The document has been partially filled by the user — preserve ALL existing content
|
|
81
|
+
- Strengthen weak sections identified in the quality feedback below
|
|
82
|
+
- Add numeric metrics, legal references (Art. numbers), measurable targets, and specific details
|
|
83
|
+
- Expand thin sections with concrete, actionable content based on the passport data`;
|
|
84
|
+
|
|
85
|
+
return `You are a compliance document specialist for the EU AI Act (Regulation 2024/1689).
|
|
86
|
+
You are ${mode === 'scaffold' ? 'enriching' : 'strengthening'} a ${docType} document based on the AI system's passport data.
|
|
87
|
+
|
|
88
|
+
Rules:
|
|
89
|
+
${modeRules}
|
|
90
|
+
- For legal assertions that require human sign-off (signatures, legal declarations, notified body details), replace with [REVIEW REQUIRED: brief description of what's needed]
|
|
91
|
+
- Use professional regulatory language appropriate for EU AI Act compliance documentation
|
|
92
|
+
- Be specific and actionable — reference the actual system name, risk class, and capabilities
|
|
93
|
+
- Do NOT invent data that isn't in the passport (dates, test results, metrics) — use [TO BE COMPLETED: description] for those
|
|
94
|
+
- Keep the exact Markdown structure and heading hierarchy`;
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Enriches a compliance document via LLM.
|
|
99
|
+
* Two modes detected automatically:
|
|
100
|
+
* - Scaffold: document has [TODO]/placeholder brackets → fill them
|
|
101
|
+
* - Enhance: document has real content but weak sections → strengthen with specifics
|
|
102
|
+
* Human-required legal assertions are left with [REVIEW REQUIRED].
|
|
103
|
+
*/
|
|
104
|
+
export const enrichDocumentWithAI = async (input: AiEnrichInput): Promise<AiEnrichedResult> => {
|
|
105
|
+
const { baseResult, manifest, model } = input;
|
|
106
|
+
const { generateText } = await import('ai');
|
|
107
|
+
|
|
108
|
+
const passportContext = buildPassportContext(manifest);
|
|
109
|
+
|
|
110
|
+
// Auto-detect mode: scaffold (has placeholders) vs enhance (user-edited, no placeholders)
|
|
111
|
+
const hasPlaceholders = /\[[^\]]{2,60}\](?!\()/.test(baseResult.markdown);
|
|
112
|
+
const mode: 'scaffold' | 'enhance' = hasPlaceholders ? 'scaffold' : 'enhance';
|
|
113
|
+
|
|
114
|
+
const systemPrompt = buildSystemPrompt(baseResult.docType, mode);
|
|
115
|
+
const l2Feedback = buildL2Feedback(baseResult.markdown);
|
|
116
|
+
|
|
117
|
+
const prompt = mode === 'scaffold'
|
|
118
|
+
? `Here is the AI system passport data:
|
|
119
|
+
${passportContext}
|
|
120
|
+
|
|
121
|
+
Here are the manual fields that need enrichment: ${baseResult.manualFields.join(', ')}
|
|
122
|
+
|
|
123
|
+
Here is the document to enrich:
|
|
124
|
+
${baseResult.markdown}
|
|
125
|
+
|
|
126
|
+
Return the complete enriched document (full Markdown). Keep all existing content, enrich unfilled sections.`
|
|
127
|
+
: `Here is the AI system passport data:
|
|
128
|
+
${passportContext}
|
|
129
|
+
|
|
130
|
+
Quality analysis of weak sections that need strengthening:
|
|
131
|
+
${l2Feedback}
|
|
132
|
+
|
|
133
|
+
Here is the document to improve:
|
|
134
|
+
${baseResult.markdown}
|
|
135
|
+
|
|
136
|
+
Return the complete improved document (full Markdown). Preserve all existing content. Strengthen the weak sections identified above with specific details, metrics, and legal references.`;
|
|
137
|
+
|
|
138
|
+
try {
|
|
139
|
+
const result = await generateText({ model, system: systemPrompt, prompt });
|
|
140
|
+
const marker = `\n\n<!-- complior:reviewed ${new Date().toISOString()} -->`;
|
|
141
|
+
const enrichedMarkdown = result.text.trim() + marker;
|
|
142
|
+
|
|
143
|
+
// Count how many fields were likely addressed
|
|
144
|
+
const remainingPlaceholders = (enrichedMarkdown.match(/\[(?:TO BE COMPLETED|REVIEW REQUIRED)[^\]]*\]/g) ?? []).length;
|
|
145
|
+
const aiFieldsCount = Math.max(0, baseResult.manualFields.length - remainingPlaceholders);
|
|
146
|
+
|
|
147
|
+
return Object.freeze({
|
|
148
|
+
markdown: enrichedMarkdown,
|
|
149
|
+
docType: baseResult.docType,
|
|
150
|
+
prefilledFields: Object.freeze([...baseResult.prefilledFields]),
|
|
151
|
+
manualFields: Object.freeze([...baseResult.manualFields]),
|
|
152
|
+
aiEnriched: true as const,
|
|
153
|
+
aiFieldsCount,
|
|
154
|
+
});
|
|
155
|
+
} catch (err) {
|
|
156
|
+
// Re-throw so caller (fix-service) can handle and log the error
|
|
157
|
+
throw new Error(`AI enrichment failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
158
|
+
}
|
|
159
|
+
};
|
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { generateDocument, ALL_DOC_TYPES, TEMPLATE_FILE_MAP } from './document-generator.js';
|
|
3
|
+
import type { DocType } from './document-generator.js';
|
|
4
|
+
import type { AgentPassport } from '../../types/passport.types.js';
|
|
5
|
+
|
|
6
|
+
const createMockPassport = (overrides?: Partial<AgentPassport>): AgentPassport =>
|
|
7
|
+
({
|
|
8
|
+
agent_id: 'test-agent-001',
|
|
9
|
+
name: 'test-agent',
|
|
10
|
+
display_name: 'Test AI Agent',
|
|
11
|
+
version: '1.0.0',
|
|
12
|
+
description: 'A test AI agent for compliance scanning',
|
|
13
|
+
type: 'assistant',
|
|
14
|
+
framework: 'openai',
|
|
15
|
+
autonomy_level: 'L2',
|
|
16
|
+
model: {
|
|
17
|
+
provider: 'OpenAI',
|
|
18
|
+
model_id: 'gpt-4o',
|
|
19
|
+
},
|
|
20
|
+
owner: {
|
|
21
|
+
team: 'Acme Corp',
|
|
22
|
+
responsible_person: 'Jane Doe',
|
|
23
|
+
},
|
|
24
|
+
compliance: {
|
|
25
|
+
eu_ai_act: {
|
|
26
|
+
risk_class: 'high',
|
|
27
|
+
},
|
|
28
|
+
complior_score: 72,
|
|
29
|
+
},
|
|
30
|
+
constraints: {
|
|
31
|
+
human_approval_required: ['deploy', 'delete'],
|
|
32
|
+
escalation_rules: [],
|
|
33
|
+
},
|
|
34
|
+
autonomy_evidence: {
|
|
35
|
+
human_approval_gates: 3,
|
|
36
|
+
unsupervised_actions: 1,
|
|
37
|
+
no_logging_actions: 0,
|
|
38
|
+
auto_rated: false,
|
|
39
|
+
},
|
|
40
|
+
permissions: {
|
|
41
|
+
tools: ['read_file', 'write_file'],
|
|
42
|
+
denied: ['execute_shell'],
|
|
43
|
+
},
|
|
44
|
+
source_files: [],
|
|
45
|
+
signature: { value: '', publicKey: '', algorithm: 'ed25519' },
|
|
46
|
+
created: '2026-01-01T00:00:00Z',
|
|
47
|
+
updated: '2026-01-01T00:00:00Z',
|
|
48
|
+
...overrides,
|
|
49
|
+
}) as unknown as AgentPassport;
|
|
50
|
+
|
|
51
|
+
const SIMPLE_TEMPLATE = `# Test Document
|
|
52
|
+
| Company | [Company Name] |
|
|
53
|
+
| Date | [Date] |
|
|
54
|
+
| System | [AI System Name] |
|
|
55
|
+
| Provider | [Provider] |
|
|
56
|
+
| Version | [X.Y] |
|
|
57
|
+
| Risk | [Risk Class] |
|
|
58
|
+
`;
|
|
59
|
+
|
|
60
|
+
describe('document-generator', () => {
|
|
61
|
+
describe('ALL_DOC_TYPES', () => {
|
|
62
|
+
it('contains exactly 14 document types', () => {
|
|
63
|
+
expect(ALL_DOC_TYPES).toHaveLength(14);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('maps each type to a template file', () => {
|
|
67
|
+
for (const dt of ALL_DOC_TYPES) {
|
|
68
|
+
expect(TEMPLATE_FILE_MAP[dt]).toBeDefined();
|
|
69
|
+
expect(TEMPLATE_FILE_MAP[dt]).toMatch(/\.md$/);
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
describe('generateDocument — common placeholders', () => {
|
|
75
|
+
it('replaces [Company Name] with organization override', () => {
|
|
76
|
+
const result = generateDocument({
|
|
77
|
+
manifest: createMockPassport(),
|
|
78
|
+
template: SIMPLE_TEMPLATE,
|
|
79
|
+
docType: 'ai-literacy',
|
|
80
|
+
organization: 'Override Corp',
|
|
81
|
+
});
|
|
82
|
+
expect(result.markdown).toContain('Override Corp');
|
|
83
|
+
expect(result.markdown).not.toContain('[Company Name]');
|
|
84
|
+
expect(result.prefilledFields).toContain('Company Name');
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('replaces [Company Name] with manifest.owner.team when no organization', () => {
|
|
88
|
+
const result = generateDocument({
|
|
89
|
+
manifest: createMockPassport(),
|
|
90
|
+
template: SIMPLE_TEMPLATE,
|
|
91
|
+
docType: 'ai-literacy',
|
|
92
|
+
});
|
|
93
|
+
expect(result.markdown).toContain('Acme Corp');
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('marks Company Name as manual when missing', () => {
|
|
97
|
+
const passport = createMockPassport({ owner: { team: '' } } as any);
|
|
98
|
+
const result = generateDocument({
|
|
99
|
+
manifest: passport,
|
|
100
|
+
template: SIMPLE_TEMPLATE,
|
|
101
|
+
docType: 'ai-literacy',
|
|
102
|
+
});
|
|
103
|
+
expect(result.manualFields).toContain('Company Name');
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('replaces [Date] with today ISO', () => {
|
|
107
|
+
const result = generateDocument({
|
|
108
|
+
manifest: createMockPassport(),
|
|
109
|
+
template: SIMPLE_TEMPLATE,
|
|
110
|
+
docType: 'ai-literacy',
|
|
111
|
+
});
|
|
112
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
113
|
+
expect(result.markdown).toContain(today);
|
|
114
|
+
expect(result.markdown).not.toContain('[Date]');
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it('replaces [AI System Name]', () => {
|
|
118
|
+
const result = generateDocument({
|
|
119
|
+
manifest: createMockPassport(),
|
|
120
|
+
template: SIMPLE_TEMPLATE,
|
|
121
|
+
docType: 'ai-literacy',
|
|
122
|
+
});
|
|
123
|
+
expect(result.markdown).toContain('Test AI Agent');
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it('replaces [Provider]', () => {
|
|
127
|
+
const result = generateDocument({
|
|
128
|
+
manifest: createMockPassport(),
|
|
129
|
+
template: SIMPLE_TEMPLATE,
|
|
130
|
+
docType: 'ai-literacy',
|
|
131
|
+
});
|
|
132
|
+
expect(result.markdown).toContain('OpenAI');
|
|
133
|
+
expect(result.markdown).not.toContain('| Provider | [Provider] |');
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it('replaces [X.Y] with version', () => {
|
|
137
|
+
const result = generateDocument({
|
|
138
|
+
manifest: createMockPassport(),
|
|
139
|
+
template: SIMPLE_TEMPLATE,
|
|
140
|
+
docType: 'ai-literacy',
|
|
141
|
+
});
|
|
142
|
+
expect(result.markdown).toContain('1.0.0');
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it('replaces [Risk Class]', () => {
|
|
146
|
+
const result = generateDocument({
|
|
147
|
+
manifest: createMockPassport(),
|
|
148
|
+
template: SIMPLE_TEMPLATE,
|
|
149
|
+
docType: 'ai-literacy',
|
|
150
|
+
});
|
|
151
|
+
expect(result.markdown).toContain('high');
|
|
152
|
+
expect(result.markdown).not.toContain('[Risk Class]');
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
describe('generateDocument — document ID replacement', () => {
|
|
157
|
+
it('replaces ALP-[YYYY]-[NNN] for ai-literacy', () => {
|
|
158
|
+
const template = '| Document ID | ALP-[YYYY]-[NNN] |';
|
|
159
|
+
const result = generateDocument({
|
|
160
|
+
manifest: createMockPassport(),
|
|
161
|
+
template,
|
|
162
|
+
docType: 'ai-literacy',
|
|
163
|
+
});
|
|
164
|
+
expect(result.markdown).toMatch(/ALP-\d{4}-\d{3}/);
|
|
165
|
+
expect(result.markdown).not.toContain('[YYYY]');
|
|
166
|
+
expect(result.prefilledFields).toContain('Document ID');
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it('replaces ART5-[YYYY]-[NNN] for art5-screening', () => {
|
|
170
|
+
const template = '| Report ID | ART5-[YYYY]-[NNN] |';
|
|
171
|
+
const result = generateDocument({
|
|
172
|
+
manifest: createMockPassport(),
|
|
173
|
+
template,
|
|
174
|
+
docType: 'art5-screening',
|
|
175
|
+
});
|
|
176
|
+
expect(result.markdown).toMatch(/ART5-\d{4}-\d{3}/);
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it('does not add Document ID to prefilled if pattern not in template', () => {
|
|
180
|
+
const result = generateDocument({
|
|
181
|
+
manifest: createMockPassport(),
|
|
182
|
+
template: SIMPLE_TEMPLATE,
|
|
183
|
+
docType: 'technical-documentation',
|
|
184
|
+
});
|
|
185
|
+
expect(result.prefilledFields).not.toContain('Document ID');
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
describe('generateDocument — type-specific manual fields', () => {
|
|
190
|
+
it('ai-literacy has training-related manual fields', () => {
|
|
191
|
+
const result = generateDocument({
|
|
192
|
+
manifest: createMockPassport(),
|
|
193
|
+
template: SIMPLE_TEMPLATE,
|
|
194
|
+
docType: 'ai-literacy',
|
|
195
|
+
});
|
|
196
|
+
expect(result.manualFields).toContain('Training levels configuration');
|
|
197
|
+
expect(result.manualFields).toContain('Sign-off signatures');
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
it('art5-screening has prohibited practice manual fields', () => {
|
|
201
|
+
const result = generateDocument({
|
|
202
|
+
manifest: createMockPassport(),
|
|
203
|
+
template: SIMPLE_TEMPLATE,
|
|
204
|
+
docType: 'art5-screening',
|
|
205
|
+
});
|
|
206
|
+
expect(result.manualFields).toContain('Prohibited practice details');
|
|
207
|
+
expect(result.manualFields).toContain('Decision and justification');
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
it('technical-documentation has architecture manual fields', () => {
|
|
211
|
+
const result = generateDocument({
|
|
212
|
+
manifest: createMockPassport(),
|
|
213
|
+
template: SIMPLE_TEMPLATE,
|
|
214
|
+
docType: 'technical-documentation',
|
|
215
|
+
});
|
|
216
|
+
expect(result.manualFields).toContain('System architecture details');
|
|
217
|
+
expect(result.manualFields).toContain('Performance metrics');
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
it('incident-report has incident manual fields', () => {
|
|
221
|
+
const result = generateDocument({
|
|
222
|
+
manifest: createMockPassport(),
|
|
223
|
+
template: SIMPLE_TEMPLATE,
|
|
224
|
+
docType: 'incident-report',
|
|
225
|
+
});
|
|
226
|
+
expect(result.manualFields).toContain('Incident description');
|
|
227
|
+
expect(result.manualFields).toContain('Root cause analysis');
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
it('declaration-of-conformity has conformity manual fields', () => {
|
|
231
|
+
const result = generateDocument({
|
|
232
|
+
manifest: createMockPassport(),
|
|
233
|
+
template: SIMPLE_TEMPLATE,
|
|
234
|
+
docType: 'declaration-of-conformity',
|
|
235
|
+
});
|
|
236
|
+
expect(result.manualFields).toContain('Harmonised standards used');
|
|
237
|
+
expect(result.manualFields).toContain('Signatory');
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
it('monitoring-policy has monitoring manual fields', () => {
|
|
241
|
+
const result = generateDocument({
|
|
242
|
+
manifest: createMockPassport(),
|
|
243
|
+
template: SIMPLE_TEMPLATE,
|
|
244
|
+
docType: 'monitoring-policy',
|
|
245
|
+
});
|
|
246
|
+
expect(result.manualFields).toContain('Human oversight assignments');
|
|
247
|
+
expect(result.manualFields).toContain('Log retention schedule');
|
|
248
|
+
});
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
describe('generateDocument — all 6 types produce valid results', () => {
|
|
252
|
+
for (const docType of ALL_DOC_TYPES) {
|
|
253
|
+
it(`generates valid result for ${docType}`, () => {
|
|
254
|
+
const result = generateDocument({
|
|
255
|
+
manifest: createMockPassport(),
|
|
256
|
+
template: SIMPLE_TEMPLATE,
|
|
257
|
+
docType,
|
|
258
|
+
organization: 'Test Corp',
|
|
259
|
+
});
|
|
260
|
+
expect(result.docType).toBe(docType);
|
|
261
|
+
expect(result.markdown).toBeTruthy();
|
|
262
|
+
expect(result.prefilledFields.length).toBeGreaterThan(0);
|
|
263
|
+
expect(result.manualFields.length).toBeGreaterThan(0);
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
describe('generateDocument — result is frozen', () => {
|
|
269
|
+
it('returns a frozen object', () => {
|
|
270
|
+
const result = generateDocument({
|
|
271
|
+
manifest: createMockPassport(),
|
|
272
|
+
template: SIMPLE_TEMPLATE,
|
|
273
|
+
docType: 'ai-literacy',
|
|
274
|
+
});
|
|
275
|
+
expect(Object.isFrozen(result)).toBe(true);
|
|
276
|
+
expect(Object.isFrozen(result.prefilledFields)).toBe(true);
|
|
277
|
+
expect(Object.isFrozen(result.manualFields)).toBe(true);
|
|
278
|
+
});
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
describe('generateDocument — edge cases', () => {
|
|
282
|
+
it('handles passport with minimal fields gracefully', () => {
|
|
283
|
+
const minimal = createMockPassport({
|
|
284
|
+
model: { provider: '', model_id: '' } as any,
|
|
285
|
+
compliance: { eu_ai_act: { risk_class: '' } } as any,
|
|
286
|
+
});
|
|
287
|
+
const result = generateDocument({
|
|
288
|
+
manifest: minimal,
|
|
289
|
+
template: SIMPLE_TEMPLATE,
|
|
290
|
+
docType: 'ai-literacy',
|
|
291
|
+
});
|
|
292
|
+
expect(result.markdown).toBeTruthy();
|
|
293
|
+
expect(result.manualFields).toContain('Provider');
|
|
294
|
+
expect(result.manualFields).toContain('Risk Class');
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
it('replaces multiple occurrences of same placeholder', () => {
|
|
298
|
+
const template = '[Company Name] is great. [Company Name] is the best.';
|
|
299
|
+
const result = generateDocument({
|
|
300
|
+
manifest: createMockPassport(),
|
|
301
|
+
template,
|
|
302
|
+
docType: 'ai-literacy',
|
|
303
|
+
organization: 'Multi Corp',
|
|
304
|
+
});
|
|
305
|
+
expect(result.markdown).toBe('Multi Corp is great. Multi Corp is the best.');
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
it('preserves GUIDANCE comments in output', () => {
|
|
309
|
+
const template = '<!-- GUIDANCE: This is guidance -->\n[Company Name]';
|
|
310
|
+
const result = generateDocument({
|
|
311
|
+
manifest: createMockPassport(),
|
|
312
|
+
template,
|
|
313
|
+
docType: 'ai-literacy',
|
|
314
|
+
});
|
|
315
|
+
expect(result.markdown).toContain('<!-- GUIDANCE:');
|
|
316
|
+
});
|
|
317
|
+
});
|
|
318
|
+
});
|