opencomplai-core 0.1.0__tar.gz

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 (117) hide show
  1. opencomplai_core-0.1.0/.gitignore +69 -0
  2. opencomplai_core-0.1.0/PKG-INFO +108 -0
  3. opencomplai_core-0.1.0/README.md +90 -0
  4. opencomplai_core-0.1.0/pyproject.toml +29 -0
  5. opencomplai_core-0.1.0/src/opencomplai_core/__init__.py +22 -0
  6. opencomplai_core-0.1.0/src/opencomplai_core/adapters/__init__.py +25 -0
  7. opencomplai_core-0.1.0/src/opencomplai_core/adapters/base.py +33 -0
  8. opencomplai_core-0.1.0/src/opencomplai_core/adapters/http.py +57 -0
  9. opencomplai_core-0.1.0/src/opencomplai_core/adapters/offline.py +27 -0
  10. opencomplai_core-0.1.0/src/opencomplai_core/compliance_checker/__init__.py +28 -0
  11. opencomplai_core-0.1.0/src/opencomplai_core/compliance_checker/bridge.py +30 -0
  12. opencomplai_core-0.1.0/src/opencomplai_core/compliance_checker/catalog.py +50 -0
  13. opencomplai_core-0.1.0/src/opencomplai_core/compliance_checker/data/help_content.json +56 -0
  14. opencomplai_core-0.1.0/src/opencomplai_core/compliance_checker/data/obligations.json +67 -0
  15. opencomplai_core-0.1.0/src/opencomplai_core/compliance_checker/data/status_changes.json +34 -0
  16. opencomplai_core-0.1.0/src/opencomplai_core/compliance_checker/engine.py +292 -0
  17. opencomplai_core-0.1.0/src/opencomplai_core/compliance_checker/models.py +73 -0
  18. opencomplai_core-0.1.0/src/opencomplai_core/compliance_checker/report.py +141 -0
  19. opencomplai_core-0.1.0/src/opencomplai_core/dossier.py +155 -0
  20. opencomplai_core-0.1.0/src/opencomplai_core/engine.py +70 -0
  21. opencomplai_core-0.1.0/src/opencomplai_core/eval_engine.py +128 -0
  22. opencomplai_core-0.1.0/src/opencomplai_core/evaluators/__init__.py +5 -0
  23. opencomplai_core-0.1.0/src/opencomplai_core/evaluators/_hashing.py +26 -0
  24. opencomplai_core-0.1.0/src/opencomplai_core/evaluators/base.py +26 -0
  25. opencomplai_core-0.1.0/src/opencomplai_core/evaluators/bias.py +158 -0
  26. opencomplai_core-0.1.0/src/opencomplai_core/evaluators/data/safety_signatures.json +27 -0
  27. opencomplai_core-0.1.0/src/opencomplai_core/evaluators/leakage.py +174 -0
  28. opencomplai_core-0.1.0/src/opencomplai_core/evaluators/registry.py +15 -0
  29. opencomplai_core-0.1.0/src/opencomplai_core/evaluators/safety.py +107 -0
  30. opencomplai_core-0.1.0/src/opencomplai_core/models.py +708 -0
  31. opencomplai_core-0.1.0/src/opencomplai_core/purge.py +23 -0
  32. opencomplai_core-0.1.0/src/opencomplai_core/rules.py +360 -0
  33. opencomplai_core-0.1.0/src/opencomplai_core/scan_engine.py +644 -0
  34. opencomplai_core-0.1.0/src/opencomplai_core/scanner/__init__.py +11 -0
  35. opencomplai_core-0.1.0/src/opencomplai_core/scanner/_hashing.py +64 -0
  36. opencomplai_core-0.1.0/src/opencomplai_core/scanner/ai_usage_gate.py +320 -0
  37. opencomplai_core-0.1.0/src/opencomplai_core/scanner/base.py +34 -0
  38. opencomplai_core-0.1.0/src/opencomplai_core/scanner/cache.py +86 -0
  39. opencomplai_core-0.1.0/src/opencomplai_core/scanner/config_ai_sites.py +67 -0
  40. opencomplai_core-0.1.0/src/opencomplai_core/scanner/constants.py +5 -0
  41. opencomplai_core-0.1.0/src/opencomplai_core/scanner/data/ai_signals.json +10 -0
  42. opencomplai_core-0.1.0/src/opencomplai_core/scanner/detectors/__init__.py +1 -0
  43. opencomplai_core-0.1.0/src/opencomplai_core/scanner/detectors/_common.py +55 -0
  44. opencomplai_core-0.1.0/src/opencomplai_core/scanner/detectors/_signals.py +104 -0
  45. opencomplai_core-0.1.0/src/opencomplai_core/scanner/detectors/ai_dependency.py +61 -0
  46. opencomplai_core-0.1.0/src/opencomplai_core/scanner/detectors/artifact.py +56 -0
  47. opencomplai_core-0.1.0/src/opencomplai_core/scanner/detectors/ast_usage.py +95 -0
  48. opencomplai_core-0.1.0/src/opencomplai_core/scanner/detectors/biometric.py +74 -0
  49. opencomplai_core-0.1.0/src/opencomplai_core/scanner/detectors/dataflow.py +73 -0
  50. opencomplai_core-0.1.0/src/opencomplai_core/scanner/detectors/endpoint.py +61 -0
  51. opencomplai_core-0.1.0/src/opencomplai_core/scanner/detectors/semantic.py +98 -0
  52. opencomplai_core-0.1.0/src/opencomplai_core/scanner/extractors/__init__.py +1 -0
  53. opencomplai_core-0.1.0/src/opencomplai_core/scanner/extractors/artifacts.py +24 -0
  54. opencomplai_core-0.1.0/src/opencomplai_core/scanner/extractors/ast.py +80 -0
  55. opencomplai_core-0.1.0/src/opencomplai_core/scanner/extractors/config.py +69 -0
  56. opencomplai_core-0.1.0/src/opencomplai_core/scanner/extractors/manifests.py +109 -0
  57. opencomplai_core-0.1.0/src/opencomplai_core/scanner/extractors/notebooks.py +51 -0
  58. opencomplai_core-0.1.0/src/opencomplai_core/scanner/feature_types.py +99 -0
  59. opencomplai_core-0.1.0/src/opencomplai_core/scanner/features.py +84 -0
  60. opencomplai_core-0.1.0/src/opencomplai_core/scanner/file_ai_context.py +99 -0
  61. opencomplai_core-0.1.0/src/opencomplai_core/scanner/fusion.py +95 -0
  62. opencomplai_core-0.1.0/src/opencomplai_core/scanner/inventory.py +242 -0
  63. opencomplai_core-0.1.0/src/opencomplai_core/scanner/mapping.py +77 -0
  64. opencomplai_core-0.1.0/src/opencomplai_core/scanner/ocignore.py +315 -0
  65. opencomplai_core-0.1.0/src/opencomplai_core/scanner/registry.py +22 -0
  66. opencomplai_core-0.1.0/src/opencomplai_core/scanner/snippet_cache.py +58 -0
  67. opencomplai_core-0.1.0/src/opencomplai_core/signing.py +152 -0
  68. opencomplai_core-0.1.0/src/opencomplai_core/state_machine.py +123 -0
  69. opencomplai_core-0.1.0/src/opencomplai_core/telemetry.py +181 -0
  70. opencomplai_core-0.1.0/src/opencomplai_core/verification.py +121 -0
  71. opencomplai_core-0.1.0/tests/__init__.py +1 -0
  72. opencomplai_core-0.1.0/tests/fixtures/fli_golden/01_auth_rep_only.json +23 -0
  73. opencomplai_core-0.1.0/tests/fixtures/fli_golden/02_out_of_scope_not_ai.json +21 -0
  74. opencomplai_core-0.1.0/tests/fixtures/fli_golden/03_out_of_scope_s1.json +25 -0
  75. opencomplai_core-0.1.0/tests/fixtures/fli_golden/04_out_of_scope_excluded.json +27 -0
  76. opencomplai_core-0.1.0/tests/fixtures/fli_golden/05_prohibited.json +32 -0
  77. opencomplai_core-0.1.0/tests/fixtures/fli_golden/06_high_risk_provider.json +31 -0
  78. opencomplai_core-0.1.0/tests/fixtures/fli_golden/07_high_risk_deployer_fria.json +37 -0
  79. opencomplai_core-0.1.0/tests/fixtures/fli_golden/08_become_provider.json +34 -0
  80. opencomplai_core-0.1.0/tests/fixtures/fli_golden/09_gpai_provider.json +31 -0
  81. opencomplai_core-0.1.0/tests/fixtures/fli_golden/10_gpai_systemic_risk.json +34 -0
  82. opencomplai_core-0.1.0/tests/fixtures/fli_golden/11_transparency_only_deployer.json +30 -0
  83. opencomplai_core-0.1.0/tests/fixtures/fli_golden/12_product_manufacturer_out_of_scope.json +25 -0
  84. opencomplai_core-0.1.0/tests/fixtures/fli_golden/13_high_risk_exception_deployer.json +36 -0
  85. opencomplai_core-0.1.0/tests/fixtures/fli_golden/14_distributor_high_risk.json +29 -0
  86. opencomplai_core-0.1.0/tests/fixtures/fli_golden/15_distributor_not_high_risk.json +23 -0
  87. opencomplai_core-0.1.0/tests/fixtures/fli_golden/16_handover_provider.json +34 -0
  88. opencomplai_core-0.1.0/tests/fixtures/fli_golden/17_hr6_not_high_risk.json +28 -0
  89. opencomplai_core-0.1.0/tests/test_ai_usage_gate.py +159 -0
  90. opencomplai_core-0.1.0/tests/test_code_signal_matching.py +57 -0
  91. opencomplai_core-0.1.0/tests/test_compliance_checker_engine.py +134 -0
  92. opencomplai_core-0.1.0/tests/test_compliance_checker_golden.py +38 -0
  93. opencomplai_core-0.1.0/tests/test_compliance_checker_report.py +50 -0
  94. opencomplai_core-0.1.0/tests/test_config_ai_sites.py +121 -0
  95. opencomplai_core-0.1.0/tests/test_engine.py +79 -0
  96. opencomplai_core-0.1.0/tests/test_eval_engine.py +27 -0
  97. opencomplai_core-0.1.0/tests/test_evaluators_bias.py +54 -0
  98. opencomplai_core-0.1.0/tests/test_evaluators_leakage.py +43 -0
  99. opencomplai_core-0.1.0/tests/test_evaluators_safety.py +48 -0
  100. opencomplai_core-0.1.0/tests/test_false_positive_controls.py +55 -0
  101. opencomplai_core-0.1.0/tests/test_feature_extractors.py +69 -0
  102. opencomplai_core-0.1.0/tests/test_gold_set.py +114 -0
  103. opencomplai_core-0.1.0/tests/test_no_source_in_evidence.py +25 -0
  104. opencomplai_core-0.1.0/tests/test_ocignore.py +137 -0
  105. opencomplai_core-0.1.0/tests/test_purge.py +44 -0
  106. opencomplai_core-0.1.0/tests/test_repo_inventory.py +91 -0
  107. opencomplai_core-0.1.0/tests/test_scan_engine.py +268 -0
  108. opencomplai_core-0.1.0/tests/test_scanner_cache.py +47 -0
  109. opencomplai_core-0.1.0/tests/test_scanner_detectors.py +47 -0
  110. opencomplai_core-0.1.0/tests/test_scanner_mapping.py +61 -0
  111. opencomplai_core-0.1.0/tests/test_scanner_models.py +125 -0
  112. opencomplai_core-0.1.0/tests/test_signal_fusion.py +85 -0
  113. opencomplai_core-0.1.0/tests/test_signals_matching.py +28 -0
  114. opencomplai_core-0.1.0/tests/test_signing.py +104 -0
  115. opencomplai_core-0.1.0/tests/test_state_machine.py +74 -0
  116. opencomplai_core-0.1.0/tests/test_telemetry.py +72 -0
  117. opencomplai_core-0.1.0/tests/test_verification.py +172 -0
@@ -0,0 +1,69 @@
1
+ # Python
2
+ __pycache__/
3
+ *.pyc
4
+ *.pyo
5
+ .pytest_cache/
6
+ *.egg-info/
7
+ dist/
8
+ build/
9
+ .coverage
10
+ htmlcov/
11
+ .mypy_cache/
12
+
13
+ # uv — DO NOT ignore uv.lock
14
+ .venv/
15
+
16
+ # Node.js
17
+ node_modules/
18
+ dist/
19
+ *.js.map
20
+ .pnpm-store/
21
+
22
+ # Editors
23
+ .idea/
24
+ .vscode/
25
+ *.swp
26
+ .DS_Store
27
+ .cursor/*
28
+ .autopilot.json
29
+
30
+ # Secrets
31
+ .env
32
+ *.pem
33
+ *.key
34
+
35
+ # Docs build output
36
+ site/
37
+ docs/site/
38
+ docs-env/
39
+ .mkdocs/
40
+
41
+ # Build artifacts
42
+ .mintlify/
43
+
44
+ # Opencomplai generated artifacts (output of `opencomplai init` / `opencomplai check`)
45
+ compliance-artifact.json
46
+ system-manifest.json
47
+ # ...but keep the committed example fixtures used by the scanner docs
48
+ !examples/sample-system/**/system-manifest.json
49
+ !tests/fixtures/**/system-manifest.json
50
+ .venv-ci-check/*
51
+ # GitHub issues sync output (local mirror; may contain PII from issues)
52
+ github-issues/
53
+
54
+ docs/src/assets/js/checker-widget.js
55
+ docs/checker-widget/src/data/
56
+ docs/checker-widget/node_modules/
57
+ packages/cli/src/opencomplai_cli/data/checker-local.html
58
+
59
+ # --- Public-repo hardening (keep AI-tooling and internal artifacts out) ---
60
+ .claude/
61
+ .cursor/
62
+ .autopilot.json
63
+ .selfaudit/
64
+ compliance-reports/
65
+ *.plan.md
66
+ x.key
67
+ .tmp-*.db
68
+ ci-logs/
69
+ tmp/
@@ -0,0 +1,108 @@
1
+ Metadata-Version: 2.4
2
+ Name: opencomplai-core
3
+ Version: 0.1.0
4
+ Summary: Opencomplai core risk assessment engine for EU AI Act compliance
5
+ Project-URL: Homepage, https://opencomplai.com
6
+ Project-URL: Documentation, https://docs.opencomplai.com
7
+ Author-email: Opencomplai <hello@opencomplai.com>
8
+ License: AGPL-3.0-only
9
+ Requires-Python: >=3.11
10
+ Requires-Dist: cryptography>=48.0.1
11
+ Requires-Dist: pydantic>=2.0
12
+ Provides-Extra: dev
13
+ Requires-Dist: pytest>=7.0; extra == 'dev'
14
+ Requires-Dist: ruff>=0.1.0; extra == 'dev'
15
+ Provides-Extra: reports
16
+ Requires-Dist: fpdf2>=2.7; extra == 'reports'
17
+ Description-Content-Type: text/markdown
18
+
19
+ # opencomplai-core
20
+
21
+ [![License: AGPL-3.0](https://img.shields.io/badge/license-AGPL--3.0-blue.svg)](https://www.gnu.org/licenses/agpl-3.0)
22
+ [![PyPI](https://img.shields.io/pypi/v/opencomplai-core.svg)](https://pypi.org/project/opencomplai-core/)
23
+ [![Python](https://img.shields.io/badge/python-3.11%2B-blue.svg)](https://www.python.org/)
24
+
25
+ The EU AI Act compliance risk engine at the heart of [Opencomplai](https://opencomplai.com).
26
+ `opencomplai-core` turns a declared `system-manifest.json` and your source tree into a
27
+ deterministic, rule-based risk classification — no LLM calls, no network access, fully
28
+ reproducible.
29
+
30
+ It powers risk classification (`UnacceptableRiskRule`, `AnnexIIIClassifierRule`,
31
+ `ProfilingDetectionRule`, `SubstantialModificationRule`) and the code-corroboration scan
32
+ engine that cross-checks what a manifest *claims* against what the code actually does.
33
+
34
+ ## Install
35
+
36
+ ```bash
37
+ pip install opencomplai-core
38
+ ```
39
+
40
+ For PDF report generation, install the optional extra:
41
+
42
+ ```bash
43
+ pip install "opencomplai-core[reports]"
44
+ ```
45
+
46
+ > Most users want the [`opencomplai`](https://pypi.org/project/opencomplai/) meta-package
47
+ > (engine + CLI) or the [`opencomplai-cli`](https://pypi.org/project/opencomplai-cli/)
48
+ > command-line tool. Install `opencomplai-core` directly when you are embedding the engine
49
+ > in your own application.
50
+
51
+ ## Quick start
52
+
53
+ ### Classify a model from a declared manifest
54
+
55
+ ```python
56
+ from opencomplai import assess, AssessmentInput, ModelMetadata
57
+
58
+ result = assess(AssessmentInput(
59
+ model=ModelMetadata(
60
+ name="loan-scorer",
61
+ version="1.0.0",
62
+ modality="tabular",
63
+ use_case="creditworthiness scoring for consumer loans",
64
+ deployment_context="production",
65
+ )
66
+ ))
67
+
68
+ print(result.risk_level) # e.g. RiskLevel.HIGH
69
+ for rule in result.rule_results:
70
+ print(rule.rule_id, "PASS" if rule.passed else "FAIL")
71
+ ```
72
+
73
+ ### Corroborate a manifest against the code
74
+
75
+ ```python
76
+ from pathlib import Path
77
+ from opencomplai_core.scan_engine import run_scan
78
+
79
+ report = run_scan(
80
+ repo_root=Path("."),
81
+ commit_ref="HEAD",
82
+ )
83
+
84
+ print(report.summary.result) # PASS / CONTROL_FAIL / ...
85
+ for finding in report.findings:
86
+ print(finding.finding_id, finding.mapped_taxonomy)
87
+ ```
88
+
89
+ The scan engine extracts features from the repository, fuses evidence across detectors,
90
+ and maps findings to EU AI Act taxonomy (Annex III high-risk areas, Article 5 prohibited
91
+ practices, profiling under Article 6).
92
+
93
+ ## What you get
94
+
95
+ - **Deterministic risk classification** — same inputs always produce the same output, so
96
+ results are auditable and CI-gateable.
97
+ - **Code corroboration** — detect when a manifest under-declares (claims minimal risk while
98
+ the code does biometric identification, profiling, etc.).
99
+ - **Merkle-linked evidence** — findings carry verifiable evidence items for audit trails.
100
+
101
+ ## Documentation
102
+
103
+ Full docs, the EU AI Act concepts guide, and the SDK reference live at
104
+ **[docs.opencomplai.com](https://docs.opencomplai.com)**.
105
+
106
+ ## License
107
+
108
+ AGPL-3.0-only. See [LICENSE](https://www.gnu.org/licenses/agpl-3.0).
@@ -0,0 +1,90 @@
1
+ # opencomplai-core
2
+
3
+ [![License: AGPL-3.0](https://img.shields.io/badge/license-AGPL--3.0-blue.svg)](https://www.gnu.org/licenses/agpl-3.0)
4
+ [![PyPI](https://img.shields.io/pypi/v/opencomplai-core.svg)](https://pypi.org/project/opencomplai-core/)
5
+ [![Python](https://img.shields.io/badge/python-3.11%2B-blue.svg)](https://www.python.org/)
6
+
7
+ The EU AI Act compliance risk engine at the heart of [Opencomplai](https://opencomplai.com).
8
+ `opencomplai-core` turns a declared `system-manifest.json` and your source tree into a
9
+ deterministic, rule-based risk classification — no LLM calls, no network access, fully
10
+ reproducible.
11
+
12
+ It powers risk classification (`UnacceptableRiskRule`, `AnnexIIIClassifierRule`,
13
+ `ProfilingDetectionRule`, `SubstantialModificationRule`) and the code-corroboration scan
14
+ engine that cross-checks what a manifest *claims* against what the code actually does.
15
+
16
+ ## Install
17
+
18
+ ```bash
19
+ pip install opencomplai-core
20
+ ```
21
+
22
+ For PDF report generation, install the optional extra:
23
+
24
+ ```bash
25
+ pip install "opencomplai-core[reports]"
26
+ ```
27
+
28
+ > Most users want the [`opencomplai`](https://pypi.org/project/opencomplai/) meta-package
29
+ > (engine + CLI) or the [`opencomplai-cli`](https://pypi.org/project/opencomplai-cli/)
30
+ > command-line tool. Install `opencomplai-core` directly when you are embedding the engine
31
+ > in your own application.
32
+
33
+ ## Quick start
34
+
35
+ ### Classify a model from a declared manifest
36
+
37
+ ```python
38
+ from opencomplai import assess, AssessmentInput, ModelMetadata
39
+
40
+ result = assess(AssessmentInput(
41
+ model=ModelMetadata(
42
+ name="loan-scorer",
43
+ version="1.0.0",
44
+ modality="tabular",
45
+ use_case="creditworthiness scoring for consumer loans",
46
+ deployment_context="production",
47
+ )
48
+ ))
49
+
50
+ print(result.risk_level) # e.g. RiskLevel.HIGH
51
+ for rule in result.rule_results:
52
+ print(rule.rule_id, "PASS" if rule.passed else "FAIL")
53
+ ```
54
+
55
+ ### Corroborate a manifest against the code
56
+
57
+ ```python
58
+ from pathlib import Path
59
+ from opencomplai_core.scan_engine import run_scan
60
+
61
+ report = run_scan(
62
+ repo_root=Path("."),
63
+ commit_ref="HEAD",
64
+ )
65
+
66
+ print(report.summary.result) # PASS / CONTROL_FAIL / ...
67
+ for finding in report.findings:
68
+ print(finding.finding_id, finding.mapped_taxonomy)
69
+ ```
70
+
71
+ The scan engine extracts features from the repository, fuses evidence across detectors,
72
+ and maps findings to EU AI Act taxonomy (Annex III high-risk areas, Article 5 prohibited
73
+ practices, profiling under Article 6).
74
+
75
+ ## What you get
76
+
77
+ - **Deterministic risk classification** — same inputs always produce the same output, so
78
+ results are auditable and CI-gateable.
79
+ - **Code corroboration** — detect when a manifest under-declares (claims minimal risk while
80
+ the code does biometric identification, profiling, etc.).
81
+ - **Merkle-linked evidence** — findings carry verifiable evidence items for audit trails.
82
+
83
+ ## Documentation
84
+
85
+ Full docs, the EU AI Act concepts guide, and the SDK reference live at
86
+ **[docs.opencomplai.com](https://docs.opencomplai.com)**.
87
+
88
+ ## License
89
+
90
+ AGPL-3.0-only. See [LICENSE](https://www.gnu.org/licenses/agpl-3.0).
@@ -0,0 +1,29 @@
1
+ [project]
2
+ name = "opencomplai-core"
3
+ version = "0.1.0"
4
+ description = "Opencomplai core risk assessment engine for EU AI Act compliance"
5
+ readme = "README.md"
6
+ license = { text = "AGPL-3.0-only" }
7
+ authors = [{ name = "Opencomplai", email = "hello@opencomplai.com" }]
8
+ requires-python = ">=3.11"
9
+ dependencies = [
10
+ "pydantic>=2.0",
11
+ "cryptography>=48.0.1",
12
+ ]
13
+
14
+ [project.urls]
15
+ Homepage = "https://opencomplai.com"
16
+ Documentation = "https://docs.opencomplai.com"
17
+
18
+ [project.optional-dependencies]
19
+ dev = [
20
+ "pytest>=7.0",
21
+ "ruff>=0.1.0",
22
+ ]
23
+ reports = [
24
+ "fpdf2>=2.7",
25
+ ]
26
+
27
+ [build-system]
28
+ requires = ["hatchling"]
29
+ build-backend = "hatchling.build"
@@ -0,0 +1,22 @@
1
+ """Opencomplai core risk assessment engine."""
2
+
3
+ from opencomplai_core.engine import assess
4
+ from opencomplai_core.models import (
5
+ AssessmentInput,
6
+ EvidenceObject,
7
+ LedgerEvent,
8
+ RiskResult,
9
+ ScanStatusArtifact,
10
+ SystemManifest,
11
+ )
12
+
13
+ __version__ = "0.1.0"
14
+ __all__ = [
15
+ "AssessmentInput",
16
+ "EvidenceObject",
17
+ "LedgerEvent",
18
+ "RiskResult",
19
+ "ScanStatusArtifact",
20
+ "SystemManifest",
21
+ "assess",
22
+ ]
@@ -0,0 +1,25 @@
1
+ """Source adapter registry for the Ground Truth Verification Graph."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from opencomplai_core.adapters.base import SourceAdapter
6
+ from opencomplai_core.adapters.http import HTTPAdapter
7
+ from opencomplai_core.adapters.offline import OfflineAdapter
8
+
9
+ __all__ = ["HTTPAdapter", "OfflineAdapter", "SourceAdapter", "get_adapter"]
10
+
11
+
12
+ def get_adapter(source_ref: str, egress_proxy_url: str = "") -> SourceAdapter:
13
+ """
14
+ Return the appropriate SourceAdapter for source_ref.
15
+
16
+ Routing:
17
+ offline://* → OfflineAdapter (deterministic stub; safe in airgap/tests)
18
+ http://* | https://* → HTTPAdapter (routes through egress proxy)
19
+ (anything else) → OfflineAdapter as safe fallback
20
+ """
21
+ if source_ref.startswith("offline://") or not source_ref.startswith(
22
+ ("http://", "https://")
23
+ ):
24
+ return OfflineAdapter()
25
+ return HTTPAdapter(egress_proxy_url=egress_proxy_url)
@@ -0,0 +1,33 @@
1
+ """Abstract base class for ground-truth source adapters."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from abc import ABC, abstractmethod
6
+
7
+
8
+ class SourceAdapter(ABC):
9
+ """
10
+ Adapter that fetches a ground-truth value for a given claim.
11
+
12
+ Implementations must be safe to call concurrently and must not
13
+ store mutable state between calls.
14
+ """
15
+
16
+ @abstractmethod
17
+ async def lookup(self, claim: dict) -> dict:
18
+ """
19
+ Look up the ground-truth value for claim.
20
+
21
+ Args:
22
+ claim: dict with at least claim_ref, source_ref, and optionally
23
+ expected_value, metric, threshold.
24
+
25
+ Returns:
26
+ dict with at least a "value" key containing the looked-up value.
27
+ May include additional metadata (e.g. source, timestamp).
28
+
29
+ Raises:
30
+ RuntimeError: if the external source is unavailable (caller should
31
+ treat this as DEPENDENCY_UNAVAILABLE).
32
+ """
33
+ ...
@@ -0,0 +1,57 @@
1
+ """
2
+ HTTP adapter — routes external source lookups through the egress proxy.
3
+
4
+ All outbound HTTP calls must go through the egress proxy (REQ-ARC-001).
5
+ Raises RuntimeError on connectivity failure so the caller can handle
6
+ DEPENDENCY_UNAVAILABLE and queue for retry.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import json
12
+ import urllib.error
13
+ import urllib.request
14
+
15
+ from opencomplai_core.adapters.base import SourceAdapter
16
+
17
+
18
+ class HTTPAdapter(SourceAdapter):
19
+ """
20
+ Fetches a ground-truth value from an external HTTP source via the egress proxy.
21
+
22
+ The egress proxy enforces the allowlisted schema and destinations
23
+ (PRD §4.4); this adapter just routes through it.
24
+ """
25
+
26
+ def __init__(self, egress_proxy_url: str = "http://egress-proxy:8004") -> None:
27
+ self._proxy_url = egress_proxy_url.rstrip("/")
28
+
29
+ async def lookup(self, claim: dict) -> dict:
30
+ source_ref = claim.get("source_ref", "")
31
+ if not source_ref:
32
+ raise RuntimeError("claim missing source_ref for HTTP lookup")
33
+
34
+ payload = json.dumps(
35
+ {
36
+ "destination": source_ref,
37
+ "claim_ref": claim.get("claim_ref", ""),
38
+ "expected_value": claim.get("expected_value"),
39
+ }
40
+ ).encode("utf-8")
41
+
42
+ req = urllib.request.Request(
43
+ f"{self._proxy_url}/v1/egress/lookup",
44
+ data=payload,
45
+ headers={"Content-Type": "application/json"},
46
+ method="POST",
47
+ )
48
+ try:
49
+ with urllib.request.urlopen(req, timeout=10) as resp:
50
+ return json.loads(resp.read())
51
+ except urllib.error.HTTPError as exc:
52
+ body = exc.read().decode(errors="replace")
53
+ raise RuntimeError(
54
+ f"Egress proxy returned {exc.code} for {source_ref}: {body}"
55
+ ) from exc
56
+ except Exception as exc:
57
+ raise RuntimeError(f"HTTP adapter lookup failed: {exc}") from exc
@@ -0,0 +1,27 @@
1
+ """
2
+ Offline (deterministic stub) adapter.
3
+
4
+ Used in airgap scan mode and all unit tests. Always returns the expected_value
5
+ from the claim, so every claim resolves as VERIFIED — this is intentional for
6
+ local/offline environments where external verification is unavailable.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ from opencomplai_core.adapters.base import SourceAdapter
12
+
13
+
14
+ class OfflineAdapter(SourceAdapter):
15
+ """
16
+ Returns expected_value from the claim as the lookup result.
17
+
18
+ Produces a deterministic, dependency-free response suitable for
19
+ airgap mode and CI environments that cannot reach external sources.
20
+ """
21
+
22
+ async def lookup(self, claim: dict) -> dict:
23
+ return {
24
+ "value": claim.get("expected_value"),
25
+ "source": "offline",
26
+ "deterministic": True,
27
+ }
@@ -0,0 +1,28 @@
1
+ """EU AI Act Compliance Checker — FLI-parity decision engine."""
2
+
3
+ from opencomplai_core.compliance_checker.bridge import bridge_to_manifest_fields
4
+ from opencomplai_core.compliance_checker.engine import CHECKER_VERSION, evaluate
5
+ from opencomplai_core.compliance_checker.models import (
6
+ CheckerSession,
7
+ ComplianceCheckerResult,
8
+ EntityType,
9
+ )
10
+ from opencomplai_core.compliance_checker.report import (
11
+ export_all,
12
+ render_json,
13
+ render_markdown,
14
+ render_pdf,
15
+ )
16
+
17
+ __all__ = [
18
+ "CHECKER_VERSION",
19
+ "CheckerSession",
20
+ "ComplianceCheckerResult",
21
+ "EntityType",
22
+ "bridge_to_manifest_fields",
23
+ "evaluate",
24
+ "export_all",
25
+ "render_json",
26
+ "render_markdown",
27
+ "render_pdf",
28
+ ]
@@ -0,0 +1,30 @@
1
+ """Bridge compliance checker results to system manifest fields."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from opencomplai_core.compliance_checker.models import ComplianceCheckerResult
6
+
7
+
8
+ def bridge_to_manifest_fields(result: ComplianceCheckerResult) -> dict[str, object]:
9
+ """Map checker output to SystemManifest-compatible fields."""
10
+ entity = result.effective_entity
11
+ operator_role = entity.value if entity is not None else "unknown"
12
+
13
+ if result.is_prohibited:
14
+ intended_purpose = "prohibited_practice"
15
+ elif result.is_high_risk:
16
+ intended_purpose = "high_risk_ai_system"
17
+ elif any(item.id == "transparency" for item in result.obligations):
18
+ intended_purpose = "limited_risk_transparency"
19
+ elif any(item.id == "gpai_provider" for item in result.obligations):
20
+ intended_purpose = "general_purpose_ai_model"
21
+ elif result.in_scope:
22
+ intended_purpose = "in_scope_ai_system"
23
+ else:
24
+ intended_purpose = "out_of_scope"
25
+
26
+ return {
27
+ "operator_role": operator_role,
28
+ "intended_purpose": intended_purpose,
29
+ "high_risk_presumption": result.is_high_risk,
30
+ }
@@ -0,0 +1,50 @@
1
+ """Load FLI catalog JSON from the bundled data directory."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ from functools import lru_cache
7
+ from pathlib import Path
8
+
9
+ from opencomplai_core.compliance_checker.models import ObligationItem, StatusChangeItem
10
+
11
+ _DATA_DIR = Path(__file__).resolve().parent / "data"
12
+
13
+
14
+ def _load_json(name: str) -> dict:
15
+ path = _DATA_DIR / name
16
+ with path.open(encoding="utf-8") as handle:
17
+ return json.load(handle)
18
+
19
+
20
+ @lru_cache(maxsize=1)
21
+ def load_obligations() -> dict[str, ObligationItem]:
22
+ raw = _load_json("obligations.json")
23
+ return {key: ObligationItem(id=key, **value) for key, value in raw.items()}
24
+
25
+
26
+ @lru_cache(maxsize=1)
27
+ def load_status_changes() -> dict[str, StatusChangeItem]:
28
+ raw = _load_json("status_changes.json")
29
+ return {key: StatusChangeItem(id=key, **value) for key, value in raw.items()}
30
+
31
+
32
+ @lru_cache(maxsize=1)
33
+ def load_help_content() -> dict[str, dict[str, str]]:
34
+ return _load_json("help_content.json")
35
+
36
+
37
+ def get_obligation(obligation_id: str) -> ObligationItem:
38
+ obligations = load_obligations()
39
+ if obligation_id not in obligations:
40
+ msg = f"Unknown obligation id: {obligation_id}"
41
+ raise KeyError(msg)
42
+ return obligations[obligation_id]
43
+
44
+
45
+ def get_status_change(status_id: str) -> StatusChangeItem:
46
+ status_changes = load_status_changes()
47
+ if status_id not in status_changes:
48
+ msg = f"Unknown status change id: {status_id}"
49
+ raise KeyError(msg)
50
+ return status_changes[status_id]
@@ -0,0 +1,56 @@
1
+ {
2
+ "entity_definitions": {
3
+ "title": "Operator roles under the AI Act",
4
+ "body": "Article 3(3) defines operators: a provider develops an AI system or has it developed and places it on the market or puts it into service under its own name or trademark; a deployer uses an AI system under its authority; a distributor makes an AI system available on the Union market; an importer places an AI system from a third country on the Union market; a product manufacturer places on the market an AI system together with its product under its own name or trademark; an authorised representative is a natural or legal person established in the Union who has received a written mandate from a provider."
5
+ },
6
+ "entity_roles": {
7
+ "provider": {
8
+ "title": "Provider",
9
+ "description": "You develop an AI system (or have it developed) and place it on the market or put it into service under your own name or trademark. In short: you build and ship it."
10
+ },
11
+ "deployer": {
12
+ "title": "Deployer",
13
+ "description": "You use an AI system under your own authority in a professional capacity — you are not an affected end-user. In short: you bought it and run it on people or data."
14
+ },
15
+ "distributor": {
16
+ "title": "Distributor",
17
+ "description": "You make an AI system available on the EU market in the supply chain, without being its provider or importer. In short: you are a reseller or sales channel."
18
+ },
19
+ "importer": {
20
+ "title": "Importer",
21
+ "description": "You are established in the EU and place on the market an AI system carrying the name or trademark of a provider established outside the EU. In short: you bring a non-EU system into the EU."
22
+ },
23
+ "product_manufacturer": {
24
+ "title": "Product manufacturer",
25
+ "description": "You place on the market or put into service an AI system together with your product and under your own name or trademark. In short: AI is built into a product you sell."
26
+ },
27
+ "authorised_rep": {
28
+ "title": "Authorised representative",
29
+ "description": "You are a person or entity in the EU holding a written mandate from a non-EU provider to act on its behalf for AI Act obligations."
30
+ }
31
+ },
32
+ "ai_system_definition": {
33
+ "title": "Definition of an AI system",
34
+ "body": "An AI system is a machine-based system designed to operate with varying levels of autonomy, that may exhibit adaptiveness after deployment and that, for explicit or implicit objectives, infers, from the input it receives, how to generate outputs such as predictions, content, recommendations, or decisions that can influence physical or virtual environments (Article 3(1))."
35
+ },
36
+ "high_risk_overview": {
37
+ "title": "High-risk classification",
38
+ "body": "An AI system is high-risk if it is a product covered by Union harmonisation legislation listed in Annex I with a required third-party conformity assessment, and the product includes an AI system as a safety component; or if it is listed in Annex III and none of the Article 6(3) exceptions apply."
39
+ },
40
+ "scope_overview": {
41
+ "title": "Scope of the AI Act",
42
+ "body": "The AI Act applies to providers placing AI systems on the Union market or putting them into service, deployers with a place of establishment or located in the Union, and to providers and deployers in third countries where the output is used in the Union. Certain exclusions apply under Article 2 for military, national security, research, and personal non-professional activities."
43
+ },
44
+ "modifications_overview": {
45
+ "title": "Substantial modifications",
46
+ "body": "A substantial modification of an AI system is a change that affects compliance with the AI Act and requires a new conformity assessment. A deployer, distributor, importer, or product manufacturer that substantially modifies a system becomes a provider under Article 25(1)(b)."
47
+ },
48
+ "gpai_overview": {
49
+ "title": "General-purpose AI models",
50
+ "body": "A general-purpose AI model is an AI model, including where trained with a large amount of data using self-supervision at scale, that displays significant generality and is capable of competently performing a wide range of distinct tasks. Chapter V sets obligations for GPAI model providers distinct from high-risk AI system obligations."
51
+ },
52
+ "disclaimer": {
53
+ "title": "Not legal advice",
54
+ "body": "This tool automates the Future of Life Institute compliance checker logic for educational and planning purposes. It does not constitute legal advice. Seek qualified legal counsel and follow national guidance for formal compliance decisions."
55
+ }
56
+ }