# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/how-does-an-instance-detect-a-replayed-mcp-tool-schema-under-a-valid-signature-the-attestation-freshness-boundary-in-signed-tool-manifests.md
# Remnant Warrant:    https://corpusfetch.com/c/how-does-an-instance-detect-a-replayed-mcp-tool-schema-under-a-valid-signature-the-attestation-freshness-boundary-in-signed-tool-manifests.warrant.json
# Markdown SHA-256:   43775258d552c6547280b73a23963d0caed3a3ccdc89ce44ac057b5c363ef858
# Code AST SHA-256:   74613e41411742643b7618ff2356f36eb1cc0485f7efda8a73ec723e29ce8c5e
# Verified Classes:   StaleAttestationError, SignedManifest
# Defensive Guards:   4 fail-closed invariants (zero external deps)

import hashlib
import time
from dataclasses import dataclass


class StaleAttestationError(RuntimeError):
    """Raised when a signed manifest is authentic but not fresh, or not bound to the live endpoint."""


@dataclass(frozen=True)
class SignedManifest:
    server_id: str
    tool_name: str
    input_schema: str
    issued_at: float
    signature: bytes
    manifest_hash: str


def verify_and_admit(
    manifest: SignedManifest,
    cached_hash: str | None,
    endpoint_nonce_ok: bool,
    now: float,
    max_staleness_s: float = 300.0,
    max_skew_s: float = 30.0,
) -> str:
    # Signature itself is assumed verified upstream; this gate enforces freshness + binding.
    if manifest.issued_at > now + max_skew_s:
        raise StaleAttestationError(
            f"manifest issued_at {manifest.issued_at} is in the future beyond skew"
        )
    age = now - manifest.issued_at
    if age > max_staleness_s:
        raise StaleAttestationError(
            f"manifest for {manifest.server_id}/{manifest.tool_name} is {age:.0f}s stale "
            f"(max {max_staleness_s}s); refusing to execute under cached schema"
        )
    if not endpoint_nonce_ok:
        raise StaleAttestationError(
            f"live endpoint failed nonce challenge for server_id={manifest.server_id}; "
            "signature valid but not bound to this connection"
        )
    if cached_hash is not None and cached_hash != manifest.manifest_hash:
        raise StaleAttestationError(
            f"manifest hash rotated for {manifest.tool_name}; re-attestation required"
        )
    return manifest.manifest_hash
