reinject_mcp_servers copied .mcp.json's mcpServers into the compiled Copilot
manifest verbatim via jq. apm's own path does not: collect_mcp_servers runs
_sanitize_mcp_servers(), which drops env/headers/authorization and redacts
secret-shaped keys, because copying them into a committed manifest exfiltrates
them into the distributed artefact. The re-injection was the only route around
that sanitizer, and it wrote to a tracked, marketplace-distributed file.
Both host schemas document mcpServers as "string or object -- config path or
inline definitions", so the pointer form is valid and carries no resolved
content. It also preserves the ${VAR} indirection the sanitizer strips.
Also in this pass:
- mktemp+mv left the manifest at 0600 while --check compared content only, so
a real sync silently demoted a mode the gate could not see
- --check --all exited 0 when the marketplace yielded zero plugins, including
on unparseable JSON: the one gate whose work list comes from a generated file
could be silenced by regenerating its own input
- sync_dir took an unguarded $target_dir despite a comment claiming otherwise
- basename '.'/'..' escaped $SCRATCH_ROOT and made bundle selection arbitrary
- path_manifest compared only the exec bit, so check and sync disagreed
- sync-marketplace-mirror.sh fell back to pwd outside a worktree and reported
no drift on a tree it never identified
Mode comparison is deliberately files-only: directory modes come from umask on
one side and checkout on the other and git tracks neither, so comparing them
reports the runner's umask rather than a property of the mirror.
Tests: 44 -> 67 and 15 -> 19 assertions, each verified to fail under the
mutation it exists to catch.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X7GvKuJfy2WrdBmUttV4DT
305 lines
13 KiB
Bash
Executable File
305 lines
13 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
SCRIPT="$REPO_ROOT/scripts/sync-marketplace-mirror.sh"
|
|
PASS=0
|
|
FAIL=0
|
|
|
|
pass() { echo " PASS: $1"; PASS=$((PASS + 1)); }
|
|
fail() { echo " FAIL: $1"; FAIL=$((FAIL + 1)); }
|
|
|
|
# Fixture: a temp directory that is its own git worktree. Since
|
|
# scripts/sync-marketplace-mirror.sh resolves REPO_ROOT via
|
|
# `git rev-parse --show-toplevel 2>/dev/null || pwd`, isolation has to come
|
|
# from that call answering "the fixture" -- so the fixture owns a real .git.
|
|
#
|
|
# Relying instead on `git rev-parse` FAILING inside a bare `mktemp -d` (its
|
|
# previous form) is not isolation: two ordinary conditions make it succeed and
|
|
# resolve to the LIVE repo, at which point every test writes to this repo's own
|
|
# tracked .github/plugin/marketplace.json. Both are reproduced and fixed here:
|
|
# - TMPDIR pointing inside a git worktree, which puts the fixture in one.
|
|
# - An inherited GIT_DIR/GIT_WORK_TREE, which re-targets `git -C` and
|
|
# `git rev-parse` regardless of cwd. tests/run-tests.sh is itself a pre-push
|
|
# hook, and git hooks export exactly those variables -- the same leak
|
|
# tests/test-git-hooks-install.sh:6-10 already defends against.
|
|
# run_script() strips GIT_DIR/GIT_WORK_TREE for the second; `git init` here
|
|
# covers the first and makes the resolution positive rather than accidental.
|
|
# run-tests.sh:52-53 asserts no test writes back into the live repo tree, and
|
|
# that claim now carries the concurrent runner.
|
|
make_fixture() {
|
|
local dir
|
|
dir="$(mktemp -d)"
|
|
# Physical path: `git rev-parse --show-toplevel` reports the resolved path,
|
|
# and on macOS `mktemp -d` hands back one under the /tmp -> /private/tmp
|
|
# symlink. Without -P the script's REPO_ROOT and the assertions' $FIXTURE
|
|
# would name the same directory differently and every diff would compare
|
|
# against a path the script never wrote.
|
|
dir="$(cd "$dir" && pwd -P)"
|
|
# Checked, not best-effort: this init IS the isolation invariant. `echo "$dir"`
|
|
# is the last statement, so a silently-failed init would return a plain temp
|
|
# dir, `git rev-parse --show-toplevel` would walk up to whatever repo encloses
|
|
# it, and the suite would go back to writing into the live tree.
|
|
if ! env -u GIT_DIR -u GIT_WORK_TREE git -C "$dir" init -q >/dev/null 2>&1; then
|
|
echo "make_fixture: 'git init' failed in $dir — every test would then resolve REPO_ROOT to an enclosing repo and write outside the fixture" >&2
|
|
exit 1
|
|
fi
|
|
echo "$dir"
|
|
}
|
|
|
|
SRC_REL=".claude-plugin/marketplace.json"
|
|
DST_REL=".github/plugin/marketplace.json"
|
|
CONTENT_A='{"plugins":[{"name":"demo","version":"1.0.0"}]}'
|
|
CONTENT_B='{"plugins":[{"name":"demo","version":"2.0.0"}]}'
|
|
|
|
write_src() {
|
|
local dir="$1" content="$2"
|
|
mkdir -p "$dir/.claude-plugin"
|
|
printf '%s' "$content" > "$dir/$SRC_REL"
|
|
}
|
|
|
|
write_dst() {
|
|
local dir="$1" content="$2"
|
|
mkdir -p "$dir/.github/plugin"
|
|
printf '%s' "$content" > "$dir/$DST_REL"
|
|
}
|
|
|
|
# `env -u GIT_DIR -u GIT_WORK_TREE` mirrors tests/test-git-hooks-install.sh:10:
|
|
# under a git hook (run-tests.sh runs as pre-push) those are exported, and the
|
|
# script's `git rev-parse --show-toplevel` would then answer with the LIVE repo
|
|
# no matter which directory it was invoked from.
|
|
run_script() {
|
|
local dir="$1"
|
|
shift
|
|
(cd "$dir" && env -u GIT_DIR -u GIT_WORK_TREE bash "$SCRIPT" "$@")
|
|
}
|
|
|
|
CLEANUP_DIRS=()
|
|
trap 'rm -rf ${CLEANUP_DIRS[@]+"${CLEANUP_DIRS[@]}"}' EXIT
|
|
track() { CLEANUP_DIRS+=("$1"); }
|
|
|
|
# --- 1. No .claude-plugin/marketplace.json at all: real-sync mode is a no-op, exit 0 ---
|
|
echo ""
|
|
echo "--- missing source: real sync exits 0 and creates nothing ---"
|
|
FIXTURE1="$(make_fixture)"; track "$FIXTURE1"
|
|
if run_script "$FIXTURE1" > /dev/null 2>&1 && [[ ! -e "$FIXTURE1/$DST_REL" ]]; then
|
|
pass "missing source exits 0 in real-sync mode without creating a mirror"
|
|
else
|
|
fail "missing source should exit 0 and create nothing in real-sync mode"
|
|
fi
|
|
|
|
# --- 2. No source: --check mode is also a no-op, exit 0 (nothing to drift-check) ---
|
|
echo ""
|
|
echo "--- missing source: --check exits 0 (nothing to compare) ---"
|
|
FIXTURE2="$(make_fixture)"; track "$FIXTURE2"
|
|
if run_script "$FIXTURE2" --check > /dev/null 2>&1; then
|
|
pass "missing source exits 0 in --check mode"
|
|
else
|
|
fail "missing source should exit 0 in --check mode, not report drift"
|
|
fi
|
|
|
|
# --- 2b. Source missing but a mirror still present: --check must FAIL ---
|
|
# --check used to exit 0 on any missing source, so deleting
|
|
# .claude-plugin/marketplace.json left a stale .github/plugin/marketplace.json
|
|
# reported as "no drift" -- a mirror of a file that no longer exists. That is
|
|
# the silent divergence this script's header says it prevents ("keeps that
|
|
# legacy mirror byte-identical ... instead of letting it silently drift"), and
|
|
# scripts/sync-plugin-content.sh --check --all already errors on the same
|
|
# condition. Case 2 above still holds: neither file present stays a no-op.
|
|
echo ""
|
|
echo "--- missing source with a surviving mirror: --check reports drift ---"
|
|
FIXTURE2B="$(make_fixture)"; track "$FIXTURE2B"
|
|
write_dst "$FIXTURE2B" "$CONTENT_A"
|
|
if run_script "$FIXTURE2B" --check > /dev/null 2>&1; then
|
|
fail "exited 0 with a stale mirror and no source -- expected drift (exit 1)"
|
|
else
|
|
pass "a mirror with no source left to mirror is reported as drift"
|
|
fi
|
|
# Real-sync mode keeps its no-op: it has nothing to copy, and deleting a
|
|
# tracked file is not this script's call to make.
|
|
if run_script "$FIXTURE2B" > /dev/null 2>&1 && [[ -f "$FIXTURE2B/$DST_REL" ]]; then
|
|
pass "real-sync mode still no-ops on a missing source, leaving the mirror alone"
|
|
else
|
|
fail "real-sync mode should no-op on a missing source, not fail or delete the mirror"
|
|
fi
|
|
|
|
# --- 3. Source exists, mirror missing entirely: --check reports drift (exit 1) ---
|
|
echo ""
|
|
echo "--- --check reports drift when the mirror file does not exist yet ---"
|
|
FIXTURE3="$(make_fixture)"; track "$FIXTURE3"
|
|
write_src "$FIXTURE3" "$CONTENT_A"
|
|
if run_script "$FIXTURE3" --check > /dev/null 2>&1; then
|
|
fail "exited 0 with no mirror file present -- expected drift (exit 1)"
|
|
else
|
|
pass "missing mirror file is reported as drift"
|
|
fi
|
|
|
|
# --- 4. Real sync creates the mirror (and its parent dir) byte-identical to the source ---
|
|
echo ""
|
|
echo "--- real sync creates .github/plugin/marketplace.json byte-identical to source ---"
|
|
FIXTURE4="$(make_fixture)"; track "$FIXTURE4"
|
|
write_src "$FIXTURE4" "$CONTENT_A"
|
|
if run_script "$FIXTURE4" > /dev/null 2>&1 \
|
|
&& [[ -f "$FIXTURE4/$DST_REL" ]] \
|
|
&& diff -q "$FIXTURE4/$SRC_REL" "$FIXTURE4/$DST_REL" > /dev/null 2>&1; then
|
|
pass "real sync creates the mirror file identical to the source"
|
|
else
|
|
fail "real sync did not create a byte-identical mirror file"
|
|
fi
|
|
|
|
# --- 5. --check is clean immediately after a real sync ---
|
|
echo ""
|
|
echo "--- --check is clean right after syncing ---"
|
|
if run_script "$FIXTURE4" --check > /dev/null 2>&1; then
|
|
pass "no drift reported immediately after syncing"
|
|
else
|
|
fail "drift reported right after syncing -- sync and check disagree"
|
|
fi
|
|
|
|
# --- 6. Editing the source after a sync introduces drift; re-sync clears it ---
|
|
echo ""
|
|
echo "--- source edited after sync is detected as drift, cleared by re-sync ---"
|
|
write_src "$FIXTURE4" "$CONTENT_B"
|
|
if run_script "$FIXTURE4" --check > /dev/null 2>&1; then
|
|
fail "no drift reported after editing the source -- expected drift"
|
|
else
|
|
pass "editing the source after a sync is detected as drift"
|
|
run_script "$FIXTURE4" > /dev/null 2>&1
|
|
if run_script "$FIXTURE4" --check > /dev/null 2>&1; then
|
|
pass "re-sync clears the drift"
|
|
else
|
|
fail "re-sync did not clear the drift"
|
|
fi
|
|
fi
|
|
|
|
# --- 7. A mirror that was hand-seeded already identical to the source: --check is clean ---
|
|
echo ""
|
|
echo "--- --check is clean when the mirror already matches, without ever syncing ---"
|
|
FIXTURE7="$(make_fixture)"; track "$FIXTURE7"
|
|
write_src "$FIXTURE7" "$CONTENT_A"
|
|
write_dst "$FIXTURE7" "$CONTENT_A"
|
|
if run_script "$FIXTURE7" --check > /dev/null 2>&1; then
|
|
pass "an already-in-sync mirror reports no drift"
|
|
else
|
|
fail "an already-in-sync mirror should report no drift"
|
|
fi
|
|
|
|
# --- 8. A stale, pre-existing mirror that differs from source: --check flags it, sync fixes it ---
|
|
echo ""
|
|
echo "--- a stale pre-existing mirror is flagged by --check and overwritten by sync ---"
|
|
FIXTURE8="$(make_fixture)"; track "$FIXTURE8"
|
|
write_src "$FIXTURE8" "$CONTENT_A"
|
|
write_dst "$FIXTURE8" "$CONTENT_B"
|
|
if run_script "$FIXTURE8" --check > /dev/null 2>&1; then
|
|
fail "a stale mirror was not flagged as drift"
|
|
else
|
|
pass "a stale pre-existing mirror is flagged as drift"
|
|
fi
|
|
run_script "$FIXTURE8" > /dev/null 2>&1
|
|
if diff -q "$FIXTURE8/$SRC_REL" "$FIXTURE8/$DST_REL" > /dev/null 2>&1; then
|
|
pass "real sync overwrites the stale mirror to match the source"
|
|
else
|
|
fail "real sync did not overwrite the stale mirror"
|
|
fi
|
|
|
|
# --- 9. An unknown/extra positional argument is rejected with a usage error ---
|
|
echo ""
|
|
echo "--- an unrecognized argument is rejected (usage, exit 1) ---"
|
|
FIXTURE9="$(make_fixture)"; track "$FIXTURE9"
|
|
write_src "$FIXTURE9" "$CONTENT_A"
|
|
if run_script "$FIXTURE9" --bogus > /dev/null 2>&1; then
|
|
fail "exited 0 with an unrecognized argument -- expected a usage error"
|
|
else
|
|
pass "an unrecognized argument is rejected"
|
|
fi
|
|
|
|
# --- 10. --check followed by a stray extra argument is also rejected ---
|
|
echo ""
|
|
echo "--- --check plus a trailing extra argument is rejected (usage, exit 1) ---"
|
|
if run_script "$FIXTURE9" --check extra > /dev/null 2>&1; then
|
|
fail "exited 0 with --check plus a trailing argument -- expected a usage error"
|
|
else
|
|
pass "--check plus a trailing extra argument is rejected"
|
|
fi
|
|
|
|
# --- 11. Real sync is idempotent: running it twice in a row leaves the mirror unchanged ---
|
|
echo ""
|
|
echo "--- running real sync twice in a row is idempotent ---"
|
|
FIXTURE11="$(make_fixture)"; track "$FIXTURE11"
|
|
write_src "$FIXTURE11" "$CONTENT_A"
|
|
run_script "$FIXTURE11" > /dev/null 2>&1
|
|
run_script "$FIXTURE11" > /dev/null 2>&1
|
|
if run_script "$FIXTURE11" --check > /dev/null 2>&1; then
|
|
pass "running sync twice in a row is idempotent"
|
|
else
|
|
fail "a second sync run introduced unexpected drift"
|
|
fi
|
|
|
|
# --- 12. Fixture isolation survives an inherited GIT_DIR/GIT_WORK_TREE ---
|
|
# The whole suite's isolation is REPO_ROOT resolving to the fixture. With
|
|
# GIT_DIR/GIT_WORK_TREE exported -- which is every git-hook context, and
|
|
# run-tests.sh runs as pre-push -- `git rev-parse --show-toplevel` answers with
|
|
# THAT repo from any cwd, so the script wrote to the live tree and 5 of these
|
|
# cases failed. Point both variables at a decoy repo (never the live one, so
|
|
# this assertion cannot itself write where it must not) and assert the fixture
|
|
# still wins: the mirror lands in the fixture and the decoy stays untouched.
|
|
echo ""
|
|
echo "--- fixture isolation holds with GIT_DIR/GIT_WORK_TREE inherited from elsewhere ---"
|
|
FIXTURE12="$(make_fixture)"; track "$FIXTURE12"
|
|
DECOY="$(make_fixture)"; track "$DECOY"
|
|
write_src "$FIXTURE12" "$CONTENT_A"
|
|
if (export GIT_DIR="$DECOY/.git" GIT_WORK_TREE="$DECOY"; run_script "$FIXTURE12" > /dev/null 2>&1) \
|
|
&& [[ -f "$FIXTURE12/$DST_REL" ]] && [[ ! -e "$DECOY/$DST_REL" ]]; then
|
|
pass "an inherited GIT_DIR/GIT_WORK_TREE does not redirect writes out of the fixture"
|
|
else
|
|
fail "an inherited GIT_DIR/GIT_WORK_TREE redirected the sync outside the fixture"
|
|
fi
|
|
|
|
# --- 13. Outside any git worktree, REPO_ROOT cannot be guessed: hard error ---
|
|
# `git rev-parse --show-toplevel 2>/dev/null || pwd` used to fall back to $PWD.
|
|
# Both of this script's exit-0 paths are "the two files agree" or "neither file
|
|
# exists", so a REPO_ROOT that is not this repo reports "no drift" over a tree it
|
|
# never inspected — run --check from an empty non-worktree directory and that was
|
|
# the literal outcome. Case 2 above (a real worktree with no source file) still
|
|
# exits 0; the difference is whether the tree was identified at all.
|
|
#
|
|
# GIT_CEILING_DIRECTORIES rather than trusting `mktemp -d` to land outside a
|
|
# worktree: TMPDIR may itself sit inside one (the same hazard make_fixture's
|
|
# header documents), in which case rev-parse would succeed and this case would
|
|
# quietly test nothing. The ceiling stops git's upward walk at the fixture's
|
|
# parent, and the precondition below asserts it actually did.
|
|
echo ""
|
|
echo "--- outside a git worktree, --check errors instead of guessing \$PWD ---"
|
|
NOREPO_PARENT="$(mktemp -d)"; track "$NOREPO_PARENT"
|
|
NOREPO_PARENT="$(cd "$NOREPO_PARENT" && pwd -P)"
|
|
NOREPO="$NOREPO_PARENT/not-a-worktree"
|
|
mkdir -p "$NOREPO"
|
|
if (cd "$NOREPO" && env -u GIT_DIR -u GIT_WORK_TREE GIT_CEILING_DIRECTORIES="$NOREPO_PARENT" \
|
|
git rev-parse --show-toplevel > /dev/null 2>&1); then
|
|
fail "precondition: git rev-parse still resolves a worktree under the ceiling — this case would test nothing"
|
|
else
|
|
for MODE in "--check" ""; do
|
|
RC13=0
|
|
OUT13="$( (cd "$NOREPO" && env -u GIT_DIR -u GIT_WORK_TREE \
|
|
GIT_CEILING_DIRECTORIES="$NOREPO_PARENT" bash "$SCRIPT" ${MODE:+"$MODE"}) 2>&1 )" || RC13=$?
|
|
case "$RC13:$OUT13" in
|
|
0:*)
|
|
fail "'${MODE:-real sync}' exited 0 outside a git worktree — it reported on a tree it never identified" ;;
|
|
*"not inside a git worktree"*)
|
|
pass "'${MODE:-real sync}' errors with a not-a-worktree message instead of falling back to \$PWD" ;;
|
|
*)
|
|
fail "'${MODE:-real sync}' failed for an unexpected reason (rc=$RC13): $OUT13" ;;
|
|
esac
|
|
done
|
|
# And it must not have written anything into the directory it refused to trust.
|
|
if [[ ! -e "$NOREPO/.github" ]]; then
|
|
pass "nothing is written into the unidentified directory"
|
|
else
|
|
fail "the script created files under a directory it could not identify as the repo root"
|
|
fi
|
|
fi
|
|
|
|
echo ""
|
|
echo "Results: $PASS passed, $FAIL failed"
|
|
[[ $FAIL -eq 0 ]]
|