compliance
Platform audit trail + GDPR data-subject rights. Re-homed from a removed addon back into the always-loaded core by ADR-0009 — the personal data it acts on (user, auth, tenant) is core-owned, so the compliance plane ships on day one.
What it owns
- Audit trail — an append-only
compliance_audit_eventscollection. Every other module emits events through theiface.AuditSinkseam without importing this package; the sink write is fire-and-forget so it never blocks a hot path. - Auth security events — initialization wires the sink to the canonical auth service through
iface.AuditSinkSetterundermodule.ServiceAuthService, alongside the existing password-service and tenant-service consumers. Successful initial-password enrollment emitsself_password_addedthrough the auth security-event lane and mirrors it once asauth.password.addedin the compliance trail. Enrollment does not also emit a direct password-service audit event; existing password-service direct-audit actions keep their sink. - Module-config change events — every authenticated mutation of a module's configuration (
PATCH /v1/admin/modules/{name},PATCH …/environments/{env},PUT …/active-environment, enable/disable) emitsmodule.config.updated,module.config.environment_activated,module.enabledormodule.disabledinto the same trail with the acting user's UUID, tenant context, IP, User-Agent, the key names the request submitted and the failure code — never values or secrets, never the actor's email. Emission is best-effort (a sink failure is logged, not rolled back) and events share the trail's existing two-year retention; deployments needing guaranteed evidence should plan a durable outbox. The records hold an actor UUID, tenant context, IP and User-Agent for privileged-change forensics — the deployer documents the applicable lawful basis and retention for them in its RoPA / privacy materials. - GDPR DSR pipeline — right-of-access export and right-to-erasure over the
iface.PIIProducerseam. The pipeline walks every registered producer (user,auth,tenant,authz,notification) at request time, so adding a producer needs no change here. - Per-tenant KMS — envelope encryption + crypto-shred of a tenant's data-encryption key.
- Legal hold — an active hold on a subject blocks erasure platform-wide (DSR erase + retention auto-cleanup return
409). - Retention auto-cleanup — a daily job that hard-deletes anonymized user tombstones past the retention window. Off by default.
- Mediated erasure-request workflow — a subject lodges a request; an operator reviews, then executes or rejects it.
- SOC2 evidence — a point-in-time controls snapshot. Gated off by default (
soc2_enabled). - Compliance policies — a named, versioned catalog: one platform policy plus tenant policies assigned to internal or client tenants. A policy sets what reaches the operational logs and traces (IP addresses, user agents, user identifiers, personal-data keys, free-text scanning) and the audit retention of each retention class — stored and resolved today, applied to stored audit events by a later stage. Changes need a reason, keep an immutable version, and — when they lower protection — wait for a second operator (four eyes).
Routes
-
Self-service (authenticated subject):
POST /v1/me/dsr/{export,erase,erasure-request}. -
Admin reads (
system.compliance.audit.read):GET /v1/admin/audit-events,…/compliance/legal-holds,…/compliance/retention/preview,…/compliance/erasure-requests, and…/compliance/soc2(when enabled). -
Admin writes (step-up gated): place/release legal holds (
system.compliance.legalhold.manage), execute/reject erasure requests (system.compliance.dsr.manage). -
Policy engine reads (
system.compliance.policy.read): list and read policies and their versions, the effective policy of a tenant, the retention-class catalog, assignments, change requests, and validation previews (POST …/compliance/policies/validate,POST …/compliance/policy-assignments/{tenantId}/validate). -
Policy engine writes (
system.compliance.policy.manage, step-up gated): create, change and delete policies, assign a policy to a tenant or move it back to the platform policy, approve or reject change requests. A change that waits for four eyes answers202with the created request.Until
CEDAR_ENFORCE_ACTIONSincludessystem.compliance.policy.manage, the role table grants it by suffix to the platformmanagerrole too, who can then manage and approve policies — the same aslegalhold.manageanddsr.managetoday. Add it toCEDAR_ENFORCE_ACTIONSonce the policy engine is in use. -
Client surface (Tier 2, own tenant only):
GET /v1/tenants/{tenantId}/compliance/policyshows a client how its own data is logged and the retention configured for it;retentionEnforcedstaysfalseuntil audit events are stamped and deleted by class.
Config
soc2_enabled (default false) · auto_cleanup_enabled (default false) · retention_years (default 5) · export_retention_days (default 30) · four_eyes_enabled (default true).
:::note Always-on Unlike a fork's optional modules, the audit log + GDPR DSR pipeline cannot be disabled — that is the point of making compliance core. Only the SOC2-evidence and retention-auto-cleanup sub-features are gated. :::
Retention classes
| Class | Events | Purpose | Legal basis | Minimum | Default | Set per tenant |
|---|---|---|---|---|---|---|
admin_access | Tier-1 operator logins, logouts, failed logins, MFA, impersonation | Control of administrator access | Art. 6(1)(c) GDPR — Garante, system administrators measure | 184 days (hard) | 365 | yes |
privileged_change | Configuration, role, user, tenant and policy changes by operators | Accountability and security | Art. 6(1)(f) — legitimate interest | 1 | 730 | yes |
client_activity | Actions and logins of Tier-2 client users | Security of the service to the client | Art. 6(1)(b) or (f) | 1 | 365 | yes |
authentication_security | Authentication security events | Fraud and abuse detection | Art. 6(1)(f) | 1 | 365 | no |
compliance_evidence | Policy versions, assignments, change requests, DSR, legal holds, verifications | Demonstrating compliance (art. 5(2), 30) | Art. 6(1)(c) | 1 | 1825 | no |
The catalog is fixed in code: a policy only chooses the days, within the minimum and ten years. Adapt the purposes and legal bases to your own records of processing. Stamping and deleting audit events by class is a later stage; until it ships, audit events keep the collection's current retention.
Four eyes
With four_eyes_enabled on (the default), a policy change that raises warnings is not applied: it becomes a change request that another operator approves or rejects with a note. The warnings are:
| Warning | Raised when |
|---|---|
less_restrictive_than_platform | a tenant policy is less restrictive than the platform policy |
less_restrictive_than_current | an assignment, a reassignment, a removal or an edit leaves a tenant with a less restrictive effective policy than it has now |
retention_longer_than_default | a class is set above its default |
retention_shorter_than_default | a class is set below its default, so audit evidence expires sooner |
sink_retention_longer_than_default | a sink value of the platform policy is above its default |
external_sink_changed | an external sink is added or changed against the current platform policy (GDPR art. 28 and 44 — check the processor agreement and transfer basis) |
ip_full | full IP addresses are kept |
review_overdue | the review date is in the past or empty |
accountability_incomplete | the record-of-processing or assessment reference is empty |
The operator ticks an acknowledgement to send a change with warnings. An approval re-checks the current state and supersedes the request if the policy or the assignment changed meanwhile. Requests expire after 14 days: a request past that age can no longer be approved or rejected, even before the hourly sweep marks it. Reasons and notes are personal data kept as compliance evidence: e-mail addresses, IBANs and codici fiscali typed into them are masked before they are stored.
:::caution Supported controls, not conformity The policy engine supports GDPR minimisation and storage limitation and ISO/IEC 27001 controls such as A.5.3, A.8.11 and A.8.15. Conformity is shown by your risk assessment and Statement of Applicability, not by this module. :::