clinicsentry 0.3.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 (194) hide show
  1. clinicsentry-0.3.0/.dockerignore +25 -0
  2. clinicsentry-0.3.0/.github/ISSUE_TEMPLATE/bug_report.md +29 -0
  3. clinicsentry-0.3.0/.github/ISSUE_TEMPLATE/config.yml +5 -0
  4. clinicsentry-0.3.0/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
  5. clinicsentry-0.3.0/.github/pull_request_template.md +29 -0
  6. clinicsentry-0.3.0/.github/workflows/ci.yml +248 -0
  7. clinicsentry-0.3.0/.github/workflows/docs.yml +27 -0
  8. clinicsentry-0.3.0/.github/workflows/release.yml +109 -0
  9. clinicsentry-0.3.0/.gitignore +43 -0
  10. clinicsentry-0.3.0/.pre-commit-config.yaml +36 -0
  11. clinicsentry-0.3.0/CHANGELOG.md +136 -0
  12. clinicsentry-0.3.0/CODE_OF_CONDUCT.md +40 -0
  13. clinicsentry-0.3.0/CONTRIBUTING.md +72 -0
  14. clinicsentry-0.3.0/CONVENTIONS.md +37 -0
  15. clinicsentry-0.3.0/Dockerfile +65 -0
  16. clinicsentry-0.3.0/LICENSE +201 -0
  17. clinicsentry-0.3.0/NOTICE +7 -0
  18. clinicsentry-0.3.0/PKG-INFO +303 -0
  19. clinicsentry-0.3.0/README.md +185 -0
  20. clinicsentry-0.3.0/RESPONSIBLE_USE.md +40 -0
  21. clinicsentry-0.3.0/SECURITY.md +48 -0
  22. clinicsentry-0.3.0/STATUS.md +16 -0
  23. clinicsentry-0.3.0/THREAT_MODEL.md +43 -0
  24. clinicsentry-0.3.0/deploy/compose/docker-compose.yml +111 -0
  25. clinicsentry-0.3.0/deploy/compose/otel-collector.yaml +37 -0
  26. clinicsentry-0.3.0/deploy/compose/prometheus.yml +11 -0
  27. clinicsentry-0.3.0/deploy/grafana/dashboards/clinicsentry.json +57 -0
  28. clinicsentry-0.3.0/deploy/grafana/provisioning/dashboards/clinicsentry.yaml +12 -0
  29. clinicsentry-0.3.0/deploy/grafana/provisioning/datasources/prometheus.yaml +9 -0
  30. clinicsentry-0.3.0/deploy/helm/clinicsentry/Chart.yaml +16 -0
  31. clinicsentry-0.3.0/deploy/helm/clinicsentry/templates/_helpers.tpl +30 -0
  32. clinicsentry-0.3.0/deploy/helm/clinicsentry/templates/deployment.yaml +58 -0
  33. clinicsentry-0.3.0/deploy/helm/clinicsentry/templates/hpa.yaml +20 -0
  34. clinicsentry-0.3.0/deploy/helm/clinicsentry/templates/networkpolicy.yaml +23 -0
  35. clinicsentry-0.3.0/deploy/helm/clinicsentry/templates/service.yaml +13 -0
  36. clinicsentry-0.3.0/deploy/helm/clinicsentry/values.yaml +61 -0
  37. clinicsentry-0.3.0/deploy/terraform/aws/main.tf +257 -0
  38. clinicsentry-0.3.0/deploy/terraform/azure/main.tf +115 -0
  39. clinicsentry-0.3.0/deploy/terraform/gcp/main.tf +121 -0
  40. clinicsentry-0.3.0/docs/adapters.md +28 -0
  41. clinicsentry-0.3.0/docs/adr/0000-template.md +30 -0
  42. clinicsentry-0.3.0/docs/adr/0001-module-boundaries.md +41 -0
  43. clinicsentry-0.3.0/docs/adr/0002-adapter-abc-contract.md +35 -0
  44. clinicsentry-0.3.0/docs/adr/0003-audit-chain-semantics.md +33 -0
  45. clinicsentry-0.3.0/docs/adr/0004-propagation-graph-schema.md +33 -0
  46. clinicsentry-0.3.0/docs/adr/0005-key-management.md +36 -0
  47. clinicsentry-0.3.0/docs/adr/0006-iec62304-class-enforcement.md +43 -0
  48. clinicsentry-0.3.0/docs/adr/0007-compliance-rule-language.md +40 -0
  49. clinicsentry-0.3.0/docs/adr/0008-exception-taxonomy.md +48 -0
  50. clinicsentry-0.3.0/docs/adr/0009-async-sync-boundary.md +29 -0
  51. clinicsentry-0.3.0/docs/adr/0010-test-conventions.md +49 -0
  52. clinicsentry-0.3.0/docs/adr/0011-di-patterns.md +29 -0
  53. clinicsentry-0.3.0/docs/adr/0012-configuration-loading.md +27 -0
  54. clinicsentry-0.3.0/docs/adr/0013-observability-hooks.md +28 -0
  55. clinicsentry-0.3.0/docs/adr/0014-threat-model-scope.md +41 -0
  56. clinicsentry-0.3.0/docs/adr/0015-redaction-mode-selection.md +28 -0
  57. clinicsentry-0.3.0/docs/adr/0016-adversarial-normalization-scan-path.md +80 -0
  58. clinicsentry-0.3.0/docs/adr/README.md +31 -0
  59. clinicsentry-0.3.0/docs/api.md +71 -0
  60. clinicsentry-0.3.0/docs/changelog.md +1 -0
  61. clinicsentry-0.3.0/docs/concepts/audit-trail.md +39 -0
  62. clinicsentry-0.3.0/docs/concepts/escalation-router.md +35 -0
  63. clinicsentry-0.3.0/docs/concepts/meddevice-mode.md +31 -0
  64. clinicsentry-0.3.0/docs/concepts/phi-firewall.md +32 -0
  65. clinicsentry-0.3.0/docs/index.md +23 -0
  66. clinicsentry-0.3.0/docs/policy.md +64 -0
  67. clinicsentry-0.3.0/docs/quickstart.md +62 -0
  68. clinicsentry-0.3.0/docs/regulatory-mapping.md +48 -0
  69. clinicsentry-0.3.0/docs/responsible-use.md +1 -0
  70. clinicsentry-0.3.0/docs/threat-model.md +1 -0
  71. clinicsentry-0.3.0/docs/tutorials/a2a.md +5 -0
  72. clinicsentry-0.3.0/docs/tutorials/adk.md +5 -0
  73. clinicsentry-0.3.0/docs/tutorials/claude.md +5 -0
  74. clinicsentry-0.3.0/docs/tutorials/crewai.md +5 -0
  75. clinicsentry-0.3.0/docs/tutorials/langgraph.md +5 -0
  76. clinicsentry-0.3.0/docs/tutorials/mcp.md +5 -0
  77. clinicsentry-0.3.0/docs/tutorials/openai-agents.md +5 -0
  78. clinicsentry-0.3.0/docs/tutorials/production.md +5 -0
  79. clinicsentry-0.3.0/examples/clinical_summarizer.py +58 -0
  80. clinicsentry-0.3.0/examples/policy.yaml +34 -0
  81. clinicsentry-0.3.0/mkdocs.yml +80 -0
  82. clinicsentry-0.3.0/pyproject.toml +248 -0
  83. clinicsentry-0.3.0/src/clinicsentry/__init__.py +32 -0
  84. clinicsentry-0.3.0/src/clinicsentry/adapters/__init__.py +27 -0
  85. clinicsentry-0.3.0/src/clinicsentry/adapters/a2a.py +60 -0
  86. clinicsentry-0.3.0/src/clinicsentry/adapters/base.py +158 -0
  87. clinicsentry-0.3.0/src/clinicsentry/adapters/claude_sdk.py +71 -0
  88. clinicsentry-0.3.0/src/clinicsentry/adapters/crewai.py +89 -0
  89. clinicsentry-0.3.0/src/clinicsentry/adapters/google_adk.py +100 -0
  90. clinicsentry-0.3.0/src/clinicsentry/adapters/langgraph.py +66 -0
  91. clinicsentry-0.3.0/src/clinicsentry/adapters/mcp_proxy.py +92 -0
  92. clinicsentry-0.3.0/src/clinicsentry/adapters/openai_agents.py +92 -0
  93. clinicsentry-0.3.0/src/clinicsentry/audit/__init__.py +24 -0
  94. clinicsentry-0.3.0/src/clinicsentry/audit/backend.py +220 -0
  95. clinicsentry-0.3.0/src/clinicsentry/audit/chain.py +137 -0
  96. clinicsentry-0.3.0/src/clinicsentry/audit/migrations/__init__.py +16 -0
  97. clinicsentry-0.3.0/src/clinicsentry/audit/migrations/alembic.ini +38 -0
  98. clinicsentry-0.3.0/src/clinicsentry/audit/migrations/env.py +54 -0
  99. clinicsentry-0.3.0/src/clinicsentry/audit/migrations/runner.py +43 -0
  100. clinicsentry-0.3.0/src/clinicsentry/audit/migrations/script.py.mako +24 -0
  101. clinicsentry-0.3.0/src/clinicsentry/audit/migrations/versions/0001_initial_audit_events.py +66 -0
  102. clinicsentry-0.3.0/src/clinicsentry/audit/otel.py +74 -0
  103. clinicsentry-0.3.0/src/clinicsentry/audit/pdf_report.py +127 -0
  104. clinicsentry-0.3.0/src/clinicsentry/audit/postgres.py +188 -0
  105. clinicsentry-0.3.0/src/clinicsentry/audit/report.py +191 -0
  106. clinicsentry-0.3.0/src/clinicsentry/audit/s3.py +169 -0
  107. clinicsentry-0.3.0/src/clinicsentry/cli.py +303 -0
  108. clinicsentry-0.3.0/src/clinicsentry/compliance/__init__.py +34 -0
  109. clinicsentry-0.3.0/src/clinicsentry/compliance/engine.py +442 -0
  110. clinicsentry-0.3.0/src/clinicsentry/compliance/rules/eu_ai_act.yaml +21 -0
  111. clinicsentry-0.3.0/src/clinicsentry/compliance/rules/fda_tplc.yaml +21 -0
  112. clinicsentry-0.3.0/src/clinicsentry/compliance/rules/hipaa.yaml +33 -0
  113. clinicsentry-0.3.0/src/clinicsentry/compliance/rules/iec62304.yaml +21 -0
  114. clinicsentry-0.3.0/src/clinicsentry/dashboard/__init__.py +21 -0
  115. clinicsentry-0.3.0/src/clinicsentry/dashboard/app.py +242 -0
  116. clinicsentry-0.3.0/src/clinicsentry/errors.py +176 -0
  117. clinicsentry-0.3.0/src/clinicsentry/escalation/__init__.py +36 -0
  118. clinicsentry-0.3.0/src/clinicsentry/escalation/channels.py +228 -0
  119. clinicsentry-0.3.0/src/clinicsentry/escalation/confidence.py +178 -0
  120. clinicsentry-0.3.0/src/clinicsentry/escalation/extra_signals.py +216 -0
  121. clinicsentry-0.3.0/src/clinicsentry/escalation/router.py +222 -0
  122. clinicsentry-0.3.0/src/clinicsentry/escalation/temperature_scaling.py +209 -0
  123. clinicsentry-0.3.0/src/clinicsentry/guard.py +279 -0
  124. clinicsentry-0.3.0/src/clinicsentry/meddevice/__init__.py +51 -0
  125. clinicsentry-0.3.0/src/clinicsentry/meddevice/cia.py +125 -0
  126. clinicsentry-0.3.0/src/clinicsentry/meddevice/clinician_auth.py +115 -0
  127. clinicsentry-0.3.0/src/clinicsentry/meddevice/cloud_kms.py +216 -0
  128. clinicsentry-0.3.0/src/clinicsentry/meddevice/http_kms.py +144 -0
  129. clinicsentry-0.3.0/src/clinicsentry/meddevice/iec62304_v2.py +64 -0
  130. clinicsentry-0.3.0/src/clinicsentry/meddevice/keys.py +152 -0
  131. clinicsentry-0.3.0/src/clinicsentry/meddevice/mode.py +208 -0
  132. clinicsentry-0.3.0/src/clinicsentry/observability/__init__.py +16 -0
  133. clinicsentry-0.3.0/src/clinicsentry/observability/logging.py +68 -0
  134. clinicsentry-0.3.0/src/clinicsentry/observability/metrics.py +82 -0
  135. clinicsentry-0.3.0/src/clinicsentry/observability/tracing.py +30 -0
  136. clinicsentry-0.3.0/src/clinicsentry/performance.py +130 -0
  137. clinicsentry-0.3.0/src/clinicsentry/phi/__init__.py +34 -0
  138. clinicsentry-0.3.0/src/clinicsentry/phi/adversarial.py +220 -0
  139. clinicsentry-0.3.0/src/clinicsentry/phi/detectors.py +198 -0
  140. clinicsentry-0.3.0/src/clinicsentry/phi/firewall.py +296 -0
  141. clinicsentry-0.3.0/src/clinicsentry/phi/medical_ner.py +110 -0
  142. clinicsentry-0.3.0/src/clinicsentry/phi/minimum_necessary.py +100 -0
  143. clinicsentry-0.3.0/src/clinicsentry/phi/multilingual.py +100 -0
  144. clinicsentry-0.3.0/src/clinicsentry/phi/ocr.py +58 -0
  145. clinicsentry-0.3.0/src/clinicsentry/phi/parsers.py +149 -0
  146. clinicsentry-0.3.0/src/clinicsentry/phi/pipeline.py +93 -0
  147. clinicsentry-0.3.0/src/clinicsentry/phi/propagation.py +51 -0
  148. clinicsentry-0.3.0/src/clinicsentry/phi/redaction.py +105 -0
  149. clinicsentry-0.3.0/src/clinicsentry/policy.py +366 -0
  150. clinicsentry-0.3.0/src/clinicsentry/py.typed +0 -0
  151. clinicsentry-0.3.0/src/clinicsentry/types.py +203 -0
  152. clinicsentry-0.3.0/tests/__init__.py +0 -0
  153. clinicsentry-0.3.0/tests/_docker_guard.py +43 -0
  154. clinicsentry-0.3.0/tests/adapters/__init__.py +8 -0
  155. clinicsentry-0.3.0/tests/adapters/test_claude_sdk_integration.py +26 -0
  156. clinicsentry-0.3.0/tests/adapters/test_crewai_integration.py +26 -0
  157. clinicsentry-0.3.0/tests/adapters/test_google_adk_integration.py +26 -0
  158. clinicsentry-0.3.0/tests/adapters/test_langgraph_integration.py +48 -0
  159. clinicsentry-0.3.0/tests/adapters/test_mcp_proxy_integration.py +26 -0
  160. clinicsentry-0.3.0/tests/adapters/test_openai_agents_integration.py +26 -0
  161. clinicsentry-0.3.0/tests/fixtures/synthetic_phi/__init__.py +4 -0
  162. clinicsentry-0.3.0/tests/fixtures/synthetic_phi/corpus.json +2352 -0
  163. clinicsentry-0.3.0/tests/fixtures/synthetic_phi/generator.py +235 -0
  164. clinicsentry-0.3.0/tests/test_adapters.py +234 -0
  165. clinicsentry-0.3.0/tests/test_adversarial_robustness.py +300 -0
  166. clinicsentry-0.3.0/tests/test_alembic_migrations.py +107 -0
  167. clinicsentry-0.3.0/tests/test_audit.py +171 -0
  168. clinicsentry-0.3.0/tests/test_audit_backends.py +162 -0
  169. clinicsentry-0.3.0/tests/test_audit_chain_mutation.py +161 -0
  170. clinicsentry-0.3.0/tests/test_cli_summary.py +77 -0
  171. clinicsentry-0.3.0/tests/test_cloud_kms_aws.py +111 -0
  172. clinicsentry-0.3.0/tests/test_cloud_kms_mocked.py +199 -0
  173. clinicsentry-0.3.0/tests/test_compliance.py +281 -0
  174. clinicsentry-0.3.0/tests/test_confidence_mutation.py +317 -0
  175. clinicsentry-0.3.0/tests/test_escalation.py +120 -0
  176. clinicsentry-0.3.0/tests/test_escalation_extra.py +135 -0
  177. clinicsentry-0.3.0/tests/test_guard_integration.py +122 -0
  178. clinicsentry-0.3.0/tests/test_http_kms.py +140 -0
  179. clinicsentry-0.3.0/tests/test_layering.py +93 -0
  180. clinicsentry-0.3.0/tests/test_meddevice.py +94 -0
  181. clinicsentry-0.3.0/tests/test_meddevice_extra.py +102 -0
  182. clinicsentry-0.3.0/tests/test_meddevice_mutation.py +369 -0
  183. clinicsentry-0.3.0/tests/test_pdf_report.py +51 -0
  184. clinicsentry-0.3.0/tests/test_performance.py +63 -0
  185. clinicsentry-0.3.0/tests/test_phi_firewall.py +155 -0
  186. clinicsentry-0.3.0/tests/test_phi_heavy_deps.py +164 -0
  187. clinicsentry-0.3.0/tests/test_phi_pipeline.py +63 -0
  188. clinicsentry-0.3.0/tests/test_policy_validation.py +183 -0
  189. clinicsentry-0.3.0/tests/test_postgres_integration.py +194 -0
  190. clinicsentry-0.3.0/tests/test_propagation.py +95 -0
  191. clinicsentry-0.3.0/tests/test_softhsm_integration.py +272 -0
  192. clinicsentry-0.3.0/tests/test_synthetic_phi.py +139 -0
  193. clinicsentry-0.3.0/tests/test_temperature_scaling.py +124 -0
  194. clinicsentry-0.3.0/tests/test_untrusted_input.py +114 -0
@@ -0,0 +1,25 @@
1
+ .git
2
+ .github
3
+ .venv
4
+ __pycache__
5
+ *.pyc
6
+ *.pyo
7
+ *.pyd
8
+ .pytest_cache
9
+ .mypy_cache
10
+ .ruff_cache
11
+ htmlcov
12
+ coverage.xml
13
+ .coverage
14
+ .coverage.*
15
+ .DS_Store
16
+ _tmp
17
+ node_modules
18
+ *.log
19
+ *.sqlite
20
+ *.db
21
+ .idea
22
+ .vscode
23
+ deploy/grafana/dashboards-generated
24
+ docs/_build
25
+ site
@@ -0,0 +1,29 @@
1
+ ---
2
+ name: Bug report
3
+ about: Something behaves incorrectly (for PHI-detection bypasses, see SECURITY.md instead)
4
+ labels: bug
5
+ ---
6
+
7
+ **⚠️ If this is a PHI-detection bypass or any security issue, do NOT file it
8
+ here — follow [SECURITY.md](../../SECURITY.md) for private reporting.**
9
+
10
+ ## What happened
11
+
12
+ A clear description of the bug.
13
+
14
+ ## Minimal reproduction
15
+
16
+ ```python
17
+ # Smallest snippet that reproduces the issue.
18
+ # NEVER paste real PHI — use synthetic identifiers (e.g. SSN 123-45-6789).
19
+ ```
20
+
21
+ ## Expected behavior
22
+
23
+ ## Environment
24
+
25
+ - clinicsentry version:
26
+ - Python version:
27
+ - OS:
28
+ - Installed extras (e.g. `[phi]`, `[postgres]`):
29
+ - Agent framework + version (if adapter-related):
@@ -0,0 +1,5 @@
1
+ blank_issues_enabled: true
2
+ contact_links:
3
+ - name: Security vulnerability (private)
4
+ url: https://github.com/aakash1411/clinicsentry/security/advisories/new
5
+ about: PHI-detection bypasses and other vulnerabilities — never file these as public issues.
@@ -0,0 +1,20 @@
1
+ ---
2
+ name: Feature request
3
+ about: Propose a new capability or improvement
4
+ labels: enhancement
5
+ ---
6
+
7
+ ## Problem
8
+
9
+ What clinical-AI compliance problem does this solve? Reference the relevant
10
+ regulation clause (HIPAA / FDA TPLC / IEC 62304 / EU AI Act) if applicable.
11
+
12
+ ## Proposed solution
13
+
14
+ ## Alternatives considered
15
+
16
+ ## Constraints
17
+
18
+ ClinicSentry is latency-budgeted middleware (≤50 ms p95 total overhead, no
19
+ additional LLM calls on the hot path). Note any expected latency or
20
+ dependency impact.
@@ -0,0 +1,29 @@
1
+ ## Summary
2
+
3
+ What and why (one paragraph).
4
+
5
+ ## ADR reference
6
+
7
+ ADR-NNNN (link to `docs/adr/`).
8
+
9
+ ## Changes
10
+
11
+ - Bullet list of concrete changes.
12
+
13
+ ## Testing
14
+
15
+ - `pytest -q tests/test_<module>.py`
16
+ - Manual verification steps (if applicable).
17
+
18
+ ## Risk / Compliance
19
+
20
+ Any HIPAA / FDA / IEC 62304 implications? Reference the rule.
21
+
22
+ ## Checklist
23
+
24
+ - [ ] Tests added / updated.
25
+ - [ ] Coverage ≥ 85%.
26
+ - [ ] `ruff check`, `ruff format --check`, `mypy --strict` clean.
27
+ - [ ] `CHANGELOG.md` updated under `## [Unreleased]`.
28
+ - [ ] `CHANGELOG.md` updated if this advances a feature.
29
+ - [ ] Any breaking change documented in PR title with `[breaking]`.
@@ -0,0 +1,248 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ workflow_dispatch:
8
+
9
+ concurrency:
10
+ group: ci-${{ github.ref }}
11
+ cancel-in-progress: true
12
+
13
+ jobs:
14
+ lint:
15
+ runs-on: ubuntu-latest
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+ - uses: actions/setup-python@v5
19
+ with:
20
+ python-version: "3.11"
21
+ cache: "pip"
22
+ - run: pip install -e '.[dev]'
23
+ - run: ruff format --check .
24
+ - run: ruff check .
25
+
26
+ typecheck:
27
+ runs-on: ubuntu-latest
28
+ steps:
29
+ - uses: actions/checkout@v4
30
+ - uses: actions/setup-python@v5
31
+ with:
32
+ python-version: "3.11"
33
+ cache: "pip"
34
+ - run: pip install -e '.[dev]'
35
+ - run: mypy
36
+
37
+ test:
38
+ runs-on: ubuntu-latest
39
+ strategy:
40
+ matrix:
41
+ python-version: ["3.11", "3.12", "3.13"]
42
+ steps:
43
+ - uses: actions/checkout@v4
44
+ - uses: actions/setup-python@v5
45
+ with:
46
+ python-version: ${{ matrix.python-version }}
47
+ cache: "pip"
48
+ - run: pip install -e '.[dev,all]'
49
+ - run: pytest --cov=clinicsentry --cov-report=xml --cov-report=term -q
50
+ - name: Upload coverage
51
+ if: matrix.python-version == '3.11'
52
+ uses: actions/upload-artifact@v4
53
+ with:
54
+ name: coverage
55
+ path: coverage.xml
56
+
57
+ import-safety:
58
+ runs-on: ubuntu-latest
59
+ steps:
60
+ - uses: actions/checkout@v4
61
+ - uses: actions/setup-python@v5
62
+ with:
63
+ python-version: "3.11"
64
+ - run: pip install -e .
65
+ - name: Import every public module in a subprocess
66
+ run: |
67
+ python - <<'PY'
68
+ import importlib
69
+ import pkgutil
70
+ import sys
71
+ import clinicsentry
72
+
73
+ failed = []
74
+ for mod in pkgutil.walk_packages(clinicsentry.__path__, prefix="clinicsentry."):
75
+ if "dashboard" in mod.name or "cli" in mod.name:
76
+ continue
77
+ try:
78
+ importlib.import_module(mod.name)
79
+ except Exception as e:
80
+ failed.append((mod.name, repr(e)))
81
+
82
+ for name, err in failed:
83
+ print(f"FAIL: {name}: {err}", file=sys.stderr)
84
+ sys.exit(1 if failed else 0)
85
+ PY
86
+
87
+ license-scan:
88
+ runs-on: ubuntu-latest
89
+ steps:
90
+ - uses: actions/checkout@v4
91
+ - uses: actions/setup-python@v5
92
+ with:
93
+ python-version: "3.11"
94
+ - run: pip install -e '.[dev]' pip-licenses
95
+ - run: |
96
+ pip-licenses --format=markdown --order=license \
97
+ --allow-only="Apache Software License;Apache License 2.0;Apache-2.0;Apache-2.0 OR BSD-2-Clause;Apache-2.0 OR BSD-3-Clause;MIT License;MIT;BSD License;BSD 3-Clause;BSD 2-Clause;BSD-3-Clause;BSD-2-Clause;ISC;ISC License (ISCL);Mozilla Public License 2.0 (MPL 2.0);MPL-2.0;Python Software Foundation License;PSF-2.0;Freely Distributable;The Unlicense (Unlicense);Public Domain"
98
+
99
+ security-scan:
100
+ runs-on: ubuntu-latest
101
+ steps:
102
+ - uses: actions/checkout@v4
103
+ - uses: actions/setup-python@v5
104
+ with:
105
+ python-version: "3.11"
106
+ - run: pip install -e '.[dev]'
107
+ - run: pip-audit --strict || true # advisory until baseline established
108
+ - run: bandit -r src/clinicsentry -ll -ii
109
+
110
+ api-stability:
111
+ runs-on: ubuntu-latest
112
+ steps:
113
+ - uses: actions/checkout@v4
114
+ - uses: actions/setup-python@v5
115
+ with:
116
+ python-version: "3.11"
117
+ - run: pip install -e .
118
+ - name: Check public __all__ surface is non-empty
119
+ run: |
120
+ python - <<'PY'
121
+ import clinicsentry
122
+ assert clinicsentry.__all__, "clinicsentry.__all__ must not be empty"
123
+ assert "ClinicSentry" in clinicsentry.__all__
124
+ print("public surface:", sorted(clinicsentry.__all__))
125
+ PY
126
+
127
+ package-data:
128
+ # Verifies the compliance YAML rule files are included in both wheel and
129
+ # sdist artifacts. Without this, `load_default_rulesets()` silently returns
130
+ # zero rules at runtime, producing empty regulatory reports.
131
+ runs-on: ubuntu-latest
132
+ steps:
133
+ - uses: actions/checkout@v4
134
+ - uses: actions/setup-python@v5
135
+ with:
136
+ python-version: "3.11"
137
+ cache: "pip"
138
+ - run: pip install build
139
+ - run: python -m build
140
+ - name: Verify rules YAML in wheel
141
+ run: |
142
+ python -m zipfile -l dist/*.whl | grep "compliance/rules/.*\.yaml" | tee /tmp/wheel-yaml.txt
143
+ test $(wc -l < /tmp/wheel-yaml.txt) -ge 4
144
+ - name: Verify rules YAML in sdist
145
+ run: |
146
+ tar -tzf dist/*.tar.gz | grep "compliance/rules/.*\.yaml" | tee /tmp/sdist-yaml.txt
147
+ test $(wc -l < /tmp/sdist-yaml.txt) -ge 4
148
+ - name: Verify default rulesets load from installed wheel
149
+ run: |
150
+ python -m venv /tmp/wheelvenv
151
+ /tmp/wheelvenv/bin/pip install dist/*.whl
152
+ /tmp/wheelvenv/bin/python -c "
153
+ from clinicsentry.compliance import load_default_rulesets
154
+ sets = load_default_rulesets()
155
+ assert len(sets) == 4, sets
156
+ assert sum(len(s.rules) for s in sets) >= 14
157
+ print('OK:', len(sets), 'rulesets')
158
+ "
159
+
160
+ postgres-integration:
161
+ # Postgres audit backend integration tests via testcontainers. The
162
+ # ubuntu-latest runner ships a running Docker daemon, so testcontainers
163
+ # talks to it over the default socket — no docker-in-docker service needed.
164
+ runs-on: ubuntu-latest
165
+ steps:
166
+ - uses: actions/checkout@v4
167
+ - uses: actions/setup-python@v5
168
+ with:
169
+ python-version: "3.11"
170
+ cache: "pip"
171
+ - run: pip install -e '.[dev,postgres]' 'testcontainers[postgres]>=4.0' 'psycopg[binary]>=3.1'
172
+ - run: pytest tests/test_postgres_integration.py -q
173
+
174
+ adapter-sdks:
175
+ # Real-SDK compatibility tests for each adapter. Each adapter test file
176
+ # auto-skips when its SDK is not installed, so a fan-out matrix lets each
177
+ # SDK be installed in its own clean job and tested independently.
178
+ runs-on: ubuntu-latest
179
+ strategy:
180
+ fail-fast: false
181
+ matrix:
182
+ include:
183
+ - extra: "langgraph"
184
+ test: "tests/adapters/test_langgraph_integration.py"
185
+ - extra: "crewai"
186
+ test: "tests/adapters/test_crewai_integration.py"
187
+ - extra: "adk"
188
+ test: "tests/adapters/test_google_adk_integration.py"
189
+ - extra: "openai-agents"
190
+ test: "tests/adapters/test_openai_agents_integration.py"
191
+ - extra: "claude"
192
+ test: "tests/adapters/test_claude_sdk_integration.py"
193
+ - extra: "mcp"
194
+ test: "tests/adapters/test_mcp_proxy_integration.py"
195
+ steps:
196
+ - uses: actions/checkout@v4
197
+ - uses: actions/setup-python@v5
198
+ with:
199
+ python-version: "3.11"
200
+ cache: "pip"
201
+ - run: pip install -e ".[dev,${{ matrix.extra }}]"
202
+ - run: pytest ${{ matrix.test }} -q
203
+
204
+ heavy-deps:
205
+ # Heavy PHI detection happy-path runs. Manual / on-demand only because
206
+ # spaCy model wheels and Tesseract binary inflate runtime significantly
207
+ # and we don't want them on every PR.
208
+ if: ${{ contains(github.event.head_commit.message, '[heavy-deps]') || github.event_name == 'workflow_dispatch' }}
209
+ runs-on: ubuntu-latest
210
+ steps:
211
+ - uses: actions/checkout@v4
212
+ - uses: actions/setup-python@v5
213
+ with:
214
+ python-version: "3.11"
215
+ cache: "pip"
216
+ - name: Install Tesseract
217
+ run: sudo apt-get update && sudo apt-get install -y tesseract-ocr
218
+ - run: pip install -e '.[dev,phi,nlp-medical,ocr]'
219
+ - name: Install spaCy clinical model
220
+ run: |
221
+ pip install https://s3-us-west-2.amazonaws.com/ai2-s2-scispacy/releases/v0.5.4/en_core_sci_sm-0.5.4.tar.gz || echo "scispacy model unavailable"
222
+ - run: pytest tests/test_phi_heavy_deps.py -q
223
+
224
+ mutation:
225
+ # Mutation testing against the four novelty modules. Manually triggered
226
+ # only — full runs cost ~10 minutes and aren't useful on every PR.
227
+ if: ${{ contains(github.event.head_commit.message, '[mutation]') || github.event_name == 'workflow_dispatch' }}
228
+ runs-on: ubuntu-latest
229
+ steps:
230
+ - uses: actions/checkout@v4
231
+ - uses: actions/setup-python@v5
232
+ with:
233
+ python-version: "3.11"
234
+ cache: "pip"
235
+ - run: pip install -e '.[dev]'
236
+ - name: Run mutmut on each novelty module
237
+ run: |
238
+ set -e
239
+ for module in \
240
+ src/clinicsentry/phi/propagation.py \
241
+ src/clinicsentry/audit/chain.py \
242
+ src/clinicsentry/escalation/confidence.py \
243
+ src/clinicsentry/meddevice/mode.py; do
244
+ echo "=== mutmut: $module ==="
245
+ rm -rf .mutmut-cache
246
+ mutmut run --paths-to-mutate="$module" --simple-output || true
247
+ mutmut results
248
+ done
@@ -0,0 +1,27 @@
1
+ name: Docs
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ jobs:
9
+ docstring-check:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: actions/checkout@v4
13
+ - uses: actions/setup-python@v5
14
+ with:
15
+ python-version: "3.11"
16
+ - run: pip install -e '.[dev]'
17
+ - run: ruff check --select D --extend-ignore D203,D213,D104,D105,D107 src/clinicsentry
18
+
19
+ build-mkdocs:
20
+ runs-on: ubuntu-latest
21
+ steps:
22
+ - uses: actions/checkout@v4
23
+ - uses: actions/setup-python@v5
24
+ with:
25
+ python-version: "3.11"
26
+ - run: pip install -e '.[docs]'
27
+ - run: mkdocs build --strict
@@ -0,0 +1,109 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*.*.*"
7
+
8
+ permissions:
9
+ contents: write
10
+ id-token: write # cosign keyless signing + PyPI trusted publishing
11
+ packages: write
12
+
13
+ jobs:
14
+ build-and-sign:
15
+ runs-on: ubuntu-latest
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+
19
+ - uses: actions/setup-python@v5
20
+ with:
21
+ python-version: "3.11"
22
+ cache: "pip"
23
+
24
+ - name: Install build tooling
25
+ run: pip install --upgrade build twine
26
+
27
+ - name: Verify tag matches package version
28
+ run: |
29
+ PKG_VERSION=$(python -c "import tomllib; print(tomllib.load(open('pyproject.toml','rb'))['project']['version'])")
30
+ TAG_VERSION="${GITHUB_REF_NAME#v}"
31
+ if [ "$PKG_VERSION" != "$TAG_VERSION" ]; then
32
+ echo "Tag $GITHUB_REF_NAME does not match pyproject version $PKG_VERSION" >&2
33
+ exit 1
34
+ fi
35
+
36
+ - name: Build wheel + sdist
37
+ run: python -m build
38
+
39
+ - name: Validate distribution metadata
40
+ run: twine check --strict dist/*
41
+
42
+ - name: Smoke-test wheel in a clean venv
43
+ run: |
44
+ python -m venv /tmp/smoke
45
+ /tmp/smoke/bin/pip install dist/*.whl
46
+ /tmp/smoke/bin/python -c "import clinicsentry; print(clinicsentry.__version__)"
47
+ /tmp/smoke/bin/clinicsentry scan "SSN 123-45-6789" | grep -q "REDACTED"
48
+
49
+ - name: Install Syft (SBOM)
50
+ uses: anchore/sbom-action/download-syft@v0.17.7
51
+
52
+ - name: Generate CycloneDX SBOM
53
+ run: |
54
+ syft dir:. -o cyclonedx-json=sbom.cyclonedx.json
55
+ syft dir:. -o spdx-json=sbom.spdx.json
56
+
57
+ - name: Install Cosign
58
+ uses: sigstore/cosign-installer@v3.7.0
59
+
60
+ - name: Sign SBOM (keyless)
61
+ env:
62
+ COSIGN_EXPERIMENTAL: "1"
63
+ run: cosign sign-blob --yes --output-signature sbom.cyclonedx.json.sig sbom.cyclonedx.json
64
+
65
+ - name: Build container image
66
+ run: docker build -t clinicsentry:${{ github.ref_name }} .
67
+
68
+ - name: Sign container image (keyless)
69
+ env:
70
+ COSIGN_EXPERIMENTAL: "1"
71
+ run: |
72
+ docker save clinicsentry:${{ github.ref_name }} -o image.tar
73
+ cosign sign-blob --yes --output-signature image.tar.sig image.tar
74
+
75
+ - name: Upload release artifacts
76
+ uses: softprops/action-gh-release@v2
77
+ with:
78
+ files: |
79
+ dist/*
80
+ sbom.cyclonedx.json
81
+ sbom.spdx.json
82
+ sbom.cyclonedx.json.sig
83
+ image.tar.sig
84
+
85
+ - name: Store dists for publish job
86
+ uses: actions/upload-artifact@v4
87
+ with:
88
+ name: python-dists
89
+ path: dist/
90
+
91
+ publish-pypi:
92
+ # Requires a PyPI "trusted publisher" configured for this repo + workflow.
93
+ # The `pypi` environment gates the publish behind any protection rules you
94
+ # configure (e.g. required reviewers).
95
+ needs: build-and-sign
96
+ runs-on: ubuntu-latest
97
+ environment:
98
+ name: pypi
99
+ permissions:
100
+ id-token: write
101
+ steps:
102
+ - name: Download dists
103
+ uses: actions/download-artifact@v4
104
+ with:
105
+ name: python-dists
106
+ path: dist/
107
+
108
+ - name: Publish to PyPI (trusted publishing)
109
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,43 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # Distribution / packaging
7
+ build/
8
+ dist/
9
+ *.egg-info/
10
+ *.egg
11
+
12
+ # Virtual environments
13
+ .venv/
14
+ venv/
15
+ env/
16
+
17
+ # IDE
18
+ .idea/
19
+ .vscode/
20
+ *.swp
21
+ *.swo
22
+
23
+ # OS
24
+ .DS_Store
25
+ Thumbs.db
26
+
27
+ # Testing / coverage
28
+ .pytest_cache/
29
+ .coverage
30
+ htmlcov/
31
+ .mypy_cache/
32
+ .ruff_cache/
33
+
34
+ # Temp / scratch
35
+ _tmp/
36
+
37
+ # Audit files created by demos
38
+ *.sqlite
39
+ *.sqlite3
40
+ clinicsentry_audit.log
41
+
42
+ # Local agent settings
43
+ .claude/
@@ -0,0 +1,36 @@
1
+ repos:
2
+ - repo: https://github.com/pre-commit/pre-commit-hooks
3
+ rev: v4.6.0
4
+ hooks:
5
+ - id: trailing-whitespace
6
+ - id: end-of-file-fixer
7
+ - id: check-yaml
8
+ exclude: ^deploy/helm/.*/templates/
9
+ - id: check-toml
10
+ - id: check-merge-conflict
11
+ - id: detect-private-key
12
+ - id: mixed-line-ending
13
+
14
+ - repo: https://github.com/astral-sh/ruff-pre-commit
15
+ rev: v0.4.10
16
+ hooks:
17
+ - id: ruff
18
+ args: [--fix, --exit-non-zero-on-fix]
19
+ - id: ruff-format
20
+
21
+ - repo: https://github.com/pre-commit/mirrors-mypy
22
+ rev: v1.10.0
23
+ hooks:
24
+ - id: mypy
25
+ additional_dependencies:
26
+ - pydantic>=2.0
27
+ - types-PyYAML
28
+ args: [--config-file=pyproject.toml]
29
+ files: ^src/clinicsentry/
30
+
31
+ - repo: https://github.com/PyCQA/bandit
32
+ rev: 1.7.9
33
+ hooks:
34
+ - id: bandit
35
+ args: [-ll, -ii, -r]
36
+ files: ^src/clinicsentry/