From 4a6ba4a2b4fb8f6073ce41fc7589dc1f3c123c65 Mon Sep 17 00:00:00 2001 From: Chris Arderne Date: Tue, 1 Sep 2026 11:37:41 +0100 Subject: [PATCH 1/3] chore: add repository synchronization gates --- .github/workflows/dispatch-repo-ops-sync.yml | 41 ++++++++++ .github/workflows/repo-ops-sync-gate.yml | 85 ++++++++++++++++++++ 2 files changed, 126 insertions(+) create mode 100644 .github/workflows/dispatch-repo-ops-sync.yml create mode 100644 .github/workflows/repo-ops-sync-gate.yml diff --git a/.github/workflows/dispatch-repo-ops-sync.yml b/.github/workflows/dispatch-repo-ops-sync.yml new file mode 100644 index 00000000000..0d64f7db251 --- /dev/null +++ b/.github/workflows/dispatch-repo-ops-sync.yml @@ -0,0 +1,41 @@ +name: Dispatch RepoOps sync + +on: + push: + branches: [main] + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: dispatch-repo-ops-sync + cancel-in-progress: false + +jobs: + dispatch: + if: vars.REPO_OPS_SYNC_ENABLED == 'true' + runs-on: ubuntu-latest + steps: + - name: Create Dispatcher App token + id: app-token + uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 + with: + app-id: ${{ vars.REPO_OPS_DISPATCHER_APP_ID }} + private-key: ${{ secrets.REPO_OPS_DISPATCHER_APP_PRIVATE_KEY }} + owner: triggerdotdev + permission-contents: write + + - name: Dispatch the private sync worker + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + PUBLIC_SHA: ${{ github.sha }} + MONO_REPOSITORY: ${{ secrets.REPO_OPS_MONO_REPOSITORY }} + run: | + set -euo pipefail + [[ "$MONO_REPOSITORY" =~ ^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$ ]] + [[ "$PUBLIC_SHA" =~ ^[0-9a-f]{40}$ ]] + gh api "repos/${MONO_REPOSITORY}/dispatches" \ + --method POST \ + --field event_type=repo-ops-public-push \ + --field "client_payload[public_sha]=$PUBLIC_SHA" diff --git a/.github/workflows/repo-ops-sync-gate.yml b/.github/workflows/repo-ops-sync-gate.yml new file mode 100644 index 00000000000..392d96a0b31 --- /dev/null +++ b/.github/workflows/repo-ops-sync-gate.yml @@ -0,0 +1,85 @@ +name: repo-ops-sync-gate + +on: + pull_request: + merge_group: + +permissions: + contents: read + +jobs: + gate: + runs-on: ubuntu-latest + steps: + - name: Reject reserved RepoOps trailers + if: github.event_name == 'pull_request' + env: + PR_TITLE: ${{ github.event.pull_request.title }} + PR_BODY: ${{ github.event.pull_request.body }} + run: | + python3 - <<'PY' + import os + import re + import sys + + text = f"{os.environ.get('PR_TITLE', '')}\n{os.environ.get('PR_BODY', '')}" + match = re.search(r"(?m)^(?:OSS-RevId|Mono-RevId):", text) + if match: + print(f"BLOCKED: PR title/body contains reserved RepoOps trailer {match.group(0)!r}", file=sys.stderr) + raise SystemExit(1) + print("ok: no reserved RepoOps trailers") + PY + + - name: Pull request check context + if: github.event_name == 'pull_request' + run: echo 'State is checked again against the live tips by merge queue.' + + - name: Create read-only Dispatcher App token + if: github.event_name == 'merge_group' + id: app-token + uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 + with: + app-id: ${{ vars.REPO_OPS_DISPATCHER_APP_ID }} + private-key: ${{ secrets.REPO_OPS_DISPATCHER_APP_PRIVATE_KEY }} + owner: triggerdotdev + permission-contents: read + + - name: Wait for pending mono changes + if: github.event_name == 'merge_group' + env: + APP_TOKEN: ${{ steps.app-token.outputs.token }} + PUBLIC_TOKEN: ${{ github.token }} + MONO_BASELINE: ${{ vars.REPO_OPS_MONO_BASELINE }} + PUBLIC_BASELINE: ${{ vars.REPO_OPS_PUBLIC_BASELINE }} + MONO_REPOSITORY: ${{ secrets.REPO_OPS_MONO_REPOSITORY }} + PUBLIC_REPOSITORY: ${{ github.repository }} + run: | + set -euo pipefail + [[ "$MONO_REPOSITORY" =~ ^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$ ]] + [[ "$PUBLIC_REPOSITORY" =~ ^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$ ]] + git clone --filter=blob:none --no-tags \ + "https://x-access-token:${PUBLIC_TOKEN}@github.com/${PUBLIC_REPOSITORY}.git" public + git clone --filter=blob:none --no-tags \ + "https://x-access-token:${APP_TOKEN}@github.com/${MONO_REPOSITORY}.git" mono + + for _ in $(seq 1 60); do + git -C public fetch --no-tags origin \ + +refs/heads/main:refs/remotes/origin/main + git -C mono fetch --no-tags origin \ + +refs/heads/main:refs/remotes/origin/main + output="$(mktemp)" + mono/tooling/plan-repo-ops-outbound.sh \ + mono public "$(git -C mono rev-parse origin/main)" \ + "$MONO_BASELINE" "$PUBLIC_BASELINE" "$output" + native_count="$(grep -E '^native_count=' "$output" | cut -d= -f2)" + rm -f "$output" + + if (( native_count == 0 )); then + echo 'No unsynced native mono oss/ commits.' + exit 0 + fi + echo "Waiting for $native_count native mono oss/ commit(s)." + sleep 10 + done + echo 'Timed out waiting for mono-to-public sync.' >&2 + exit 1 From 12cfdc65d09a8573619fbfd6d04e83d2f803b435 Mon Sep 17 00:00:00 2001 From: Chris Arderne Date: Tue, 1 Sep 2026 12:20:09 +0100 Subject: [PATCH 2/3] fix: scope repository synchronization tokens --- .github/workflows/dispatch-repo-ops-sync.yml | 1 + .github/workflows/repo-ops-sync-gate.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/.github/workflows/dispatch-repo-ops-sync.yml b/.github/workflows/dispatch-repo-ops-sync.yml index 0d64f7db251..ce4f4fbb9a1 100644 --- a/.github/workflows/dispatch-repo-ops-sync.yml +++ b/.github/workflows/dispatch-repo-ops-sync.yml @@ -24,6 +24,7 @@ jobs: app-id: ${{ vars.REPO_OPS_DISPATCHER_APP_ID }} private-key: ${{ secrets.REPO_OPS_DISPATCHER_APP_PRIVATE_KEY }} owner: triggerdotdev + repositories: ${{ secrets.REPO_OPS_MONO_REPOSITORY }} permission-contents: write - name: Dispatch the private sync worker diff --git a/.github/workflows/repo-ops-sync-gate.yml b/.github/workflows/repo-ops-sync-gate.yml index 392d96a0b31..d02058951d1 100644 --- a/.github/workflows/repo-ops-sync-gate.yml +++ b/.github/workflows/repo-ops-sync-gate.yml @@ -42,6 +42,7 @@ jobs: app-id: ${{ vars.REPO_OPS_DISPATCHER_APP_ID }} private-key: ${{ secrets.REPO_OPS_DISPATCHER_APP_PRIVATE_KEY }} owner: triggerdotdev + repositories: ${{ secrets.REPO_OPS_MONO_REPOSITORY }} permission-contents: read - name: Wait for pending mono changes From 892e95c80b12bd51c44171f3fcaa2b729cdcc48e Mon Sep 17 00:00:00 2001 From: Chris Arderne Date: Tue, 1 Sep 2026 16:32:58 +0100 Subject: [PATCH 3/3] fix: harden repository synchronization workflows --- .github/workflows/dispatch-repo-ops-sync.yml | 1 - .github/workflows/repo-ops-sync-gate.yml | 4 +++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/dispatch-repo-ops-sync.yml b/.github/workflows/dispatch-repo-ops-sync.yml index ce4f4fbb9a1..50cde0f2f07 100644 --- a/.github/workflows/dispatch-repo-ops-sync.yml +++ b/.github/workflows/dispatch-repo-ops-sync.yml @@ -23,7 +23,6 @@ jobs: with: app-id: ${{ vars.REPO_OPS_DISPATCHER_APP_ID }} private-key: ${{ secrets.REPO_OPS_DISPATCHER_APP_PRIVATE_KEY }} - owner: triggerdotdev repositories: ${{ secrets.REPO_OPS_MONO_REPOSITORY }} permission-contents: write diff --git a/.github/workflows/repo-ops-sync-gate.yml b/.github/workflows/repo-ops-sync-gate.yml index d02058951d1..47461239be1 100644 --- a/.github/workflows/repo-ops-sync-gate.yml +++ b/.github/workflows/repo-ops-sync-gate.yml @@ -2,6 +2,7 @@ name: repo-ops-sync-gate on: pull_request: + types: [opened, edited, reopened, synchronize] merge_group: permissions: @@ -9,6 +10,8 @@ permissions: jobs: gate: + if: github.event_name == 'pull_request' || vars.REPO_OPS_SYNC_ENABLED == 'true' + timeout-minutes: 15 runs-on: ubuntu-latest steps: - name: Reject reserved RepoOps trailers @@ -41,7 +44,6 @@ jobs: with: app-id: ${{ vars.REPO_OPS_DISPATCHER_APP_ID }} private-key: ${{ secrets.REPO_OPS_DISPATCHER_APP_PRIVATE_KEY }} - owner: triggerdotdev repositories: ${{ secrets.REPO_OPS_MONO_REPOSITORY }} permission-contents: read