@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.
Files changed (594) hide show
  1. package/.well-known/ai-compliance.json +16 -0
  2. package/COMPLIANCE.md +64 -0
  3. package/data/data-integrity.test.ts +75 -0
  4. package/data/eval/eval-mappings.json +33 -0
  5. package/data/llm/model-pricing.json +15 -0
  6. package/data/llm/model-routing.json +36 -0
  7. package/data/onboarding/risk-profile.json +17 -0
  8. package/data/regulations/eu-ai-act/README.md +245 -0
  9. package/data/regulations/eu-ai-act/applicability-tree.json +160 -0
  10. package/data/regulations/eu-ai-act/cross-mapping.json +175 -0
  11. package/data/regulations/eu-ai-act/localization.json +186 -0
  12. package/data/regulations/eu-ai-act/obligations.json +3981 -0
  13. package/data/regulations/eu-ai-act/regulation-meta.json +482 -0
  14. package/data/regulations/eu-ai-act/scoring.json +342 -0
  15. package/data/regulations/eu-ai-act/technical-requirements.json +2590 -0
  16. package/data/regulations/eu-ai-act/timeline.json +160 -0
  17. package/data/regulations/jurisdictions/at.json +15 -0
  18. package/data/regulations/jurisdictions/be.json +15 -0
  19. package/data/regulations/jurisdictions/bg.json +15 -0
  20. package/data/regulations/jurisdictions/cy.json +15 -0
  21. package/data/regulations/jurisdictions/cz.json +15 -0
  22. package/data/regulations/jurisdictions/de.json +15 -0
  23. package/data/regulations/jurisdictions/dk.json +15 -0
  24. package/data/regulations/jurisdictions/ee.json +15 -0
  25. package/data/regulations/jurisdictions/es.json +15 -0
  26. package/data/regulations/jurisdictions/fi.json +15 -0
  27. package/data/regulations/jurisdictions/fr.json +15 -0
  28. package/data/regulations/jurisdictions/gr.json +15 -0
  29. package/data/regulations/jurisdictions/hr.json +15 -0
  30. package/data/regulations/jurisdictions/hu.json +15 -0
  31. package/data/regulations/jurisdictions/ie.json +15 -0
  32. package/data/regulations/jurisdictions/is.json +15 -0
  33. package/data/regulations/jurisdictions/it.json +15 -0
  34. package/data/regulations/jurisdictions/li.json +15 -0
  35. package/data/regulations/jurisdictions/lt.json +15 -0
  36. package/data/regulations/jurisdictions/lu.json +15 -0
  37. package/data/regulations/jurisdictions/lv.json +15 -0
  38. package/data/regulations/jurisdictions/mt.json +15 -0
  39. package/data/regulations/jurisdictions/nl.json +15 -0
  40. package/data/regulations/jurisdictions/no.json +15 -0
  41. package/data/regulations/jurisdictions/pl.json +15 -0
  42. package/data/regulations/jurisdictions/pt.json +15 -0
  43. package/data/regulations/jurisdictions/ro.json +15 -0
  44. package/data/regulations/jurisdictions/se.json +15 -0
  45. package/data/regulations/jurisdictions/si.json +15 -0
  46. package/data/regulations/jurisdictions/sk.json +15 -0
  47. package/data/scanner/check-id-categories.json +81 -0
  48. package/data/scanner/confidence-params.json +16 -0
  49. package/data/scanner/limits.json +4 -0
  50. package/data/schemas/http-contract-sample.json +79 -0
  51. package/data/schemas/http-contract.json +144 -0
  52. package/data/semgrep-rules/bare-call.yaml +37 -0
  53. package/data/semgrep-rules/injection.yaml +73 -0
  54. package/data/semgrep-rules/missing-error-handling.yaml +58 -0
  55. package/data/semgrep-rules/unsafe-deser.yaml +65 -0
  56. package/data/templates/eu-ai-act/ai-literacy.md +184 -0
  57. package/data/templates/eu-ai-act/art5-screening.md +131 -0
  58. package/data/templates/eu-ai-act/data-governance.md +145 -0
  59. package/data/templates/eu-ai-act/declaration-of-conformity.md +161 -0
  60. package/data/templates/eu-ai-act/fria.md +127 -0
  61. package/data/templates/eu-ai-act/gpai-systemic-risk.md +150 -0
  62. package/data/templates/eu-ai-act/gpai-transparency.md +166 -0
  63. package/data/templates/eu-ai-act/incident-report.md +188 -0
  64. package/data/templates/eu-ai-act/instructions-for-use.md +202 -0
  65. package/data/templates/eu-ai-act/monitoring-policy.md +110 -0
  66. package/data/templates/eu-ai-act/qms.md +180 -0
  67. package/data/templates/eu-ai-act/risk-management-system.md +123 -0
  68. package/data/templates/eu-ai-act/technical-documentation.md +287 -0
  69. package/data/templates/eu-ai-act/worker-notification.md +143 -0
  70. package/data/templates/policies/biometrics-ai-policy.md +214 -0
  71. package/data/templates/policies/critical-infra-ai-policy.md +228 -0
  72. package/data/templates/policies/education-ai-policy.md +184 -0
  73. package/data/templates/policies/finance-ai-policy.md +191 -0
  74. package/data/templates/policies/healthcare-ai-policy.md +197 -0
  75. package/data/templates/policies/hr-ai-policy.md +178 -0
  76. package/data/templates/policies/legal-ai-policy.md +189 -0
  77. package/data/templates/policies/migration-ai-policy.md +239 -0
  78. package/engine.log +7 -0
  79. package/package.json +74 -0
  80. package/src/composition-root.ts +791 -0
  81. package/src/data/eval/conformity-tests.test.ts +122 -0
  82. package/src/data/eval/ct-1-transparency.ts +106 -0
  83. package/src/data/eval/ct-10-gpai.ts +25 -0
  84. package/src/data/eval/ct-11-industry.ts +42 -0
  85. package/src/data/eval/ct-2-oversight.ts +41 -0
  86. package/src/data/eval/ct-3-explanation.ts +14 -0
  87. package/src/data/eval/ct-4-bias.ts +83 -0
  88. package/src/data/eval/ct-5-accuracy.ts +41 -0
  89. package/src/data/eval/ct-6-robustness.ts +81 -0
  90. package/src/data/eval/ct-7-prohibited.ts +52 -0
  91. package/src/data/eval/ct-8-logging.ts +68 -0
  92. package/src/data/eval/ct-9-risk-awareness.ts +33 -0
  93. package/src/data/eval/deterministic-evaluator.ts +120 -0
  94. package/src/data/eval/index.ts +55 -0
  95. package/src/data/eval/judge-prompts.ts +146 -0
  96. package/src/data/eval/llm-judged-tests.ts +279 -0
  97. package/src/data/eval/llm-tests.test.ts +83 -0
  98. package/src/data/eval/remediation/ct-1-transparency.ts +91 -0
  99. package/src/data/eval/remediation/ct-10-gpai.ts +94 -0
  100. package/src/data/eval/remediation/ct-11-industry.ts +94 -0
  101. package/src/data/eval/remediation/ct-2-oversight.ts +71 -0
  102. package/src/data/eval/remediation/ct-3-explanation.ts +70 -0
  103. package/src/data/eval/remediation/ct-4-bias.ts +70 -0
  104. package/src/data/eval/remediation/ct-5-accuracy.ts +70 -0
  105. package/src/data/eval/remediation/ct-6-robustness.ts +70 -0
  106. package/src/data/eval/remediation/ct-7-prohibited.ts +94 -0
  107. package/src/data/eval/remediation/ct-8-logging.ts +94 -0
  108. package/src/data/eval/remediation/ct-9-risk-awareness.ts +94 -0
  109. package/src/data/eval/remediation/index.ts +89 -0
  110. package/src/data/eval/remediation/owasp-art5.ts +15 -0
  111. package/src/data/eval/remediation/owasp-llm01.ts +72 -0
  112. package/src/data/eval/remediation/owasp-llm02.ts +72 -0
  113. package/src/data/eval/remediation/owasp-llm03.ts +15 -0
  114. package/src/data/eval/remediation/owasp-llm04.ts +15 -0
  115. package/src/data/eval/remediation/owasp-llm05.ts +15 -0
  116. package/src/data/eval/remediation/owasp-llm06.ts +15 -0
  117. package/src/data/eval/remediation/owasp-llm07.ts +15 -0
  118. package/src/data/eval/remediation/owasp-llm08.ts +15 -0
  119. package/src/data/eval/remediation/owasp-llm09.ts +15 -0
  120. package/src/data/eval/remediation/owasp-llm10.ts +15 -0
  121. package/src/data/eval/remediation/remediation.test.ts +229 -0
  122. package/src/data/eval/remediation/test-mapping.ts +290 -0
  123. package/src/data/eval/security-rubrics.ts +381 -0
  124. package/src/data/finding-explanations.json +453 -0
  125. package/src/data/industry-patterns.ts +161 -0
  126. package/src/data/registry-cards.ts +368 -0
  127. package/src/data/regulation/index.ts +5 -0
  128. package/src/data/regulation/jurisdiction-data.test.ts +73 -0
  129. package/src/data/regulation/jurisdiction-data.ts +65 -0
  130. package/src/data/regulation/regulation-data.ts +19 -0
  131. package/src/data/regulation/regulation-loader.test.ts +107 -0
  132. package/src/data/regulation/regulation-loader.ts +56 -0
  133. package/src/data/scanner-constants.ts +46 -0
  134. package/src/data/schemas/schemas-core.ts +140 -0
  135. package/src/data/schemas/schemas-supplementary.ts +211 -0
  136. package/src/data/schemas/schemas.ts +28 -0
  137. package/src/data/security/attack-probes.test.ts +62 -0
  138. package/src/data/security/attack-probes.ts +496 -0
  139. package/src/data/security/eu-ai-act-security.ts +40 -0
  140. package/src/data/security/index.ts +19 -0
  141. package/src/data/security/mitre-atlas.test.ts +43 -0
  142. package/src/data/security/mitre-atlas.ts +93 -0
  143. package/src/data/security/nist-ai-rmf.ts +43 -0
  144. package/src/data/security/owasp-llm-top10.test.ts +60 -0
  145. package/src/data/security/owasp-llm-top10.ts +138 -0
  146. package/src/data/template-registry.ts +53 -0
  147. package/src/data/tool-versions.json +22 -0
  148. package/src/domain/audit/audit-package.test.ts +152 -0
  149. package/src/domain/audit/audit-package.ts +166 -0
  150. package/src/domain/audit/audit-trail.test.ts +121 -0
  151. package/src/domain/audit/audit-trail.ts +174 -0
  152. package/src/domain/audit/index.ts +8 -0
  153. package/src/domain/audit/permissions-matrix.test.ts +136 -0
  154. package/src/domain/audit/permissions-matrix.ts +121 -0
  155. package/src/domain/certification/adversarial/bias-tests.ts +95 -0
  156. package/src/domain/certification/adversarial/evaluators.ts +304 -0
  157. package/src/domain/certification/adversarial/index.ts +11 -0
  158. package/src/domain/certification/adversarial/prompt-injection.ts +103 -0
  159. package/src/domain/certification/adversarial/safety-boundary.ts +132 -0
  160. package/src/domain/certification/aiuc1-readiness.test.ts +236 -0
  161. package/src/domain/certification/aiuc1-readiness.ts +298 -0
  162. package/src/domain/certification/aiuc1-requirements.ts +235 -0
  163. package/src/domain/certification/index.ts +10 -0
  164. package/src/domain/certification/redteam-runner.test.ts +97 -0
  165. package/src/domain/certification/redteam-runner.ts +205 -0
  166. package/src/domain/certification/test-runner.test.ts +232 -0
  167. package/src/domain/certification/test-runner.ts +289 -0
  168. package/src/domain/cost/cost-estimator.test.ts +187 -0
  169. package/src/domain/cost/cost-estimator.ts +133 -0
  170. package/src/domain/disclaimer.test.ts +52 -0
  171. package/src/domain/disclaimer.ts +39 -0
  172. package/src/domain/documents/ai-enricher.test.ts +120 -0
  173. package/src/domain/documents/ai-enricher.ts +159 -0
  174. package/src/domain/documents/document-generator.test.ts +318 -0
  175. package/src/domain/documents/document-generator.ts +239 -0
  176. package/src/domain/documents/index.ts +9 -0
  177. package/src/domain/documents/passport-helpers.ts +25 -0
  178. package/src/domain/documents/policy-generator.test.ts +252 -0
  179. package/src/domain/documents/policy-generator.ts +94 -0
  180. package/src/domain/documents/worker-notification-generator.test.ts +162 -0
  181. package/src/domain/documents/worker-notification-generator.ts +141 -0
  182. package/src/domain/eval/adapters/adapter-port.ts +94 -0
  183. package/src/domain/eval/adapters/adapters.test.ts +303 -0
  184. package/src/domain/eval/adapters/anthropic-adapter.ts +57 -0
  185. package/src/domain/eval/adapters/auto-detect.ts +104 -0
  186. package/src/domain/eval/adapters/create-chat-adapter.ts +106 -0
  187. package/src/domain/eval/adapters/custom-adapter.ts +74 -0
  188. package/src/domain/eval/adapters/http-adapter.ts +66 -0
  189. package/src/domain/eval/adapters/index.ts +7 -0
  190. package/src/domain/eval/adapters/ollama-adapter.ts +48 -0
  191. package/src/domain/eval/adapters/openai-adapter.ts +58 -0
  192. package/src/domain/eval/adapters/with-timeout.ts +25 -0
  193. package/src/domain/eval/conformity-score.test.ts +161 -0
  194. package/src/domain/eval/conformity-score.ts +135 -0
  195. package/src/domain/eval/eval-constants.ts +55 -0
  196. package/src/domain/eval/eval-evidence.test.ts +85 -0
  197. package/src/domain/eval/eval-evidence.ts +103 -0
  198. package/src/domain/eval/eval-fix-generator.test.ts +421 -0
  199. package/src/domain/eval/eval-fix-generator.ts +205 -0
  200. package/src/domain/eval/eval-passport.test.ts +82 -0
  201. package/src/domain/eval/eval-passport.ts +89 -0
  202. package/src/domain/eval/eval-remediation-report.test.ts +682 -0
  203. package/src/domain/eval/eval-remediation-report.ts +170 -0
  204. package/src/domain/eval/eval-report.ts +108 -0
  205. package/src/domain/eval/eval-runner.test.ts +609 -0
  206. package/src/domain/eval/eval-runner.ts +593 -0
  207. package/src/domain/eval/eval-to-findings.test.ts +293 -0
  208. package/src/domain/eval/eval-to-findings.ts +83 -0
  209. package/src/domain/eval/index.ts +31 -0
  210. package/src/domain/eval/llm-judge.test.ts +139 -0
  211. package/src/domain/eval/llm-judge.ts +168 -0
  212. package/src/domain/eval/remediation-types.ts +90 -0
  213. package/src/domain/eval/security-integration.test.ts +196 -0
  214. package/src/domain/eval/security-integration.ts +136 -0
  215. package/src/domain/eval/types.test.ts +173 -0
  216. package/src/domain/eval/types.ts +244 -0
  217. package/src/domain/eval/verdict-utils.ts +45 -0
  218. package/src/domain/fixer/create-fixer.ts +101 -0
  219. package/src/domain/fixer/diff.ts +70 -0
  220. package/src/domain/fixer/fix-history.ts +23 -0
  221. package/src/domain/fixer/fixer.test.ts +306 -0
  222. package/src/domain/fixer/index.ts +9 -0
  223. package/src/domain/fixer/strategies/bandit-fix.ts +61 -0
  224. package/src/domain/fixer/strategies/bias-testing.ts +49 -0
  225. package/src/domain/fixer/strategies/ci-compliance.ts +57 -0
  226. package/src/domain/fixer/strategies/content-marking.ts +45 -0
  227. package/src/domain/fixer/strategies/cve-upgrade.ts +66 -0
  228. package/src/domain/fixer/strategies/data-governance.ts +65 -0
  229. package/src/domain/fixer/strategies/disclosure.ts +69 -0
  230. package/src/domain/fixer/strategies/doc-code-sync.ts +53 -0
  231. package/src/domain/fixer/strategies/documentation.ts +59 -0
  232. package/src/domain/fixer/strategies/error-handler.ts +63 -0
  233. package/src/domain/fixer/strategies/hitl-gate.ts +67 -0
  234. package/src/domain/fixer/strategies/index.ts +61 -0
  235. package/src/domain/fixer/strategies/kill-switch-test.ts +85 -0
  236. package/src/domain/fixer/strategies/kill-switch.ts +53 -0
  237. package/src/domain/fixer/strategies/license-fix.ts +57 -0
  238. package/src/domain/fixer/strategies/log-retention.ts +40 -0
  239. package/src/domain/fixer/strategies/logging.ts +59 -0
  240. package/src/domain/fixer/strategies/metadata.ts +45 -0
  241. package/src/domain/fixer/strategies/permission-guard.ts +84 -0
  242. package/src/domain/fixer/strategies/record-keeping.ts +69 -0
  243. package/src/domain/fixer/strategies/secret-rotation.ts +52 -0
  244. package/src/domain/fixer/strategies.test.ts +341 -0
  245. package/src/domain/fixer/template-engine.test.ts +64 -0
  246. package/src/domain/fixer/template-engine.ts +38 -0
  247. package/src/domain/fixer/types.ts +88 -0
  248. package/src/domain/frameworks/aiuc1-framework.test.ts +159 -0
  249. package/src/domain/frameworks/aiuc1-framework.ts +126 -0
  250. package/src/domain/frameworks/collect-foundation-metrics.test.ts +96 -0
  251. package/src/domain/frameworks/collect-foundation-metrics.ts +34 -0
  252. package/src/domain/frameworks/eu-ai-act-framework.test.ts +117 -0
  253. package/src/domain/frameworks/eu-ai-act-framework.ts +100 -0
  254. package/src/domain/frameworks/framework-registry.test.ts +91 -0
  255. package/src/domain/frameworks/framework-registry.ts +38 -0
  256. package/src/domain/frameworks/index.ts +8 -0
  257. package/src/domain/frameworks/mitre-atlas-framework.test.ts +53 -0
  258. package/src/domain/frameworks/mitre-atlas-framework.ts +53 -0
  259. package/src/domain/frameworks/owasp-llm-framework.test.ts +77 -0
  260. package/src/domain/frameworks/owasp-llm-framework.ts +54 -0
  261. package/src/domain/frameworks/score-plugin-framework.ts +117 -0
  262. package/src/domain/fria/fria-generator.test.ts +273 -0
  263. package/src/domain/fria/fria-generator.ts +366 -0
  264. package/src/domain/import/promptfoo-importer.test.ts +103 -0
  265. package/src/domain/import/promptfoo-importer.ts +151 -0
  266. package/src/domain/onboarding/guided-onboarding.test.ts +144 -0
  267. package/src/domain/onboarding/guided-onboarding.ts +135 -0
  268. package/src/domain/passport/builder/domain-mapper.ts +9 -0
  269. package/src/domain/passport/builder/manifest-builder.test.ts +546 -0
  270. package/src/domain/passport/builder/manifest-builder.ts +535 -0
  271. package/src/domain/passport/builder/manifest-diff.test.ts +105 -0
  272. package/src/domain/passport/builder/manifest-diff.ts +89 -0
  273. package/src/domain/passport/builder/manifest-files.ts +17 -0
  274. package/src/domain/passport/crypto-signer.test.ts +93 -0
  275. package/src/domain/passport/crypto-signer.ts +157 -0
  276. package/src/domain/passport/discovery/agent-discovery.test.ts +296 -0
  277. package/src/domain/passport/discovery/agent-discovery.ts +325 -0
  278. package/src/domain/passport/discovery/autonomy-analyzer.test.ts +141 -0
  279. package/src/domain/passport/discovery/autonomy-analyzer.ts +113 -0
  280. package/src/domain/passport/discovery/permission-scanner.test.ts +191 -0
  281. package/src/domain/passport/discovery/permission-scanner.ts +414 -0
  282. package/src/domain/passport/export/a2a-mapper.ts +75 -0
  283. package/src/domain/passport/export/aiuc1-mapper.ts +126 -0
  284. package/src/domain/passport/export/export.test.ts +207 -0
  285. package/src/domain/passport/export/index.ts +41 -0
  286. package/src/domain/passport/export/nist-mapper.ts +227 -0
  287. package/src/domain/passport/import/a2a-importer.test.ts +133 -0
  288. package/src/domain/passport/import/a2a-importer.ts +156 -0
  289. package/src/domain/passport/import/index.ts +2 -0
  290. package/src/domain/passport/index.ts +32 -0
  291. package/src/domain/passport/obligation-field-map.test.ts +113 -0
  292. package/src/domain/passport/obligation-field-map.ts +117 -0
  293. package/src/domain/passport/passport-validator.test.ts +156 -0
  294. package/src/domain/passport/passport-validator.ts +126 -0
  295. package/src/domain/passport/scan-to-compliance.test.ts +336 -0
  296. package/src/domain/passport/scan-to-compliance.ts +166 -0
  297. package/src/domain/passport/test-generator.test.ts +93 -0
  298. package/src/domain/passport/test-generator.ts +136 -0
  299. package/src/domain/proxy/index.ts +11 -0
  300. package/src/domain/proxy/json-rpc.test.ts +72 -0
  301. package/src/domain/proxy/json-rpc.ts +53 -0
  302. package/src/domain/proxy/policy-engine.test.ts +259 -0
  303. package/src/domain/proxy/policy-engine.ts +137 -0
  304. package/src/domain/proxy/proxy-bridge.ts +125 -0
  305. package/src/domain/proxy/proxy-interceptor.test.ts +184 -0
  306. package/src/domain/proxy/proxy-interceptor.ts +120 -0
  307. package/src/domain/proxy/proxy-types.ts +35 -0
  308. package/src/domain/registry/compute-agent-score.test.ts +279 -0
  309. package/src/domain/registry/compute-agent-score.ts +162 -0
  310. package/src/domain/reporter/audit-report.test.ts +87 -0
  311. package/src/domain/reporter/audit-report.ts +116 -0
  312. package/src/domain/reporter/badge-generator.test.ts +54 -0
  313. package/src/domain/reporter/badge-generator.ts +40 -0
  314. package/src/domain/reporter/compliance-md.ts +45 -0
  315. package/src/domain/reporter/index.ts +7 -0
  316. package/src/domain/reporter/pdf-renderer.ts +282 -0
  317. package/src/domain/reporter/share.test.ts +92 -0
  318. package/src/domain/reporter/share.ts +80 -0
  319. package/src/domain/scanner/ast/swc-analyzer.test.ts +49 -0
  320. package/src/domain/scanner/ast/swc-analyzer.ts +124 -0
  321. package/src/domain/scanner/attestations.ts +97 -0
  322. package/src/domain/scanner/checks/ai-disclosure.test.ts +90 -0
  323. package/src/domain/scanner/checks/ai-disclosure.ts +54 -0
  324. package/src/domain/scanner/checks/ai-literacy.ts +163 -0
  325. package/src/domain/scanner/checks/behavioral-constraints.test.ts +167 -0
  326. package/src/domain/scanner/checks/behavioral-constraints.ts +86 -0
  327. package/src/domain/scanner/checks/compliance-metadata.ts +63 -0
  328. package/src/domain/scanner/checks/content-marking.ts +74 -0
  329. package/src/domain/scanner/checks/dep-deep-scan.test.ts +318 -0
  330. package/src/domain/scanner/checks/dep-deep-scan.ts +137 -0
  331. package/src/domain/scanner/checks/documentation.test.ts +88 -0
  332. package/src/domain/scanner/checks/documentation.ts +79 -0
  333. package/src/domain/scanner/checks/git-history.test.ts +120 -0
  334. package/src/domain/scanner/checks/git-history.ts +163 -0
  335. package/src/domain/scanner/checks/gpai-systemic-risk.test.ts +84 -0
  336. package/src/domain/scanner/checks/gpai-systemic-risk.ts +98 -0
  337. package/src/domain/scanner/checks/gpai-transparency.ts +94 -0
  338. package/src/domain/scanner/checks/index.ts +28 -0
  339. package/src/domain/scanner/checks/industry/index.ts +40 -0
  340. package/src/domain/scanner/checks/industry/industry.test.ts +287 -0
  341. package/src/domain/scanner/checks/interaction-logging.test.ts +113 -0
  342. package/src/domain/scanner/checks/interaction-logging.ts +142 -0
  343. package/src/domain/scanner/checks/nhi-scanner.test.ts +158 -0
  344. package/src/domain/scanner/checks/nhi-scanner.ts +78 -0
  345. package/src/domain/scanner/checks/passport-completeness.test.ts +127 -0
  346. package/src/domain/scanner/checks/passport-completeness.ts +82 -0
  347. package/src/domain/scanner/checks/passport-presence.test.ts +56 -0
  348. package/src/domain/scanner/checks/passport-presence.ts +78 -0
  349. package/src/domain/scanner/checks/pattern-check-factory.ts +70 -0
  350. package/src/domain/scanner/checks/permission-scanner.test.ts +279 -0
  351. package/src/domain/scanner/checks/permission-scanner.ts +90 -0
  352. package/src/domain/scanner/checks/presence-check-factory.test.ts +124 -0
  353. package/src/domain/scanner/checks/presence-check-factory.ts +275 -0
  354. package/src/domain/scanner/compliance-diff.test.ts +165 -0
  355. package/src/domain/scanner/compliance-diff.ts +138 -0
  356. package/src/domain/scanner/confidence.test.ts +235 -0
  357. package/src/domain/scanner/confidence.ts +156 -0
  358. package/src/domain/scanner/constants.ts +13 -0
  359. package/src/domain/scanner/create-scanner.ts +573 -0
  360. package/src/domain/scanner/cross-layer.test.ts +372 -0
  361. package/src/domain/scanner/cross-layer.ts +232 -0
  362. package/src/domain/scanner/data/ai-packages.ts +82 -0
  363. package/src/domain/scanner/debt-calculator.test.ts +89 -0
  364. package/src/domain/scanner/debt-calculator.ts +111 -0
  365. package/src/domain/scanner/drift.test.ts +191 -0
  366. package/src/domain/scanner/drift.ts +73 -0
  367. package/src/domain/scanner/evidence-store.test.ts +207 -0
  368. package/src/domain/scanner/evidence-store.ts +195 -0
  369. package/src/domain/scanner/evidence.test.ts +104 -0
  370. package/src/domain/scanner/evidence.ts +71 -0
  371. package/src/domain/scanner/external/bandit-runner.test.ts +45 -0
  372. package/src/domain/scanner/external/bandit-runner.ts +90 -0
  373. package/src/domain/scanner/external/checks.ts +321 -0
  374. package/src/domain/scanner/external/dedup.test.ts +79 -0
  375. package/src/domain/scanner/external/dedup.ts +94 -0
  376. package/src/domain/scanner/external/detect-secrets-runner.test.ts +58 -0
  377. package/src/domain/scanner/external/detect-secrets-runner.ts +81 -0
  378. package/src/domain/scanner/external/external-scanner.test.ts +221 -0
  379. package/src/domain/scanner/external/external-scanner.ts +36 -0
  380. package/src/domain/scanner/external/finding-mapper.test.ts +95 -0
  381. package/src/domain/scanner/external/finding-mapper.ts +138 -0
  382. package/src/domain/scanner/external/index.ts +15 -0
  383. package/src/domain/scanner/external/mappings.ts +93 -0
  384. package/src/domain/scanner/external/modelscan-runner.test.ts +35 -0
  385. package/src/domain/scanner/external/modelscan-runner.ts +101 -0
  386. package/src/domain/scanner/external/path-utils.ts +8 -0
  387. package/src/domain/scanner/external/runner-port.ts +45 -0
  388. package/src/domain/scanner/external/semgrep-runner.test.ts +52 -0
  389. package/src/domain/scanner/external/semgrep-runner.ts +94 -0
  390. package/src/domain/scanner/external/types.ts +32 -0
  391. package/src/domain/scanner/finding-attribution.test.ts +444 -0
  392. package/src/domain/scanner/finding-attribution.ts +195 -0
  393. package/src/domain/scanner/finding-explainer.test.ts +157 -0
  394. package/src/domain/scanner/finding-explainer.ts +73 -0
  395. package/src/domain/scanner/fix-diff-builder.test.ts +272 -0
  396. package/src/domain/scanner/fix-diff-builder.ts +477 -0
  397. package/src/domain/scanner/import-graph.test.ts +162 -0
  398. package/src/domain/scanner/import-graph.ts +198 -0
  399. package/src/domain/scanner/languages/adapter.test.ts +105 -0
  400. package/src/domain/scanner/languages/adapter.ts +239 -0
  401. package/src/domain/scanner/layers/index.ts +24 -0
  402. package/src/domain/scanner/layers/layer1-files.ts +54 -0
  403. package/src/domain/scanner/layers/layer2-docs.test.ts +1207 -0
  404. package/src/domain/scanner/layers/layer2-docs.ts +297 -0
  405. package/src/domain/scanner/layers/layer2-parsing.ts +217 -0
  406. package/src/domain/scanner/layers/layer3-config.test.ts +187 -0
  407. package/src/domain/scanner/layers/layer3-config.ts +279 -0
  408. package/src/domain/scanner/layers/layer3-parsers.ts +73 -0
  409. package/src/domain/scanner/layers/layer4-patterns.test.ts +397 -0
  410. package/src/domain/scanner/layers/layer4-patterns.ts +216 -0
  411. package/src/domain/scanner/layers/layer5-docs.test.ts +99 -0
  412. package/src/domain/scanner/layers/layer5-docs.ts +250 -0
  413. package/src/domain/scanner/layers/layer5-llm.test.ts +146 -0
  414. package/src/domain/scanner/layers/layer5-llm.ts +262 -0
  415. package/src/domain/scanner/layers/layer5-targeted.test.ts +93 -0
  416. package/src/domain/scanner/layers/layer5-targeted.ts +233 -0
  417. package/src/domain/scanner/layers/lockfile-parsers.test.ts +320 -0
  418. package/src/domain/scanner/layers/lockfile-parsers.ts +184 -0
  419. package/src/domain/scanner/regulation-version.test.ts +54 -0
  420. package/src/domain/scanner/regulation-version.ts +23 -0
  421. package/src/domain/scanner/role-filter.test.ts +116 -0
  422. package/src/domain/scanner/role-filter.ts +51 -0
  423. package/src/domain/scanner/rules/banned-packages-data.ts +553 -0
  424. package/src/domain/scanner/rules/banned-packages-sdk.ts +65 -0
  425. package/src/domain/scanner/rules/banned-packages.test.ts +249 -0
  426. package/src/domain/scanner/rules/banned-packages.ts +55 -0
  427. package/src/domain/scanner/rules/comment-filter.test.ts +115 -0
  428. package/src/domain/scanner/rules/comment-filter.ts +297 -0
  429. package/src/domain/scanner/rules/index.ts +9 -0
  430. package/src/domain/scanner/rules/nhi-patterns.test.ts +128 -0
  431. package/src/domain/scanner/rules/nhi-patterns.ts +60 -0
  432. package/src/domain/scanner/rules/pattern-rules.ts +1152 -0
  433. package/src/domain/scanner/sbom.test.ts +136 -0
  434. package/src/domain/scanner/sbom.ts +103 -0
  435. package/src/domain/scanner/scan-cache.test.ts +136 -0
  436. package/src/domain/scanner/scan-cache.ts +115 -0
  437. package/src/domain/scanner/scanner.test.ts +125 -0
  438. package/src/domain/scanner/score-calculator.test.ts +363 -0
  439. package/src/domain/scanner/score-calculator.ts +189 -0
  440. package/src/domain/scanner/security-score.test.ts +107 -0
  441. package/src/domain/scanner/security-score.ts +116 -0
  442. package/src/domain/scanner/source-filter.ts +24 -0
  443. package/src/domain/scanner/validators.ts +223 -0
  444. package/src/domain/shared/compliance-constants.ts +48 -0
  445. package/src/domain/shared/disclosure-patterns.ts +16 -0
  446. package/src/domain/shared/index.ts +6 -0
  447. package/src/domain/shared/parse-dependencies.ts +21 -0
  448. package/src/domain/supply-chain/dependency-analyzer.ts +138 -0
  449. package/src/domain/supply-chain/index.ts +3 -0
  450. package/src/domain/supply-chain/supply-chain.test.ts +211 -0
  451. package/src/domain/supply-chain/types.ts +32 -0
  452. package/src/domain/whatif/config-fixer.ts +187 -0
  453. package/src/domain/whatif/index.ts +6 -0
  454. package/src/domain/whatif/scenario-engine.ts +121 -0
  455. package/src/domain/whatif/simulate-actions.test.ts +161 -0
  456. package/src/domain/whatif/simulate-actions.ts +114 -0
  457. package/src/domain/whatif/whatif.test.ts +135 -0
  458. package/src/e2e/gaps-e2e.test.ts +259 -0
  459. package/src/e2e/smoke.test.ts +101 -0
  460. package/src/hooks/hooks-export.test.ts +81 -0
  461. package/src/hooks/installer.ts +113 -0
  462. package/src/http/cors.test.ts +38 -0
  463. package/src/http/create-router.ts +259 -0
  464. package/src/http/routes/agent.route.ts +380 -0
  465. package/src/http/routes/audit.route.ts +66 -0
  466. package/src/http/routes/badge.route.ts +23 -0
  467. package/src/http/routes/cert.route.ts +66 -0
  468. package/src/http/routes/chat.route.ts +228 -0
  469. package/src/http/routes/cost.route.ts +33 -0
  470. package/src/http/routes/debt.route.ts +29 -0
  471. package/src/http/routes/disclaimer.route.ts +64 -0
  472. package/src/http/routes/eval.route.ts +161 -0
  473. package/src/http/routes/events.route.test.ts +108 -0
  474. package/src/http/routes/events.route.ts +71 -0
  475. package/src/http/routes/external-scan.route.ts +24 -0
  476. package/src/http/routes/file.route.ts +54 -0
  477. package/src/http/routes/fix.route.ts +219 -0
  478. package/src/http/routes/frameworks.route.test.ts +66 -0
  479. package/src/http/routes/frameworks.route.ts +36 -0
  480. package/src/http/routes/git.route.ts +27 -0
  481. package/src/http/routes/guided-onboarding.route.ts +65 -0
  482. package/src/http/routes/import.route.ts +64 -0
  483. package/src/http/routes/jurisdiction.route.ts +22 -0
  484. package/src/http/routes/obligations.route.test.ts +122 -0
  485. package/src/http/routes/obligations.route.ts +110 -0
  486. package/src/http/routes/onboarding.route.ts +53 -0
  487. package/src/http/routes/provider.route.ts +42 -0
  488. package/src/http/routes/proxy.route.ts +40 -0
  489. package/src/http/routes/redteam.route.ts +84 -0
  490. package/src/http/routes/report.route.ts +29 -0
  491. package/src/http/routes/scan.route.ts +104 -0
  492. package/src/http/routes/share.route.ts +44 -0
  493. package/src/http/routes/shell.route.ts +27 -0
  494. package/src/http/routes/status.route.ts +66 -0
  495. package/src/http/routes/supply-chain.route.ts +121 -0
  496. package/src/http/routes/sync.route.ts +328 -0
  497. package/src/http/routes/tools.route.ts +29 -0
  498. package/src/http/routes/whatif.route.ts +96 -0
  499. package/src/http/utils/validation.ts +31 -0
  500. package/src/index.ts +1 -0
  501. package/src/infra/bundle-fetcher.ts +77 -0
  502. package/src/infra/cache-storage.ts +34 -0
  503. package/src/infra/event-bus.ts +31 -0
  504. package/src/infra/file-collector.ts +61 -0
  505. package/src/infra/file-ops-adapter.ts +95 -0
  506. package/src/infra/file-watcher.test.ts +90 -0
  507. package/src/infra/file-watcher.ts +106 -0
  508. package/src/infra/git-adapter.ts +93 -0
  509. package/src/infra/git-history-adapter.ts +41 -0
  510. package/src/infra/headless-browser.ts +178 -0
  511. package/src/infra/llm-adapter.test.ts +83 -0
  512. package/src/infra/llm-adapter.ts +86 -0
  513. package/src/infra/logger.ts +27 -0
  514. package/src/infra/project-config.test.ts +74 -0
  515. package/src/infra/project-config.ts +35 -0
  516. package/src/infra/rate-limiter.test.ts +36 -0
  517. package/src/infra/rate-limiter.ts +34 -0
  518. package/src/infra/retry.ts +46 -0
  519. package/src/infra/saas-client.ts +123 -0
  520. package/src/infra/search-adapter.ts +113 -0
  521. package/src/infra/shell-adapter.ts +68 -0
  522. package/src/infra/tool-manager.test.ts +99 -0
  523. package/src/infra/tool-manager.ts +197 -0
  524. package/src/llm/agents/agent-modes.test.ts +44 -0
  525. package/src/llm/agents/modes.ts +68 -0
  526. package/src/llm/routing/cost-routing.test.ts +37 -0
  527. package/src/llm/routing/cost-tracker.ts +74 -0
  528. package/src/llm/routing/model-routing.test.ts +79 -0
  529. package/src/llm/routing/model-routing.ts +38 -0
  530. package/src/llm/routing/pricing.ts +19 -0
  531. package/src/llm/sse-protocol.ts +77 -0
  532. package/src/llm/tool-definitions.ts +83 -0
  533. package/src/llm/tool-executors.ts +80 -0
  534. package/src/llm/tools/types.ts +13 -0
  535. package/src/mcp/create-mcp-stack.ts +82 -0
  536. package/src/mcp/handlers.ts +245 -0
  537. package/src/mcp/index.ts +28 -0
  538. package/src/mcp/mcp-server.test.ts +80 -0
  539. package/src/mcp/server.ts +79 -0
  540. package/src/mcp/tools.ts +48 -0
  541. package/src/onboarding/auto-detect.ts +164 -0
  542. package/src/onboarding/onboarding.test.ts +89 -0
  543. package/src/onboarding/profile.ts +169 -0
  544. package/src/onboarding/questions.ts +112 -0
  545. package/src/onboarding/wizard.ts +66 -0
  546. package/src/output/github-issue.ts +32 -0
  547. package/src/output/json-output.ts +67 -0
  548. package/src/ports/browser.port.ts +23 -0
  549. package/src/ports/events.port.ts +28 -0
  550. package/src/ports/llm.port.ts +23 -0
  551. package/src/ports/logger.port.ts +6 -0
  552. package/src/ports/process.port.ts +6 -0
  553. package/src/ports/scanner.port.ts +15 -0
  554. package/src/server.ts +134 -0
  555. package/src/services/badge-service.ts +67 -0
  556. package/src/services/chat-service.test.ts +162 -0
  557. package/src/services/chat-service.ts +152 -0
  558. package/src/services/cost-service.ts +52 -0
  559. package/src/services/debt-service.ts +65 -0
  560. package/src/services/eval-integration.test.ts +132 -0
  561. package/src/services/eval-service.test.ts +373 -0
  562. package/src/services/eval-service.ts +463 -0
  563. package/src/services/external-scan-service.ts +60 -0
  564. package/src/services/file-service.ts +37 -0
  565. package/src/services/fix-service.test.ts +470 -0
  566. package/src/services/fix-service.ts +648 -0
  567. package/src/services/framework-service.test.ts +159 -0
  568. package/src/services/framework-service.ts +67 -0
  569. package/src/services/onboarding-service.ts +165 -0
  570. package/src/services/passport-audit.ts +244 -0
  571. package/src/services/passport-documents.ts +258 -0
  572. package/src/services/passport-service-utils.ts +72 -0
  573. package/src/services/passport-service.test.ts +251 -0
  574. package/src/services/passport-service.ts +339 -0
  575. package/src/services/proxy-service.ts +81 -0
  576. package/src/services/report-service.ts +72 -0
  577. package/src/services/scan-service.test.ts +470 -0
  578. package/src/services/scan-service.ts +335 -0
  579. package/src/services/share-service.ts +108 -0
  580. package/src/services/shared/backup.ts +23 -0
  581. package/src/services/status-service.ts +38 -0
  582. package/src/services/undo-service.test.ts +190 -0
  583. package/src/services/undo-service.ts +144 -0
  584. package/src/test-helpers/factories.ts +116 -0
  585. package/src/types/common.schemas.ts +147 -0
  586. package/src/types/common.types.ts +292 -0
  587. package/src/types/contract.test.ts +217 -0
  588. package/src/types/errors.ts +52 -0
  589. package/src/types/framework.types.ts +87 -0
  590. package/src/types/passport-schemas.ts +241 -0
  591. package/src/types/passport.types.ts +296 -0
  592. package/src/version.ts +1 -0
  593. package/tsconfig.json +20 -0
  594. package/vitest.config.ts +9 -0
@@ -0,0 +1,79 @@
1
+ import type { CheckResult } from '../../../types/common.types.js';
2
+ import type { ScanContext } from '../../../ports/scanner.port.js';
3
+
4
+ const CHECK_ID = 'documentation';
5
+ const OBLIGATION_ID = 'eu-ai-act-OBL-019';
6
+
7
+ const COMPLIANCE_DOC_PATTERNS: readonly RegExp[] = [
8
+ /^COMPLIANCE\.md$/i,
9
+ /^COMPLIANCE[-_]?DOCUMENTATION/i,
10
+ /^AI[-_]?COMPLIANCE/i,
11
+ /^EU[-_]?AI[-_]?ACT/i,
12
+ ];
13
+
14
+ const COMPLIANCE_CONTENT_PATTERNS: readonly RegExp[] = [
15
+ /\bcompliance\b.*\bdocumentation\b/i,
16
+ /\beu ai act\b/i,
17
+ /\brisk assessment\b/i,
18
+ /\bcompliance report\b/i,
19
+ /\bregulatory compliance\b/i,
20
+ /\bai act\b.*\bcompliance\b/i,
21
+ ];
22
+
23
+ const COMPLIOR_DIR = '.complior/';
24
+
25
+ const isComplianceDocFile = (relativePath: string): boolean => {
26
+ const filename = relativePath.split('/').pop() ?? '';
27
+ return COMPLIANCE_DOC_PATTERNS.some((p) => p.test(filename));
28
+ };
29
+
30
+ const hasComplianceContent = (content: string): boolean =>
31
+ COMPLIANCE_CONTENT_PATTERNS.some((p) => p.test(content));
32
+
33
+ export const checkDocumentation = (ctx: ScanContext): readonly CheckResult[] => {
34
+ for (const file of ctx.files) {
35
+ if (isComplianceDocFile(file.relativePath)) {
36
+ return [{
37
+ type: 'pass',
38
+ checkId: CHECK_ID,
39
+ message: `Compliance documentation found: ${file.relativePath}`,
40
+ }];
41
+ }
42
+ }
43
+
44
+ const compliorFiles = ctx.files.filter((f) =>
45
+ f.relativePath.startsWith(COMPLIOR_DIR),
46
+ );
47
+
48
+ if (compliorFiles.length > 0) {
49
+ return [{
50
+ type: 'pass',
51
+ checkId: CHECK_ID,
52
+ message: `.complior/ directory found with compliance configuration`,
53
+ }];
54
+ }
55
+
56
+ const docsFiles = ctx.files.filter((f) =>
57
+ f.relativePath.startsWith('docs/') && f.extension === '.md',
58
+ );
59
+
60
+ for (const file of docsFiles) {
61
+ if (hasComplianceContent(file.content)) {
62
+ return [{
63
+ type: 'pass',
64
+ checkId: CHECK_ID,
65
+ message: `Compliance content found in docs: ${file.relativePath}`,
66
+ }];
67
+ }
68
+ }
69
+
70
+ return [{
71
+ type: 'fail',
72
+ checkId: CHECK_ID,
73
+ message: 'No compliance documentation found',
74
+ severity: 'medium',
75
+ obligationId: OBLIGATION_ID,
76
+ articleReference: 'Art. 11',
77
+ fix: 'Create a COMPLIANCE.md or .complior/ directory documenting your AI Act compliance measures',
78
+ }];
79
+ };
@@ -0,0 +1,120 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { gitHistoryToCheckResults } from './git-history.js';
3
+ import type { GitHistoryResult } from './git-history.js';
4
+
5
+ describe('gitHistoryToCheckResults', () => {
6
+ it('marks fresh documents as pass', () => {
7
+ const result: GitHistoryResult = {
8
+ fileHistories: [{
9
+ relativePath: 'docs/fria.md',
10
+ created: new Date(Date.now() - 30 * 86400000).toISOString(),
11
+ lastModified: new Date(Date.now() - 10 * 86400000).toISOString(),
12
+ commitCount: 5,
13
+ authors: ['Alice', 'Bob'],
14
+ daysSinceLastModified: 10,
15
+ }],
16
+ bulkCommits: [],
17
+ };
18
+
19
+ const checks = gitHistoryToCheckResults(result);
20
+ expect(checks.some((c) => c.type === 'pass' && c.checkId.includes('freshness'))).toBe(true);
21
+ });
22
+
23
+ it('warns about stale documents (>90 days)', () => {
24
+ const result: GitHistoryResult = {
25
+ fileHistories: [{
26
+ relativePath: 'docs/risk-management.md',
27
+ created: new Date(Date.now() - 200 * 86400000).toISOString(),
28
+ lastModified: new Date(Date.now() - 120 * 86400000).toISOString(),
29
+ commitCount: 2,
30
+ authors: ['Alice'],
31
+ daysSinceLastModified: 120,
32
+ }],
33
+ bulkCommits: [],
34
+ };
35
+
36
+ const checks = gitHistoryToCheckResults(result);
37
+ const stale = checks.find((c) => c.type === 'fail' && c.checkId.includes('freshness'));
38
+ expect(stale).toBeDefined();
39
+ expect(stale?.severity).toBe('low');
40
+ });
41
+
42
+ it('fails for very stale documents (>180 days)', () => {
43
+ const result: GitHistoryResult = {
44
+ fileHistories: [{
45
+ relativePath: 'docs/data-governance.md',
46
+ created: new Date(Date.now() - 365 * 86400000).toISOString(),
47
+ lastModified: new Date(Date.now() - 200 * 86400000).toISOString(),
48
+ commitCount: 1,
49
+ authors: ['Alice'],
50
+ daysSinceLastModified: 200,
51
+ }],
52
+ bulkCommits: [],
53
+ };
54
+
55
+ const checks = gitHistoryToCheckResults(result);
56
+ const stale = checks.find((c) => c.type === 'fail' && c.checkId.includes('freshness'));
57
+ expect(stale).toBeDefined();
58
+ expect(stale?.severity).toBe('medium');
59
+ });
60
+
61
+ it('warns about single-author risk documents', () => {
62
+ const result: GitHistoryResult = {
63
+ fileHistories: [{
64
+ relativePath: 'docs/fria.md',
65
+ created: new Date().toISOString(),
66
+ lastModified: new Date().toISOString(),
67
+ commitCount: 1,
68
+ authors: ['Alice'],
69
+ daysSinceLastModified: 5,
70
+ }],
71
+ bulkCommits: [],
72
+ };
73
+
74
+ const checks = gitHistoryToCheckResults(result);
75
+ const authorCheck = checks.find((c) => c.checkId.includes('author-diversity'));
76
+ expect(authorCheck).toBeDefined();
77
+ expect(authorCheck?.type).toBe('fail');
78
+ });
79
+
80
+ it('does not warn about single author for non-risk documents', () => {
81
+ const result: GitHistoryResult = {
82
+ fileHistories: [{
83
+ relativePath: 'docs/ai-literacy.md',
84
+ created: new Date().toISOString(),
85
+ lastModified: new Date().toISOString(),
86
+ commitCount: 1,
87
+ authors: ['Alice'],
88
+ daysSinceLastModified: 5,
89
+ }],
90
+ bulkCommits: [],
91
+ };
92
+
93
+ const checks = gitHistoryToCheckResults(result);
94
+ const authorCheck = checks.find((c) => c.checkId.includes('author-diversity'));
95
+ expect(authorCheck).toBeUndefined();
96
+ });
97
+
98
+ it('detects bulk compliance commits', () => {
99
+ const result: GitHistoryResult = {
100
+ fileHistories: [],
101
+ bulkCommits: [{
102
+ hash: 'abc1234567890',
103
+ docCount: 5,
104
+ date: '2026-03-01T10:00:00Z',
105
+ }],
106
+ };
107
+
108
+ const checks = gitHistoryToCheckResults(result);
109
+ const bulk = checks.find((c) => c.checkId === 'git-bulk-compliance');
110
+ expect(bulk).toBeDefined();
111
+ expect(bulk?.type).toBe('fail');
112
+ expect(bulk?.message).toContain('5 documents');
113
+ });
114
+
115
+ it('returns empty results for no histories', () => {
116
+ const result: GitHistoryResult = { fileHistories: [], bulkCommits: [] };
117
+ const checks = gitHistoryToCheckResults(result);
118
+ expect(checks).toEqual([]);
119
+ });
120
+ });
@@ -0,0 +1,163 @@
1
+ import type { CheckResult } from '../../../types/common.types.js';
2
+
3
+ export interface GitFileHistory {
4
+ readonly relativePath: string;
5
+ readonly created: string; // ISO date of first commit
6
+ readonly lastModified: string; // ISO date of last commit
7
+ readonly commitCount: number;
8
+ readonly authors: readonly string[];
9
+ readonly daysSinceLastModified: number;
10
+ }
11
+
12
+ export interface GitHistoryResult {
13
+ readonly fileHistories: readonly GitFileHistory[];
14
+ readonly bulkCommits: readonly { hash: string; docCount: number; date: string }[];
15
+ }
16
+
17
+ /** Port for git operations — keeps domain I/O-free (Clean Architecture). */
18
+ export interface GitHistoryPort {
19
+ readonly isGitRepo: (projectPath: string) => boolean;
20
+ readonly listTrackedFiles: (projectPath: string) => readonly string[];
21
+ readonly getFileLog: (projectPath: string, filePath: string) => readonly { hash: string; date: string; author: string }[];
22
+ }
23
+
24
+ const COMPLIANCE_DOCS = [
25
+ 'fria.md', 'risk-management.md', 'risk-assessment.md', 'data-governance.md',
26
+ 'technical-documentation.md', 'tech-documentation.md', 'transparency-notice.md',
27
+ 'human-oversight.md', 'incident-report.md', 'monitoring-plan.md', 'monitoring-policy.md',
28
+ 'worker-notification.md', 'ai-literacy.md', 'art5-screening.md', 'model-card.md',
29
+ 'declaration-of-conformity.md', 'declaration-conformity.md', 'qms.md',
30
+ 'quality-management.md', 'instructions-for-use.md', 'data-quality.md',
31
+ ];
32
+
33
+ const isComplianceDoc = (path: string): boolean => {
34
+ const filename = path.split('/').pop()?.toLowerCase() ?? '';
35
+ return COMPLIANCE_DOCS.some((doc) => filename === doc);
36
+ };
37
+
38
+ const daysBetween = (dateStr: string): number => {
39
+ const date = new Date(dateStr);
40
+ const now = new Date();
41
+ return Math.floor((now.getTime() - date.getTime()) / (1000 * 60 * 60 * 24));
42
+ };
43
+
44
+ /**
45
+ * Analyze git history for compliance documents.
46
+ * Pure domain function — receives git operations via port.
47
+ */
48
+ export const analyzeGitHistory = (projectPath: string, git: GitHistoryPort): GitHistoryResult => {
49
+ if (!git.isGitRepo(projectPath)) {
50
+ return { fileHistories: [], bulkCommits: [] };
51
+ }
52
+
53
+ const trackedFiles = git.listTrackedFiles(projectPath);
54
+ const compliancePaths = trackedFiles.filter(isComplianceDoc);
55
+
56
+ const fileHistories: GitFileHistory[] = [];
57
+ const commitDocMap = new Map<string, { docs: string[]; date: string }>();
58
+
59
+ for (const filePath of compliancePaths) {
60
+ const commits = git.getFileLog(projectPath, filePath);
61
+ if (commits.length === 0) continue;
62
+
63
+ const authors = [...new Set(commits.map((c) => c.author))];
64
+ const lastModified = commits[0]?.date ?? '';
65
+ const created = commits[commits.length - 1]?.date ?? '';
66
+
67
+ fileHistories.push({
68
+ relativePath: filePath,
69
+ created,
70
+ lastModified,
71
+ commitCount: commits.length,
72
+ authors,
73
+ daysSinceLastModified: daysBetween(lastModified),
74
+ });
75
+
76
+ for (const commit of commits) {
77
+ const existing = commitDocMap.get(commit.hash);
78
+ if (existing) {
79
+ existing.docs.push(filePath);
80
+ } else {
81
+ commitDocMap.set(commit.hash, { docs: [filePath], date: commit.date });
82
+ }
83
+ }
84
+ }
85
+
86
+ const bulkCommits = [...commitDocMap.entries()]
87
+ .filter(([, v]) => v.docs.length > 3)
88
+ .map(([hash, v]) => ({ hash, docCount: v.docs.length, date: v.date }));
89
+
90
+ return { fileHistories, bulkCommits };
91
+ };
92
+
93
+ /**
94
+ * Convert git history analysis into scanner CheckResults.
95
+ */
96
+ export const gitHistoryToCheckResults = (result: GitHistoryResult): readonly CheckResult[] => {
97
+ const checks: CheckResult[] = [];
98
+
99
+ for (const file of result.fileHistories) {
100
+ const docName = file.relativePath.split('/').pop() ?? file.relativePath;
101
+
102
+ // Freshness checks
103
+ if (file.daysSinceLastModified > 180) {
104
+ checks.push({
105
+ type: 'fail',
106
+ checkId: `git-freshness-${docName.replace(/\.md$/i, '')}`,
107
+ message: `${docName} not updated in ${file.daysSinceLastModified} days — may be outdated (Art. 9(2): "throughout the lifetime")`,
108
+ severity: 'medium',
109
+ obligationId: 'eu-ai-act-OBL-020',
110
+ articleReference: 'Art. 9(2)',
111
+ fix: `Review and update ${docName} — last modified ${file.lastModified.split('T')[0]}`,
112
+ file: file.relativePath,
113
+ });
114
+ } else if (file.daysSinceLastModified > 90) {
115
+ checks.push({
116
+ type: 'fail',
117
+ checkId: `git-freshness-${docName.replace(/\.md$/i, '')}`,
118
+ message: `${docName} not updated in ${file.daysSinceLastModified} days — consider reviewing`,
119
+ severity: 'low',
120
+ obligationId: 'eu-ai-act-OBL-020',
121
+ articleReference: 'Art. 9(2)',
122
+ fix: `Review ${docName} for accuracy — last modified ${file.lastModified.split('T')[0]}`,
123
+ file: file.relativePath,
124
+ });
125
+ } else {
126
+ checks.push({
127
+ type: 'pass',
128
+ checkId: `git-freshness-${docName.replace(/\.md$/i, '')}`,
129
+ message: `${docName} is fresh — last updated ${file.daysSinceLastModified}d ago (${file.commitCount} commits)`,
130
+ });
131
+ }
132
+
133
+ // Single-author warning for risk assessments and FRIAs
134
+ const isRiskDoc = /fria|risk/i.test(docName);
135
+ if (isRiskDoc && file.authors.length === 1) {
136
+ checks.push({
137
+ type: 'fail',
138
+ checkId: `git-author-diversity-${docName.replace(/\.md$/i, '')}`,
139
+ message: `${docName} has only 1 author (${file.authors[0]}) — multi-stakeholder review recommended`,
140
+ severity: 'info',
141
+ obligationId: 'eu-ai-act-OBL-013',
142
+ articleReference: 'Art. 27(1)',
143
+ fix: `Have additional stakeholders review and commit to ${docName}`,
144
+ file: file.relativePath,
145
+ });
146
+ }
147
+ }
148
+
149
+ // Bulk commit detection
150
+ for (const bulk of result.bulkCommits) {
151
+ checks.push({
152
+ type: 'fail',
153
+ checkId: 'git-bulk-compliance',
154
+ message: `Bulk compliance commit detected: ${bulk.docCount} documents in single commit ${bulk.hash.slice(0, 7)} (${bulk.date.split('T')[0]})`,
155
+ severity: 'low',
156
+ obligationId: 'eu-ai-act-OBL-020',
157
+ articleReference: 'Art. 9(2)',
158
+ fix: 'Compliance documents should be maintained incrementally, not created in bulk',
159
+ });
160
+ }
161
+
162
+ return checks;
163
+ };
@@ -0,0 +1,84 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { checkGpaiSystemicRisk } from './gpai-systemic-risk.js';
3
+ import { createScanFile, createScanCtx } from '../../../test-helpers/factories.js';
4
+
5
+ describe('checkGpaiSystemicRisk', () => {
6
+ it('returns skip when no GPAI indicators in codebase', () => {
7
+ const ctx = createScanCtx([
8
+ createScanFile('src/app.ts', 'function main() { return "hello"; }'),
9
+ createScanFile('src/utils.ts', 'export const add = (a: number, b: number) => a + b;'),
10
+ ]);
11
+
12
+ const results = checkGpaiSystemicRisk(ctx);
13
+
14
+ expect(results).toHaveLength(1);
15
+ expect(results[0].type).toBe('skip');
16
+ });
17
+
18
+ it('returns pass when dedicated systemic risk doc exists', () => {
19
+ const ctx = createScanCtx([
20
+ createScanFile('docs/GPAI-SYSTEMIC-RISK-ASSESSMENT.md', '# GPAI Systemic Risk Assessment\n\nContent here.'),
21
+ createScanFile('src/app.ts', 'function main() {}'),
22
+ ]);
23
+
24
+ const results = checkGpaiSystemicRisk(ctx);
25
+
26
+ expect(results).toHaveLength(1);
27
+ expect(results[0].type).toBe('pass');
28
+ expect(results[0].message).toContain('GPAI-SYSTEMIC-RISK-ASSESSMENT.md');
29
+ });
30
+
31
+ it('returns pass when md files contain systemic risk content', () => {
32
+ const ctx = createScanCtx([
33
+ createScanFile('docs/RISK-MANAGEMENT.md', '# Risk Management\n\nWe conduct adversarial testing on all model outputs.'),
34
+ createScanFile('src/app.ts', 'function main() {}'),
35
+ ]);
36
+
37
+ const results = checkGpaiSystemicRisk(ctx);
38
+
39
+ expect(results).toHaveLength(1);
40
+ expect(results[0].type).toBe('pass');
41
+ expect(results[0].message).toContain('systemic risk content found');
42
+ });
43
+
44
+ it('returns fail when code has LLM indicators without risk doc', () => {
45
+ const ctx = createScanCtx([
46
+ createScanFile('src/model.ts', 'const model = "large language model"; // our provider uses LLM'),
47
+ createScanFile('docs/README.md', '# Project\n\nA simple tool.'),
48
+ ]);
49
+
50
+ const results = checkGpaiSystemicRisk(ctx);
51
+
52
+ expect(results).toHaveLength(1);
53
+ expect(results[0].type).toBe('fail');
54
+ expect(results[0].severity).toBe('high');
55
+ expect(results[0].message).toContain('systemic risk indicators detected');
56
+ });
57
+
58
+ it('does NOT trigger on markdown docs describing the model', () => {
59
+ const ctx = createScanCtx([
60
+ createScanFile('docs/compliance/TECH-DOCUMENTATION.md',
61
+ '# Technical Documentation\n\n## General Description\nThis system uses a large language model provided by the vendor.\n\n## System Elements\nIntegration details.'),
62
+ createScanFile('src/app.ts', 'function main() { return "hello"; }'),
63
+ ]);
64
+
65
+ const results = checkGpaiSystemicRisk(ctx);
66
+
67
+ expect(results).toHaveLength(1);
68
+ // .md files excluded from indicator scan → no indicators in code → skip
69
+ expect(results[0].type).toBe('skip');
70
+ });
71
+
72
+ it('returns fail for FLOP threshold in code', () => {
73
+ const ctx = createScanCtx([
74
+ createScanFile('src/config.ts', 'const COMPUTE_BUDGET = "10^25"; // FLOP threshold'),
75
+ createScanFile('docs/README.md', '# Project docs'),
76
+ ]);
77
+
78
+ const results = checkGpaiSystemicRisk(ctx);
79
+
80
+ expect(results).toHaveLength(1);
81
+ expect(results[0].type).toBe('fail');
82
+ expect(results[0].severity).toBe('high');
83
+ });
84
+ });
@@ -0,0 +1,98 @@
1
+ import type { CheckResult } from '../../../types/common.types.js';
2
+ import type { ScanContext } from '../../../ports/scanner.port.js';
3
+
4
+ const CHECK_ID = 'gpai-systemic-risk';
5
+ const ARTICLE_REF = 'Art. 55';
6
+ const OBLIGATION_ID = 'eu-ai-act-OBL-023';
7
+
8
+ const DOC_PATTERNS: readonly RegExp[] = [
9
+ /^GPAI[-_]?SYSTEMIC[-_]?RISK/i,
10
+ /^SYSTEMIC[-_]?RISK[-_]?ASSESSMENT/i,
11
+ /^GPAI[-_]?RISK[-_]?ASSESSMENT/i,
12
+ /^MODEL[-_]?RISK[-_]?ASSESSMENT/i,
13
+ ];
14
+
15
+ const CONTENT_PATTERNS: readonly RegExp[] = [
16
+ /\bsystemic risk\b/i,
17
+ /\badversarial testing\b/i,
18
+ /\bred teaming\b/i,
19
+ /\bincident monitoring\b.*\bgpai\b/i,
20
+ /\bgpai\b.*\bincident monitoring\b/i,
21
+ /\bmodel evaluation\b.*\bsafety\b/i,
22
+ ];
23
+
24
+ /** Indicators that the project deals with GPAI models that may have systemic risk. */
25
+ const SYSTEMIC_INDICATORS: readonly RegExp[] = [
26
+ /\b10\^25\b|\b1e25\b/i, // FLOP threshold (Art. 51)
27
+ /\bsystemic risk\b/i,
28
+ /\bfoundation model\b.*\blarge\b/i,
29
+ /\blarge language model\b/i,
30
+ /\bfrontier model\b/i,
31
+ /\bgeneral[-_ ]?purpose ai\b.*\bsystemic\b/i,
32
+ ];
33
+
34
+ const isDocFile = (relativePath: string): boolean => {
35
+ const filename = relativePath.split('/').pop() ?? '';
36
+ return DOC_PATTERNS.some((p) => p.test(filename));
37
+ };
38
+
39
+ const hasContent = (content: string): boolean =>
40
+ CONTENT_PATTERNS.some((p) => p.test(content));
41
+
42
+ const hasSystemicIndicators = (content: string): boolean =>
43
+ SYSTEMIC_INDICATORS.some((p) => p.test(content));
44
+
45
+ export const checkGpaiSystemicRisk = (ctx: ScanContext): readonly CheckResult[] => {
46
+ // 1. Check for dedicated systemic risk doc file
47
+ for (const file of ctx.files) {
48
+ if (isDocFile(file.relativePath)) {
49
+ return [{
50
+ type: 'pass',
51
+ checkId: CHECK_ID,
52
+ message: `GPAI systemic risk assessment found: ${file.relativePath} (${ARTICLE_REF})`,
53
+ }];
54
+ }
55
+ }
56
+
57
+ // 2. Check markdown files for systemic risk content
58
+ const docsFiles = ctx.files.filter((f) => f.extension === '.md');
59
+ for (const file of docsFiles) {
60
+ if (hasContent(file.content)) {
61
+ return [{
62
+ type: 'pass',
63
+ checkId: CHECK_ID,
64
+ message: `GPAI systemic risk content found in: ${file.relativePath} (${ARTICLE_REF})`,
65
+ }];
66
+ }
67
+ }
68
+
69
+ // 3. Only flag if project has systemic risk indicators in code/config files.
70
+ // Compliance docs that merely describe a provider's model (e.g., "large language model")
71
+ // should not trigger systemic risk assessment requirements for deployers.
72
+ const codeFiles = ctx.files.filter((f) => f.extension !== '.md');
73
+ let indicatorsFound = false;
74
+ for (const file of codeFiles) {
75
+ if (hasSystemicIndicators(file.content)) {
76
+ indicatorsFound = true;
77
+ break;
78
+ }
79
+ }
80
+
81
+ if (indicatorsFound) {
82
+ return [{
83
+ type: 'fail',
84
+ checkId: CHECK_ID,
85
+ message: `GPAI systemic risk indicators detected without risk assessment (${ARTICLE_REF})`,
86
+ severity: 'high',
87
+ obligationId: OBLIGATION_ID,
88
+ articleReference: ARTICLE_REF,
89
+ fix: 'Create a GPAI-SYSTEMIC-RISK-ASSESSMENT.md with adversarial testing, incident monitoring, and cybersecurity measures',
90
+ }];
91
+ }
92
+
93
+ return [{
94
+ type: 'skip',
95
+ checkId: CHECK_ID,
96
+ reason: 'No GPAI systemic risk indicators detected',
97
+ }];
98
+ };
@@ -0,0 +1,94 @@
1
+ import type { CheckResult } from '../../../types/common.types.js';
2
+ import type { ScanContext } from '../../../ports/scanner.port.js';
3
+
4
+ const CHECK_ID = 'gpai-transparency';
5
+ const ARTICLE_REF = 'Art. 51-53';
6
+ const OBLIGATION_ID = 'eu-ai-act-OBL-022';
7
+
8
+ const GPAI_DOC_PATTERNS: readonly RegExp[] = [
9
+ /^MODEL[-_]?CARD\.md$/i,
10
+ /^model[-_]?card\./i,
11
+ /^GPAI[-_]?DOCUMENTATION/i,
12
+ /^TRAINING[-_]?DATA[-_]?DOCUMENTATION/i,
13
+ /^MODEL[-_]?DOCUMENTATION/i,
14
+ ];
15
+
16
+ const GPAI_CONTENT_PATTERNS: readonly RegExp[] = [
17
+ /\bmodel card\b/i,
18
+ /\btraining data\b.*\bdocumentation\b/i,
19
+ /\bgpai\b/i,
20
+ /\bgeneral[-_ ]?purpose ai\b/i,
21
+ /\bfoundation model\b/i,
22
+ /\bmodel transparency\b/i,
23
+ ];
24
+
25
+ const GPAI_USAGE_PATTERNS: readonly RegExp[] = [
26
+ /\bfine[-_]?tun/i,
27
+ /\bmodel training\b/i,
28
+ /\btraining pipeline\b/i,
29
+ /\bmodel weights\b/i,
30
+ /\bpre[-_]?train/i,
31
+ /\btransformers\b/,
32
+ /\btorch\b/,
33
+ /\btensorflow\b/i,
34
+ ];
35
+
36
+ const isGpaiDocFile = (relativePath: string): boolean => {
37
+ const filename = relativePath.split('/').pop() ?? '';
38
+ return GPAI_DOC_PATTERNS.some((p) => p.test(filename));
39
+ };
40
+
41
+ const hasGpaiContent = (content: string): boolean =>
42
+ GPAI_CONTENT_PATTERNS.some((p) => p.test(content));
43
+
44
+ const hasGpaiUsage = (content: string): boolean =>
45
+ GPAI_USAGE_PATTERNS.some((p) => p.test(content));
46
+
47
+ export const checkGpaiTransparency = (ctx: ScanContext): readonly CheckResult[] => {
48
+ for (const file of ctx.files) {
49
+ if (isGpaiDocFile(file.relativePath)) {
50
+ return [{
51
+ type: 'pass',
52
+ checkId: CHECK_ID,
53
+ message: `GPAI documentation found: ${file.relativePath} (${ARTICLE_REF})`,
54
+ }];
55
+ }
56
+ }
57
+
58
+ const docsFiles = ctx.files.filter((f) => f.extension === '.md');
59
+ for (const file of docsFiles) {
60
+ if (hasGpaiContent(file.content)) {
61
+ return [{
62
+ type: 'pass',
63
+ checkId: CHECK_ID,
64
+ message: `GPAI transparency content found in: ${file.relativePath} (${ARTICLE_REF})`,
65
+ }];
66
+ }
67
+ }
68
+
69
+ let gpaiUsageFound = false;
70
+ for (const file of ctx.files) {
71
+ if (hasGpaiUsage(file.content)) {
72
+ gpaiUsageFound = true;
73
+ break;
74
+ }
75
+ }
76
+
77
+ if (gpaiUsageFound) {
78
+ return [{
79
+ type: 'fail',
80
+ checkId: CHECK_ID,
81
+ message: `GPAI/model training code detected without transparency documentation (${ARTICLE_REF})`,
82
+ severity: 'high',
83
+ obligationId: OBLIGATION_ID,
84
+ articleReference: ARTICLE_REF,
85
+ fix: 'Create a MODEL_CARD.md with model capabilities, limitations, training data, and intended use',
86
+ }];
87
+ }
88
+
89
+ return [{
90
+ type: 'skip',
91
+ checkId: CHECK_ID,
92
+ reason: 'No GPAI/model training usage detected',
93
+ }];
94
+ };
@@ -0,0 +1,28 @@
1
+ export { checkAiDisclosure } from './ai-disclosure.js';
2
+ export { checkAiLiteracy } from './ai-literacy.js';
3
+ export { checkBehavioralConstraints } from './behavioral-constraints.js';
4
+ export { checkComplianceMetadata } from './compliance-metadata.js';
5
+ export { checkContentMarking } from './content-marking.js';
6
+ export { checkDocumentation } from './documentation.js';
7
+ export { checkGpaiSystemicRisk } from './gpai-systemic-risk.js';
8
+ export { checkGpaiTransparency } from './gpai-transparency.js';
9
+ export { checkInteractionLogging } from './interaction-logging.js';
10
+ export { checkPassportCompleteness } from './passport-completeness.js';
11
+ export { checkPassportPresence } from './passport-presence.js';
12
+ export { checkPermissions } from './permission-scanner.js';
13
+ export { checkIndustryPatterns } from './industry/index.js';
14
+ export { createPatternCheck } from './pattern-check-factory.js';
15
+ export type { PatternCheckConfig } from './pattern-check-factory.js';
16
+ export { createPresenceCheck, ALL_PRESENCE_CONFIGS } from './presence-check-factory.js';
17
+ export { checkFriaPresence, checkArt5ScreeningPresence, checkTechnicalDocumentationPresence } from './presence-check-factory.js';
18
+ export { checkIncidentReportPresence, checkDeclarationOfConformityPresence } from './presence-check-factory.js';
19
+ export { checkMonitoringPolicyPresence, checkWorkerNotificationPresence } from './presence-check-factory.js';
20
+ export { checkRiskManagementPresence, checkDataGovernancePresence } from './presence-check-factory.js';
21
+ export { checkQmsPresence, checkInstructionsForUsePresence } from './presence-check-factory.js';
22
+ export type { PresenceCheckConfig } from './presence-check-factory.js';
23
+ export { runDepDeepScan, depScanToCheckResults } from './dep-deep-scan.js';
24
+ export type { DepScanResult, KnownVulnerability } from './dep-deep-scan.js';
25
+ export { analyzeGitHistory, gitHistoryToCheckResults } from './git-history.js';
26
+ export type { GitFileHistory, GitHistoryPort, GitHistoryResult } from './git-history.js';
27
+ export { runNhiScan, nhiToCheckResults } from './nhi-scanner.js';
28
+ export type { NhiCheckResult } from './nhi-scanner.js';