Repository navigation
fix(workflows): allow nested source files and package-registry egress - #1744
Conversation
Two defects found during a live end-to-end run against a real .NET repository. Both compile clean and fail only at agent runtime. allowed-files matched the repository root only. The 40 extension globs were declared bare (`*.cs`, `*.csproj`, `*.java`, ...), and `*` does not cross `/`, so nothing outside the root matched. The supplementary directory globs are all lowercase conventional names, so a repository using top-level project folders -- the default .NET solution layout -- had no file the worker was permitted to change. Observed live: 5 `.csproj`, 3 `.cs`, and one dotfile path all rejected; the run reported success and no pull request appeared. Each extension now has a `**/*.ext` mirror alongside the root form, `Dockerfile*` and `Makefile` gained nested variants, and `*.razor` was added -- it was missing entirely, which blocked Blazor components at any depth. network.allowed granted no package registry. `[defaults]` covers GitHub and certificate infrastructure only, so the agent could not restore dependencies and therefore could not build or test its own work. Observed live: `dotnet restore` took a proxy 403 against api.nuget.org, and the worker correctly reported the task incomplete rather than guessing. Added the ecosystem identifiers containers, dotnet, go, java, node, python, ruby, and rust. Scoped to the worker. `workflows/squad.md` plans and routes rather than restoring packages, so its network surface stays narrow. Closes #1743 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 090e9874-9835-489a-b38d-05a450b3fc53
🟢 Impact Analysis — PR #1744Risk tier: 🟢 LOW 📊 Summary
🎯 Risk Factors
📦 Modules Affectedroot (1 file)
This report is generated automatically for every PR. See #733 for details. |
🛫 PR Readiness Check
PR Scope: 🔧 Infrastructure
|
| Status | Check | Details |
|---|---|---|
| ❌ | Single commit | 2 commits — consider squashing before review |
| ✅ | Not in draft | Ready for review |
| ✅ | Branch up to date | Up to date with dev |
| ❌ | Copilot review | No Copilot review yet — it may still be processing |
| ✅ | Changeset present | No source files changed — changeset not required |
| ✅ | Scope clean | No .squad/ or docs/proposals/ files |
| ✅ | No merge conflicts | No merge conflicts |
| ❌ | Copilot threads resolved | 1 unresolved Copilot thread(s) — fix and resolve before merging |
| ✅ | CI passing | All checks passing |
Files Changed (1 file, +69 −1)
| File | +/− |
|---|---|
workflows/squad-implement-worker.md |
+69 −1 |
Total: +69 −1
This check runs automatically on every push. Fix any ❌ items and push again.
See CONTRIBUTING.md and PR Requirements for details.
There was a problem hiding this comment.
Pull request overview
This PR updates the Squad implement worker workflow configuration to (1) allow edits to source files located in nested directories (common in real-world repo layouts), and (2) grant outbound network egress to language package registries so the worker can restore/build/test during implementation.
Changes:
- Expanded
safe-outputs.create-pull-request.allowed-filesby adding**/*.<ext>mirrors (and nestedDockerfile*/Makefilevariants) plus*.razorto support nested source trees. - Broadened
network.allowedfor the worker to include curated gh-aw ecosystems (e.g.,dotnet,node,python, etc.) for package-registry access.
Show a summary per file
| File | Description |
|---|---|
| workflows/squad-implement-worker.md | Adds package-registry egress and widens the worker’s editable-file allowlist to support nested source layouts. |
Review details
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Suppressed comments (1)
workflows/squad-implement-worker.md:142
- Adding
**/*.yaml/**/*.ymlmakes it possible for the implement worker to modify YAML anywhere, including.github/workflows/, which the workflow instructions explicitly prohibit changing later in this file. If the intent is to keep workflow/agent metadata immutable from the implement worker, consider keeping YAML allowlisted only at the repo root and within the explicitly named directories (e.g.config/**,src/**, etc.).
- "*.yaml"
- "**/*.yaml"
- "*.yml"
- "**/*.yml"
- Files reviewed: 1/1 changed files
- Comments generated: 1
- Review effort level: Lite
| - "*.md" | ||
| - "**/*.md" |
There was a problem hiding this comment.
Agreed, and thanks — this is a real regression I introduced. Before the widening, root-anchored *.md never matched .squad/team.md or .github/workflows/*.md, so the prose rule at L231-232 was backed by a structural guarantee. Adding **/*.md (and **/*.yml, **/*.json) quietly demoted that to instruction-following, on the one workflow that must not be able to rewrite its own definition.
Rather than special-case .github/copilot-instructions.md, fixed in 7251b14 with excluded-files, which strips matching paths from the patch before the commit is created. That restores the structural guarantee for all four forbidden directories while keeping the nested globs this PR exists to add. .github/copilot-instructions.md stays writable because only the named subdirectories are excluded. Verified excluded_files reaches the compiled lock.
…lowlist Adding nested `**/*.md`, `**/*.yml`, and `**/*.json` patterns made paths writable that root-anchored globs had blocked structurally -- among them .github/workflows/, .github/agents/, .github/aw/, and .squad/. The prompt already forbids changing those in prose, but that turned a structural guarantee into instruction-following, and it would let the worker rewrite its own workflow definition or the squad configuration that routes it. excluded-files strips those paths from the patch before the commit is created, restoring the guarantee without narrowing the nested globs that the widening exists to provide. .github/copilot-instructions.md stays writable, since only the four named subdirectories are excluded. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 090e9874-9835-489a-b38d-05a450b3fc53
Closes #1743
Two configuration defects in the implementation worker, both found during a live end-to-end run against a real .NET repository (
bradygaster/aspiregregator-squad-test). Neither is caught by compilation — both compile clean and fail only at agent runtime.A.
allowed-filesmatched the repository root onlyThe allowlist declared its 40 extension globs bare —
*.cs,*.csproj,*.java,*.go. A*does not cross a/, so those patterns match only files sitting at the repository root. The supplementary directory globs are all lowercase conventional names (src/**,lib/**,app/**,api/**, …).The effect: a repository that puts source in top-level project folders — the default .NET solution layout, and common in Java and Go — has no file the worker is permitted to change.
Observed live against
AppHost/ Abstractions/ Grains/ Frontend/ FeedUpdater/ Defaults/. Every file in the worker's patch was rejected — 5.csproj, 3.cs, and.github/copilot-instructions.md. The run reported success. The pull request simply never appeared. That silence is what makes this worth fixing carefully: there is no failure signal to follow.Every extension now carries a
**/*.extmirror alongside the root-level form. Keeping both is deliberate — whether**/matches zero path segments is implementation-defined, and I did not want correctness resting on an assumption I had not verified.Dockerfile*andMakefilegained nested variants for the same reason.*.razorwas absent from the list entirely and has been added; Blazor components were unwritable at any depth, root included.B.
network.allowedgranted no package-registry egress[defaults]covers GitHub and certificate infrastructure, but no language package registry. An implementation agent that cannot restore dependencies cannot build or test what it just wrote.Observed live:
dotnet restoretook a proxy 403 againstapi.nuget.org. The worker behaved correctly — it reported the work incomplete rather than guessing — but it could not finish. gh-aw's compiler emits a recommendation to add thedotnetecosystem in precisely this case, and that recommendation disappears with this change.Added
containers,dotnet,go,java,node,python,ruby,rust.Scoped to the worker only.
workflows/squad.mdplans and routes; it does not restore packages, so its network surface stays narrow. Widening it would trade real attack surface for nothing.Verification
Compiled with real gh-aw (
v0.86.2) and inspected the generated lock rather than trusting the source diff:api.nuget.org,registry.npmjs.org,pypi.org,repo.maven.apache.org,crates.ioin resolved domains**/*.csproj,**/*.razorin resolvedallowed_filesslash_command+bots:insquad.md) — unrelated to this changetest/gh-aw-quality.test.tsThe nested-glob fix is not theoretical: the same widening applied ad hoc during the e2e is what unblocked the run that produced a real modernization pull request (Aspire
9.0.0-rc.1→13.4.6, Orleans →9.2.1, plus a genuine FluentUI Icons breaking-change fix), green on ubuntu, windows, and macOS.Security note
No new secrets, actions, or redirects. The only privilege change is outbound network scope, widened from
defaultstodefaultsplus eight gh-aw-curated package-registry ecosystems. These are gh-aw's own maintained domain sets, not hand-written hosts, and they are read-only package fetches on the workflow that already holdsedit:andbash:. Theallowed-fileschange widens which paths may be written;protected-filesandmax-patch-files: 500are unchanged, so sensitive manifests remain guarded.Out of scope
Found in the same run, deliberately not fixed here:
protected-files: request_reviewlogs that it will proceed with a request-changes review, then hard-refuses the push (Signed-commit payload violates file-protection policy). Soft policy, hard enforcement — this looks like a gh-aw upstream bug and belongs there.slash_command+bots:warning insquad.md.