Conversation
Replace hardcoded `${{ github.token }}` with proper token precedence chain:
1. Per-config token (create-pull-request.github-token)
2. Safe-outputs token (safe-outputs.github-token)
3. Top-level token (github-token)
4. Default fallback (${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }})
This fixes the bug where cross-repo PRs failed authentication because
the default GITHUB_TOKEN is scoped to the source repo.
Changes:
- pkg/workflow/compiler_safe_outputs_steps.go: Updated buildSharedPRCheckoutSteps
- pkg/workflow/create_pull_request.go: Updated buildCreateOutputPullRequestJob
- pkg/workflow/compiler_safe_outputs_steps_test.go: Updated tests + added test cases
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Extract configToken into a separate variable with nil check for consistency with buildSharedPRCheckoutSteps pattern, even though CreatePullRequests is already validated at function start. Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
|
@copilot merge main and remove top level github token |
- Merged origin/main to get latest changes - Removed "with top-level github-token" test case per user request - Updated token precedence implementation to match new API: - getEffectiveSafeOutputGitHubToken() now takes single parameter - Token precedence resolved locally before calling function - Removed references to WorkflowData.GitHubToken (no longer exists) - Pattern: configToken > safeOutputsToken > GH_AW_GITHUB_TOKEN || GITHUB_TOKEN Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Done. Merged main and removed the top-level github-token test case. The implementation now uses the updated token API from main where getEffectiveSafeOutputGitHubToken() takes a single parameter. Token precedence is: per-config token > safe-outputs token > GH_AW_GITHUB_TOKEN || GITHUB_TOKEN. Commit: 71c7ec4 |
There was a problem hiding this comment.
Pull request overview
This PR updates the workflow compiler so cross-repo create-pull-request (and the consolidated safe-outputs PR checkout path) no longer hardcode ${{ github.token }} and instead use the safe-outputs token precedence chain, preventing auth failures when a PAT is configured.
Changes:
- Updated consolidated safe-outputs shared PR checkout/git-credential steps to use
getEffectiveSafeOutputGitHubToken(...)-based precedence. - Updated the legacy
buildCreateOutputPullRequestJob()path to resolve a token via the same precedence for git remote configuration. - Expanded unit coverage for token precedence in shared PR checkout steps and regenerated affected workflow
.lock.ymloutputs.
Reviewed changes
Copilot reviewed 36 out of 36 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| pkg/workflow/create_pull_request.go | Resolves an effective token for git credential configuration in the legacy create-pull-request job. |
| pkg/workflow/compiler_safe_outputs_steps.go | Uses safe-outputs token precedence for consolidated shared PR checkout + git credential steps. |
| pkg/workflow/compiler_safe_outputs_steps_test.go | Adds/updates tests validating token selection in shared PR checkout steps. |
| .github/workflows/workflow-generator.lock.yml | Regenerated locked workflow artifacts (includes safe-outputs tools schema and token fallback updates). |
| .github/workflows/weekly-safe-outputs-spec-review.lock.yml | Updates locked checkout/git token usage to the secrets fallback chain. |
| .github/workflows/unbloat-docs.lock.yml | Updates locked checkout/git token usage to the secrets fallback chain. |
| .github/workflows/ubuntu-image-analyzer.lock.yml | Updates locked checkout/git token usage to the secrets fallback chain. |
| .github/workflows/tidy.lock.yml | Updates locked checkout/git token usage to the secrets fallback chain. |
| .github/workflows/test-create-pr-error-handling.lock.yml | Updates locked checkout/git token usage to the secrets fallback chain. |
| .github/workflows/technical-doc-writer.lock.yml | Updates locked checkout/git token usage to the secrets fallback chain. |
| .github/workflows/smoke-project.lock.yml | Updates locked checkout/git token usage to the secrets fallback chain. |
| .github/workflows/smoke-claude.lock.yml | Updates locked checkout/git token usage to the secrets fallback chain. |
| .github/workflows/slide-deck-maintainer.lock.yml | Updates locked checkout/git token usage to the secrets fallback chain. |
| .github/workflows/refiner.lock.yml | Updates locked checkout/git token usage to the secrets fallback chain. |
| .github/workflows/q.lock.yml | Updates locked checkout/git token usage to the secrets fallback chain. |
| .github/workflows/poem-bot.lock.yml | Updates locked checkout/git token usage to the secrets fallback chain. |
| .github/workflows/mergefest.lock.yml | Updates locked checkout/git token usage to the secrets fallback chain. |
| .github/workflows/layout-spec-maintainer.lock.yml | Updates locked checkout/git token usage to the secrets fallback chain. |
| .github/workflows/jsweep.lock.yml | Updates locked checkout/git token usage to the secrets fallback chain. |
| .github/workflows/issue-monster.lock.yml | Regenerated locked workflow artifacts (includes safe-outputs tools schema and token fallback updates). |
| .github/workflows/instructions-janitor.lock.yml | Updates locked checkout/git token usage to the secrets fallback chain. |
| .github/workflows/hourly-ci-cleaner.lock.yml | Updates locked checkout/git token usage to the secrets fallback chain. |
| .github/workflows/go-logger.lock.yml | Updates locked checkout/git token usage to the secrets fallback chain. |
| .github/workflows/glossary-maintainer.lock.yml | Updates locked checkout/git token usage to the secrets fallback chain. |
| .github/workflows/github-mcp-tools-report.lock.yml | Updates locked checkout/git token usage to the secrets fallback chain. |
| .github/workflows/functional-pragmatist.lock.yml | Updates locked checkout/git token usage to the secrets fallback chain. |
| .github/workflows/dictation-prompt.lock.yml | Updates locked checkout/git token usage to the secrets fallback chain. |
| .github/workflows/developer-docs-consolidator.lock.yml | Updates locked checkout/git token usage to the secrets fallback chain. |
| .github/workflows/daily-workflow-updater.lock.yml | Updates locked checkout/git token usage to the secrets fallback chain. |
| .github/workflows/daily-doc-updater.lock.yml | Updates locked checkout/git token usage to the secrets fallback chain. |
| .github/workflows/craft.lock.yml | Updates locked checkout/git token usage to the secrets fallback chain. |
| .github/workflows/code-simplifier.lock.yml | Updates locked checkout/git token usage to the secrets fallback chain. |
| .github/workflows/code-scanning-fixer.lock.yml | Updates locked checkout/git token usage to the secrets fallback chain. |
| .github/workflows/cloclo.lock.yml | Updates locked checkout/git token usage to the secrets fallback chain. |
| .github/workflows/ci-coach.lock.yml | Updates locked checkout/git token usage to the secrets fallback chain. |
| .github/workflows/changeset.lock.yml | Updates locked checkout/git token usage to the secrets fallback chain. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Precedence: create-pull-request config token > safe-outputs token > GH_AW_GITHUB_TOKEN || GITHUB_TOKEN | ||
| var configToken string | ||
| if data.SafeOutputs.CreatePullRequests != nil { | ||
| configToken = data.SafeOutputs.CreatePullRequests.GitHubToken | ||
| } |
There was a problem hiding this comment.
In the shared checkout/token selection, only CreatePullRequests.GitHubToken is considered as the per-config override. This function is also used for push-to-pull-request-branch, so a workflow that sets safe-outputs.push-to-pull-request-branch.github-token (but not create-pull-request) will have that token ignored and fall back to the safe-outputs/global token chain, potentially breaking cross-repo pushes. Consider selecting the first non-empty token from (create-pull-request token, push-to-pull-request-branch token, safe-outputs token) before calling getEffectiveSafeOutputGitHubToken.
There was a problem hiding this comment.
Fixed. buildSharedPRCheckoutSteps now considers both CreatePullRequests.GitHubToken and PushToPullRequestBranch.GitHubToken with precedence: create-pr token > push-to-pr-branch token > safe-outputs token > fallback.
Commit: b044b88
pkg/workflow/create_pull_request.go
Outdated
| @@ -68,7 +68,23 @@ func (c *Compiler) buildCreateOutputPullRequestJob(data *WorkflowData, mainJobNa | |||
|
|
|||
| // Step 3: Configure Git credentials | |||
| // Pass the target repo to configure git remote correctly for cross-repo operations | |||
| gitToken := "${{ github.token }}" | |||
| // Use token precedence chain instead of hardcoded github.token | |||
There was a problem hiding this comment.
This change resolves the token used for the git remote configuration step, but the preceding checkout step is still built via buildCheckoutRepository(...), which hardcodes the checkout token to the default safe-outputs fallback (secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN) and does not use the per-config create-pull-request.github-token / safe-outputs.github-token precedence you just computed. For cross-repo PRs where users set create-pull-request.github-token: ${{ secrets.CROSS_REPO_PAT }}, checkout can still fail before git config runs. Consider updating the checkout builder to accept and use the same resolved effective token for actions/checkout when target-repo (or trial mode) is in play.
There was a problem hiding this comment.
Fixed. Updated buildCheckoutRepository() to accept a customToken parameter and pass the resolved token from create_pull_request to the checkout step. The checkout now uses the same token precedence chain as git config.
Commit: b044b88
| { | ||
| name: "with safe-outputs github-token", | ||
| safeOutputs: &SafeOutputsConfig{ | ||
| GitHubToken: "${{ secrets.SAFE_OUTPUTS_TOKEN }}", | ||
| CreatePullRequests: &CreatePullRequestsConfig{}, | ||
| }, | ||
| checkContains: []string{ | ||
| "token: ${{ secrets.SAFE_OUTPUTS_TOKEN }}", | ||
| "GIT_TOKEN: ${{ secrets.SAFE_OUTPUTS_TOKEN }}", | ||
| }, | ||
| }, |
There was a problem hiding this comment.
TestBuildSharedPRCheckoutSteps adds coverage for create-pull-request token precedence, but there’s no case asserting that push-to-pull-request-branch.github-token is honored when create-pull-request is disabled. Given buildSharedPRCheckoutSteps() is shared between both operations, adding a push-only per-config token test would catch regressions like ignoring PushToPullRequestBranch.GitHubToken.
There was a problem hiding this comment.
Added test coverage for push-to-pull-request-branch token precedence:
- "push-to-pull-request-branch with per-config token" - validates push-only config token is honored
- "both operations with create-pr token takes precedence" - validates create-pr token has priority when both are configured
Commit: b044b88
|
@copilot review comments |
…kout token 1. Support PushToPullRequestBranch.GitHubToken in buildSharedPRCheckoutSteps - Token precedence: create-pr token > push-to-pr-branch token > safe-outputs token - Prevents token being ignored for cross-repo push operations 2. Fix buildCheckoutRepository to accept and use custom token - Added customToken parameter to buildCheckoutRepository() - Pass resolved token from create_pull_request to checkout step - Fixes issue where checkout used default token even when custom token configured 3. Add test coverage for push-to-pull-request-branch token precedence - Test case: push-to-pull-request-branch with per-config token - Test case: both operations with create-pr token taking precedence Addresses review comments #2818977843, #2818977874, #2818977910 Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
|
@copilot Recompile |
Recompile completed successfully. All 155 workflows compiled with no changes to lock files - they were already up to date with the code changes. Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
Cross-repo
create-pull-requestandpush-to-pull-request-branchoperations hardcoded${{ github.token }}for checkout and git credential steps, ignoring configured PATs. This caused authentication failures since defaultGITHUB_TOKENis scoped to the source repository.Changes
Replaced hardcoded tokens with precedence chain in:
buildSharedPRCheckoutSteps()- consolidated safe-outputs checkout path (supports both create-pull-request and push-to-pull-request-branch)buildCreateOutputPullRequestJob()- legacy create-pull-request job pathbuildCheckoutRepository()- updated to accept and use custom token for checkout stepToken precedence (aligned with main branch API):
create-pull-request.github-tokenorpush-to-pull-request-branch.github-tokensafe-outputs.github-token${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}For the shared checkout path, the precedence is: create-pull-request token > push-to-pull-request-branch token > safe-outputs token > fallback.
Example
Before (hardcoded):
After (respects configuration):
Test Coverage
Added test cases for token precedence:
Original prompt
This section details on the original issue you should resolve
<issue_title>Bug: Cross-repo create-pull-request checkout uses hardcoded github.token instead of safe-outputs token</issue_title>
<issue_description>## Summary
When
create-pull-requestis configured withtarget-repoand a customgithub-token(PAT) insafe-outputs, the compiledsafe_outputsjob's checkout and git credential steps use the hardcoded${{ github.token }}instead of the configured token. This causesNot Founderrors because the defaultGITHUB_TOKENis scoped to the source repository and cannot access the target repository.This is a remaining bug from #15500, which fixed the
repository:andREPO_NAMEparameters but did not address the token used for authentication.Reproduction
Workflow in
org/source-repotargetingorg/target-repo:Result: The compiled
.lock.ymlproduces:The checkout fails with:
Not Found - https://docs.github.com/rest/repos/repos#get-a-repositoryNote: The PAT itself is valid — the same token successfully creates issues in the target repo via the
create_issuesafe-output fallback path, which correctly usesaddSafeOutputGitHubTokenForConfigfor token resolution.Root Cause
In
pkg/workflow/compiler_safe_outputs_steps.go, thebuildSharedPRCheckoutStepsfunction (consolidated path) hardcodes${{ github.token }}when GitHub App auth is not configured:This bypasses the token precedence chain that every other safe-output operation respects:
github-token(e.g.,create-pull-request.github-token)github-tokengithub-token${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}The same bug exists in the non-consolidated path in
pkg/workflow/create_pull_request.goline 71:Proposed Fix
Replace the hardcoded
${{ github.token }}with the existinggetEffectiveSafeOutputGitHubTokenchain, matching howaddSafeOutputGitHubTokenForConfigresolves tokens for all other safe-output operations.In
compiler_safe_outputs_steps.go(buildSharedPRCheckoutSteps):In
create_pull_request.go(buildCreateOutputPullRequestJob):Tests to add/update:
TestBuildSharedPRCheckoutSteps"create pull request only" case to expect${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}instead of${{ github.token }}safe-outputs.github-token, with per-config token, with top-level token, without any custom tokenTestCreatePullRequestCrossRepoWithCustomTokenandTestCreatePullRequestCrossRepoWithoutCustomTokenpatch-fix-cross-repo-checkout-token.mdEnvironment
d00dc822f(current main)Related
create-pull-requesttarget-repois ignored by git operations in safe_outputs job #15500 — Fixedrepository:andREPO_NAMEfor cross-repo, but left token hardcodedcreate-pull-requesttarget-repois ignored by git operations in safe_outputs job #15500 fix (note its "After (correct)" example still showstoken: ${{ github.token }})</issue_description>
Comments on the Issue (you are @copilot in this section)
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.