Module 12 · Enterprise level (capstone)

Lesson 56 — Compliance

GDPR, audit logs and SOC 2 / ISO 27001 at a glance.

Published
In this lesson
  1. Exercise 1 — The legal bases
  2. Exercise 2 — The Art. 30 map
  3. Exercise 3 — The SOC 2 evidences
  4. Exercise 4 — The audit log and the breach
  5. Exercise 5 — The internal DPO
  6. Professor's summary
  1. The classification: email (contract: the sale), optional phone (consent: only if the org wants SMS notices), purchase history (contract + fiscal obligation: the retention), login IP (legitimate interest: security, 23), the analytics cookie (consent BEFORE loading it: the banner), the org's photo (consent + the content's lawfulness). The table with the basis per row: the datum without a basis does not get collected (minimization).
  2. The opt-in's evidence:
python
class MarketingConsent(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    version_texto = models.CharField(max_length=20)     # "v2027-03"
    concedido_en = models.DateTimeField()
    revocado_en = models.DateTimeField(null=True)

# marketing's filter: ACTIVE consent (granted and not revoked) — the derived flag, not the loose boolean
  1. The extended erasure flow: the profile and contacts get DELETED; the ticket/ledger's email gets ANONYMIZED (u-841@deleted.invalid — the invoicing history's integrity preserved) and the audit records "erasure executed per request X, 3 tables, 2 anonymized". The test: the later export without PII + the ledger balancing (the month's commission identical): the money's legal exception works without breaking the invoicing.

Exercise 2 — The Art. 30 map

  1. The map's findings: 45's log: technical identifiers without PII (basis: legitimate interest, 30-day retention); the profile cache (38): PII in Redis → contract basis + per-user purge (23) + 60 s TTL (the datum expiring by itself: retention in the cache); the event's guests table (the free-text field of the companions' names): unclassified → classified (contract, retention event end + fiscal).
  2. The PII guard: the test scanning active cache keys and sample log lines against the email/phone regexes: 0 matches. The typical finding: 26's detail with the email the user mistyped (the error log carried the payload: fixed with the identifier).
  3. The map's doc with the quarterly review and the owner: the Art. 30 document with the link to each schema (48: doc-linked-to-code).

Exercise 3 — The SOC 2 evidences

  1. The 3 evidences (repo scripts):
bash
manage.py reporte_accesos --desde 2027-07   # the role escalations of the audit (23/21)
manage.py reporte_secretos                  # 27's rotations with date and actor
manage.py reporte_cambios --sin-review      # the deploys without a PR: expected 0 (41)
  1. The change chain proven: direct push to main → blocked (branch protection: 41's PR + CI); the kubectl apply outside the pipeline → 44's drift diff catches it at the next plan; the emergency hotfix → emergency PR with the documented later review (47). The change controls with evidence: the CI + the IaC.
  2. The honest gap: the quarterly access review (who has access they no longer need?) did not exist → the issue with owner/date (exercise 1's script as its base). The declared gap: the control on its way.

Exercise 4 — The audit log and the breach

  1. The auditor's queries with their test:
python
def test_consulta_de_datos_de_usuario_solo_admin(self):
    self.client.force_authenticate(self.soporte)          # NOT an auditor
    r = self.client.get(f"/admin/audit/dato/{self.user.id}")
    self.assertEqual(r.status_code, 403)                   # 21: audit access is privileged
    self.client.force_authenticate(self.auditor)
    self.assertEqual(self.client.get(...).status_code, 200)  # and the query got audited (the meta-audit!)
  1. Retention as a job: with FakeClock 13 months: the audit row > 12 months archives to cold (42's bucket) and the purge's record lands in audit. The revoked consent: the marketing datum purged in the next cycle with its row ("purged by revocation").
  2. The breach runbook (excerpt): T0 detect (46's alert) → T+1h scope (47: protocol) → T+2h contain (41's flag/rollback) → T+24h assess risk (high? → notify the affected) → T+72h notify the regulator (the doc's template) → postmortem with the regulatory action. The written thresholds: "sensitive data or >100 affected: the affected always; the rest: the DPO's assessment" — the decision documented before the clock.

Exercise 5 — The internal DPO

  1. The schema's linter:
python
def test_toda_tabla_con_pii_clasificada(self):
    for model in MODELOS_CON_DATOS_PERSONALES:
        assert hasattr(model, "data_classification"), \
            f"{model.__name__} without legal basis/retention: the Art. 30 map lies"

The data_classification = {"base": "contrato", "retencion": "5y"} in the Meta: the schema annotates its compliance (§2's map generated from code: 48's living reference).

  1. The internal DPO's diagram:
[Art.30 map generated from the schema] ← the classification linter (1)
[export/erasure API]  → audit ← SLA minutes (23)
[retention jobs 31]   → audit ← automatic purges (4)
[SOC 2 evidences]     → cron reports (3)
[breach runbook]      → doc with expiry (48)
  1. The final checklist (10 items): legal bases, generated map, consent with evidence, erasure with the money's exception, portability, PII in log/cache guarded, auditor queries, automated retention, breach runbook, SOC 2 evidences (3 of 5: the access review in issue). The real status: 9 of 10 — compliance as the course's engineering consequence, with the remaining gap documented.

Professor's summary

  • GDPR gets implemented in the data's cycle: legal basis per datum, minimization, retention by type, and the erasure respecting the money's exception (anonymize, don't delete the invoicing).
  • SOC 2 audits controls operating: the course already produces the evidences (PRs, rotations, drills, postmortems) — 80% of the certificate is organizing good engineering.
  • The append-only audit log + the auditor's queries + the retention jobs + the classification linter = the internal DPO: compliance as the system's observable consequence.