Skip to content

fix(fe): restrict contest pages to contest admin and manager - #3821

Open
saeyeon-05 wants to merge 1 commit into
mainfrom
t3093-contest-access-guard
Open

saeyeon-05 wants to merge 1 commit into
mainfrom
t3093-contest-access-guard

Conversation

@saeyeon-05

@saeyeon-05 saeyeon-05 commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

Description

  • 대회 관리 페이지(/admin/contest/[contestId]/...) 접근 권한 제한
  • 해당 대회의 Admin, Manager만 허용, Reviewer, 참가자는 차단
  • 권한 없으면 빨간 토스트 후 /admin/contest로 이동
  • 사이트 Admin 예외 없음 (회의 결정)

Closes TAS-3093

Test

  • /admin/contest/99999/edit 접속 → 토스트 후 목록으로 이동
  • 본인이 Admin인 대회 접속 → 정상 로딩
스크린샷 2026-10-07 오후 7 13 32

Summary by CodeRabbit

  • Access Control
    • Contest administration pages are now available only to users with an Admin or Manager role for that contest.
    • Users without the required access are redirected to the contest administration page and shown an access-denied message.

@coderabbitai

coderabbitai Bot commented Oct 7, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: a2190127-ffa1-47e8-a8ed-5d116f3e7936
📥 Commits

Reviewing files that changed from the base of the PR and between a4a171b and 0e3576c.

📒 Files selected for processing (2)
  • apps/frontend/app/admin/contest/[contestId]/_components/ContestAccessDenied.tsx
  • apps/frontend/app/admin/contest/[contestId]/layout.tsx

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

The contest layout fetches contest roles and renders its children only for a matching Admin or Manager role. Otherwise, it renders a component that redirects to /admin/contest and displays an access-denied error toast.

Changes

Contest access

Layer / File(s) Summary
Role retrieval and route gate
apps/frontend/app/admin/contest/[contestId]/layout.tsx
The layout fetches contest roles and treats fetch errors as an empty role list. It renders children only when a role matches the contest ID and is Admin or Manager.
Denied-access handling
apps/frontend/app/admin/contest/[contestId]/_components/ContestAccessDenied.tsx
The component redirects to /admin/contest and displays an access-denied error toast after 100 ms. It runs these actions only on its first effect run and renders null.

Priority: ➖ Normal

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix

Sequence Diagram(s)

sequenceDiagram
  participant Layout as Contest layout
  participant Roles as contest/role
  participant Denied as ContestAccessDenied
  participant Router
  participant Toast as Error toast
  Layout->>Roles: Fetch contest roles
  Roles-->>Layout: Return roles or fetch error
  Layout->>Denied: Render when no matching Admin or Manager role exists
  Denied->>Router: Replace route with /admin/contest
  Denied->>Toast: Show access-denied error after 100 ms
Loading

Merge Risk: 🔵 Low · up to 0e357

A revoked manager may still see contest information already loaded in their browser until refresh. New protected requests are blocked, so this is mergeable with owner awareness.

Security Architecture Review

Security architecture risk: 🟡 Moderate · up to 0e357

The change restricts initial page access, but permissions may remain stale after access is revoked. The existing role lookup also has a missing-identity weakness. Server-side checks limit fresh privileged access, so this is an additional page-access control rather than a complete authorization boundary.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — The retained stale-layout path concerns a previously authorized user's contest UI and already-fetched information, including an invitation code. The inspected current-role guard limits subsequent protected requests after revocation. Separately, the inherited null-identity role endpoint can expose contestId and role metadata across userContest rows. Neither path establishes newly gained mutation authority, infrastructure access or broader data-store privileges from this PR.

Security Findings and Attack Paths

  • inferred — The retained, reportable medium-severity authorization finding describes role removal followed by client navigation that reuses an authorized layout and already-loaded content. The new gate checks roles only when its server layout executes; force-dynamic does not itself provide explicit invalidation of mounted client state. Base/head comparison shows that the cached-content mechanism already existed under a route with no contest-specific parent gate. The PR does not demonstrably introduce or worsen that exposure, although its new admission check does not resolve continuous revocation.

Trust Boundaries and Controls

  • inferred — The actual REST producer has an inherited identity gap: authentication failure on a public request can return a null user, and the controller then passes undefined userId into findMany. With the inspected Prisma configuration lacking strict undefined checking, the filter can be omitted, allowing other users' role rows to satisfy the new layout's contest-and-role test. This is a successful-response path, so the layout's exception handling does not deny it. The endpoint and the outer admin layout's existing use of it predate the PR; expanded effective access was not established.

Resilience and Maintainability Implications

  • observed — Role removal and role updates mutate the authoritative userContest records, so subsequent role-list and ordinary-user guard reads observe those writes. The new layout adds no corresponding invalidation of already-rendered authorization state. Full server re-entry obtains current roles; exact interruption, concurrency and client remount behavior remain unverified.

Hardening Proposals

  • proposed — Require a valid authenticated identity for role-list responses, or explicitly return no roles when identity is missing. Reject undefined identity filters before database access so successful responses cannot borrow another user's membership.
  • proposed — Define permission and identity transitions explicitly: revalidate route admission and clear sensitive client state when membership or session identity changes. Preserve per-operation backend enforcement and verify revocation through repeated navigation, interruption and recovery.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 3 functions across 2 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: restricting contest pages to contest Admins and Managers.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@howso245-dot howso245-dot added the preview 이 라벨이 붙어있어야 프론트엔드 Preview 환경이 생성됩니다 label Oct 7, 2026
@skkuding-bot

skkuding-bot Bot commented Oct 7, 2026

Copy link
Copy Markdown

✅ Syncing Preview App Succeeded

Application: frontend
Revision: 0e3576c8d351541029e0d935f293a5082befe190
Health Status: Healthy

Open Preview | View in Argo CD

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

preview 이 라벨이 붙어있어야 프론트엔드 Preview 환경이 생성됩니다 size/M ⛳️ team-frontend

Projects

Status: Pending ✋

Development

Successfully merging this pull request may close these issues.

2 participants