Skip to content

Require explicit scopes for GitHub App tokens at compile time - #64976

Merged
pelikhan merged 10 commits into
mainfrom
copilot/enforce-app-token-permissions
Oct 2, 2026
Merged

pelikhan merged 10 commits into
mainfrom
copilot/enforce-app-token-permissions

Conversation

Copilot AI commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

Four Squad workflows mint GitHub App tokens without permission inputs, leaving each token with the App installation’s full scope.

  • Compiler guard: Check token-creation steps in all compiled jobs, including imported and generated steps. Missing permission-* inputs fail compilation in strict mode and warn otherwise.
  • Squad scope: Set the shared bootstrap token to permission-contents: read and regenerate the four affected lock files.
  • Guidance: Document the requirement and add regression coverage for scoped and unscoped tokens.
with:
  permission-contents: read

Generated by 👨‍🍳 PR Sous Chef · pi · gpt54 · 24.7 AIC · ⌖ 8.59 AIC · ⊞ 9.2K · ◷
Comment /souschef to run again

Copilot AI and others added 2 commits October 2, 2026 08:22
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 Enforce scoped GitHub App tokens at compile time Require explicit scopes for GitHub App tokens at compile time Oct 2, 2026
Copilot AI requested a review from pelikhan October 2, 2026 08:38
@pelikhan
pelikhan marked this pull request as ready for review October 2, 2026 13:17
Copilot AI balanced review requested due to automatic review settings October 2, 2026 13:17
@github-actions

github-actions Bot commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

✅ PR Code Quality Reviewer completed the code quality review.

🔎 Code quality review by PR Code Quality Reviewer

@github-actions

github-actions Bot commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

✅ Test Quality Sentinel completed test quality analysis.

Test Quality Sentinel skipped because pre-fetch PR data was unavailable: unable to fetch test file diff

🧪 Test quality analysis by Test Quality Sentinel

@github-actions

github-actions Bot commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

✅ Ponytail Reviewer completed successfully!

Warning

Threat Detection Engine Failure — The analysis engine could not complete. This is a tooling failure, not a security finding.

What happened

The threat detection engine failed to produce results.

Review the workflow run logs for details.

Generated by Ponytail Reviewer for #64976

@github-actions

github-actions Bot commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

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

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer

@github-actions

github-actions Bot commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

✅ Design Decision Gate 🏗️ completed the design decision gate check. See the comment below for the result and any generated ADR draft.

🏗️ ADR gate enforced by Design Decision Gate 🏗️

@github-actions

github-actions Bot commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

Comment Memory

reviewed_at: 2026-10-02T13:20:14Z
review_event: COMMENT
top_themes:
  - app-token scope validator misclassifies explicit permission inputs set to none as unscoped
files_reviewed:
  - .github/aw/actions-lock.json
  - .github/workflows/shared/squad.md
  - docs/src/content/docs/reference/steps-jobs.md
  - pkg/workflow/app_token_permissions_validation.go
  - pkg/workflow/app_token_permissions_validation_test.go
  - pkg/workflow/compiler.go
comment_count: 2

Note

This comment is managed by comment memory.

It stores persistent context for this thread in the code block at the top of this comment.
Edit only the text inside the backtick fences; workflow metadata and the footer are regenerated automatically.

Learn more about comment memory

🔎 Code quality review by PR Code Quality Reviewer · copilot · gpt54 · 58.4 AIC · ⌖ 7.2 AIC · ⊞ 19.2K · ◷
Comment /review to run again

@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.

hello

🔎 Code quality review by PR Code Quality Reviewer · copilot · gpt54 · 58.4 AIC · ⌖ 7.2 AIC · ⊞ 19.2K
Comment /review to run again

continue
}
level, ok := value.(string)
if ok && (level == "read" || level == "write") {

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

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This appears to be a placeholder comment and has no actionable finding; no code change was needed.

continue
}
level, ok := value.(string)
if ok && (level == "read" || level == "write") {

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.

This only counts read/write permission inputs as scoped, so permission inputs set to none are wrongly treated as unscoped and can still fail strict mode.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The validator now recognizes none as an explicit permission level, with regression coverage. Updated in 6ac9bf6.

@github-actions

github-actions Bot commented Oct 2, 2026

Copy link
Copy Markdown
Contributor
🏗️ ADR required — draft added for PR #64976

I added a draft ADR at docs/adr/64976-require-explicit-github-app-token-scopes.md because this PR exceeds the default business-logic threshold (152 additions) and introduces an architectural compiler policy.

Evidence used

  • PR summary states the compiler will enforce explicit permission-* inputs for actions/create-github-app-token and scope the shared Squad bootstrap token.
  • pkg/workflow/app_token_permissions_validation.go adds compile-time validation for app-token steps across compiled jobs.
  • pkg/workflow/compiler.go wires that validation into compilation.
  • .github/workflows/shared/squad.md and regenerated lock files show the new least-privilege token scope in compiled workflow output.
  • docs/src/content/docs/reference/steps-jobs.md documents the new authoring requirement.

Next action

Please review the draft ADR, confirm the decision wording and trade-offs, and update it if needed before merge.

🏗️ ADR gate enforced by Design Decision Gate 🏗️ · pi · gpt54 · 32.4 AIC · ⌖ 11.6 AIC · ⊞ 9.9K · ◷
Comment /review to run again

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.

Copilot review overview

🟡 Changes recommended

The guard is bypassable by case variants, mishandles permission inputs, and includes undocumented generated changes.

Review effort: Balanced
Findings: 2 High severity · 3 Medium severity

Open (5)
What changed in this PR

Adds compile-time enforcement for explicitly scoped GitHub App tokens.

Changes:

  • Validates compiled token-creation steps, warning or failing by strict mode.
  • Adds tests and documentation.
  • Scopes Squad bootstrap tokens and refreshes generated workflow artifacts.
File Description
pkg/​workflow/​compiler.go Invokes compiled-token validation.
pkg/​workflow/​app_token_permissions_validation.go Implements permission checks.
pkg/​workflow/​app_token_permissions_validation_test.go Adds regression tests.
docs/​src/​content/​docs/​reference/​steps-jobs.md Documents explicit scopes.
.github/​workflows/​shared/​squad.md Restricts bootstrap token to contents read.
.github/​workflows/​squad.lock.yml Regenerates scoped Squad workflow.
.github/​workflows/​squad-plan.lock.yml Regenerates scoped planning workflow.
.github/​workflows/​squad-implement-worker.lock.yml Regenerates scoped worker workflow.
.github/​workflows/​squad-game-planner.lock.yml Regenerates scoped game-planner workflow.
.github/​workflows/​visual-regression-checker.lock.yml Refreshes unrelated firewall output.
.github/​workflows/​spec-enforcer.lock.yml Refreshes coverage action pin.
.github/​workflows/​purelock.lock.yml Refreshes coverage action pin.
.github/​aw/​actions-lock.json Updates cached action versions.

if !ok {
continue
}
if !strings.HasPrefix(uses, "actions/create-github-app-token@") {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The validator now normalizes the action reference and permission-input key before matching, with case-variant coverage. Updated in 6ac9bf6.

Comment thread pkg/workflow/compiler.go Outdated
// fast-path checks avoid an unnecessary yaml.Unmarshal.
needsSchemaCheck := !c.skipValidation
needsWorkflowParse := needsSchemaCheck || requireSelfHostedRunners
needsAppTokenCheck := strings.Contains(yamlContent, "actions/create-github-app-token@")

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The compiler prefilter now normalizes the compiled YAML before detection, and the validator matches the action reference case-insensitively. Covered by the case-variant compile test in 6ac9bf6.

- name: Upload code coverage report
id: upload_code_coverage
uses: actions/upload-code-coverage@bfa741d815a28cb064a8e3a0837e577457a017d5 # v1.4.3
uses: actions/upload-code-coverage@2b21a77928be8d5168c2b9581a67f2adbebacc52 # v1.4.4

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The current PR diff does not modify purelock.lock.yml; the unrelated coverage-action drift is absent. No lock change was included in 6ac9bf6.

- name: Upload code coverage report
id: upload_code_coverage
uses: actions/upload-code-coverage@bfa741d815a28cb064a8e3a0837e577457a017d5 # v1.4.3
uses: actions/upload-code-coverage@2b21a77928be8d5168c2b9581a67f2adbebacc52 # v1.4.4

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The current PR diff does not modify spec-enforcer.lock.yml; the unrelated coverage-action drift is absent. No lock change was included in 6ac9bf6.

GH_AW_MAX_AI_CREDITS="1000"
fi
printf '%s\n' "{\"\$schema\":\"https://github.com/github/gh-aw-firewall/releases/download/v0.28.31/awf-config.schema.json\",\"network\":{\"allowDomains\":[\"*.grafana.net\",\"*.sentry.io\",\"127.0.0.1\",\"::1\",\"api.npms.io\",\"api.snapcraft.io\",\"archive.ubuntu.com\",\"azure.archive.ubuntu.com\",\"bun.sh\",\"cdn.jsdelivr.net\",\"cdn.playwright.dev\",\"crl.geotrust.com\",\"crl.globalsign.com\",\"crl.identrust.com\",\"crl.sectigo.com\",\"crl.thawte.com\",\"crl.usertrust.com\",\"crl.verisign.com\",\"crl3.digicert.com\",\"crl4.digicert.com\",\"crls.ssl.com\",\"deb.nodesource.com\",\"deno.land\",\"esm.sh\",\"get.pnpm.io\",\"googleapis.deno.dev\",\"googlechromelabs.github.io\",\"json-schema.org\",\"json.schemastore.org\",\"jsr.io\",\"keyserver.ubuntu.com\",\"localhost\",\"nodejs.org\",\"npm.pkg.github.com\",\"npmjs.com\",\"npmjs.org\",\"ocsp.digicert.com\",\"ocsp.geotrust.com\",\"ocsp.globalsign.com\",\"ocsp.identrust.com\",\"ocsp.sectigo.com\",\"ocsp.ssl.com\",\"ocsp.thawte.com\",\"ocsp.usertrust.com\",\"ocsp.verisign.com\",\"packagecloud.io\",\"packages.cloud.google.com\",\"packages.microsoft.com\",\"playwright.download.prss.microsoft.com\",\"ppa.launchpad.net\",\"registry.bower.io\",\"registry.npmjs.com\",\"registry.npmjs.org\",\"registry.yarnpkg.com\",\"repo.yarnpkg.com\",\"s.symcb.com\",\"s.symcd.com\",\"security.ubuntu.com\",\"skimdb.npmjs.com\",\"storage.googleapis.com\",\"telemetry.vercel.com\",\"ts-crl.ws.symantec.com\",\"ts-ocsp.ws.symantec.com\",\"www.googleapis.com\",\"www.npmjs.com\",\"www.npmjs.org\",\"yarnpkg.com\"],\"isolation\":true,\"topologyAttach\":[\"awmg-mcpg\"]},\"apiProxy\":{\"enabled\":true,\"enableTokenSteering\":true,\"maxRuns\":500,\"maxAiCredits\":${GH_AW_MAX_AI_CREDITS},\"maxCacheMisses\":5,\"models\":{\"agent\":[\"sonnet-6x\",\"gpt-6\",\"gpt-5.4\",\"gpt-5.5\",\"gpt-5.6\",\"gpt-5.3\",\"gemini-pro\",\"any\"],\"antigravity\":[\"copilot/antigravity*\",\"google/antigravity*\",\"gemini/antigravity*\"],\"any\":[\"copilot/*\",\"anthropic/*\",\"openai/*\",\"google/*\",\"gemini/*\"],\"auto\":[\"copilot/auto\",\"large\"],\"claude\":[\"agent\"],\"codex\":[\"agent\"],\"coding\":[\"copilot/gpt-5*codex*\",\"openai/gpt-5*codex*\",\"gpt-5-codex\",\"kimi\"],\"computer-use\":[\"copilot/*computer-use*\",\"google/*computer-use*\",\"gemini/*computer-use*\",\"openai/*computer-use*\"],\"copilot\":[\"agent\"],\"deep-research\":[\"copilot/deep-research*\",\"copilot/o3-deep-research*\",\"copilot/o4-mini-deep-research*\",\"google/deep-research*\",\"gemini/deep-research*\",\"openai/o3-deep-research*\",\"openai/o4-mini-deep-research*\"],\"detection\":[\"small\"],\"evals\":[\"small\"],\"fable\":[\"copilot/*fable*\",\"anthropic/*fable*\"],\"gemini\":[\"agent\"],\"gemini-3-flash\":[\"copilot/gemini-3*flash*\",\"google/gemini-3*flash*\",\"gemini/gemini-3*flash*\"],\"gemini-3-pro\":[\"copilot/gemini-3*pro*\",\"google/gemini-3*pro*\",\"google/nano-banana*\",\"gemini/gemini-3*pro*\"],\"gemini-3.1-flash\":[\"copilot/gemini-3.1*flash*\",\"google/gemini-3.1*flash*\",\"gemini/gemini-3.1*flash*\"],\"gemini-3.1-pro\":[\"copilot/gemini-3.1*pro*\",\"google/gemini-3.1*pro*\",\"gemini/gemini-3.1*pro*\"],\"gemini-3.5-flash\":[\"copilot/gemini-3.5*flash*\",\"google/gemini-3.5*flash*\",\"gemini/gemini-3.5*flash*\"],\"gemini-3.6-flash\":[\"copilot/gemini-3.6*flash*\",\"google/gemini-3.6*flash*\",\"gemini/gemini-3.6*flash*\"],\"gemini-3.7-flash\":[\"copilot/gemini-3.7*flash*\",\"google/gemini-3.7*flash*\",\"gemini/gemini-3.7*flash*\"],\"gemini-3.8-flash\":[\"copilot/gemini-3.8*flash*\",\"google/gemini-3.8*flash*\",\"gemini/gemini-3.8*flash*\"],\"gemini-flash\":[\"copilot/gemini-*flash*\",\"google/gemini-*flash*\",\"gemini/gemini-*flash*\"],\"gemini-flash-lite\":[\"copilot/gemini-*flash*lite*\",\"google/gemini-*flash*lite*\",\"gemini/gemini-*flash*lite*\"],\"gemini-omni\":[\"copilot/gemini-omni*\",\"google/gemini-omni*\",\"gemini/gemini-omni*\"],\"gemini-pro\":[\"copilot/gemini-*pro*\",\"google/gemini-*pro*\",\"gemini/gemini-*pro*\"],\"gemma\":[\"copilot/gemma*\",\"google/gemma*\",\"gemini/gemma*\"],\"gpt-5\":[\"copilot/gpt-5*\",\"openai/gpt-5*\"],\"gpt-5-codex\":[\"copilot/gpt-5*codex*\",\"openai/gpt-5*codex*\"],\"gpt-5-mini\":[\"copilot/gpt-5*mini*\",\"openai/gpt-5*mini*\"],\"gpt-5-nano\":[\"copilot/gpt-5*nano*\",\"openai/gpt-5*nano*\"],\"gpt-5-pro\":[\"copilot/gpt-5*pro*\",\"openai/gpt-5*pro*\"],\"gpt-5.1\":[\"copilot/gpt-5.1*\",\"openai/gpt-5.1*\"],\"gpt-5.2\":[\"copilot/gpt-5.2*\",\"openai/gpt-5.2*\"],\"gpt-5.3\":[\"copilot/gpt-5.3*\",\"openai/gpt-5.3*\"],\"gpt-5.4\":[\"copilot/gpt-5.4*\",\"openai/gpt-5.4*\"],\"gpt-5.5\":[\"copilot/gpt-5.5*\",\"openai/gpt-5.5*\"],\"gpt-5.6\":[\"copilot/gpt-5.6*\",\"openai/gpt-5.6*\"],\"gpt-6\":[\"copilot/gpt-6*\",\"openai/gpt-6*\"],\"grok\":[\"copilot/*grok*\",\"openai/*grok*\"],\"haiku\":[\"copilot/*haiku*\",\"anthropic/*haiku*\"],\"image-generation\":[\"copilot/gpt-image*\",\"openai/gpt-image*\",\"openai/chatgpt-image*\",\"copilot/gemini-*image*\",\"google/gemini-*image*\",\"gemini/gemini-*image*\",\"google/imagen*\"],\"kimi\":[\"copilot/kimi*\",\"openai/kimi*\"],\"kiwi\":[\"copilot/kiwi*\",\"openai/kiwi*\"],\"large\":[\"sonnet\",\"gpt-6\",\"gpt-5-pro\",\"gpt-5\",\"gemini-pro\"],\"lyria\":[\"google/lyria*\",\"gemini/lyria*\",\"copilot/lyria*\"],\"mai-code\":[\"copilot/MAI-Code*\",\"copilot/mai-code*\",\"openai/MAI-Code*\"],\"mai-code-1-flash-picker\":[\"copilot/MAI-Code-1-Flash-picker*\",\"copilot/mai-code-1-flash-picker*\",\"openai/MAI-Code-1-Flash-picker*\"],\"mini\":[\"haiku\",\"gpt-5-mini\",\"gpt-5-nano\",\"gemini-flash-lite\"],\"nano-banana\":[\"copilot/nano-banana*\",\"google/nano-banana*\",\"gemini/nano-banana*\"],\"opus\":[\"copilot/*opus*\",\"anthropic/*opus*\"],\"opusplan\":[\"opus?effort=high\"],\"raptor-mini\":[\"copilot/raptor*\",\"openai/raptor*\"],\"reasoning\":[\"copilot/o1*\",\"copilot/o3*\",\"copilot/o4*\",\"openai/o1*\",\"openai/o3*\",\"openai/o4*\"],\"robotics\":[\"copilot/*robotics*\",\"google/*robotics*\",\"gemini/*robotics*\"],\"small\":[\"mini\"],\"small-agent\":[\"haiku\",\"gpt-5-mini\",\"gemini-flash\"],\"sonnet\":[\"copilot/*sonnet*\",\"anthropic/*sonnet*\"],\"sonnet-6x\":[\"copilot/*sonnet-4.5*\",\"copilot/*sonnet-4.6*\",\"copilot/*sonnet-5*\",\"copilot/*sonnet-4-5-*\",\"anthropic/*sonnet-4-5-*\",\"copilot/*sonnet-4-6*\",\"anthropic/*sonnet-4-6*\",\"anthropic/*sonnet-5*\"],\"summarization\":[\"haiku\",\"gpt-5-mini\",\"gemini-flash-lite\",\"mini\"],\"veo\":[\"google/veo*\",\"gemini/veo*\"],\"vision\":[\"copilot/gemini-*image*\",\"google/gemini-*image*\",\"gemini/gemini-*image*\",\"copilot/gemini-*flash*\",\"google/gemini-*flash*\",\"gemini/gemini-*flash*\"]}},\"container\":{\"imageTag\":\"0.28.31,squid=sha256:90a46d2e6e910ace2c09c2dcf6b56dc374ed513d9da642a4e9fcfcd6e9248a9d,agent=sha256:c4ab1d48d533cc7daaa5f2e1193d1a644888242fb8813d49c6de46d129224b76,api-proxy=sha256:a5a37489635109334a5e2b5cb2eaba32e8c8f1a89d8dea6009baa962a8904c4a,cli-proxy=sha256:505df66052e6688cf419ad248a511d17093475bd66a958618078d3c9cdf95083\"},\"logging\":{\"proxyLogsDir\":\"/tmp/gh-aw/sandbox/firewall/logs\",\"auditDir\":\"/tmp/gh-aw/sandbox/firewall/audit\"}}" > "${RUNNER_TEMP}/gh-aw/awf-config.json"
printf '%s\n' "{\"\$schema\":\"https://github.com/github/gh-aw-firewall/releases/download/v0.28.31/awf-config.schema.json\",\"network\":{\"allowDomains\":[\"*.grafana.net\",\"*.sentry.io\",\"127.0.0.1\",\"::1\",\"api.npms.io\",\"api.snapcraft.io\",\"archive.ubuntu.com\",\"azure.archive.ubuntu.com\",\"bun.sh\",\"cdn.jsdelivr.net\",\"cdn.playwright.dev\",\"crl.geotrust.com\",\"crl.globalsign.com\",\"crl.identrust.com\",\"crl.sectigo.com\",\"crl.thawte.com\",\"crl.usertrust.com\",\"crl.verisign.com\",\"crl3.digicert.com\",\"crl4.digicert.com\",\"crls.ssl.com\",\"deb.nodesource.com\",\"deno.land\",\"esm.sh\",\"get.pnpm.io\",\"googleapis.deno.dev\",\"googlechromelabs.github.io\",\"host.docker.internal\",\"json-schema.org\",\"json.schemastore.org\",\"jsr.io\",\"keyserver.ubuntu.com\",\"localhost\",\"nodejs.org\",\"npm.pkg.github.com\",\"npmjs.com\",\"npmjs.org\",\"ocsp.digicert.com\",\"ocsp.geotrust.com\",\"ocsp.globalsign.com\",\"ocsp.identrust.com\",\"ocsp.sectigo.com\",\"ocsp.ssl.com\",\"ocsp.thawte.com\",\"ocsp.usertrust.com\",\"ocsp.verisign.com\",\"packagecloud.io\",\"packages.cloud.google.com\",\"packages.microsoft.com\",\"playwright.download.prss.microsoft.com\",\"ppa.launchpad.net\",\"registry.bower.io\",\"registry.npmjs.com\",\"registry.npmjs.org\",\"registry.yarnpkg.com\",\"repo.yarnpkg.com\",\"s.symcb.com\",\"s.symcd.com\",\"security.ubuntu.com\",\"skimdb.npmjs.com\",\"storage.googleapis.com\",\"telemetry.vercel.com\",\"ts-crl.ws.symantec.com\",\"ts-ocsp.ws.symantec.com\",\"www.googleapis.com\",\"www.npmjs.com\",\"www.npmjs.org\",\"yarnpkg.com\"],\"isolation\":true,\"topologyAttach\":[\"awmg-mcpg\"]},\"apiProxy\":{\"enabled\":true,\"enableTokenSteering\":true,\"maxRuns\":500,\"maxAiCredits\":${GH_AW_MAX_AI_CREDITS},\"maxCacheMisses\":5,\"models\":{\"agent\":[\"sonnet-6x\",\"gpt-6\",\"gpt-5.4\",\"gpt-5.5\",\"gpt-5.6\",\"gpt-5.3\",\"gemini-pro\",\"any\"],\"antigravity\":[\"copilot/antigravity*\",\"google/antigravity*\",\"gemini/antigravity*\"],\"any\":[\"copilot/*\",\"anthropic/*\",\"openai/*\",\"google/*\",\"gemini/*\"],\"auto\":[\"copilot/auto\",\"large\"],\"claude\":[\"agent\"],\"codex\":[\"agent\"],\"coding\":[\"copilot/gpt-5*codex*\",\"openai/gpt-5*codex*\",\"gpt-5-codex\",\"kimi\"],\"computer-use\":[\"copilot/*computer-use*\",\"google/*computer-use*\",\"gemini/*computer-use*\",\"openai/*computer-use*\"],\"copilot\":[\"agent\"],\"deep-research\":[\"copilot/deep-research*\",\"copilot/o3-deep-research*\",\"copilot/o4-mini-deep-research*\",\"google/deep-research*\",\"gemini/deep-research*\",\"openai/o3-deep-research*\",\"openai/o4-mini-deep-research*\"],\"detection\":[\"small\"],\"evals\":[\"small\"],\"fable\":[\"copilot/*fable*\",\"anthropic/*fable*\"],\"gemini\":[\"agent\"],\"gemini-3-flash\":[\"copilot/gemini-3*flash*\",\"google/gemini-3*flash*\",\"gemini/gemini-3*flash*\"],\"gemini-3-pro\":[\"copilot/gemini-3*pro*\",\"google/gemini-3*pro*\",\"google/nano-banana*\",\"gemini/gemini-3*pro*\"],\"gemini-3.1-flash\":[\"copilot/gemini-3.1*flash*\",\"google/gemini-3.1*flash*\",\"gemini/gemini-3.1*flash*\"],\"gemini-3.1-pro\":[\"copilot/gemini-3.1*pro*\",\"google/gemini-3.1*pro*\",\"gemini/gemini-3.1*pro*\"],\"gemini-3.5-flash\":[\"copilot/gemini-3.5*flash*\",\"google/gemini-3.5*flash*\",\"gemini/gemini-3.5*flash*\"],\"gemini-3.6-flash\":[\"copilot/gemini-3.6*flash*\",\"google/gemini-3.6*flash*\",\"gemini/gemini-3.6*flash*\"],\"gemini-3.7-flash\":[\"copilot/gemini-3.7*flash*\",\"google/gemini-3.7*flash*\",\"gemini/gemini-3.7*flash*\"],\"gemini-3.8-flash\":[\"copilot/gemini-3.8*flash*\",\"google/gemini-3.8*flash*\",\"gemini/gemini-3.8*flash*\"],\"gemini-flash\":[\"copilot/gemini-*flash*\",\"google/gemini-*flash*\",\"gemini/gemini-*flash*\"],\"gemini-flash-lite\":[\"copilot/gemini-*flash*lite*\",\"google/gemini-*flash*lite*\",\"gemini/gemini-*flash*lite*\"],\"gemini-omni\":[\"copilot/gemini-omni*\",\"google/gemini-omni*\",\"gemini/gemini-omni*\"],\"gemini-pro\":[\"copilot/gemini-*pro*\",\"google/gemini-*pro*\",\"gemini/gemini-*pro*\"],\"gemma\":[\"copilot/gemma*\",\"google/gemma*\",\"gemini/gemma*\"],\"gpt-5\":[\"copilot/gpt-5*\",\"openai/gpt-5*\"],\"gpt-5-codex\":[\"copilot/gpt-5*codex*\",\"openai/gpt-5*codex*\"],\"gpt-5-mini\":[\"copilot/gpt-5*mini*\",\"openai/gpt-5*mini*\"],\"gpt-5-nano\":[\"copilot/gpt-5*nano*\",\"openai/gpt-5*nano*\"],\"gpt-5-pro\":[\"copilot/gpt-5*pro*\",\"openai/gpt-5*pro*\"],\"gpt-5.1\":[\"copilot/gpt-5.1*\",\"openai/gpt-5.1*\"],\"gpt-5.2\":[\"copilot/gpt-5.2*\",\"openai/gpt-5.2*\"],\"gpt-5.3\":[\"copilot/gpt-5.3*\",\"openai/gpt-5.3*\"],\"gpt-5.4\":[\"copilot/gpt-5.4*\",\"openai/gpt-5.4*\"],\"gpt-5.5\":[\"copilot/gpt-5.5*\",\"openai/gpt-5.5*\"],\"gpt-5.6\":[\"copilot/gpt-5.6*\",\"openai/gpt-5.6*\"],\"gpt-6\":[\"copilot/gpt-6*\",\"openai/gpt-6*\"],\"grok\":[\"copilot/*grok*\",\"openai/*grok*\"],\"haiku\":[\"copilot/*haiku*\",\"anthropic/*haiku*\"],\"image-generation\":[\"copilot/gpt-image*\",\"openai/gpt-image*\",\"openai/chatgpt-image*\",\"copilot/gemini-*image*\",\"google/gemini-*image*\",\"gemini/gemini-*image*\",\"google/imagen*\"],\"kimi\":[\"copilot/kimi*\",\"openai/kimi*\"],\"kiwi\":[\"copilot/kiwi*\",\"openai/kiwi*\"],\"large\":[\"sonnet\",\"gpt-6\",\"gpt-5-pro\",\"gpt-5\",\"gemini-pro\"],\"lyria\":[\"google/lyria*\",\"gemini/lyria*\",\"copilot/lyria*\"],\"mai-code\":[\"copilot/MAI-Code*\",\"copilot/mai-code*\",\"openai/MAI-Code*\"],\"mai-code-1-flash-picker\":[\"copilot/MAI-Code-1-Flash-picker*\",\"copilot/mai-code-1-flash-picker*\",\"openai/MAI-Code-1-Flash-picker*\"],\"mini\":[\"haiku\",\"gpt-5-mini\",\"gpt-5-nano\",\"gemini-flash-lite\"],\"nano-banana\":[\"copilot/nano-banana*\",\"google/nano-banana*\",\"gemini/nano-banana*\"],\"opus\":[\"copilot/*opus*\",\"anthropic/*opus*\"],\"opusplan\":[\"opus?effort=high\"],\"raptor-mini\":[\"copilot/raptor*\",\"openai/raptor*\"],\"reasoning\":[\"copilot/o1*\",\"copilot/o3*\",\"copilot/o4*\",\"openai/o1*\",\"openai/o3*\",\"openai/o4*\"],\"robotics\":[\"copilot/*robotics*\",\"google/*robotics*\",\"gemini/*robotics*\"],\"small\":[\"mini\"],\"small-agent\":[\"haiku\",\"gpt-5-mini\",\"gemini-flash\"],\"sonnet\":[\"copilot/*sonnet*\",\"anthropic/*sonnet*\"],\"sonnet-6x\":[\"copilot/*sonnet-4.5*\",\"copilot/*sonnet-4.6*\",\"copilot/*sonnet-5*\",\"copilot/*sonnet-4-5-*\",\"anthropic/*sonnet-4-5-*\",\"copilot/*sonnet-4-6*\",\"anthropic/*sonnet-4-6*\",\"anthropic/*sonnet-5*\"],\"summarization\":[\"haiku\",\"gpt-5-mini\",\"gemini-flash-lite\",\"mini\"],\"veo\":[\"google/veo*\",\"gemini/veo*\"],\"vision\":[\"copilot/gemini-*image*\",\"google/gemini-*image*\",\"gemini/gemini-*image*\",\"copilot/gemini-*flash*\",\"google/gemini-*flash*\",\"gemini/gemini-*flash*\"]}},\"container\":{\"imageTag\":\"0.28.31,squid=sha256:90a46d2e6e910ace2c09c2dcf6b56dc374ed513d9da642a4e9fcfcd6e9248a9d,agent=sha256:c4ab1d48d533cc7daaa5f2e1193d1a644888242fb8813d49c6de46d129224b76,api-proxy=sha256:a5a37489635109334a5e2b5cb2eaba32e8c8f1a89d8dea6009baa962a8904c4a,cli-proxy=sha256:505df66052e6688cf419ad248a511d17093475bd66a958618078d3c9cdf95083\"},\"logging\":{\"proxyLogsDir\":\"/tmp/gh-aw/sandbox/firewall/logs\",\"auditDir\":\"/tmp/gh-aw/sandbox/firewall/audit\"}}" > "${RUNNER_TEMP}/gh-aw/awf-config.json"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The current PR diff does not modify visual-regression-checker.lock.yml; the unrelated firewall allowlist drift is absent. No lock change was included in 6ac9bf6.

@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 /diagnosing-bugs and /tdd — requesting changes: the new strict-mode validator has an unhandled false-positive path.

📋 Key Themes & Highlights

Key Themes

  • Real regression, not edge case: buildPreActivationAppTokenMintStep (used when github-app is combined with skip-if-match/skip-if-no-match) never emits permission-* inputs, unlike the other two app-token generators (buildActivationAppTokenMintStep, buildDailyAICAppTokenMintStep) which both call convertPermissionsToAppTokenFields. Verified by compiling a minimal repro workflow in this repo (strict mode is enforced here via aw.json): compilation fails with the exact error this PR introduces, for a workflow author who did nothing wrong.
  • Test gap: the new test file covers the warning/strict toggle and a synthetic unscoped job, but never exercises the github-app + skip-if-match combination that triggers the gap above. A regression test here would have caught it.
  • Scope of the fix is good: checking imported/generated steps (not just user-authored ones) is the right call given the four Squad lock files this PR already had to patch — it shows the detection genuinely works on compiler-emitted steps. The gap is that one more compiler-emitted generator wasn't updated to match.

Positive Highlights

  • ✅ The compiler now validates on the compiled YAML rather than the markdown source, catching both imported and generated steps — this is the correct approach and matches the PR description's stated goal.
  • ✅ Docs update in steps-jobs.md is clear and actionable, with a concrete code example.
  • ✅ needsAppTokenCheck short-circuits the YAML parse/validation path when no create-github-app-token usage exists, avoiding unnecessary work on unrelated workflows.

Unrelated note: .github/aw/actions-lock.json also downgrades github/stale-repos and super-linter/super-linter pins — worth confirming that's intentional and not an artifact of a stale rebase/merge.

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · copilot · sonnet50 · 117 AIC · ⌖ 15.8 AIC · ⊞ 10K
Comment /matt to run again

}
}
return nil
}

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.

[/diagnosing-bugs] This new strict-mode check has an untested blind spot: buildPreActivationAppTokenMintStep (pkg/workflow/compiler_pre_activation_job.go) mints an actions/create-github-app-token step for skip-if checks but never emits any permission-* input. Any workflow combining github-app with skip-if-match/skip-if-no-match will now fail compilation in strict mode with this exact validator's error, even though the author did nothing wrong.

💡 Repro
---
on:
  workflow_dispatch:
  skip-if-match: "is:issue is:open label:test"
github-app:
  app-id: ${{ vars.APP_ID }}
  private-key: ${{ secrets.APP_KEY }}
---

Compiling this in this repo (strict mode is enforced via aw.json) fails with:

strict mode: actions/create-github-app-token in job "pre_activation" (Generate GitHub App token for skip-if checks) has no explicit permission-* inputs

buildDailyAICAppTokenMintStep and buildActivationAppTokenMintStep both call convertPermissionsToAppTokenFields to emit scoped permission-* fields, but buildPreActivationAppTokenMintStep doesn't — it's the one generator this PR's validator doesn't account for. Either (a) add a minimal permission-* scope (e.g. the scopes needed for the skip-if search query, likely permission-issues/permission-pull-requests: read) to that step, or (b) add a regression test asserting the compiler still succeeds for a github-app + skip-if-match workflow in strict mode, since none of the current .github/workflows/*.lock.yml files exercise this combination today.

@copilot please address this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The pre-activation skip-if token now receives issues: read and pull-requests: read scopes. A strict-mode compile regression covers github-app with skip-if-match. Updated in 6ac9bf6.

map[string]any{"uses": "actions/create-github-app-token@sha", "with": map[string]any{"private-key": "secret"}},
}},
}}
if err := compiler.validateAppTokenPermissions(workflow, true); err == nil || !strings.Contains(err.Error(), `job "custom"`) {

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] Good coverage of the warning/strict toggle and empty-string edge case, but the test suite only exercises the on.github-app + arbitrary job path and the synthetic validateAppTokenPermissions custom-job case. It never compiles a real github-app + skip-if-match/skip-if-no-match workflow, which is exactly the combination that currently breaks (see the sibling comment on app_token_permissions_validation.go). Adding that case here would have caught the regression before merge.

@copilot please address this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Added a regression test that compiles a strict-mode github-app plus skip-if-match workflow and checks the generated read scopes. Updated in 6ac9bf6.

@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.

Summary

This PR adds a compile-time guard that rejects (strict mode) or warns about any actions/create-github-app-token step lacking an explicit permission-* input. The intent — avoiding fully-scoped installation tokens — is good, but the guard is applied globally to all compiled jobs, including several compiler-generated token-mint steps that currently never set permission-*:

  • buildPreActivationAppTokenMintStep (skip-if checks via on.github-app)
  • generateOTLPOIDCMintStep (observability.otlp.github-app)
  • sideRepoAppTokenMintStepYAML (cross-repo maintenance checkout)

I verified by compiling a minimal workflow with strict: true and observability.otlp.github-app configured — it now fails compilation with no documented way to add a permission-* field for that schema. This is a correctness regression for any workflow using these existing, legitimate features in strict mode (the default), not just the four Squad workflows this PR explicitly fixed.

Test coverage also doesn't exercise these compiler-generated paths — only a hand-authored step in a synthetic workflow.

Details and suggested fixes are in the inline comments.

🧵 Reviewed using Impeccable skills by Impeccable Skills Reviewer · copilot · sonnet50 · 256.2 AIC · ⌖ 13.2 AIC · ⊞ 8.1K

}
}
return nil
}

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.

This new strict-mode gate scans every compiled job for uses: actions/create-github-app-token@... and requires a permission-* field, but several existing compiler-generated token-mint call sites never emit one — so this PR will break those workflows the moment strict mode (the default) is on:

  • buildPreActivationAppTokenMintStep (compiler_pre_activation_job.go:776-815, used for skip-if checks) never appends any permission-* field.
  • generateOTLPOIDCMintStep → buildGitHubAppTokenMintStepWithMeta(app, nil, ...) (compiler_yaml_step_generation.go:150) passes permissions=nil for observability.otlp.github-app.
  • sideRepoAppTokenMintStepYAML (side_repo_maintenance.go:143-152) explicitly passes nil "no additional permission scoping".

I confirmed this by compiling a minimal workflow with strict: true + observability.otlp.github-app:

error: strict mode: actions/create-github-app-token in job "safe_outputs" (Mint OTLP GitHub App token) has no explicit permission-* inputs

This will fail compilation for any existing workflow using OTLP GitHub App auth, skip-if checks with on.github-app, or side-repo maintenance checkout, with no way to set a permission-* input (none of those schemas expose one). Please either:

  1. Skip/allowlist these compiler-generated steps (they're already scoped by the App's installation, not by job permissions), or
  2. Plumb a permission-scoping mechanism through to these call sites before enabling the check in strict mode.

@copilot please address this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Generated tokens now receive explicit scopes: skip-if gets issue/PR read, nil generic tokens default to contents read, head tokens get contents/PR write, and side-repo maintenance gets its required permission union. Regression tests cover these paths. Updated in 6ac9bf6.

if err := compiler.validateAppTokenPermissions(workflow, true); err == nil || !strings.Contains(err.Error(), `job "custom"`) {
t.Fatalf("expected custom job permission error, got %v", err)
}
}

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 regression test only covers a synthetic workflow with a manually-authored create-github-app-token step. It doesn't exercise any of the compiler-generated token-mint paths (pre-activation skip-if token, OTLP App auth, side-repo maintenance, plugin installs) that this change actually affects in production workflows — several of which, as noted in the other comment, don't set permission-* and will now fail strict-mode compilation. Consider adding a test that compiles a workflow using e.g. on.github-app + skip-if-match, or observability.otlp.github-app, to catch this class of regression.

@copilot please address this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Added tests for generated pre-activation, default/app-configured, OTLP, and side-repository token scopes; the existing workflow package tests also pass. Updated in 6ac9bf6.

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot Quick triage nudge: branch refresh was attempted by sous-chef. Please review the current state of this PR and run the pr-finisher skill to move it toward merge readiness.

Generated by 👨🍳 PR Sous Chef

Generated by 👨‍🍳 PR Sous Chef · pi · gpt54 · 23.2 AIC · ⌖ 8.74 AIC · ⊞ 9.7K · ◷
Comment /souschef to run again

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

Copilot AI commented Oct 2, 2026

Copy link
Copy Markdown
Contributor Author

@copilot Quick triage nudge: branch refresh was attempted by sous-chef. Please review the current state of this PR and run the pr-finisher skill to move it toward merge readiness.

Generated by [�...

Ran the requested PR-finisher pass and pushed review fixes in 6ac9bf6. The compiler/token-scope changes and regression tests are in place; local workflow recompilation succeeded. The PR remains blocked and CI needs a maintainer-triggered run.

Copilot AI and others added 2 commits October 2, 2026 14:50
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>

Copilot AI commented Oct 2, 2026

Copy link
Copy Markdown
Contributor Author

@copilot compiler should also require the repositories field (suggest syntax for current repo using expression)

The compiler now requires a non-empty repositories input for every compiled App-token action and suggests repositories: ${{ github.event.repository.name }} to scope it to the current repo. Updated in $(git rev-parse --short HEAD). The docs example and regression tests were updated as well.

@pelikhan

pelikhan commented Oct 2, 2026

Copy link
Copy Markdown
Collaborator

@copilot ensure

repositories: ${{ github.event.repository.name }

Is a best secure practices

Copilot AI and others added 2 commits October 2, 2026 15:08
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>

Copilot AI commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor Author

@copilot ensure

...

github.event.repository.name is not my preferred expression: use repositories: ${{ github.repository }}. The token action accepts the fully qualified owner/repository value, and github.repository is a trusted, stable context that explicitly scopes the token to this repo. Updated the compiler suggestion, docs, and Squad defaults; for a different owner, provide an explicit repository list. Fix pushed in f6d09ff.

@copilot Quick triage nudge: branch refresh was attempted by sous-chef. Please review the current state of this PR and run the pr-finisher skill to move it toward merge readiness.

Generated by [�...

Completed the PR-finisher pass and pushed f6d09ff. Local lint, focused tests, and recompilation passed. The latest CI compile failure is fixed; make test still exposes unrelated stale constants-test expectations, and CI needs a maintainer re-trigger after this push.

@pelikhan

pelikhan commented Oct 2, 2026

Copy link
Copy Markdown
Collaborator

@copilot fix compilation errors in agentic workflows (squad)

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot This PR still needs forward progress. Please address the outstanding blocking review, rerun any needed checks, refresh the branch if appropriate, and finish with the pr-finisher skill.

Generated by 👨‍🍳 PR Sous Chef · pi · gpt54 · 25.3 AIC · ⌖ 8.55 AIC · ⊞ 9.7K · ◷
Comment /souschef to run again

Copilot AI commented Oct 2, 2026

Copy link
Copy Markdown
Contributor Author

@copilot fix compilation errors in agentic workflows (squad)

I couldn't reproduce a Squad compilation error at current HEAD (f6d09ff). make recompile compiled all 301 workflows successfully, including the Squad workflows, and the focused pkg/workflow tests passed. No code change was warranted. The full make test failure is unrelated: pkg/constants expects older Firewall (v0.28.30) and MCP Gateway (v0.4.27) versions than the current constants (v0.28.31 and v0.4.28).

…oken-permissions

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

Copilot AI commented Oct 2, 2026

Copy link
Copy Markdown
Contributor Author

@copilot This PR still needs forward progress. Please address the outstanding blocking review, rerun any needed checks, refresh the branch if appropriate, and finish with the pr-finisher skill.

G...

Merged current main in d3f84e1; the four Squad strict-mode compilation errors on 7108ffb were fixed by f6d09ff. After the merge, make test passed and make recompile compiled all 301 workflows. The PR’s prior review comments already have substantive replies, but GitHub still reports their threads unresolved; I have no thread-resolution operation available here, so a maintainer needs to resolve them. Current-head CI is queued and needs a maintainer re-trigger/verification.

@pelikhan
pelikhan merged commit ffa3933 into main Oct 2, 2026
35 checks passed
@pelikhan
pelikhan deleted the copilot/enforce-app-token-permissions branch October 2, 2026 16:26
@github-actions

github-actions Bot commented Oct 3, 2026

Copy link
Copy Markdown
Contributor

🎉 This pull request is included in a new release.

Release: v0.90.3

github-actions Bot added a commit that referenced this pull request Oct 3, 2026
PR #64976 added compile-time validation requiring manually-authored
actions/create-github-app-token steps to declare explicit repositories
and permission-* inputs (error in strict mode, warning otherwise).
Declarative github-app: blocks already compute these automatically and
are unaffected; syntax-core.md didn't mention the new custom-step
requirement.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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.

4 participants