#!/usr/bin/env bash # Tests for scripts/check-executables-allow-sync.sh — the pre-push gate that # keeps root apm.yml's executables.allow key level with kyberforge's version. # # Fixtures are two-file skeletons (root apm.yml + plugins/kyberforge/apm.yml) # rather than copies of the real repo: the gate reads exactly those two files, # and a hand-built fixture is the only way to construct the drift it exists to # catch without editing the real manifests. set -euo pipefail REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" SCRIPT="$REPO_ROOT/scripts/check-executables-allow-sync.sh" PASS=0 FAIL=0 pass() { echo " PASS: $1"; PASS=$((PASS + 1)); } fail() { echo " FAIL: $1"; FAIL=$((FAIL + 1)); } # Same `exit 77` (automake convention; run-tests.sh renders it as SKIPPED) guard # the vale suites use. The script itself runs fine without python3 — it falls # back to a shape scan — but this suite asserts BOTH readers agree, and the # PyYAML path cannot be exercised at all on a machine without it. Reporting # those cases as failures would say "a regression landed" when the truth is # "this machine is missing a dev dependency". command -v python3 > /dev/null 2>&1 || { echo "SKIP: python3 is required to exercise the PyYAML reader"; exit 77; } python3 -c 'import yaml' > /dev/null 2>&1 || { echo "SKIP: PyYAML is required to exercise the PyYAML reader"; exit 77; } FIXTURES=() cleanup() { [[ ${#FIXTURES[@]} -eq 0 ]] || rm -rf "${FIXTURES[@]}"; } trap cleanup EXIT # make_fixture # The executables block is passed verbatim (may be empty) so a fixture can omit # it entirely, which is one of the failure modes under test. make_fixture() { local version_line="$1" executables_block="$2" dir dir="$(mktemp -d)" FIXTURES+=("$dir") mkdir -p "$dir/plugins/kyberforge" { echo "name: kyberforge" echo "$version_line" echo "description: fixture" } > "$dir/plugins/kyberforge/apm.yml" { echo "name: ai-development" echo "version: 0.0.1" echo "dependencies:" echo " apm:" echo " - name: kyberforge" [[ -n "$executables_block" ]] && printf '%s\n' "$executables_block" # A top-level key after the block: the fallback reader must stop collecting # allow keys here rather than reading on into the next section. echo "marketplace:" echo " owner:" echo " name: fixture" } > "$dir/apm.yml" printf '%s\n' "$dir" } MATCHING_BLOCK='executables: allow: kyberforge#1.5.0: hooks: true bin: true' STALE_BLOCK='executables: allow: kyberforge#1.4.0: hooks: true bin: true' OTHER_PACKAGE_BLOCK='executables: allow: git#1.0.0: hooks: true' # run_gate — echoes combined output, sets GATE_RC. GATE_RC=0 run_gate() { GATE_RC=0 bash "$SCRIPT" "$1" > /dev/null 2>&1 || GATE_RC=$? } # --------------------------------------------------------------------------- echo "--- the real repo passes ---" # --------------------------------------------------------------------------- # The gate's whole value is that it is green on a correct tree and red on drift; # a version bump landing in only one of the two real manifests must show up here. run_gate "$REPO_ROOT" [[ $GATE_RC -eq 0 ]] && pass "current repo state passes" \ || fail "current repo state should pass — the gate said: $(bash "$SCRIPT" "$REPO_ROOT" 2>&1 | head -3)" # --------------------------------------------------------------------------- echo "" echo "--- matching version ---" # --------------------------------------------------------------------------- F="$(make_fixture "version: 1.5.0" "$MATCHING_BLOCK")" run_gate "$F" [[ $GATE_RC -eq 0 ]] && pass "exits 0 when the allow key names the plugin's version" \ || fail "should pass when key and version agree, got rc=$GATE_RC" F="$(make_fixture 'version: "1.5.0"' "$MATCHING_BLOCK")" run_gate "$F" [[ $GATE_RC -eq 0 ]] && pass "exits 0 when the version is quoted" \ || fail "a quoted version must compare the same as an unquoted one, got rc=$GATE_RC" # --------------------------------------------------------------------------- echo "" echo "--- mismatched version ---" # --------------------------------------------------------------------------- F="$(make_fixture "version: 1.5.0" "$STALE_BLOCK")" run_gate "$F" [[ $GATE_RC -ne 0 ]] && pass "fails when the allow key names a different version" \ || fail "a stale allow key must fail the push" OUT="$(bash "$SCRIPT" "$F" 2>&1 || true)" grep -q "kyberforge#1.5.0" <<< "$OUT" && pass "names the key that should be there" \ || fail "the failure must state the expected key" grep -q "kyberforge#1.4.0" <<< "$OUT" && pass "names the stale key it found instead" \ || fail "the failure must quote back the stale key" grep -q "Why:" <<< "$OUT" && grep -q "Fix:" <<< "$OUT" && pass "uses the FAIL/Why/Fix message block" \ || fail "message must carry Why: and Fix: lines" # --------------------------------------------------------------------------- echo "" echo "--- missing executables.allow ---" # --------------------------------------------------------------------------- F="$(make_fixture "version: 1.5.0" "")" run_gate "$F" [[ $GATE_RC -ne 0 ]] && pass "fails when there is no executables block at all" \ || fail "a missing executables.allow must fail — apm deploys no hooks without it" OUT="$(bash "$SCRIPT" "$F" 2>&1 || true)" grep -q "executables:" <<< "$OUT" && grep -q "kyberforge#1.5.0" <<< "$OUT" \ && pass "shows the block to add" || fail "the failure must show the block to add" # An `executables:` key that is not a mapping is the same hole as no key at all. F="$(make_fixture "version: 1.5.0" "executables:")" run_gate "$F" [[ $GATE_RC -ne 0 ]] && pass "fails when executables: exists but allow: does not" \ || fail "an empty executables: block grants nothing and must fail" # --------------------------------------------------------------------------- echo "" echo "--- allow present, kyberforge key missing ---" # --------------------------------------------------------------------------- F="$(make_fixture "version: 1.5.0" "$OTHER_PACKAGE_BLOCK")" run_gate "$F" [[ $GATE_RC -ne 0 ]] && pass "fails when allow: exists but names no kyberforge key" \ || fail "an allow block covering only other packages must still fail" # --------------------------------------------------------------------------- echo "" echo "--- degenerate inputs fail loudly rather than passing silently ---" # --------------------------------------------------------------------------- run_gate "$REPO_ROOT/definitely-not-a-directory" [[ $GATE_RC -ne 0 ]] && pass "fails on a nonexistent REPO_ROOT" \ || fail "a bad path must not exit 0 — that reads as 'checked, in sync'" # No kyberforge plugin at all is the one legitimate no-op: nothing to pin. NO_PLUGIN="$(mktemp -d)"; FIXTURES+=("$NO_PLUGIN") echo "name: someone-else" > "$NO_PLUGIN/apm.yml" run_gate "$NO_PLUGIN" [[ $GATE_RC -eq 0 ]] && pass "no-ops in a repo with no kyberforge plugin" \ || fail "a repo without plugins/kyberforge/ has nothing to check" # ...but a kyberforge directory with no manifest is drift, not a no-op. mkdir -p "$NO_PLUGIN/plugins/kyberforge" run_gate "$NO_PLUGIN" [[ $GATE_RC -ne 0 ]] && pass "fails when plugins/kyberforge/ has no apm.yml" \ || fail "a plugin dir with no manifest must not silently pass" F="$(make_fixture "description: no version here" "$MATCHING_BLOCK")" run_gate "$F" [[ $GATE_RC -ne 0 ]] && pass "fails when the plugin manifest declares no version" \ || fail "no version means nothing to compare — must fail, not pass" # --------------------------------------------------------------------------- echo "" echo "--- the fallback reader agrees with the PyYAML reader ---" # --------------------------------------------------------------------------- # PyYAML is deliberately not a hard dependency of this gate (no other pre-push # hook needs it), so the shape-scan fallback carries the same verdicts. Masking # is done with a python3 stub whose `import yaml` fails, which is the exact # condition on a machine that has python3 without PyYAML. NO_YAML_BIN="$(mktemp -d)"; FIXTURES+=("$NO_YAML_BIN") printf '#!/usr/bin/env bash\nexit 1\n' > "$NO_YAML_BIN/python3" chmod +x "$NO_YAML_BIN/python3" run_fallback() { GATE_RC=0 PATH="$NO_YAML_BIN:$PATH" bash "$SCRIPT" "$1" > /dev/null 2>&1 || GATE_RC=$? } F="$(make_fixture "version: 1.5.0" "$MATCHING_BLOCK")" run_fallback "$F" [[ $GATE_RC -eq 0 ]] && pass "fallback passes a matching fixture" || fail "fallback should pass when in sync" F="$(make_fixture 'version: "1.5.0"' "$MATCHING_BLOCK")" run_fallback "$F" [[ $GATE_RC -eq 0 ]] && pass "fallback strips quotes from the version" || fail "fallback mishandled a quoted version" F="$(make_fixture "version: 1.5.0" "$STALE_BLOCK")" run_fallback "$F" [[ $GATE_RC -ne 0 ]] && pass "fallback fails a stale key" || fail "fallback missed a stale key" F="$(make_fixture "version: 1.5.0" "")" run_fallback "$F" [[ $GATE_RC -ne 0 ]] && pass "fallback fails a missing executables block" || fail "fallback missed a missing block" F="$(make_fixture "version: 1.5.0" "$OTHER_PACKAGE_BLOCK")" run_fallback "$F" [[ $GATE_RC -ne 0 ]] && pass "fallback fails when no kyberforge key is present" || fail "fallback missed an absent key" run_fallback "$REPO_ROOT" [[ $GATE_RC -eq 0 ]] && pass "fallback passes the real repo" || fail "fallback disagrees with PyYAML on the real repo" # --------------------------------------------------------------------------- echo "" echo "--- wired into the pre-push gate ---" # --------------------------------------------------------------------------- # A gate nobody runs is not a gate; this is the only assertion that the script # is actually reachable from `git push`. CONFIG="$REPO_ROOT/.pre-commit-config.yaml" grep -q "id: check-executables-allow-sync" "$CONFIG" \ && pass ".pre-commit-config.yaml declares the hook" || fail "hook is not declared in .pre-commit-config.yaml" grep -q "scripts/check-executables-allow-sync.sh" "$CONFIG" \ && pass ".pre-commit-config.yaml points at the script" || fail "hook does not reference the script path" # --------------------------------------------------------------------------- echo "" echo "Results: $PASS passed, $FAIL failed" [[ $FAIL -eq 0 ]]