"""Masking display filter for KV values (WARDEN-WP-0026 T03). Defense-in-depth, **not a boundary**: any place warden would otherwise render a secret value for a human (a status/listing view) shows a *fingerprint* instead — presence, length, and a short non-reversible hash. Two operators can compare fingerprints to confirm they hold the same value (e.g. that a rotation landed the expected token) without either seeing it, and a fingerprint in a transcript discloses nothing. Limitation (documented, by design): raw `bao kv get ` bypasses this entirely — warden only masks *warden-mediated* output. The real boundary is OpenBao policy plus the T01 capabilities-safe verify and T02 no-stdout transports. """ from __future__ import annotations import hashlib from dataclasses import dataclass # Short, non-reversible hash: first 8 hex chars of SHA-256. Not a value, and a # collision is irrelevant for the "same/different?" comparison this supports. _HASH_PREFIX_LEN = 8 @dataclass(frozen=True) class Fingerprint: present: bool length: int sha256_prefix: str # "" when the value is empty/absent def render(self) -> str: if not self.present: return "‹absent›" return f"‹hidden len={self.length} sha256:{self.sha256_prefix}›" def fingerprint(value: str | None) -> Fingerprint: """Compute a non-reversible fingerprint of a value. Never returns the value.""" if not value: return Fingerprint(present=False, length=0, sha256_prefix="") digest = hashlib.sha256(value.encode("utf-8")).hexdigest()[:_HASH_PREFIX_LEN] return Fingerprint(present=True, length=len(value), sha256_prefix=digest) def mask_value(value: str | None) -> str: """Render a value as its masked fingerprint string. Never emits the value.""" return fingerprint(value).render()