From 909b21be04865da56f76b1ac5416c1bc97ba73d2 Mon Sep 17 00:00:00 2001 From: Craig Jennings Date: Wed, 1 Jul 2026 21:40:11 -0400 Subject: fix(sweep): recognize anchored /.ai/ style; warn on publicly reachable tooling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sweep-gitignore-tooling.sh decided gitignore-mode with an exact unanchored match on `.ai/`, so a project using the anchored `/.ai/` form was misclassified as track-mode and silently skipped — which left .emacs.d's tracked tooling on a public GitHub mirror until its 2026-06-30 scrub. Both forms now count for mode detection and per-pattern presence, and appended lines follow whichever style the file already uses. Track-mode projects also get a new check: tracked tooling paths combined with a non-cjennings.net remote draw a loud WARN, since a track-mode repo on a public host is the exposure the convention exists to prevent. The convention itself is now written down in protocols.org: a non-cjennings.net remote means the tooling set is gitignored, a deliberate team-shared config being the only explicit exception, and a private remote is not proof of privacy because a server-side mirror hook republishes invisibly. From the .emacs.d handoff (2026-06-30 tooling-exposure broadcast). --- scripts/tests/sweep-gitignore-tooling.bats | 67 ++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) (limited to 'scripts/tests/sweep-gitignore-tooling.bats') diff --git a/scripts/tests/sweep-gitignore-tooling.bats b/scripts/tests/sweep-gitignore-tooling.bats index a28087e..6dc46ee 100644 --- a/scripts/tests/sweep-gitignore-tooling.bats +++ b/scripts/tests/sweep-gitignore-tooling.bats @@ -109,3 +109,70 @@ make_project() { [ "$status" -eq 0 ] [[ "$output" == *"not a git checkout"* ]] } + +@test "sweep: anchored /.ai/ is recognized as gitignore-mode, appends anchored" { + make_project anchored $'/.ai/\n' + + run bash "$SWEEP" "$ROOT" + + [ "$status" -eq 0 ] + [[ "$output" != *"anchored — track-mode"* ]] + grep -qFx "/.claude/" "$ROOT/anchored/.gitignore" + grep -qFx "/CLAUDE.md" "$ROOT/anchored/.gitignore" + grep -qFx "/AGENTS.md" "$ROOT/anchored/.gitignore" +} + +@test "sweep: anchored partial project gets only the missing lines" { + make_project anchoredpartial $'/.ai/\n/.claude/\n' + + run bash "$SWEEP" "$ROOT" + + [ "$status" -eq 0 ] + # /.claude/ already present in anchored form — not re-added in either form. + [ "$(grep -cFx '/.claude/' "$ROOT/anchoredpartial/.gitignore")" -eq 1 ] + ! grep -qFx ".claude/" "$ROOT/anchoredpartial/.gitignore" + grep -qFx "/CLAUDE.md" "$ROOT/anchoredpartial/.gitignore" + grep -qFx "/AGENTS.md" "$ROOT/anchoredpartial/.gitignore" +} + +@test "sweep: anchored gitignore-mode is idempotent" { + make_project anchored2 $'/.ai/\n' + bash "$SWEEP" "$ROOT" >/dev/null + + run bash "$SWEEP" "$ROOT" + + [ "$status" -eq 0 ] + [[ "$output" == *"already complete"* ]] + [ "$(grep -cFx '/.claude/' "$ROOT/anchored2/.gitignore")" -eq 1 ] +} + +@test "sweep: track-mode with tracked tooling and a non-cjennings.net remote warns" { + make_project publictrack $'out/\n' + echo "# project rules" > "$ROOT/publictrack/CLAUDE.md" + (cd "$ROOT/publictrack" \ + && git add CLAUDE.md \ + && git -c user.email=t@t -c user.name=t commit -qm seed \ + && git remote add origin git@github.com:someone/publictrack.git) + + run bash "$SWEEP" "$ROOT" + + [ "$status" -eq 0 ] + [[ "$output" == *"WARN"* ]] + [[ "$output" == *"publicly reachable"* ]] + # Still track-mode: nothing written to its .gitignore. + ! grep -qFx ".claude/" "$ROOT/publictrack/.gitignore" +} + +@test "sweep: track-mode with tracked tooling on a cjennings.net remote stays quiet" { + make_project privatetrack $'out/\n' + echo "# project rules" > "$ROOT/privatetrack/CLAUDE.md" + (cd "$ROOT/privatetrack" \ + && git add CLAUDE.md \ + && git -c user.email=t@t -c user.name=t commit -qm seed \ + && git remote add origin git@cjennings.net:privatetrack.git) + + run bash "$SWEEP" "$ROOT" + + [ "$status" -eq 0 ] + [[ "$output" != *"publicly reachable"* ]] +} -- cgit v1.2.3