Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .github/protection/main.required-checks.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@
"branch": "main",
"required_status_checks": [
"meta-gate",
"CI Core Gate ",
"CI Core Gate \u2705",
"Unit Tests",
"gate",
"Release Readiness Gate",
"SOC Controls",
"test (20.x)",
"Workflow Validity Check"
"Workflow Validity Check",
"merge-queue / merge-queue-critical"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

critical

Retaining existing required checks (e.g., Unit Tests, gate, CI Core Gate) alongside the new merge-queue / merge-queue-critical check is likely to cause a deadlock in the merge queue.

According to the PR description, the automation workflows providing these checks have been converted to manual workflow_dispatch. If these checks are not configured to trigger on the merge_group event, they will never report a status for merge candidates, causing the queue to wait indefinitely.

Furthermore, if merge-queue-critical already performs install, lint, typecheck, and test, these existing checks are redundant. You should remove the redundant or disabled checks from this list to ensure the merge queue can progress.

Additionally, please ensure the check name merge-queue / merge-queue-critical exactly matches the status reported by the new workflow (this requires the workflow in .github/workflows/merge-queue.yml to have name: merge-queue).

],
"strict": true,
"require_pull_request": true,
Expand Down
3 changes: 1 addition & 2 deletions .github/workflows/merge-group-heavy.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
name: merge-group-heavy

on:
merge_group:
workflow_dispatch:

jobs:
heavy:
if: github.event_name == 'merge_group'
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
Expand Down
46 changes: 4 additions & 42 deletions .github/workflows/merge-queue-feeder.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
name: Merge Queue Feeder

on:
schedule:
- cron: "*/2 * * * *"
workflow_dispatch:

permissions:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
contents: write
contents: read
pull-requests: write
Comment on lines 6 to 8
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Drop unnecessary pull-requests: write permission for a no-op workflow.

This workflow no longer performs PR mutations, so retaining write scope is excess privilege.

🔐 Proposed least-privilege fix
 permissions:
   contents: read
-  pull-requests: write
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
permissions:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
contents: write
contents: read
pull-requests: write
permissions:
contents: read
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/merge-queue-feeder.yml around lines 6 - 8, The workflow
grants unnecessary write scope via the permissions key "pull-requests: write";
remove the "pull-requests: write" entry under permissions so the permissions
block only includes "contents: read" (or explicitly set pull-requests: none) to
follow least-privilege; check that no steps in the workflow use PR mutation APIs
(references to pull-requests) before committing the change, and update any code
that required write access if found.


env:
Expand All @@ -16,43 +13,8 @@ env:
jobs:
feed-queue:
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Install GitHub CLI
uses: cli/cli-action@v2

- name: Fetch eligible PRs
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Intentional no-op
run: |
gh pr list \
--label "queue:merge-now" \
--state open \
--json number \
> mergeable.json

- name: Determine queue depth
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh pr list \
--search "is:queued" \
--json number \
> queue.json

- name: Feed merge queue
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
TARGET=20
CURRENT=$(jq length queue.json)

if [ "$CURRENT" -lt "$TARGET" ]; then
NEEDED=$((TARGET-CURRENT))
jq -r '.[].number' mergeable.json | head -n $NEEDED | while read pr; do
gh pr merge $pr --auto --squash
done
fi
echo "Native GitHub merge queue is authoritative."
echo "Manual feeder is retained for emergency one-off operation only."
155 changes: 117 additions & 38 deletions .github/workflows/merge-queue.yml
Original file line number Diff line number Diff line change
@@ -1,58 +1,137 @@
name: Merge Queue CI
name: merge-queue

on:
merge_group:
types: [checks_requested]
pull_request:
types: [enqueued, dequeued, synchronize, reopened, ready_for_review]
branches: [main]

permissions:
contents: read
pull-requests: write

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
group: merge-queue-main
cancel-in-progress: false
Comment on lines 14 to +16
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Isolate merge-group runs from PR-event concurrency

merge-queue.yml now triggers on high-frequency pull_request actions (synchronize, reopened, etc.) while using a single workflow-level concurrency lock (merge-queue-main) with cancel-in-progress: false. Since workflow concurrency is shared across all runs of this workflow, comment-only queue-visibility runs can backlog ahead of merge-queue-critical, delaying the required merge-queue validation and stalling merges during routine PR activity. Scope concurrency to the merge_group path (or split groups by event) so required queue checks are not blocked by visibility updates.

Useful? React with 👍 / 👎.

Comment on lines 14 to +16
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

In GitHub Actions, does workflow-level concurrency apply to all runs regardless of which job executes, and can it serialize runs across different event types in the same workflow?

💡 Result:

Yes, workflow-level concurrency in GitHub Actions applies to all runs of that workflow regardless of which job executes, and it can serialize runs across different event types in the same workflow.

Citations:


🏁 Script executed:

cat -n .github/workflows/merge-queue.yml

Repository: BrianCLong/summit

Length of output: 5369


Move concurrency constraint to merge-queue-critical job only.

Workflow-level concurrency serializes both pull_request runs (queue-visibility) and merge_group runs (merge-queue-critical). This queues informational PR visibility updates ahead of required merge gate validations, reducing merge throughput.

Fix: Apply concurrency to the critical validation job only
-concurrency:
-  group: merge-queue-main
-  cancel-in-progress: false
-
 jobs:
   queue-visibility:
     if: github.event_name == 'pull_request'
     runs-on: ubuntu-latest
   merge-queue-critical:
     if: github.event_name == 'merge_group'
+    concurrency:
+      group: merge-queue-main
+      cancel-in-progress: false
     runs-on: ubuntu-latest
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/merge-queue.yml around lines 14 - 16, The workflow-level
concurrency block should be removed and instead added to the
merge-queue-critical job only: delete the top-level concurrency stanza and add a
concurrency: group: merge-queue-main cancel-in-progress: false block inside the
job named merge-queue-critical so only that job is serialized (leaving
pull_request/queue-visibility runs unconstrained); update the workflow YAML
accordingly to move the concurrency constraint from the workflow root to the
merge-queue-critical job definition.


jobs:
merge-heavy:
name: Heavy Checks
queue-visibility:
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
steps:
- name: Publish queue state comment
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const pr = context.payload.pull_request;
if (!pr) {
core.info('No pull_request payload, skipping.');
return;
}

const marker = '<!-- merge-queue-status -->';
const state = context.payload.action;
const branch = 'main';

let queueSize = 0;
let positionText = 'Not currently in queue';
let reason = 'No dequeue reason reported.';

try {
const queue = await github.request('GET /repos/{owner}/{repo}/merge-queue', {
owner: context.repo.owner,
repo: context.repo.repo,
branch,
});

const entries = queue.data?.entries ?? [];
queueSize = entries.length;
const index = entries.findIndex((entry) => entry.number === pr.number);
if (index >= 0) {
positionText = `${index + 1} of ${queueSize}`;
}
} catch (error) {
core.warning(`Unable to read merge queue: ${error.message}`);
}

if (state === 'dequeued') {
reason = context.payload.reason || 'Validation failed or PR no longer mergeable.';
}

const body = [
marker,
`### Merge Queue Status`,
`- **PR:** #${pr.number}`,
`- **Event:** ${state}`,
`- **Queue position:** ${positionText}`,
`- **Queue depth:** ${queueSize}`,
`- **Removal reason:** ${reason}`,
'',
'_Queue is FIFO and each candidate is validated on latest `main` through `merge_group` before merge._',
].join('\n');

const comments = await github.paginate(github.rest.issues.listComments, {
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pr.number,
per_page: 100,
});

const existing = comments.find((comment) => comment.body?.includes(marker));

if (existing) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: existing.id,
body,
});
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pr.number,
body,
});
}
Comment on lines +75 to +98
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

For GitHub Actions pull_requestevents from forks, can workflow-levelpull-requests: writestill be downgraded soissues.createComment/issues.updateComment fails with permission errors?

💡 Result:

Yes, for GitHub Actions workflows triggered by pull_request events from forks (excluding pull_request_target), the GITHUB_TOKEN permissions are automatically downgraded to read-only if the repository setting "Send write tokens to workflows from pull requests" is not enabled. This downgrade occurs even if the workflow explicitly requests pull-requests: write permissions. As a result, API calls like issues.createComment or issues.updateComment (which require issues: write or pull-requests: write) will fail with permission errors such as "Resource not accessible by integration" (HTTP 403). This security measure prevents untrusted fork workflows from performing write operations on the base repository. The official documentation confirms: "if the workflow was triggered by a pull request event other than pull_request_target from a forked repository, and the Send write tokens to workflows from pull requests setting is not selected, the permissions are adjusted to change any write permissions to read only." To allow write permissions: - Enable the "Send write tokens to workflows from pull requests" setting in repository Settings > Actions > General (available for private repositories; public repos have additional restrictions). - Or use pull_request_target trigger (runs workflow from base branch with full permissions, but requires caution against malicious PR code). Note: issues.createComment maps to issues: write permission, and PR comments also work with pull-requests: write. Both are downgraded in this scenario.

Citations:


🏁 Script executed:

# Check if the file exists and read the relevant section
fd -t f 'merge-queue.yml' --exec cat -n {} \;

Repository: BrianCLong/summit

Length of output: 43


🏁 Script executed:

# List files in .github/workflows directory
ls -la .github/workflows/ 2>/dev/null || echo "Directory not found"

# Search for any files with 'merge' in name
fd -t f 'merge' 

# Search for the specific code pattern to find where it lives
rg "listComments" -t yaml -A 5

Repository: BrianCLong/summit

Length of output: 50373


🏁 Script executed:

# Read the merge-queue.yml file with line numbers
cat -n .github/workflows/merge-queue.yml | head -120

Repository: BrianCLong/summit

Length of output: 4571


Wrap comment operations in try-catch to handle fork PR permission restrictions.

Lines 75-98 lack error handling for listComments, createComment, and updateComment. On pull_request events from forks, the GITHUB_TOKEN is automatically downgraded to read-only (even with explicit pull-requests: write permission), causing these operations to fail with 403 errors. Since this is a visibility-only job, permission failures should be logged as warnings, not fail the workflow.

🛡️ Proposed fail-soft handling
+            try {
               const comments = await github.paginate(github.rest.issues.listComments, {
                 owner: context.repo.owner,
                 repo: context.repo.repo,
                 issue_number: pr.number,
                 per_page: 100,
               });

               const existing = comments.find((comment) => comment.body?.includes(marker));

               if (existing) {
                 await github.rest.issues.updateComment({
                   owner: context.repo.owner,
                   repo: context.repo.repo,
                   comment_id: existing.id,
                   body,
                 });
               } else {
                 await github.rest.issues.createComment({
                   owner: context.repo.owner,
                   repo: context.repo.repo,
                   issue_number: pr.number,
                   body,
                 });
               }
+            } catch (error) {
+              core.warning(`Unable to publish queue status comment: ${error.message}`);
+            }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const comments = await github.paginate(github.rest.issues.listComments, {
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pr.number,
per_page: 100,
});
const existing = comments.find((comment) => comment.body?.includes(marker));
if (existing) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: existing.id,
body,
});
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pr.number,
body,
});
}
try {
const comments = await github.paginate(github.rest.issues.listComments, {
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pr.number,
per_page: 100,
});
const existing = comments.find((comment) => comment.body?.includes(marker));
if (existing) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: existing.id,
body,
});
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pr.number,
body,
});
}
} catch (error) {
core.warning(`Unable to publish queue status comment: ${error.message}`);
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/merge-queue.yml around lines 75 - 98, Wrap the block that
calls github.paginate(github.rest.issues.listComments) and the subsequent
github.rest.issues.updateComment/createComment calls in a try-catch so
permission errors from forked PRs do not fail the workflow; catch any error
thrown around the comments lookup/update/create (the variables/comments flow
that computes existing from comments, and calls updateComment or createComment
with body and marker) and log a warning including the error message (instead of
throwing), then continue silently for visibility-only runs.


merge-queue-critical:
if: github.event_name == 'merge_group'
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
<<<<<<< HEAD
- name: Checkout merge candidate
uses: actions/checkout@v4
with:
fetch-depth: 0
fetch-tags: true
- uses: pnpm/action-setup@v4
=======
- uses: pnpm/action-setup@v3
>>>>>>> pr-21884

- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 9.15.4
- uses: actions/setup-node@v4
with:
node-version: 24
cache: 'pnpm'

- name: Check for PR Validation Artifact
id: validate
uses: actions/download-artifact@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
name: ci-validation-${{ github.event.merge_group.head_sha }}
path: .
continue-on-error: true

- name: Install
if: steps.validate.outcome != 'success'
run: pnpm install

- name: Build
if: steps.validate.outcome != 'success'
run: pnpm -r build || echo "Build skipped or no scripts"
node-version: 24
cache: pnpm

- name: Test
if: steps.validate.outcome != 'success'
run: pnpm -r test || echo "Test skipped or no scripts"
- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Audit
if: steps.validate.outcome != 'success'
run: pnpm audit || true
- name: Critical validation suite
run: |
pnpm run lint --if-present
pnpm run typecheck --if-present
pnpm run test --if-present
Comment on lines +127 to +129
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

Does pnpm run <script> --if-present exit successfully when the script is missing, and therefore skip the check without failing CI?

💡 Result:

Yes, pnpm run <script> --if-present exits successfully (exit code 0) when the script is missing. It skips the script without failing, allowing the command to succeed in CI pipelines.

Citations:


🏁 Script executed:

# Find and examine the merge-queue.yml file
fd -t f "merge-queue.yml" .github/workflows/

Repository: BrianCLong/summit

Length of output: 94


🏁 Script executed:

# Read the merge-queue.yml file to see the context around lines 127-129
cat -n .github/workflows/merge-queue.yml | head -150 | tail -50

Repository: BrianCLong/summit

Length of output: 1920


🏁 Script executed:

# Check if package.json exists and see if lint, typecheck, test scripts are defined
if [ -f package.json ]; then
  echo "=== Checking package.json for scripts ==="
  cat package.json | jq '.scripts | keys[] | select(. == "lint" or . == "typecheck" or . == "test")'
fi

Repository: BrianCLong/summit

Length of output: 128


Remove --if-present from critical validation suite in merge-queue gate.

--if-present silently succeeds when scripts are missing, which can produce a passing required check without actually running lint, typecheck, or test. For a merge-queue gate, these validations must always execute. While the scripts currently exist in package.json, using --if-present creates risk if future refactoring accidentally removes one.

Proposed fix
       - name: Critical validation suite
         run: |
-          pnpm run lint --if-present
-          pnpm run typecheck --if-present
-          pnpm run test --if-present
+          pnpm run lint
+          pnpm run typecheck
+          pnpm run test
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
pnpm run lint --if-present
pnpm run typecheck --if-present
pnpm run test --if-present
pnpm run lint
pnpm run typecheck
pnpm run test
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/merge-queue.yml around lines 127 - 129, The merge-queue
job currently runs "pnpm run lint --if-present", "pnpm run typecheck
--if-present", and "pnpm run test --if-present" which allows silent success when
scripts are missing; remove the "--if-present" flags so the commands always fail
if the corresponding npm scripts are absent (update the three invocations for
lint, typecheck and test), and optionally add an explicit pre-check that
validates those scripts exist in package.json or restore the missing scripts if
needed to ensure the gate always executes real validations.


- name: Generate SBOM
if: steps.validate.outcome != 'success'
run: node scripts/generate_sbom.mjs || echo "SBOM generation failed"
- name: Publish merge-group summary
if: always()
run: |
echo "### Merge Queue Validation" >> "$GITHUB_STEP_SUMMARY"
echo "- Merge group SHA: ${{ github.event.merge_group.head_sha }}" >> "$GITHUB_STEP_SUMMARY"
echo "- Base ref: ${{ github.event.merge_group.base_ref }}" >> "$GITHUB_STEP_SUMMARY"
echo "- Trigger: ${{ github.event_name }}" >> "$GITHUB_STEP_SUMMARY"
35 changes: 2 additions & 33 deletions .github/workflows/merge-train-autopilot.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
name: Merge-train Autopilot

on:
schedule:
- cron: '*/30 * * * *'
workflow_dispatch:
inputs:
batch_size:
Expand All @@ -19,7 +17,6 @@ on:
default: false

permissions:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
contents: read
pull-requests: write

Expand All @@ -36,34 +33,6 @@ jobs:
fetch-tags: true

- name: Run Autopilot
id: drain
run: |
# Use inputs if provided, otherwise defaults
BATCH="${{ github.event.inputs.batch_size || '10' }}"
MAXQ="${{ github.event.inputs.max_queue || '50' }}"
DRY="${{ github.event.inputs.dry_run }}"

ARGS="--batch-size $BATCH --max-queue $MAXQ"
if [ "$DRY" == "true" ]; then ARGS="$ARGS --dry-run"; fi

# If triggered by schedule, use defaults explicitly
if [ "${{ github.event_name }}" == "schedule" ]; then
ARGS="--batch-size 10 --max-queue 50"
fi

chmod +x .github/scripts/merge-train-autopilot.sh
./.github/scripts/merge-train-autopilot.sh $ARGS | tee autopilot.log
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Step Summary
if: always()
run: |
echo "### Merge-train Autopilot Report" >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
if [ -f autopilot.log ]; then
cat autopilot.log >> $GITHUB_STEP_SUMMARY
else
echo "Error: autopilot.log not found." >> $GITHUB_STEP_SUMMARY
fi
echo '```' >> $GITHUB_STEP_SUMMARY
echo "Autopilot now manual-only to prevent unsupervised queue churn."
echo "Use GitHub native merge queue for routine sequencing."
Loading