1010 branches :
1111 - main
1212 - develop
13- push :
14- branches :
15- - ci/pr-**
1613
1714env :
1815 REGION : us-west-2
@@ -26,158 +23,17 @@ env:
2623 ECR_REPOSITORY : " roboverse-dev"
2724
2825jobs :
29- prepare-or-promote :
30- name : prepare-or-promote
31- runs-on : ubuntu-latest
32- permissions :
33- contents : write
34- pull-requests : write
35- issues : write
36- env :
37- PRIV_CI_PUSH_TOKEN : ${{ secrets.PRIV_CI_PUSH_TOKEN }}
38- outputs :
39- run_direct : ${{ steps.decide.outputs.run_direct }}
40- pr_number : ${{ steps.decide.outputs.pr_number }}
41- reason : ${{ steps.decide.outputs.reason }}
42- steps :
43- - name : Route CI flow
44- id : decide
45- env :
46- GITHUB_EVENT_NAME : ${{ github.event_name }}
47- GITHUB_REF : ${{ github.ref }}
48- PR_NUMBER : ${{ github.event.pull_request.number || '' }}
49- HEAD_REPO : ${{ github.event.pull_request.head.repo.full_name || '' }}
50- BASE_REPO : ${{ github.repository }}
51- GH_TOKEN : ${{ secrets.GITHUB_TOKEN }}
52- GITHUB_EVENT_PATH : ${{ github.event_path }}
53- run : |
54- RUN_DIRECT="false"
55- PR_NUM="${PR_NUMBER}"
56- REASON=""
57-
58- case "$GITHUB_EVENT_NAME" in
59- merge_group)
60- BASE_REPO_NAME="${BASE_REPO}"
61- HAS_FORK="false"
62- PRS=$(jq -r '.merge_group.pull_requests[].number // empty' "$GITHUB_EVENT_PATH" 2>/dev/null || true)
63-
64- if [ -z "$PRS" ]; then
65- echo "No pull requests listed in merge_group payload; defaulting to same-repo."
66- fi
67-
68- for PR in $PRS; do
69- HEAD_REPO_NAME=$(gh api "repos/${BASE_REPO_NAME}/pulls/${PR}" --jq '.head.repo.full_name' 2>/dev/null || echo "")
70- BASE_REPO_FROM_PR=$(gh api "repos/${BASE_REPO_NAME}/pulls/${PR}" --jq '.base.repo.full_name' 2>/dev/null || echo "$BASE_REPO_NAME")
71-
72- if [ -z "$HEAD_REPO_NAME" ]; then
73- echo "Warning: could not determine head repo for PR #$PR; assuming same-repo."
74- continue
75- fi
76-
77- if [ "$HEAD_REPO_NAME" != "$BASE_REPO_FROM_PR" ]; then
78- HAS_FORK="true"
79- echo "Detected fork PR #$PR (head repo: $HEAD_REPO_NAME, base repo: $BASE_REPO_FROM_PR)"
80- else
81- echo "PR #$PR is same-repo (head repo: $HEAD_REPO_NAME)"
82- fi
83- done
84-
85- if [ "$HAS_FORK" = "true" ]; then
86- RUN_DIRECT="false"
87- REASON="merge_group_contains_fork"
88- else
89- RUN_DIRECT="true"
90- REASON="merge_group_same_repo_only"
91- fi
92- ;;
93- push)
94- if [[ "$GITHUB_REF" =~ ^refs/heads/ci/pr- ]]; then
95- RUN_DIRECT="true"
96- REASON="ci/pr-* push"
97- PR_NUM="${GITHUB_REF#refs/heads/ci/pr-}"
98- else
99- REASON="unsupported push ref"
100- fi
101- ;;
102- workflow_dispatch)
103- RUN_DIRECT="true"
104- REASON="manual dispatch"
105- ;;
106- pull_request_target)
107- if [ "$HEAD_REPO" = "$BASE_REPO" ]; then
108- REASON="same-repo PR, no promotion needed"
109- else
110- REASON="fork PR requires promotion"
111- fi
112- ;;
113- *)
114- REASON="unsupported event"
115- ;;
116- esac
117-
118- echo "run_direct=${RUN_DIRECT}" >> "$GITHUB_OUTPUT"
119- echo "pr_number=${PR_NUM}" >> "$GITHUB_OUTPUT"
120- echo "reason=${REASON}" >> "$GITHUB_OUTPUT"
121-
122- - name : Check actor permission
123- id : perm
124- if : >
125- github.event_name == 'pull_request_target' &&
126- steps.decide.outputs.reason == 'fork PR requires promotion' &&
127- env.PRIV_CI_PUSH_TOKEN != '' &&
128- env.PRIV_CI_PUSH_TOKEN != null
129- env :
130- ACTOR : ${{ github.actor }}
131- REPO : ${{ github.repository }}
132- GH_TOKEN : ${{ secrets.GITHUB_TOKEN }}
133- run : |
134- perm=$(gh api "repos/$REPO/collaborators/$ACTOR/permission" --jq .permission 2>/dev/null || echo "none")
135- echo "permission=$perm" >> "$GITHUB_OUTPUT"
136- echo "Actor: $ACTOR, permission: $perm"
137-
138- - name : Checkout repository for promotion
139- if : >
140- github.event_name == 'pull_request_target' &&
141- steps.decide.outputs.reason == 'fork PR requires promotion' &&
142- (steps.perm.outputs.permission == 'write' || steps.perm.outputs.permission == 'maintain' || steps.perm.outputs.permission == 'admin')
143- uses : actions/checkout@v4
144- with :
145- fetch-depth : 0
146- token : ${{ secrets.PRIV_CI_PUSH_TOKEN }}
147-
148- - name : Promote fork PR to ci/pr-* branch
149- if : >
150- github.event_name == 'pull_request_target' &&
151- steps.decide.outputs.reason == 'fork PR requires promotion' &&
152- (steps.perm.outputs.permission == 'write' || steps.perm.outputs.permission == 'maintain' || steps.perm.outputs.permission == 'admin')
153- env :
154- PR_NUMBER : ${{ steps.decide.outputs.pr_number }}
155- REPO : ${{ github.repository }}
156- GH_TOKEN : ${{ secrets.PRIV_CI_PUSH_TOKEN }}
157- run : |
158- set -euo pipefail
159- BRANCH="ci/pr-${PR_NUMBER}"
160- git config --global user.name "github-actions[bot]"
161- git config --global user.email "github-actions[bot]@users.noreply.github.com"
162- gh pr checkout "$PR_NUMBER"
163- git push origin HEAD:"$BRANCH"
164-
165-
16626 pre-merge-tests :
167- needs : prepare-or-promote
168- if : needs.prepare-or-promote.outputs.run_direct == 'true'
27+ if : github.event_name == 'merge_group' || github.event_name == 'workflow_dispatch'
16928 permissions :
170- contents : write # Need write access to delete ci/pr-* branches
29+ contents : read
17130 pull-requests : write
172- issues : write # Post status comment back to PR
31+ issues : write
17332 runs-on : codebuild-EC2_Launcher2-${{ github.run_id }}-${{ github.run_attempt }}
17433 timeout-minutes : 720
17534 steps :
176- # change to the source code directory
17735 - name : Checkout code
17836 uses : actions/checkout@v4
179- with :
180- token : ${{ secrets.PRIV_CI_PUSH_TOKEN }}
18137 - run : aws --version
18238 # ############ Prebuild ############
18339 - name : pre_build
@@ -540,182 +396,26 @@ jobs:
540396 if-no-files-found : warn
541397 retention-days : 7
542398
543-
544- - name : Report commit status to PR
545- if : always()
546- uses : actions/github-script@v7
547- env :
548- JOB_STATUS : ${{ job.status }}
549- PRIV_CI_PUSH_TOKEN : ${{ secrets.PRIV_CI_PUSH_TOKEN }}
550- with :
551- github-token : ${{ secrets.PRIV_CI_PUSH_TOKEN }}
552- script : |
553- const status = process.env.JOB_STATUS;
554- const ref = context.ref;
555-
556- // Only report status for ci/pr-* branches
557- const match = ref.match(/^refs\/heads\/ci\/pr-(\d+)$/);
558- if (!match) {
559- core.info(`Ref ${ref} is not a ci/pr-* branch, skip status reporting.`);
560- return;
561- }
562-
563- const prNumber = Number(match[1]);
564-
565- // Get the PR's HEAD SHA
566- const { data: pr } = await github.rest.pulls.get({
567- owner: context.repo.owner,
568- repo: context.repo.repo,
569- pull_number: prNumber
570- });
571-
572- const sha = pr.head.sha;
573- core.info(`Reporting status to PR #${prNumber} commit ${sha}`);
574-
575- // Map job status to commit status state
576- let state, description;
577- if (status === 'success') {
578- state = 'success';
579- description = 'Privileged CI tests passed';
580- } else if (status === 'cancelled') {
581- state = 'error';
582- description = 'Privileged CI tests were cancelled';
583- } else {
584- state = 'failure';
585- description = 'Privileged CI tests failed';
586- }
587-
588- const runUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`;
589-
590- // Create commit status
591- await github.rest.repos.createCommitStatus({
592- owner: context.repo.owner,
593- repo: context.repo.repo,
594- sha: sha,
595- state: state,
596- context: 'pre-merge-tests',
597- description: description,
598- target_url: runUrl
599- });
600-
601- core.info(`✅ Reported status '${state}' to commit ${sha}`);
602-
603- - name : Clean up ci/pr-* branch
604- if : always()
605- run : |
606- REF="${GITHUB_REF}"
607- # Only delete if we're running on a ci/pr-* branch
608- if [[ "$REF" =~ ^refs/heads/ci/pr-[0-9]+$ ]]; then
609- BRANCH="${REF#refs/heads/}"
610- echo "Cleaning up temporary branch: $BRANCH"
611- # Delete the branch from remote (ignore errors if already deleted)
612- git push origin --delete "$BRANCH" 2>/dev/null || echo "Branch $BRANCH already deleted or not found"
613- echo "✓ Cleanup complete"
614- else
615- echo "Not a ci/pr-* branch (ref: $REF), skipping cleanup"
616- fi
617-
618- fork-merge-group-check :
619- needs : prepare-or-promote
620- if : needs.prepare-or-promote.outputs.reason == 'merge_group_contains_fork'
399+ workflow-integrity-check :
621400 runs-on : ubuntu-latest
401+ if : github.event_name == 'pull_request_target'
622402 permissions :
623- statuses : write
403+ pull-requests : read
624404 steps :
625- - name : Check pre-merge-tests status for fork PRs
405+ - name : Check for workflow changes
626406 env :
627407 GH_TOKEN : ${{ secrets.GITHUB_TOKEN }}
628- GITHUB_REPOSITORY : ${{ github.repository }}
629- GITHUB_EVENT_PATH : ${{ github.event_path }}
408+ PR_NUMBER : ${{ github.event.pull_request.number }}
630409 run : |
631- set -euo pipefail
632-
633- echo "merge_group contains fork PR(s). Checking pre-merge-tests commit statuses..."
634-
635- # Extract PR numbers from merge_group payload
636- PRS=$(jq -r '.merge_group.pull_requests[].number // empty' "$GITHUB_EVENT_PATH" 2>/dev/null || true)
637-
638- if [ -z "$PRS" ]; then
639- echo "⚠️ Warning: No pull requests listed in merge_group payload."
640- echo "This is unexpected. Proceeding with caution (passing)."
641- exit 0
642- fi
643-
644- ALL_PASSED=true
645- for PR in $PRS; do
646- # Check if this is a fork PR
647- PR_DATA=$(gh api "repos/${GITHUB_REPOSITORY}/pulls/${PR}" 2>/dev/null || echo "{}")
648- HEAD_REPO=$(echo "$PR_DATA" | jq -r '.head.repo.full_name // ""')
649- BASE_REPO=$(echo "$PR_DATA" | jq -r '.base.repo.full_name // ""')
650- HEAD_SHA=$(echo "$PR_DATA" | jq -r '.head.sha // ""')
651-
652- if [ "$HEAD_REPO" = "$BASE_REPO" ]; then
653- echo "PR #$PR is same-repo, skipping status check."
654- continue
655- fi
656-
657- if [ -z "$HEAD_SHA" ]; then
658- echo "❌ Could not get HEAD SHA for PR #$PR."
659- ALL_PASSED=false
660- continue
661- fi
662-
663- echo "PR #$PR is from fork ($HEAD_REPO). Checking commit status for $HEAD_SHA..."
664-
665- # Get the combined status for the commit
666- STATUS_DATA=$(gh api "repos/${GITHUB_REPOSITORY}/commits/${HEAD_SHA}/status" 2>/dev/null || echo "{}")
667-
668- # Find the pre-merge-tests status
669- PRIV_STATUS=$(echo "$STATUS_DATA" | jq -r '.statuses[] | select(.context == "pre-merge-tests") | .state' | head -1)
670-
671- echo " Commit: $HEAD_SHA"
672- echo " pre-merge-tests status: ${PRIV_STATUS:-not found}"
673-
674- if [ -z "$PRIV_STATUS" ]; then
675- echo "❌ No pre-merge-tests status found for PR #$PR. Please ensure the ci/pr-* run completed."
676- ALL_PASSED=false
677- elif [ "$PRIV_STATUS" = "pending" ]; then
678- echo "⏳ pre-merge-tests is still pending for PR #$PR. Please wait for completion."
679- ALL_PASSED=false
680- elif [ "$PRIV_STATUS" != "success" ]; then
681- echo "❌ pre-merge-tests status is '$PRIV_STATUS' for PR #$PR."
682- ALL_PASSED=false
683- else
684- echo "✅ pre-merge-tests passed for PR #$PR."
685- fi
686- done
687-
688- if [ "$ALL_PASSED" = "true" ]; then
689- echo ""
690- echo "All fork PR privileged tests have passed. Merge queue check succeeded."
691- exit 0
692- else
693- echo ""
694- echo "One or more fork PR privileged tests have not passed. Failing merge queue check."
695- exit 1
696- fi
697-
698- - name : Report pre-merge-tests status to merge group commit
699- if : always()
700- env :
701- GH_TOKEN : ${{ secrets.GITHUB_TOKEN }}
702- MERGE_GROUP_SHA : ${{ github.event.merge_group.head_sha }}
703- RUN_URL : ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
704- JOB_STATUS : ${{ job.status }}
705- run : |
706- if [ "$JOB_STATUS" = "success" ]; then
707- STATE="success"
708- DESCRIPTION="Fork PR privileged tests verified"
709- else
710- STATE="failure"
711- DESCRIPTION="Fork PR privileged tests failed"
712- fi
713-
714- echo "Reporting pre-merge-tests status ($STATE) to merge group commit ${MERGE_GROUP_SHA}..."
715- gh api "repos/${{ github.repository }}/statuses/${MERGE_GROUP_SHA}" \
716- -X POST \
717- -f state=$STATE \
718- -f context=pre-merge-tests \
719- -f description="$DESCRIPTION" \
720- -f target_url="${RUN_URL}"
721- echo "✅ Successfully reported pre-merge-tests status."
410+ set -euo pipefail
411+ echo "Checking if .github/workflows/premerge-ci.yml is modified in PR #$PR_NUMBER..."
412+ CHANGES=$(gh pr diff "$PR_NUMBER" --name-only)
413+
414+ if echo "$CHANGES" | grep -q "^.github/workflows/premerge-ci.yml$"; then
415+ echo "❌ Critical workflow modification detected!"
416+ echo "For security reasons, this workflow file cannot be modified via Pull Request."
417+ echo "Please revert changes to .github/workflows/premerge-ci.yml to pass this check."
418+ exit 1
419+ fi
420+
421+ echo "✅ Workflow integrity verified (file not modified)."
0 commit comments