From 9b30817021101efe7a5783d571fcfdd168309c13 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 4 Apr 2026 14:18:25 +0900 Subject: [PATCH] fix(ci): prevent shell injection in workflow expressions --- .github/workflows/ci.yml | 18 ++++++----- .github/workflows/sisyphus-agent.yml | 47 +++++++++++++++++----------- 2 files changed, 40 insertions(+), 25 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 84b1a2c93..e55772f45 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,8 +17,10 @@ jobs: if: github.event_name == 'pull_request' steps: - name: Check PR target branch + env: + BASE_REF: ${{ github.base_ref }} run: | - if [ "${{ github.base_ref }}" = "master" ]; then + if [ "$BASE_REF" = "master" ]; then echo "::error::PRs to master branch are not allowed. Please target the 'dev' branch instead." echo "" echo "PULL REQUESTS TO MASTER ARE BLOCKED" @@ -27,7 +29,7 @@ jobs: echo "Please close this PR and create a new one targeting 'dev'." exit 1 else - echo "PR targets '${{ github.base_ref }}' branch - OK" + echo "PR targets '${BASE_REF}' branch - OK" fi test: @@ -132,6 +134,10 @@ jobs: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Create or update draft release + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + NOTES: ${{ steps.notes.outputs.notes }} + TARGET_SHA: ${{ github.sha }} run: | EXISTING_DRAFT=$(gh release list --json tagName,isDraft --jq '.[] | select(.isDraft == true and .tagName == "next") | .tagName') @@ -141,7 +147,7 @@ jobs: --title "Upcoming Changes 🍿" \ --notes-file - \ --draft <<'EOF' - ${{ steps.notes.outputs.notes }} + $NOTES EOF else echo "Creating new draft release..." @@ -149,9 +155,7 @@ jobs: --title "Upcoming Changes 🍿" \ --notes-file - \ --draft \ - --target ${{ github.sha }} <<'EOF' - ${{ steps.notes.outputs.notes }} + --target "$TARGET_SHA" <<'EOF' + $NOTES EOF fi - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/sisyphus-agent.yml b/.github/workflows/sisyphus-agent.yml index 3d4f33cf1..7c83e3151 100644 --- a/.github/workflows/sisyphus-agent.yml +++ b/.github/workflows/sisyphus-agent.yml @@ -40,8 +40,10 @@ jobs: # gh CLI auth as sisyphus-dev-ai - name: Authenticate gh CLI as sisyphus-dev-ai + env: + GITHUB_TOKEN: ${{ secrets.GH_PAT }} run: | - echo "${{ secrets.GH_PAT }}" | gh auth login --with-token + echo "$GITHUB_TOKEN" | gh auth login --with-token gh auth status - name: Ensure tmux is available (Linux) @@ -372,28 +374,33 @@ jobs: if: steps.context.outputs.comment_id != '' env: GITHUB_TOKEN: ${{ secrets.GH_PAT }} + REPOSITORY: ${{ github.repository }} + COMMENT_ID: ${{ steps.context.outputs.comment_id }} run: | - gh api "/repos/${{ github.repository }}/issues/comments/${{ steps.context.outputs.comment_id }}/reactions" \ + gh api "/repos/${REPOSITORY}/issues/comments/${COMMENT_ID}/reactions" \ -X POST -f content="eyes" || true - name: Add working label if: steps.context.outputs.number != '' env: GITHUB_TOKEN: ${{ secrets.GH_PAT }} + REPOSITORY: ${{ github.repository }} + CONTEXT_TYPE: ${{ steps.context.outputs.type }} + CONTEXT_NUMBER: ${{ steps.context.outputs.number }} run: | gh label create "sisyphus: working" \ - --repo "${{ github.repository }}" \ + --repo "$REPOSITORY" \ --color "fcf2e1" \ --description "Sisyphus is currently working on this" \ --force || true - if [[ "${{ steps.context.outputs.type }}" == "pr" ]]; then - gh pr edit "${{ steps.context.outputs.number }}" \ - --repo "${{ github.repository }}" \ + if [[ "$CONTEXT_TYPE" == "pr" ]]; then + gh pr edit "$CONTEXT_NUMBER" \ + --repo "$REPOSITORY" \ --add-label "sisyphus: working" || true else - gh issue edit "${{ steps.context.outputs.number }}" \ - --repo "${{ github.repository }}" \ + gh issue edit "$CONTEXT_NUMBER" \ + --repo "$REPOSITORY" \ --add-label "sisyphus: working" || true fi @@ -514,26 +521,30 @@ jobs: if: always() env: GITHUB_TOKEN: ${{ secrets.GH_PAT }} + REPOSITORY: ${{ github.repository }} + COMMENT_ID: ${{ steps.context.outputs.comment_id }} + CONTEXT_NUMBER: ${{ steps.context.outputs.number }} + CONTEXT_TYPE: ${{ steps.context.outputs.type }} run: | - if [[ -n "${{ steps.context.outputs.comment_id }}" ]]; then - REACTION_ID=$(gh api "/repos/${{ github.repository }}/issues/comments/${{ steps.context.outputs.comment_id }}/reactions" \ + if [[ -n "$COMMENT_ID" ]]; then + REACTION_ID=$(gh api "/repos/${REPOSITORY}/issues/comments/${COMMENT_ID}/reactions" \ --jq '.[] | select(.content == "eyes" and .user.login == "sisyphus-dev-ai") | .id' | head -1) if [[ -n "$REACTION_ID" ]]; then - gh api -X DELETE "/repos/${{ github.repository }}/reactions/${REACTION_ID}" || true + gh api -X DELETE "/repos/${REPOSITORY}/reactions/${REACTION_ID}" || true fi - gh api "/repos/${{ github.repository }}/issues/comments/${{ steps.context.outputs.comment_id }}/reactions" \ + gh api "/repos/${REPOSITORY}/issues/comments/${COMMENT_ID}/reactions" \ -X POST -f content="+1" || true fi - if [[ -n "${{ steps.context.outputs.number }}" ]]; then - if [[ "${{ steps.context.outputs.type }}" == "pr" ]]; then - gh pr edit "${{ steps.context.outputs.number }}" \ - --repo "${{ github.repository }}" \ + if [[ -n "$CONTEXT_NUMBER" ]]; then + if [[ "$CONTEXT_TYPE" == "pr" ]]; then + gh pr edit "$CONTEXT_NUMBER" \ + --repo "$REPOSITORY" \ --remove-label "sisyphus: working" || true else - gh issue edit "${{ steps.context.outputs.number }}" \ - --repo "${{ github.repository }}" \ + gh issue edit "$CONTEXT_NUMBER" \ + --repo "$REPOSITORY" \ --remove-label "sisyphus: working" || true fi fi