#!/usr/bin/env bash
# tests/node-vm/run-tests.sh -- guard for modules/node-vm (MAC pinning).
# Static assertions that the interface MAC pin is present and correctly
# shaped (regression guard: an unpinned node NIC MAC can be silently
# REGENERATED by an in-place apply, stranding the node in MAAS -- the
# 2026-07-21 commissioning incident, docs/audit/commissioning-diag-20260721.txt).
# Also asserts the inner root actually pins all 9 nodes x 6 planes.
# Runs `tofu validate` on the module when the binary is available; skips
# gracefully when it is not. Exit: 0 all pass | 1 any case failed. ASCII + LF.
set -uo pipefail
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT="$(cd "$HERE/../.." && pwd)"
MOD="$ROOT/opentofu/modules/node-vm"
INNER="$ROOT/opentofu/vr1-dc0-substrate/main.tf"
PASS=0; FAIL=0
ok(){ echo "  PASS  $1"; PASS=$((PASS+1)); }
no(){ echo "  FAIL  $1"; FAIL=$((FAIL+1)); }

[ -f "$MOD/main.tf" ] && ok "T1 module main.tf present" || no "T1 module main.tf present"
[ -f "$MOD/variables.tf" ] && ok "T2 module variables.tf present" || no "T2 module variables.tf present"

# T3: interface_macs variable exists with a safe default (unpinned allowed
# ONLY as an explicit empty default, for pre-enlistment use)
VAR_BLOCK="$(awk '/^variable "interface_macs" \{/{f=1} f{print; n+=gsub(/\{/,"{"); n-=gsub(/\}/,"}"); if(n==0 && f)exit}' "$MOD/variables.tf")"
grep -q 'type *= *list(string)' <<<"$VAR_BLOCK" \
  && ok "T3 interface_macs is list(string)" \
  || no "T3 interface_macs is list(string)"
grep -q 'default *= *\[\]' <<<"$VAR_BLOCK" \
  && ok "T4 interface_macs defaults to empty (opt-in pin)" \
  || no "T4 interface_macs defaults to empty (opt-in pin)"

# T5/T6: both validations present -- all-or-nothing length, and MAC format
grep -q 'length(var.interface_macs) == length(var.network_names)' <<<"$VAR_BLOCK" \
  && ok "T5 validation: all-or-nothing (no partial pinning)" \
  || no "T5 validation: all-or-nothing (no partial pinning)"
grep -q '0-9a-fA-F' <<<"$VAR_BLOCK" \
  && ok "T6 validation: MAC format regex present" \
  || no "T6 validation: MAC format regex present"

# T7: the interfaces comprehension actually consumes the pin, guarded on
# emptiness, in the schema-verified shape mac = { address = ... }
IF_LINE="$(grep -n 'mac *= *length(var.interface_macs) > 0 ? { address = var.interface_macs\[i\] } : null' "$MOD/main.tf" || true)"
[ -n "$IF_LINE" ] \
  && ok "T7 interfaces consume the pin (mac = { address = ... } / null)" \
  || no "T7 interfaces consume the pin (mac = { address = ... } / null)"

# T8: the inner root pins EVERY node: 9 macs lists, 54 MAC literals total,
# and the module call passes interface_macs through.
if [ -f "$INNER" ]; then
  # Count CONFIG, not prose: strip comment lines first. Measured 2026-07-29 -- a comment
  # explaining the deliberate `macs = []` at first apply contained the literal and inflated
  # this count to 11, which reads exactly like a real extra node. Same class as the
  # ledger-scan next-free defect, where a doc QUOTING a token inflated the counter.
  MACS_LISTS="$(grep -v '^[[:space:]]*#' "$INNER" | grep -c 'macs = \[')"
  MAC_LITERALS="$(grep -v '^[[:space:]]*#' "$INNER" | grep -oE '"([0-9a-f]{2}:){5}[0-9a-f]{2}"' | wc -l)"
  # RE-POINTED 2026-07-29: was 9 / 54. The D-104 AMENDMENT adds a 10th node per DC -- the
  # dedicated Juju controller <dc>-juju-01 -- whose six MACs were pinned from measurement
  # after its first apply (it is ENLISTED, which is the boundary past which unpinned MACs
  # can be regenerated and strand the node). So the ruled shape is 10 nodes x 6 planes.
  # Kept EXACT rather than relaxed to >=: an exact count is the whole value of these two.
  #
  # RE-POINTED AGAIN 2026-07-30: now 11 / 66. D-132 q1 (RULED) puts a MAAS REGION in each
  # DC, and its placement sub-ruling puts that region in its OWN VM at utility .6 --
  # <dc>-maas-01, authored into both substrate roots and APPLIED at dc0, with its six MACs
  # pinned from measurement the same day. Same reasoning as the juju controller: once
  # enlisted, unpinned MACs can be regenerated and strand the node.
  #
  # THIS HARNESS WENT RED ON 2026-07-30 AND THE SESSION THAT CAUSED IT DID NOT RE-RUN IT.
  # Commits 086c827 (author both region VMs) and 447315f (pin dc0's MACs) moved the counts
  # to 11/66 while the assertions still read 10/60; the failure was found by the NEXT
  # session's gauntlet. Recorded here rather than silently corrected -- the lesson is that
  # an exact-count assertion is only as good as the gauntlet run that follows the commit.
  #
  # RE-POINTED AGAIN 2026-08-07: now 12 / 72. D-129(iii) AMENDMENT (rulings a-d) adds the
  # DEDICATED per-DC TAILSCALE subnet router <dc>-tailscale-01 at utility .7, applied at dc0
  # with its six MACs pinned from measurement the same day (same enlist-boundary reasoning as
  # the juju controller and region VMs). AND IT WENT RED THE SAME WAY AS 2026-07-30: the
  # session that added the VM re-ran the gauntlet after the TOOLING commit (101 green) but not
  # after the SUBSTRATE commit, so 11->12 went undetected until the savegame gauntlet -- the
  # exact lesson this comment already records. Re-run the gauntlet after EVERY commit that
  # touches the inner root, not just the last one.
  #
  # ASYMMETRY IS GONE: as of 2026-08-07 dc1's root ALSO carries 12 macs lists and 72 literals
  # -- `vr1-dc1-maas-01` was applied+pinned and `vr1-dc1-tailscale-01` added the same day. Both
  # roots are 12/72. This harness still reads the dc0 root only.
  [ "$MACS_LISTS" -eq 12 ] \
    && ok "T8 inner root: 12 per-node macs lists (9 role + juju controller + MAAS region + Tailscale)" \
    || no "T8 inner root: 12 per-node macs lists (found $MACS_LISTS)"
  [ "$MAC_LITERALS" -eq 72 ] \
    && ok "T9 inner root: 72 pinned MAC literals (12 nodes x 6 planes)" \
    || no "T9 inner root: 72 pinned MAC literals (found $MAC_LITERALS)"
  DUPES="$(grep -oE '"([0-9a-f]{2}:){5}[0-9a-f]{2}"' "$INNER" | sort | uniq -d | wc -l)"
  [ "$DUPES" -eq 0 ] \
    && ok "T10 inner root: no duplicate MACs" \
    || no "T10 inner root: no duplicate MACs ($DUPES duplicated)"
  grep -q 'interface_macs *= *each.value.macs' "$INNER" \
    && ok "T11 inner root: module call passes interface_macs" \
    || no "T11 inner root: module call passes interface_macs"
else
  no "T8-T11 inner root main.tf present"
fi

# T13-T15: power-ownership guard (operator-ruled 2026-07-21) -- the domain
# block must ignore_changes on running (MAAS owns node power; an apply must
# never flip it), must NOT ignore anything else there, and must cite MAAS.
DOM_BLOCK="$(awk '/^resource "libvirt_domain" "node" \{/{f=1} f{print; n+=gsub(/\{/,"{"); n-=gsub(/\}/,"}"); if(n==0 && f)exit}' "$MOD/main.tf")"
grep -q 'ignore_changes = \[running\]' <<<"$DOM_BLOCK" \
  && ok "T13 domain ignores running drift (MAAS owns power)" \
  || no "T13 domain ignores running drift (MAAS owns power)"
IGNORE_COUNT="$(grep -c 'ignore_changes' <<<"$DOM_BLOCK")"
[ "$IGNORE_COUNT" -eq 1 ] \
  && ok "T14 exactly one ignore_changes in the domain block (no scope creep)" \
  || no "T14 exactly one ignore_changes in the domain block (found $IGNORE_COUNT)"
grep -q 'MAAS' <<<"$DOM_BLOCK" \
  && ok "T15 guard cites MAAS power ownership" \
  || no "T15 guard cites MAAS power ownership"

# T12: module still validates when tofu is available (init -backend=false is
# offline once the provider is in the plugin cache; skip cleanly otherwise)
if command -v tofu >/dev/null 2>&1; then
  TMP="$(mktemp -d)"; trap 'rm -rf "$TMP"' EXIT
  cp "$MOD"/*.tf "$TMP"/
  if (cd "$TMP" && tofu init -backend=false -input=false >/dev/null 2>&1 \
      && tofu validate >/dev/null 2>&1); then
    ok "T12 module validates (tofu validate)"
  else
    no "T12 module validates (tofu validate)"
  fi
else
  echo "  SKIP  T12 tofu binary not available (static checks above still bind)"
fi

echo; echo "node-vm: $PASS passed, $FAIL failed"
[ "$FAIL" -eq 0 ]
