Commit graph

2 commits

Author SHA1 Message Date
Randall Stillwell
79171e8b97 feat(layout): default user=null + Sign-in CTA when logged out (Brief 1 of fix-layout-default-user)
Closes the source-side half of P0 #7 from .convoys/ship-readiness.md.
The page-side sweep (Brief 2) follows in a separate commit.

components/Layout.js:
  - Default user prop is now null (was hardcoded to
    { email: 'me@randallstillwell.com', role: 'user' })
  - UserProfileDropdown renders a "Sign in" link to /login when
    user === null instead of the maintainer's email + auth-only menu
    items (Decision A1)
  - All user.* accesses guarded with optional chaining or null checks
  - useState hook stays above the new null-user early return to satisfy
    rules-of-hooks (boot-the-brief caught this on the first try;
    see AGENTS.md Gotcha #11.5)

test/components/Layout.test.js (new):
  - First jsdom test in the repo (Decision D2)
  - 5 regression-lock assertions: no maintainer email ever rendered
    (prop omitted, prop=null), Sign-in link exists with href=/login,
    supplied email renders when prop is set, no "Guest" placeholder
    (locks A1 copy choice)
  - Mocks next/link, next/router (prefetch, replace, events, query),
    and theme-context.useTheme for jsdom safety under Next 16

package.json + package-lock.json:
  - Add jsdom@^29 and @testing-library/react@^16 to devDependencies
  - @testing-library/dom@^10 added explicitly (peer auto-install
    skipped it under npm 11; brief anticipated this fallback)

vitest.config.js (deviation from brief — see PR description):
  - Add esbuild { loader: 'jsx', jsx: 'automatic' } so vitest can
    parse JSX in .js files. Required to import any React component
    written in the repo's Next.js pages-router .js convention
    (AGENTS.md Gotcha #9). The brief said "no change" to this file,
    but JSX-in-.js parsing is a hard prerequisite for the new test
    to import components/Layout.js — the alternatives (rename test
    to .test.jsx; rewrite test in React.createElement) either break
    the test glob or still hit the same Layout.js parse failure.
    Other tests are unaffected (they import non-JSX modules).

Smoke output: see PR description.

addresses: P0 #7 from .convoys/ship-readiness.md (last P0 ship-blocker)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-24 14:22:20 -05:00
Randall Stillwell
1629afbb76 test(auth): add vitest harness + 16 auth-focused unit tests (Brief 5 of fix-auth-bypass)
Closes AGENTS.md gotcha #11 (well, the relevant half of it — "Testing:
None yet" line in §6 is now stale).

Installs vitest@^3.2.4 (single devDep, no UI / coverage / jsdom) and
adds 16 unit tests across 3 files that lock in post-Brief-1/2/4
behavior:

  test/lib/auth-secret.test.js (3 tests)
    - JWT_SECRET exports the env value
    - JWT_TOKEN_TTL is canonical 24h
    - Module throws at load when JWT_SECRET is empty

  test/lib/permission-middleware.test.js (8 tests)
    - getUserFromRequest returns null for: missing header, non-Bearer
      scheme, malformed token, wrong-secret token, expired token,
      valid-token-no-user-row
    - Returns user object for valid token + user row
    - Brief 2 regression lock: does NOT return the synthetic admin
      shape { userId: 1, email: 'admin@tcgvault.com', role: 'admin' }
      when no Authorization header is present

  test/api/auth-utils.test.js (5 tests)
    - generateToken issues 24h JWT (exp - iat === 86400)
    - Payload includes userId, email, role
    - verifyToken round-trips valid tokens
    - Returns null for malformed / wrong-secret tokens

CI: re-enabled the previously commented-out test: job in
.github/workflows/ci.yml. Blocking (no || true wrapper) — vitest is
the first runner in this repo and we want CI red on test regression.
JWT_SECRET is set via a CI-only fake; production secret is unaffected.

Rate-limit (Brief 4) coverage deferred to a future expand-auth-tests
convoy per architect's call (R11). package.json has "type": "module"
so vitest's default Vite-based transform handles .js ESM out of the
box — no transform config needed.

Convoy: fix-auth-bypass / Brief 5 (last brief)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-23 11:12:15 -05:00