Problems
Three separate but related problems arise when features: copilot-requests: true is used.
Problem 1: create-agent-session still requires COPILOT_GITHUB_TOKEN
The intent of features: copilot-requests: true is to eliminate the need for the COPILOT_GITHUB_TOKEN PAT secret by using the built-in ${{ github.token }} (which gets the copilot-requests: write permission injected automatically). However, the create-agent-session safe output is not covered by this substitution.
Affected component
The create-agent-session safe output uses UseCopilotRequestsToken: true, which routes through getEffectiveCopilotRequestsToken() in pkg/workflow/github_token.go. That function's fallback chain is:
1. Custom github-token field (if set)
2. secrets.COPILOT_GITHUB_TOKEN
(no further fallback)
It has no awareness of the copilot-requests feature flag and never substitutes ${{ github.token }}. If the user omits COPILOT_GITHUB_TOKEN (which is the whole point of using the feature flag), the create-agent-session step will receive an empty token and fail at runtime.
Additionally, the safe-outputs job does not receive copilot-requests: write permission — it only gets contents: read + issues: write (from ComputePermissionsForSafeOutputs() in pkg/workflow/safe_outputs_permissions.go). Even if the token substitution were fixed, the job permission would also need to be updated.
Not affected
The GitHub MCP server is not affected. Its token chain is:
secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN
GITHUB_TOKEN is always automatically provided by GitHub Actions and does not require a PAT. The MCP server will work without any user-configured secrets.
Current state
# Compiled safe-outputs step — always uses COPILOT_GITHUB_TOKEN regardless of feature flag
- name: Create Agent Session
uses: actions/github-script@...
with:
github-token: ${{ secrets.COPILOT_GITHUB_TOKEN }} # ← hardcoded, fails if secret absent
script: |
...
Desired state
When features: copilot-requests: true is set, the create-agent-session step should use ${{ github.token }} instead of secrets.COPILOT_GITHUB_TOKEN, and the safe-outputs job permissions should include copilot-requests: write.
Solution
-
Thread copilot-requests awareness into getEffectiveCopilotRequestsToken() — or add a new getEffectiveCopilotRequestsTokenForFeature(useCopilotRequests bool, customToken string) string that substitutes ${{ github.token }} when the flag is active.
-
Pass copilot-requests flag into the safe-outputs job permission computation — in ComputePermissionsForSafeOutputs(), when copilot-requests is enabled and create-agent-session is present, merge copilot-requests: write into the safe-outputs job permissions.
-
Update buildCreateAgentSessionStepConfig() in pkg/workflow/compiler_safe_outputs_specialized.go to accept and pass the useCopilotRequests boolean so the correct token is selected.
Problem 2: Agent job using github.token fails if it runs longer than ~1 hour
The Copilot API creates a server-side session when the agent starts. That session is bound to the token presented at session creation. The ${{ github.token }} value is baked into the step's environment at the moment the step starts — it is never refreshed during the step.
If the Copilot API session expires (approximately 1 hour), all subsequent tool calls and inference requests will fail mid-run with authentication errors. The agent job will appear to be running but will be unable to make any progress.
Why the detection job is not affected
The threat-detection job also receives copilot-requests: write and runs the Copilot CLI, but it completes in under 1 minute. It is a one-shot classification pass, not an interactive agent session. The 1-hour expiry is irrelevant for it.
Current state
# Schema allows any positive integer — no upper bound enforced
timeout-minutes: 120 # user sets this; schema only requires minimum: 1
# Compiled agent step — token baked in, never refreshed
- name: Execute GitHub Copilot CLI
timeout-minutes: 120
env:
COPILOT_GITHUB_TOKEN: ${{ github.token }} # ← expires ~1h after workflow start
S2STOKENS: "true"
...
Desired state
Users should be warned (or blocked at compile time) if they set timeout-minutes > 60 while features: copilot-requests: true is enabled, since the combination is likely to produce silent mid-run failures.
Solution
In pkg/workflow/copilot_engine_execution.go, after detecting useCopilotRequests, check the configured timeout and emit a compile-time warning:
if useCopilotRequests && workflowData.TimeoutMinutes != "" {
timeoutVal := parseTimeoutMinutesInt(workflowData.TimeoutMinutes)
if timeoutVal > 60 {
fmt.Fprintln(os.Stderr, console.FormatWarningMessage(
"features: copilot-requests: true with timeout-minutes > 60 may cause mid-run " +
"authentication failures: the github.token Copilot session expires after ~1 hour. " +
"Set timeout-minutes ≤ 60 or configure COPILOT_GITHUB_TOKEN as a PAT instead."))
}
}
This is a low-risk, high-value change that surfaces the failure mode to the user at gh aw compile time rather than mid-run.
Problem 3: Schema allows timeout-minutes values that exceed GitHub Actions limits
The compiled agent step receives the user-configured timeout-minutes directly. The JSON schema only enforces minimum: 1 with no upper bound. GitHub-hosted runners have a hard limit of 6 hours (360 minutes) per job. Any value above this will cause the job to fail immediately at startup with a GitHub Actions configuration error.
Current state
// pkg/parser/schemas/main_workflow_schema.json
"timeout-minutes": {
"type": "integer",
"minimum": 1
// no maximum
}
# A user can write this and it compiles fine, but will fail at runtime
timeout-minutes: 500
Desired state
The schema should enforce a maximum of 360 (6 hours) to match the GitHub-hosted runner limit. This prevents users from compiling workflows that are guaranteed to fail at runtime due to the Actions platform constraint.
Note on self-hosted runners: Self-hosted runners technically support up to 35 days, but this is not a practical limit for agentic workflows. The 360-minute cap is the appropriate guard rail for typical use and matches the GitHub platform default.
Solution
Update pkg/parser/schemas/main_workflow_schema.json to add "maximum": 360 to the timeout-minutes integer schema:
"timeout-minutes": {
"description": "Workflow timeout in minutes (GitHub Actions standard field). Defaults to 20 minutes for agentic workflows. Maximum is 360 minutes (6 hours) for GitHub-hosted runners.",
"oneOf": [
{
"type": "integer",
"minimum": 1,
"maximum": 360,
"examples": [5, 10, 30]
},
{
"type": "string",
"pattern": "^\\$\\{\\{.*\\}\\}$",
"description": "GitHub Actions expression that resolves to an integer (e.g. '${{ inputs.timeout }}')"
}
]
}
After changing the schema, run make build to rebuild the binary (schema files are embedded via //go:embed) and make recompile to recompile all workflow lock files.
Summary Table
| # |
Problem |
Component |
Fix |
| 1 |
create-agent-session ignores copilot-requests: true, still requires COPILOT_GITHUB_TOKEN PAT; safe-outputs job also missing copilot-requests: write permission |
compiler_safe_outputs_specialized.go, safe_outputs_permissions.go, github_token.go |
Propagate feature flag into token selection and permission computation |
| 2 |
Agent step with timeout-minutes > 60 + copilot-requests: true silently fails after ~1 hour |
copilot_engine_execution.go |
Emit compile-time warning when timeout exceeds session lifetime |
| 3 |
Schema allows timeout-minutes > 360, which GitHub-hosted runners reject at runtime |
pkg/parser/schemas/main_workflow_schema.json |
Add maximum: 360 to the schema |
Problems
Three separate but related problems arise when
features: copilot-requests: trueis used.Problem 1:
create-agent-sessionstill requiresCOPILOT_GITHUB_TOKENThe intent of
features: copilot-requests: trueis to eliminate the need for theCOPILOT_GITHUB_TOKENPAT secret by using the built-in${{ github.token }}(which gets thecopilot-requests: writepermission injected automatically). However, thecreate-agent-sessionsafe output is not covered by this substitution.Affected component
The
create-agent-sessionsafe output usesUseCopilotRequestsToken: true, which routes throughgetEffectiveCopilotRequestsToken()inpkg/workflow/github_token.go. That function's fallback chain is:It has no awareness of the
copilot-requestsfeature flag and never substitutes${{ github.token }}. If the user omitsCOPILOT_GITHUB_TOKEN(which is the whole point of using the feature flag), thecreate-agent-sessionstep will receive an empty token and fail at runtime.Additionally, the safe-outputs job does not receive
copilot-requests: writepermission — it only getscontents: read+issues: write(fromComputePermissionsForSafeOutputs()inpkg/workflow/safe_outputs_permissions.go). Even if the token substitution were fixed, the job permission would also need to be updated.Not affected
The GitHub MCP server is not affected. Its token chain is:
GITHUB_TOKENis always automatically provided by GitHub Actions and does not require a PAT. The MCP server will work without any user-configured secrets.Current state
Desired state
When
features: copilot-requests: trueis set, thecreate-agent-sessionstep should use${{ github.token }}instead ofsecrets.COPILOT_GITHUB_TOKEN, and the safe-outputs job permissions should includecopilot-requests: write.Solution
Thread
copilot-requestsawareness intogetEffectiveCopilotRequestsToken()— or add a newgetEffectiveCopilotRequestsTokenForFeature(useCopilotRequests bool, customToken string) stringthat substitutes${{ github.token }}when the flag is active.Pass
copilot-requestsflag into the safe-outputs job permission computation — inComputePermissionsForSafeOutputs(), whencopilot-requestsis enabled andcreate-agent-sessionis present, mergecopilot-requests: writeinto the safe-outputs job permissions.Update
buildCreateAgentSessionStepConfig()inpkg/workflow/compiler_safe_outputs_specialized.goto accept and pass theuseCopilotRequestsboolean so the correct token is selected.Problem 2: Agent job using
github.tokenfails if it runs longer than ~1 hourThe Copilot API creates a server-side session when the agent starts. That session is bound to the token presented at session creation. The
${{ github.token }}value is baked into the step's environment at the moment the step starts — it is never refreshed during the step.If the Copilot API session expires (approximately 1 hour), all subsequent tool calls and inference requests will fail mid-run with authentication errors. The agent job will appear to be running but will be unable to make any progress.
Why the detection job is not affected
The threat-detection job also receives
copilot-requests: writeand runs the Copilot CLI, but it completes in under 1 minute. It is a one-shot classification pass, not an interactive agent session. The 1-hour expiry is irrelevant for it.Current state
Desired state
Users should be warned (or blocked at compile time) if they set
timeout-minutes > 60whilefeatures: copilot-requests: trueis enabled, since the combination is likely to produce silent mid-run failures.Solution
In
pkg/workflow/copilot_engine_execution.go, after detectinguseCopilotRequests, check the configured timeout and emit a compile-time warning:This is a low-risk, high-value change that surfaces the failure mode to the user at
gh aw compiletime rather than mid-run.Problem 3: Schema allows
timeout-minutesvalues that exceed GitHub Actions limitsThe compiled agent step receives the user-configured
timeout-minutesdirectly. The JSON schema only enforcesminimum: 1with no upper bound. GitHub-hosted runners have a hard limit of 6 hours (360 minutes) per job. Any value above this will cause the job to fail immediately at startup with a GitHub Actions configuration error.Current state
Desired state
The schema should enforce a maximum of
360(6 hours) to match the GitHub-hosted runner limit. This prevents users from compiling workflows that are guaranteed to fail at runtime due to the Actions platform constraint.Solution
Update
pkg/parser/schemas/main_workflow_schema.jsonto add"maximum": 360to thetimeout-minutesinteger schema:After changing the schema, run
make buildto rebuild the binary (schema files are embedded via//go:embed) andmake recompileto recompile all workflow lock files.Summary Table
create-agent-sessionignorescopilot-requests: true, still requiresCOPILOT_GITHUB_TOKENPAT; safe-outputs job also missingcopilot-requests: writepermissioncompiler_safe_outputs_specialized.go,safe_outputs_permissions.go,github_token.gotimeout-minutes > 60+copilot-requests: truesilently fails after ~1 hourcopilot_engine_execution.gotimeout-minutes> 360, which GitHub-hosted runners reject at runtimepkg/parser/schemas/main_workflow_schema.jsonmaximum: 360to the schema