fix: replace git push with GraphQL signed commits to satisfy required_signatures rulesets#21576
fix: replace git push with GraphQL signed commits to satisfy required_signatures rulesets#21576
Conversation
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Add pushSignedCommits() helper to push_to_pull_request_branch.cjs and create_pull_request.cjs that replays local commits via the GitHub GraphQL createCommitOnBranch mutation, producing cryptographically signed commits. Falls back to plain git push on GHES or when GraphQL fails. Handles added/modified/deleted/renamed/copied files. Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
| * @param {object} [opts.gitAuthEnv] - Environment variables for git push fallback auth | ||
| * @returns {Promise<void>} | ||
| */ | ||
| async function pushSignedCommits({ githubClient, owner, repo, branch, baseRef, cwd, gitAuthEnv }) { |
There was a problem hiding this comment.
@copilot move to helper file, add integration test into a test branch (reuse test branch) . Reuse with create pr safe output
There was a problem hiding this comment.
✅ The smoke test agent confirms: pushSignedCommits has been moved to push_signed_commits.cjs and is reused by both create_pull_request.cjs and push_to_pull_request_branch.cjs as requested! The new helper file also includes push_signed_commits.test.cjs for testing.
📰 BREAKING: Report filed by Smoke Copilot
|
Hey
If you'd like a hand addressing these, here's a ready-to-run prompt for your coding agent:
|
|
✨ The prophecy is fulfilled... Smoke Codex has completed its mystical journey. The stars align. 🌟 |
|
🎬 THE END — Smoke Claude MISSION: ACCOMPLISHED! The hero saves the day! ✨ |
|
📰 BREAKING: Smoke Copilot is now investigating this pull request. Sources say the story is developing... |
|
✅ All tools validated successfully! Agent Container Smoke Test confirms agent container is ready. |
Agent Container Tool Check
Result: 12/12 tools available ✅ Overall Status: PASS
|
|
Commit pushed:
|
|
Smoke Test: Codex Engine Validation
Warning
|
|
🤖 Smoke test §23249688412 —
Status: PARTIAL PASS — Serena MCP tools not available
|
There was a problem hiding this comment.
Smoke test review of PR #21576 — replacing git push with GraphQL createCommitOnBranch for signed commits is a solid approach to satisfy required-signature rulesets. Two minor observations: (1) exec needs an explicit require, and (2) the per-commit ls-remote loop could be optimized. Overall the implementation looks correct with good fallback handling.
📰 BREAKING: Report filed by Smoke Copilot
| * @param {object} opts | ||
| * @param {any} opts.githubClient - Authenticated Octokit client with .graphql() | ||
| * @param {string} opts.owner - Repository owner | ||
| * @param {string} opts.repo - Repository name |
There was a problem hiding this comment.
The exec module is used here but doesn't appear to be declared with a require at the top of the file. Consider adding const exec = require("@actions/exec"); to the imports section to make the dependency explicit.
| const expectedHeadOid = oidOut.trim().split(/\s+/)[0]; | ||
| if (!expectedHeadOid) { | ||
| throw new Error(`Could not resolve remote HEAD OID for branch ${branch}`); | ||
| } |
There was a problem hiding this comment.
The ls-remote call on every iteration of the loop (for (const sha of shas)) makes an extra network round-trip per commit. For repos with many new commits, this could be slow. Consider fetching the initial remote HEAD OID once before the loop and updating it locally after each successful GraphQL mutation.
|
Smoke Test Results — Run §23249688423
Overall: PARTIAL (2 skipped)
|
There was a problem hiding this comment.
💥 Automated smoke test review - all systems nominal!
💥 [THE END] — Illustrated by Smoke Claude
| * @param {object} [opts.gitAuthEnv] - Environment variables for git push fallback auth | ||
| * @returns {Promise<void>} | ||
| */ | ||
| async function pushSignedCommits({ githubClient, owner, repo, branch, baseRef, cwd, gitAuthEnv }) { |
There was a problem hiding this comment.
The function signature destructures all options inline — consider defining a JSDoc typedef for the options object to improve IDE autocomplete and make it clearer what callers must provide.
| const { stdout: revListOut } = await exec.getExecOutput("git", ["rev-list", "--reverse", `${baseRef}..HEAD`], { cwd }); | ||
| const shas = revListOut.trim().split("\n").filter(Boolean); | ||
|
|
||
| if (shas.length === 0) { |
There was a problem hiding this comment.
Good early-exit guard. The shas.length === 0 check prevents unnecessary GraphQL calls when there are no new commits to push.
|
📰 VERDICT: Smoke Copilot has concluded. All systems operational. This is a developing story. 🎤 |
There was a problem hiding this comment.
Pull request overview
This PR replaces direct git push usage with a GraphQL-based commit replay (createCommitOnBranch) so commits created by the workflow are GitHub-signed and comply with required_signatures branch protection rules, with a fallback to git push when GraphQL isn’t available.
Changes:
- Introduces
pushSignedCommits()helper to replay commits via GraphQLcreateCommitOnBranchand fall back togit push. - Updates
push_to_pull_request_branch.cjsandcreate_pull_request.cjsto use the new helper instead of directgit push. - Adds integration tests for the helper and updates existing tests to cover the new flow.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
actions/setup/js/push_signed_commits.cjs |
Adds GraphQL-based signed commit replay helper with git-push fallback. |
actions/setup/js/push_to_pull_request_branch.cjs |
Switches push step from git push to pushSignedCommits(). |
actions/setup/js/create_pull_request.cjs |
Switches branch push steps from git push to pushSignedCommits(). |
actions/setup/js/push_signed_commits.test.cjs |
Adds integration tests for commit enumeration, payload construction, and fallback behavior. |
actions/setup/js/push_to_pull_request_branch.test.cjs |
Updates mocks to account for the new signed-push flow and fallback. |
go.mod |
Promotes github.com/charmbracelet/lipgloss to a direct dependency. |
.changeset/patch-use-signed-commit-pushes.md |
Declares a patch release for signed-commit push behavior change. |
Comments suppressed due to low confidence (1)
actions/setup/js/create_pull_request.cjs:919
- Same issue as the earlier pushSignedCommits call: if the branch doesn’t already exist on the remote,
pushSignedCommits()will fall back togit push(unsigned) becausegit ls-remotereturns no OID. For the allow-empty branch creation path, this likely happens every time; consider creating the remote ref first via GraphQL (or in the helper) socreateCommitOnBranchis used and commits are GitHub-signed underrequired_signatures.
await pushSignedCommits({
githubClient,
owner: repoParts.owner,
repo: repoParts.repo,
branch: branchName,
baseRef: `origin/${baseBranch}`,
cwd: process.cwd(),
});
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
| } else if (status.startsWith("R") || status.startsWith("C")) { | ||
| // Rename or Copy: parts[1] = old path, parts[2] = new path | ||
| deletions.push({ path: parts[1] }); | ||
| const content = fs.readFileSync(path.join(cwd, parts[2])); | ||
| additions.push({ path: parts[2], contents: content.toString("base64") }); | ||
| } else { | ||
| // Added or Modified | ||
| const content = fs.readFileSync(path.join(cwd, parts[1])); | ||
| additions.push({ path: parts[1], contents: content.toString("base64") }); | ||
| } |
| // Get the current remote HEAD OID (updated each iteration) | ||
| const { stdout: oidOut } = await exec.getExecOutput("git", ["ls-remote", "origin", `refs/heads/${branch}`], { cwd }); | ||
| const expectedHeadOid = oidOut.trim().split(/\s+/)[0]; | ||
| if (!expectedHeadOid) { | ||
| throw new Error(`Could not resolve remote HEAD OID for branch ${branch}`); | ||
| } |
| const result = await githubClient.graphql( | ||
| `mutation($input: CreateCommitOnBranchInput!) { | ||
| createCommitOnBranch(input: $input) { commit { oid } } | ||
| }`, | ||
| { input } | ||
| ); | ||
| const oid = result?.createCommitOnBranch?.commit?.oid; | ||
| core.info(`pushSignedCommits: signed commit created: ${oid}`); | ||
| } | ||
| core.info(`pushSignedCommits: all ${shas.length} commit(s) pushed as signed commits`); | ||
| } catch (graphqlError) { | ||
| core.warning(`pushSignedCommits: GraphQL signed push failed, falling back to git push: ${graphqlError instanceof Error ? graphqlError.message : String(graphqlError)}`); | ||
| await exec.exec("git", ["push", "origin", branch], { | ||
| cwd, | ||
| env: { ...process.env, ...(gitAuthEnv || {}) }, | ||
| }); | ||
| } |
| await pushSignedCommits({ | ||
| githubClient, | ||
| owner: repoParts.owner, | ||
| repo: repoParts.repo, | ||
| branch: branchName, | ||
| baseRef: `origin/${baseBranch}`, | ||
| cwd: process.cwd(), | ||
| }); |
* docs: add GH_HOST and RUNNER_TEMP to glossary (daily scan 2026-03-18) (#21553) * docs: update GHES CLI docs and add Copilot GHES troubleshooting guide (#21528) * Fix list height not updating on terminal resize (#21555) * fix(daily-workflow-updater): unblock PR creation by setting protected-files: allowed (#21554) * chore: bump MCP Gateway v0.1.15→v0.1.17 (#21552) * feat: custom Huh theme mapped from pkg/styles Dracula palette (#21557) * Add top-level `github-app` frontmatter as universal fallback for token minting (#21510) * feat: add GitHub App-only permissions support (#21511) * fix: fall back to existing remote tracking ref when incremental patch fetch fails (#21568) * Add weekly blog post writer agentic workflow (#21575) * ci: add timeout-minutes to all 25 jobs lacking explicit limits (#21601) * fix: add setupGlobals in generate_aw_info step to fix staged mode ReferenceError (#21602) * Disable lockdown mode for weekly blog post generator (#21598) * fix: replace git push with GraphQL signed commits to satisfy required_signatures rulesets (#21576) * docs: add weekly update blog post for 2026-03-18 (#21608) Covers v0.58.0 through v0.61.0 (7 releases this week), notable PRs, and auto-triage-issues as Agent of the Week. Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix failing CI: merge main to include setupGlobals in generate_aw_info step and update golden files Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com> --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
…ains on data residency (#21527) * Initial plan * Fix threat detection AWF run missing --copilot-api-target and GHE domains on data residency When engine.api-target is configured for GHE Cloud with data residency, propagate the APITarget from the main engine config to the detection engine config so the threat detection AWF invocation receives the same --copilot-api-target flag and GHE-specific domains in --allow-domains. Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com> * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Add GITHUB_COPILOT_BASE_URL env var support and fix integration test api-target - Fix TestAPITargetDomainsInThreatDetectionStep to use api.contoso-aw.ghe.com (copilot-api. prefix does not trigger base-domain derivation in GetAPITargetDomains) - Add GetCopilotAPITarget() helper: resolves --copilot-api-target from engine.api-target (explicit) or GITHUB_COPILOT_BASE_URL in engine.env (fallback), mirroring the OPENAI_BASE_URL/ANTHROPIC_BASE_URL pattern for Codex/Claude - Update awf_helpers.go, copilot_engine_execution.go, and domains.go to use the helper - Add unit tests for GetCopilotAPITarget and engine execution step - Add integration test TestGitHubCopilotBaseURLInCompiledWorkflow - Update engines.md docs to document GITHUB_COPILOT_BASE_URL Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> * Update DefaultMCPGatewayVersion to v0.1.17 and regenerate golden/lock files (#21609) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com> * fix: merge main to resolve failing build-wasm and test CI jobs (#21612) * docs: add GH_HOST and RUNNER_TEMP to glossary (daily scan 2026-03-18) (#21553) * docs: update GHES CLI docs and add Copilot GHES troubleshooting guide (#21528) * Fix list height not updating on terminal resize (#21555) * fix(daily-workflow-updater): unblock PR creation by setting protected-files: allowed (#21554) * chore: bump MCP Gateway v0.1.15→v0.1.17 (#21552) * feat: custom Huh theme mapped from pkg/styles Dracula palette (#21557) * Add top-level `github-app` frontmatter as universal fallback for token minting (#21510) * feat: add GitHub App-only permissions support (#21511) * fix: fall back to existing remote tracking ref when incremental patch fetch fails (#21568) * Add weekly blog post writer agentic workflow (#21575) * ci: add timeout-minutes to all 25 jobs lacking explicit limits (#21601) * fix: add setupGlobals in generate_aw_info step to fix staged mode ReferenceError (#21602) * Disable lockdown mode for weekly blog post generator (#21598) * fix: replace git push with GraphQL signed commits to satisfy required_signatures rulesets (#21576) * docs: add weekly update blog post for 2026-03-18 (#21608) Covers v0.58.0 through v0.61.0 (7 releases this week), notable PRs, and auto-triage-issues as Agent of the Week. Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix failing CI: merge main to include setupGlobals in generate_aw_info step and update golden files Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com> --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com> Co-authored-by: Landon Cox <landon.cox@microsoft.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Commits created via
git am+git pushover the Git protocol are unverified because GitHub does not auto-sign them. This breaks repos withrequired_signaturesbranch protection rules (enterprise blocker).Approach
Replace only the final
git pushstep with a GraphQL replay that reads the locally-applied tree (fromgit am) and submits each commit viacreateCommitOnBranch— which GitHub auto-signs. The patch generation andgit ampipeline is unchanged.Changes
push_to_pull_request_branch.cjs— addpushSignedCommits()helper; replacegit pushcall sitecreate_pull_request.cjs— same helper (deduped inline); replace bothgit pushcall sites (post-patch and allow-empty)pushSignedCommits()behaviorgitAuthEnvpassed through to fallbackgit pushfor cross-repo PAT authpush_to_pull_request_branch.test.cjsto mock the new GraphQL + fallback flowOriginal prompt
🔒 GitHub Advanced Security automatically protects Copilot coding agent pull requests. You can protect all pull requests by enabling Advanced Security for your repositories. Learn more about Advanced Security.
✨ PR Review Safe Output Test - Run 23245212334
✨ PR Review Safe Output Test - Run 23249688423