Skip to content

Allow steps.*.outputs.* in github-token expressions for same-job safe-output auth - #48101

Merged
pelikhan merged 5 commits into
mainfrom
copilot/allow-steps-outputs-github-token
Jul 26, 2026
Merged

Allow steps.*.outputs.* in github-token expressions for same-job safe-output auth#48101
pelikhan merged 5 commits into
mainfrom
copilot/allow-steps-outputs-github-token

Conversation

Copilot AI commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

safe-outputs.github-token accepted secrets.* and needs.*.outputs.*, but rejected same-job steps.*.outputs.*. That blocked short-lived token minting in pre-steps/setup-steps from being wired directly into Process Safe Outputs.

  • Schema update ($defs.github_token)

    • Expanded the token-expression regex in main_workflow_schema.json to accept:
      • secrets.<NAME> (with || fallback chain)
      • needs.<job>.outputs.<name>
      • steps.<id>.outputs.<name> (new)
    • Updated schema description/examples to document same-job step output usage.
  • Runtime/frontmatter validation parity

    • Updated githubTokenExpressionRegexp in pkg/workflow/skills_frontmatter.go to match the same accepted forms, including steps.*.outputs.*.
    • Updated validation error examples accordingly.
  • Focused coverage for accepted pattern

    • Added schema-level test coverage for steps.*.outputs.* in both:
      • safe-outputs.github-token
      • per-output github-token
    • Extended integration tests to accept steps.*.outputs.* in:
      • safe-outputs
      • individual safe-output configs
      • tools.github.github-token
safe-outputs:
  github-token: ${{ steps.fetch_token.outputs.token }}
  create-issue:
    github-token: ${{ steps.fetch_token.outputs.token }}

Generated by 👨‍🍳 PR Sous Chef · gpt54 · 14 AIC · ⌖ 8.18 AIC · ⊞ 7.1K ·
Comment /souschef to run again

Copilot AI and others added 2 commits July 26, 2026 03:32
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Allow steps outputs in safe-outputs.github-token for token minting Allow steps.*.outputs.* in github-token expressions for same-job safe-output auth Jul 26, 2026
Copilot AI requested a review from pelikhan July 26, 2026 03:41
@pelikhan
pelikhan marked this pull request as ready for review July 26, 2026 03:45
Copilot AI review requested due to automatic review settings July 26, 2026 03:45

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Expands GitHub token expressions to support same-job step outputs.

Changes:

  • Allows steps.*.outputs.* token expressions.
  • Adds schema and compilation coverage.
  • Updates workflow routing metadata.
Show a summary per file
File Description
pkg/workflow/skills_frontmatter.go Broadens token validation and error guidance.
pkg/workflow/skills_frontmatter_test.go Tests step-output skill tokens.
pkg/workflow/github_token_validation_test.go Tests affected token configurations.
pkg/parser/schemas/main_workflow_schema.json Expands the token schema.
pkg/parser/schema_test.go Tests schema acceptance.
.github/skills/agentic-workflows/SKILL.md Registers the release workflow prompt.

Review details

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comments suppressed due to low confidence (1)

pkg/parser/schemas/main_workflow_schema.json:13254

  • The new branch rejects valid step/output identifiers containing hyphens, despite the advertised steps.*.outputs.* support. This repository itself emits expressions such as ${{ steps.safe-outputs-app-token.outputs.token }} (pkg/workflow/safe_outputs_env.go:230), so a common producer ID like fetch-token still fails schema validation. Allow - after the first character for both the step ID and output name, and cover that form in the tests.
      "pattern": "^\\$\\{\\{\\s*(secrets\\.[A-Za-z_][A-Za-z0-9_]*(\\s*\\|\\|\\s*secrets\\.[A-Za-z_][A-Za-z0-9_]*)*|needs\\.[A-Za-z_][A-Za-z0-9_]*\\.outputs\\.[A-Za-z_][A-Za-z0-9_]*|steps\\.[A-Za-z_][A-Za-z0-9_]*\\.outputs\\.[A-Za-z_][A-Za-z0-9_]*)\\s*\\}\\}$",
      "description": "GitHub token expression. Accepts a secrets expression (e.g., `${{ secrets.NAME }}` or `${{ secrets.NAME1 || secrets.NAME2 }}`), a cross-job output expression (e.g., `${{ needs.auth.outputs.token }}`), or a same-job step output expression (e.g., `${{ steps.fetch_token.outputs.token }}`). Pattern details: secret names, job IDs, step IDs, and output names in dot notation match `[A-Za-z_][A-Za-z0-9_]*` (identifiers without hyphens).",
  • Files reviewed: 6/6 changed files
  • Comments generated: 2
  • Review effort level: Medium

Comment thread pkg/workflow/skills_frontmatter.go Outdated

var skillSpecRegexp = regexp.MustCompile(`^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+(?:/[A-Za-z0-9_.-]+(?:/[A-Za-z0-9_.-]+)*)?@[0-9a-f]{40}$`)
var githubTokenExpressionRegexp = regexp.MustCompile(`^\$\{\{\s*(secrets\.[A-Za-z_][A-Za-z0-9_]*(\s*\|\|\s*secrets\.[A-Za-z_][A-Za-z0-9_]*)*|needs\.[A-Za-z_][A-Za-z0-9_]*\.outputs\.[A-Za-z_][A-Za-z0-9_]*)\s*\}\}$`)
var githubTokenExpressionRegexp = regexp.MustCompile(`^\$\{\{\s*(secrets\.[A-Za-z_][A-Za-z0-9_]*(\s*\|\|\s*secrets\.[A-Za-z_][A-Za-z0-9_]*)*|needs\.[A-Za-z_][A-Za-z0-9_]*\.outputs\.[A-Za-z_][A-Za-z0-9_]*|steps\.[A-Za-z_][A-Za-z0-9_]*\.outputs\.[A-Za-z_][A-Za-z0-9_]*)\s*\}\}$`)
"pattern": "^\\$\\{\\{\\s*(secrets\\.[A-Za-z_][A-Za-z0-9_]*(\\s*\\|\\|\\s*secrets\\.[A-Za-z_][A-Za-z0-9_]*)*|needs\\.[A-Za-z_][A-Za-z0-9_]*\\.outputs\\.[A-Za-z_][A-Za-z0-9_]*)\\s*\\}\\}$",
"description": "GitHub token expression. Accepts a secrets expression (e.g., `${{ secrets.NAME }}` or `${{ secrets.NAME1 || secrets.NAME2 }}`) or a job output expression (e.g., `${{ needs.auth.outputs.token }}`). Pattern details: secret names match `[A-Za-z_][A-Za-z0-9_]*`; job IDs and output names in dot notation match `[A-Za-z_][A-Za-z0-9_]*` (identifiers without hyphens).",
"examples": ["${{ secrets.GITHUB_TOKEN }}", "${{ secrets.CUSTOM_PAT }}", "${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}", "${{ needs.auth.outputs.token }}"]
"pattern": "^\\$\\{\\{\\s*(secrets\\.[A-Za-z_][A-Za-z0-9_]*(\\s*\\|\\|\\s*secrets\\.[A-Za-z_][A-Za-z0-9_]*)*|needs\\.[A-Za-z_][A-Za-z0-9_]*\\.outputs\\.[A-Za-z_][A-Za-z0-9_]*|steps\\.[A-Za-z_][A-Za-z0-9_]*\\.outputs\\.[A-Za-z_][A-Za-z0-9_]*)\\s*\\}\\}$",
@github-actions

github-actions Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Design Decision Gate 🏗️ completed the design decision gate check.

No ADR enforcement needed: PR #48101 does not have the 'implementation' label and has ≤100 new lines of code in business logic directories (50 additions detected, threshold is 100).

@github-actions

github-actions Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅

@github-actions

github-actions Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Test Quality Sentinel completed test quality analysis.

@github-actions

github-actions Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

PR Code Quality Reviewer completed the code quality review.

@github-actions github-actions Bot mentioned this pull request Jul 26, 2026

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: Allow steps.*.outputs.* in github-token expressions

The change is well-scoped and the implementation is internally consistent — schema regex, Go runtime regexp, tests, and error messages all updated in tandem.

One correctness issue found:

GitHub Actions step IDs allow hyphens (e.g., id: fetch-token), but the new regex segments steps\.[A-Za-z_][A-Za-z0-9_]* and outputs\.[A-Za-z_][A-Za-z0-9_]* only accept underscores. This means ${{ steps.fetch-token.outputs.my-token }} is a valid GitHub expression that will be incorrectly rejected. The fix is to use [A-Za-z_][A-Za-z0-9_-]* for step ID and output name segments (matching the existing needs pattern's same limitation, though both should ideally be fixed).

Pre-existing note (already flagged by prior comments): The skills[].github-token validation shares this same regexp. Skills run in the activation/setup job, not the agent job, so steps.* outputs may not exist in that context — but that's a separate concern already raised in existing review comments.

🧵 Reviewed using Impeccable skills by Impeccable Skills Reviewer · sonnet46 · 19.3 AIC · ⌖ 5.89 AIC · ⊞ 5K

Comment thread pkg/workflow/skills_frontmatter.go Outdated

var skillSpecRegexp = regexp.MustCompile(`^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+(?:/[A-Za-z0-9_.-]+(?:/[A-Za-z0-9_.-]+)*)?@[0-9a-f]{40}$`)
var githubTokenExpressionRegexp = regexp.MustCompile(`^\$\{\{\s*(secrets\.[A-Za-z_][A-Za-z0-9_]*(\s*\|\|\s*secrets\.[A-Za-z_][A-Za-z0-9_]*)*|needs\.[A-Za-z_][A-Za-z0-9_]*\.outputs\.[A-Za-z_][A-Za-z0-9_]*)\s*\}\}$`)
var githubTokenExpressionRegexp = regexp.MustCompile(`^\$\{\{\s*(secrets\.[A-Za-z_][A-Za-z0-9_]*(\s*\|\|\s*secrets\.[A-Za-z_][A-Za-z0-9_]*)*|needs\.[A-Za-z_][A-Za-z0-9_]*\.outputs\.[A-Za-z_][A-Za-z0-9_]*|steps\.[A-Za-z_][A-Za-z0-9_]*\.outputs\.[A-Za-z_][A-Za-z0-9_]*)\s*\}\}$`)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new steps branch of the regex uses [A-Za-z_][A-Za-z0-9_]* for the step ID, which rejects hyphens. GitHub Actions step IDs frequently use hyphens (e.g., id: fetch-token), so ${{ steps.fetch-token.outputs.token }} would fail this validation even though it is a perfectly valid GitHub expression.

Consider using [A-Za-z_][A-Za-z0-9_-]* for the step ID segment — consistent with how GitHub Actions allows hyphens in id: fields. The output name pattern could similarly allow hyphens.

The same fix should be applied to the steps pattern in main_workflow_schema.json line 13253 for consistency.

@copilot please address this.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Skills-Based Review 🧠

Applied /tdd and /grill-with-docs — requesting changes on two correctness issues.

📋 Key Themes & Highlights

Key Themes

  1. Context mismatch on shared regexp: The single githubTokenExpressionRegexp now accepts steps.* in all token-validation contexts, including skills[].github-token. Skills run in the activation job before user pre-steps/setup-steps, so accepting steps.* there will silently validate tokens that can never resolve at runtime.

  2. Hyphenated step IDs rejected: GitHub Actions step IDs may legally contain hyphens (e.g. fetch-token), but the new regex's character class [A-Za-z0-9_]* rejects them. This will cause confusing validation errors for a common naming convention.

Positive Highlights

  • ✅ Clean, minimal change — only the regexp and matching test additions, no structural churn
  • ✅ Good parity maintenance between JSON schema pattern and Go runtime regexp
  • ✅ Tests cover all three usage contexts (safe-outputs, per-output, tools.github)
  • ✅ Updated error message examples are helpful and actionable

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · sonnet46 · 30.1 AIC · ⌖ 4.84 AIC · ⊞ 6.7K
Comment /matt to run again

Comment thread pkg/workflow/skills_frontmatter.go Outdated

var skillSpecRegexp = regexp.MustCompile(`^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+(?:/[A-Za-z0-9_.-]+(?:/[A-Za-z0-9_.-]+)*)?@[0-9a-f]{40}$`)
var githubTokenExpressionRegexp = regexp.MustCompile(`^\$\{\{\s*(secrets\.[A-Za-z_][A-Za-z0-9_]*(\s*\|\|\s*secrets\.[A-Za-z_][A-Za-z0-9_]*)*|needs\.[A-Za-z_][A-Za-z0-9_]*\.outputs\.[A-Za-z_][A-Za-z0-9_]*)\s*\}\}$`)
var githubTokenExpressionRegexp = regexp.MustCompile(`^\$\{\{\s*(secrets\.[A-Za-z_][A-Za-z0-9_]*(\s*\|\|\s*secrets\.[A-Za-z_][A-Za-z0-9_]*)*|needs\.[A-Za-z_][A-Za-z0-9_]*\.outputs\.[A-Za-z_][A-Za-z0-9_]*|steps\.[A-Za-z_][A-Za-z0-9_]*\.outputs\.[A-Za-z_][A-Za-z0-9_]*)\s*\}\}$`)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/tdd] The updated regexp permits steps.* tokens for skills[].github-token, but skills run in the activation job before user pre-steps/setup-steps — so a same-job step output can never be resolved there.

This context mismatch means the new branch in the shared regexp silently accepts an expression that will always fail at runtime for skill installs.

💡 Suggested fix

Split into two regexps:

  • githubTokenExpressionRegexp (safe-outputs / tools) — permits secrets.*, needs.*, steps.*
  • skillsGithubTokenExpressionRegexp (skills[]) — permits only secrets.* and needs.*

This makes each context's validator match its actual runtime capabilities.

@copilot please address this.

"pattern": "^\\$\\{\\{\\s*(secrets\\.[A-Za-z_][A-Za-z0-9_]*(\\s*\\|\\|\\s*secrets\\.[A-Za-z_][A-Za-z0-9_]*)*|needs\\.[A-Za-z_][A-Za-z0-9_]*\\.outputs\\.[A-Za-z_][A-Za-z0-9_]*)\\s*\\}\\}$",
"description": "GitHub token expression. Accepts a secrets expression (e.g., `${{ secrets.NAME }}` or `${{ secrets.NAME1 || secrets.NAME2 }}`) or a job output expression (e.g., `${{ needs.auth.outputs.token }}`). Pattern details: secret names match `[A-Za-z_][A-Za-z0-9_]*`; job IDs and output names in dot notation match `[A-Za-z_][A-Za-z0-9_]*` (identifiers without hyphens).",
"examples": ["${{ secrets.GITHUB_TOKEN }}", "${{ secrets.CUSTOM_PAT }}", "${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}", "${{ needs.auth.outputs.token }}"]
"pattern": "^\\$\\{\\{\\s*(secrets\\.[A-Za-z_][A-Za-z0-9_]*(\\s*\\|\\|\\s*secrets\\.[A-Za-z_][A-Za-z0-9_]*)*|needs\\.[A-Za-z_][A-Za-z0-9_]*\\.outputs\\.[A-Za-z_][A-Za-z0-9_]*|steps\\.[A-Za-z_][A-Za-z0-9_]*\\.outputs\\.[A-Za-z_][A-Za-z0-9_]*)\\s*\\}\\}$",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/grill-with-docs] The shared github_token $defs is referenced by both safe-outputs.github-token and skills[].github-token. Expanding it to include steps.* inadvertently permits same-job step outputs for skill installs, which run in a context where those steps don't exist.

Consider a separate $defs entry (e.g. github_token_safe_outputs) for the safe-output/tools contexts, and keep the skills entry restricted to secrets.*/needs.* only.

@copilot please address this.

Comment thread pkg/workflow/skills_frontmatter.go Outdated

var skillSpecRegexp = regexp.MustCompile(`^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+(?:/[A-Za-z0-9_.-]+(?:/[A-Za-z0-9_.-]+)*)?@[0-9a-f]{40}$`)
var githubTokenExpressionRegexp = regexp.MustCompile(`^\$\{\{\s*(secrets\.[A-Za-z_][A-Za-z0-9_]*(\s*\|\|\s*secrets\.[A-Za-z_][A-Za-z0-9_]*)*|needs\.[A-Za-z_][A-Za-z0-9_]*\.outputs\.[A-Za-z_][A-Za-z0-9_]*)\s*\}\}$`)
var githubTokenExpressionRegexp = regexp.MustCompile(`^\$\{\{\s*(secrets\.[A-Za-z_][A-Za-z0-9_]*(\s*\|\|\s*secrets\.[A-Za-z_][A-Za-z0-9_]*)*|needs\.[A-Za-z_][A-Za-z0-9_]*\.outputs\.[A-Za-z_][A-Za-z0-9_]*|steps\.[A-Za-z_][A-Za-z0-9_]*\.outputs\.[A-Za-z_][A-Za-z0-9_]*)\s*\}\}$`)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/tdd] Step IDs in GitHub Actions can contain hyphens (e.g. fetch-token), but the regexp character class [A-Za-z_][A-Za-z0-9_]* rejects them. A user writing ${{ steps.fetch-token.outputs.token }} will get a cryptic validation error.

💡 Fix

Change the step-ID character class to [A-Za-z_][A-Za-z0-9_-]* in both the Go regexp and the JSON schema pattern to match valid GitHub Actions step IDs.

Add a test case: ${{ steps.fetch-token.outputs.token }} should pass validation.

@copilot please address this.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Test Quality Sentinel: 82/100. 0% implementation tests (threshold: 30%).

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

REQUEST_CHANGES — Two correctness bugs and one schema-design issue must be fixed before merge.

### Blocking issues (3)
  1. Hyphenated step IDs rejected ([A-Za-z_][A-Za-z0-9_]* rejects -). ${{ steps.fetch-token.outputs.token }} — the canonical real-world form — fails validation. The schema description even concedes this but leaves it unfixed. All tests use underscored IDs, so this gap is invisible in CI.

  2. steps.* permitted in skills[].github-token via the shared regexp. Skills run in the activation job where steps.* context doesn't exist; the expression silently resolves to an empty string, producing an auth failure at install time — after schema validation passes.

  3. Shared $defs/github_token in the JSON Schema propagates the steps.* branch to every consumer including skills[].github-token. The definition needs to be split so only same-job consumers (safe-outputs, tools) get the steps.* alternative.

🔎 Code quality review by PR Code Quality Reviewer · sonnet46 · 40.9 AIC · ⌖ 5.02 AIC · ⊞ 5.7K
Comment /review to run again

Comment thread pkg/workflow/skills_frontmatter.go Outdated

var skillSpecRegexp = regexp.MustCompile(`^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+(?:/[A-Za-z0-9_.-]+(?:/[A-Za-z0-9_.-]+)*)?@[0-9a-f]{40}$`)
var githubTokenExpressionRegexp = regexp.MustCompile(`^\$\{\{\s*(secrets\.[A-Za-z_][A-Za-z0-9_]*(\s*\|\|\s*secrets\.[A-Za-z_][A-Za-z0-9_]*)*|needs\.[A-Za-z_][A-Za-z0-9_]*\.outputs\.[A-Za-z_][A-Za-z0-9_]*)\s*\}\}$`)
var githubTokenExpressionRegexp = regexp.MustCompile(`^\$\{\{\s*(secrets\.[A-Za-z_][A-Za-z0-9_]*(\s*\|\|\s*secrets\.[A-Za-z_][A-Za-z0-9_]*)*|needs\.[A-Za-z_][A-Za-z0-9_]*\.outputs\.[A-Za-z_][A-Za-z0-9_]*|steps\.[A-Za-z_][A-Za-z0-9_]*\.outputs\.[A-Za-z_][A-Za-z0-9_]*)\s*\}\}$`)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

steps.* context is invalid for skills[].github-token — this regex change silently allows a pattern that will produce an empty token at runtime.

💡 Details and suggested fix

githubTokenExpressionRegexp is used to validate skills[].github-token (around line 95). Skills are installed in the activation job, which is a separate job from the agent job. The steps.* context map is only populated within the same job, so ${{ steps.fetch_token.outputs.token }} in skills[].github-token will resolve to an empty string at runtime — passing regex validation but then failing silently at install time.

The steps.* branch should only be permitted in contexts where the referencing field and the step producing the token are in the same job (e.g., safe-outputs.github-token, tools.github.github-token). Consider splitting $defs/github_token into two variants:

  • github_token — secrets + needs (for cross-job contexts like skills)
  • github_token_same_job — secrets + needs + steps (for safe-outputs and tools)

This avoids giving users a false-green at schema-validation time.

Comment thread pkg/workflow/skills_frontmatter.go Outdated

var skillSpecRegexp = regexp.MustCompile(`^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+(?:/[A-Za-z0-9_.-]+(?:/[A-Za-z0-9_.-]+)*)?@[0-9a-f]{40}$`)
var githubTokenExpressionRegexp = regexp.MustCompile(`^\$\{\{\s*(secrets\.[A-Za-z_][A-Za-z0-9_]*(\s*\|\|\s*secrets\.[A-Za-z_][A-Za-z0-9_]*)*|needs\.[A-Za-z_][A-Za-z0-9_]*\.outputs\.[A-Za-z_][A-Za-z0-9_]*)\s*\}\}$`)
var githubTokenExpressionRegexp = regexp.MustCompile(`^\$\{\{\s*(secrets\.[A-Za-z_][A-Za-z0-9_]*(\s*\|\|\s*secrets\.[A-Za-z_][A-Za-z0-9_]*)*|needs\.[A-Za-z_][A-Za-z0-9_]*\.outputs\.[A-Za-z_][A-Za-z0-9_]*|steps\.[A-Za-z_][A-Za-z0-9_]*\.outputs\.[A-Za-z_][A-Za-z0-9_]*)\s*\}\}$`)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regex rejects hyphenated step IDs, blocking the primary use case this PR adds${{ steps.fetch-token.outputs.token }} will fail validation.

💡 Details and suggested fix

GitHub Actions allows hyphens in step IDs. The step-ID segment of the new pattern, [A-Za-z_][A-Za-z0-9_]*, rejects hyphens. Users who write:

- id: fetch-token
  uses: ...

and then reference ${{ steps.fetch-token.outputs.token }} will get a validation error despite the expression being valid in GitHub Actions. The schema description even notes this limitation ("identifiers without hyphens"), acknowledging it's a gap rather than fixing it.

Fix the character class to allow hyphens in the middle of identifiers:

// Before:
steps\.[A-Za-z_][A-Za-z0-9_]*\.outputs\.[A-Za-z_][A-Za-z0-9_]*
// After (step ID and output name can contain hyphens):
steps\.[A-Za-z_][A-Za-z0-9_-]*\.outputs\.[A-Za-z_][A-Za-z0-9_-]*

Same fix is needed in the JSON Schema pattern field in main_workflow_schema.json.

Add a test case with a hyphenated step ID to prevent regression.

"pattern": "^\\$\\{\\{\\s*(secrets\\.[A-Za-z_][A-Za-z0-9_]*(\\s*\\|\\|\\s*secrets\\.[A-Za-z_][A-Za-z0-9_]*)*|needs\\.[A-Za-z_][A-Za-z0-9_]*\\.outputs\\.[A-Za-z_][A-Za-z0-9_]*)\\s*\\}\\}$",
"description": "GitHub token expression. Accepts a secrets expression (e.g., `${{ secrets.NAME }}` or `${{ secrets.NAME1 || secrets.NAME2 }}`) or a job output expression (e.g., `${{ needs.auth.outputs.token }}`). Pattern details: secret names match `[A-Za-z_][A-Za-z0-9_]*`; job IDs and output names in dot notation match `[A-Za-z_][A-Za-z0-9_]*` (identifiers without hyphens).",
"examples": ["${{ secrets.GITHUB_TOKEN }}", "${{ secrets.CUSTOM_PAT }}", "${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}", "${{ needs.auth.outputs.token }}"]
"pattern": "^\\$\\{\\{\\s*(secrets\\.[A-Za-z_][A-Za-z0-9_]*(\\s*\\|\\|\\s*secrets\\.[A-Za-z_][A-Za-z0-9_]*)*|needs\\.[A-Za-z_][A-Za-z0-9_]*\\.outputs\\.[A-Za-z_][A-Za-z0-9_]*|steps\\.[A-Za-z_][A-Za-z0-9_]*\\.outputs\\.[A-Za-z_][A-Za-z0-9_]*)\\s*\\}\\}$",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shared $defs/github_token now allows steps.* everywhere it is referenced, including contexts where steps context is unavailable — schema validation will pass for skills[].github-token: ${{ steps.foo.outputs.bar }} even though that will always resolve to an empty string at runtime.

💡 Details and suggested fix

$defs/github_token is reused by:

  • skills[].github-token (activation job — no steps.* context)
  • tools.github.github-token (agent job — steps.* available)
  • safe-outputs.github-token (agent job — steps.* available)
  • Per-output github-token fields (agent job — steps.* available)

Allowing steps.* in the shared definition means users who mistakenly write steps.* in skills[].github-token will get a clean schema validation pass, then a silent runtime auth failure during skill installation.

Split the definition:

"github_token": { "pattern": "...secrets...|...needs..." },
"github_token_same_job": { "pattern": "...secrets...|...needs...|...steps..." }

Then use github_token_same_job only in safe-outputs and tools.github refs.

@github-actions

Copy link
Copy Markdown
Contributor

🤖 PR Triage — §30192186368

Field Value
Category feature
Risk 🟡 medium
Score 74 / 100 (impact 35 + urgency 23 + quality 16)
Action ⚡ fast_track

Why: Extends github-token expression allowlist to accept steps.*.outputs.*. CI passing (full suite green). Mixed review (CHANGES_REQUESTED then APPROVED). Schema + integration test coverage included.

Next: Confirm latest review state is APPROVED, then fast-track merge.

Generated by 🔧 PR Triage Agent · sonnet46 · 48.8 AIC · ⌖ 8.75 AIC · ⊞ 5.7K ·

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot please run the pr-finisher skill, address the unresolved review feedback and failed checks below, and rerun checks once the branch is up to date.

Unresolved review feedback:

Failed checks:

Generated by 👨‍🍳 PR Sous Chef · gpt54 · 14 AIC · ⌖ 8.18 AIC · ⊞ 7.1K ·
Comment /souschef to run again

Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>

Copilot AI commented Jul 26, 2026

Copy link
Copy Markdown
Contributor Author

@copilot please run the pr-finisher skill, address the unresolved review feedback and failed checks below, and rerun checks once the branch is up to date.

Unresolved review feedback:...

Addressed in 5026560. skills[].github-token is restricted back to activation-safe secrets.* / needs.*.outputs.*, same-job consumers now use a separate schema path that still allows steps.*.outputs.*, and the same-job pattern now accepts hyphenated step/output names. I also checked the cited failed test jobs locally: the previously failing TestFallbackAWFilesMatchesLocalAWDirectory now passes on this branch, so those CI failures were stale. Since agent pushes do not retrigger workflows, a maintainer still needs to rerun CI on the updated head.

Copilot AI requested a review from gh-aw-bot July 26, 2026 08:55
@pelikhan
pelikhan merged commit 2c8d5f1 into main Jul 26, 2026
23 checks passed
@pelikhan
pelikhan deleted the copilot/allow-steps-outputs-github-token branch July 26, 2026 09:22
@github-actions

Copy link
Copy Markdown
Contributor

🎉 This pull request is included in a new release.

Release: v0.83.4

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Allow ${{ steps.*.outputs.* }} in safe-outputs.github-token for same-job token minting

4 participants