Tools: I Added EU AI Act Compliance Checks to My CI/CD Pipeline — Here's How

Tools: I Added EU AI Act Compliance Checks to My CI/CD Pipeline — Here's How

Source: Dev.to

The problem with manual compliance reviews ## What I automated ## The GitHub Actions workflow ## What a flagged PR looks like ## What this caught in practice ## The timeline pressure ## Getting started Two months ago, I merged a PR that added face detection to our image processing service. Nobody on the team realized this put us squarely in the EU AI Act's high-risk category. We found out three weeks later, during a manual review. By then, the feature had been in production for 20 days with zero compliance documentation. That's when I decided: compliance checks belong in CI/CD, not in quarterly reviews. Most teams treat AI regulation the same way they treated GDPR in 2018 — as a legal problem, not an engineering problem. Someone from legal sends a spreadsheet once a quarter, engineers fill it out from memory, and everyone hopes nothing slipped through. This doesn't work when your codebase changes daily. A single pip install face-recognition in a feature branch can shift your regulatory classification overnight. My CI pipeline now checks three things on every PR that touches Python files: 1. Framework detection — What AI/ML libraries are in the dependency tree? New imports of transformers, torch, tensorflow, face_recognition, or similar trigger a flag. 2. Risk indicator scan — Does the code contain patterns associated with high-risk categories? Keywords like candidate_score, credit_risk, biometric, recidivism in function names, variable names, or comments. 3. Article mapping — Which EU AI Act articles apply based on what was found? The scan maps findings to specific obligations (Article 6 for high-risk classification, Article 52 for transparency, Article 53 for foundation models). If anything changes between the base branch and the PR, the check fails with a clear message explaining what was detected and what the developer needs to do. Here's the workflow I use. It runs on every PR that modifies Python files: When the scan detects something, the developer sees a comment like: Clear, actionable, tied to specific lines. No legal jargon, no 50-page report. In the first month of running this: The resume parser is the one that justified the entire setup. Without the automated check, it would have shipped undocumented to production — exactly like the face detection incident. Full enforcement of high-risk system rules starts August 2026. That's about six months from now. If you're shipping AI features to EU users (or EU customers of your SaaS), the clock is running. Adding a compliance scan to CI doesn't guarantee compliance — you still need legal review for anything flagged as high-risk. But it does two things no manual process can: The MCP server I use for scanning is open-source: arkforge.fr/mcp. It runs locally, analyzes your Python files, and outputs structured JSON. If you want the CI/CD integration without maintaining it yourself, there's a hosted version that plugs into GitHub Actions and sends alerts when your compliance status changes. Either way — the worst time to discover you're building a high-risk AI system is after a regulator tells you. I build tools that help developers deal with AI regulation. If you've set up something similar, I'd like to hear what worked — drop a comment or open an issue on the repo. Templates let you quickly answer FAQs or store snippets for re-use. Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment's permalink. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse CODE_BLOCK: name: EU AI Act Compliance Check on: pull_request: paths: - '**.py' - 'requirements*.txt' - 'pyproject.toml' jobs: compliance-scan: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v5 with: python-version: '3.11' - name: Run compliance scan run: | pip install mcp-eu-ai-act python -m mcp_eu_ai_act.scan --path . --output report.json - name: Check results run: | python -c " import json report = json.load(open('report.json')) risks = report.get('risk_indicators', {}) high_risk = any(v for v in risks.values() if v) if high_risk: print('::warning::High-risk AI indicators detected') for cat, items in risks.items(): for item in items: print(f'::warning::{cat}: {item}') print('Review required before merge.') else: print('No high-risk indicators found.') " Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: name: EU AI Act Compliance Check on: pull_request: paths: - '**.py' - 'requirements*.txt' - 'pyproject.toml' jobs: compliance-scan: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v5 with: python-version: '3.11' - name: Run compliance scan run: | pip install mcp-eu-ai-act python -m mcp_eu_ai_act.scan --path . --output report.json - name: Check results run: | python -c " import json report = json.load(open('report.json')) risks = report.get('risk_indicators', {}) high_risk = any(v for v in risks.values() if v) if high_risk: print('::warning::High-risk AI indicators detected') for cat, items in risks.items(): for item in items: print(f'::warning::{cat}: {item}') print('Review required before merge.') else: print('No high-risk indicators found.') " CODE_BLOCK: name: EU AI Act Compliance Check on: pull_request: paths: - '**.py' - 'requirements*.txt' - 'pyproject.toml' jobs: compliance-scan: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v5 with: python-version: '3.11' - name: Run compliance scan run: | pip install mcp-eu-ai-act python -m mcp_eu_ai_act.scan --path . --output report.json - name: Check results run: | python -c " import json report = json.load(open('report.json')) risks = report.get('risk_indicators', {}) high_risk = any(v for v in risks.values() if v) if high_risk: print('::warning::High-risk AI indicators detected') for cat, items in risks.items(): for item in items: print(f'::warning::{cat}: {item}') print('Review required before merge.') else: print('No high-risk indicators found.') " CODE_BLOCK: EU AI Act Compliance Scan — 2 findings [HIGH-RISK] Biometric indicators detected in src/face_verify.py - face_recognition.face_encodings (line 34) - Applicable: Article 6, Annex III Category 1 [TRANSPARENCY] LLM interaction detected in src/chatbot.py - openai.ChatCompletion (line 12) - Applicable: Article 52 (disclose AI interaction to users) Action required: Document risk assessment in docs/compliance/ Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: EU AI Act Compliance Scan — 2 findings [HIGH-RISK] Biometric indicators detected in src/face_verify.py - face_recognition.face_encodings (line 34) - Applicable: Article 6, Annex III Category 1 [TRANSPARENCY] LLM interaction detected in src/chatbot.py - openai.ChatCompletion (line 12) - Applicable: Article 52 (disclose AI interaction to users) Action required: Document risk assessment in docs/compliance/ CODE_BLOCK: EU AI Act Compliance Scan — 2 findings [HIGH-RISK] Biometric indicators detected in src/face_verify.py - face_recognition.face_encodings (line 34) - Applicable: Article 6, Annex III Category 1 [TRANSPARENCY] LLM interaction detected in src/chatbot.py - openai.ChatCompletion (line 12) - Applicable: Article 52 (disclose AI interaction to users) Action required: Document risk assessment in docs/compliance/ - Trigger on dependency file changes too. A new library in requirements.txt can change your classification even without code changes. - Warning, not failure. I use ::warning instead of exit 1 because not every detection means "stop." Sometimes you need face detection. The point is to make it visible, not to block everything. - JSON output for traceability. The report.json becomes part of the PR artifacts. When a regulator asks "when did you assess this?", you point to the PR. - 2 PRs added new ML dependencies without anyone realizing the compliance implications. Both were low-risk, but now we have documentation proving we checked. - 1 PR introduced a resume-parsing feature using embeddings. The scan flagged it as Annex III Category 4 (employment). The developer hadn't considered the regulatory angle at all. We added human oversight before merging. - 0 false positives that caused real friction. A few warnings on benign uses of sklearn, but since warnings don't block, nobody complained. - It catches changes at the moment they happen, not weeks later. - It creates a timestamped audit trail that regulators can verify.