#!/usr/bin/env bash
# tests/cloudinit-vm/run-tests.sh -- guard for modules/cloudinit-vm (D-130).
# Static assertions that the D-130 lifecycle guard is present and correctly
# placed (regression guard: removing it silently reintroduces the post-reboot
# seed-volume forced replacement, GA-F01). 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)"
MOD="$(cd "$HERE/../.." && pwd)/opentofu/modules/cloudinit-vm"
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"

# T2: the D-130 lifecycle guard lives INSIDE the seed-volume resource block --
# extract the block by brace counting from awk, then assert its content.
SEED_BLOCK="$(awk '/^resource "libvirt_volume" "seed" \{/{f=1} f{print; n+=gsub(/\{/,"{"); n-=gsub(/\}/,"}"); if(n==0 && f)exit}' "$MOD/main.tf")"
grep -q 'ignore_changes' <<<"$SEED_BLOCK" \
  && ok "T2 seed volume carries lifecycle ignore_changes (D-130)" \
  || no "T2 seed volume carries lifecycle ignore_changes (D-130)"
grep -q 'ignore_changes = \[create\]' <<<"$SEED_BLOCK" \
  && ok "T3 guard targets the create attribute exactly" \
  || no "T3 guard targets the create attribute exactly"
grep -q 'D-130' <<<"$SEED_BLOCK" \
  && ok "T4 guard cites its governing decision" \
  || no "T4 guard cites its governing decision"

# T5: the guard must NOT leak onto the data disk (only the seed volume's
# create is staging-derived; ignoring the disk's attributes would mask drift)
DISK_BLOCK="$(awk '/^resource "libvirt_volume" "disk" \{/{f=1} f{print; n+=gsub(/\{/,"{"); n-=gsub(/\}/,"}"); if(n==0 && f)exit}' "$MOD/main.tf")"
grep -q 'ignore_changes' <<<"$DISK_BLOCK" \
  && no "T5 data-disk volume has NO ignore_changes" \
  || ok "T5 data-disk volume has NO ignore_changes"

# T5a-T5d: interface_macs MAC pinning (ported from node-vm 2026-07-22 -- the
# 2026-07-20 voffice1 Kea/MAC-regen incident class). Same regression intent as
# tests/node-vm: the var, both validations, and the conditional wiring must stay.
grep -q 'variable "interface_macs"' "$MOD/variables.tf" \
  && ok "T5a interface_macs variable present" \
  || no "T5a interface_macs variable present"
grep -q 'exactly one MAC per network_names entry' "$MOD/variables.tf" \
  && ok "T5b count validation present (all-or-nothing pinning)" \
  || no "T5b count validation present (all-or-nothing pinning)"
grep -q '0-9a-fA-F.*{2}' "$MOD/variables.tf" \
  && ok "T5c MAC format validation present" \
  || no "T5c MAC format validation present"
grep -q 'mac = length(var.interface_macs) > 0 ? { address = var.interface_macs\[i\] } : null' "$MOD/main.tf" \
  && ok "T5d interfaces wiring carries the conditional MAC pin" \
  || no "T5d interfaces wiring carries the conditional MAC pin"

# T6: 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 "T6 module validates (tofu validate)"
  else
    no "T6 module validates (tofu validate)"
  fi
else
  echo "  SKIP  T6 tofu binary not available (static checks above still bind)"
fi

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