You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: actions/setup/js/dispatch_workflow.cjs
+3-1Lines changed: 3 additions & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -55,7 +55,9 @@ async function main(config = {}) {
55
55
// repo_helpers.cjs for consistent slug validation and glob-pattern matching (e.g. "org/*").
56
56
if(isCrossRepoDispatch){
57
57
if(allowedRepos.size===0){
58
-
thrownewError(`E004: Cross-repository dispatch to '${resolvedRepoSlug}' is not permitted. No allowlist is configured. Define 'allowed_repos' to enable cross-repository dispatch.`);
58
+
thrownewError(
59
+
`E004: Cross-repository dispatch to '${resolvedRepoSlug}' is not permitted. No allowlist is configured. Define 'allowed-repos' in the workflow's 'safe-outputs.dispatch-workflow' section to enable cross-repository dispatch.`
# ADR-39080: Accept `allowed-repos` for cross-repo `dispatch-workflow`
2
+
3
+
**Date**: 2026-06-13
4
+
**Status**: Draft
5
+
6
+
## Context
7
+
8
+
The `safe-outputs.dispatch-workflow` feature lets an agent dispatch other workflows, including in a different repository when `target-repo` is set. The JavaScript handler already enforced an allowlist at runtime (error `E004`), expecting an `allowed_repos` config value, but the workflow frontmatter schema and the Go compiler never accepted an `allowed-repos` key. As a result, an author who wrote a valid cross-repo configuration with `allowed-repos` failed at compile time, leaving no supported way to configure cross-repository dispatch end to end. Other cross-repo safe outputs (e.g. `create-code-scanning-alert`, `push-to-pull-request-branch`) already follow a consistent pattern of declaring an `allowed-repos` allowlist in frontmatter that is parsed by the compiler and emitted into the handler config.
9
+
10
+
## Decision
11
+
12
+
We will add `allowed-repos` to the `dispatch-workflow` safe-output as a first-class frontmatter field, wired through the full pipeline so cross-repo dispatch is configurable end to end:
13
+
14
+
- Add `allowed-repos` to the `dispatch-workflow` JSON schema, accepting both an array of `owner/repo` slugs (supporting wildcards such as `org/*`) and a GitHub Actions expression resolving to a comma-separated list.
15
+
- Parse `allowed-repos` into `DispatchWorkflowConfig.AllowedRepos` via the shared `ParseStringArrayFromConfig` helper.
16
+
- Emit it into the runtime handler config as `allowed_repos` using `AddTemplatableStringSlice`, matching the JS handler contract and preserving templated allowlists the same way other cross-repo safe outputs do.
17
+
18
+
We chose to mirror the existing cross-repo safe-output convention rather than invent a new mechanism, so configuration and templating behave identically across all safe outputs. The runtime error message is also tightened to point authors at the `safe-outputs.dispatch-workflow` section instead of an internal config key name.
19
+
20
+
## Alternatives Considered
21
+
22
+
### Alternative 1: Keep runtime-only enforcement, document the limitation
23
+
Leave the schema and compiler unchanged and require users to rely on the runtime check, documenting that cross-repo dispatch could not be statically configured. Rejected because it leaves a valid feature unreachable through supported configuration — any `allowed-repos` config fails to compile — and contradicts the runtime handler that already expects the allowlist.
24
+
25
+
### Alternative 2: Introduce a new, dispatch-specific allowlist key/shape
26
+
Add a bespoke field (e.g. `dispatch-allowlist`) with its own parsing and emission logic specific to `dispatch-workflow`. Rejected because it would diverge from the established `allowed-repos` convention used by other cross-repo safe outputs, duplicating templating logic and increasing cognitive load for authors who already know the existing pattern.
27
+
28
+
## Consequences
29
+
30
+
### Positive
31
+
- Cross-repository `dispatch-workflow` can now be configured end to end (schema → compiler → handler) without compile-time failures.
32
+
- Behavior is consistent with other cross-repo safe outputs, including templated/expression-based allowlists, reducing surprise for authors.
33
+
- Regression tests cover schema acceptance, config parsing, and handler-config emission for the new field.
34
+
35
+
### Negative
36
+
- Adds another surface (schema + parsing + emission) that must stay in sync with the JS handler's `allowed_repos` contract; a future change to one side risks drift.
37
+
- Broadens the configuration surface of a security-sensitive feature (cross-repo dispatch), so the allowlist semantics and wildcard matching must be reviewed carefully.
38
+
39
+
### Neutral
40
+
- The frontmatter key is `allowed-repos` while the emitted handler key is `allowed_repos`; the naming difference follows the existing convention but must be remembered when tracing config through the pipeline.
41
+
- No change to default behavior: omitting `allowed-repos` still blocks cross-repo dispatch via the existing `E004` error.
42
+
43
+
---
44
+
45
+
*This is a DRAFT ADR generated by the [Design Decision Gate](https://github.com/github/gh-aw/actions/runs/27468597143) workflow. The PR author must review, complete, and finalize this document before the PR can merge.*
Copy file name to clipboardExpand all lines: docs/src/content/docs/reference/safe-outputs.md
+3Lines changed: 3 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1218,6 +1218,9 @@ safe-outputs:
1218
1218
1219
1219
- **`workflows`** (required) - List of workflow names (without `.md` extension) that the agent is allowed to dispatch. For same-repo dispatch, each workflow must exist locally and support the `workflow_dispatch` trigger.
1220
1220
- **`max`** (optional) - Maximum number of workflow dispatches allowed (default: 1, maximum: 50). This prevents excessive workflow triggering.
1221
+
- **`target-repo`** (optional) - Target repository in `owner/repo` format for cross-repository dispatch.
1222
+
- **`allowed-repos`** (optional) - Allowlist of cross-repository dispatch targets. Required when `target-repo` points to a different repository. Supports repository slugs and wildcards such as `org/*`, or a GitHub Actions expression string (e.g. `"${{ inputs['allowed-repos'] }}"`) for dynamic allowlists.
1223
+
- **`target-ref`** (optional) - Git ref to dispatch on. In `workflow_call` relay scenarios, the compiler injects this automatically so the dispatch uses the target repository's branch or tag instead of the caller's `GITHUB_REF`.
Copy file name to clipboardExpand all lines: pkg/parser/schemas/main_workflow_schema.json
+16Lines changed: 16 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -9059,6 +9059,22 @@
9059
9059
"type": "string",
9060
9060
"description": "Target repository in format 'owner/repo' for cross-repository workflow dispatch. When specified, the workflow will be dispatched to the target repository instead of the current one."
9061
9061
},
9062
+
"allowed-repos": {
9063
+
"description": "List of repositories in format 'owner/repo' that cross-repository workflow dispatch may target. Supports arrays and GitHub Actions expressions resolving to a comma-separated list (e.g. '${{ inputs['allowed-repos'] }}').",
9064
+
"oneOf": [
9065
+
{
9066
+
"type": "array",
9067
+
"items": {
9068
+
"type": "string"
9069
+
}
9070
+
},
9071
+
{
9072
+
"type": "string",
9073
+
"pattern": "^\\$\\{\\{.*\\}\\}$",
9074
+
"description": "GitHub Actions expression resolving to a comma-separated list of repository slugs (e.g. '${{ inputs['allowed-repos'] }}')"
9075
+
}
9076
+
]
9077
+
},
9062
9078
"target-ref": {
9063
9079
"type": "string",
9064
9080
"description": "Git ref (branch, tag, or SHA) to use when dispatching the workflow. For workflow_call relay scenarios this is auto-injected by the compiler from needs.activation.outputs.target_ref. Overrides the caller's GITHUB_REF."
Copy file name to clipboardExpand all lines: pkg/workflow/dispatch_workflow.go
+2Lines changed: 2 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -13,6 +13,7 @@ type DispatchWorkflowConfig struct {
13
13
WorkflowFilesmap[string]string`yaml:"workflow_files,omitempty"`// Map of workflow name to file extension (.lock.yml or .yml) - populated at compile time
14
14
AwContextWorkflows []string`yaml:"aw_context_workflows,omitempty"`// Workflows that declare aw_context in workflow_dispatch.inputs - populated at compile time
15
15
TargetRepoSlugstring`yaml:"target-repo,omitempty"`// Target repository for cross-repo dispatch (owner/repo or GitHub Actions expression)
16
+
AllowedRepos []string`yaml:"allowed-repos,omitempty"`// Allowlist for cross-repository dispatch targets
16
17
TargetRefstring`yaml:"target-ref,omitempty"`// Target ref for cross-repo dispatch; overrides the caller's GITHUB_REF
0 commit comments