Compliance evidence mapping¶
PrivaCI produces technical evidence for database anonymization runs. Your organization remains the controller/processor for GDPR, the covered entity or business associate for HIPAA, and the accountable party for SOC 2 and ISO 27001 certifications. This document describes how to collect and verify PrivaCI artifacts and maps report fields to frameworks your compliance team may reference — it is not audit advice.
Marketing alignment: PrivaCI supports audit-ready reports for SOC 2, ISO 27001, GDPR, and HIPAA reviews. It does not replace organizational certification, control design, or legal determinations. Framework mappings below are illustrative; validate scope with your auditor or counsel.
How to use this document¶
| Audience | Start here |
|---|---|
| Platform / data engineering | Evidence collection workflow |
| Compliance / GRC | Field → framework mapping and Evidence artifact checklist |
| Legal / DPO | ROPA snippet and Retention starter template |
Evidence collection workflow¶
Run this sequence after each production-source anonymization job (or on a schedule aligned with your change-management cadence).
1. Execute and record the run¶
export SOURCE_DB_URL='postgresql://…/production_source'
export TARGET_DB_URL='postgresql://…/staging_target'
export ANONYMIZATION_SALT='…' # ≥32 chars; never commit
export PRIVACI_OPERATOR_ID='platform-team-ci-42' # optional; appears in report
privaci run --config mask-rules.yaml
# Note the run_id printed in the summary (also in _privaci.runs).
The run writes immutable state to _privaci.runs and _privaci.audit_log on the
target database. Partial runs can be resumed; interrupted runs exit 130.
2. Generate a signed compliance report¶
See Signed reports for key generation, env vars, and verify.
export PRIVACI_REPORT_SIGNING_KEY_PEM='…'
export PRIVACI_OPERATOR_ID='ci-pipeline-42'
export PRIVACI_REPORT_SUMMARY_MD='/var/evidence/run-summary.md'
export PRIVACI_REPORT_SUMMARY_PDF='/var/evidence/run-summary.pdf'
privaci report --run <run-uuid> --format json --output "evidence/report-<run-uuid>.json"
# Or human-readable PDF (verify the signed JSON companion, not PDF bytes):
privaci report --run <run-uuid> --format pdf --output "evidence/run-<run-uuid>.pdf"
For S3 evidence buckets (all commercial tiers), use an object URI — see public Object output URIs:
privaci report --run <run-uuid> --format json \
--output "s3://compliance-evidence/privaci/<year>/<run-uuid>/report.json"
Archive the signed JSON, Markdown sidecar (if generated), and PDF summary (if generated). For S3 Object Lock buckets, store JSON + PDF under the same prefix so auditors can reconcile each run against its signed provenance and coverage fields.
3. Verify signature and integrity (CI or auditor workstation)¶
export PRIVACI_REPORT_VERIFY_PUBLIC_KEY_PEM="$(cat report-signing.pub.pem)"
python - <<'PY'
from pathlib import Path
from privaci_commercial.report_verify import verify_report_file
payload = verify_report_file(
Path("evidence/report-<run-uuid>.json"),
public_key_pem=Path("report-signing.pub.pem").read_bytes(),
)
print(payload["summary"]["verdict"]["status"])
PY
4. Check schema drift (optional gate before the next run)¶
See Drift detection for the Python API and CI gate pattern.
5. File evidence¶
Store under a stable path, e.g. s3://compliance-evidence/privaci/<year>/<run_id>/:
| Artifact | Retention |
|---|---|
Signed report-<run_id>.json |
≥12–18 months (see Retention) |
run-summary.md sidecar |
Same as JSON |
| Verification log (stdout / CI job URL) | Same as JSON |
mask-rules.yaml hash (from summary.provenance.config_hash) |
Version-controlled separately |
| Drift report JSON (if collected) | Same as JSON |
Report structure¶
Signed JSON reports (commercial layer) contain:
| Section | Purpose |
|---|---|
summary |
One-screen verdict, coverage, exceptions — start here |
run |
Raw run metadata from _privaci.runs |
audit_events |
Full drill-down audit trail |
Envelope signature |
Ed25519 tamper evidence over canonical JSON |
Generate a report:
export TARGET_DB_URL='postgresql://postgres:dev@127.0.0.1:55433/privaci_target'
export PRIVACI_REPORT_SIGNING_KEY_PEM='…' # optional; signs envelope
export PRIVACI_OPERATOR_ID='ci-pipeline-42' # optional; provenance
export PRIVACI_REPORT_SUMMARY_MD='/tmp/run-summary.md' # optional sidecar
privaci report --run <run-uuid> --format json --output report.json
S3 (ECS task role or AWS_* credentials):
privaci report --run <run-uuid> --format json \
--output "s3://compliance-evidence/privaci/<run-uuid>/report.json"
See public Object output URIs for URI forms, MinIO testing, and custom plugins.
Verify a signed report:
from pathlib import Path
from privaci_commercial.report_verify import verify_report_file
public_pem = Path("report-signing.pub.pem").read_bytes()
payload = verify_report_file(Path("report.json"), public_key_pem=public_pem)
print(payload["summary"]["verdict"])
Or set PRIVACI_REPORT_VERIFY_PUBLIC_KEY_PEM and use
:func:privaci_commercial.report_verify.verify_report_bytes in CI.
Markdown-only export (commercial ReportRenderer, format summary-md):
from uuid import UUID
from privaci_commercial.reports import SignedJsonReportRenderer
md = SignedJsonReportRenderer().render(
UUID("019ed1bf-97be-730a-8bb0-e019cea366c9"),
output_format="summary-md",
)
print(md.decode())
Field → framework mapping¶
Illustrative mapping only — customers decide which controls and frameworks apply.
| Summary field | SOC 2 TSC | ISO 27001 | GDPR | HIPAA de-ID |
|---|---|---|---|---|
verdict.status, timestamps, duration_ms |
PI1.2 processing integrity | A.8.15 logging | Art 30 ops record | Processing log (when, outcome) |
provenance.run_id, config_hash, versions |
CC8.1 change/config traceability | A.8.11 documented techniques | Art 32 measures | Rule/version binding |
provenance.salt_fingerprint |
C1.1 confidentiality | A.8.11 pseudonymisation key governance | Art 32 pseudonymisation | Tokenization key controls |
provenance.operator |
CC6.1 logical access | A.8.2 user identification | Accountability | Certifier identity |
controls_applied.techniques |
C1.1 / PI1.3 | A.8.11 masking techniques | Art 32 technical measures | Field transformation inventory |
controls_applied.techniques_by_column |
Primary column-level method counts (fake, redact, hash, …) | A.8.11 documented per-field techniques | Art 32 measure inventory | Per-column transformation map |
coverage.* |
PI1.4 completeness | A.8.11 effectiveness | Risk mitigation evidence | QA / sampling support |
schema_objects.created |
PI1.2 schema change evidence | A.8.9 inventory of replicated objects | Art 30 technical measures | View/function inventory |
schema_objects.definition_only |
PI1.3 no-copy guarantee for matviews | A.8.11 definition-only shells | Art 32 residual risk control | Matview contents not copied |
schema_objects.skipped |
PI1.4 exceptions | Nonconformity / deferred objects | Art 32 residual risk | Elevated/unsafe skips |
attention_required.* |
PI1.4 exceptions | Nonconformity / risk register | Art 32 residual risk | Residual PHI review |
attention_required.policy_diff_findings |
Pre-run CI gate evidence | Policy drift before masking | Residual risk from preview | Preview-before-run QA |
processing_scope.personal_data_categories_inferred |
— | A.8.11 data inventory (partial) | Art 30 ROPA categories | Identifier categories |
audit_rollup + audit_events |
CC7.2 monitoring | A.8.15 event logging | Integrity (Art 32) | Audit trail |
Ed25519 signature |
CC7.2 integrity | A.8.15 log protection | Integrity (Art 32) | Tamper-evident record |
Evidence artifact checklist¶
Product-focused list of what to collect per anonymization run. Your org owns control design, policy wording, and how evidence maps to certification scope.
| Artifact | Source | Notes |
|---|---|---|
| Signed compliance report | privaci report --format json |
Primary technical evidence; verify with Ed25519 |
| PDF summary | privaci report --format pdf or PRIVACI_REPORT_SUMMARY_PDF |
Human-readable view; tamper-evidence is the JSON companion |
| Signature verification output | report_verify (see workflow step 3) |
Proves payload unchanged since signing |
| Markdown summary sidecar | PRIVACI_REPORT_SUMMARY_MD or summary-md |
Human-readable; same run as JSON |
mask-rules.yaml commit |
Version control | Tie to summary.provenance.config_hash |
| Operator / runner identity | PRIVACI_OPERATOR_ID or CI role |
Optional; set in your pipeline |
| Drift review output | Drift Python API (see step 4) | When schema may have changed |
| Run exit code / CI job URL | Shell / orchestrator | 0 = succeeded |
Example index for your evidence store:
## PrivaCI run evidence — <run_id>
| Item | Location |
| --- | --- |
| Signed report | evidence/report-<uuid>.json |
| Verify log | ci/job-<id> or manual output |
| Config | git:<sha> (config_hash: …) |
| Drift (if run) | drift-<date>.json |
Retention starter template¶
Starter text for your internal policy — adjust periods and roles to match your obligations. PrivaCI does not host or retain customer reports.
## PrivaCI compliance report retention
**Purpose:** Preserve tamper-evident evidence of database anonymization runs.
**Scope:** All production-source → non-production anonymization jobs using PrivaCI.
**Retention period:** Minimum 18 months from report generation date.
**Storage:** [Customer bucket / GRC system]. Encryption at rest required.
**Access:** Compliance, Internal Audit, and Platform Engineering (read-only).
**Deletion:** Automated lifecycle rule after retention period; deletion logged.
**Verification:** Re-run signature verification annually on a sample of archived reports.
**Related artifacts:** mask-rules.yaml (version control, indefinite);
signing public key (until key rotation + overlap period ends).
ROPA snippet (customer template)¶
## Processing activity: non-production database anonymization
- **Purpose:** Realistic staging/test data without production PII
- **Lawful basis / role:** [customer completes]
- **Categories of data subjects:** See `summary.processing_scope.data_subject_categories_inferred`
- **Categories of personal data:** See `summary.processing_scope.personal_data_categories_inferred`
- **Recipients:** Internal non-production environments (in-VPC)
- **Retention:** Target DB per customer policy; signed report retained ≥12–18 months
- **Technical measures:** PrivaCI in-VPC masking; evidence: signed report `{run_id}`
Control ownership matrix¶
| Area | Customer owns | PrivaCI provides |
|---|---|---|
| Certification scope & policies | ✓ | Guidance only (this doc) |
| Database credentials & network | ✓ | Connection via standard Postgres |
| Salt / signing key custody | ✓ | Fingerprint + signature mechanics |
| Mask rule authoring | ✓ | Validation + execution |
| Run execution & scheduling | ✓ | CLI / container |
| Tamper-evident report | — | ✓ Signed JSON + verify helpers |
| In-run audit trail | — | ✓ _privaci.audit_log + report export |
| Report hosting & retention | ✓ | — |
| Organizational SOC 2 / ISO cert | ✓ | Product evidence, not vendor cert |
Retention guidance¶
Store signed reports for at least 12–18 months to cover typical SOC 2 Type II observation windows. PrivaCI does not retain customer reports — reports live in your environment.
Gaps and roadmap¶
| Gap | Impact | Mitigation |
|---|---|---|
| Preflight catalog warnings not in audit log | Incomplete exception register | Engine batch: write warnings to _privaci.audit_log |
No config_version in summary |
Weaker config traceability | Add when config artifact ID is stored on run row |
passed_through events not emitted by engine yet |
Passthrough counts from PII detections only | Engine batch: emit column.passed_through |
| Organizational SOC 2 / ISO certs | Vendor trust vs product evidence | BoundaryLogic vendor audit (separate from product) |
privaci detect-drift CLI |
Requires engine v1.0.0+ and commercial v1.0.0+ | Use drift CLI or Python API in CI |
Related documentation¶
Commercial¶
- Signed reports — signing, verify, Markdown export
- Drift detection — schema drift CI gate
- Troubleshooting — exit codes
Public engine¶
- Error codes — exit codes for run/report failures
- State schema —
_privacitables referenced in reports - Configuration —
mask-rules.yaml
Disclaimer¶
This mapping is guidance for customer compliance teams, not legal advice. Consult counsel for certification scope and HIPAA de-identification determinations.