Skip to content

[CHORE] 프리뷰 배포#422

Merged
unifolio0 merged 5 commits intodevelopfrom
chore/#421
Feb 25, 2026
Merged

[CHORE] 프리뷰 배포#422
unifolio0 merged 5 commits intodevelopfrom
chore/#421

Conversation

@unifolio0
Copy link
Contributor

@unifolio0 unifolio0 commented Feb 20, 2026

🚩 연관 이슈

closed #421

📝 작업 내용

  • 프리뷰 배포 기능을 구현했습니다.
  • 관련 환경 변수나 시크릿 변수는 노션의 ENV 페이지에 기록했습니다.
  • dev나 prod에는 영향이 안 가도록 했는데 제가 프론트는 첨이라 확실하진 않으니 확인 부탁드립니다.

🏞️ 스크린샷 (선택)

🗣️ 리뷰 요구사항 (선택)

Summary by CodeRabbit

  • New Features

    • PR 미리보기 자동 배포 및 PR 종료 시 미리보기 정리(정리 알림 코멘트 포함)
  • New Features / 배포 설정

    • 애플리케이션 기본 경로(VITE_BASE_PATH) 지원 — 빌드/배포 및 공개 URL에 기본 경로 적용
  • Improvements

    • OAuth 리디렉션에 기본 경로 반영
    • 번역 파일 로드 경로가 기본 경로를 반영
    • 공유·투표 URL에 기본 경로 적용
  • Refactor

    • 라우팅 구조 재구성 및 전역 에러/뒤로가기/업데이트 처리 통합

@gemini-code-assist
Copy link

Summary of Changes

Hello @unifolio0, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

이 PR은 프리뷰 배포 기능을 지원하기 위해 애플리케이션의 기본 경로(base path) 처리 방식을 개선합니다. VITE_BASE_PATH 환경 변수를 도입하여 동적으로 URL을 생성하고 라우팅을 설정함으로써, 다양한 배포 환경에서 애플리케이션이 올바르게 동작하도록 합니다. 이는 개발 및 프로덕션 환경에 영향을 주지 않으면서 프리뷰 환경을 독립적으로 운영할 수 있는 기반을 마련합니다.

Highlights

  • 프리뷰 배포 기능 지원: 프리뷰 배포 기능을 구현하기 위한 기반을 마련했습니다.
  • URL 생성 로직 업데이트: VITE_BASE_PATH 환경 변수를 활용하여 애플리케이션 내에서 생성되는 모든 URL의 기본 경로를 동적으로 처리하도록 업데이트했습니다.
  • React Router 라우팅 설정: React Router의 createBrowserRouterbasename 옵션을 추가하여 라우팅 경로가 VITE_BASE_PATH에 따라 올바르게 동작하도록 설정했습니다.
  • Google OAuth state 파라미터 추가: Google OAuth 인증 요청 시 state 파라미터에 VITE_BASE_PATH를 포함하여 인증 후 리다이렉트 시 올바른 경로로 돌아올 수 있도록 했습니다.
Changelog
  • src/constants/debate_template.ts
    • createTableShareUrl 함수에서 VITE_BASE_PATH를 사용하여 공유 URL 경로를 조정했습니다.
  • src/page/DebateVotePage/DebateVotePage.tsx
    • 투표 URL 생성 시 VITE_BASE_PATH를 적용하도록 수정했습니다.
  • src/routes/routes.tsx
    • createBrowserRouterVITE_BASE_PATHbasename으로 설정하여 라우팅 기본 경로를 동적으로 처리하도록 변경했습니다.
  • src/util/arrayEncoding.ts
    • createTableShareUrl 함수에서 VITE_BASE_PATH를 사용하여 공유 URL 경로를 조정했습니다.
  • src/util/googleAuth.ts
    • Google OAuth 인증 요청 시 VITE_BASE_PATHstate 파라미터로 추가하여 리다이렉트 후 경로를 유지하도록 했습니다.
  • src/vite-env.d.ts
    • ImportMetaEnv 인터페이스에 VITE_BASE_PATH 속성을 추가하여 타입 정의를 업데이트했습니다.
  • vite.config.ts
    • Vite 설정에서 base 옵션을 VITE_BASE_PATH 환경 변수에 따라 동적으로 설정하도록 변경했습니다.
Ignored Files
  • Ignored by pattern: .github/workflows/** (2)
    • .github/workflows/cleanup-preview.yml
    • .github/workflows/deploy-preview.yml
Activity
  • 현재까지 풀 리퀘스트에 대한 활동은 제공되지 않았습니다.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@coderabbitai
Copy link

coderabbitai bot commented Feb 20, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6bf22db and b4f569d.

📒 Files selected for processing (1)
  • .github/workflows/cleanup-preview.yml
🚧 Files skipped from review as they are similar to previous changes (1)
  • .github/workflows/cleanup-preview.yml

Walkthrough

develop 대상 PR에 대해 Preview 배포 및 정리 워크플로우를 추가하고, VITE_BASE_PATH 환경변수에 따라 앱의 라우팅, 번들 베이스, i18n 로드 경로 및 여러 URL 생성 로직을 베이스패스에 맞게 조정했습니다.

Changes

Cohort / File(s) Summary
GitHub Actions 워크플로우
​.github/workflows/deploy-preview.yml, ​.github/workflows/cleanup-preview.yml
PR 오픈/업데이트 시 PR별 S3 업로드·CloudFront 무효화·PR 댓글로 Preview URL 게시. PR 종료 시 S3의 pr-{PR_NUMBER} 경로 삭제 및 정리 댓글 작성.
앱 URL 및 OAuth 관련 변경
src/constants/debate_template.ts, src/util/arrayEncoding.ts, src/page/DebateVotePage/DebateVotePage.tsx, src/util/googleAuth.ts
VITE_BASE_PATH가 정의되고 '/'가 아닐 경우 공유·투표 URL과 OAuth state에 베이스패스를 프리픽스로 삽입하도록 URL 생성 로직을 변경.
라우팅 구조 및 베이스패스 설정
src/routes/routes.tsx, vite.config.ts, src/i18n.ts, src/vite-env.d.ts
최상위 라우트 트리를 ErrorBoundaryWrapper/BackActionHandler/UpdateModalWrapper로 감싸고 LanguageWrapper 경로 추가. createBrowserRouterbasename 옵션 적용. Vite base 설정 추가, i18n loadPath에 베이스패스 적용, ImportMetaEnv에 VITE_BASE_PATH 타입 추가.

Sequence Diagram(s)

sequenceDiagram
    participant User as 사용자
    participant GitHub as GitHub Actions
    participant Builder as CI (Node)
    participant S3 as AWS S3
    participant CloudFront as CloudFront
    participant PR as PR 댓글

    rect rgba(100,150,255,0.5)
    Note over User,PR: Deploy Preview (PR 열기/업데이트)
    User->>GitHub: PR 열기 또는 푸시
    GitHub->>Builder: 코드 체크아웃 및 .env 생성 (VITE_BASE_PATH 포함) 및 빌드
    Builder->>GitHub: 빌드 결과 반환
    GitHub->>S3: 빌드 아티팩트 업로드 (pr-{PR_NUMBER} 경로) 및 oauth-handler 업로드
    GitHub->>CloudFront: 캐시 무효화 (PR 경로 및 /oauth)
    GitHub->>PR: Preview URL 포함 댓글 생성/갱신
    PR-->>User: 배포 알림
    end

    rect rgba(150,200,100,0.5)
    Note over User,PR: Cleanup Preview (PR 닫기)
    User->>GitHub: PR 닫기
    GitHub->>S3: pr-{PR_NUMBER} 경로 삭제
    GitHub->>CloudFront: 관련 캐시 무효화 (선택적)
    GitHub->>PR: 정리 완료 댓글 작성
    PR-->>User: 정리 알림
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

chore

Suggested reviewers

  • jaeml06
  • useon
  • i-meant-to-be

Poem

🐰 프리뷰 길 따라 폴더를 뛰네,
pr 폴더에 쌓인 빌드의 발자국,
캐시를 털고 댓글로 인사 남기네.
VITE_BASE_PATH로 길 잇고,
닫힘엔 깔끔히 쓸고 떠나요 🧹✨

🚥 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%. 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 PR 제목은 프리뷰 배포 기능 추가라는 주요 변경사항을 정확하게 반영하고 있습니다.
Linked Issues check ✅ Passed 프리뷰 배포 워크플로우 구현 요구사항이 충족되었으며, 환경 변수 설정, AWS 연동, 배포 자동화가 모두 포함되어 있습니다.
Out of Scope Changes check ✅ Passed 모든 변경사항이 프리뷰 배포 구현과 직접 관련된 범위 내에서 이루어졌으며, 개발 및 프로덕션 환경에 영향을 주지 않습니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch chore/#421

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 and usage tips.

@github-actions
Copy link

github-actions bot commented Feb 20, 2026

🚀 Preview 배포 완료!

환경 URL
Preview 열기
API Dev 환경

PR이 닫히면 자동으로 정리됩니다.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

프리뷰 배포를 위한 VITE_BASE_PATH 환경 변수 대응 작업을 진행해 주셨습니다. 전반적으로 필요한 부분에 basename과 경로 접두사 처리가 잘 반영되었습니다. 다만, DebateVotePage.tsx에서 baseUrlundefined일 경우 URL이 비정상적으로 생성될 수 있는 문제와, 경로 접두사를 계산하는 로직이 여러 곳에 중복되어 있는 점에 대해 개선 의견을 드립니다.

Comment on lines +36 to +38
const basePath = import.meta.env.VITE_BASE_PATH;
const pathPrefix = basePath && basePath !== '/' ? basePath : '';
return `${baseUrl}${pathPrefix}/vote/${pollId}`;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

baseUrlundefined일 경우(특히 개발 환경에서), voteUrl"undefined/vote/..."와 같은 잘못된 문자열로 생성됩니다. 또한 baseUrl에 트레일링 슬래시가 포함되어 있을 경우 경로가 중복될 수 있으므로, 다른 파일들(debate_template.ts, arrayEncoding.ts)과 마찬가지로 window.location.origin을 폴백으로 사용하고 슬래시를 정규화하는 로직이 필요합니다.

    const resolvedBaseUrl = (baseUrl || window.location.origin).replace(/\/+$/, '');
    const basePath = import.meta.env.VITE_BASE_PATH;
    const pathPrefix = basePath && basePath !== '/' ? basePath : '';
    return `${resolvedBaseUrl}${pathPrefix}/vote/${pollId}`;

Comment on lines +19 to +20
const basePath = import.meta.env.VITE_BASE_PATH;
const pathPrefix = basePath && basePath !== '/' ? basePath : '';

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

VITE_BASE_PATH를 기반으로 pathPrefix를 생성하는 로직이 여러 파일(debate_template.ts, DebateVotePage.tsx, arrayEncoding.ts)에서 동일하게 반복되고 있습니다. 이를 공통 유틸리티 함수로 분리하여 관리하는 것을 권장합니다.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (3)
.github/workflows/deploy-preview.yml (2)

82-83: 프리뷰 도메인이 하드코딩되어 있습니다.

preview.debate-timer.com이 워크플로우 스크립트에 직접 하드코딩되어 있습니다. 시크릿이나 변수로 관리하면 도메인 변경 시 워크플로우 수정 없이 대응할 수 있습니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/deploy-preview.yml around lines 82 - 83, The preview
domain is hardcoded when constructing url using prNumber; change this to use a
workflow variable or secret (e.g., PREVIEW_DOMAIN) instead of the literal
"https://preview.debate-timer.com", and update the url construction (where url
is defined) to interpolate that env/secret value (or default) so domain changes
are managed via workflow inputs/environment rather than editing the script.

29-33: .env 생성 시 셸 인젝션 방지를 위해 heredoc 사용을 권장합니다.

${{ vars.ENV }}${{ secrets.ENV }} 값에 셸 특수 문자가 포함되면 예기치 않은 동작이 발생할 수 있습니다. Heredoc을 사용하면 더 안전합니다.

♻️ Heredoc 방식으로 변경
       - name: Setup .env
         run: |
-          echo "${{ vars.ENV }}" > .env
-          echo "${{ secrets.ENV }}" >> .env
+          cat > .env << 'ENVEOF'
+          ${{ vars.ENV }}
+          ENVEOF
+          cat >> .env << 'ENVEOF'
+          ${{ secrets.ENV }}
+          ENVEOF
           echo "VITE_BASE_PATH=/pr-${{ github.event.pull_request.number }}" >> .env
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/deploy-preview.yml around lines 29 - 33, The "Setup .env"
step uses multiple echo calls that can be vulnerable to shell interpretation of
special characters in ${{ vars.ENV }} and ${{ secrets.ENV }}; replace the three
echo lines with a single heredoc that writes all content into .env (use a quoted
delimiter like <<'EOF' to prevent the shell from interpreting special
characters), include the expanded values ${{ vars.ENV }} and ${{ secrets.ENV }}
and the VITE_BASE_PATH line inside the heredoc, and close with EOF so the file
is created atomically and safely.
src/page/DebateVotePage/DebateVotePage.tsx (1)

36-38: base path 접두사 로직이 여러 파일에 중복되어 있습니다.

동일한 패턴이 arrayEncoding.ts, debate_template.ts, DebateVotePage.tsx, googleAuth.ts에 반복됩니다:

const basePath = import.meta.env.VITE_BASE_PATH;
const pathPrefix = basePath && basePath !== '/' ? basePath : '';

공통 유틸 함수로 추출하면 유지보수성이 향상됩니다.

♻️ 유틸 함수 추출 예시

예를 들어, src/util/basePath.ts에 아래와 같이 정의:

export function getBasePathPrefix(): string {
  const basePath = import.meta.env.VITE_BASE_PATH;
  return basePath && basePath !== '/' ? basePath : '';
}

그 후 각 파일에서 getBasePathPrefix()를 호출하는 방식으로 변경할 수 있습니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/page/DebateVotePage/DebateVotePage.tsx` around lines 36 - 38, Multiple
files duplicate the base path prefix logic (the two-line snippet calculating
pathPrefix); extract this into a shared util (e.g., export function
getBasePathPrefix() in a new util file) and replace the inline logic in
DebateVotePage (and the other occurrences like arrayEncoding.ts,
debate_template.ts, googleAuth.ts) by importing and calling getBasePathPrefix();
update the code that builds the vote URL (currently returning
`${baseUrl}${pathPrefix}/vote/${pollId}`) to use the returned prefix from
getBasePathPrefix() instead of recalculating it inline.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/cleanup-preview.yml:
- Around line 23-25: The cleanup workflow's "Delete Preview from S3" step only
removes objects from S3 but doesn't invalidate CloudFront, so cached assets can
still be served; update that step to run an AWS CloudFront invalidation after
the aws s3 rm command by calling the AWS CLI (aws cloudfront
create-invalidation) using the distribution ID from a secret (e.g.,
AWS_CLOUDFRONT_DISTRIBUTION_ID) and invalidate the preview path
/pr-<pull_request_number>/* (use github.event.pull_request.number to build the
path), and ensure the step handles the operation result (fail the job on
invalidation error or wait for completion) so the preview is fully removed from
the CDN.

In @.github/workflows/deploy-preview.yml:
- Around line 54-69: The oauth-handler.html currently reads the URLSearchParams
'state' and calls window.location.replace(state + '/oauth?' + params.toString())
without validation, enabling open-redirect; update the JS in oauth-handler.html
to validate the extracted state value against an explicit whitelist or ensure it
is a same-origin path (reject absolute URLs with other origins), only perform
window.location.replace when validation passes, and otherwise render a safe
error/notice or a fixed internal redirect; keep the existing
params.delete('state') behavior but do not redirect if validation fails.

In `@src/util/googleAuth.ts`:
- Around line 17-20: The code currently sets params.state = basePath (basePath,
params.state) which enables open-redirects because oauth-handler.html blindly
redirects using state; update oauth-handler.html to treat state only as a safe
local route by validating the received state against a whitelist/pattern (e.g.,
ensure it starts with "/pr-" or matches allowed path regex) and reject or fall
back to a safe default if it doesn't match, and keep using state for CSRF tokens
separately (do not rely on it for arbitrary redirect destinations).

---

Nitpick comments:
In @.github/workflows/deploy-preview.yml:
- Around line 82-83: The preview domain is hardcoded when constructing url using
prNumber; change this to use a workflow variable or secret (e.g.,
PREVIEW_DOMAIN) instead of the literal "https://preview.debate-timer.com", and
update the url construction (where url is defined) to interpolate that
env/secret value (or default) so domain changes are managed via workflow
inputs/environment rather than editing the script.
- Around line 29-33: The "Setup .env" step uses multiple echo calls that can be
vulnerable to shell interpretation of special characters in ${{ vars.ENV }} and
${{ secrets.ENV }}; replace the three echo lines with a single heredoc that
writes all content into .env (use a quoted delimiter like <<'EOF' to prevent the
shell from interpreting special characters), include the expanded values ${{
vars.ENV }} and ${{ secrets.ENV }} and the VITE_BASE_PATH line inside the
heredoc, and close with EOF so the file is created atomically and safely.

In `@src/page/DebateVotePage/DebateVotePage.tsx`:
- Around line 36-38: Multiple files duplicate the base path prefix logic (the
two-line snippet calculating pathPrefix); extract this into a shared util (e.g.,
export function getBasePathPrefix() in a new util file) and replace the inline
logic in DebateVotePage (and the other occurrences like arrayEncoding.ts,
debate_template.ts, googleAuth.ts) by importing and calling getBasePathPrefix();
update the code that builds the vote URL (currently returning
`${baseUrl}${pathPrefix}/vote/${pollId}`) to use the returned prefix from
getBasePathPrefix() instead of recalculating it inline.

Comment on lines +17 to +20
const basePath = import.meta.env.VITE_BASE_PATH;
if (basePath && basePath !== '/') {
params.state = basePath;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

OAuth state 파라미터를 라우팅 목적으로 사용하면 보안 위험이 있습니다.

OAuth state 파라미터는 일반적으로 CSRF 방지를 위해 사용됩니다. 여기서 basePath를 전달하는 용도로 사용하고 있는데, deploy-preview.ymloauth-handler.htmlstate 값을 기반으로 무조건 리다이렉트하므로 오픈 리다이렉트 취약점이 발생합니다.

공격자가 https://preview.debate-timer.com/oauth?code=AUTH_CODE&state=https://evil.com 같은 URL을 구성하면, oauth-handler.htmlhttps://evil.com/oauth?code=AUTH_CODE로 리다이렉트하여 인증 코드가 유출될 수 있습니다.

oauth-handler.html에서 state 값이 허용된 경로 패턴(예: /pr- 접두사)인지 검증해야 합니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/util/googleAuth.ts` around lines 17 - 20, The code currently sets
params.state = basePath (basePath, params.state) which enables open-redirects
because oauth-handler.html blindly redirects using state; update
oauth-handler.html to treat state only as a safe local route by validating the
received state against a whitelist/pattern (e.g., ensure it starts with "/pr-"
or matches allowed path regex) and reject or fall back to a safe default if it
doesn't match, and keep using state for CSRF tokens separately (do not rely on
it for arbitrary redirect destinations).

Copy link
Contributor

@i-meant-to-be i-meant-to-be left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

확인했습니다! 작업 환경이 달라 코드 파악하시는 데 시간이 좀 걸리셨을 텐데, 직접 처리하시느라 고생하셨어요. 중요한 리뷰 한 건이 있어 RC 남기고 갑니다.

Comment on lines +59 to +66
<script>
var params = new URLSearchParams(window.location.search);
var state = params.get('state');
if (state) {
params.delete('state');
window.location.replace(state + '/oauth?' + params.toString());
}
</script>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

권장: state 검증 로직 추가

CodeRabbit이 짚어준 내용과 동일합니다. 공격자가 "https://preview.debate-timer.com/oauth?client_id=...&redirect_uri=https://preview.debate-timer.com/oauth&state=https://evil.com" 등의 URL로 우리 팀원을 공격한다면, 팀원의 OAuth 관련 민감 정보가 유출될 가능성이 있어 보여요. state 변수에 대한 검증 로직을 추가하는 것이 좋아 보입니다.

아래는 Gemini가 제안해 준 검증 코드예요:

// 보안 패치: state가 'pr-숫자' 형식이거나, '/'로 시작하는 상대 경로인지 검증
// 예: "pr-123" 또는 "/pr-123" 만 허용
var validStateRegex = /^pr-\d+$/; 

if (state && validStateRegex.test(state)) {
  // 검증 통과 시에만 이동
  params.delete('state');
  // 상대 경로를 명시적으로 사용하여 외부 도메인 이동 차단
  window.location.replace('/' + state + '/oauth?' + params.toString());
} else {
  // 검증 실패 시 에러 처리 또는 메인으로 이동
  console.error('Invalid state parameter');
  document.body.innerHTML = "<h1>잘못된 접근입니다. (Invalid OAuth State)</h1>";
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

검증 로직 추가했습니다!

Copy link
Contributor Author

@unifolio0 unifolio0 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/noti
@i-meant-to-be 리뷰 반영했습니다!

Comment on lines +59 to +66
<script>
var params = new URLSearchParams(window.location.search);
var state = params.get('state');
if (state) {
params.delete('state');
window.location.replace(state + '/oauth?' + params.toString());
}
</script>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

검증 로직 추가했습니다!

Copy link
Contributor

@i-meant-to-be i-meant-to-be left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

확인했습니다! 빠른 반영 감삼다

Copy link
Contributor

@useon useon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

비토 !! 제안했던 작업 선뜻 맡아서 작업해 주셔서 정말 감사합니다 .. 덕분에 생산성이 더 증가될 것 같숨다 .. !!!!!!

@unifolio0 unifolio0 merged commit d25b2d5 into develop Feb 25, 2026
3 checks passed
@unifolio0 unifolio0 deleted the chore/#421 branch February 25, 2026 05:00
@github-actions
Copy link

🧹 Preview 배포가 정리되었습니다.

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.

[CHORE] 프리뷰 배포

3 participants