#!/usr/bin/env bash
# tests/dc-snap-proxy/run-tests.sh -- guard for scripts/dc-snap-proxy.sh
# (D-135/D-107 RULING 2, 2026-07-31: the per-DC snap FORWARD PROXY, squid,
# CONNECT-only, destination-restricted).
#
# TWO HALVES, DELIBERATELY.
#   STATIC (T1-T22): the identity values a silent edit would break -- both sites'
#     utility .4, ruled edge gateways and MEASURED client CIDRs, the port that
#     is NOT MAAS's 3128, stable-identity keying, service-owned net artifacts,
#     the consumption keys, the store/CDN allowlist, and arg/site validation.
#   BEHAVIORAL (T23-T49): `check` and `node` are DRIVEN, against a mktemp
#     SYSROOT and fake curl/ss/systemctl/virsh/ip/dpkg on PATH. A grep cannot
#     tell a gate that fails from one that merely cannot fail, and this script's
#     whole point is being a GA-R6 gate: every FAIL path and every REFUSE path
#     below has its own failing fixture.
#
# WHAT THE GREEN BELOW DOES *NOT* PROVE (say it plainly, GA-R1): no proxy has
# ever been installed, so no snap has been installed through one. This is a
# FIXTURE green. The real gates are `check <site>` on the rack and `node <site>`
# from a client, at apply time.
#
# Exit: 0 all pass | 1 any case failed. ASCII + LF.
set -uo pipefail
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SCRIPT="$(cd "$HERE/../.." && pwd)/scripts/dc-snap-proxy.sh"
PASS=0; FAIL=0
ok(){ echo "  PASS  $1"; PASS=$((PASS+1)); }
no(){ echo "  FAIL  $1"; FAIL=$((FAIL+1)); }

[ -f "$SCRIPT" ] && ok "T1 script present" || { no "T1 script present"; echo; echo "dc-snap-proxy: $PASS passed, $FAIL failed"; exit 1; }
bash -n "$SCRIPT" 2>/dev/null && ok "T2 bash -n clean" || no "T2 bash -n clean"

# ===========================================================================
# STATIC -- identity values and structural invariants.
# ===========================================================================

# T3-T5: dc0 row. The utility .4 is the address the deploy will be pointed at;
# the edge gw is the proxy's only upstream egress; CLIENT_CIDR is the MEASURED
# source the charm CONTAINERS use toward .4 (metal-admin, NOT the metal-internal
# address `juju status` prints -- that misreading would deny every client).
D0="$(awk '/^  dc0\)/{f=1} f{print} f&&/^    ;;/{exit}' "$SCRIPT")"
grep -q 'LISTEN_CIDR="10.12.8.4/22"' <<<"$D0" \
  && grep -q 'UTIL_NET="vr1-dc0-metal-admin"' <<<"$D0" \
  && ok "T3 dc0 LISTEN 10.12.8.4/22 on metal-admin (D-134 utility .4)" \
  || no "T3 dc0 LISTEN 10.12.8.4/22 on metal-admin (D-134 utility .4)"
grep -q 'EDGE_GW="10.12.4.1"' <<<"$D0" \
  && ok "T4 dc0 edge gw 10.12.4.1" || no "T4 dc0 edge gw 10.12.4.1"
grep -q 'CLIENT_CIDR="10.12.8.0/22"' <<<"$D0" \
  && ok "T5 dc0 client ACL is metal-admin 10.12.8.0/22 (measured container source)" \
  || no "T5 dc0 client ACL is metal-admin 10.12.8.0/22 (measured container source)"

# T6-T8: dc1 row -- values from lib-net.sh's own vr1-dc1 arm, never mirrored
# from dc0 by symmetry (the lib-hosts.sh scar).
D1="$(awk '/^  dc1\)/{f=1} f{print} f&&/^    ;;/{exit}' "$SCRIPT")"
grep -q 'LISTEN_CIDR="10.12.68.4/22"' <<<"$D1" \
  && grep -q 'UTIL_NET="vr1-dc1-metal-admin"' <<<"$D1" \
  && ok "T6 dc1 LISTEN 10.12.68.4/22 on metal-admin (utility .4)" \
  || no "T6 dc1 LISTEN 10.12.68.4/22 on metal-admin (utility .4)"
grep -q 'EDGE_GW="10.12.64.1"' <<<"$D1" \
  && ok "T7 dc1 edge gw 10.12.64.1" || no "T7 dc1 edge gw 10.12.64.1"
grep -q 'CLIENT_CIDR="10.12.68.0/22"' <<<"$D1" \
  && ok "T8 dc1 client ACL is metal-admin 10.12.68.0/22" \
  || no "T8 dc1 client ACL is metal-admin 10.12.68.0/22"

# T9: the port. 3128 AND 8000 are MAAS's squid, WILDCARD-bound on BOTH racks
# (measured); 3142 is dc1's apt-cacher-ng; 80 is dc0's mirror nginx. A silent
# move to 3128 would produce a squid that cannot bind, on both DCs.
grep -q 'PROXY_PORT="3129"' "$SCRIPT" \
  && ! grep -qE 'PROXY_PORT="(3128|8000|3142|80)"' "$SCRIPT" \
  && ok "T9 proxy port pinned 3129 (3128/8000 are MAAS's squid, 3142 is acng)" \
  || no "T9 proxy port pinned 3129 (3128/8000 are MAAS's squid, 3142 is acng)"

# T10: stable-identity keying -- bridge from the libvirt net NAME, no virbrN.
# Scoped to NON-COMMENT lines on purpose: the site rows quote the MEASURED
# `ip -4 -o addr` and `ip route show default` output, which names virbr2/virbr5/
# virbr6, and deleting that evidence to satisfy a grep would destroy the
# provenance the values rest on. What must not exist is an EXECUTED literal.
CODE="$(grep -vE '^[[:space:]]*#' "$SCRIPT")"
grep -q 'net-dumpxml' <<<"$CODE" && ! grep -qE 'virbr[0-9]' <<<"$CODE" \
  && ok "T10 bridge resolved from net name; no EXECUTED virbrN literal" \
  || no "T10 bridge resolved from net name; no EXECUTED virbrN literal"

# T11: this service OWNS its net layer and NAMES it for itself. The D-135
# lesson: on a DC running only the mirror (dc0) or only the cache proxy (dc1),
# that one's documented teardown must not be able to kill this proxy.
grep -q 'snap-proxy-net.service' "$SCRIPT" \
  && grep -q 'snap-proxy-net-apply' "$SCRIPT" \
  && ! grep -qE '(NET_UNIT|NET_HELPER|RESOLVED_DROPIN)=.*(mirror|cache-proxy)' "$SCRIPT" \
  && grep -qE 'ip addr replace' "$SCRIPT" && grep -qE 'ip route replace default' "$SCRIPT" \
  && ok "T11 net layer OWNED here and named for THIS service" \
  || no "T11 net layer OWNED here and named for THIS service"

# T11b: no OPERATIVE referral to the other two services' installers. Scoped to
# NON-COMMENT lines: the header's account of WHY the coupling is forbidden cites
# them, and deleting that history to satisfy a grep would lose the reason.
grep -vE '^[[:space:]]*#' "$SCRIPT" | grep -qE '(dc-mirror|dc-cache-proxy)\.sh install' \
  && no "T11b no OPERATIVE dc-mirror/dc-cache-proxy referral (header history exempt)" \
  || ok "T11b no OPERATIVE dc-mirror/dc-cache-proxy referral (header history exempt)"

# T12: idempotent verbs only, so this net unit and the mirror's / cache proxy's
# coexist on a rack running two of them instead of fighting.
! grep -qE 'ip (addr|route) add ' "$SCRIPT" \
  && ok "T12 net writes use idempotent replace (safe to coexist)" \
  || no "T12 net writes use idempotent replace (safe to coexist)"

# T13: MEASURED/RULED tag discipline on every site row (hard rule 2).
MR="$(grep -cE 'MEASURED/RULED' "$SCRIPT")"
[ "$MR" -ge 2 ] && ok "T13 both site rows carry a MEASURED/RULED tag" \
  || no "T13 both site rows carry a MEASURED/RULED tag (found $MR)"

# T14: install requires root.
grep -q 'install requires root' "$SCRIPT" && ok "T14 install requires root" \
  || no "T14 install requires root"

# T15: consumption documents BOTH snap keys, and warns that the store-proxy trio
# is a DIFFERENT product (snapd rejects proxy.store without a signed assertion).
grep -q 'snap-http-proxy=http://' "$SCRIPT" \
  && grep -q 'snap-https-proxy=http://' "$SCRIPT" \
  && grep -qE 'snap-store-proxy.*EMPTY|EMPTY.*snap-store' "$SCRIPT" \
  && ok "T15 documents both snap keys + leaves the store-proxy trio empty" \
  || no "T15 documents both snap keys + leaves the store-proxy trio empty"

# T16: the destination allowlist must carry the API host AND a CDN wildcard.
# snapd uses ONE http client for the API and the DOWNLOAD, so an allowlist with
# only api.snapcraft.io authenticates and then fails every download.
# Scoped to the STORE_DOMAINS VALUE, not to the file: the header discusses every
# one of these hosts in prose, so a file-wide grep would stay green after the
# allowlist itself was narrowed. That near-miss is the "citation is an existence
# claim; only its content is evidence" class.
SD="$(grep -E '^STORE_DOMAINS=' "$SCRIPT")"
grep -q 'api\.snapcraft\.io' <<<"$SD" \
  && grep -q '\.snapcraftcontent\.com' <<<"$SD" \
  && grep -q 'login\.ubuntu\.com' <<<"$SD" \
  && ok "T16 allowlist VALUE carries the store API, login and the CDN wildcard" \
  || no "T16 allowlist VALUE carries the store API, login and the CDN wildcard"

# T17: the generated squid config binds the LISTEN address SPECIFICALLY. A
# wildcard bind would collide with MAAS's squid and would also expose the proxy
# on the transit and provider legs.
grep -q 'http_port ${LISTEN}:${PROXY_PORT}' "$SCRIPT" \
  && ok "T17 squid binds LISTEN:PORT specifically, not wildcard" \
  || no "T17 squid binds LISTEN:PORT specifically, not wildcard"

# T18: the PACKAGED squid.service is stood down at install AND asserted by check.
# Its squid.conf pins http_port 3128 (MAAS holds it), so it can only crash-loop.
# The install half is scoped to do_install's BODY: `check`'s failure message also
# tells the operator to run that command, so a file-wide grep would stay green
# after install stopped doing it.
INSTALL_BODY="$(awk '/^do_install\(\) \{/{f=1} f{print} f&&/^\}/{exit}' "$SCRIPT")"
grep -q 'systemctl disable --now squid' <<<"$INSTALL_BODY" \
  && grep -q 'PACKAGED squid.service is ACTIVE' "$SCRIPT" \
  && ok "T18 packaged squid.service disabled BY install + asserted by check" \
  || no "T18 packaged squid.service disabled BY install + asserted by check"

# T19: install PARSES the config before enabling anything.
grep -q 'squid -k parse -f' "$SCRIPT" \
  && ok "T19 install parses the squid config before enabling" \
  || no "T19 install parses the squid config before enabling"

# T20: install never apt-installs -- it fails loud with the exact line instead,
# so a package install stays operator-visible (the dc-mirror/dc-cache-proxy
# pattern). The first grep must match an INVOCATION (a command at the start of a
# statement), never the guidance string, which contains the same words.
# Double-quoted strings are blanked first, for the same reason as T50: the
# guidance message legitimately CONTAINS `apt-get update && apt-get install -y
# squid`, and a naive invocation regex matches inside it.
if grep -vE '^[[:space:]]*#' "$SCRIPT" | sed 's/"[^"]*"/""/g' \
   | grep -qE '(^|;|&&|\|\|)[[:space:]]*(sudo[[:space:]]+)?apt(-get)?[[:space:]]+install'; then
  no "T20 install never apt-installs; it prints the line for the operator"
elif grep -q 'run: apt-get update && apt-get install -y squid' "$SCRIPT"; then
  ok "T20 install never apt-installs; it prints the line for the operator"
else
  no "T20 install never apt-installs; it prints the line for the operator"
fi

# T20b: NEITHER `check` NOR `install` may gate on `dpkg -s squid` (BUG-4,
# 2026-07-31). dpkg exits 0 for `Status: deinstall ok config-files`, so a PURGED
# squid reports as present -- in `check` that is a false green, and in
# `install`'s prereq it sails past and dies confusingly at `squid -k parse` or at
# unit start instead. `check`'s half is proven behaviorally by T41/T41b; this
# case exists because `do_install` is never EXECUTED by this harness (it needs
# root and a real rack), so its half would otherwise have no assertion at all.
# Asserted on the whole file: the correct number of `dpkg -s` gates is zero.
if grep -vE '^[[:space:]]*#' "$SCRIPT" | grep -q 'dpkg -s'; then
  no "T20b neither check nor install gates on 'dpkg -s' (a purged package exits 0)"
elif grep -qE '^[[:space:]]*if \[ ! -x "\$\{SYSROOT\}/usr/sbin/squid" \]' <<<"$INSTALL_BODY"; then
  ok "T20b neither check nor install gates on 'dpkg -s' (a purged package exits 0)"
else
  no "T20b install's package prereq is not the binary test -- it must be [ ! -x ...squid ]"
fi

# T21-T22: arg / site validation.
out="$(bash "$SCRIPT" bogus dc0 2>&1)"; rc=$?
[ "$rc" = "2" ] && grep -q 'usage:' <<<"$out" \
  && ok "T21 bad mode -> usage, exit 2" || no "T21 bad mode -> usage, exit 2"
bash "$SCRIPT" check zz >/dev/null 2>&1; [ "$?" = "2" ] \
  && ok "T22 unknown site -> exit 2" || no "T22 unknown site -> exit 2"

# ===========================================================================
# BEHAVIORAL -- drive `check dc0` and `node dc0` against a fake world.
# ===========================================================================
TMP="$(mktemp -d)"; trap 'rm -rf "$TMP"' EXIT
FB="$TMP/bin"; mkdir -p "$FB"
SR="$TMP/sysroot"

cat > "$FB/curl" <<'FAKE'
#!/usr/bin/env bash
# fake curl: honours -o <file>, writes %{http_code} to stdout and any error text
# to stderr, and exits like the real one. Behaviour is selected per TARGET URL,
# because check makes three probes with three different meanings.
out="/dev/null"; url=""
while [ $# -gt 0 ]; do
  case "$1" in
    -o) out="$2"; shift 2 ;;
    -w|-x|-m|-H) shift 2 ;;
    -*) shift ;;
    *)  url="$1"; shift ;;
  esac
done
store_body() { # $1 = which fields to include
  case "$1" in
    full)   printf '{"channel-map":[{"download":{"sha3-384":"deadbeef","size":1}}]}\n' > "$out" ;;
    nochan) printf '{"result":"error","message":"nope"}\n' > "$out" ;;
    nosha)  printf '{"channel-map":[{"download":{"size":1}}]}\n' > "$out" ;;
  esac
}
deny_403() { echo "curl: (56) CONNECT tunnel failed, response 403" >&2; printf '000'; exit 56; }
case "$url" in
  *api.snapcraft.io*)
    case "$(cat "$FAKEDIR/curl.store")" in
      ok)      store_body full;   printf '200' ;;
      nochan)  store_body nochan; printf '200' ;;
      nosha)   store_body nosha;  printf '200' ;;
      http404) printf 'not found\n' > "$out"; printf '404' ;;
      unreach) echo "curl: (7) Failed to connect to 10.12.8.4 port 3129" >&2; printf '000'; exit 7 ;;
      denied)  deny_403 ;;
    esac ;;
  *snapcraftcontent.com*)
    case "$(cat "$FAKEDIR/curl.cdn")" in
      ok)      printf '403' ;;
      refused) deny_403 ;;
      weird)   echo "curl: (35) TLS connect error" >&2; printf '000'; exit 35 ;;
    esac ;;
  *)
    case "$(cat "$FAKEDIR/curl.deny")" in
      denied) deny_403 ;;
      served) printf '200' ;;
      weird)  echo "curl: (28) Operation timed out" >&2; printf '000'; exit 28 ;;
    esac ;;
esac
FAKE

cat > "$FB/ss" <<'FAKE'
#!/usr/bin/env bash
case "$(cat "$FAKEDIR/ss.mode")" in
  listen)   printf 'State  Recv-Q Send-Q Local Address:Port  Peer Address:Port\nLISTEN 0      256          10.12.8.4:3129       0.0.0.0:*    \n' ;;
  wildcard) printf 'State  Recv-Q Send-Q Local Address:Port  Peer Address:Port\nLISTEN 0      256                  *:3129       0.0.0.0:*    \n' ;;
  none)     printf 'State  Recv-Q Send-Q Local Address:Port  Peer Address:Port\n' ;;
esac
FAKE

cat > "$FB/systemctl" <<'FAKE'
#!/usr/bin/env bash
# modes: units.mode  = enabled|disabled   (our two units)
#        pkgsquid.mode = off|active|enabled
verb="$1"; shift
quiet=0; [ "${1:-}" = "--quiet" ] && { quiet=1; shift; }
unit="${1:-}"
u="$(cat "$FAKEDIR/units.mode")"; p="$(cat "$FAKEDIR/pkgsquid.mode")"
case "$unit" in
  squid|squid.service)
    case "$verb" in
      is-enabled) [ "$p" = "enabled" ] && { echo enabled; exit 0; }; echo disabled; exit 1 ;;
      is-active)  [ "$p" = "active" ] && exit 0 || exit 3 ;;
    esac ;;
  *snap-proxy.service|*snap-proxy-net.service)
    case "$verb" in
      is-enabled) [ "$u" = "enabled" ] && { echo enabled; exit 0; }; echo disabled; exit 1 ;;
      is-active)  [ "$u" = "enabled" ] && exit 0 || exit 3 ;;
    esac ;;
esac
exit 0
FAKE

cat > "$FB/virsh" <<'FAKE'
#!/usr/bin/env bash
case "$(cat "$FAKEDIR/virsh.mode")" in
  ok)      printf "<network>\n  <bridge name='virbrTEST' stp='on' delay='0'/>\n</network>\n" ;;
  missing) exit 1 ;;
esac
FAKE

cat > "$FB/ip" <<'FAKE'
#!/usr/bin/env bash
args="$*"
case "$args" in
  *"addr show dev"*)
    case "$(cat "$FAKEDIR/ip.addr")" in
      ok)      printf '7: virbrTEST    inet 10.12.8.4/22 brd 10.12.11.255 scope global secondary virbrTEST\n' ;;
      missing) : ;;
    esac ;;
  *"route show default"*)
    case "$(cat "$FAKEDIR/ip.route")" in
      ok)      printf 'default via 10.12.4.1 dev virbrX proto static\n' ;;
      missing) : ;;
    esac ;;
esac
FAKE

# NO dpkg fake any more. The script asserts the squid BINARY under SYSROOT rather
# than `dpkg -s squid`, because dpkg exits 0 for `Status: deinstall ok
# config-files` -- a PURGED squid reported as present (BUG-4, 2026-07-31). The
# seam is therefore a real file under $SR, seeded by seed_sysroot and removed by
# T41, which is drivable in both directions exactly as the dpkg fake was.
chmod +x "$FB"/*

# Lay down a SYSROOT whose five artifacts are byte-identical to what the script
# generates -- by asking THE SCRIPT ITSELF to render them, never by copying its
# text into this file. A hand-copied expectation drifts silently; this cannot.
# Everything above the final MODE dispatch is the script's library half: sourcing
# it with `set -- check dc0` yields the real site row and the real generators.
LIB="$TMP/lib.sh"
LASTCASE="$(grep -n '^case "\$MODE" in$' "$SCRIPT" | tail -1 | cut -d: -f1)"
if [ -z "$LASTCASE" ]; then
  no "T-lib could not locate the MODE dispatch -- behavioral cases cannot run"
  echo; echo "dc-snap-proxy: $PASS passed, $FAIL failed"; exit 1
fi
head -n "$((LASTCASE-1))" "$SCRIPT" > "$LIB"
render() { # render <gen_fn>
  env DC_SNAP_PROXY_SYSROOT="$SR" LIB="$LIB" GENFN="$1" bash -c '
    set -- check dc0
    . "$LIB"
    "$GENFN"
  ' _
}
seed_sysroot() {
  rm -rf "$SR"
  mkdir -p "$SR/etc/squid" "$SR/etc/systemd/system" "$SR/etc/systemd/resolved.conf.d" \
           "$SR/usr/local/sbin" "$SR/usr/sbin" "$SR/etc"
  # The squid BINARY seam (BUG-4). Executable and present = the green baseline.
  install -m 0755 /dev/null "$SR/usr/sbin/squid"
  render gen_squid_conf      > "$SR/etc/squid/dc0-snap-proxy.conf"
  render gen_proxy_unit      > "$SR/etc/systemd/system/dc0-snap-proxy.service"
  render gen_net_helper      > "$SR/usr/local/sbin/dc0-snap-proxy-net-apply"
  render gen_net_unit        > "$SR/etc/systemd/system/dc0-snap-proxy-net.service"
  render gen_resolved_dropin > "$SR/etc/systemd/resolved.conf.d/dc0-snap-proxy.conf"
  printf 'PATH="/usr/bin:/bin"\nhttps_proxy=http://10.12.8.4:3129\nhttp_proxy=http://10.12.8.4:3129\n' \
    > "$SR/etc/environment"
}
set_modes() { # all-green defaults
  printf 'ok'        > "$TMP/curl.store"
  printf 'ok'        > "$TMP/curl.cdn"
  printf 'denied'    > "$TMP/curl.deny"
  printf 'listen'    > "$TMP/ss.mode"
  printf 'enabled'   > "$TMP/units.mode"
  printf 'off'       > "$TMP/pkgsquid.mode"
  printf 'ok'        > "$TMP/virsh.mode"
  printf 'ok'        > "$TMP/ip.addr"
  printf 'ok'        > "$TMP/ip.route"
}
run_mode() { # run_mode <check|node> <want_rc> <regex> <label>
  local mode="$1" want="$2" rx="$3" label="$4" out rc
  out="$(env FAKEDIR="$TMP" DC_SNAP_PROXY_SYSROOT="$SR" PATH="$FB:$PATH" \
         bash "$SCRIPT" "$mode" dc0 2>&1)"; rc=$?
  if [ "$rc" = "$want" ] && grep -qE "$rx" <<<"$out"; then ok "$label"
  else no "$label (rc=$rc want=$want)"; sed 's/^/        /' <<<"$out" | head -8; fi
}

# --- T23: the all-green baseline. If this cannot pass, nothing below means
# anything -- a suite whose green case is broken proves only that it is red.
seed_sysroot; set_modes
run_mode check 0 'dc-snap-proxy check \(dc0\): PASS' "T23 check: fully-built rack -> PASS"

# T23b: the probe ACL must not be a DEAD loopback rule (BUG-1, 2026-07-31).
# squid binds LISTEN:PORT only, so nothing can ever arrive on 127.0.0.1 and the
# original `acl snap_probe src 127.0.0.1/32` matched nothing -- the probes were
# silently admitted by snap_clients instead, and the comment misdescribed its own
# mechanism. The hazard was live: anyone NARROWING snap_clients would break
# `check`, and the rule they would reach for would not have helped. Asserted on
# the RENDERED artifact, never on the comment that describes it.
#
# >>> THIS ASSERTION IS PROVISIONAL AND ITS EXPECTED VALUE IS KNOWN WRONG. DO NOT
# "FIX" IT BY EDITING THE EXPECTED STRING TO MATCH. <<< MEASURED on the dc0 rack
# 2026-07-31, AFTER the BUG-1 fix shipped:
#     ip route get 10.12.8.4  ->  local 10.12.8.4 dev lo src 10.12.8.2
# The LISTEN address `.4` is a SECONDARY on virbr2 (primary `.2`), and Linux does
# not auto-select a secondary as a source address. Squid's own access log
# attributes every rack-side probe to 10.12.8.2. So `acl snap_probe src
# 10.12.8.4/32` matches NOTHING: BUG-1's fix corrected the mechanism DESCRIPTION
# but landed on the WRONG ADDRESS, and the rule is still dead.
# Nothing is broken today -- the probes are admitted by `snap_clients`, exactly as
# before. What remains unconnected is the rule's STATED PURPOSE: that narrowing
# `snap_clients` must not silently break `check`.
# The correct value is the rack's PRIMARY metal-admin leg (dc0 `10.12.8.2`), which
# needs a site-keyed MEASURED row (dc1's `10.12.68.2` is already recorded in
# lib-hosts.sh). NOT changed here ON PURPOSE: `check` diffs the generated config
# against the rack's LIVE file, so editing gen_squid_conf turns the live dc0 gate
# RED until `install` is re-run -- a live mutation, out of scope under hard rule 1.
# Fix the script and this assertion TOGETHER at the next install; dc1 is the
# natural point, so both DCs land in one pass.
CONF="$(render gen_squid_conf)"
if grep -qE '^acl snap_probe src 10\.12\.8\.4/32$' <<<"$CONF" \
   && ! grep -qE '^acl snap_probe src .*127\.0\.0\.1' <<<"$CONF"; then
  ok "T23b probe ACL is the LISTEN address, not a dead loopback rule"
else
  no "T23b probe ACL is the LISTEN address, not a dead loopback rule"
  grep -E '^acl snap_probe' <<<"$CONF" | sed 's/^/        /'
fi

# --- T24-T25: artifacts asserted on CONTENT, not existence (the dc-mirror.sh
# false-green class, fixed 2026-07-27).
seed_sysroot; set_modes
printf '# hand-edited on the rack\n' >> "$SR/etc/squid/dc0-snap-proxy.conf"
run_mode check 1 'DIFFERS from generated content' "T24 check: hand-edited squid.conf -> FAIL (content, not existence)"
seed_sysroot; set_modes
rm -f "$SR/etc/systemd/system/dc0-snap-proxy-net.service"
run_mode check 1 'snap-proxy-net.service absent' "T25 check: missing owned net unit -> FAIL"

# --- T26-T27: unit state, including the packaged squid that can only crash-loop.
seed_sysroot; set_modes; printf 'disabled' > "$TMP/units.mode"
run_mode check 1 'not enabled \(it would not survive a reboot\)' "T26 check: units not enabled -> FAIL"
seed_sysroot; set_modes; printf 'active' > "$TMP/pkgsquid.mode"
run_mode check 1 'PACKAGED squid.service is ACTIVE' "T27 check: packaged squid running -> FAIL"
seed_sysroot; set_modes; printf 'enabled' > "$TMP/pkgsquid.mode"
run_mode check 1 'PACKAGED squid.service is ENABLED' "T27b check: packaged squid enabled -> FAIL"

# --- T28-T29: the listener. A WILDCARD bind is not "close enough": it collides
# with MAAS's squid and exposes the proxy on the transit and provider legs.
seed_sysroot; set_modes; printf 'wildcard' > "$TMP/ss.mode"
run_mode check 1 'bound WILDCARD, not on 10.12.8.4' "T28 check: wildcard bind -> FAIL (not accepted)"
seed_sysroot; set_modes; printf 'none' > "$TMP/ss.mode"
run_mode check 1 'nothing listening on 10.12.8.4:3129' "T29 check: no listener -> FAIL"

# --- T30-T32: the net layer's live effect, and the REFUSE that separates
# "the alias is absent" from "I could not look".
seed_sysroot; set_modes; printf 'missing' > "$TMP/ip.addr"
run_mode check 1 'absent on the metal-admin bridge' "T30 check: LISTEN alias missing -> FAIL"
seed_sysroot; set_modes; printf 'missing' > "$TMP/virsh.mode"
run_mode check 3 'did not resolve to a bridge -- the alias is UNKNOWN, not absent' \
  "T31 check: unresolvable bridge -> REFUSE (rc 3, not 0)"
seed_sysroot; set_modes; printf 'missing' > "$TMP/ip.route"
run_mode check 1 'no upstream egress' "T32 check: no default route -> FAIL"

# --- T33-T36: the ALLOW-direction probe, asserted on CONTENT. A 200 is not
# evidence: a proxy error page carries one too.
seed_sysroot; set_modes; printf 'nochan' > "$TMP/curl.store"
run_mode check 1 'no "channel-map"' "T33 check: 200 without channel-map -> FAIL (content, not status)"
seed_sysroot; set_modes; printf 'nosha' > "$TMP/curl.store"
run_mode check 1 'no sha3-384 download digest' "T34 check: store body without a digest -> FAIL"
seed_sysroot; set_modes; printf 'http404' > "$TMP/curl.store"
run_mode check 1 'returned HTTP 404 through the proxy' "T35 check: store 404 -> FAIL"
seed_sysroot; set_modes; printf 'unreach' > "$TMP/curl.store"
run_mode check 3 "unreachable is not 'nothing there'" "T36 check: proxy unreachable -> REFUSE (rc 3)"

# --- T37-T38: the CDN tunnel. snapd downloads through the SAME proxy, so an
# allowlist that names only the API host would authenticate and then fail.
seed_sysroot; set_modes; printf 'refused' > "$TMP/curl.cdn"
run_mode check 1 'allowlist is too narrow' "T37 check: CDN tunnel refused -> FAIL"
seed_sysroot; set_modes; printf 'weird' > "$TMP/curl.cdn"
run_mode check 3 'neither an allowed tunnel nor a proxy denial' "T38 check: unrecognised CDN result -> REFUSE"

# --- T39-T40: the DENY direction. This is the assertion that proves the
# destination allowlist is IN FORCE rather than merely written down.
seed_sysroot; set_modes; printf 'served' > "$TMP/curl.deny"
run_mode check 1 'OPEN forward proxy on the node plane' "T39 check: non-allowlisted host SERVED -> FAIL (open proxy)"
seed_sysroot; set_modes; printf 'weird' > "$TMP/curl.deny"
run_mode check 3 'allowlist state is UNKNOWN' "T40 check: unrecognised deny result -> REFUSE"

# --- T41/T41b-T42: binary absence FAILS (an observed absence), tool absence
# REFUSES ("could not look" is never "nothing there").
seed_sysroot; set_modes; rm -f "$SR/usr/sbin/squid"
run_mode check 1 'squid binary absent' "T41 check: squid binary absent -> FAIL"
# T41b is the case the OLD `dpkg -s` assertion could not fail on, and is why
# BUG-4 mattered: a PURGED package leaves its config-files record behind, so
# `dpkg -s squid` exits 0 while no executable exists. Here the file is present
# but NOT executable -- the exact residue shape -- and the assertion must still
# turn red. Without this case the fix would be untested in its own direction.
seed_sysroot; set_modes; install -m 0644 /dev/null "$SR/usr/sbin/squid"
run_mode check 1 'squid binary absent' "T41b check: squid path present but NOT executable -> FAIL"
# T42 needs a PATH with NO curl AT ALL. Deleting the fake is not enough -- the
# real /usr/bin/curl is still on PATH and the script would then probe a dead
# 10.12.8.4:3129 and REFUSE for the WRONG REASON, with the right exit code. That
# near-miss is exactly the "would my instrument look like this if it were broken"
# tell, so the case builds a closed PATH: the fakes minus curl, plus explicit
# symlinks to the real utilities the script legitimately uses.
NB="$TMP/nocurl"; mkdir -p "$NB"
for f in "$FB"/*; do
  [ "$(basename "$f")" = "curl" ] || ln -sf "$f" "$NB/"
done
for t in bash env diff mktemp grep head tail rm sed cat cut awk tr; do
  p="$(command -v "$t" 2>/dev/null)"; [ -n "$p" ] && ln -sf "$p" "$NB/$t"
done
seed_sysroot; set_modes
out="$(env FAKEDIR="$TMP" DC_SNAP_PROXY_SYSROOT="$SR" PATH="$NB" bash "$SCRIPT" check dc0 2>&1)"; rc=$?
if [ "$rc" = "3" ] && grep -q 'curl is not present' <<<"$out"; then
  ok "T42 check: no curl on PATH -> REFUSE (rc 3, not 0)"
else
  no "T42 check: no curl on PATH -> REFUSE (rc 3, not 0) (rc=$rc want=3)"
  sed 's/^/        /' <<<"$out" | tail -6
fi

# ===========================================================================
# `node` -- the CLIENT-side gate. `check` asserts rack-side facts a container
# cannot satisfy, so pointing a client at `check` would fail for reasons that
# say nothing about client reachability. These cases drive the client half.
# ===========================================================================
seed_sysroot; set_modes
run_mode node 0 'dc-snap-proxy node \(dc0\): PASS' "T43 node: reachable + denied + env set -> PASS"

# T44 the failure the measurement in the header exists to prevent: a client whose
# SOURCE address is outside CLIENT_CIDR is refused BY THE PROXY, and that must
# read as a client/ACL problem, not as "the store is down".
seed_sysroot; set_modes; printf 'denied' > "$TMP/curl.store"
run_mode node 1 "source address is outside 10.12.8.0/22" \
  "T44 node: proxy denies this client -> FAIL naming the ACL, not the store"

seed_sysroot; set_modes; printf 'unreach' > "$TMP/curl.store"
run_mode node 3 "unreachable is not 'nothing there'" "T45 node: proxy unreachable -> REFUSE (rc 3)"
seed_sysroot; set_modes; printf 'nochan' > "$TMP/curl.store"
run_mode node 1 'no "channel-map"' "T46 node: 200 without channel-map -> FAIL"
seed_sysroot; set_modes; printf 'served' > "$TMP/curl.deny"
run_mode node 1 'OPEN forward proxy on the node plane' "T47 node: allowlist not in force from the client -> FAIL"

# T48-T49: snapd's own view, read WITHOUT root. juju shells out `snap set system
# proxy.*` and snapd writes those to /etc/environment, so this is the artifact --
# and `snap get system proxy` would have needed root and broken the no-root rule.
seed_sysroot; set_modes
grep -v 'https_proxy' "$SR/etc/environment" > "$SR/etc/environment.new" && mv "$SR/etc/environment.new" "$SR/etc/environment"
run_mode node 1 'the juju keys have not reached this client' "T48 node: no https_proxy in /etc/environment -> FAIL"
seed_sysroot; set_modes
printf 'https_proxy=http://10.12.99.99:3128\n' > "$SR/etc/environment"
run_mode node 1 'points somewhere ELSE' "T49 node: https_proxy points at another proxy -> FAIL"

# T50: `node` must stay CLIENT-satisfiable -- no root, no systemctl, no virsh, no
# generated-file diffs. That is the whole reason `check` cannot serve a client.
# Double-quoted strings are BLANKED before the grep: the assertion is about CODE,
# not prose. The body legitimately tells an operator to measure a client's source
# with `ip route get <listen>` inside a failure MESSAGE, and rewording that hint
# to dodge a regex would be gaming the test rather than satisfying it.
BODY="$(awk '/^do_node\(\) \{/{f=1} f{print} f&&/^\}/{exit}' "$SCRIPT")"
BODY_CODE="$(sed 's/"[^"]*"/""/g' <<<"$BODY")"
if grep -qE 'systemctl|virsh|util_bridge|id -u|ip (addr|route)|diff -q|dpkg' <<<"$BODY_CODE"; then
  no "T50 node body is client-satisfiable only (no rack-side calls)"
else ok "T50 node body is client-satisfiable only (no rack-side calls)"; fi

echo; echo "dc-snap-proxy: $PASS passed, $FAIL failed"
[ "$FAIL" -eq 0 ] && exit 0 || exit 1
