# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/what-structural-signals-indicate-that-taint-from-a-prompt-injection-source-has-silently-laundered-through-a-tool-output-re-serialization-boundary.md
# Remnant Warrant:    https://corpusfetch.com/c/what-structural-signals-indicate-that-taint-from-a-prompt-injection-source-has-silently-laundered-through-a-tool-output-re-serialization-boundary.warrant.json
# Markdown SHA-256:   7a4e8f2e82f4eff43b2fafc8b9b420ba2de073909e95a661e5ff2c82eb9b2f37
# Code AST SHA-256:   66e46746abff188c168c25635200c916ecbcc134effd4a461c2f43b38ba042c8
# Verified Classes:   TaintLaunderingError, TaintLabel
# Defensive Guards:   2 fail-closed invariants (zero external deps)

import hashlib
from dataclasses import dataclass


class TaintLaunderingError(RuntimeError):
    """Raised when a taint label's referenced bytes no longer match its issued content hash."""


@dataclass(frozen=True)
class TaintLabel:
    content_sha256: str      # hash of the exact bytes the label was issued for
    origin: str              # e.g. "external_untrusted"
    span_start: int
    span_end: int


def reanchor_or_invalidate(
    label: TaintLabel,
    post_serialization_buffer: bytes,
    serializer_provides_mapping: bool,
) -> TaintLabel:
    """Cross a re-serialization boundary with a taint label.

    Re-anchors if the serializer gives us a span mapping; otherwise fails closed
    by re-issuing the label against the whole buffer as unknown provenance.
    """
    if not serializer_provides_mapping:
        # Fail-closed: over-taint the entire re-serialized output.
        return TaintLabel(
            content_sha256=hashlib.sha256(post_serialization_buffer).hexdigest(),
            origin="unknown_provenance",
            span_start=0,
            span_end=len(post_serialization_buffer),
        )

    # Mapping path: verify the re-anchored span still hashes to the issued content.
    raise TaintLaunderingError(
        "serializer mapping path not implemented; refusing to carry span label "
        f"for origin={label.origin!r} across byte-changing transform without "
        "content-hash verification"
    )


def consume_tainted_span(label: TaintLabel, current_bytes: bytes) -> None:
    """Enforcement point: verify label-to-bytes binding before trusting content."""
    actual = hashlib.sha256(current_bytes).hexdigest()
    if actual != label.content_sha256:
        raise TaintLaunderingError(
            f"label bound to {label.content_sha256[:12]} but span now hashes to "
            f"{actual[:12]}; taint laundered through re-serialization boundary"
        )
