AI Risk Management & Data Governance — Ecotrans / p24-infra

Document type: Internal formal record — EU AI Act Art. 9 (risk management) & Art. 10 (data governance) good practice
Scope: All AI systems deployed by the p24-infra project
Last reviewed: 2026-06-28
Next review due: 2027-06-16
Owner: Radek Konarski (p24-infra admin)
Risk classification: No system is high-risk. Current systems are minimal or limited risk under the EU AI Act — see eu-ai-act-compliance.md. Parts A/B cover the two audit-engine systems; Part C covers the remaining registered n8n / GitHub Actions / Telegram systems.

Note on applicability: Art. 9 and Art. 10 are mandatory only for high-risk AI systems (Annex III). This document is maintained as good practice for minimal-risk systems and as a readiness baseline in case any system is reclassified. It also fulfils the has_risk_management and has_data_governance compliance fields in dev_r_ai_systems.


Part A — Risk Management

A.1 Systems covered

SystemServiceRisk tierModel
workbook-designeraudit-engineminimalclaude-sonnet-4-6
report-generatoraudit-engineminimalclaude-sonnet-4-6

A.2 Risk identification & assessment

R-01 — Incorrect workbook design leading to misleading reports

AttributeDetail
DescriptionClaude designs a WorkbookSpec with wrong connector params, wrong data sources, or misframed analysis goals. The resulting report misrepresents infrastructure health.
Trigger conditionsAmbiguous action description; poor prompt context; model regression
LikelihoodLow — action descriptions are templated and reviewed at design time; 3 retries with JSON-schema validation
ImpactLow — reports are informational; no automated action is taken; Prometheus and Grafana serve as independent ground truth
Mitigation(1) WorkbookSpec JSON-schema validation before activation (2) Human operator reviews weekly/daily reports (3) /reoptimize endpoint to manually trigger redesign (4) Prometheus alerts fire independently of report output
Residual riskNegligible

R-02 — AI hallucination in generated report

AttributeDetail
DescriptionClaude invents metric values, fabricates alert states, or draws incorrect conclusions from real connector data.
Trigger conditionsModel hallucination; prompt injection in connector data
LikelihoodLow-medium — connector data is structured (JSON/PromQL output); hallucination risk exists on synthesis step
ImpactLow-medium — operator might miss a genuine issue or act on a phantom one
Mitigation(1) Reports labelled “AI-generated — verify against Grafana before acting” (2) All source data retained in audit.runs output for cross-check (3) Critical alerts come from Alertmanager, not from AI reports
Residual riskLow

R-03 — Sensitive infrastructure data exposure via AI calls

AttributeDetail
DescriptionInfrastructure metrics, service names, or credentials sent to the AI model are intercepted or retained by the AI provider.
Trigger conditionsNetwork interception; AI provider data retention; accidental secret injection
LikelihoodLow — calls route through claude-proxy on vps-h1 over private network; TLS on all external hops
ImpactMedium — infrastructure topology details could aid a targeted attack
Mitigation(1) claude-proxy on private vps-h1, authenticated with CLAUDE_PROXY_SECRET (2) Claude Max subscription — Anthropic does not train on Claude Max data by default (3) Secret scrubbing: connector params must never include raw credentials (validated in WorkbookSpec schema) (4) Anthropic’s EU data processing and privacy policies apply
Residual riskLow

R-04 — Token budget overrun causing service cost spike

AttributeDetail
DescriptionA runaway ai_workbook action consumes excessive tokens, exceeding monthly budget.
Trigger conditionsVery large connector data payload; retry loop bug
LikelihoodLow — guardrails.py enforces per-action cap (2k–12k tokens) and monthly rolling cap (100k tokens for p24-infra)
ImpactLow — financial (Claude Max flat-rate subscription, no marginal cost); service disruption if monthly cap hit before month end
Mitigationguardrails.py blocks execution when cap exceeded; audit.increment_monthly_tokens() RPC tracks usage atomically
Residual riskNegligible

R-05 — AI system unavailability (claude-proxy or Anthropic API down)

AttributeDetail
DescriptionReports are not generated during an outage.
Trigger conditionsclaude-proxy crash; Anthropic service outage; network partition
LikelihoodLow-medium — Anthropic has high availability; claude-proxy is a single-process systemd service
ImpactLow — missed report; Prometheus/Grafana continue operating independently
Mitigation(1) ai.py falls back from claude-proxy to direct ANTHROPIC_API_KEY if proxy returns 5xx (2) audit.runs records status='error'; retry happens on next scheduled run (3) Audit engine itself has a Prometheus health endpoint (/metrics)
Residual riskNegligible

R-06 — Prompt injection via connector data

AttributeDetail
DescriptionMalicious content in a monitored system (e.g. a GitHub issue title, a Prometheus label) attempts to override the AI’s instructions.
Trigger conditionsAdversarial content in monitored data sources
LikelihoodVery low — data sources are internal (Prometheus, Supabase) or authenticated external APIs
ImpactLow — could cause incorrect report output; no code execution or external network calls from AI output
Mitigation(1) Connector data is structured (JSON/metrics), reducing free-text attack surface (2) AI output is text-only; no tool calls or shell commands are executed from report output (3) WorkbookSpec validation prevents injecting new connector steps via report content
Residual riskNegligible

A.3 Overall residual risk verdict

Negligible to Low. All identified risks are mitigated to acceptable levels through existing architectural controls. The systems are appropriate for their minimal-risk classification. No additional risk controls are required before August 2026 for these systems.

A.4 High-risk classification triggers

The following scenarios would require re-assessment and full Art. 9 compliance:

  • Introducing AI that scores, ranks, or evaluates driver performance → Annex III.4(a)
  • Introducing AI that automatically assigns tasks or routes to human workers → Annex III.4(a)/(b)
  • Introducing AI that makes creditworthiness assessments about customers → Annex III.5(b)
  • Introducing AI that manages safety-critical vehicle systems or emergency dispatch → Annex III.2(a)

When any of the above is planned: pause deployment, complete full Art. 9 risk management system documentation, and apply conformity assessment procedures.

A.5 Review schedule

EventAction
Annual (next: 2027-06-16)Re-assess all risks; update last_reviewed in dev_r_ai_systems
New AI system deploymentComplete risk assessment before go-live; add row to dev_r_ai_systems
New model version (major)Re-evaluate R-02 and R-03
Security incidentImmediate re-assessment of R-03 and R-06

Part B — Data Governance

B.1 Data inventory

Data categorySourceContains PII?Sent to AI?
Prometheus metricsvps-i1 node_exporter, cAdvisorNoYes (aggregated time series)
Prometheus alert statesAlertmanagerNoYes (alert names, labels)
GitHub Actions dataGitHub APINo (only run counts, workflow names)Yes
Wasabi backup statusWasabi S3 bucket scanNoYes (JSON backup manifest)
Supabase queue depthsSupabase pg_stat_statements, queue tablesNo (counts/depths only)Yes
Supabase fleet datafleet_positions, incidentsPotentially (vehicle IDs)Yes — see B.3
n8n workflow metricsPrometheus n8n_*NoYes
audit.runs outputSupabase audit.runsNoNo (stored, not fed back)

B.2 Personal data assessment

Current connectors in production do not process personal data at the point of AI input:

  • Prometheus metrics: numeric time series, no person identifiers
  • GitHub API: workflow run counts, commit SHAs — no PII
  • Wasabi: file names, sizes, timestamps — no PII
  • Supabase queue depths: integer counts — no PII

Fleet data (Supabase connector — Weekly Fleet Inspection Report):
This connector queries fleet_positions and incidents. These tables may contain:

  • Vehicle registration plates (indirectly identifies a driver in some jurisdictions)
  • GPS coordinates linked to a vehicle

Handling: The AI workbook spec for fleet reports must aggregate and anonymise before passing to AI (e.g. counts, status distributions, not raw plate + location tuples). The workbook designer is instructed to use aggregate queries via the Supabase connector row_limit parameter. Direct raw GPS + plate data must never appear in AI workbook input.

This constraint is noted in audit.projects.config ("pii_handling": "aggregate_only") and enforced by workbook design review.

B.3 Data flow diagram

[Prometheus]──────────────────────────────────────┐
[GitHub API]──────────────────────────────────────┤
[Wasabi S3]──────→ audit-engine connectors         │
[Supabase DB]─────  (on vps-h1)                    │
                         │                         │
                         ▼ structured JSON          │
                   claude-proxy:9999                │
                   (vps-h1, local)                  │
                         │ HTTPS                   │
                         ▼                         │
                  Anthropic Claude API              │
                         │                         │
                         ▼                         │
                   AI analysis text                 │
                         │                         │
                         ▼                         │
              audit.runs (Supabase) ◄──────────────┘
                         │
                         ▼
              PDF via pdf-service → email / Google Drive

All data leaves the VPS network only toward:

  1. Anthropic Claude API (TLS 1.3) — EU data processing terms apply
  2. Supabase (PostgreSQL, TLS) — EU region (eu-central-1)
  3. Google Drive (TLS) — for report archival

B.4 Data quality & bias

Training data: We do not train models — we use Anthropic Claude via API/OAuth. Bias in the underlying model is Anthropic’s responsibility (provider obligations under EU AI Act Art. 55).

Input data quality: Prometheus metrics are collected at 15s intervals by node_exporter/cAdvisor with no preprocessing. Data quality depends on exporter correctness. Known gaps:

  • bms-2 and bms-3 do not yet have node_exporter deployed → those servers are not reflected in AI reports
  • Thanos query covers both live Prometheus + S3 historical blocks for trend analysis

Connector row_limit: All workbook steps set row_limit to prevent unbounded data payloads.

B.5 Data retention

StoreDataCurrent retentionTarget
audit.runsAll run outputs including connector dataIndefinite90 days (add cleanup job)
audit.workbooksWorkbook specsIndefinite (versioned)Keep 3 active versions per action
Anthropic APIRequest/response during callPer Anthropic privacy policy (no retention for Max)N/A
Google DrivePDF reportsIndefiniteAnnual archival review
EmailPDF attachmentsPer email provider policyN/A

Action item: Create a pg_cron job on Supabase to delete audit.runs rows older than 90 days.

B.6 Access controls

SystemWho can accessHow
audit-engineService (vps-h1)SUPABASE_SERVICE_KEY (env var on vps-h1)
audit.runsgrafana_readonly (read), service_role (write)Supabase RLS policies
dev_r_ai_systemsgrafana_readonly (read), service_role (write)Supabase RLS policies
claude-proxyaudit-engine onlyCLAUDE_PROXY_SECRET header (env var)
Anthropic APIclaude-proxy onlyClaude Max OAuth credentials (~/.claude/.credentials.json)
PDF reports (email)Recipients: radieu@gmail.com, ecotrans.automation@gmail.comEmail auth
PDF reports (Drive)Google SA with Drive scopePer-project Vault secret

No external user has access to AI system inputs, outputs, or intermediate data.

B.7 Third-party processors

ProcessorRoleLegal basisEU adequacy
AnthropicProcesses infrastructure metrics + fleet aggregates to generate reportsLegitimate interest (operational reporting); Claude Max subscription termsAnthropic’s EU SCCs / DPA applies; Claude Max: no training on inputs
SupabaseStores AI outputs in audit.runsContract (Supabase Pro subscription)EU region (eu-central-1); Supabase DPA available
Google (Drive/SMTP)Report archival and deliveryContractEU adequacy decision applies

B.8 Data governance review

Any change to the set of connectors or data sources used by audit-engine workbooks must:

  1. Be assessed against B.1–B.3 above
  2. Confirm no PII is passed raw to the AI model
  3. Update this document

Next full review: 2027-06-16


Part C — Risk Management & Data Governance for n8n / GitHub Actions / Telegram AI systems

Added: 2026-06-28 (#1976) — completes the has_risk_management and has_data_governance record for the seven systems that were previously at compliance_status = partial in dev_r_ai_systems. None of these systems is high-risk; this part is the Art. 9 / Art. 10 good-practice baseline appropriate to their minimal / limited classification.

C.1 Systems covered

SystemServiceRisk tierModelProcesses personal data?
imap-inbox-ai-classifiern8n-hstgrminimalClaude (Anthropic)Yes — inbound email content
ai-documents-inbox-processingn8n-cloudminimalClaude (Anthropic)Possibly — names on invoices
wa-ai-to-inboxn8n-bms4minimalClaude Haiku (via SSH→vps-i1)Yes — WhatsApp message content
voice-to-text-inspectiontelegram-inspection-botminimalspeech-to-textNo (transcription only)
tronik-gps-kierowcyn8n-bms4limitedclaude-sonnet-4-6 (via SSH→vps-i1)Yes — GPS linked to named drivers
tronik-gps-serwisant-mobilnyn8n-bms4limitedclaude-sonnet-4-6 (via SSH→vps-i1)Yes — GPS linked to named technicians
resource-incident-triagegha/resource-incident-triagelimitedclaude-sonnet-4-6No (infrastructure telemetry only)
gmail-tools-daily-inbox-agentn8n-bms4minimalClaude Code CLI (Anthropic, via SSH→bms-4)Yes — inbox content of radieu@gmail.com and its correspondents

2026-07-31 (#4724): gmail-tools-daily-inbox-agent was added to this part. It is the first system here that is agentic — the model does not merely classify text, it holds tools for the duration of the run: Gmail write access (label, archive, send) and, because it is invoked as claude --dangerously-skip-permissions, unrestricted Bash and file access on bms-4. C-R4 as originally written (“no shell or tool execution from model output”) is precisely what this system breaks, in both senses; C-R6 below replaces it for this system and must be read as covering the host dimension, not only the mailbox one.

C.2 Shared risk assessment

These systems share a common control profile: each performs classification, transcription, or reporting only — none takes an autonomous action that legally or significantly affects a natural person, so none falls under Annex III. The risks below apply across the group; system-specific notes follow.

RiskLikelihoodImpactMitigationResidual
C-R1 Misclassification / wrong routingLow–mediumLow — output is triage metadata, reviewed downstream; no irreversible actionHuman review of routed items; n8n execution history retained for replayLow
C-R2 AI hallucination in generated text (GPS reports, transcripts)LowLow — reports are informational; recipients told output is AI-assisted (Art. 52 footer)Transparency disclosure on outputs; source data retained for cross-checkLow
C-R3 Personal-data exposure to the AI providerLowMedium — email/WhatsApp/GPS content is personal dataClaude Max / API under Anthropic EU DPA (no training on inputs); calls over TLS; SSH→vps-i1 transport on a private pathLow
C-R4 Prompt injection via inbound content (email, WhatsApp, GPS notes)LowLow — output is text/labels only; no shell or tool execution from model outputOutput consumed as data only; no downstream code execution from model textNegligible
C-R5 Drift into high-risk use (worker scoring / performance evaluation)LowHigh if it occurredWatch-item: GPS report systems are confirmed not used for worker performance evaluation (see C.5); reclassify to Annex III.4(a) and pause if that changesControlled
C-R6 Prompt injection driving a tool call (agentic systems only — currently gmail-tools-daily-inbox-agent)Medium — inbound email is fully attacker-controlled, arrives daily, and is read by the model in the same context as its own instructions(a) Gmail. Worst case is mislabelled, wrongly archived or trashed mail in one personal inbox. Archiving is fully reversible; gmail.modify also permits users.messages.trash, and trashed mail stays recoverable for the 30 days before Google auto-purges it — recovery is possible but time-boxed. (b) Host — was the dimension that made this system different; now bounded. The agent previously ran as claude --dangerously-skip-permissions (unrestricted Bash/file tools for the whole run) as claude-runner, whose home directory holds vps_root_key (root SSH to the whole fleet) and an owner-level GitHub PAT. As of the Option A fix below, the agent instead runs under an explicit --allowedTools allowlist — Read scoped to two named files, Edit scoped to priorities.md, and five fixed Bash(node scripts/<script>.js ...) patterns, no bare Bash/Write/node -e. A tool call outside that list is denied, not skipped, so an injection can no longer reach arbitrary command execution through this agent’s own tool use. The separate, host-wide question — that vps_root_key/the PAT sit on a UID shared by every claude-runner process on bms-4, reachable by any OTHER compromise of that account, not just this agent — remains open and is tracked as Option B, a priorities.md §P1 item independent of this workflow(a) is capped by scope: the live grant carries gmail.modify / gmail.readonly / gmail.labels only — no gmail.settings.*, so it cannot create server-side filters or forwarding rules, and no gmail.*.delete scope (hard-delete is out of reach; trash-and-auto-purge is the residual path, closed by the 24 h digest loop). Bounds are fixed by a repo-committed playbook (gmail-filtering-playbook.md §14) rather than by inbound text; OAuth credentials reach curl on stdin rather than argv (/proc/<pid>/cmdline is world-readable on a host running four concurrent agent sessions); each run leaves a 0600 transcript at /var/log/p24-infra-workers/gmail-daily-agent-*.log; and the owner’s daily digest makes effects visible within 24 h. (b) — Option A shipped. Krok 1’s open-ended Gmail-API scripting (the reason a narrow allowlist wasn’t previously possible without breaking the workflow) was replaced with two purpose-built scripts — gmail-query.js (read-only) and gmail-mutate.js (label add/remove only; cannot delete, send, or create labels/filters; fails closed on an unknown label) — giving the allowlist something safe to point at. Full rationale + live verification: radieu/gmail-tools docs/daily-agent-security-model.md. Unsetting ANTHROPIC_API_KEY and SSH_AUTH_SOCK closes inherited paths only, and this does not reach the on-disk key/PAT readable by any other process under the same UID — that residual is Option B’s scope, not this fix’sLow for this workflow’s own attributable risk — Option A closes the realistic injection→execution path specific to this agent. The broader host-level question (credential placement shared across every claude-runner process on bms-4) remains open, tracked separately as priorities.md §P1 / Option B, and is not specific to gmail-tools-daily-inbox-agent — every other agent on that account carries the same exposure today

C.3 System-specific notes

  • imap-inbox-ai-classifier / ai-documents-inbox-processing — minimal-risk classifiers. No mandatory EU AI Act obligation. Structured logging and explicit human-oversight controls are good-practice (not legally required at this tier); n8n execution history provides a basic audit trail. Personal data handling: see C.4.
  • wa-ai-to-inbox — minimal-risk message triage. Art. 52 transparency does not apply: the system routes inbound WhatsApp messages into a Supabase inbox and never returns AI-generated text to the end user (AI replies are handled separately by the waha-router Cloudflare Worker). Human oversight: inbox is reviewed by staff.
  • voice-to-text-inspection — minimal-risk transcription. No automated decision; a human mechanic sends a voice note and receives a text transcript. Human reviews all output; logging present.
  • tronik-gps-kierowcy / tronik-gps-serwisant-mobilny — limited-risk reporting. Art. 52 transparency met: an AI-disclosure footer was added to the report document (2026-06-16). Human oversight: reports are reviewed before use. Confirmed not used for worker performance evaluation (see C.5) — remain limited, not Annex III.4(a).
  • resource-incident-triage — limited-risk infrastructure triage; operates on server/infra telemetry only (no people scoring/allocation). Full control set already documented (docs/playbooks/resource-incident-monitoring.md); autonomous action is bounded to documented playbooks with human-action escalation, and production-critical targets (WAHA, MongoDB, Pinbox24) are hard-excluded. Activation remains **gated on 1467 — an operational safety control, not a documentation gap.
  • gmail-tools-daily-inbox-agent (#4724) — minimal-risk personal-inbox housekeeping, and the only agentic system in this part (see C-R6). Once a day it categorises, archives and digests the owner’s own Gmail. It is not Annex III: it scores no one, allocates no work to anyone, and makes no decision about a natural person — the subject of the data is the operator himself. Art. 52 transparency is not engaged: the sole recipient of AI-generated text (the daily digest) is the same person who runs the system. Human oversight (Art. 14): the digest is read daily, every Gmail action the agent can take is reversible — labels and archiving unconditionally, trashing for the 30 days before Google’s auto-purge (see C-R6) — and the n8n workflow can be deactivated with one API call (docs/gmail-tools-daily-agent-operations.md §Operations). Logging (Art. 12): full per-run transcript on bms-4 plus the n8n execution record; failures reach Discord + Supabase proc_log via the shared error_flow handler. The minimal tier is an EU AI Act classification, not a security rating, and the two do not move together here. The tier answers one question — does the system evaluate, rank, allocate or decide about a natural person? It does not, so no Annex III category attaches and the tier is correct at minimal. The security blast radius was separately assessed under C-R6(b); since the Option A fix (a scoped --allowedTools allowlist replacing --dangerously-skip-permissions — see C-R6 above and radieu/gmail-tools docs/daily-agent-security-model.md) this workflow’s own attributable residual is Low, with the broader host-wide credential-placement question (Option B) tracked separately as priorities.md §P1, not specific to this system. The workflow shipped deactivated on three gates; p24-infra#4785 is resolved and C-R6(b) is resolved via Option A — only radieu/gmail-tools#2 (expired OAuth grant, needs an owner re-auth) remains before activation.

C.4 Data governance for these systems

SystemPersonal data inLawful basisHandling / retention
imap-inbox-ai-classifierEmail subject/bodyLegitimate interest (mail routing)Classified in transit; n8n retains execution history per n8n retention policy; no separate AI-side store
ai-documents-inbox-processingNames on invoices/documentsLegitimate interest (document routing)Financial documents; extracted fields stored in the target system, not retained by the AI step
wa-ai-to-inboxWhatsApp message contentLegitimate interest (support triage)Routed into Supabase inbox; subject to the WhatsApp/inbox retention policy; no AI-side store
voice-to-text-inspectionVoice note (mechanic’s own)Legitimate interest / consent (user initiates)Transcribed to text; no profiling; transcript returned to sender
tronik-gps-kierowcyGPS coordinates + driver identityLegitimate interest (fleet ops)Aggregated into a report; AI-disclosure footer; raw GPS not used for individual performance scoring
tronik-gps-serwisant-mobilnyGPS coordinates + technician identityLegitimate interest (service ops)Same handling as tronik-gps-kierowcy
resource-incident-triageNone (infra telemetry)Legitimate interest (ops)No personal data; logs in GH Actions + dev_r_incidents
gmail-tools-daily-inbox-agentEmail subject/body/sender of radieu@gmail.com — includes third-party correspondentsLegitimate interest (the account holder’s own mail administration); the data subject of the account is the operatorRead in-place via the Gmail API — no copy is exported to Supabase or any other store. Two durable artefacts may quote subjects and senders, both treated as personal data with the controls implemented in the runner script, not merely asserted: (1) the run transcript on bms-4 (/var/log/p24-infra-workers/gmail-daily-agent-*.log, owned by claude-runner) is created 0600 under umask 077 — the shared directory is 2755 and sibling worker logs are 0666, so the mode is set per-file — and pruned after 30 days by a filename-scoped find … -delete at the start of each run, which is the only retention mechanism covering that directory (no logrotate unit or repo-wide rotation exists); (2) the 60-line tail carried into the n8n execution record and its Discord alert, purged after 7 days by n8n’s own EXECUTIONS_DATA_PRUNE=true / EXECUTIONS_DATA_MAX_AGE=168 (bms-4/docker-compose.yml). No AI-side retention (Anthropic EU DPA, no training on inputs)

Third-party processors: Anthropic (Claude — EU DPA, no training on inputs), Supabase (EU region, DPA), and the respective n8n / Telegram / WhatsApp transports. These align with the Part B B.7 entries.

C.5 High-risk drift confirmation (2026-06-28, #1976)

A registry-wide review confirmed no system has drifted into high-risk classification: all 12 registered systems are minimal (6) or limited (6); none is high or prohibited. The two GPS report systems carry the only material reclassification trigger (Annex III.4(a)) and were explicitly confirmed not to be used for evaluating, ranking, promoting, terminating, or allocating tasks to workers — they produce location/route reports only. If that use ever changes, pause and complete the full Art. 9 high-risk procedure per A.4.

2026-07-31 (#4724) — new-system check. gmail-tools-daily-inbox-agent was assessed against A.4 on registration and does not trigger a high-risk category: it evaluates, ranks and allocates nothing to any person, and the only natural person whose affairs it touches is the account owner who operates it. Classification: minimal. Its distinguishing property is agency (tool use), not risk tier — that is handled by C-R6, not by reclassification.

C.6 Review schedule

Same cadence as A.5 / B.8: annual review (next 2027-06-16), plus immediate re-assessment on any new AI system, major model change, or any move toward worker-performance use of the GPS systems.