run.sh 4.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. #!/usr/bin/env bash
  2. # Self-test for process-compose-ops — fully offline: no network, no download.
  3. #
  4. # Wraps the skill's binary-integrity verifier (scripts/verify-binary.ps1), which
  5. # re-checks the committed process-compose.exe SHA-256 against the recorded
  6. # EXE_HASH. Unlike the three §7 staleness scripts this verifier is PowerShell and
  7. # platform-locked to a Windows binary, so the suite has two layers:
  8. # * contract / structural (run anywhere, no PowerShell host required): the .ps1
  9. # exists and encodes the Get-FileHash/EXE_HASH compare plus the mismatch
  10. # throw — proving it is a real check, not a vacuous rubber stamp;
  11. # * behavioural happy + negative against a temp bin/ — exercised only when a
  12. # PowerShell host (pwsh | powershell) is present. A dummy .exe and a
  13. # hand-written EXE_HASH stand in for the real binary, so no download and no
  14. # network ever occur. SKIP'd (suite stays green) on a PowerShell-less Linux
  15. # runner — the structural layer still runs.
  16. #
  17. # Usage: bash tests/run.sh
  18. # Exit: 0 all pass, 1 one or more failures
  19. set -uo pipefail
  20. HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
  21. SKILL="$(dirname "$HERE")"
  22. V="$SKILL/scripts/verify-binary.ps1"
  23. # A PowerShell host, if any (pwsh = PowerShell 7 cross-platform; powershell =
  24. # Windows PowerShell 5.1). Absent on most Linux CI runners.
  25. PSHOST=""
  26. for c in pwsh powershell; do
  27. if command -v "$c" >/dev/null 2>&1 && "$c" -NoProfile -Command 'exit 0' >/dev/null 2>&1; then PSHOST="$c"; break; fi
  28. done
  29. SB="$(mktemp -d)"; trap 'rm -rf "$SB"' EXIT
  30. PASS=0; FAIL=0
  31. ok() { PASS=$((PASS+1)); printf ' PASS %s\n' "$1"; }
  32. no() { FAIL=$((FAIL+1)); printf ' FAIL %s\n' "$1"; }
  33. expect_exit() { [[ "$2" == "$3" ]] && ok "$1 (exit $3)" || no "$1 (want $2 got $3)"; }
  34. expect_has() { case "$3" in *"$2"*) ok "$1";; *) no "$1 (missing '$2')";; esac; }
  35. echo "=== process-compose-ops self-test ==="
  36. # ── contract / structural (runs anywhere, no PowerShell host needed) ──────────
  37. echo "-- contract --"
  38. [[ -f "$V" ]] && ok "verify-binary.ps1 present" || no "verify-binary.ps1 present"
  39. [[ -s "$V" ]] && ok "verify-binary.ps1 non-empty" || no "verify-binary.ps1 non-empty"
  40. # The verifier must encode the integrity check it claims to run: a SHA-256
  41. # compare of the binary against EXE_HASH that throws on mismatch. If these
  42. # markers were gutted the verifier would be a vacuous rubber stamp.
  43. vtxt="$(cat "$V")"
  44. expect_has "computes SHA-256 of the binary" "Get-FileHash" "$vtxt"
  45. expect_has "reads recorded EXE_HASH" "EXE_HASH" "$vtxt"
  46. expect_has "fails loud on mismatch" "MISMATCH" "$vtxt"
  47. # ── behavioural (happy + negative) under a PowerShell host, if present ─────────
  48. echo "-- behavioural (${PSHOST:-no powershell host}) --"
  49. if [[ -z "$PSHOST" ]]; then
  50. echo " SKIP happy/negative (no pwsh/powershell on this runner — structural layer above still ran)"
  51. else
  52. # happy: a dummy .exe whose recorded EXE_HASH matches its actual SHA-256.
  53. mkdir -p "$SB/ok/bin"
  54. printf 'process-compose-fake-bytes' > "$SB/ok/bin/process-compose.exe"
  55. # sha256sum and Get-FileHash compute the identical digest; the verifier
  56. # compares lowercased + trimmed, so this matches what it recomputes.
  57. sha256sum "$SB/ok/bin/process-compose.exe" | awk '{print $1}' > "$SB/ok/bin/EXE_HASH"
  58. "$PSHOST" -NoProfile -File "$V" -BinDir "$SB/ok/bin" >/dev/null 2>&1
  59. expect_exit "matching EXE_HASH -> 0" 0 $?
  60. # negative: a recorded EXE_HASH that disagrees with the actual SHA-256.
  61. mkdir -p "$SB/bad/bin"
  62. printf 'process-compose-fake-bytes' > "$SB/bad/bin/process-compose.exe"
  63. printf '0000000000000000000000000000000000000000000000000000000000000000' > "$SB/bad/bin/EXE_HASH"
  64. "$PSHOST" -NoProfile -File "$V" -BinDir "$SB/bad/bin" >"$SB/neg.out" 2>&1
  65. rc=$?
  66. [[ "$rc" -ne 0 ]] && ok "mismatched EXE_HASH -> nonzero (exit $rc)" || no "mismatched EXE_HASH -> nonzero (got 0)"
  67. expect_has "verifier reports MISMATCH" "MISMATCH" "$(cat "$SB/neg.out")"
  68. fi
  69. # ── SKILL.md sanity ───────────────────────────────────────────────────────────
  70. echo "-- SKILL.md --"
  71. grep -q '^name: process-compose-ops$' "$SKILL/SKILL.md" && ok "frontmatter name" || no "frontmatter name"
  72. grep -q 'verify-binary.ps1' "$SKILL/SKILL.md" && ok "verifier cited from SKILL.md" || no "verifier cited from SKILL.md"
  73. echo ""
  74. echo "=== $PASS passed, $FAIL failed ==="
  75. [[ "$FAIL" -eq 0 ]] || exit 1
  76. exit 0