aeat.adapters.inbound.sanitizer._records module

Strict pydantic v2 records for the adapters.inbound.sanitizer subpackage.

Every record in this module is frozen, extra=”forbid”, strict=True. Cleartext PII lives exclusively in pydantic.SecretStr fields so accidental repr / log inclusion does not leak the source value. Synthetic replacements are validated against the same checksum / shape rules the project applies to live values, so a sanitised fixture round-trips through production parsers unchanged.

SecretStr is a display/logging guard, not a storage policy. Operator mapping files that contain real values must remain outside git; committed audit records should contain only synthetic values, hashes, surface names, and counts.

class NifReplacement(**data)[source]

Bases: _ReplacementBase

Replacement entry whose synthetic value must be a valid NIF/NIE.

Parameters:
  • real (SecretStr)

  • synthetic (Annotated[str, StringConstraints(strip_whitespace=False, to_upper=None, to_lower=None, strict=None, min_length=1, max_length=None, pattern=None, ascii_only=None)])

  • surface_label (Annotated[str, StringConstraints(strip_whitespace=False, to_upper=None, to_lower=None, strict=None, min_length=1, max_length=None, pattern=None, ascii_only=None)])

class NameReplacement(**data)[source]

Bases: _ReplacementBase

Replacement entry for a taxpayer or representative name.

The synthetic value is constrained to a non-blank uppercased string so it round-trips through parsers that expect AEAT’s APELLIDO APELLIDO NOMBRE shape.

Parameters:
  • real (SecretStr)

  • synthetic (Annotated[str, StringConstraints(strip_whitespace=False, to_upper=None, to_lower=None, strict=None, min_length=1, max_length=None, pattern=None, ascii_only=None)])

  • surface_label (Annotated[str, StringConstraints(strip_whitespace=False, to_upper=None, to_lower=None, strict=None, min_length=1, max_length=None, pattern=None, ascii_only=None)])

class AddressReplacement(**data)[source]

Bases: _ReplacementBase

Replacement entry for a postal address.

Parameters:
  • real (SecretStr)

  • synthetic (Annotated[str, StringConstraints(strip_whitespace=False, to_upper=None, to_lower=None, strict=None, min_length=1, max_length=None, pattern=None, ascii_only=None)])

  • surface_label (Annotated[str, StringConstraints(strip_whitespace=False, to_upper=None, to_lower=None, strict=None, min_length=1, max_length=None, pattern=None, ascii_only=None)])

class ExpedienteReplacement(**data)[source]

Bases: _ReplacementBase

Replacement entry for an AEAT expediente identifier.

AEAT expedientes are typically opaque 13-19 character alphanumeric strings; the synthetic value preserves the same length window so width-sensitive layout cues survive.

Parameters:
  • real (SecretStr)

  • synthetic (Annotated[str, StringConstraints(strip_whitespace=False, to_upper=None, to_lower=None, strict=None, min_length=1, max_length=None, pattern=None, ascii_only=None)])

  • surface_label (Annotated[str, StringConstraints(strip_whitespace=False, to_upper=None, to_lower=None, strict=None, min_length=1, max_length=None, pattern=None, ascii_only=None)])

class CsvReplacement(**data)[source]

Bases: _ReplacementBase

Replacement entry for an AEAT Código Seguro de Verificación.

AEAT CSVs are 16-character base32-like strings. The synthetic value preserves the length so downstream parsers that match on length-bounded patterns continue to match.

Parameters:
  • real (SecretStr)

  • synthetic (Annotated[str, StringConstraints(strip_whitespace=False, to_upper=None, to_lower=None, strict=None, min_length=1, max_length=None, pattern=None, ascii_only=None)])

  • surface_label (Annotated[str, StringConstraints(strip_whitespace=False, to_upper=None, to_lower=None, strict=None, min_length=1, max_length=None, pattern=None, ascii_only=None)])

class NrcReplacement(**data)[source]

Bases: _ReplacementBase

Replacement entry for an AEAT Número de Referencia Completo.

Parameters:
  • real (SecretStr)

  • synthetic (Annotated[str, StringConstraints(strip_whitespace=False, to_upper=None, to_lower=None, strict=None, min_length=1, max_length=None, pattern=None, ascii_only=None)])

  • surface_label (Annotated[str, StringConstraints(strip_whitespace=False, to_upper=None, to_lower=None, strict=None, min_length=1, max_length=None, pattern=None, ascii_only=None)])

class IbanReplacement(**data)[source]

Bases: _ReplacementBase

Replacement entry for an IBAN (ES- prefixed).

Parameters:
  • real (SecretStr)

  • synthetic (Annotated[str, StringConstraints(strip_whitespace=False, to_upper=None, to_lower=None, strict=None, min_length=1, max_length=None, pattern=None, ascii_only=None)])

  • surface_label (Annotated[str, StringConstraints(strip_whitespace=False, to_upper=None, to_lower=None, strict=None, min_length=1, max_length=None, pattern=None, ascii_only=None)])

class ImporteReplacement(**data)[source]

Bases: _ReplacementBase

Replacement entry for a monetary amount in AEAT comma-decimal shape.

Parameters:
  • real (SecretStr)

  • synthetic (Annotated[str, StringConstraints(strip_whitespace=False, to_upper=None, to_lower=None, strict=None, min_length=1, max_length=None, pattern=None, ascii_only=None)])

  • surface_label (Annotated[str, StringConstraints(strip_whitespace=False, to_upper=None, to_lower=None, strict=None, min_length=1, max_length=None, pattern=None, ascii_only=None)])

class ArbitraryReplacement(**data)[source]

Bases: _ReplacementBase

Replacement entry with no shape constraint.

Use sparingly — every arbitrary entry bypasses checksum and layout validation, so a poorly chosen synthetic can break a deep-extractor regression. Reserve for ad-hoc strings such as capture-time fingerprints or one-off identifiers.

Parameters:
  • real (SecretStr)

  • synthetic (Annotated[str, StringConstraints(strip_whitespace=False, to_upper=None, to_lower=None, strict=None, min_length=1, max_length=None, pattern=None, ascii_only=None)])

  • surface_label (Annotated[str, StringConstraints(strip_whitespace=False, to_upper=None, to_lower=None, strict=None, min_length=1, max_length=None, pattern=None, ascii_only=None)])

class TokenMap(**data)[source]

Bases: BaseModel

Declarative input mapping for sanitize_pdf().

Each tuple holds zero-or-more replacement records of the matching category. Empty tuples are permitted; a TokenMap with every category empty is structurally valid but produces a no-replacement sanitisation (the metadata + dynamic-surface scrub still runs). The real values inside replacement entries are the operator-supplied authority for the rewrite; the sanitizer does not run probabilistic PII discovery.

Variables:
  • nif – Replacements for NIF / NIE values.

  • name – Replacements for taxpayer / representative names.

  • address – Replacements for postal addresses.

  • expediente – Replacements for AEAT expediente identifiers.

  • csv – Replacements for Código Seguro de Verificación strings.

  • nrc – Replacements for Número de Referencia Completo strings.

  • iban – Replacements for ES-prefixed IBANs.

  • importe – Replacements for AEAT comma-decimal monetary amounts.

  • arbitrary – Replacements without shape constraints.

Parameters:
nif: tuple[NifReplacement, ...]
name: tuple[NameReplacement, ...]
address: tuple[AddressReplacement, ...]
expediente: tuple[ExpedienteReplacement, ...]
csv: tuple[CsvReplacement, ...]
nrc: tuple[NrcReplacement, ...]
iban: tuple[IbanReplacement, ...]
importe: tuple[ImporteReplacement, ...]
arbitrary: tuple[ArbitraryReplacement, ...]
is_empty()[source]

Returns True when no replacement of any category is set.

Return type:

bool

class Replacement(**data)[source]

Bases: BaseModel

One token-replace edit recorded in SanitizationResult.replacements_applied.

Variables:
  • surface – Closed-set surface name (DocInfo key, content- stream, structtree text, …).

  • surface_index – Tuple-encoded location within the surface. For content streams, (page_index, instruction_index).

  • real_sha256 – SHA-256 of the cleartext PII the entry matched against. Never the cleartext itself — committing the cleartext into replacements_applied would defeat the entire sanitiser. Treat this hash as fixture-review metadata, not as a production de-identification key.

  • synthetic – The synthetic replacement text that landed in the output. Safe to log.

  • encoding – Encoding form in which the operand was rewritten (literal string, hex string, etc.).

Parameters:
  • surface (Literal['docinfo_title', 'docinfo_subject', 'docinfo_author', 'docinfo_keywords', 'docinfo_creator', 'docinfo_producer', 'docinfo_creation_date', 'docinfo_mod_date', 'docinfo_other', 'xmp_packet', 'xmp_dc_title', 'xmp_dc_description', 'xmp_dc_creator', 'xmp_pdf_keywords', 'xmp_pdfa_claim', 'content_stream', 'annotation_contents', 'annotation_drop', 'structtree_actualtext', 'structtree_alt', 'structtree_dropped', 'attachments', 'javascript', 'open_action', 'additional_actions', 'optional_content_groups', 'acroform_field_value', 'acroform_dropped', 'page_thumbnail', 'outlines', 'page_labels', 'incremental_update_history'])

  • surface_index (tuple[int, ...])

  • real_sha256 (str)

  • synthetic (Annotated[str, StringConstraints(strip_whitespace=False, to_upper=None, to_lower=None, strict=None, min_length=1, max_length=None, pattern=None, ascii_only=None)])

  • encoding (Literal['literal', 'hex', 'actualtext', 'docinfo_string', 'xmp_string'])

surface: _SurfaceName
surface_index: tuple[int, ...]
real_sha256: str
synthetic: _NonEmptyStr
encoding: _EncodingName
class ScrubbedSurface(**data)[source]

Bases: BaseModel

Counter for one PII surface that was wiped (vs. token-replaced).

Variables:
  • surface – Closed-set surface name.

  • count – Number of items removed (0 when the surface was absent in the source — recorded so callers can audit the sanitiser’s coverage).

Parameters:
  • surface (Literal['docinfo_title', 'docinfo_subject', 'docinfo_author', 'docinfo_keywords', 'docinfo_creator', 'docinfo_producer', 'docinfo_creation_date', 'docinfo_mod_date', 'docinfo_other', 'xmp_packet', 'xmp_dc_title', 'xmp_dc_description', 'xmp_dc_creator', 'xmp_pdf_keywords', 'xmp_pdfa_claim', 'content_stream', 'annotation_contents', 'annotation_drop', 'structtree_actualtext', 'structtree_alt', 'structtree_dropped', 'attachments', 'javascript', 'open_action', 'additional_actions', 'optional_content_groups', 'acroform_field_value', 'acroform_dropped', 'page_thumbnail', 'outlines', 'page_labels', 'incremental_update_history'])

  • count (int)

surface: _SurfaceName
count: int
class SanitizationWarning(**data)[source]

Bases: BaseModel

One non-fatal warning emitted during sanitisation.

Variables:
  • code – Closed-set warning identifier.

  • detail – Free-form detail string. Must NOT contain cleartext PII; the caller is responsible for constructing a PII-safe detail.

Parameters:
  • code (Literal['unknown_surface_present', 'encoding_inferred', 'structtree_dropped_lossy', 'pdfa_claim_invalidated', 'digital_signature_present_refusing', 'incremental_update_history_consolidated', 'source_sha256_already_in_known_sanitized_set', 'missing_replacement_target'])

  • detail (Annotated[str, StringConstraints(strip_whitespace=False, to_upper=None, to_lower=None, strict=None, min_length=1, max_length=None, pattern=None, ascii_only=None)])

code: _WarningCode
detail: _NonEmptyStr
class DeterminismFlags(**data)[source]

Bases: BaseModel

Captured save-flag set used to produce byte-stable output.

Variables:
  • deterministic_id – Whether deterministic_id was passed (true in normal operation).

  • static_id – Debug-only static_id flag (false in normal operation).

  • object_stream_mode – One of "preserve", "generate", or "disable".

  • linearize – Whether linearisation was requested.

  • recompress_flate – Whether flate streams were recompressed.

  • compress_streams – Whether streams were compressed.

Parameters:
  • deterministic_id (bool)

  • static_id (bool)

  • object_stream_mode (Literal['preserve', 'generate', 'disable'])

  • linearize (bool)

  • recompress_flate (bool)

  • compress_streams (bool)

deterministic_id: bool
static_id: bool
object_stream_mode: Literal['preserve', 'generate', 'disable']
linearize: bool
recompress_flate: bool
compress_streams: bool
class SanitizationResult(**data)[source]

Bases: BaseModel

Outcome of a successful sanitize_pdf() call.

The output_bytes field carries the sanitised PDF; the CLI shell writes it to disk. The library function itself never touches the filesystem. The result is an audit record for fixture preparation, not an application persistence model.

Variables:
  • output_bytes – Byte-for-byte sanitised PDF.

  • source_sha256 – SHA-256 of the input bytes.

  • output_sha256 – SHA-256 of output_bytes.

  • source_size_bytes – Size of the input.

  • output_size_bytes – Size of output_bytes.

  • sanitizer_version – Version string of the sanitiser at the time of the run.

  • determinism_flags – Captured save-flag set.

  • replacements_applied – One row per token-replace edit.

  • surfaces_scrubbed – One row per PII surface that was wiped.

  • warnings – Non-fatal warnings.

Parameters:
output_bytes: bytes
source_sha256: str
output_sha256: str
source_size_bytes: int
output_size_bytes: int
sanitizer_version: _NonEmptyStr
determinism_flags: DeterminismFlags
replacements_applied: tuple[Replacement, ...]
surfaces_scrubbed: tuple[ScrubbedSurface, ...]
warnings: tuple[SanitizationWarning, ...]