-
Notifications
You must be signed in to change notification settings - Fork 2
[Chore] CI 구축 및 Vercel 배포 후 fork sync 자동화 #278
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
a73759d
de27a02
30c4724
11fbe26
b487f87
b19b6f2
96774d4
daaa622
3ab5fcb
eed3f02
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,92 @@ | ||||||||||
| name: ci | ||||||||||
|
|
||||||||||
| on: | ||||||||||
| push: | ||||||||||
| branches: [main, develop] | ||||||||||
| pull_request: | ||||||||||
| branches: [main, develop] | ||||||||||
|
|
||||||||||
| permissions: | ||||||||||
| contents: read | ||||||||||
| pull-requests: write | ||||||||||
|
|
||||||||||
| concurrency: | ||||||||||
| group: ci-${{ github.ref }} | ||||||||||
| cancel-in-progress: true | ||||||||||
|
|
||||||||||
| jobs: | ||||||||||
| build-and-deploy: | ||||||||||
| runs-on: ubuntu-latest | ||||||||||
| steps: | ||||||||||
| - name: Checkout Code | ||||||||||
| uses: actions/checkout@v4 | ||||||||||
|
|
||||||||||
| - name: Install pnpm | ||||||||||
| uses: pnpm/action-setup@v4 | ||||||||||
|
|
||||||||||
| - name: Setup Node.js | ||||||||||
| uses: actions/setup-node@v4 | ||||||||||
| with: | ||||||||||
| node-version: "20.x" | ||||||||||
| cache: "pnpm" | ||||||||||
|
|
||||||||||
| - name: Install dependencies | ||||||||||
| run: pnpm install --frozen-lockfile | ||||||||||
|
|
||||||||||
| - name: Check project | ||||||||||
| id: check_step | ||||||||||
| run: pnpm run lint && pnpm run typecheck | ||||||||||
| continue-on-error: true | ||||||||||
|
|
||||||||||
| - name: Build project | ||||||||||
| id: build_step | ||||||||||
| run: pnpm run build | ||||||||||
| continue-on-error: true | ||||||||||
|
|
||||||||||
| - name: Output build result | ||||||||||
| if: github.event_name == 'pull_request' && always() | ||||||||||
| uses: marocchino/sticky-pull-request-comment@v2 | ||||||||||
|
Comment on lines
+47
to
+48
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🌐 Web query:
💡 Result: Yes, for GitHub Actions workflows triggered by pull_request events from forks, the GITHUB_TOKEN has its write permissions (including pull-requests: write) downgraded to read-only. This is a security measure to prevent malicious forks from performing write actions on the base repository. The recommended guard pattern for comment-posting steps (which require pull-requests: write) is to use the pull_request_target event instead of pull_request. This event runs in the context of the base branch (trusted code), providing a full read/write GITHUB_TOKEN even for forks. Example workflow snippet: on: pull_request_target: types: [opened, synchronize] permissions: pull-requests: write contents: read jobs: comment: runs-on: ubuntu-latest steps: - name: Post comment run: | gh pr comment ${{ github.event.pull_request.number }} --body "Your comment here" env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} Security notes: - Do not checkout the PR head sha (untrusted code) with actions/checkout using ref: ${{ github.event.pull_request.head.sha }} unless strictly sandboxed. - For read-only tasks like building/testing, stick to pull_request. - Explicitly set minimal permissions with the permissions key. - Optionally, enable repo setting "Send write tokens to workflows from pull requests" for pull_request events, but pull_request_target is preferred for write actions like commenting. Citations:
포크 PR에서 sticky comment 실패 가능성에 대한 보호 필요 정확한 지적이야. GitHub Actions의 보안 정책상 fork PR에서 제시한 가드 패턴은 정확한 해결책이야. PR이 같은 저장소에서 나온 경우에만 단계를 실행하도록 제한하면 fork PR에서의 실패를 방지할 수 있어: 가드 패턴 적용 if: github.event_name == 'pull_request' && always() && github.event.pull_request.head.repo.full_name == github.repository
uses: marocchino/sticky-pull-request-comment@v2참고로 더 근본적인 방법은 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||
| with: | ||||||||||
| header: build-result | ||||||||||
| message: | | ||||||||||
| ### 🚀 빌드 결과 | ||||||||||
| ${{ steps.check_step.outcome == 'success' && '🩵 린트 검사 완료' || '😥 린트 검사 실패' }} | ||||||||||
| ${{ steps.build_step.outcome == 'success' && '💙 빌드 성공' || '😭 빌드 실패' }} | ||||||||||
|
|
||||||||||
| <details> | ||||||||||
| <summary>✔️ 로그 확인하기</summary> | ||||||||||
| <br> | ||||||||||
| <a href="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"> | ||||||||||
| Actions 탭에서 자세히 보기! | ||||||||||
| </a> | ||||||||||
| </details> | ||||||||||
|
|
||||||||||
| - name: Notify Discord Alarm | ||||||||||
| if: github.event_name == 'pull_request' && always() | ||||||||||
| run: | | ||||||||||
| PR_TITLE="${{ github.event.pull_request.title }}" | ||||||||||
| PR_USER="${{ github.event.pull_request.user.login }}" | ||||||||||
| PR_URL="${{ github.event.pull_request.html_url }}" | ||||||||||
|
|
||||||||||
| if [ "${{ steps.build_step.outcome }}" == "success" ]; then | ||||||||||
| COLOR=3066993 | ||||||||||
| TITLE="💙 빌드 성공" | ||||||||||
| else | ||||||||||
| COLOR=15158332 | ||||||||||
| TITLE="😭 빌드 실패" | ||||||||||
| fi | ||||||||||
|
|
||||||||||
| DESCRIPTION="📄 Title : \`$PR_TITLE\`\n ✏️ 작성자 : \`$PR_USER\`\n\n[🔎 PR보러가기]($PR_URL)" | ||||||||||
| curl -H "Content-Type: application/json" \ | ||||||||||
| -d "{ | ||||||||||
| \"embeds\": [{ | ||||||||||
| \"title\": \"$TITLE\", | ||||||||||
| \"description\": \"$DESCRIPTION\", | ||||||||||
| \"color\": $COLOR | ||||||||||
| }] | ||||||||||
| }" \ | ||||||||||
| "${{ secrets.DISCORD_WEBHOOK_URL }}" | ||||||||||
|
Comment on lines
+64
to
+88
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# 직접 삽입 패턴(잠재적 인젝션 지점) 확인
rg -nP '\${{\s*github\.event\.pull_request\.(title|body|user\.login|html_url)\s*}}' .github/workflows/ci.yml -C2
# 문자열로 JSON을 수동 조합하는 패턴 확인
rg -nP 'curl .* -d "\{' .github/workflows/ci.yml -C2Repository: DdingSroom/dding-sroom-frontend Length of output: 426 🏁 Script executed: cat -n .github/workflows/ci.yml | sed -n '60,95p'Repository: DdingSroom/dding-sroom-frontend Length of output: 1615 🏁 Script executed: # 워크플로우 파일에서 다른 PR 메타데이터 삽입 패턴 확인
rg -n 'github\.event\.pull_request\.' .github/workflows/ci.yml
# 다른 curl/JSON 구성 패턴 확인
rg -n 'curl.*-d' .github/workflows/ci.yml -A3Repository: DdingSroom/dding-sroom-frontend Length of output: 268 PR 메타데이터 직접 삽입으로 인한 커맨드 인젝션 및 JSON 페이로드 손상 위험 69~71줄의 더불어 81~89줄처럼 변수를 문자열 기반으로 JSON에 직접 넣으면 PR 제목이나 저자명에 큰따옴표나 개행이 들어왔을 때 JSON 구조가 깨진다. 포크 PR에서는 다음처럼 개선하는 게 좋아:
개선 예시 - name: Notify Discord Alarm
- if: github.event_name == 'pull_request' && always()
+ if: github.event_name == 'pull_request' && always() && secrets.DISCORD_WEBHOOK_URL != ''
+ env:
+ PR_TITLE: ${{ github.event.pull_request.title }}
+ PR_USER: ${{ github.event.pull_request.user.login }}
+ PR_URL: ${{ github.event.pull_request.html_url }}
+ DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
run: |
- PR_TITLE="${{ github.event.pull_request.title }}"
- PR_USER="${{ github.event.pull_request.user.login }}"
- PR_URL="${{ github.event.pull_request.html_url }}"
-
if [ "${{ steps.build_step.outcome }}" == "success" ]; then
COLOR=3066993
TITLE="💙 빌드 성공"
@@
- DESCRIPTION="**📄 Title : \`$PR_TITLE\`\n ✏️ 작성자 : \`$PR_USER\`\n\n[🔎 PR보러가기]($PR_URL)"
- curl -H "Content-Type: application/json" \
- -d "{
- \"embeds\": [{
- \"title\": \"$TITLE\",
- \"description\": \"$DESCRIPTION\",
- \"color\": $COLOR
- }]
- }" \
- "${{ secrets.DISCORD_WEBHOOK_URL }}"
+ DESCRIPTION="**📄 Title : \`$PR_TITLE\`\n ✏️ 작성자 : \`$PR_USER\`\n\n[🔎 PR보러가기]($PR_URL)"
+ jq -n \
+ --arg title "$TITLE" \
+ --arg description "$DESCRIPTION" \
+ --argjson color "$COLOR" \
+ '{embeds:[{title:$title,description:$description,color:$color}]}' \
+ | curl -fsS -H "Content-Type: application/json" --data `@-` "$DISCORD_WEBHOOK_URL"🧰 Tools🪛 actionlint (1.7.12)[error] 68-68: "github.event.pull_request.title" is potentially untrusted. avoid using it directly in inline scripts. instead, pass it through an environment variable. see https://docs.github.com/en/actions/reference/security/secure-use#good-practices-for-mitigating-script-injection-attacks for more details (expression) 🤖 Prompt for AI Agents |
||||||||||
|
|
||||||||||
| - name: Check Build Status | ||||||||||
| if: steps.check_step.outcome == 'failure' || steps.build_step.outcome == 'failure' | ||||||||||
| run: exit 1 | ||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| name: sync-fork-for-vercel-deploy | ||
|
|
||
| on: | ||
| push: | ||
| branches: [main] | ||
| workflow_dispatch: | ||
|
|
||
| permissions: | ||
| contents: write | ||
|
|
||
| jobs: | ||
| sync-fork: | ||
| runs-on: ubuntu-latest | ||
|
|
||
| steps: | ||
| - name: Checkout repository | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| token: ${{ secrets.FORK_SYNC_TOKEN }} | ||
|
|
||
|
Comment on lines
+16
to
+20
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: cat -n .github/workflows/vercel-sync.ymlRepository: DdingSroom/dding-sroom-frontend Length of output: 793 checkout 단계에서 불필요한 PAT 노출을 줄이자 현재 코드는 checkout 단계(19줄)에서 최소 권한 원칙을 적용하면, checkout은 기본 토큰으로 동작하고 PAT는 정말 필요한 fork-sync 단계에만 전달하는 게 안전해. 여기에 개선 예시 - name: Checkout repository
uses: actions/checkout@v4
with:
- token: ${{ secrets.FORK_SYNC_TOKEN }}
+ persist-credentials: false🤖 Prompt for AI Agents |
||
| - name: Sync upstream -> fork (u-zzn) | ||
| uses: tgymnich/fork-sync@v2.3.1 | ||
|
Comment on lines
+17
to
+22
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: cat -n .github/workflows/vercel-sync.yml | head -30Repository: DdingSroom/dding-sroom-frontend Length of output: 793 🌐 Web query:
💡 Result: SHA pinning provides significantly better supply chain security than version tags in GitHub Actions. Version tags (e.g., Citations:
서드파티 액션은 버전 태그 대신 커밋 SHA로 고정해야 한다. 배포 및 동기화 워크플로우에서는 공급망 보안이 특히 중요한데, 버전 태그(예: 반면 커밋 SHA는 변경 불가능한 Git 해시로, 자동으로 악의적인 업데이트를 실행할 수 없다. GitHub도 공식적으로 "action을 불변 릴리스로 사용하는 유일한 방법"으로 전체 길이의 커밋 SHA 고정을 권장하고 있다. 다음처럼 각 액션의 태그에 해당하는 커밋 SHA로 변경하자: - name: Checkout repository
- uses: actions/checkout@v4
+ uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
with:
token: ${{ secrets.FORK_SYNC_TOKEN }}
- name: Sync upstream -> fork (u-zzn)
- uses: tgymnich/fork-sync@v2.3.1
+ uses: tgymnich/fork-sync@<fork-sync-commit-sha> # v2.3.1SHA는 각 저장소의 태그 페이지에서 확인하거나 🤖 Prompt for AI Agents |
||
| with: | ||
| github_token: ${{ secrets.FORK_SYNC_TOKEN }} | ||
| owner: u-zzn | ||
| base: main | ||
| head: main | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: DdingSroom/dding-sroom-frontend
Length of output: 568
🏁 Script executed:
Repository: DdingSroom/dding-sroom-frontend
Length of output: 3502
🏁 Script executed:
Repository: DdingSroom/dding-sroom-frontend
Length of output: 133
🏁 Script executed:
Repository: DdingSroom/dding-sroom-frontend
Length of output: 86
🏁 Script executed:
cat -n README.md | head -50Repository: DdingSroom/dding-sroom-frontend
Length of output: 1590
GitHub Actions의 SHA 커밋 해시로 고정해서 공급망 공격 리스크 줄이기
현재 워크플로우에서 사용하는 액션들이 버전 태그(
v4,v2,v1)로만 고정되어 있는데, 태그는 언제든지 다른 커밋을 가리키도록 재지정될 수 있어요. 누군가가 해당 태그를 의도적으로(또는 실수로) 변경하면 예상과 다른 코드가 실행되는 보안 사고로 이어질 수 있습니다.특히 CI/CD 워크플로우는 저장소에 대한 권한을 가진 상태에서 실행되기 때문에, 이 지점을 통한 공급망 공격(supply chain attack)은 상당히 심각한 결과를 초래할 수 있어요.
다음처럼 구체적인 커밋 SHA로 고정하는 것이 안전합니다:
수정 예시
각 액션의 최신 SHA는 GitHub Marketplace에서 확인할 수 있습니다. 액션 페이지의 "Used by" 섹션이나 릴리스 페이지에서 원하는 버전의 커밋 해시를 찾아 적용하면 돼요.
수정이 필요한 라인들:
actions/checkout@v4pnpm/action-setup@v4actions/setup-node@v4marocchino/sticky-pull-request-comment@v2hkusu/review-assign-action@v1🤖 Prompt for AI Agents