Skip to content

fix(web-ui): dead nav branch removal, prod CSP eval drop, fail-closed auth guard (#783)#891

Merged
frankbria merged 3 commits into
mainfrom
feature/issue-783-frontend-residuals
Jul 25, 2026
Merged

fix(web-ui): dead nav branch removal, prod CSP eval drop, fail-closed auth guard (#783)#891
frankbria merged 3 commits into
mainfrom
feature/issue-783-frontend-residuals

Conversation

@frankbria

@frankbria frankbria commented Jul 25, 2026

Copy link
Copy Markdown
Owner

Closes #783

Summary

Three frontend residuals from the SaaS launch-readiness audit (P3.12):

  1. Dead nav branch removed — every NAV_ITEMS entry was enabled: true, so the disabled "coming soon" <span> branch in AppSidebar was unreachable. The enabled field and branch are deleted.
  2. CSP hardening + residual-risk documentation'unsafe-eval' now ships only in dev (NODE_ENV === 'development'; Next.js React Refresh needs it, production bundles never eval). 'unsafe-inline' stays (App Router without nonce middleware requires it) and the residual risk is documented accurately in security-headers.js, including the top-level-navigation exfil channel CSP cannot close (window.location = attacker + token) and the upgrade path (nonce middleware / httpOnly-cookie token) — the path the issue's acceptance criteria explicitly allow.
  3. Auth guard fails closed — with no stored token, a checkAuthAccess() probe error (backend unreachable) now redirects to /login instead of rendering the app shell. Only an explicit 2xx allows token-less access (auth-disabled backend). Server-side enforcement was never affected; this was cosmetic fail-open.

Review

Cross-family adversarial review (opencode / GLM) run pre-PR: 0 critical/major, 4 minor — 2 fixed in-branch (exfil-comment accuracy, stale nav test wording + undercount), 2 handled below (limitations / demo verification).

Known limitations

  • Auth-disabled local dev + backend blip: with CODEFRAME_AUTH_REQUIRED=false and no token, a transient backend outage now lands the user on /login (previously the shell rendered and SWR auto-recovered). Recovery: navigate back to / once the backend is up. This is the tradeoff the issue's acceptance criteria requested ("prefer failing closed to /login on the probe-error path").
  • unsafe-inline + localStorage JWT residual risk remains (documented, not eliminated) — full fix is nonce middleware and/or httpOnly cookie migration, out of scope per acceptance criteria.

Test plan

…auth guard closed (#783)

- AppSidebar: delete the unreachable !enabled 'coming soon' branch (all
  NAV_ITEMS were enabled:true)
- security-headers: ship 'unsafe-eval' only in dev (Next.js React Refresh);
  document the residual localStorage-JWT + unsafe-inline risk and upgrade path
- AppLayout: probe-error path now fails closed to /login instead of rendering
  the shell; checkAuthAccess docs updated

Closes #783
@github-actions

github-actions Bot commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Claude finished @frankbria's task in 3m 18s —— View job


I'll analyze this and get back to you.

@github-actions

github-actions Bot commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Claude finished @frankbria's task in 11m 17s —— View job


Precision bug-hunt review complete

Reviewed PR #891 for concrete defects only (logic errors, null-deref/crash paths, security vulnerabilities, data loss, race conditions, breaking contract changes). Style/architecture/coverage are owned by the separate general review and excluded.

  • Gather PR diff + existing comments (none — clean review surface)
  • Read changed source files + surrounding context (next.config.js, auth.ts, all checkAuthAccess callers, NAV_ITEMS references)
  • Verify each suspicious hunk against real code
  • Post summary (no findings → no inline comments)

Result: ✅ no defects found. Summary posted as a separate comment. All four runtime hunks verified correct against their real callers: the CSP dev/prod split is wired through next.config.js headers() with the right NODE_ENV in each mode, the fail-closed auth branch has no inverted condition / redirect loop / authorized-user regression, the timeout: 5000 classifies as 'error' (fail-closed) on timeout, and the removed nav enabled field is fully unreferenced.

@github-actions

Copy link
Copy Markdown
Contributor

✅ GLM review: no defects found.

Scope: precision bug-hunt (logic errors, null/crash paths, security vulns, data loss/races, breaking contract changes). Style/architecture/coverage are covered by the separate general review and excluded here.

Verified against real callers/callees:

  • security-headers.js — dev/prod 'unsafe-eval' split via NODE_ENV; consumed through next.config.js headers() → securityHeaders(process.env), evaluated with the correct NODE_ENV in both next dev and next start; secure default when unset.
  • AppLayout.tsx — fail-closed branch is logically correct (allowed → shell; denied/error/login); checkAuthAccess always resolves (try/catch) so the .then never rejects; /login is a BARE_ROUTE (no redirect loop); token-bearing users short-circuit before the probe, so no authorized-user lockout.
  • api.tstimeout: 5000 (ms) is correct; an axios timeout has no response.status, so it classifies as 'error' (fail-closed) as intended.
  • AppSidebar.tsx — removed enabled field/dead branch is fully unreferenced; key={href} preserved.

@frankbria

Copy link
Copy Markdown
Owner Author

Demo verification (Phase 11 — hard gate) ✅

Production build (next build + next start, real browser via agent-browser):

Criterion Action Outcome evidence Status
Dead nav branch removed Rendered shell on /tasks (prod bundle), inspected aside nav DOM {"links":10,"spans":0} — all 10 items (Workspace…Settings) are <a> elements, zero disabled <span>s, "coming soon" absent from the document; screenshot shows full sidebar VERIFIED
CSP hardened + residual risk documented curl -I the prod server; navigated app pages and dumped browser console Live header: script-src 'self' 'unsafe-inline'no unsafe-eval; console had zero CSP-violation messages while the prod bundle ran (confirms nothing evals in prod). Residual risk (incl. top-level-nav exfil channel) documented in security-headers.js VERIFIED
Probe-error path fails closed Cleared localStorage, backend down, visited /tasks Landed on /login (sign-in form rendered), app shell never mounted (aside absent) — redirect within ~8s thanks to the new 5s probe cap VERIFIED

Demo artifacts (session-local, gitignored): scratchpad/demo/fail-closed-login.png, scratchpad/demo/sidebar-10-links.png.

Demo-discovered fix: on networks where a dead backend port hangs instead of refusing (observed on WSL2), the probe had no timeout, so the fail-closed redirect waited on the OS connect timeout (~2 min on the loader). Added timeout: 5000 to the probe (a314f06) — redirect is now prompt.

@frankbria
frankbria merged commit d696978 into main Jul 25, 2026
10 of 11 checks passed
@frankbria
frankbria deleted the feature/issue-783-frontend-residuals branch July 25, 2026 03:47
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.

[P3.12] Frontend residual: dead "coming soon" nav branch + CSP/localStorage tradeoff + fail-open auth guard

1 participant