Skip to content

Commit 893fa02

Browse files
authored
Guard coverage: classify create_agent_task as read-write and blocked (#3139)
`gh agent-task create` (`POST copilot-api/agents/swe/v1/jobs/{owner}/{repo}`) had no guard entry despite causing real repo mutations (branch creation + PR). Per agent instructions, this operation is read-write (reads task context, writes branch/PR) and unsupported (unconditionally blocked). ### `tools.rs` - Added `"create_agent_task"` to `READ_WRITE_OPERATIONS` — operation is classified as `"read-write"` in `label_resource` - Added `"create_agent_task"` to `is_blocked_tool()` — DIFC evaluator always denies it via `blocked_integrity` override, consistent with `transfer_repository`, `archive_repository`, etc. ### `labels/tool_rules.rs` - Added match arm for `create_agent_task` applying repo-visibility secrecy before the `blocked_integrity` override kicks in at `label_resource` ```rust // tools.rs pub const READ_WRITE_OPERATIONS: &[&str] = &[ // ...existing entries... "create_agent_task", // gh agent-task create — blocked: unsupported agent operation ]; pub fn is_blocked_tool(tool_name: &str) -> bool { matches!( tool_name, "transfer_repository" | "archive_repository" | "unarchive_repository" | "rename_repository" | "create_agent_task" ) } ``` > [!WARNING] > > <details> > <summary>Firewall rules blocked me from connecting to one or more addresses (expand for details)</summary> > > #### I tried to connect to the following addresses, but was blocked by firewall rules: > > - `example.com` > - Triggering command: `/tmp/go-build2534278610/b340/launcher.test /tmp/go-build2534278610/b340/launcher.test -test.testlogfile=/tmp/go-build2534278610/b340/testlog.txt -test.paniconexit0 -test.timeout=10m0s /tmp/go-build2534278610/b223/vet.cfg flib/difflib.go 64/src/runtime/cgo x_amd64/compile` (dns block) > - `invalid-host-that-does-not-exist-12345.com` > - Triggering command: `/tmp/go-build2534278610/b322/config.test /tmp/go-build2534278610/b322/config.test -test.testlogfile=/tmp/go-build2534278610/b322/testlog.txt -test.paniconexit0 -test.timeout=10m0s rev-�� ternal/engine/wazevo/backend/isa/amd64/abi_entry_amd64.s` (dns block) > - `nonexistent.local` > - Triggering command: `/tmp/go-build2534278610/b340/launcher.test /tmp/go-build2534278610/b340/launcher.test -test.testlogfile=/tmp/go-build2534278610/b340/testlog.txt -test.paniconexit0 -test.timeout=10m0s /tmp/go-build2534278610/b223/vet.cfg flib/difflib.go 64/src/runtime/cgo x_amd64/compile` (dns block) > - `slow.example.com` > - Triggering command: `/tmp/go-build2534278610/b340/launcher.test /tmp/go-build2534278610/b340/launcher.test -test.testlogfile=/tmp/go-build2534278610/b340/testlog.txt -test.paniconexit0 -test.timeout=10m0s /tmp/go-build2534278610/b223/vet.cfg flib/difflib.go 64/src/runtime/cgo x_amd64/compile` (dns block) > - `this-host-does-not-exist-12345.com` > - Triggering command: `/tmp/go-build2534278610/b349/mcp.test /tmp/go-build2534278610/b349/mcp.test -test.testlogfile=/tmp/go-build2534278610/b349/testlog.txt -test.paniconexit0 -test.timeout=10m0s go_.�� @v1.1.3/ascii/eq-errorsas @v1.1.3/ascii/va-ifaceassert x_amd64/vet -I /tmp/go-build132/usr/bin/runc -I x_amd64/vet -I g_.a 0098554/b151/ x_amd64/vet -o /dev/null` (dns block) > > If you need me to access, download, or install something from one of these locations, you can either: > > - Configure [Actions setup steps](https://gh.io/copilot/actions-setup-steps) to set up my environment, which run before the firewall is enabled > - Add the appropriate URLs or hosts to the custom allowlist in this repository's [Copilot coding agent settings](https://github.com/github/gh-aw-mcpg/settings/copilot/coding_agent) (admins only) > > </details>
2 parents 19ad536 + 44a4fc3 commit 893fa02

2 files changed

Lines changed: 35 additions & 1 deletion

File tree

guards/github-guard/rust-guard/src/labels/tool_rules.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -627,6 +627,15 @@ pub fn apply_tool_labels(
627627
integrity = writer_integrity(repo_id, ctx);
628628
}
629629

630+
// === Copilot coding-agent task (blocked: unsupported agent operation) ===
631+
"create_agent_task" => {
632+
// Creates a Copilot coding-agent job that modifies repo branches and opens a PR.
633+
// Blocked via is_blocked_tool(); secrecy applied so the resource is correctly
634+
// classified before the integrity override in label_resource.
635+
// S = S(repo); I = blocked (override applied in label_resource)
636+
secrecy = apply_repo_visibility_secrecy(&owner, &repo, repo_id, secrecy, ctx);
637+
}
638+
630639
// === Copilot agent operations (repo-scoped) ===
631640
"assign_copilot_to_issue" | "request_copilot_review" => {
632641
// Copilot assignment/review requests return repo-scoped content.

guards/github-guard/rust-guard/src/tools.rs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ pub const READ_WRITE_OPERATIONS: &[&str] = &[
6262
"issue_write",
6363
"sub_issue_write",
6464
"update_gist",
65+
// Pre-emptive entries for anticipated future MCP tools (no equivalent tool today)
66+
// gh agent-task create — creates a Copilot coding-agent job (branch + PR); blocked as unsupported
67+
"create_agent_task",
6568
];
6669

6770
/// Check if a tool is a write operation
@@ -121,10 +124,16 @@ pub fn is_unlock_operation(tool_name: &str) -> bool {
121124
/// symmetric to `archive_repository` and equally unsupported.
122125
/// - `rename_repository`: renames a repository, breaking all clone URLs, webhooks, and external
123126
/// references; unsupported as an agent operation.
127+
/// - `create_agent_task`: creates a Copilot coding-agent job that opens a branch and PR;
128+
/// unsupported as a directly invocable agent operation.
124129
pub fn is_blocked_tool(tool_name: &str) -> bool {
125130
matches!(
126131
tool_name,
127-
"transfer_repository" | "archive_repository" | "unarchive_repository" | "rename_repository"
132+
"transfer_repository"
133+
| "archive_repository"
134+
| "unarchive_repository"
135+
| "rename_repository"
136+
| "create_agent_task"
128137
)
129138
}
130139

@@ -210,4 +219,20 @@ mod tests {
210219
);
211220
}
212221
}
222+
223+
#[test]
224+
fn test_create_agent_task_is_read_write_and_blocked() {
225+
assert!(
226+
is_read_write_operation("create_agent_task"),
227+
"create_agent_task must be classified as a read-write operation"
228+
);
229+
assert!(
230+
is_blocked_tool("create_agent_task"),
231+
"create_agent_task must be unconditionally blocked (unsupported agent operation)"
232+
);
233+
assert!(
234+
!is_write_operation("create_agent_task"),
235+
"create_agent_task should not be in WRITE_OPERATIONS (it is in READ_WRITE_OPERATIONS)"
236+
);
237+
}
213238
}

0 commit comments

Comments
 (0)