From 82d1946e5b88224c89afd539522903b6eea382bb Mon Sep 17 00:00:00 2001 From: Shane da Silva Date: Sat, 29 Aug 2026 12:47:51 -0700 Subject: [PATCH 1/3] fix: restrict secret workflows to org members --- .github/sts/slack-config.sts.yaml | 3 ++ .github/sts/workflow-member.sts.yaml | 12 +++++ .github/workflows/preview.yml | 69 +++++++++++++++++++++++++++ .github/workflows/preview_destroy.yml | 36 ++++++++++---- .github/workflows/preview_sweep.yml | 33 +++++++++++-- .github/workflows/production.yml | 20 ++++++++ .github/workflows/pull_request.yml | 24 ---------- 7 files changed, 160 insertions(+), 37 deletions(-) create mode 100644 .github/sts/workflow-member.sts.yaml create mode 100644 .github/workflows/preview.yml diff --git a/.github/sts/slack-config.sts.yaml b/.github/sts/slack-config.sts.yaml index c67fe67..f93f42b 100644 --- a/.github/sts/slack-config.sts.yaml +++ b/.github/sts/slack-config.sts.yaml @@ -13,5 +13,8 @@ subject: - repo:tempoxyz@211589300/tip.bot@1232143975:environment:preview - repo:tempoxyz@211589300/tip.bot@1232143975:environment:production +claim_pattern: + job_workflow_ref: tempoxyz/tip\.bot/\.github/workflows/(preview_deploy|preview_destroy|preview_sweep|production)\.yml@refs/heads/main + permissions: secrets: write diff --git a/.github/sts/workflow-member.sts.yaml b/.github/sts/workflow-member.sts.yaml new file mode 100644 index 0000000..7f13839 --- /dev/null +++ b/.github/sts/workflow-member.sts.yaml @@ -0,0 +1,12 @@ +# Allows secret-bearing workflows loaded from main to check whether the actor +# who ultimately triggered the run is a current tempoxyz organization member. +# The token grants only organization membership visibility. +subject: + - repo:tempoxyz@211589300/tip.bot@1232143975:pull_request + - repo:tempoxyz@211589300/tip.bot@1232143975:ref:refs/heads/main + +claim_pattern: + job_workflow_ref: tempoxyz/tip\.bot/\.github/workflows/(preview|preview_destroy|preview_sweep|production)\.yml@refs/heads/main + +permissions: + members: read diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml new file mode 100644 index 0000000..b230280 --- /dev/null +++ b/.github/workflows/preview.yml @@ -0,0 +1,69 @@ +name: Preview + +on: # zizmor: ignore[dangerous-triggers] Loads from main and authorizes the triggering actor before checking out PR code. + workflow_run: + workflows: [Pull Request] + types: [completed] + +permissions: {} + +jobs: + authorize: + name: Authorize + if: github.event.workflow_run.conclusion == 'success' + runs-on: ubuntu-latest + outputs: + pr_number: ${{ steps.pr.outputs.number }} + permissions: + contents: read + id-token: write + pull-requests: read + steps: + - name: Mint organization membership token + id: member_token + uses: tempoxyz/gh-actions/actions/github-sts@dd1014bf8244fded7a501e701cafab240a4f9f0e # main + with: + policy: workflow-member + + - name: Check triggering actor organization membership + env: + ACTOR: ${{ github.run_attempt != '1' && github.triggering_actor || github.event.workflow_run.triggering_actor.login }} + GH_TOKEN: ${{ steps.member_token.outputs.token }} + run: gh api --silent "orgs/tempoxyz/members/${ACTOR}" + + - name: Resolve pull request + id: pr + env: + GH_TOKEN: ${{ github.token }} + HEAD_SHA: ${{ github.event.workflow_run.head_sha }} + run: | + NUMBER=$(gh api "repos/${{ github.repository }}/commits/${HEAD_SHA}/pulls" \ + --jq 'map(select(.state == "open" and .draft == false)) | first | .number // empty') + if [ -z "$NUMBER" ]; then + echo "No open, ready pull request found for ${HEAD_SHA}." + exit 1 + fi + echo "number=$NUMBER" >> "$GITHUB_OUTPUT" + + preview: + name: Preview + needs: authorize + permissions: + contents: read + id-token: write + issues: write + pull-requests: write + uses: ./.github/workflows/preview_deploy.yml + with: + pr_number: ${{ needs.authorize.outputs.pr_number }} + sha: ${{ github.event.workflow_run.head_sha }} + twitter_bot_handle: ${{ vars.TWITTER_BOT_HANDLE || 'tipbotgg' }} + secrets: + CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} + FEE_PAYER_PRIVATE_KEY_MAINNET: ${{ secrets.FEE_PAYER_PRIVATE_KEY_MAINNET }} + FEE_PAYER_PRIVATE_KEY_TESTNET: ${{ secrets.FEE_PAYER_PRIVATE_KEY_TESTNET }} + SECRET_KEY: ${{ secrets.SECRET_KEY }} + SLACK_CONFIG_ACCESS_TOKEN: ${{ secrets.SLACK_CONFIG_ACCESS_TOKEN }} + SLACK_CONFIG_REFRESH_TOKEN: ${{ secrets.SLACK_CONFIG_REFRESH_TOKEN }} + TEMPO_API_KEY: ${{ secrets.TEMPO_API_KEY }} diff --git a/.github/workflows/preview_destroy.yml b/.github/workflows/preview_destroy.yml index e1368b2..4b69dc0 100644 --- a/.github/workflows/preview_destroy.yml +++ b/.github/workflows/preview_destroy.yml @@ -1,18 +1,14 @@ name: Preview Destroy -on: - pull_request: +on: # zizmor: ignore[dangerous-triggers] Runs main's workflow and checkout; PR code is never checked out. + pull_request_target: types: [closed, converted_to_draft] concurrency: group: slack-config-ci cancel-in-progress: false -permissions: - contents: read - id-token: write - issues: write - pull-requests: write +permissions: {} env: PREVIEW_APEX: pr${{ github.event.pull_request.number }} @@ -21,11 +17,35 @@ env: WRANGLER_SEND_METRICS: false jobs: + authorize: + name: Authorize + runs-on: ubuntu-latest + permissions: + contents: read + id-token: write + steps: + - name: Mint organization membership token + id: member_token + uses: tempoxyz/gh-actions/actions/github-sts@dd1014bf8244fded7a501e701cafab240a4f9f0e # main + with: + policy: workflow-member + + - name: Check triggering actor organization membership + env: + ACTOR: ${{ github.triggering_actor }} + GH_TOKEN: ${{ steps.member_token.outputs.token }} + run: gh api --silent "orgs/tempoxyz/members/${ACTOR}" + destroy: name: Destroy - if: contains(fromJSON('["COLLABORATOR", "MEMBER", "OWNER"]'), github.event.pull_request.author_association) + needs: authorize runs-on: ubuntu-latest environment: preview + permissions: + contents: read + id-token: write + issues: write + pull-requests: write steps: - name: Read preview state id: state diff --git a/.github/workflows/preview_sweep.yml b/.github/workflows/preview_sweep.yml index 3b851d0..ae4f86f 100644 --- a/.github/workflows/preview_sweep.yml +++ b/.github/workflows/preview_sweep.yml @@ -9,20 +9,43 @@ concurrency: group: slack-config-ci cancel-in-progress: false -permissions: - contents: read - id-token: write - issues: write - pull-requests: write +permissions: {} env: WRANGLER_SEND_METRICS: false jobs: + authorize: + name: Authorize + if: github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/main' + runs-on: ubuntu-latest + permissions: + contents: read + id-token: write + steps: + - name: Mint organization membership token + id: member_token + uses: tempoxyz/gh-actions/actions/github-sts@dd1014bf8244fded7a501e701cafab240a4f9f0e # main + with: + policy: workflow-member + + - name: Check triggering actor organization membership + env: + ACTOR: ${{ github.triggering_actor }} + GH_TOKEN: ${{ steps.member_token.outputs.token }} + run: gh api --silent "orgs/tempoxyz/members/${ACTOR}" + sweep: name: Sweep Orphaned Previews + if: always() && (github.event_name == 'schedule' || needs.authorize.result == 'success') + needs: authorize runs-on: ubuntu-latest environment: preview + permissions: + contents: read + id-token: write + issues: write + pull-requests: write steps: - name: Checkout uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 diff --git a/.github/workflows/production.yml b/.github/workflows/production.yml index 8325be7..874db13 100644 --- a/.github/workflows/production.yml +++ b/.github/workflows/production.yml @@ -10,8 +10,28 @@ env: WRANGLER_SEND_METRICS: false jobs: + authorize: + name: Authorize + runs-on: ubuntu-latest + permissions: + contents: read + id-token: write + steps: + - name: Mint organization membership token + id: member_token + uses: tempoxyz/gh-actions/actions/github-sts@dd1014bf8244fded7a501e701cafab240a4f9f0e # main + with: + policy: workflow-member + + - name: Check triggering actor organization membership + env: + ACTOR: ${{ github.triggering_actor }} + GH_TOKEN: ${{ steps.member_token.outputs.token }} + run: gh api --silent "orgs/tempoxyz/members/${ACTOR}" + check: name: Check + needs: authorize permissions: contents: read uses: ./.github/workflows/check.yml diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index e9546f6..c4dd82a 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -18,27 +18,3 @@ jobs: check: name: Check uses: ./.github/workflows/check.yml - - preview: - name: Preview - if: github.event.pull_request.draft == false && contains(fromJSON('["COLLABORATOR", "MEMBER", "OWNER"]'), github.event.pull_request.author_association) - needs: check - permissions: - contents: read - id-token: write - issues: write - pull-requests: write - uses: ./.github/workflows/preview_deploy.yml - with: - pr_number: ${{ github.event.pull_request.number }} - sha: ${{ github.event.pull_request.head.sha }} - twitter_bot_handle: ${{ vars.TWITTER_BOT_HANDLE || 'tipbotgg' }} - secrets: - CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} - CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} - FEE_PAYER_PRIVATE_KEY_MAINNET: ${{ secrets.FEE_PAYER_PRIVATE_KEY_MAINNET }} - FEE_PAYER_PRIVATE_KEY_TESTNET: ${{ secrets.FEE_PAYER_PRIVATE_KEY_TESTNET }} - SECRET_KEY: ${{ secrets.SECRET_KEY }} - SLACK_CONFIG_ACCESS_TOKEN: ${{ secrets.SLACK_CONFIG_ACCESS_TOKEN }} - SLACK_CONFIG_REFRESH_TOKEN: ${{ secrets.SLACK_CONFIG_REFRESH_TOKEN }} - TEMPO_API_KEY: ${{ secrets.TEMPO_API_KEY }} From d19e70f4c66c949699fbd516d59fe53eebdd8357 Mon Sep 17 00:00:00 2001 From: Shane da Silva Date: Sat, 29 Aug 2026 12:55:00 -0700 Subject: [PATCH 2/3] fix: load privileged PR workflows from main --- .github/sts/workflow-member.sts.yaml | 2 +- .github/workflows/check.yml | 20 ++++++-- .github/workflows/preview.yml | 69 ---------------------------- .github/workflows/preview_sweep.yml | 5 +- .github/workflows/pull_request.yml | 51 +++++++++++++++++++- .github/workflows/zizmor.yml | 7 +-- 6 files changed, 72 insertions(+), 82 deletions(-) delete mode 100644 .github/workflows/preview.yml diff --git a/.github/sts/workflow-member.sts.yaml b/.github/sts/workflow-member.sts.yaml index 7f13839..f6a88e3 100644 --- a/.github/sts/workflow-member.sts.yaml +++ b/.github/sts/workflow-member.sts.yaml @@ -6,7 +6,7 @@ subject: - repo:tempoxyz@211589300/tip.bot@1232143975:ref:refs/heads/main claim_pattern: - job_workflow_ref: tempoxyz/tip\.bot/\.github/workflows/(preview|preview_destroy|preview_sweep|production)\.yml@refs/heads/main + job_workflow_ref: tempoxyz/tip\.bot/\.github/workflows/(pull_request|preview_destroy|preview_sweep|production)\.yml@refs/heads/main permissions: members: read diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 8bddef6..a7693d7 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -3,12 +3,14 @@ name: Check on: workflow_call: inputs: - skip_workers: - default: false + ref: + default: '' required: false - type: boolean - workflow_dispatch: - inputs: + type: string + repository: + default: '' + required: false + type: string skip_workers: default: false required: false @@ -31,6 +33,8 @@ jobs: uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: persist-credentials: false + ref: ${{ inputs.ref || github.sha }} + repository: ${{ inputs.repository || github.repository }} - name: Setup pnpm uses: ./.github/actions/setup-pnpm @@ -75,6 +79,8 @@ jobs: uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: persist-credentials: false + ref: ${{ inputs.ref || github.sha }} + repository: ${{ inputs.repository || github.repository }} - name: Setup pnpm uses: ./.github/actions/setup-pnpm @@ -91,6 +97,8 @@ jobs: uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: persist-credentials: false + ref: ${{ inputs.ref || github.sha }} + repository: ${{ inputs.repository || github.repository }} - name: Setup pnpm uses: ./.github/actions/setup-pnpm @@ -132,6 +140,8 @@ jobs: uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: persist-credentials: false + ref: ${{ inputs.ref || github.sha }} + repository: ${{ inputs.repository || github.repository }} - name: Setup pnpm uses: ./.github/actions/setup-pnpm diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml deleted file mode 100644 index b230280..0000000 --- a/.github/workflows/preview.yml +++ /dev/null @@ -1,69 +0,0 @@ -name: Preview - -on: # zizmor: ignore[dangerous-triggers] Loads from main and authorizes the triggering actor before checking out PR code. - workflow_run: - workflows: [Pull Request] - types: [completed] - -permissions: {} - -jobs: - authorize: - name: Authorize - if: github.event.workflow_run.conclusion == 'success' - runs-on: ubuntu-latest - outputs: - pr_number: ${{ steps.pr.outputs.number }} - permissions: - contents: read - id-token: write - pull-requests: read - steps: - - name: Mint organization membership token - id: member_token - uses: tempoxyz/gh-actions/actions/github-sts@dd1014bf8244fded7a501e701cafab240a4f9f0e # main - with: - policy: workflow-member - - - name: Check triggering actor organization membership - env: - ACTOR: ${{ github.run_attempt != '1' && github.triggering_actor || github.event.workflow_run.triggering_actor.login }} - GH_TOKEN: ${{ steps.member_token.outputs.token }} - run: gh api --silent "orgs/tempoxyz/members/${ACTOR}" - - - name: Resolve pull request - id: pr - env: - GH_TOKEN: ${{ github.token }} - HEAD_SHA: ${{ github.event.workflow_run.head_sha }} - run: | - NUMBER=$(gh api "repos/${{ github.repository }}/commits/${HEAD_SHA}/pulls" \ - --jq 'map(select(.state == "open" and .draft == false)) | first | .number // empty') - if [ -z "$NUMBER" ]; then - echo "No open, ready pull request found for ${HEAD_SHA}." - exit 1 - fi - echo "number=$NUMBER" >> "$GITHUB_OUTPUT" - - preview: - name: Preview - needs: authorize - permissions: - contents: read - id-token: write - issues: write - pull-requests: write - uses: ./.github/workflows/preview_deploy.yml - with: - pr_number: ${{ needs.authorize.outputs.pr_number }} - sha: ${{ github.event.workflow_run.head_sha }} - twitter_bot_handle: ${{ vars.TWITTER_BOT_HANDLE || 'tipbotgg' }} - secrets: - CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} - CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} - FEE_PAYER_PRIVATE_KEY_MAINNET: ${{ secrets.FEE_PAYER_PRIVATE_KEY_MAINNET }} - FEE_PAYER_PRIVATE_KEY_TESTNET: ${{ secrets.FEE_PAYER_PRIVATE_KEY_TESTNET }} - SECRET_KEY: ${{ secrets.SECRET_KEY }} - SLACK_CONFIG_ACCESS_TOKEN: ${{ secrets.SLACK_CONFIG_ACCESS_TOKEN }} - SLACK_CONFIG_REFRESH_TOKEN: ${{ secrets.SLACK_CONFIG_REFRESH_TOKEN }} - TEMPO_API_KEY: ${{ secrets.TEMPO_API_KEY }} diff --git a/.github/workflows/preview_sweep.yml b/.github/workflows/preview_sweep.yml index ae4f86f..c30a8e4 100644 --- a/.github/workflows/preview_sweep.yml +++ b/.github/workflows/preview_sweep.yml @@ -1,9 +1,10 @@ name: Preview Sweep on: + repository_dispatch: + types: [preview_sweep] schedule: - cron: '0 0 * * *' # Daily at midnight UTC - workflow_dispatch: concurrency: group: slack-config-ci @@ -17,7 +18,7 @@ env: jobs: authorize: name: Authorize - if: github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/main' + if: github.event_name == 'repository_dispatch' runs-on: ubuntu-latest permissions: contents: read diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index c4dd82a..6a14310 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -1,7 +1,7 @@ name: Pull Request -on: - pull_request: +on: # zizmor: ignore[dangerous-triggers] Loads from main; untrusted tests have no secrets and run separately from preview. + pull_request_target: types: [opened, synchronize, reopened, ready_for_review] permissions: @@ -18,3 +18,50 @@ jobs: check: name: Check uses: ./.github/workflows/check.yml + with: + ref: ${{ github.event.pull_request.head.sha }} + repository: ${{ github.event.pull_request.head.repo.full_name }} + + authorize: + name: Authorize + if: github.event.pull_request.draft == false + needs: check + runs-on: ubuntu-latest + permissions: + contents: read + id-token: write + steps: + - name: Mint organization membership token + id: member_token + uses: tempoxyz/gh-actions/actions/github-sts@dd1014bf8244fded7a501e701cafab240a4f9f0e # main + with: + policy: workflow-member + + - name: Check triggering actor organization membership + env: + ACTOR: ${{ github.triggering_actor }} + GH_TOKEN: ${{ steps.member_token.outputs.token }} + run: gh api --silent "orgs/tempoxyz/members/${ACTOR}" + + preview: + name: Preview + needs: authorize + permissions: + contents: read + id-token: write + issues: write + pull-requests: write + uses: ./.github/workflows/preview_deploy.yml + with: + pr_number: ${{ github.event.pull_request.number }} + sha: ${{ github.event.pull_request.head.sha }} + twitter_bot_handle: ${{ vars.TWITTER_BOT_HANDLE || 'tipbotgg' }} + secrets: + CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} + FEE_PAYER_PRIVATE_KEY_MAINNET: ${{ secrets.FEE_PAYER_PRIVATE_KEY_MAINNET }} + FEE_PAYER_PRIVATE_KEY_TESTNET: ${{ secrets.FEE_PAYER_PRIVATE_KEY_TESTNET }} + SECRET_KEY: ${{ secrets.SECRET_KEY }} + SLACK_CONFIG_ACCESS_TOKEN: ${{ secrets.SLACK_CONFIG_ACCESS_TOKEN }} + SLACK_CONFIG_REFRESH_TOKEN: ${{ secrets.SLACK_CONFIG_REFRESH_TOKEN }} + TEMPO_API_KEY: ${{ secrets.TEMPO_API_KEY }} diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml index afaa946..fbeb2dc 100644 --- a/.github/workflows/zizmor.yml +++ b/.github/workflows/zizmor.yml @@ -1,11 +1,10 @@ name: zizmor -on: - pull_request: +on: # zizmor: ignore[dangerous-triggers] Loads from main and audits PR code without secrets or write permissions. + pull_request_target: branches: ['**'] push: branches: [main] - workflow_dispatch: permissions: {} @@ -21,6 +20,8 @@ jobs: uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: persist-credentials: false + ref: ${{ github.event.pull_request.head.sha || github.sha }} + repository: ${{ github.event.pull_request.head.repo.full_name || github.repository }} - name: Run zizmor uses: zizmorcore/zizmor-action@b572f7b1a1c2d41efaab43d504f68d215c3cd727 # v0.5.4 From 2f59dccf22cebc9be3e26e9f24f1f045b10d9e55 Mon Sep 17 00:00:00 2001 From: Shane da Silva Date: Sat, 29 Aug 2026 12:56:48 -0700 Subject: [PATCH 3/3] fix: keep PR checks unprivileged --- .github/sts/workflow-member.sts.yaml | 2 +- .github/workflows/check.yml | 16 ------- .github/workflows/preview.yml | 69 ++++++++++++++++++++++++++++ .github/workflows/pull_request.yml | 51 +------------------- .github/workflows/zizmor.yml | 6 +-- 5 files changed, 74 insertions(+), 70 deletions(-) create mode 100644 .github/workflows/preview.yml diff --git a/.github/sts/workflow-member.sts.yaml b/.github/sts/workflow-member.sts.yaml index f6a88e3..7f13839 100644 --- a/.github/sts/workflow-member.sts.yaml +++ b/.github/sts/workflow-member.sts.yaml @@ -6,7 +6,7 @@ subject: - repo:tempoxyz@211589300/tip.bot@1232143975:ref:refs/heads/main claim_pattern: - job_workflow_ref: tempoxyz/tip\.bot/\.github/workflows/(pull_request|preview_destroy|preview_sweep|production)\.yml@refs/heads/main + job_workflow_ref: tempoxyz/tip\.bot/\.github/workflows/(preview|preview_destroy|preview_sweep|production)\.yml@refs/heads/main permissions: members: read diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index a7693d7..1cbbad2 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -3,14 +3,6 @@ name: Check on: workflow_call: inputs: - ref: - default: '' - required: false - type: string - repository: - default: '' - required: false - type: string skip_workers: default: false required: false @@ -33,8 +25,6 @@ jobs: uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: persist-credentials: false - ref: ${{ inputs.ref || github.sha }} - repository: ${{ inputs.repository || github.repository }} - name: Setup pnpm uses: ./.github/actions/setup-pnpm @@ -79,8 +69,6 @@ jobs: uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: persist-credentials: false - ref: ${{ inputs.ref || github.sha }} - repository: ${{ inputs.repository || github.repository }} - name: Setup pnpm uses: ./.github/actions/setup-pnpm @@ -97,8 +85,6 @@ jobs: uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: persist-credentials: false - ref: ${{ inputs.ref || github.sha }} - repository: ${{ inputs.repository || github.repository }} - name: Setup pnpm uses: ./.github/actions/setup-pnpm @@ -140,8 +126,6 @@ jobs: uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: persist-credentials: false - ref: ${{ inputs.ref || github.sha }} - repository: ${{ inputs.repository || github.repository }} - name: Setup pnpm uses: ./.github/actions/setup-pnpm diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml new file mode 100644 index 0000000..b230280 --- /dev/null +++ b/.github/workflows/preview.yml @@ -0,0 +1,69 @@ +name: Preview + +on: # zizmor: ignore[dangerous-triggers] Loads from main and authorizes the triggering actor before checking out PR code. + workflow_run: + workflows: [Pull Request] + types: [completed] + +permissions: {} + +jobs: + authorize: + name: Authorize + if: github.event.workflow_run.conclusion == 'success' + runs-on: ubuntu-latest + outputs: + pr_number: ${{ steps.pr.outputs.number }} + permissions: + contents: read + id-token: write + pull-requests: read + steps: + - name: Mint organization membership token + id: member_token + uses: tempoxyz/gh-actions/actions/github-sts@dd1014bf8244fded7a501e701cafab240a4f9f0e # main + with: + policy: workflow-member + + - name: Check triggering actor organization membership + env: + ACTOR: ${{ github.run_attempt != '1' && github.triggering_actor || github.event.workflow_run.triggering_actor.login }} + GH_TOKEN: ${{ steps.member_token.outputs.token }} + run: gh api --silent "orgs/tempoxyz/members/${ACTOR}" + + - name: Resolve pull request + id: pr + env: + GH_TOKEN: ${{ github.token }} + HEAD_SHA: ${{ github.event.workflow_run.head_sha }} + run: | + NUMBER=$(gh api "repos/${{ github.repository }}/commits/${HEAD_SHA}/pulls" \ + --jq 'map(select(.state == "open" and .draft == false)) | first | .number // empty') + if [ -z "$NUMBER" ]; then + echo "No open, ready pull request found for ${HEAD_SHA}." + exit 1 + fi + echo "number=$NUMBER" >> "$GITHUB_OUTPUT" + + preview: + name: Preview + needs: authorize + permissions: + contents: read + id-token: write + issues: write + pull-requests: write + uses: ./.github/workflows/preview_deploy.yml + with: + pr_number: ${{ needs.authorize.outputs.pr_number }} + sha: ${{ github.event.workflow_run.head_sha }} + twitter_bot_handle: ${{ vars.TWITTER_BOT_HANDLE || 'tipbotgg' }} + secrets: + CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} + FEE_PAYER_PRIVATE_KEY_MAINNET: ${{ secrets.FEE_PAYER_PRIVATE_KEY_MAINNET }} + FEE_PAYER_PRIVATE_KEY_TESTNET: ${{ secrets.FEE_PAYER_PRIVATE_KEY_TESTNET }} + SECRET_KEY: ${{ secrets.SECRET_KEY }} + SLACK_CONFIG_ACCESS_TOKEN: ${{ secrets.SLACK_CONFIG_ACCESS_TOKEN }} + SLACK_CONFIG_REFRESH_TOKEN: ${{ secrets.SLACK_CONFIG_REFRESH_TOKEN }} + TEMPO_API_KEY: ${{ secrets.TEMPO_API_KEY }} diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index 6a14310..c4dd82a 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -1,7 +1,7 @@ name: Pull Request -on: # zizmor: ignore[dangerous-triggers] Loads from main; untrusted tests have no secrets and run separately from preview. - pull_request_target: +on: + pull_request: types: [opened, synchronize, reopened, ready_for_review] permissions: @@ -18,50 +18,3 @@ jobs: check: name: Check uses: ./.github/workflows/check.yml - with: - ref: ${{ github.event.pull_request.head.sha }} - repository: ${{ github.event.pull_request.head.repo.full_name }} - - authorize: - name: Authorize - if: github.event.pull_request.draft == false - needs: check - runs-on: ubuntu-latest - permissions: - contents: read - id-token: write - steps: - - name: Mint organization membership token - id: member_token - uses: tempoxyz/gh-actions/actions/github-sts@dd1014bf8244fded7a501e701cafab240a4f9f0e # main - with: - policy: workflow-member - - - name: Check triggering actor organization membership - env: - ACTOR: ${{ github.triggering_actor }} - GH_TOKEN: ${{ steps.member_token.outputs.token }} - run: gh api --silent "orgs/tempoxyz/members/${ACTOR}" - - preview: - name: Preview - needs: authorize - permissions: - contents: read - id-token: write - issues: write - pull-requests: write - uses: ./.github/workflows/preview_deploy.yml - with: - pr_number: ${{ github.event.pull_request.number }} - sha: ${{ github.event.pull_request.head.sha }} - twitter_bot_handle: ${{ vars.TWITTER_BOT_HANDLE || 'tipbotgg' }} - secrets: - CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} - CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} - FEE_PAYER_PRIVATE_KEY_MAINNET: ${{ secrets.FEE_PAYER_PRIVATE_KEY_MAINNET }} - FEE_PAYER_PRIVATE_KEY_TESTNET: ${{ secrets.FEE_PAYER_PRIVATE_KEY_TESTNET }} - SECRET_KEY: ${{ secrets.SECRET_KEY }} - SLACK_CONFIG_ACCESS_TOKEN: ${{ secrets.SLACK_CONFIG_ACCESS_TOKEN }} - SLACK_CONFIG_REFRESH_TOKEN: ${{ secrets.SLACK_CONFIG_REFRESH_TOKEN }} - TEMPO_API_KEY: ${{ secrets.TEMPO_API_KEY }} diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml index fbeb2dc..85fd919 100644 --- a/.github/workflows/zizmor.yml +++ b/.github/workflows/zizmor.yml @@ -1,7 +1,7 @@ name: zizmor -on: # zizmor: ignore[dangerous-triggers] Loads from main and audits PR code without secrets or write permissions. - pull_request_target: +on: + pull_request: branches: ['**'] push: branches: [main] @@ -20,8 +20,6 @@ jobs: uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: persist-credentials: false - ref: ${{ github.event.pull_request.head.sha || github.sha }} - repository: ${{ github.event.pull_request.head.repo.full_name || github.repository }} - name: Run zizmor uses: zizmorcore/zizmor-action@b572f7b1a1c2d41efaab43d504f68d215c3cd727 # v0.5.4