mirror of
https://github.com/twentyhq/twenty
synced 2026-04-21 21:47:38 +00:00
## Summary - Fix expression injection vulnerabilities in composite actions (`restore-cache`, `nx-affected`) and workflow files (`claude.yml`) - Reduce overly broad permissions in `ci-utils.yaml` (Danger.js) and `ci-breaking-changes.yaml` - Restructure `preview-env-dispatch.yaml`: auto-trigger for members, opt-in for contributor PRs via `preview-app` label (safe because keepalive has no write tokens) - Isolate all write-access operations (PR comments, cross-repo posting) to a new dedicated [`twentyhq/ci-privileged`](https://github.com/twentyhq/ci-privileged) repo via `repository_dispatch`, so that workflows in twenty that execute contributor code never have write tokens - Create `post-ci-comments.yaml` (`workflow_run` bridge) to dispatch breaking changes results to ci-privileged, solving the [fork PR comment issue](https://github.com/twentyhq/twenty/pull/13713#issuecomment-3168999083) - Delete 5 unused secrets and broken `i18n-qa-report` workflow - Remove `TWENTY_DISPATCH_TOKEN` from twenty (moved to ci-privileged as `CORE_TEAM_ISSUES_COMMENT_TOKEN`) - Use `toJSON()` for all `client-payload` values to prevent JSON injection ## Security model after this PR | Workflow | Executes fork code? | Write tokens available? | |----------|---------------------|------------------------| | preview-env-keepalive | Yes | None (contents: read only) | | preview-env-dispatch | No (base branch) | CI_PRIVILEGED_DISPATCH_TOKEN only | | ci-breaking-changes | Yes | None (contents: read only) | | post-ci-comments (workflow_run) | No (default branch) | CI_PRIVILEGED_DISPATCH_TOKEN only | | claude.yml | No (base branch) | CI_PRIVILEGED_DISPATCH_TOKEN, CLAUDE_CODE_OAUTH_TOKEN | | ci-utils (Danger.js) | No (base branch) | GITHUB_TOKEN (scoped) | All actual write tokens (`TWENTY_PR_COMMENT_TOKEN`, `CORE_TEAM_ISSUES_COMMENT_TOKEN`) live in `twentyhq/ci-privileged` with strict CODEOWNERS review and branch protection. ## Test plan - [ ] Verify preview environment comments still appear on member PRs - [ ] Verify adding `preview-app` label triggers preview for contributor PRs - [ ] Verify breaking changes reports still post on PRs (including fork PRs) - [ ] Verify Claude cross-repo responses still post on core-team-issues - [ ] Confirm ci-privileged branch protection is enforced
71 lines
2.6 KiB
YAML
71 lines
2.6 KiB
YAML
name: Post CI Comments
|
|
|
|
on:
|
|
workflow_run:
|
|
workflows: ['GraphQL and OpenAPI Breaking Changes Detection']
|
|
types: [completed]
|
|
|
|
permissions:
|
|
actions: read
|
|
|
|
jobs:
|
|
dispatch-breaking-changes:
|
|
if: github.event.workflow_run.conclusion == 'success'
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 5
|
|
steps:
|
|
- name: Get PR number from workflow run
|
|
id: pr-info
|
|
uses: actions/github-script@v7
|
|
with:
|
|
script: |
|
|
const runId = context.payload.workflow_run.id;
|
|
const headSha = context.payload.workflow_run.head_sha;
|
|
const headBranch = context.payload.workflow_run.head_branch;
|
|
const headRepo = context.payload.workflow_run.head_repository;
|
|
|
|
// workflow_run.pull_requests is empty for fork PRs,
|
|
// so fall back to searching by head SHA
|
|
let pullRequests = context.payload.workflow_run.pull_requests;
|
|
let prNumber;
|
|
|
|
if (pullRequests && pullRequests.length > 0) {
|
|
prNumber = pullRequests[0].number;
|
|
} else {
|
|
core.info(`pull_requests is empty (likely a fork PR), searching by SHA ${headSha}`);
|
|
const owner = context.repo.owner;
|
|
const repo = context.repo.repo;
|
|
const headLabel = `${headRepo.owner.login}:${headBranch}`;
|
|
|
|
const { data: prs } = await github.rest.pulls.list({
|
|
owner,
|
|
repo,
|
|
state: 'open',
|
|
head: headLabel,
|
|
per_page: 1,
|
|
});
|
|
|
|
if (prs.length > 0) {
|
|
prNumber = prs[0].number;
|
|
}
|
|
}
|
|
|
|
if (!prNumber) {
|
|
core.info('No pull request found for this workflow run');
|
|
core.setOutput('has_pr', 'false');
|
|
return;
|
|
}
|
|
|
|
core.setOutput('pr_number', prNumber);
|
|
core.setOutput('run_id', runId);
|
|
core.setOutput('has_pr', 'true');
|
|
core.info(`PR #${prNumber}, Run ID: ${runId}`);
|
|
|
|
- name: Dispatch to ci-privileged
|
|
if: steps.pr-info.outputs.has_pr == 'true'
|
|
uses: peter-evans/repository-dispatch@v2
|
|
with:
|
|
token: ${{ secrets.CI_PRIVILEGED_DISPATCH_TOKEN }}
|
|
repository: twentyhq/ci-privileged
|
|
event-type: breaking-changes-report
|
|
client-payload: '{"pr_number": ${{ toJSON(steps.pr-info.outputs.pr_number) }}, "run_id": ${{ toJSON(steps.pr-info.outputs.run_id) }}, "repo": ${{ toJSON(github.repository) }}, "branch_state": ${{ toJSON(github.event.workflow_run.head_branch) }}}'
|