Skip to content

[WIP] Ensure updates are pushing to other orgs and repos#5

Open
Copilot wants to merge 5 commits intomainfrom
copilot/test-update-push-to-orgs
Open

[WIP] Ensure updates are pushing to other orgs and repos#5
Copilot wants to merge 5 commits intomainfrom
copilot/test-update-push-to-orgs

Conversation

Copy link

Copilot AI commented Jan 27, 2026

Implementation Plan: Test & Ensure Updates Push to Orgs

Understanding

This repository (.github) is a central coordination hub for 15 BlackRoad organizations. The implementation adds:

  1. Mechanism to push updates TO other org repositories
  2. Tests to validate sync functionality
  3. Automated PR merge to main

Implementation Checklist

  • Create workflow to sync .github files to other orgs
    • Add sync-to-orgs.yml workflow that pushes workflow templates
    • Configure to run on push to main
    • Add manual dispatch for testing
    • Support dry-run mode for testing
    • Improve error handling and reporting
    • Support cross-org dispatches with DISPATCH_TOKEN
  • Add comprehensive tests for sync functionality
    • Create test script to verify sync workflow
    • Add tests for registry validation
    • Add tests for dispatch payload format
    • Add tests for workflow triggers
    • Add integration test for end-to-end flow
  • Add automated PR merge workflow
    • Create auto-merge.yml for approved PRs
    • Add status checks requirement
    • Configure to merge to main after CI passes
    • Add PR commenting on auto-merge
    • Remove overly broad triggers (check_suite, status)
    • Improve error handling when PR not found
  • Update CI workflow to test sync functionality
    • Add sync validation step
    • Integrate test_sync.py into CI pipeline
    • Update summary job to include sync results
  • Add documentation
    • Create comprehensive SYNC.md guide
    • Update README.md with sync information
    • Add workflow templates for target repos
    • Add security notes about DISPATCH_TOKEN
    • Add warnings about direct commits and permissions
  • Validate implementation
    • Run tests locally (all pass ✅)
    • Verify workflow YAML is valid (all valid ✅)
    • Check all files are committed (✅)
  • Request code review (✅)
  • Address review feedback (✅)
  • Run security scan
Original prompt

lets actually be testing and ensuring that updates here are actually pushing to the other orgs and repos and once you submit the pull request ensure it hits main


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

Co-authored-by: blackboxprogramming <118287761+blackboxprogramming@users.noreply.github.com>
PR_NUMBER="${{ github.event.pull_request.number }}"
elif [ "${{ github.event_name }}" == "workflow_run" ]; then
# Extract PR number from workflow run
PR_NUMBER=$(gh pr list --json number,headRefName --jq '.[] | select(.headRefName=="${{ github.event.workflow_run.head_branch }}") | .number' | head -1)

Check failure

Code scanning / CodeQL

Code injection Critical

Potential code injection in
${ github.event.workflow_run.head_branch }
, which may be controlled by an external user (
workflow_run
).

Copilot Autofix

AI 18 days ago

In general, to fix code injection issues in GitHub Actions, never interpolate untrusted ${{ ... }} expressions directly inside run: scripts. Instead, assign the value to an environment variable via env: (where the expression is safely resolved by the runner before the shell starts) and then reference it using the shell’s native syntax (e.g. $VAR or "${VAR}"). This prevents the untrusted data from being interpreted as shell syntax.

For this workflow, the only problematic usage is ${{ github.event.workflow_run.head_branch }} inside the PR_NUMBER=$(...) command. We should move github.event.workflow_run.head_branch into an env var (e.g. HEAD_BRANCH) on the step, and then use $HEAD_BRANCH solely via shell expansion. Additionally, any log messages that currently embed ${{ github.event.workflow_run.head_branch }} inside the script should be updated to use $HEAD_BRANCH as well, so the script doesn’t reference the expression syntax at all.

Concretely:

  • In the “Get PR info” step, add HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }} under env: (alongside GITHUB_TOKEN).
  • Change line 41 from using "${{ github.event.workflow_run.head_branch }}" inside the jq filter to using "${HEAD_BRANCH}".
  • Change the error message on line 48 from ... ${{ github.event.workflow_run.head_branch }} to $HEAD_BRANCH.

No new methods or external libraries are needed; we only adjust the YAML workflow and rely on normal Bash variable expansion.


Suggested changeset 1
.github/workflows/auto-merge.yml

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/.github/workflows/auto-merge.yml b/.github/workflows/auto-merge.yml
--- a/.github/workflows/auto-merge.yml
+++ b/.github/workflows/auto-merge.yml
@@ -32,20 +32,21 @@
         id: pr
         env:
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+          HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }}
         run: |
           # Get PR number from the event
           if [ "${{ github.event_name }}" == "pull_request_review" ]; then
             PR_NUMBER="${{ github.event.pull_request.number }}"
           elif [ "${{ github.event_name }}" == "workflow_run" ]; then
             # Extract PR number from workflow run
-            PR_NUMBER=$(gh pr list --json number,headRefName --jq '.[] | select(.headRefName=="${{ github.event.workflow_run.head_branch }}") | .number' | head -1)
+            PR_NUMBER=$(gh pr list --json number,headRefName --jq ".[] | select(.headRefName==\"${HEAD_BRANCH}\") | .number" | head -1)
           else
             echo "No PR found for event type: ${{ github.event_name }}"
             exit 1
           fi
           
           if [ -z "$PR_NUMBER" ]; then
-            echo "No PR number found for branch ${{ github.event.workflow_run.head_branch }}"
+            echo "No PR number found for branch $HEAD_BRANCH"
             exit 1
           fi
           
EOF
@@ -32,20 +32,21 @@
id: pr
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }}
run: |
# Get PR number from the event
if [ "${{ github.event_name }}" == "pull_request_review" ]; then
PR_NUMBER="${{ github.event.pull_request.number }}"
elif [ "${{ github.event_name }}" == "workflow_run" ]; then
# Extract PR number from workflow run
PR_NUMBER=$(gh pr list --json number,headRefName --jq '.[] | select(.headRefName=="${{ github.event.workflow_run.head_branch }}") | .number' | head -1)
PR_NUMBER=$(gh pr list --json number,headRefName --jq ".[] | select(.headRefName==\"${HEAD_BRANCH}\") | .number" | head -1)
else
echo "No PR found for event type: ${{ github.event_name }}"
exit 1
fi

if [ -z "$PR_NUMBER" ]; then
echo "No PR number found for branch ${{ github.event.workflow_run.head_branch }}"
echo "No PR number found for branch $HEAD_BRANCH"
exit 1
fi

Copilot is powered by AI and may make mistakes. Always verify output.
- name: Check merge conditions
id: check
run: |
STATE="${{ steps.pr.outputs.state }}"

Check failure

Code scanning / CodeQL

Code injection Critical

Potential code injection in
${ steps.pr.outputs.state }
, which may be controlled by an external user (
pull_request_review
).
Potential code injection in
${ steps.pr.outputs.state }
, which may be controlled by an external user (
workflow_run
).

Copilot Autofix

AI 18 days ago

General fix approach: avoid using ${{ ... }} expression interpolation directly inside shell run: blocks for data that might be tainted. Instead, assign those values to environment variables at the step level using ${{ ... }} once, then access them inside the script using the native shell syntax ($VAR). This prevents GitHub’s expression language from injecting into the shell parsing context.

Best concrete fix here: in the “Check merge conditions” step, move the three interpolations of steps.pr.outputs.state, mergeable, and review_decision out of the script body and into an env: section, then in the script simply reference $STATE, $MERGEABLE, and $REVIEW_DECISION. This preserves existing behavior (the same strings are passed, the same comparisons and outputs occur), but closes the code injection pattern flagged by CodeQL. Only that step needs modification; other uses like if: steps.check.outputs.can_merge == 'true' are in YAML expressions, not shell.

Required changes in .github/workflows/auto-merge.yml:

  • Add an env: block to the “Check merge conditions” step that maps:
    • STATE: ${{ steps.pr.outputs.state }}
    • MERGEABLE: ${{ steps.pr.outputs.mergeable }}
    • REVIEW_DECISION: ${{ steps.pr.outputs.review_decision }}
  • Remove the three initial assignment lines inside the run: block that currently assign those via ${{ ... }}.
  • Keep all subsequent usage of $STATE, $MERGEABLE, $REVIEW_DECISION unchanged, since they already use safe shell variable expansion.

No new methods or external libraries are needed; this is pure YAML and shell syntax.


Suggested changeset 1
.github/workflows/auto-merge.yml

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/.github/workflows/auto-merge.yml b/.github/workflows/auto-merge.yml
--- a/.github/workflows/auto-merge.yml
+++ b/.github/workflows/auto-merge.yml
@@ -66,11 +66,11 @@
 
       - name: Check merge conditions
         id: check
+        env:
+          STATE: ${{ steps.pr.outputs.state }}
+          MERGEABLE: ${{ steps.pr.outputs.mergeable }}
+          REVIEW_DECISION: ${{ steps.pr.outputs.review_decision }}
         run: |
-          STATE="${{ steps.pr.outputs.state }}"
-          MERGEABLE="${{ steps.pr.outputs.mergeable }}"
-          REVIEW_DECISION="${{ steps.pr.outputs.review_decision }}"
-          
           echo "PR State: $STATE"
           echo "Mergeable: $MERGEABLE"
           echo "Review Decision: $REVIEW_DECISION"
EOF
@@ -66,11 +66,11 @@

- name: Check merge conditions
id: check
env:
STATE: ${{ steps.pr.outputs.state }}
MERGEABLE: ${{ steps.pr.outputs.mergeable }}
REVIEW_DECISION: ${{ steps.pr.outputs.review_decision }}
run: |
STATE="${{ steps.pr.outputs.state }}"
MERGEABLE="${{ steps.pr.outputs.mergeable }}"
REVIEW_DECISION="${{ steps.pr.outputs.review_decision }}"

echo "PR State: $STATE"
echo "Mergeable: $MERGEABLE"
echo "Review Decision: $REVIEW_DECISION"
Copilot is powered by AI and may make mistakes. Always verify output.
id: check
run: |
STATE="${{ steps.pr.outputs.state }}"
MERGEABLE="${{ steps.pr.outputs.mergeable }}"

Check failure

Code scanning / CodeQL

Code injection Critical

Potential code injection in
${ steps.pr.outputs.mergeable }
, which may be controlled by an external user (
pull_request_review
).
Potential code injection in
${ steps.pr.outputs.mergeable }
, which may be controlled by an external user (
workflow_run
).

Copilot Autofix

AI 18 days ago

General approach: Avoid using ${{ steps.pr.outputs.* }} directly inside shell code. Instead, map those values into environment variables in the step definition (env:) and then read them using standard shell variable expansion ($VAR). This matches GitHub’s recommended mitigation and prevents CodeQL from flagging code injection, while preserving behavior.

Best concrete fix here:

  • In the “Check merge conditions” step, remove inline GitHub expression usage within the run: script:
    • Replace:
      STATE="${{ steps.pr.outputs.state }}"
      MERGEABLE="${{ steps.pr.outputs.mergeable }}"
      REVIEW_DECISION="${{ steps.pr.outputs.review_decision }}"
    • With references to environment variables (e.g., STATE="$STATE", etc.).
  • Configure those environment variables using the step’s env: block:
    env:
      STATE: ${{ steps.pr.outputs.state }}
      MERGEABLE: ${{ steps.pr.outputs.mergeable }}
      REVIEW_DECISION: ${{ steps.pr.outputs.review_decision }}
  • Optionally, for consistency and future-proofing, we could do the same style for other steps, but the reported taint path is specifically for mergeable at line 71 in this step, so we will minimally adjust this step only.
  • No additional imports, tools, or external dependencies are needed; we just restructure how data is passed into the shell.

Concrete changes (line-level):

  • In .github/workflows/auto-merge.yml, in the “Check merge conditions” step (around lines 67–76):
    • Add an env: section with STATE, MERGEABLE, and REVIEW_DECISION populated from ${{ steps.pr.outputs.* }}.
    • Simplify the run: script to rely on those shell environment variables rather than embedding expressions inside the script.

This preserves all existing logic and outputs, only changing how the values are passed to the shell.

Suggested changeset 1
.github/workflows/auto-merge.yml

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/.github/workflows/auto-merge.yml b/.github/workflows/auto-merge.yml
--- a/.github/workflows/auto-merge.yml
+++ b/.github/workflows/auto-merge.yml
@@ -66,11 +66,11 @@
 
       - name: Check merge conditions
         id: check
+        env:
+          STATE: ${{ steps.pr.outputs.state }}
+          MERGEABLE: ${{ steps.pr.outputs.mergeable }}
+          REVIEW_DECISION: ${{ steps.pr.outputs.review_decision }}
         run: |
-          STATE="${{ steps.pr.outputs.state }}"
-          MERGEABLE="${{ steps.pr.outputs.mergeable }}"
-          REVIEW_DECISION="${{ steps.pr.outputs.review_decision }}"
-          
           echo "PR State: $STATE"
           echo "Mergeable: $MERGEABLE"
           echo "Review Decision: $REVIEW_DECISION"
EOF
@@ -66,11 +66,11 @@

- name: Check merge conditions
id: check
env:
STATE: ${{ steps.pr.outputs.state }}
MERGEABLE: ${{ steps.pr.outputs.mergeable }}
REVIEW_DECISION: ${{ steps.pr.outputs.review_decision }}
run: |
STATE="${{ steps.pr.outputs.state }}"
MERGEABLE="${{ steps.pr.outputs.mergeable }}"
REVIEW_DECISION="${{ steps.pr.outputs.review_decision }}"

echo "PR State: $STATE"
echo "Mergeable: $MERGEABLE"
echo "Review Decision: $REVIEW_DECISION"
Copilot is powered by AI and may make mistakes. Always verify output.
run: |
STATE="${{ steps.pr.outputs.state }}"
MERGEABLE="${{ steps.pr.outputs.mergeable }}"
REVIEW_DECISION="${{ steps.pr.outputs.review_decision }}"

Check failure

Code scanning / CodeQL

Code injection Critical

Potential code injection in
${ steps.pr.outputs.review_decision }
, which may be controlled by an external user (
pull_request_review
).
Potential code injection in
${ steps.pr.outputs.review_decision }
, which may be controlled by an external user (
workflow_run
).

Copilot Autofix

AI 18 days ago

To fix the problem, we should stop interpolating ${{ steps.pr.outputs.review_decision }} directly into the shell script and instead pass it through an environment variable, then read it using native shell variable syntax ($REVIEW_DECISION) inside the run: block. This matches GitHub’s recommended pattern and prevents expression-based injection.

Concretely, in the Check merge conditions step (lines 68–87), we will:

  • Add an env: section that maps the step outputs (state, mergeable, review_decision) to environment variables (STATE, MERGEABLE, REVIEW_DECISION).
  • Change the first lines of the script so that STATE, MERGEABLE, and REVIEW_DECISION are either used directly from the environment or explicitly assigned from $STATE, $MERGEABLE, $REVIEW_DECISION using pure shell syntax, without any ${{ ... }} interpolation inside run:.

This keeps the workflow behavior identical: it still checks the same conditions and sets the same can_merge output, but the untrusted data path into the shell is now via a normal environment variable, which GitHub scopes safely at the expression level. No new imports or external dependencies are needed, and all changes are confined to the .github/workflows/auto-merge.yml file in the Check merge conditions step.

Suggested changeset 1
.github/workflows/auto-merge.yml

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/.github/workflows/auto-merge.yml b/.github/workflows/auto-merge.yml
--- a/.github/workflows/auto-merge.yml
+++ b/.github/workflows/auto-merge.yml
@@ -66,10 +66,14 @@
 
       - name: Check merge conditions
         id: check
+        env:
+          STATE: ${{ steps.pr.outputs.state }}
+          MERGEABLE: ${{ steps.pr.outputs.mergeable }}
+          REVIEW_DECISION: ${{ steps.pr.outputs.review_decision }}
         run: |
-          STATE="${{ steps.pr.outputs.state }}"
-          MERGEABLE="${{ steps.pr.outputs.mergeable }}"
-          REVIEW_DECISION="${{ steps.pr.outputs.review_decision }}"
+          STATE="$STATE"
+          MERGEABLE="$MERGEABLE"
+          REVIEW_DECISION="$REVIEW_DECISION"
           
           echo "PR State: $STATE"
           echo "Mergeable: $MERGEABLE"
EOF
@@ -66,10 +66,14 @@

- name: Check merge conditions
id: check
env:
STATE: ${{ steps.pr.outputs.state }}
MERGEABLE: ${{ steps.pr.outputs.mergeable }}
REVIEW_DECISION: ${{ steps.pr.outputs.review_decision }}
run: |
STATE="${{ steps.pr.outputs.state }}"
MERGEABLE="${{ steps.pr.outputs.mergeable }}"
REVIEW_DECISION="${{ steps.pr.outputs.review_decision }}"
STATE="$STATE"
MERGEABLE="$MERGEABLE"
REVIEW_DECISION="$REVIEW_DECISION"

echo "PR State: $STATE"
echo "Mergeable: $MERGEABLE"
Copilot is powered by AI and may make mistakes. Always verify output.
echo "🎯 Auto-merge Summary"
echo ""
echo "PR: #${{ steps.pr.outputs.pr_number }}"
echo "State: ${{ steps.pr.outputs.state }}"

Check failure

Code scanning / CodeQL

Code injection Critical

Potential code injection in
${ steps.pr.outputs.state }
, which may be controlled by an external user (
pull_request_review
).
Potential code injection in
${ steps.pr.outputs.state }
, which may be controlled by an external user (
workflow_run
).

Copilot Autofix

AI 18 days ago

In general, to fix this class of issues in GitHub Actions, avoid using ${{ ... }} expressions directly inside shell scripts (run: blocks) with values that might be influenced by untrusted input. Instead, map those values into environment variables with workflow expression syntax, and then read them within the script using the shell’s own variable syntax (e.g., $VAR), which is what GitHub recommends.

Concretely for this workflow, the problematic use is in the Summary step:

- name: Summary
  if: always()
  run: |
    echo "🎯 Auto-merge Summary"
    echo ""
    echo "PR: #${{ steps.pr.outputs.pr_number }}"
    echo "State: ${{ steps.pr.outputs.state }}"
    echo "Can merge: ${{ steps.check.outputs.can_merge }}"
    echo "Status: ${{ job.status }}"

We should (a) pass the needed values into the step via env: using ${{ ... }} only there, and (b) in the run: block, refer to them with shell syntax ($PR_NUMBER, $STATE, etc.). This removes direct interpolation of potentially tainted data into the script and satisfies CodeQL’s recommendation.

Implementation details, all in .github/workflows/auto-merge.yml:

  • Modify the Summary step to add an env: section defining:
    • PR_NUMBER: ${{ steps.pr.outputs.pr_number }}
    • STATE: ${{ steps.pr.outputs.state }}
    • CAN_MERGE: ${{ steps.check.outputs.can_merge }}
    • JOB_STATUS: ${{ job.status }}
  • Update the run: script in that step to use those environment variables:
    • echo "PR: #$PR_NUMBER"
    • echo "State: $STATE"
    • echo "Can merge: $CAN_MERGE"
    • echo "Status: $JOB_STATUS"
  • No new methods or external dependencies are needed; we only adjust YAML structure and shell variable usage.

This single change addresses all alert variants related to ${{ steps.pr.outputs.state }} in this step.


Suggested changeset 1
.github/workflows/auto-merge.yml

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/.github/workflows/auto-merge.yml b/.github/workflows/auto-merge.yml
--- a/.github/workflows/auto-merge.yml
+++ b/.github/workflows/auto-merge.yml
@@ -120,10 +120,15 @@
 
       - name: Summary
         if: always()
+        env:
+          PR_NUMBER: ${{ steps.pr.outputs.pr_number }}
+          STATE: ${{ steps.pr.outputs.state }}
+          CAN_MERGE: ${{ steps.check.outputs.can_merge }}
+          JOB_STATUS: ${{ job.status }}
         run: |
           echo "🎯 Auto-merge Summary"
           echo ""
-          echo "PR: #${{ steps.pr.outputs.pr_number }}"
-          echo "State: ${{ steps.pr.outputs.state }}"
-          echo "Can merge: ${{ steps.check.outputs.can_merge }}"
-          echo "Status: ${{ job.status }}"
+          echo "PR: #$PR_NUMBER"
+          echo "State: $STATE"
+          echo "Can merge: $CAN_MERGE"
+          echo "Status: $JOB_STATUS"
EOF
@@ -120,10 +120,15 @@

- name: Summary
if: always()
env:
PR_NUMBER: ${{ steps.pr.outputs.pr_number }}
STATE: ${{ steps.pr.outputs.state }}
CAN_MERGE: ${{ steps.check.outputs.can_merge }}
JOB_STATUS: ${{ job.status }}
run: |
echo "🎯 Auto-merge Summary"
echo ""
echo "PR: #${{ steps.pr.outputs.pr_number }}"
echo "State: ${{ steps.pr.outputs.state }}"
echo "Can merge: ${{ steps.check.outputs.can_merge }}"
echo "Status: ${{ job.status }}"
echo "PR: #$PR_NUMBER"
echo "State: $STATE"
echo "Can merge: $CAN_MERGE"
echo "Status: $JOB_STATUS"
Copilot is powered by AI and may make mistakes. Always verify output.
Copilot AI and others added 2 commits January 27, 2026 21:06
Co-authored-by: blackboxprogramming <118287761+blackboxprogramming@users.noreply.github.com>
…ocumentation

Co-authored-by: blackboxprogramming <118287761+blackboxprogramming@users.noreply.github.com>
fi

if [ -z "$PR_NUMBER" ]; then
echo "No PR number found for branch ${{ github.event.workflow_run.head_branch }}"

Check failure

Code scanning / CodeQL

Code injection Critical

Potential code injection in
${ github.event.workflow_run.head_branch }
, which may be controlled by an external user (
workflow_run
).

Copilot Autofix

AI 18 days ago

In general, the fix is to avoid using ${{ github.* }} (or any untrusted expression) directly inside the shell script body. Instead, pass the potentially untrusted value into the step via env: and reference it inside the script using native shell variable expansion ($VAR). This way, the expression engine only assigns to an environment variable, and the shell never sees ${{ ... }} syntax and cannot misinterpret it as part of a command.

For this workflow, the best minimal fix without changing functionality is:

  1. Add an environment variable (e.g., HEAD_BRANCH) in the Get PR info step, assigning it from ${{ github.event.workflow_run.head_branch }}.
  2. Replace the inline uses of ${{ github.event.workflow_run.head_branch }} inside the run: script with $HEAD_BRANCH.

This preserves the behavior (same branch name value) but follows GitHub’s recommended pattern and eliminates the code-injection warning. Concretely, edit .github/workflows/auto-merge.yml:

  • In the Get PR info step’s env: block, add HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }}.
  • In the PR_NUMBER=$(...) line, replace the expression inside the jq filter from "${{ github.event.workflow_run.head_branch }}" to "$HEAD_BRANCH".
  • In the error echo line, replace ${{ github.event.workflow_run.head_branch }} with $HEAD_BRANCH.

No new methods or external tools are required; this is purely a YAML/inline shell change within the shown step.

Suggested changeset 1
.github/workflows/auto-merge.yml

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/.github/workflows/auto-merge.yml b/.github/workflows/auto-merge.yml
--- a/.github/workflows/auto-merge.yml
+++ b/.github/workflows/auto-merge.yml
@@ -32,20 +32,21 @@
         id: pr
         env:
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+          HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }}
         run: |
           # Get PR number from the event
           if [ "${{ github.event_name }}" == "pull_request_review" ]; then
             PR_NUMBER="${{ github.event.pull_request.number }}"
           elif [ "${{ github.event_name }}" == "workflow_run" ]; then
             # Extract PR number from workflow run
-            PR_NUMBER=$(gh pr list --json number,headRefName --jq '.[] | select(.headRefName=="${{ github.event.workflow_run.head_branch }}") | .number' | head -1)
+            PR_NUMBER=$(gh pr list --json number,headRefName --jq ".[] | select(.headRefName==\"$HEAD_BRANCH\") | .number" | head -1)
           else
             echo "No PR found for event type: ${{ github.event_name }}"
             exit 1
           fi
           
           if [ -z "$PR_NUMBER" ]; then
-            echo "No PR number found for branch ${{ github.event.workflow_run.head_branch }}"
+            echo "No PR number found for branch $HEAD_BRANCH"
             exit 1
           fi
           
EOF
@@ -32,20 +32,21 @@
id: pr
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }}
run: |
# Get PR number from the event
if [ "${{ github.event_name }}" == "pull_request_review" ]; then
PR_NUMBER="${{ github.event.pull_request.number }}"
elif [ "${{ github.event_name }}" == "workflow_run" ]; then
# Extract PR number from workflow run
PR_NUMBER=$(gh pr list --json number,headRefName --jq '.[] | select(.headRefName=="${{ github.event.workflow_run.head_branch }}") | .number' | head -1)
PR_NUMBER=$(gh pr list --json number,headRefName --jq ".[] | select(.headRefName==\"$HEAD_BRANCH\") | .number" | head -1)
else
echo "No PR found for event type: ${{ github.event_name }}"
exit 1
fi

if [ -z "$PR_NUMBER" ]; then
echo "No PR number found for branch ${{ github.event.workflow_run.head_branch }}"
echo "No PR number found for branch $HEAD_BRANCH"
exit 1
fi

Copilot is powered by AI and may make mistakes. Always verify output.
Co-authored-by: blackboxprogramming <118287761+blackboxprogramming@users.noreply.github.com>
@blackboxprogramming blackboxprogramming marked this pull request as ready for review January 31, 2026 12:39
Copilot AI review requested due to automatic review settings January 31, 2026 12:39
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 46f5a4b8ef

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +47 to +49
if [ -z "$PR_NUMBER" ]; then
echo "No PR number found for branch ${{ github.event.workflow_run.head_branch }}"
exit 1

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Guard workflow_run when no PR exists

On workflow_run events, CI also runs for direct pushes to main/develop (see .github/workflows/ci.yml on.push.branches), so there is often no associated PR. In that case PR_NUMBER will be empty and this step exits 1, causing the auto-merge workflow to fail on every push/merge to those branches. Consider skipping the job when github.event.workflow_run.pull_requests is empty or explicitly gating workflow_run to PR-triggered runs to avoid persistent failures.

Useful? React with 👍 / 👎.

Comment on lines +81 to +83
if [ "$STATE" == "OPEN" ] && \
[ "$MERGEABLE" == "MERGEABLE" ] && \
[ "$REVIEW_DECISION" == "APPROVED" ]; then

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Enforce base branch before auto-merge

The merge gate only checks state, mergeable, and reviewDecision and never verifies the PR’s base branch. Because CI also runs on develop, an approved PR targeting develop will satisfy these checks and be auto-merged, despite the workflow’s stated intent to merge only to main. Add a base-branch condition (e.g., github.event.pull_request.base.ref == 'main' or equivalent for workflow_run) to prevent unintended merges to non-main branches.

Useful? React with 👍 / 👎.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements a comprehensive sync system to push updates from the central .github repository (The Bridge) to other BlackRoad organization repositories. The implementation adds automated sync workflows, comprehensive testing, auto-merge functionality, and documentation.

Changes:

  • Adds sync-to-orgs workflow that dispatches repository events to active organization repositories
  • Implements auto-merge workflow to automatically merge approved PRs after CI passes
  • Integrates sync testing into the CI pipeline
  • Provides comprehensive documentation and receiver workflow templates

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
tests/test_sync.py Test suite validating sync workflow configuration and registry structure
tests/test_integration.py End-to-end integration test simulating the complete sync flow
.github/workflows/sync-to-orgs.yml Main workflow dispatching sync events to target organization repositories
.github/workflows/auto-merge.yml Workflow automating PR merges after approval and successful CI
.github/workflows/ci.yml Updated CI pipeline including sync functionality tests
templates/workflows/sync-receiver.yml Template workflow for target repositories to receive and process sync events
docs/SYNC.md Comprehensive documentation covering sync architecture, usage, and troubleshooting
README.md Updated overview with sync features and quick start instructions

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

branches: [main]
paths:
- 'templates/**'
- '.github/workflows/**'
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The workflow triggers on changes to .github/workflows/** which includes this workflow file itself. This could potentially cause an infinite loop if the sync process modifies workflow files and commits them back. While this PR shows the workflow dispatching to other repos (not modifying this repo), this path pattern should be more specific to avoid triggering on unrelated workflow changes. Consider being more specific about which workflows should trigger sync, or exclude this specific workflow file from the trigger path.

Suggested change
- '.github/workflows/**'
- '.github/workflows/**'
- '!.github/workflows/sync-to-orgs.yml'

Copilot uses AI. Check for mistakes.
Comment on lines +142 to +147
payload = {
'event_type': 'sync_from_bridge',
'client_payload': {
'source': 'BlackRoad-OS/.github',
'ref': os.environ.get('GITHUB_SHA', 'main'),
'timestamp': '${{ github.event.head_commit.timestamp }}'
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The timestamp field uses GitHub Actions syntax '${{ github.event.head_commit.timestamp }}' inside a Python string literal, which won't be interpolated. This will result in the literal string being sent rather than the actual timestamp value. To fix this, the timestamp should be passed as an environment variable and accessed via os.environ.get(), similar to how GITHUB_SHA is handled on line 146.

Suggested change
payload = {
'event_type': 'sync_from_bridge',
'client_payload': {
'source': 'BlackRoad-OS/.github',
'ref': os.environ.get('GITHUB_SHA', 'main'),
'timestamp': '${{ github.event.head_commit.timestamp }}'
# Derive head commit timestamp from the GitHub event payload
import json
head_commit_timestamp = None
event_path = os.environ.get('GITHUB_EVENT_PATH')
if event_path:
try:
with open(event_path, 'r', encoding='utf-8') as f:
event = json.load(f)
head_commit = event.get('head_commit') or {}
head_commit_timestamp = head_commit.get('timestamp')
except Exception:
head_commit_timestamp = None
payload = {
'event_type': 'sync_from_bridge',
'client_payload': {
'source': 'BlackRoad-OS/.github',
'ref': os.environ.get('GITHUB_SHA', 'main'),
'timestamp': head_commit_timestamp

Copilot uses AI. Check for mistakes.
fi

if [ -z "$PR_NUMBER" ]; then
echo "No PR number found for branch ${{ github.event.workflow_run.head_branch }}"
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error message on line 48 references github.event.workflow_run.head_branch even when the event type is pull_request_review. This will cause confusing error messages when a pull_request_review event doesn't have a PR number. Consider making this error message conditional on the event type or using a generic message that doesn't reference event-specific fields.

Suggested change
echo "No PR number found for branch ${{ github.event.workflow_run.head_branch }}"
echo "No PR number found for event ${{ github.event_name }}"

Copilot uses AI. Check for mistakes.
Comment on lines +48 to +49
echo "No PR number found for branch ${{ github.event.workflow_run.head_branch }}"
exit 1
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The workflow will fail with "exit 1" when no PR number is found for a branch in workflow_run events. However, this is normal behavior when CI runs on direct commits to main (not from a PR). The workflow should handle this case gracefully by exiting early without error, rather than failing the entire workflow. Consider checking if this is a PR-related run before attempting to find the PR number, or exit with success (exit 0) when no PR is found.

Suggested change
echo "No PR number found for branch ${{ github.event.workflow_run.head_branch }}"
exit 1
if [ "${{ github.event_name }}" == "workflow_run" ]; then
echo "No PR number found for branch ${{ github.event.workflow_run.head_branch }}; this workflow_run is not associated with a PR. Exiting successfully."
exit 0
else
echo "No PR number found for event type: ${{ github.event_name }}"
exit 1
fi

Copilot uses AI. Check for mistakes.
Comment on lines +7 to +8
pull_request_review:
types: [submitted]
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The workflow triggers on all pull_request_review submissions (line 7-8), not just approvals. This means it will run for comments, changes requested, and dismissals as well. While the workflow does check for approval status later (line 95), it's more efficient to filter at the trigger level. Consider adding a filter: types: [submitted] with if: github.event.review.state == 'approved' at the job level, or change the trigger to only fire on approvals.

Copilot uses AI. Check for mistakes.
Comment on lines +86 to +87
git add -A

Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using git add -A adds all files in the repository to the commit, including potentially unintended files (e.g., temporary files, local configurations, or sensitive data). This is risky in an automated workflow. Consider using more specific git add commands that target only the files that should be synced (e.g., git add .github/workflows/ or specific file patterns), or add a check to only commit files that were explicitly modified by the sync process.

Suggested change
git add -A
# Only stage files that are expected to be modified by this sync process
paths_to_add=()
# Shared workflows
if [ -d ".github/workflows" ]; then
paths_to_add+=(".github/workflows")
fi
# Example shared config files (uncomment or extend as needed)
if [ -f ".editorconfig" ]; then
paths_to_add+=(".editorconfig")
fi
if [ ${#paths_to_add[@]} -eq 0 ]; then
echo "No known sync paths to add to commit"
else
git add "${paths_to_add[@]}"
fi

Copilot uses AI. Check for mistakes.
Tests that updates are properly dispatched to target orgs
"""

import json
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Import of 'json' is not used.

Suggested change
import json

Copilot uses AI. Check for mistakes.
"""

import json
import os
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Import of 'os' is not used.

Suggested change
import os

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants