#!/usr/bin/env python3
"""Anchored builder: provision-rig-r2.sh (FROZEN) -> provision-rig-r3.sh.

doyle WD47ADZV tightened the seed scope: a temporary export in the parent shell
exposes the seed to every child launched during that interval, including the
timeout/registration helpers. So r3 does not export it at all. The seed is passed
as a COMMAND-PREFIX ASSIGNMENT on the signing command itself, which places it in
the environment of exactly that command (and the timeout that bounds it, the
floor imposed by xtask reading its seed from the environment), and nowhere else.

The retained shell variable is never exported and is unset immediately after.
The pre-apply absence assertion is KEPT and RELABELLED: doyle is right that it
does not prove earlier containment, only that nothing from the apply onward can
inherit it.
"""
import hashlib
import pathlib
import sys

HERE = pathlib.Path(__file__).resolve().parent
SRC = HERE / "provision-rig-r2.sh"
DST = HERE / "provision-rig-r3.sh"
SRC_SHA = "1a959d1730f733e8bec5bf6be12820bcc841d39ef743c79e8318a48b698a61a3"

raw = SRC.read_bytes()
got = hashlib.sha256(raw).hexdigest()
if got != SRC_SHA:
    sys.exit(f"SOURCE_DRIFT: {SRC.name} is {got}, pin says {SRC_SHA}")
if DST.exists():
    sys.exit(f"DESTINATION_EXISTS: {DST.name} is some attempt's evidence; it is not overwritten")
text = raw.decode("utf-8")

EDITS = []


def edit(name, old, new):
    EDITS.append((name, old, new))


# ---- 1. the header's account of what happens to the seed --------------------
edit(
    "header-seed-account",
    """#   - the seed is read ONCE at preflight into a shell variable and IMMEDIATELY unset from the
#     environment, so no later child — apply, daemon, capture — can inherit it (doyle OCTAXWYQ);
#   - it is exported for the SIGNING CALL ONLY, and unset again on the next line;
#   - it is NEVER an argument: an argument is visible in the process table to every other
#     process on the box. It is never printed, never written to evidence, never archived, and
#     the absence of the variable is ASSERTED before the apply rather than assumed.""",
    """#   - the seed is read ONCE at preflight into a NON-EXPORTED shell variable and IMMEDIATELY
#     unset from the environment, so no child inherits it by default (doyle OCTAXWYQ);
#   - IT IS NEVER EXPORTED, not even briefly. doyle WD47ADZV: a temporary export in this shell
#     would hand the seed to every child launched during that interval, the timeout and
#     registration helpers included. It is passed as a COMMAND-PREFIX ASSIGNMENT on the signing
#     command, which places it in the environment of that command alone;
#   - the FLOOR, stated because it cannot be lowered: xtask reads its seed FROM THE ENVIRONMENT,
#     so the signing process must have it, and the timeout that bounds that process is its
#     parent and carries it for the same interval. Two processes, both of them the signing call
#     itself. No other command is launched in that interval;
#   - it is NEVER an argument: an argument is readable from the process table by every other
#     process on the box. It is never printed, never written to evidence, never archived;
#   - the retained variable is unset immediately after the signing call, and the ABSENCE of both
#     is asserted before the apply. That assertion is a floor, not a proof of earlier
#     containment (doyle WD47ADZV): it shows nothing from the apply onward can inherit the seed,
#     and says nothing about the interval above it. The containment above it is structural — no
#     export ever happened — not measured here.""",
)

# ---- 2. preflight: the say() line that claimed a re-export -------------------
edit(
    "preflight-seed-say",
    """say "SIGNING_SEED present in the environment, 64 hex characters, VALUE NOT REPORTED. It has been unset from this script's environment and is re-exported for the staging subprocess alone.\"""",
    """say "SIGNING_SEED present in the environment, 64 hex characters, VALUE NOT REPORTED. It is now unset from this script's environment and held in a NON-EXPORTED variable; it is never exported, and reaches only the signing command's own environment.\"""",
)

# ---- 3. the signing call: no export, no env(1), a prefix assignment ---------
edit(
    "staging-call",
    """STAGE_DEADLINE=$(( $(date +%s) + STAGE_BUDGET_S ))
export SPT_DEBUG_RELEASE_SEED="$SIGN_SEED"
bounded debug_rollout "$STAGE_DEADLINE" "$EVID/stage.out" "$EVID/stage.err" -- \\
  env SPT_HOME="$H" "$XTASK_BIN" debug-rollout \\
      --stage-dir "$H/releases" \\
      --state "$RIG_ROOT/debug-rollout-state.json" \\
      --version "$SET_VERSION" \\
      --key-id "$TRUST_KEY_ID" \\
      --artifact "$HOST_TRIPLE=$RIG_EXE"
src=$?
unset SPT_DEBUG_RELEASE_SEED
unset SIGN_SEED""",
    """# THE SIGNING CALL IS NOT ROUTED THROUGH bounded(). bounded() is a shell function, and a
# variable assignment prefixed to a function call lives in THIS shell's environment for the
# duration of the call — which is the temporary export doyle WD47ADZV ruled out. The bound is
# therefore taken by hand, in bounded()'s own shape and arithmetic, so that the assignment can
# be prefixed to the SIMPLE COMMAND and reach nothing else.
STAGE_DEADLINE=$(( $(date +%s) + STAGE_BUDGET_S ))
stage_left=$(( STAGE_DEADLINE - $(date +%s) - KILL_GRACE_S ))
if [ "$stage_left" -lt 1 ]; then
  say "BOUND_NOT_STARTED debug_rollout — nothing remains after the ${KILL_GRACE_S}s escalation reserve"
  fail "the staging bound had no room left to start in. Nothing was signed and nothing was staged."
fi
say "BOUND debug_rollout ${stage_left}s"
SPT_DEBUG_RELEASE_SEED="$SIGN_SEED" SPT_HOME="$H" \\
  timeout -k "$KILL_GRACE_S" "$stage_left" \\
    "$XTASK_BIN" debug-rollout \\
      --stage-dir "$H/releases" \\
      --state "$RIG_ROOT/debug-rollout-state.json" \\
      --version "$SET_VERSION" \\
      --key-id "$TRUST_KEY_ID" \\
      --artifact "$HOST_TRIPLE=$RIG_EXE" \\
    > "$EVID/stage.out" 2> "$EVID/stage.err"
src=$?
unset SIGN_SEED
[ "$src" -eq 124 ] || [ "$src" -eq 137 ] && say "BOUND_EXPIRED debug_rollout (killer rc=$src) — the WAIT ended; what stopped is a separate question this script does not answer by assumption\"""",
)

# ---- 4. the pre-apply assertion, relabelled as the floor it is --------------
edit(
    "apply-seed-assertion",
    """# doyle OCTAXWYQ: the seed reaches the SIGNING subprocess and nothing else. Measured here,
# not claimed: if it is still in the environment, the apply does not run.
[ -z "${SPT_DEBUG_RELEASE_SEED:-}" ] || fail "the signing seed is still in the environment at the apply. It must not be inherited by apply, daemon or capture processes."
[ -z "${SIGN_SEED:-}" ] || fail "the signing seed is still held in a shell variable at the apply"
say "SEED_SCOPE verified: SPT_DEBUG_RELEASE_SEED is absent from this script's environment before the apply, so no process from here on can inherit it\"""",
    """# doyle OCTAXWYQ / WD47ADZV: the seed reaches the signing command's environment and nothing
# else. This pair of checks is a FLOOR, not a proof of earlier containment — it establishes that
# nothing from the apply onward can inherit the seed, and says nothing about the interval above
# it. That interval is contained STRUCTURALLY, by never exporting at all, which is a property of
# the code above rather than a reading taken here.
[ -z "${SPT_DEBUG_RELEASE_SEED:-}" ] || fail "the signing seed is in the environment at the apply. It must not be inherited by apply, daemon or capture processes."
[ -z "${SIGN_SEED:-}" ] || fail "the signing seed is still held in a shell variable at the apply"
say "SEED_SCOPE_FLOOR verified: neither the environment variable nor the retained variable exists before the apply, so no process from here on can inherit the seed. This is a floor: it does not measure the interval above it, which is contained by never exporting rather than by this reading.\"""",
)

for name, old, new in EDITS:
    n = text.count(old)
    if n != 1:
        sys.exit(f"ANCHOR_{'ABSENT' if n == 0 else 'AMBIGUOUS'}: {name} matched {n} times")
    text = text.replace(old, new, 1)

DST.write_text(text, encoding="utf-8", newline="\n")
print(f"BUILT {DST.name} sha256={hashlib.sha256(DST.read_bytes()).hexdigest()}")
print(f"anchors replaced: {len(EDITS)}")
