deckhearth/.convoys/fix-auth-bypass/brief-3-delete-dev-endpoints.md
Randall Stillwell f64a80ba2a docs: post-convoy cleanup for fix-auth-bypass
Closes out the fix-auth-bypass convoy (PRs #6–#11, merged through
1629afb) on the docs side. Code already on main; this PR is docs only.

Updates:

AGENTS.md
  - §1 auth bullet refreshed (auth-secret SoT, 24h TTL, no synthetic
    admin, login/register rate limit)
  - §3 conventions point at lib/auth-secret.js + lib/rate-limit.js
  - §4 gotchas #2/#3/#5 converted to "Resolved" notes in place
    (NOT renumbered, to preserve cross-references)
  - new #12 documents the KV_REST_API_* env-var convention
  - §5 setup list adds the rate-limit env vars
  - §6 testing rewritten for Vitest (16 unit tests, blocking CI gate)

.cursor/rules/auth-and-permissions.mdc
  - canonical-surface table gains lib/auth-secret.js + lib/rate-limit.js
  - token model now 24h (was 7d) with fail-loud explanation
  - server-side authorization patterns lead with null → 401 contract

.cursor/rules/api-routes.mdc
  - removes the "CRITICAL — known bug" callout (resolved by Brief 2)
  - adds a "Rate limiting" section with verbatim shape + env-var notes
  - "Dev/test endpoints" → "Removed" historical note so future agents
    searching for test-db understand why it's gone

.convoys/fix-auth-bypass.md (restored — was on convoy branch only)
  - frontmatter → status: shipped
  - new "Convoy outcome" section: briefs + commits + resolved gotchas,
    R1-R12 risk walk, env-var-rename deviation record, queued follow-up
    convoys, lessons learned

.convoys/fix-auth-bypass/brief-{1..5}-*.md (restored from convoy branch)
  - audit-trail completeness; convoy plan references them by name
  - brief 4 additionally updated: UPSTASH_REDIS_REST_* → KV_REST_API_*
    across init rules, smoke, pre-deploy checklist
  - brief 4 has a new "Post-merge addendum" explaining the rename

.convoys/ship-readiness.md
  - P0 #1, #2, #4 → RESOLVED with merge-commit citations
  - P0 #5 (CORS), #6 (rate limit) → PARTIAL with deferral pointers
    (cors-tighten and add-rate-limiting convoys)
  - each item gains an "As-shipped" line for self-containment

README.md
  - Next.js 15 → 16, TypeScript claim corrected to JS-with-devDep
  - auth + rate-limit + testing bullets updated
  - env-var template extended with KV_REST_API_*
  - deleted dev-endpoints note added to the API list
  - "Default Admin Account" section LEFT ALONE — drop-public-setup territory

Verified: build exit 0 (with JWT_SECRET set), 16/16 vitest tests pass,
lint baseline unchanged (128/81/47).

Convoy: fix-auth-bypass / role-doc-writer (closeout)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-23 11:27:48 -05:00

5.7 KiB

convoy brief_number depends_on files deletes
fix-auth-bypass 3
.github/workflows/ci.yml
README.md
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.jsdeleted
  • pages/api/test-auth.jsdeleted
  • pages/api/test-db.jsdeleted
  • pages/api/setup-database.jsdeleted
  • .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:
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:
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 -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.