## What One-line token swap on the same-repo dispatch step in [`preview-env-dispatch.yaml`](.github/workflows/preview-env-dispatch.yaml#L40): `secrets.GITHUB_TOKEN` → `secrets.CI_PRIVILEGED_DISPATCH_TOKEN`. ## Why Regression from [#20476](https://github.com/twentyhq/twenty/pull/20476) ("security: harden CI against supply-chain attacks"), merged 2026-05-12. That PR replaced ```yaml uses: peter-evans/repository-dispatch@v2 with: token: ${{ secrets.GITHUB_TOKEN }} ... ``` with a raw `gh api` call but kept `GITHUB_TOKEN`: ```yaml env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | gh api repos/"$REPOSITORY"/dispatches -f event_type=preview-environment ... ``` The auto-provisioned `GITHUB_TOKEN` can't fire `repository_dispatch` via `gh api` even when the workflow declares `permissions: contents: write`. The action used a different code path that worked; the CLI requires a token with `repo` scope. So every dispatch from this workflow has returned `403 Resource not accessible by integration` since that PR merged — except for runs the `author_association` / `preview-app` label gate skips entirely (which then show "success" because no jobs ran). Recent failed example: https://github.com/twentyhq/twenty/actions/runs/26162974597/job/76959379235?pr=20769 ## The fix `secrets.CI_PRIVILEGED_DISPATCH_TOKEN` already exists in repo secrets and is **already used** by the immediately-following cross-repo dispatch step in the same file. Using it for the same-repo dispatch too matches the surrounding code and is consistent with the original hardening intent (use a scoped PAT, not the auto-provisioned token). ## Test plan - [ ] Merge this PR - [ ] Next PR open / sync / reopen on a member's branch → check that `Preview Environment Dispatch` succeeds (no 403) - [ ] Confirm `Preview Environment Keep Alive` workflow gets triggered (the downstream effect of the dispatch) - [ ] Confirm the tunnel URL sticky comment lands on the PR Discovered while testing an unrelated PR ([#20762](https://github.com/twentyhq/twenty/pull/20762)). Independent fix.
63 lines
2.2 KiB
YAML
63 lines
2.2 KiB
YAML
name: 'Preview Environment Dispatch'
|
|
|
|
permissions:
|
|
contents: write
|
|
|
|
on:
|
|
pull_request_target:
|
|
types: [opened, synchronize, reopened, labeled]
|
|
paths:
|
|
- packages/twenty-docker/**
|
|
- packages/twenty-server/**
|
|
- packages/twenty-front/**
|
|
- .github/workflows/preview-env-dispatch.yaml
|
|
- .github/workflows/preview-env-keepalive.yaml
|
|
|
|
concurrency:
|
|
group: ${{ github.workflow }}-${{ github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
jobs:
|
|
trigger-preview:
|
|
if: |
|
|
(github.event.action == 'labeled' && github.event.label.name == 'preview-app') ||
|
|
(
|
|
(
|
|
github.event.pull_request.author_association == 'MEMBER' ||
|
|
github.event.pull_request.author_association == 'OWNER' ||
|
|
github.event.pull_request.author_association == 'COLLABORATOR'
|
|
) && (
|
|
github.event.action == 'opened' ||
|
|
github.event.action == 'synchronize' ||
|
|
github.event.action == 'reopened'
|
|
)
|
|
)
|
|
timeout-minutes: 5
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Trigger preview environment workflow
|
|
env:
|
|
GH_TOKEN: ${{ secrets.CI_PRIVILEGED_DISPATCH_TOKEN }}
|
|
PR_NUMBER: ${{ github.event.pull_request.number }}
|
|
PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
|
|
REPOSITORY: ${{ github.repository }}
|
|
run: |
|
|
gh api repos/"$REPOSITORY"/dispatches \
|
|
-f event_type=preview-environment \
|
|
-f "client_payload[pr_number]=$PR_NUMBER" \
|
|
-f "client_payload[pr_head_sha]=$PR_HEAD_SHA" \
|
|
-f "client_payload[repo_full_name]=$REPOSITORY"
|
|
|
|
- name: Dispatch to ci-privileged for PR comment
|
|
env:
|
|
GH_TOKEN: ${{ secrets.CI_PRIVILEGED_DISPATCH_TOKEN }}
|
|
PR_NUMBER: ${{ github.event.pull_request.number }}
|
|
KEEPALIVE_DISPATCH_TIME: ${{ github.event.pull_request.updated_at }}
|
|
REPOSITORY: ${{ github.repository }}
|
|
run: |
|
|
gh api repos/twentyhq/ci-privileged/dispatches \
|
|
-f event_type=preview-env-url \
|
|
-f "client_payload[pr_number]=$PR_NUMBER" \
|
|
-f "client_payload[keepalive_dispatch_time]=$KEEPALIVE_DISPATCH_TIME" \
|
|
-f "client_payload[repo]=$REPOSITORY"
|