aeat.adapters.inbound.pdf._scrub module¶
Deterministic PII scrubbing for AEAT filing PDF fixtures.
Real filings carry the operator’s NIF, real amounts, their name, an AEAT-assigned CSV, and occasionally their IBAN / address. Committing any of that to a test corpus is a PII leak.
This module deterministically rewrites a source PDF so the output carries synthetic but structurally faithful replacements – matching the important digit counts, separators, and token shapes enough for extractor tests to exercise their primitive stack without leaking personal data. It is fixture hygiene for contributor-local corpus preparation, not a production anonymisation service.
Scrub rules:
NIF (8 digits + 1 letter or 1 letter + 7 digits + 1 letter): replaced with
00000000T(individual) orB00000000(empresa).Amounts (Spanish
1.234,56or plain1234.56): replaced with a seeded-RNG synthetic of matching digit count, preserving formatting.Names (capitalised 2+ word strings AEAT conventionally prints): replaced with
DEMO AUTÓNOMO/DEMO EMPRESA.CSV (16-char upper-alphanum): replaced with a hash-derived synthetic.
IBAN: replaced with
ESXX XXXX XXXX XX XXXXXXXXXX.Dates: preserved (GDPR Art. 4 does not treat calendar dates as PII).
Presentation IDs (10+ char upper-alphanum): replaced with seeded synthetic.
Each scrubbed file pairs with a ScrubSidecar JSON sidecar recording
the original and scrubbed digests, scrub-rule version, touched field kinds, and
consent window. The sidecar is the provenance record reviewers inspect when a
private L2 fixture is proposed.
The library is never invoked at runtime from production code — only
from contributor-local workflows (just scrub-from-drive) and
src/aeat/adapters/inbound/pdf/test_scrub.py tests.
- exception ScrubError(message=None, *, context=None, suggestion=None, translated_message=None)[source]¶
Bases:
PdfModeloImportErrorRaised when scrubbing cannot produce a safe output.
- Parameters:
- Return type:
None
- code: ClassVar[ErrorCode]¶
- class ScrubSidecar(**data)[source]¶
Bases:
BaseModelProvenance + consent record for one scrubbed L2 fixture file.
The hashes identify the original and scrubbed bytes without storing the cleartext source.
scrub_versionmakes future rule changes auditable, andconsent_revocable_untilrecords whether the contributor can later request removal of the fixture.- Parameters:
- original_sha256: str¶
- scrubbed_sha256: str¶
- scrub_version: str¶
- scrubbed_at: datetime¶
- fields_touched: tuple[str, ...]¶
- consent_revocable_until: datetime | None¶
- fixture_tier: Literal['l2']¶
- original_filename: str¶
- scrub_text(text, *, filename)[source]¶
Apply the scrub-rule set to a text stream; return
(scrubbed, fields_touched).- Parameters:
- Return type:
- Returns:
A tuple
(scrubbed_text, fields_touched)wherefields_touchedenumerates the rule kinds that matched at least once.
- compute_sidecar(*, original_path, scrubbed_path, fields_touched, consent_revocable_until=None)[source]¶
Build a
ScrubSidecardescribing one scrub run.Both paths are hashed through the shared PDF provenance helper so sidecar generation follows the same redacted-error discipline as runtime parsers.