Skip to content

Block the e2e stack targets, not just the ones that run the suite - #3

Merged
pysnooLab merged 1 commit into
mainfrom
fix/e2e-guard-covers-stack
Aug 5, 2026
Merged

Block the e2e stack targets, not just the ones that run the suite#3
pysnooLab merged 1 commit into
mainfrom
fix/e2e-guard-covers-stack

Conversation

@pysnooLab

Copy link
Copy Markdown
Collaborator

Problem

Found by the first real migration onto the plugin (atomic-crm#343). Asked to run the e2e suite, an agent reached for:

make start-e2e 2>&1 | tail -30

The guard allowed it, because the e2e category only knew the commands that run the suite (npx playwright test, make test-e2e, e2e-smoke.sh), not the ones that bring the stack up. Three things go wrong at once, and the first one costs a session:

  • It never returns. start-app-e2e backgrounds the dev server with &, the server inherits stdout, and tail waits for an EOF a live process never sends. It looks frozen; it is deterministic.
  • It destroys data. start-supabase-e2e does rm -rf on the e2e database directory before recreating it, so an agent running it wipes a human's e2e session out from under them.
  • It defeats the isolation. It brings up the shared stack on the fixed ports, which is exactly what the slot-leased isolated stack in e2e-smoke.sh replaces, and what the slot offset added earlier was protecting.

Solution

The matcher keys on the e2e token in a make target instead of enumerating targets, so start / stop / test / supabase variants are all covered and the pattern does not grow a per-project list:

/(npx\s+playwright\s+test|make\s+[\w:-]*e2e|e2e-smoke\.sh)/

Still config-driven: drop "e2e" from validation.extraForbidden and none of it applies, same as any other category.

How to test

npm test

395 tests green, 8 new. Four pin the newly blocked commands, including the exact one observed (make start-e2e 2>&1 | tail -30). Four pin unrelated make targets that must stay allowed (make lint, make build, make install, make typecheck), so the broader token match cannot quietly swallow them.

Worth noting what this does not change: a human typing !make start-e2e still gets through, because PreToolUse hooks do not fire on user-typed shell commands. That is the intended split, the guard gates agents and not the person at the keyboard.

Found by running the first real migration: an agent asked to run the e2e suite reached for
`make start-e2e 2>&1 | tail -30`, which the guard allowed because it only knew the suite
runners, not the targets that bring the stack up.

Three things go wrong at once there, and the first is the one that wastes a session:

The command never returns. start-app-e2e backgrounds the dev server with `&`, the server
inherits stdout, and `tail` waits for an EOF that a live process never sends. It looks
frozen and it is not: it is deterministic.

It destroys data. start-supabase-e2e does `rm -rf` on the e2e database directory before
recreating it, so an agent running it wipes a human's e2e session out from under them.

It defeats the isolation. It brings up the SHARED stack on the fixed ports, which is
exactly what the slot-leased isolated stack exists to replace, and what the slot offset
added earlier was protecting.

The matcher now keys on the `e2e` token in a make target rather than enumerating targets,
so start / stop / test / supabase variants are all covered without the pattern growing a
per-project list. Tests pin the four new cases plus four unrelated make targets that must
stay allowed, so the broader match cannot quietly swallow `make lint`.
@pysnooLab
pysnooLab merged commit 0a1a40d into main Aug 5, 2026
2 checks passed
@pysnooLab
pysnooLab deleted the fix/e2e-guard-covers-stack branch August 5, 2026 09:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant