ivd

ComplyEdge TrustLint — IVD integration

IVD uses ComplyEdge TrustLint on LLM-facing artifacts: offline EU AI Act screening in CI, optional runtime checks, and a public trust surface.

Tenant slug: ivd


What runs where

Layer Mechanism API key in repo? Blocks merge?
Offline gate trustlint check via ./scripts/compliance/check.sh No Yes (CI compliance job)
Runtime enforcement (CI probe) POST /v1/check via ./scripts/compliance/runtime_check.sh No (BYOK env only) No (opt-in local / scheduled)
Runtime enforcement (MCP tools) POST /v1/check around every tool call in mcp_server/registry.py → mcp_server/compliance.py No (COMPLYEDGE_API_KEY in the server env) N/A — blocks the tool call
Public proof Live seal + trust JSON No N/A
ivd_scaffold → ivd_validate → trustlint check (offline) → CI green
                    ↓ optional BYOK
              runtime_check.sh → /v1/check → audit trail → badge + trust page

Public surfaces

Surface URL
Enforcement seal (SVG) https://api.complyedge.io/v1/public/badge/ivd.svg
Trust JSON https://api.complyedge.io/v1/public/trust/ivd
Trust page https://trust.complyedge.io/ivd
Origin site (badge host) https://ivdframework.dev
Overview on site https://ivdframework.dev/#complyedge

The seal reflects live runtime audit data (checks in 24h / 7d). It is not a static marketing badge.


LLM-facing scan scope

Recipes, templates, all *_intent.yaml, and root ivd_system_intent.yaml — see .trustlint.yaml for exact globs.

Agent workflow: ivd_scaffold → ivd_validate → ./scripts/compliance/check.sh → declare done. Recipe: ivd_load_recipe compliance-trustlint.


Operator setup (BYOK)

  1. Provision a ComplyEdge tenant with slug ivd and store the API key in env only — COMPLYEDGE_API_KEY (GitHub Actions secret for optional runtime job, never in git).
  2. Enable public trust:
curl -s -X PATCH https://api.complyedge.io/v1/tenant/trust \
  -H "Authorization: Bearer $COMPLYEDGE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"trust_public_enabled": true, "public_slug": "ivd", "display_name": "IVD Framework", "website_url": "https://ivdframework.dev"}'
  1. Seed runtime checks (feeds live seal):
export COMPLYEDGE_API_KEY=ce_...
./scripts/compliance/runtime_check.sh

MCP tool calls

When the MCP server’s environment has COMPLYEDGE_API_KEY, every tool call is checked twice by call_tool (the single dispatch all 33 tools pass through):

Check direction text
Before the tool runs prompt tool name + JSON arguments
Before the result returns output the tool’s result

Each check sends agent_id (ivd-mcp), jurisdiction (EU) and context:

Field Remote (SSE / StreamableHTTP) Local (stdio)
user_id ivdkey:<sha256 prefix of the IVD API key> (never the key) local:<login>
user_role mcp_client maintainer
session_id Mcp-Session-Id header or SSE session_id omitted

A block returns the rule ID and audit event instead of the tool’s answer. If ComplyEdge cannot be reached the call goes through and the skip is logged on stderr (fail-open). Without the key nothing is sent. Optional: COMPLYEDGE_API_URL (default https://api.complyedge.io), COMPLYEDGE_AGENT_ID, COMPLYEDGE_JURISDICTION, COMPLYEDGE_TIMEOUT_S (default 15: a cold ComplyEdge instance can take ~8 s to answer, and a check that times out is skipped, verdict and Log ID with it). Tests: mcp_server/tests/unit/test_runtime_compliance.py.

Log IDs

ComplyEdge keeps a keyed fingerprint of each checked text, never the text. Every check returns an event_id (the Log ID), and a Log ID only proves something next to a copy of the text. IVD keeps none, so every checked tool call returns both Log IDs in the result’s _meta, outside the text:

{"_meta": {"complyedge": {"input_event_id": "...", "output_event_id": "..."}}}

A Log ID is null when that check did not run (ComplyEdge unreachable, or an input block that stopped the call). Without the key there is no _meta. The text you receive is exactly the text that was checked, so store each Log ID next to your copy:

Log ID Text it covers
input <tool name> <arguments as JSON with sorted keys>
output the tool result’s text

A text longer than 50,000 characters is checked on its first 50,000. Later, POST /v1/audit/verify with a Log ID and your copy answers whether they match (how audit reconciliation works). Tests: mcp_server/tests/unit/test_complyedge_log_ids.py.


CI

Job Path Secret required
compliance ./scripts/compliance/check.sh None
compliance-runtime (optional) ./scripts/compliance/runtime_check.sh COMPLYEDGE_API_KEY

Offline gate is the auditable merge blocker. Runtime is opt-in proof for live trust metrics.


Local validation

pip install 'trustlint>=2.0.1'
./scripts/compliance/check.sh
pytest mcp_server/tests/unit/test_compliance_trustlint.py -q
export COMPLYEDGE_API_KEY=ce_...
./scripts/compliance/runtime_check.sh

References