--- convoy: fix-auth-bypass brief_number: 3 depends_on: [] files: - .github/workflows/ci.yml - README.md deletes: - pages/api/simple.js - pages/api/test-auth.js - pages/api/test-db.js - pages/api/setup-database.js --- # Brief 3: Delete dev-only API endpoints + add CI guard ## Goal (1 sentence) Delete the four unauthenticated dev endpoints currently shipped to prod (`/api/simple`, `/api/test-auth`, `/api/test-db`, `/api/setup-database`) and add a CI grep step that fails the build if anyone re-introduces them. ## Files in scope (do not edit anything else) - `pages/api/simple.js` — **deleted** - `pages/api/test-auth.js` — **deleted** - `pages/api/test-db.js` — **deleted** - `pages/api/setup-database.js` — **deleted** - `.github/workflows/ci.yml` — modified (new job) - `README.md` — modified (one-line removal) ## Conventions to follow - `.cursor/rules/api-routes.mdc` § "Dev/test endpoints" — these files are explicitly called out as dev-only and slated for deletion. This brief executes that. - `.cursor/rules/no-go-zones.mdc` — none of these four files appear in the no-go list (they are not in `scripts/add-*` or any "append-only / historical" set). They are explicitly listed in the api-routes rule as "should be deleted." - `.github/workflows/ci.yml` formatting: 2-space indent, jobs go under the existing `jobs:` map, match the style of `lint:` and `schema-map-fresh:`. ## Acceptance criteria ### Deletions - [ ] `pages/api/simple.js` removed via `git rm`. - [ ] `pages/api/test-auth.js` removed via `git rm`. - [ ] `pages/api/test-db.js` removed via `git rm`. - [ ] `pages/api/setup-database.js` removed via `git rm`. - [ ] No grep hits for any of these paths anywhere in `pages/`, `components/`, `lib/`, or `scripts/`. Run before the PR: ```bash rg "/api/(simple|test-auth|test-db|setup-database)" --type js rg "(setup-database|test-auth|test-db|api/simple)" pages components lib scripts ``` Expected: zero hits in source. Doc references in `.cursor/rules/api-routes.mdc`, `AGENTS.md`, `.convoys/`, `docs/` are out of scope (doc-writer cleans them up later). ### `README.md` - [ ] Remove the line `- \`GET /api/test-db\` - Database connection test` (currently line 79). If the surrounding API list is short and now incomplete, leave it as-is — the doc-writer pass will rewrite that section. ### `.github/workflows/ci.yml` - [ ] Add a new job `forbidden-endpoints` after `schema-map-fresh:`. Verbatim shape: ```yaml forbidden-endpoints: name: No dev endpoints in pages/api runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Fail if dev endpoints re-appear under pages/api/ run: | BAD_PATHS=( "pages/api/simple.js" "pages/api/test-auth.js" "pages/api/test-db.js" "pages/api/setup-database.js" ) FOUND=() for path in "${BAD_PATHS[@]}"; do if [ -f "$path" ]; then FOUND+=("$path") fi done # Also flag any new pages/api/test-*.js the explicit list missed. while IFS= read -r path; do FOUND+=("$path") done < <(find pages/api -maxdepth 4 -type f -name 'test-*.js' 2>/dev/null || true) if [ ${#FOUND[@]} -gt 0 ]; then echo "::error::Forbidden dev endpoints present in pages/api/. Delete them or move to scripts/." for path in "${FOUND[@]}"; do echo "::error file=${path}::Forbidden dev endpoint." done exit 1 fi echo "OK: no forbidden dev endpoints under pages/api/." ``` - [ ] The job runs on `pull_request` and `push` (it inherits the workflow-level `on:` triggers — no per-job `on:` block needed). - [ ] No new `concurrency:` block (the workflow-level `concurrency:` is already set). - [ ] No `if:` conditional that lets this job skip on docs-only PRs. The check is fast (a `find` + 4 `[ -f ]` calls) and skipping it would defeat the purpose. - [ ] The job is **blocking** — no `|| true` wrapper, no `::warning` fallback. (Lint has the wrapper because of the documented `fix-lint-baseline` debt; this job is not subject to that.) ### Smoke - [ ] After deleting the files, `npm run build` succeeds (no broken imports — these endpoints are unreferenced, verified in the architect's audit). - [ ] `git grep -l 'api/simple\|test-auth\|test-db\|setup-database' pages components lib` returns no source files (only docs). - [ ] Locally, simulate the CI guard: ```bash bash -c ' BAD_PATHS=("pages/api/simple.js" "pages/api/test-auth.js" "pages/api/test-db.js" "pages/api/setup-database.js") FOUND=(); for p in "${BAD_PATHS[@]}"; do [ -f "$p" ] && FOUND+=("$p"); done [ ${#FOUND[@]} -eq 0 ] && echo OK || { echo "FAIL: ${FOUND[@]}"; exit 1; } ' ``` Expect `OK`. Then create a temporary `pages/api/test-fake.js` (matches `test-*.js` glob) and re-run — expect `FAIL`. Delete the temp file before opening the PR. ### Out of scope - [ ] No `pages/api/cards/import-*.js` deletion or gating. Those are admin-imports with rate-limit concerns; `add-rate-limiting` convoy. - [ ] No `pages/api/auth/*` changes — Brief 1 + Brief 2 + Brief 4 cover those. - [ ] No README rewrite of the API list — doc-writer pass. - [ ] No new test files — Brief 5. ## Rationale (≤3 sentences) These four files are the highest-impact deletions in the convoy: `pages/api/setup-database.js` is a public unauthenticated POST that triggers DDL, and the other three leak DB / auth internals to anyone who hits them. The CI guard is cheap insurance — without it, a future agent following an outdated tutorial could re-introduce `pages/api/test-db.js` in good faith. Keeping this brief tiny (deletions + one CI job + one README line) means it can ship in parallel with Briefs 1, 2, and 4 with no merge-conflict risk.