#!/usr/bin/env bats # Tests for scripts/orca-pull.sh — the C-09 failure contract + C-23 # cluster-wide vs namespace-scoped distinction. load test_helper PULL="$SCRIPTS_DIR/orca-pull.sh" TMP_TXN="" setup() { TMP_TXN="$(mktemp -d)" # Minimal apply/verify/rollback scripts that succeed. cat >"$TMP_TXN/apply.sh" <<'EOF' #!/usr/bin/env bash touch "$TMP_TXN/.applied-marker" exit 0 EOF # A real marker the orca-pull.sh checks for. cat >"$TMP_TXN/apply.sh" <<'EOF' #!/usr/bin/env bash touch "$(dirname "$0")/.applied" exit 0 EOF cat >"$TMP_TXN/verify.sh" <<'EOF' #!/usr/bin/env bash exit 0 EOF cat >"$TMP_TXN/rollback.sh" <<'EOF' #!/usr/bin/env bash rm -f "$(dirname "$0")/.applied" exit 0 EOF chmod +x "$TMP_TXN"/*.sh } teardown() { [ -n "$TMP_TXN" ] && rm -rf "$TMP_TXN" } @test "orca-pull.sh exists and is executable" { [ -f "$PULL" ] [ -x "$PULL" ] } @test "orca-pull.sh refuses without --txn-dir (exit 4)" { run "$PULL" --force --i-understand-the-risk assert_status 4 "$status" } @test "orca-pull.sh cluster-wide without --force exits 4 (C-23)" { run "$PULL" --txn-dir "$TMP_TXN" assert_status 4 "$status" assert_contains "$output" "requires --force" } @test "orca-pull.sh cluster-wide with --force but no ack exits 4 (C-23)" { run "$PULL" --txn-dir "$TMP_TXN" --force assert_status 4 "$status" assert_contains "$output" "--i-understand-the-risk" } @test "orca-pull.sh cluster-wide with --force --i-understand-the-risk applies" { run "$PULL" --txn-dir "$TMP_TXN" --force --i-understand-the-risk assert_status 0 "$status" assert_contains "$output" "applied" [ -f "$TMP_TXN/.applied" ] } @test "orca-pull.sh namespace-scoped applies without --force (C-23)" { run "$PULL" --txn-dir "$TMP_TXN" --namespace default assert_status 0 "$status" assert_contains "$output" "applied" [ -f "$TMP_TXN/.applied" ] } @test "orca-pull.sh idempotent re-run exits 5 (already-applied)" { # First apply. run "$PULL" --txn-dir "$TMP_TXN" --namespace default assert_status 0 "$status" # Re-run: should be a no-op (exit 5). run "$PULL" --txn-dir "$TMP_TXN" --namespace default assert_status 5 "$status" assert_contains "$output" "already-applied" } @test "orca-pull.sh apply failure runs rollback and exits 1" { # Make apply.sh fail. cat >"$TMP_TXN/apply.sh" <<'EOF' #!/usr/bin/env bash exit 1 EOF chmod +x "$TMP_TXN/apply.sh" run "$PULL" --txn-dir "$TMP_TXN" --namespace default [ "$status" -eq 1 ] } @test "orca-pull.sh verify failure runs rollback and exits 2" { # apply succeeds, verify fails. cat >"$TMP_TXN/verify.sh" <<'EOF' #!/usr/bin/env bash exit 1 EOF chmod +x "$TMP_TXN/verify.sh" run "$PULL" --txn-dir "$TMP_TXN" --namespace default [ "$status" -eq 2 ] } @test "orca-pull.sh missing bundle file exits 4" { rm -f "$TMP_TXN/verify.sh" run "$PULL" --txn-dir "$TMP_TXN" --namespace default assert_status 4 "$status" } @test "orca-pull.sh drift gate refuses with exit 6 when drift detected (R-020)" { # Create a drift-events-aggregated.json with confirmed drift. mkdir -p "$TMP_TXN/state" DRIFT_JSON="$TMP_TXN/state/drift-events-aggregated.json" cat >"$DRIFT_JSON" < no drift -> applies. mkdir -p "$TMP_TXN/state" DRIFT_JSON="$TMP_TXN/state/drift-events-aggregated.json" echo '{"ts":"2026-01-01T00:00:00Z","events":[]}' >"$DRIFT_JSON" ORCA_DRIFT_AGG_JSON="$DRIFT_JSON" run "$PULL" --txn-dir "$TMP_TXN" --namespace default assert_status 0 "$status" } @test "orca-pull.sh drift gate --force overrides (R-020)" { # Create drift, then apply with --force --i-understand-the-risk. mkdir -p "$TMP_TXN/state" DRIFT_JSON="$TMP_TXN/state/drift-events-aggregated.json" cat >"$DRIFT_JSON" <"$DRIFT_JSON" <"$DRIFT_JSON" <