Fix missing target-repo in config.json for cross-repo create_pull_request#19284
Conversation
…uest workflows - Refactor generatePullRequestConfig() to accept full *CreatePullRequestsConfig and include target-repo, allowed_repos, base_branch, draft, reviewers, title_prefix, and fallback_as_issue in config.json - Update call site to pass full struct instead of individual fields - Fix misleading repo parameter description in safe_outputs_tools.json - Enrich create_pull_request tool description dynamically when target-repo is configured in safe_outputs_tools_loader.cjs - Add helpful hint to error message in safe_outputs_handlers.cjs when agent passes owning repo but target-repo is configured differently - Add tests for target-repo in config.json and backward compatibility Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
target-repo in config.json for cross-repo create_pull_request
THis is strange, as cross repo creation is working for me. Would be good to understand this more |
|
The safe outputs MCP server probably ignores those fields. The underlying problem here is that we generate the same config twice in 2 code path. Instead, we should generate config.json in activation once, store it as an artifact and download it in each job. |
There was a problem hiding this comment.
Pull request overview
This PR fixes cross-repo create_pull_request behavior by ensuring the agent-side MCP config.json includes target-repo and other relevant create-PR configuration fields (matching the already-correct conclusion-job handler config), and improves agent-facing messaging around the optional repo parameter and repo-resolution errors.
Changes:
- Refactors
generatePullRequestConfig()to emit cross-repo fields (target-repo,allowed_repos) plus additional PR settings (e.g.,base_branch,draft,reviewers,title_prefix,fallback_as_issue) into agentconfig.json. - Updates tool schema/docs and runtime tool registration/handler error messages to better guide agents in cross-repo scenarios (especially around omitting
repo). - Updates numerous workflow
.lock.ymlfixtures to reflect the updated generatedconfig.jsonand tools schema text.
Reviewed changes
Copilot reviewed 40 out of 40 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| pkg/workflow/safe_outputs_config_generation_helpers.go | Expands create-PR config generation to include target repo + additional PR fields via generateTargetConfigWithRepos(). |
| pkg/workflow/safe_outputs_config_generation.go | Passes full CreatePullRequestsConfig into the refactored generator. |
| pkg/workflow/safe_outputs_config_generation_test.go | Adds tests for cross-repo create-PR config generation + backward compatibility. |
| pkg/workflow/js/safe_outputs_tools.json | Updates create_pull_request tool repo parameter description (agent guidance). |
| actions/setup/js/safe_outputs_tools_loader.cjs | Adds contextual tool/param description enrichment when target-repo is configured. |
| actions/setup/js/safe_outputs_handlers.cjs | Adds a targeted hint when repo validation fails due to owning-repo vs configured target-repo mismatch. |
| .github/workflows/weekly-safe-outputs-spec-review.lock.yml | Refreshes embedded safe-outputs config.json/tools descriptions to include newly generated fields/text. |
| .github/workflows/weekly-editors-health-check.lock.yml | Refreshes embedded safe-outputs config.json/tools descriptions to include newly generated fields/text. |
| .github/workflows/unbloat-docs.lock.yml | Refreshes embedded safe-outputs config.json/tools descriptions to include newly generated fields/text. |
| .github/workflows/ubuntu-image-analyzer.lock.yml | Refreshes embedded safe-outputs config.json/tools descriptions to include newly generated fields/text. |
| .github/workflows/tidy.lock.yml | Refreshes embedded safe-outputs config.json/tools descriptions to include newly generated fields/text. |
| .github/workflows/test-create-pr-error-handling.lock.yml | Refreshes embedded tools descriptions to include updated repo parameter guidance. |
| .github/workflows/technical-doc-writer.lock.yml | Refreshes embedded safe-outputs config.json/tools descriptions to include newly generated fields/text. |
| .github/workflows/smoke-project.lock.yml | Refreshes embedded safe-outputs config.json/tools descriptions to include newly generated fields/text. |
| .github/workflows/smoke-multi-pr.lock.yml | Refreshes embedded safe-outputs config.json/tools descriptions to include newly generated fields/text. |
| .github/workflows/smoke-create-cross-repo-pr.lock.yml | Refreshes embedded safe-outputs config.json/tools descriptions to include cross-repo fields (notably target-repo). |
| .github/workflows/slide-deck-maintainer.lock.yml | Refreshes embedded safe-outputs config.json/tools descriptions to include newly generated fields/text. |
| .github/workflows/refiner.lock.yml | Refreshes embedded safe-outputs config.json/tools descriptions to include newly generated fields/text. |
| .github/workflows/q.lock.yml | Refreshes embedded safe-outputs config.json/tools descriptions to include newly generated fields/text. |
| .github/workflows/poem-bot.lock.yml | Refreshes embedded safe-outputs config.json/tools descriptions to include newly generated fields/text. |
| .github/workflows/layout-spec-maintainer.lock.yml | Refreshes embedded safe-outputs config.json/tools descriptions to include newly generated fields/text. |
| .github/workflows/jsweep.lock.yml | Refreshes embedded safe-outputs config.json/tools descriptions to include newly generated fields/text. |
| .github/workflows/instructions-janitor.lock.yml | Refreshes embedded safe-outputs config.json/tools descriptions to include newly generated fields/text. |
| .github/workflows/hourly-ci-cleaner.lock.yml | Refreshes embedded safe-outputs config.json/tools descriptions to include newly generated fields/text. |
| .github/workflows/go-logger.lock.yml | Refreshes embedded safe-outputs config.json/tools descriptions to include newly generated fields/text. |
| .github/workflows/glossary-maintainer.lock.yml | Refreshes embedded safe-outputs config.json/tools descriptions to include newly generated fields/text. |
| .github/workflows/github-mcp-tools-report.lock.yml | Refreshes embedded safe-outputs config.json/tools descriptions to include newly generated fields/text. |
| .github/workflows/functional-pragmatist.lock.yml | Refreshes embedded safe-outputs config.json/tools descriptions to include newly generated fields/text. |
| .github/workflows/dictation-prompt.lock.yml | Refreshes embedded safe-outputs config.json/tools descriptions to include newly generated fields/text. |
| .github/workflows/developer-docs-consolidator.lock.yml | Refreshes embedded safe-outputs config.json/tools descriptions to include newly generated fields/text. |
| .github/workflows/dead-code-remover.lock.yml | Refreshes embedded safe-outputs config.json/tools descriptions to include newly generated fields/text. |
| .github/workflows/daily-workflow-updater.lock.yml | Refreshes embedded safe-outputs config.json/tools descriptions to include newly generated fields/text. |
| .github/workflows/daily-rendering-scripts-verifier.lock.yml | Refreshes embedded safe-outputs config.json/tools descriptions to include newly generated fields/text. |
| .github/workflows/daily-doc-updater.lock.yml | Refreshes embedded safe-outputs config.json/tools descriptions to include newly generated fields/text. |
| .github/workflows/daily-doc-healer.lock.yml | Refreshes embedded safe-outputs config.json/tools descriptions to include newly generated fields/text. |
| .github/workflows/daily-architecture-diagram.lock.yml | Refreshes embedded safe-outputs config.json/tools descriptions to include newly generated fields/text. |
| .github/workflows/code-simplifier.lock.yml | Refreshes embedded safe-outputs config.json/tools descriptions to include newly generated fields/text. |
| .github/workflows/code-scanning-fixer.lock.yml | Refreshes embedded safe-outputs config.json/tools descriptions to include newly generated fields/text. |
| .github/workflows/cloclo.lock.yml | Refreshes embedded safe-outputs config.json/tools descriptions to include newly generated fields/text. |
| .github/workflows/ci-coach.lock.yml | Refreshes embedded safe-outputs config.json/tools descriptions to include newly generated fields/text. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| "repo": { | ||
| "type": "string", | ||
| "description": "Target repository in 'owner/repo' format. Required when changes are in a subdirectory checkout (e.g., 'repos/repo-a/'). Must be in the allowed-repos list. If omitted, uses the repository at the workspace root." | ||
| "description": "Target repository in 'owner/repo' format. For multi-repo workflows where the target repo differs from the workflow repo, this must match a repo in the allowed-repos list or the configured target-repo. If omitted, defaults to the configured target-repo (from safe-outputs config), NOT the workflow repository. In most cases, you should omit this parameter and let the system use the configured default." | ||
| } |
There was a problem hiding this comment.
The repo parameter description states that omitting repo defaults to the configured target-repo and not the workflow repository. However, getDefaultTargetRepo() falls back to GITHUB_REPOSITORY (and other sources) when target-repo is not set (see actions/setup/js/repo_helpers.cjs:102-120). Please update this description to reflect the conditional behavior (e.g., defaults to target-repo when configured, otherwise defaults to the workflow/current repository).
| let toolToRegister = tool; | ||
| // Enrich create_pull_request tool description when target-repo is configured | ||
| if (tool.name === "create_pull_request" && config.create_pull_request) { | ||
| const targetRepo = config.create_pull_request["target-repo"]; | ||
| if (targetRepo) { | ||
| toolToRegister = JSON.parse(JSON.stringify(tool)); | ||
| toolToRegister.description += ` Note: This workflow is configured to create pull requests in '${targetRepo}'. You do not need to specify the repo parameter.`; | ||
| if (toolToRegister.inputSchema && toolToRegister.inputSchema.properties && toolToRegister.inputSchema.properties.repo) { | ||
| toolToRegister.inputSchema.properties.repo.description += ` Configured default: '${targetRepo}'.`; | ||
| } |
There was a problem hiding this comment.
registerPredefinedTools() clones the create_pull_request tool via JSON.parse(JSON.stringify(tool)) when target-repo is configured. At this point tools already have handler functions attached (see safe_outputs_mcp_server.cjs:47-54), and JSON serialization drops functions—so the registered tool will lose its handler and become non-functional. Use an object/structured clone approach that preserves tool.handler (e.g., shallow clone with spreads and only deep-clone inputSchema.properties.repo), or explicitly copy the handler back onto the cloned object before registering.
There was a problem hiding this comment.
Yes good catch. Missed it. It's merged so let's spin a CCA to fix / text this.
|
Yeah I think the bug report is based on an older version - but this PR looks fine and has some additional fixes |
|
I will do the config.JSON unification later. |
config.json(consumed by the MCP server during the agent job) was missingtarget-repoand all other cross-repo fields forcreate_pull_request. The conclusion job'sGH_AW_SAFE_OUTPUTS_HANDLER_CONFIGhad the full config correctly; only the agent-side config was broken. This caused the MCP server to fall back toGITHUB_REPOSITORYas the target, making cross-repo PRs impossible — the agent would either create the PR in the wrong repo or get rejected for passing the owning repo explicitly.Changes
safe_outputs_config_generation_helpers.go— RefactoredgeneratePullRequestConfig()to accept*CreatePullRequestsConfig(full struct) and emittarget-repo,allowed_repos,base_branch,draft,reviewers,title_prefix, andfallback_as_issue. Now usesgenerateTargetConfigWithRepos()as its base, consistent withclose_issue.safe_outputs_config_generation.go— Updated call site to pass the full config struct.safe_outputs_tools.json— Fixed misleadingrepoparameter description: omittingrepodefaults to the configuredtarget-repo, not the workspace root.safe_outputs_tools_loader.cjs— Whenconfig.create_pull_request["target-repo"]is set, appends a contextual note to both the tool description andrepoparameter description so agents know they can omitrepo.safe_outputs_handlers.cjs— WhenresolveAndValidateRepofails because the agent passed the owning repo whiletarget-repois configured differently, appends a targeted hint explaining the mismatch.safe_outputs_config_generation_test.go— Added tests covering cross-repo config generation and backward compatibility (notarget-repostill works).Example: A workflow with
target-repo: caido/proxy-frontendnow produces:{"create_pull_request":{"base_branch":"dev","draft":true,"max":1,"reviewers":["corb3nik"],"target-repo":"caido/proxy-frontend","title_prefix":"[refactor] "}}instead of:
{"create_pull_request":{"max":1}}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:
https://api.github.com/graphql/usr/bin/gh /usr/bin/gh api graphql -f query=query($owner: String!, $name: String!) { repository(owner: $owner, name: $name) { hasDiscussionsEnabled } } -f owner=github -f name=gh-aw(http block)/usr/bin/gh /usr/bin/gh api graphql -f query=query($owner: String!, $name: String!) { repository(owner: $owner, name: $name) { hasDiscussionsEnabled } } -f owner=github -f name=gh-aw flow(http block)/usr/bin/gh /usr/bin/gh api graphql -f query=query($owner: String!, $name: String!) { repository(owner: $owner, name: $name) { hasDiscussionsEnabled } } -f owner=github -f name=gh-aw k/gh-aw/gh-aw/pk-c(http block)https://api.github.com/repos/actions/ai-inference/git/ref/tags/v1/usr/bin/gh gh api /repos/actions/ai-inference/git/ref/tags/v1 --jq .object.sha se 6087974/b108/vet.cfg(http block)/usr/bin/gh gh api /repos/actions/ai-inference/git/ref/tags/v1 --jq .object.sha /tmp/gh-aw-test-runs/20260303-002201-41658/test-3264140609 rev-parse /usr/bin/git "prettier" --wrigit git /sh git remo�� add origin /usr/bin/git ath ../../../.prgit ../../../**/*.jsrev-parse 64/bin/go git(http block)/usr/bin/gh gh api /repos/actions/ai-inference/git/ref/tags/v1 --jq .object.sha --show-toplevel git /usr/bin/git --git-dir go /usr/bin/git git rev-�� --show-toplevel git /usr/bin/git --git-dir go /usr/bin/git git(http block)https://api.github.com/repos/actions/checkout/git/ref/tags/v3/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v3 --jq .object.sha SameOutput35423236/001/stability-test.md GO111MODULE /opt/hostedtoolcache/go/1.25.0/x64/bin/go GOINSECURE GOMOD GOMODCACHE go ortc�� -json stmain.go /opt/hostedtoolcache/go/1.25.0/x64/pkg/tool/linux_amd64/compile GOINSECURE GOMOD GOMODCACHE /opt/hostedtoolcache/go/1.25.0/x64/pkg/tool/linu--jq(http block)/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v3 --jq .object.sha -json GO111MODULE /opt/hostedtoolcache/go/1.25.0/x64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE /usr/bin/sh GOINSECURE GOMOD GOMODCACHE sh(http block)/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v3 --jq .object.sha --show-toplevel git /usr/bin/git --show-toplevel node /opt/hostedtoolc--show-toplevel git rev-�� --show-toplevel node /usr/bin/git /tmp/TestHashCongit sh /usr/bin/git git(http block)https://api.github.com/repos/actions/checkout/git/ref/tags/v5/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq .object.sha -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE x_amd64/compile GOINSECURE GOMOD GOMODCACHE x_amd64/compile(http block)/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq .object.sha --show-toplevel owner /usr/bin/git 0 -j ACCEPT git rev-�� --show-toplevel go /opt/hostedtoolcache/node/24.13.1/x64/bin/node b/workflows sh 64/bin/go node(http block)/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq .object.sha -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env y.md GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go(http block)https://api.github.com/repos/actions/checkout/git/ref/tags/v6/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v6 --jq .object.sha -bool -buildtags /usr/bin/git -errorsas -ifaceassert -nilfunc /usr/bin/git remo�� -v -tests /usr/sbin/iptables -json GO111MODULE 64/bin/go iptables(http block)/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v6 --jq .object.sha 6087974/b424/_pkg_.a go 6087974/b424=> ck '**/*.cjs' '*git GO111MODULE 64/bin/go git rev-�� CxFj/4N_hV3O2Cg4KalLpCxFj go /opt/hostedtoolcache/node/24.13.1/x64/bin/node -json GO111MODULE 64/bin/go node(http block)/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v6 --jq .object.sha /usr/bin/git bash /usr/bin/git --noprofile git 64/bin/go git rev-�� --show-toplevel node /usr/bin/git --write **/*.cjs 64/bin/go git(http block)https://api.github.com/repos/actions/github-script/git/ref/tags/v8/usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v8 --jq .object.sha GOSUMDB GOWORK 64/bin/go GOINSECURE GOMOD GOMODCACHE go env ck 'scripts/**/*GOINSECURE GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go(http block)/usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v8 --jq .object.sha 35126d5394e2a1caGOINSECURE GO111MODULE 64/bin/go GOINSECURE GOMOD erignore ache/go/1.25.0/xGO111MODULE env 8008084/b412/_pkGOINSECURE GO111MODULE 64/bin/go GOINSECURE b/gh-aw/pkg/test-o GOMODCACHE go(http block)/usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v8 --jq .object.sha -json GO111MODULE 64/bin/go GOINSECURE GOMOD erignore go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go(http block)https://api.github.com/repos/actions/setup-go/git/ref/tags/v4/usr/bin/gh gh api /repos/actions/setup-go/git/ref/tags/v4 --jq .object.sha /tmp/go-build3746087974/b416/sliceutil.test(http block)/usr/bin/gh gh api /repos/actions/setup-go/git/ref/tags/v4 --jq .object.sha -bool -buildtags /usr/bin/git -errorsas -ifaceassert -nilfunc git -C /tmp/compile-all-instructions-test-1033509952/.github/workflows config /usr/bin/git remote.origin.urgit **/*.cjs 64/bin/go git(http block)/usr/bin/gh gh api /repos/actions/setup-go/git/ref/tags/v4 --jq .object.sha --show-toplevel git /usr/bin/git --git-dir go /usr/bin/git git rev-�� --show-toplevel git /usr/bin/git --show-toplevel go /usr/bin/git git(http block)https://api.github.com/repos/actions/setup-node/git/ref/tags/v4/usr/bin/gh gh api /repos/actions/setup-node/git/ref/tags/v4 --jq .object.sha t0 go(http block)/usr/bin/gh gh api /repos/actions/setup-node/git/ref/tags/v4 --jq .object.sha -x c /usr/bin/git - git 64/bin/go git rev-�� --show-toplevel node /usr/bin/git --write **/*.cjs 64/bin/go git(http block)/usr/bin/gh gh api /repos/actions/setup-node/git/ref/tags/v4 --jq .object.sha --show-toplevel git /usr/bin/git --show-toplevel go /opt/hostedtoolc--show-toplevel git rev-�� --show-toplevel node /usr/bin/git /home/REDACTED/worgit resolved$ /usr/bin/git git(http block)https://api.github.com/repos/actions/upload-artifact/git/ref/tags/v4/usr/bin/gh gh api /repos/actions/upload-artifact/git/ref/tags/v4 --jq .object.sha agent-persona-explorer.md GO111MODULE /opt/hostedtoolcache/go/1.25.0/x/tmp/gh-aw-git-clone-2021025306 GOINSECURE GOMOD GOMODCACHE go env r/test-repo/actions/secrets GO111MODULE /opt/hostedtoolcache/go/1.25.0/x64/bin/go GOINSECURE GOMOD GOMODCACHE go(http block)/usr/bin/gh gh api /repos/actions/upload-artifact/git/ref/tags/v4 --jq .object.sha -json GO111MODULE ache/go/1.25.0/x64/bin/go GOINSECURE GOMOD GOMODCACHE erignore env -json GO111MODULE /opt/hostedtoolcache/go/1.25.0/x64/bin/go GOINSECURE GOMOD GOMODCACHE go(http block)/usr/bin/gh gh api /repos/actions/upload-artifact/git/ref/tags/v4 --jq .object.sha --show-toplevel sh /usr/bin/git "prettier" --chegit l /usr/bin/git git rev-�� --show-toplevel git /usr/bin/git --show-toplevel node /usr/bin/git git(http block)https://api.github.com/repos/astral-sh/setup-uv/git/ref/tags/eac588ad8def6316056a12d4907a9d4d84ff7a3b/usr/bin/gh gh api /repos/astral-sh/setup-uv/git/ref/tags/eac588ad8def6316056a12d4907a9d4d84ff7a3b --jq .object.sha h ../../../.pret.prettierignore .cfg sh user.name(http block)https://api.github.com/repos/github/gh-aw/actions/runs/1/artifacts/usr/bin/gh gh run download 1 --dir test-logs/run-1 GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go estl�� -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go(http block)/usr/bin/gh gh run download 1 --dir test-logs/run-1 GO111MODULE 1/x64/lib/node_modules/npm/node_modules/@npmcli/run-script/lib/node-gyp-bin/sh GOINSECURE GOMOD GOMODCACHE 9D/TE8z8DiNDUNGW-4fRZ3A/6PNtGrvPdB_1y-ee1BPv env '**/*.ts' '**/*.json' --ignore-path ../../../.pr**/*.json GO111MODULE 6ffdf860dfc35a80e1ae4f9aff292fb98724de9877836669-d GOINSECURE GOMOD GOMODCACHE go(http block)https://api.github.com/repos/github/gh-aw/actions/runs/12345/artifacts/usr/bin/gh gh run download 12345 --dir test-logs/run-12345 GO111MODULE x_amd64/compile GOINSECURE GOMOD GOMODCACHE x_amd64/compile env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go(http block)/usr/bin/gh gh run download 12345 --dir test-logs/run-12345 GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE 64/bin/node GOINSECURE GOMOD GOMODCACHE go(http block)https://api.github.com/repos/github/gh-aw/actions/runs/12346/artifacts/usr/bin/gh gh run download 12346 --dir test-logs/run-12346 GO111MODULE x_amd64/vet GOINSECURE GOMOD GOMODCACHE x_amd64/vet env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go(http block)/usr/bin/gh gh run download 12346 --dir test-logs/run-12346 GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE 1/x64/bin/node GOINSECURE GOMOD GOMODCACHE go(http block)https://api.github.com/repos/github/gh-aw/actions/runs/2/artifacts/usr/bin/gh gh run download 2 --dir test-logs/run-2 GO111MODULE x_amd64/link GOINSECURE GOMOD GOMODCACHE x_amd64/link env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE Xe/zd3aBy0104K8ZfExHKi7/u8U4vpCVJ6IIRF6zALNG(http block)/usr/bin/gh gh run download 2 --dir test-logs/run-2 GO111MODULE ache/go/1.25.0/x64/bin/go GOINSECURE GOMOD GOMODCACHE go env '**/*.ts' '**/*.json' --ignore-path ../../../.pr**/*.json GO111MODULE x_amd64/vet GOINSECURE GOMOD GOMODCACHE x_amd64/vet(http block)https://api.github.com/repos/github/gh-aw/actions/runs/3/artifacts/usr/bin/gh gh run download 3 --dir test-logs/run-3 GO111MODULE x_amd64/vet GOINSECURE GOMOD GOMODCACHE x_amd64/vet env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go(http block)/usr/bin/gh gh run download 3 --dir test-logs/run-3 GO111MODULE bin/sh GOINSECURE GOMOD GOMODCACHE go env '**/*.ts' '**/*.json' --ignore-path ../../../.pr**/*.json GO111MODULE de/node/bin/sh GOINSECURE GOMOD GOMODCACHE go(http block)https://api.github.com/repos/github/gh-aw/actions/runs/4/artifacts/usr/bin/gh gh run download 4 --dir test-logs/run-4 GO111MODULE x_amd64/vet GOINSECURE GOMOD GOMODCACHE x_amd64/vet env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go(http block)/usr/bin/gh gh run download 4 --dir test-logs/run-4 GO111MODULE h GOINSECURE GOMOD GOMODCACHE go env '**/*.ts' '**/*.json' --ignore-path ../../../.pr**/*.json GO111MODULE ache/go/1.25.0/x64/bin/go GOINSECURE GOMOD GOMODCACHE go(http block)https://api.github.com/repos/github/gh-aw/actions/runs/5/artifacts/usr/bin/gh gh run download 5 --dir test-logs/run-5 GO111MODULE x_amd64/vet GOINSECURE GOMOD GOMODCACHE x_amd64/vet env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go(http block)/usr/bin/gh gh run download 5 --dir test-logs/run-5 GO111MODULE ache/go/1.25.0/x64/bin/go GOINSECURE GOMOD GOMODCACHE go env '**/*.ts' '**/*.json' --ignore-path ../../../.pr**/*.json GO111MODULE ache/go/1.25.0/x64/bin/go GOINSECURE GOMOD GOMODCACHE go(http block)https://api.github.com/repos/github/gh-aw/actions/workflows/usr/bin/gh gh workflow list --json name,state,path GOSUMDB GOWORK 64/bin/go GOINSECURE GOMOD GOMODCACHE go m/_n�� -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go(http block)/usr/bin/gh gh run list --json databaseId,number,url,status,conclusion,workflowName,createdAt,startedAt,updatedAt,event,headBranch,headSha,displayTitle --workflow nonexistent-workflow-12345 --limit 100 GOMOD GOMODCACHE go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE node(http block)/usr/bin/gh gh run list --json databaseId,number,url,status,conclusion,workflowName,createdAt,startedAt,updatedAt,event,headBranch,headSha,displayTitle --workflow nonexistent-workflow-12345 --limit 6 GOMOD GOMODCACHE x_amd64/vet env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go(http block)https://api.github.com/repos/github/gh-aw/git/ref/tags/a70c5eada06553e3510ac27f2c3bda9d3705bccb/usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/a70c5eada06553e3510ac27f2c3bda9d3705bccb --jq .object.sha h ../../../.pret.prettierignore .cfg 64/pkg/tool/linux_amd64/vet user.email(http block)https://api.github.com/repos/github/gh-aw/git/ref/tags/v1.0.0/usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v1.0.0 --jq .object.sha -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env 1430263850/.github/workflows GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go(http block)/usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v1.0.0 --jq .object.sha h ../../../.prettierignore GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go(http block)/usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v1.0.0 --jq .object.sha --show-toplevel go /usr/bin/git .js' --ignore-pagit GO111MODULE ser.test git 1/x6�� --show-toplevel ser.test /usr/bin/git -json GO111MODULE k/gh-aw/gh-aw/no--show-toplevel git(http block)https://api.github.com/repos/githubnext/agentics/git/ref/tags//usr/bin/gh gh api /repos/githubnext/agentics/git/ref/tags/# --jq .object.sha --local user.email 64/pkg/tool/linux_amd64/vet(http block)https://api.github.com/repos/nonexistent/action/git/ref/tags/v999.999.999/usr/bin/gh gh api /repos/nonexistent/action/git/ref/tags/v999.999.999 --jq .object.sha -json GO111MODULE x_amd64/vet GOINSECURE GOMOD GOMODCACHE x_amd64/vet env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go(http block)/usr/bin/gh gh api /repos/nonexistent/action/git/ref/tags/v999.999.999 --jq .object.sha -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go(http block)/usr/bin/gh gh api /repos/nonexistent/action/git/ref/tags/v999.999.999 --jq .object.sha --show-toplevel go 64/bin/node .js' --ignore-pagit GO111MODULE 64/pkg/tool/linu--show-toplevel git 1/x6�� --show-toplevel 64/pkg/tool/linu3 /usr/bin/git -json GO111MODULE k/node_modules/.--show-toplevel git(http block)https://api.github.com/repos/nonexistent/repo/actions/runs/12345/usr/bin/gh gh run view 12345 --repo nonexistent/repo --json status,conclusion GOINSECURE GOMOD GOMODCACHE x_amd64/link env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE uC/HOMpbcQyfh4G56Kcj8To/9s4TpGNoremote.origin.url(http block)/usr/bin/gh gh run view 12345 --repo nonexistent/repo --json status,conclusion GOINSECURE GOMOD GOMODCACHE go env */*.ts' '**/*.json' --ignore-path ../../../.prettierignore GO111MODULE 64/pkg/tool/linux_amd64/asm GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/asm(http block)https://api.github.com/repos/owner/repo/actions/workflows/usr/bin/gh gh workflow list --json name,state,path --repo owner/repo 64/bin/go GOINSECURE GOMOD GOMODCACHE erignore env ript formatting GOINSECURE GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE ; \ fi(http block)/usr/bin/gh gh workflow list --json name,state,path --repo owner/repo 64/bin/go GOINSECURE GOMOD GOMODCACHE erignore env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go(http block)/usr/bin/gh gh workflow list --json name,state,path --repo owner/repo 64/bin/go **/*.ts **/*.json --ignore-path node /hom�� --write scripts/**/*.js 64/bin/go .prettierignore --log-level=erro/opt/hostedtoolcache/node/24.13.1/x64/bin/npx /usr/bin/git golangci-lint(http block)https://api.github.com/repos/owner/repo/contents/file.md/tmp/go-build3746087974/b383/cli.test /tmp/go-build3746087974/b383/cli.test -test.testlogfile=/tmp/go-build3746087974/b383/testlog.txt -test.paniconexit0 -test.v=true -test.parallel=4 -test.timeout=10m0s -test.run=^Test -test.short=true GOINSECURE GOMOD GOMODCACHE go ache�� -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go(http block)/tmp/go-build1564067028/b383/cli.test /tmp/go-build1564067028/b383/cli.test -test.testlogfile=/tmp/go-build1564067028/b383/testlog.txt -test.paniconexit0 -test.v=true -test.parallel=4 -test.timeout=10m0s -test.run=^Test -test.short=true xterm-color x_amd64/vet /usr/bin/git sh -c "prettier" --wriGOINSECURE git 64/bin/go --show-toplevel go /usr/bin/git sh(http block)https://api.github.com/repos/test-owner/test-repo/actions/secrets/usr/bin/gh gh api /repos/test-owner/test-repo/actions/secrets --jq .secrets[].name GOSUMDB GOWORK 64/bin/go GOINSECURE GOMOD GOMODCACHE go env ck 'scripts/**/*GOINSECURE GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go(http block)/usr/bin/gh gh api /repos/test-owner/test-repo/actions/secrets --jq .secrets[].name npx prettier --wGOINSECURE git 64/bin/go --show-toplevel x_amd64/compile /usr/bin/git node /hom�� --write scripts/**/*.js 64/bin/go .prettierignore --log-level=erro/home/REDACTED/work/gh-aw/gh-aw/actions/setup/js/node_modules/.bin/prettier /usr/bin/git node(http block)If you need me to access, download, or install something from one of these locations, you can either:
Original prompt
This section details on the original issue you should resolve
<issue_title>
config.jsonmissingtarget-repoforcreate_pull_requestin cross-repo workflows</issue_title><issue_description>### Summary
When a workflow runs in repo A but configures
safe-outputs.create-pull-request.target-repoto repo B, thetarget-repovalue is correctly compiled intoGH_AW_SAFE_OUTPUTS_HANDLER_CONFIG(used by the conclusion job) but is missing from theconfig.jsonfile (used by the MCP server during the agent job). This causes the MCP server to default toGITHUB_REPOSITORY(the owning repo), making cross-repo PRs impossible — the agent cannot target the configured repo.Reproduction
Workflow file (
.github/workflows/proxy-frontend-refactor.mdincaido/ai-ops):Expected behavior: The MCP server's
config.jsonincludes"target-repo":"caido/proxy-frontend". The agent can omitrepoand the default resolves tocaido/proxy-frontend. Passingrepo: "caido/proxy-frontend"explicitly also works.Actual behavior: The compiled
config.jsonis:{"create_pull_request":{"max":1},"missing_data":{},"missing_tool":{},"noop":{"max":1}}No
target-repo, nobase_branch, nodraft, noreviewers, notitle_prefix. The MCP server'sgetDefaultTargetRepo()falls back toGITHUB_REPOSITORY=caido/ai-ops.Result: when the agent omits
repo, the PR targetscaido/ai-ops. When the agent explicitly passesrepo: "caido/proxy-frontend", the server rejects it:Meanwhile,
GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG(conclusion job) has the full config:{"create_pull_request":{"base_branch":"dev","draft":true,"fallback_as_issue":false,"max":1,"max_patch_size":1024,"reviewers":["corb3nik"],"target-repo":"caido/proxy-frontend","title_prefix":"[refactor] "}}Analysis
There are two separate config generation paths in the compiler, and only one includes
target-repo:Config path 1:
config.json(agent job MCP server) — BROKENGenerated by
generateSafeOutputsConfig()inpkg/workflow/safe_outputs_config_generation.go(line 232-240):This calls
generatePullRequestConfig()inpkg/workflow/safe_outputs_config_generation_helpers.go(line 135-155), which only passesmax,allowed_labels,allow_empty,auto_merge, andexpires. It does not passtarget-repo,allowed-repos,base_branch,draft,reviewers,title_prefix, orfallback_as_issue.Config path 2:
GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG(conclusion job) — CORRECTGenerated by the handler config builder in
pkg/workflow/compiler_safe_outputs_config.go(line 346-368), which usesnewHandlerConfigBuilder()and includes all fields:Why
close_issueworks butcreate_pull_requestdoesn'tCompare:
close_issue(line 225) usesgenerateTargetConfigWithRepos()which includestarget-repoandallowed_repos. Butcreate_pull_request(line 232) usesgeneratePullRequestConfig()which does not.Secondary issue: misleading
repoparameter descriptionIn
pkg/workflow/js/safe_outputs_tools.json(line 247-249), therepoparameter says:This is incorrect. When
target-repois configured, omittingrepodefaults to thetarget-repovalue — not the workspace root. ThegetDefaultTargetRepo()function inactions/setup/js/repo_helpers.cjs(line 101) checksconfig["target-repo"]first. This misleading description causes agents to explicitly passrepowith the wrong value.Implementation Plan
1. Fix
generatePullRequestConfig()to includetarget-repoand related fieldsFile:...
config.jsonmissingtarget-repoforcreate_pull_requestin cross-repo workflows #19266🔒 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.