Skip to content
Back to skills

Gdpr Test Patterns

ASecurity

Reference catalog of GDPR-aligned test patterns - data-subject-rights workflows (Art. 15 access, Art. 16 rectification, Art. 17 erasure / \"right to be forgotten\", Art. 18 restriction, Art. 20 portability, Art. 21 objection); consent recording + revocation per Art. 7; data-residency assertions per Art. 44 - 50 international transfers; breach-notification timing tests per Art. 33 (72 hours); data-minimization assertions in fixtures per Art. 5(1)(c). The California analogue - CCPA/CPRA pattern...

  • 10 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 12, 2026
testingpythongoawsgcp

Works with

  • cli

Security analysis

A100/100

Pro scans all 13 files and shows the line behind each finding

Scanned October 12, 2026

npx -y skills add testland/qa --skill gdpr-test-patterns --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Gdpr Test Patterns?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Gdpr Test Patterns
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/testland-gdpr-test-patterns/badge)](https://www.skillsdirectory.com/skills/testland-gdpr-test-patterns)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: gdpr-test-patterns
description: "Reference catalog of GDPR-aligned test patterns - data-subject-rights workflows (Art. 15 access, Art. 16 rectification, Art. 17 erasure / \"right to be forgotten\", Art. 18 restriction, Art. 20 portability, Art. 21 objection); consent recording + revocation per Art. 7; data-residency assertions per Art. 44 - 50 international transfers; breach-notification timing tests per Art. 33 (72 hours); data-minimization assertions in fixtures per Art. 5(1)(c). The California analogue - CCPA/CPRA patterns by Cal. Civ. Code section, including Global Privacy Control (GPC) opt-out, right-to-know, deletion, right-to-correct, and sensitive-PI limits - lives in references/ccpa.md. Use when authoring GDPR- or CCPA/CPRA-readiness tests for any product processing EU or California personal data."
---

# gdpr-test-patterns

## Overview

Per [gdpr.eu][gdpr] (community-maintained reference; canonical text
at eur-lex.europa.eu Regulation 2016/679):

[gdpr]: https://gdpr.eu/

GDPR (General Data Protection Regulation, in force 2018-05-25)
applies to any processing of EU personal data regardless of the
processor's location. Failure to demonstrate compliance carries
fines up to €20M or 4% of global annual turnover (whichever higher).

This is a **reference skill** - defines the test-pattern
catalog by Article. Tests use the team's existing test framework;
this skill is the per-Article test recipe.

For products also processing California consumer data, the CCPA/CPRA
catalog by Cal. Civ. Code section - GPC opt-out (§1798.135),
right-to-know, deletion, right-to-correct, sensitive-PI limits - is in
[references/ccpa.md](references/ccpa.md).

## When to use

- Product processes EU personal data (regardless of processor location).
- Regulatory audit requires evidence of test coverage for
  data-subject rights.
- New feature touches PII handling (signup, profile, billing,
  analytics, third-party sharing).
- DPIA (Data Protection Impact Assessment) requires test evidence.

## How to use

1. Inventory every system that stores PII for a data subject (app DB, billing, analytics, CRM, support, backups) - this list drives the multi-system assertions.
2. Pick the Articles in scope for the feature under test (consent, access, erasure, portability, breach, residency, minimization).
3. Copy the matching per-Article pattern below and point it at your framework's client + models.
4. Generate fixture data with `synthetic-pii-generator` - never real customer PII.
5. Assert across ALL systems from step 1, not just the main store; add the deadline assertions (SAR 1 month per Art. 12(3), breach 72 hours per Art. 33) where the Article sets one.
6. Pin every timeline assertion to your written policy doc, not a hardcoded 30-day guess.
7. Wire the tests into CI so a schema change that reintroduces PII or skips a system fails the build.

## Test patterns by GDPR Article

### Art. 7 - Conditions for consent

```python
def test_consent_recorded_at_collection_time():
    response = client.post('/signup', json={
        'email': 'alice@example.com',
        'consent_marketing': True,
        'consent_timestamp': '2026-05-06T12:00:00Z',
    })
    user = User.objects.get(email='alice@example.com')
    consent = ConsentRecord.objects.get(user=user, scope='marketing')
    assert consent.granted is True
    assert consent.granted_at is not None
    assert consent.granted_via == 'signup-form'   # auditable evidence

def test_consent_revocable():
    revoke_consent(user, scope='marketing')
    consent = ConsentRecord.objects.get(user=user, scope='marketing')
    assert consent.granted is False
    assert consent.revoked_at is not None
    # Subsequent marketing emails must not be sent:
    assert not user.is_eligible_for(EmailType.MARKETING)
```

### Art. 15 - Right of access

```python
def test_subject_access_request_returns_all_personal_data():
    response = authenticated_client.post('/sar', json={'subject_email': 'alice@example.com'})
    assert response.status_code == 200
    data = response.json()
    # Must include data from EVERY system that holds PII for this subject:
    assert 'profile' in data
    assert 'billing' in data
    assert 'support_tickets' in data
    assert 'analytics' in data       # often forgotten; tests catch it
    assert 'third_party_sharing' in data
    # Response must arrive within 1 month per Art. 12(3):
    assert response.headers['X-Processing-Time'] < timedelta(days=30)
```

### Art. 17 - Right to erasure ("right to be forgotten")

```python
def test_erasure_removes_all_personal_data():
    erase_subject('alice@example.com')

    # Across ALL systems:
    assert User.objects.filter(email='alice@example.com').count() == 0
    assert BillingRecord.objects.filter(user_email='alice@example.com').count() == 0
    assert AnalyticsEvent.objects.filter(user_email='alice@example.com').count() == 0
    # Backup retention: erasure marker recorded; backup expires within retention window
    assert ErasureMarker.objects.filter(subject='alice@example.com').exists()
```

### Art. 20 - Right to data portability

```python
def test_data_portability_export_machine_readable():
    response = client.post('/data-export', json={'subject': 'alice@example.com'})
    export = response.json()
    # Must be in "structured, commonly used and machine-readable format"
    assert response.headers['Content-Type'] in ['application/json', 'text/csv', 'application/xml']
    # Format must be self-describing (keys not random IDs):
    assert 'profile' in export
    assert 'orders' in export
```

### Art. 33 - Breach notification (72-hour test)

```python
def test_breach_notification_workflow_within_72h():
    # Simulate a breach detection event
    breach = BreachIncident.create(detected_at=timezone.now())
    # Workflow MUST notify supervisory authority within 72 hours:
    deadline = breach.detected_at + timedelta(hours=72)
    notification = BreachNotification.objects.filter(incident=breach).first()
    assert notification is not None
    assert notification.sent_at <= deadline
    assert notification.recipient == 'supervisory.authority@dpa.example.eu'
```

### Art. 44 - 50 - International transfers (data residency)

```python
def test_eu_user_data_stored_in_eu_region():
    user = User.objects.create(email='alice@example.fr', region='EU')
    # Storage assertions vary by infra (AWS region, GCP region, etc.):
    assert user.storage_region in ['eu-west-1', 'eu-central-1', 'eu-north-1']
    # Cross-region replication MUST stay in EU:
    backups = Backup.objects.filter(user=user)
    for b in backups:
        assert b.region in EU_REGIONS
```

### Art. 5(1)(c) - Data minimization

```python
def test_signup_fixtures_contain_only_required_pii():
    fixture = load_fixture('user_signup.json')
    required = {'email', 'consent_terms', 'consent_marketing'}
    optional = {'phone', 'city', 'date_of_birth'}
    for k in fixture.keys():
        assert k in required | optional, f"Unrecognized field: {k}"
    # No SSN, no passport number, no genetic / biometric data unless explicitly justified:
    forbidden = {'ssn', 'passport', 'genetic_data', 'biometric_data'}
    for k in forbidden:
        assert k not in fixture, f"Forbidden PII type: {k}"
```

## Worked example

A support agent triggers an Art. 17 erasure for `alice@example.com`. The team already has `test_erasure_removes_all_personal_data` (above), which asserted the app `User` table was empty and passed. Running the multi-system version reveals `AnalyticsEvent` still holds rows keyed by `user_email`, because analytics writes were never wired into the erasure job. The test fails on `AnalyticsEvent.objects.filter(...).count() == 0`. The team adds analytics to the erasure fan-out, re-runs, and the test goes green with an `ErasureMarker` recorded so the nightly backup expiry honors the request within the retention window.

## Key compliance gaps tests should catch

| Gap | Detection |
|---|---|
| Marketing emails sent to revoked-consent users | Step Art. 7 + email-flow tests |
| SAR returns incomplete dataset (missing analytics/CRM) | Step Art. 15 multi-system assertion |
| Erasure leaves data in unindexed backup tables | Step Art. 17 multi-system assertion |
| EU user data quietly replicated to US region | Step Art. 44 - 50 region assertion |
| Breach detected but DPO not notified within 72h | Step Art. 33 timing test |

## Anti-patterns

| Anti-pattern | Why it fails | Fix |
|---|---|---|
| Test only main-app data store on SAR/erasure | Misses analytics, CRM, support, backups | Multi-system assertion (Steps Art. 15 + 17) |
| Hardcode 30-day SAR window assumption | GDPR allows extension to 3 months in complex cases | Test timeline against actual policy doc |
| Test consent recording without revocation | Half the workflow uncovered | Both grant + revoke tests (Step Art. 7) |
| Fixture data uses real customer PII | GDPR violation in tests themselves | Use `synthetic-pii-generator` |
| Skip data-minimization assertions | New PII types creep in via schema changes | Step Art. 5(1)(c) field-allowlist test |

## Limitations

- This skill is a test-pattern catalog, not legal advice. GDPR
  interpretation has nuance per supervisory authority (CNIL, ICO,
  DPA per country).
- Tests verify implementation; they don't replace a DPIA or legal
  review.
- Article numbers refer to GDPR text; consult eur-lex.europa.eu
  for canonical wording.
- Subject-access-request workflow varies per organization; test
  templates above are starting points.

## References

- [gdpr][gdpr] - community reference + Article navigation
- eur-lex.europa.eu/eli/reg/2016/679/oj - canonical GDPR text
- edpb.europa.eu - European Data Protection Board guidelines
- ico.org.uk/for-organisations/uk-gdpr-guidance-and-resources/ - UK ICO guide
- CCPA/CPRA California analogue (carries the oag.ca.gov + globalprivacycontrol.org citations):
  [references/ccpa.md](references/ccpa.md)
- `synthetic-pii-generator` - cross-plugin: safe test fixture generation
- `audit-trail-test-author` - companion: GDPR audit logs

Files in this skill

  • .tessl-plugin/plugin.json919 B
  • SKILL.md9.8 KB
  • evals/audit-finding-says-unsubscribe-is-unevidenced/criteria.json5 KB
  • evals/audit-finding-says-unsubscribe-is-unevidenced/task.md8.3 KB
  • evals/dashboard-flags-requests-the-dpo-says-were-fine/criteria.json7.5 KB
  • evals/dashboard-flags-requests-the-dpo-says-were-fine/task.md6.9 KB
  • evals/erasure-ticket-closed-but-the-rows-are-still-there/criteria.json5.1 KB
  • evals/erasure-ticket-closed-but-the-rows-are-still-there/task.md11.1 KB
  • evals/researcher-says-we-shared-her-data-anyway/criteria.json6 KB
  • evals/researcher-says-we-shared-her-data-anyway/task.md8.3 KB
  • evals/signup-payload-grew-twice-this-quarter/criteria.json7 KB
  • evals/signup-payload-grew-twice-this-quarter/task.md7.8 KB
  • references/ccpa.md7.5 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.