Guard coverage: block all modifying gh repo operations#2806
Conversation
…ive/archive) - Add `unarchive_repository` and `rename_repository` to WRITE_OPERATIONS - Block `archive_repository`, `unarchive_repository`, `rename_repository` in is_blocked_tool() alongside the existing `transfer_repository` entry - Add match arms in tool_rules.rs for the three new blocked operations (repo-visibility secrecy, same pattern as transfer_repository) - Add tests for newly blocked and write-classified operations Agent-Logs-Url: https://github.com/github/gh-aw-mcpg/sessions/844d1229-ef7e-493a-a187-398e882d4f68 Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
gh repo operations
There was a problem hiding this comment.
Pull request overview
This PR closes a guard-policy gap by ensuring all repo-mutating gh repo operations are consistently classified as write operations and unconditionally blocked, aligning behavior across sibling operations (archive/unarchive/rename/transfer).
Changes:
- Extend
WRITE_OPERATIONSandis_blocked_tool()to includearchive_repository,unarchive_repository, andrename_repository. - Add unit tests in
tools.rsto validate blocked + write classification for the new operations. - Update tool-label rules to apply repo-visibility secrecy for the newly blocked repo-modifying tools (matching
transfer_repositorybehavior).
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| guards/github-guard/rust-guard/src/tools.rs | Adds new repo-modifying tool names to write + blocked classification and tests for them. |
| guards/github-guard/rust-guard/src/labels/tool_rules.rs | Applies repo-visibility secrecy for newly blocked repo-modifying operations to keep resource classification consistent. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| pub fn is_blocked_tool(tool_name: &str) -> bool { | ||
| matches!(tool_name, "transfer_repository") | ||
| matches!( | ||
| tool_name, | ||
| "transfer_repository" | "archive_repository" | "unarchive_repository" | "rename_repository" | ||
| ) |
There was a problem hiding this comment.
Consider adding unit tests at the label_resource level (in lib.rs tests) for the newly blocked tools (archive/unarchive/rename), similar to the existing transfer_repository_integrity_is_blocked_after_ensure_baseline test. The current tests here validate is_blocked_tool(), but they don’t exercise the end-to-end blocked-integrity override that actually enforces the policy in runtime.
| // === Modifying Repository Operations (blocked: unsupported gh repo operations) === | ||
| "archive_repository" | "unarchive_repository" | "rename_repository" => { | ||
| // All modifying `gh repo` operations (archive, unarchive, rename) are treated as | ||
| // unsupported for automated agents — the same policy as transfer_repository. | ||
| // Blocking is enforced in label_resource via is_blocked_tool(); this arm applies | ||
| // repo-visibility secrecy so the resource is correctly classified before the | ||
| // integrity override happens in label_resource. | ||
| secrecy = apply_repo_visibility_secrecy(&owner, &repo, repo_id, secrecy, ctx); | ||
| } |
There was a problem hiding this comment.
There are existing apply_tool_labels unit tests for transfer_repository in labels/mod.rs, but none covering this new match arm. Add tests that call apply_tool_labels("archive_repository"|"unarchive_repository"|"rename_repository", …) to verify the secrecy behavior matches transfer_repository (and that the call completes deterministically in cfg(test) without relying on the backend host).
The guard had
archive_repositoryclassified as a write op but not blocked, and was missingrename_repositoryandunarchive_repositoryentirely — creating an asymmetry wheretransfer_repositorywas blocked but its sibling repo-mutating operations were not.Changes
tools.rsunarchive_repositoryandrename_repositorytoWRITE_OPERATIONSis_blocked_tool()to cover all modifyinggh repooperations:labels/tool_rules.rstransfer_repository); integrity blocking is enforced downstream viais_blocked_tool()inlabel_resourceWarning
Firewall rules blocked me from connecting to one or more addresses (expand for details)
I tried to connect to the following addresses, but was blocked by firewall rules:
example.com/tmp/go-build2882961169/b338/launcher.test /tmp/go-build2882961169/b338/launcher.test -test.testlogfile=/tmp/go-build2882961169/b338/testlog.txt -test.paniconexit0 -test.timeout=10m0s guar�� g_.a guard-d6a03f414dc506a0.1b9hao6thgithub.com/tetratelabs/wazero/internal/sys cal/bin/as guard-d6a03f414d/opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linux_amd64/vet ernal/logger/san-unsafeptr=false guard-d6a03f414d-unreachable=false ache/go/1.25.8/x/tmp/go-build2882961169/b098/vet.cfg 9916�� 6r2N21naL ache/go/1.25.8/x64/src/internal/-nolocalimports x_amd64/vet guard-d6a03f414d/opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linux_amd64/vet guard-d6a03f414d-atomic /home/REDACTED/wor-bool x_amd64/vet(dns block)invalid-host-that-does-not-exist-12345.com/tmp/go-build2882961169/b320/config.test /tmp/go-build2882961169/b320/config.test -test.testlogfile=/tmp/go-build2882961169/b320/testlog.txt -test.paniconexit0 -test.timeout=10m0s ortc�� 1.4.1/jsonrpc/jsonrpc.go 64/src/crypto/sha256/sha256.go x_amd64/compile -gnu/lib/librust/opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linux_amd64/vet 9916148/b009/ /home/REDACTED/.ru-unreachable=false x_amd64/compile --no�� 9916148/b147/_pkg_.a /home/REDACTED/.rustup/toolchains/GOAMD64_v1 x_amd64/vet bug/build/serde-/opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linux_amd64/vet guard-d6a03f414d-unsafeptr=false 64-REDACTED-linux-unreachable=false x_amd64/vet(dns block)nonexistent.local/tmp/go-build2882961169/b338/launcher.test /tmp/go-build2882961169/b338/launcher.test -test.testlogfile=/tmp/go-build2882961169/b338/testlog.txt -test.paniconexit0 -test.timeout=10m0s guar�� g_.a guard-d6a03f414dc506a0.1b9hao6thgithub.com/tetratelabs/wazero/internal/sys cal/bin/as guard-d6a03f414d/opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linux_amd64/vet ernal/logger/san-unsafeptr=false guard-d6a03f414d-unreachable=false ache/go/1.25.8/x/tmp/go-build2882961169/b098/vet.cfg 9916�� 6r2N21naL ache/go/1.25.8/x64/src/internal/-nolocalimports x_amd64/vet guard-d6a03f414d/opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linux_amd64/vet guard-d6a03f414d-atomic /home/REDACTED/wor-bool x_amd64/vet(dns block)slow.example.com/tmp/go-build2882961169/b338/launcher.test /tmp/go-build2882961169/b338/launcher.test -test.testlogfile=/tmp/go-build2882961169/b338/testlog.txt -test.paniconexit0 -test.timeout=10m0s guar�� g_.a guard-d6a03f414dc506a0.1b9hao6thgithub.com/tetratelabs/wazero/internal/sys cal/bin/as guard-d6a03f414d/opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linux_amd64/vet ernal/logger/san-unsafeptr=false guard-d6a03f414d-unreachable=false ache/go/1.25.8/x/tmp/go-build2882961169/b098/vet.cfg 9916�� 6r2N21naL ache/go/1.25.8/x64/src/internal/-nolocalimports x_amd64/vet guard-d6a03f414d/opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linux_amd64/vet guard-d6a03f414d-atomic /home/REDACTED/wor-bool x_amd64/vet(dns block)this-host-does-not-exist-12345.com/tmp/go-build2882961169/b347/mcp.test /tmp/go-build2882961169/b347/mcp.test -test.testlogfile=/tmp/go-build2882961169/b347/testlog.txt -test.paniconexit0 -test.timeout=10m0s go_.�� ache/go/1.25.8/x64/src/runtime/cgo ache/go/1.25.8/x64/src/slices/iter.go x_amd64/vet ut-1243131759.c 64-REDACTED-linux-o 64-REDACTED-linux/tmp/go-build2882961169/b331/_pkg_.a x_amd64/vet go_.�� 64/src/net internal/httpcomgithub.com/github/gh-aw-mcpg/internal/guard x_amd64/compile -p weak -lang=go1.25 x_amd64/compile(dns block)If you need me to access, download, or install something from one of these locations, you can either:
🔒 GitHub Advanced Security automatically protects Copilot coding agent pull requests. You can protect all pull requests by enabling Advanced Security for your repositories. Learn more about Advanced Security.