Files
holocron/tests/test-check-executables-allow-sync.sh
Defame1297 099cf5846c ci: gate the executables.allow key against kyberforge's version
apm approves a package's hooks and bin by an exact dictionary lookup on a
composed `name#version` key (apm_cli/security/executables.py,
is_package_approved). There is no wildcard and no version-less form, so
bumping plugins/kyberforge/apm.yml without editing root apm.yml's
`kyberforge#<version>` key errors nowhere: the entry stops matching, the
SessionStart hook stops deploying, and the install goes quietly stale.

ADR-0019 already named that as a live failure mode, mitigated only by a
comment in the executables block. This repo gates generated-content
drift, marketplace mirror drift and vale style drift deterministically,
and a silent-staleness failure is worse than any of them — a comment does
not survive the release that breaks it.

check-executables-allow-sync.sh parses the version out of the plugin
manifest and asserts the matching key exists in the root manifest. It
uses PyYAML where importable and falls back to a two-shape scan
otherwise, so a missing pip package cannot become the thing that blocks
every push; the test asserts both readers agree. 23 assertions.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X7GvKuJfy2WrdBmUttV4DT
2026-08-14 18:31:06 +00:00

244 lines
10 KiB
Bash

#!/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 <plugin-version-line> <root-executables-block>
# 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 <fixture> — 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 ]]