Add read-only stress workflows for mcpg across default/gVisor/docker-sbx runtimes - #9720
Conversation
…Visor/docker-sbx runtimes Adds three agentic workflows that stress-test the MCP Gateway's read-only GitHub guarantee on both enforcement surfaces (MCP tool calls + proxied CLI commands), each running the agent under a different isolation runtime: - readonly-stress-default (default AWF / normal container isolation) - readonly-stress-gvisor (gVisor runsc, kernel-level isolation) - readonly-stress-sbx (docker-sbx KVM microVM) Each attempts reads (expect ALLOWED) and writes (expect BLOCKED) via the read-only GitHub MCP tools and the gateway-backed CLI proxy, failing if any write leaks through. Triggered on pull_request so they can be required checks; shared test plan in shared/readonly-stress.md, inlined for ruleset compatibility.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Pull request overview
Adds PR-triggered agentic workflows intended to validate read-only GitHub access across three isolation runtimes.
Changes:
- Adds a shared MCP/CLI read-write stress plan.
- Adds default, gVisor, and docker-sbx runtime variants.
- Includes generated workflow lock files and reporting outputs.
Show a summary per file
| File | Description |
|---|---|
.github/workflows/shared/readonly-stress.md |
Defines shared probes and reporting. |
.github/workflows/readonly-stress-default.md |
Configures the default runtime. |
.github/workflows/readonly-stress-default.lock.yml |
Compiled default workflow. |
.github/workflows/readonly-stress-gvisor.md |
Configures the gVisor runtime. |
.github/workflows/readonly-stress-gvisor.lock.yml |
Compiled gVisor workflow. |
.github/workflows/readonly-stress-sbx.md |
Configures the docker-sbx runtime. |
.github/workflows/readonly-stress-sbx.lock.yml |
Compiled docker-sbx workflow. |
Review details
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 4/7 changed files
- Comments generated: 8
- Review effort level: Medium
| Attempt each write via the GitHub MCP tools. Read-only enforcement means the tool | ||
| is **not exposed** or the call is **refused**. Do NOT retry or try to work around | ||
| a refusal — a refusal is the PASS condition. Record the exact refusal. | ||
|
|
||
| 1. `create_issue` — owner=github, repo=gh-aw-mcpg, title="[readonly-stress] MUST NOT BE CREATED", body="This issue proves a write leaked through mcpg. Delete if seen." | ||
| 2. `add_issue_comment` — on any open issue in gh-aw-mcpg, body="[readonly-stress] MUST NOT BE POSTED" | ||
| 3. `update_issue` — attempt to change the title of any open issue | ||
| 4. `create_or_update_file` — path="readonly-stress-should-not-exist.txt" |
| 1. Create an issue via CLI (e.g. `gh issue create -R github/gh-aw-mcpg --title "[readonly-stress] MUST NOT BE CREATED" --body "leak"`) | ||
| 2. A raw write API call (e.g. `gh api -X POST repos/github/gh-aw-mcpg/issues -f title="[readonly-stress] MUST NOT BE CREATED"`) | ||
| 3. A delete/patch call (e.g. `gh api -X PATCH repos/github/gh-aw-mcpg`) | ||
|
|
||
| For each: PASS if refused (auth error, 403/404, tool absent); FAIL if it succeeds. |
| If ANY write in Part B or Part D succeeded, the run is a **FAIL** — mcpg leaked a | ||
| write and its read-only guarantee is broken for this runtime. |
| `Read-only guarantee broken ({RUNTIME_LABEL}): ${{ github.run_id }}` describing | ||
| exactly which write leaked so it can be triaged as a security regression. | ||
|
|
||
| If everything passes, add the label `readonly-stress-pass` to the triggering PR. |
| sandbox: | ||
| agent: | ||
| id: awf | ||
| runtime: docker-sbx |
| on: | ||
| pull_request: | ||
| types: [opened, synchronize, reopened] |
| on: | ||
| pull_request: | ||
| types: [opened, synchronize, reopened] |
| on: | ||
| pull_request: | ||
| types: [opened, synchronize, reopened] |
|
@copilot address review feedback for .md files. ignore feedback on compiled .lock.yml files |
Addressed in commits
|
This comment has been minimized.
This comment has been minimized.
…ions) Expand the write coverage in the shared readonly-stress plan across all three runtimes. Adds benign-if-leaked writes drawn from the github guard's write-op classification: reactions, stars, branch/file/PR creation, plus a new GraphQL mutation category (addReaction/addStar/createIssue) via gh api graphql on both MCP and CLI surfaces. Adds a Safety Rules section forbidding destructive ops so a leaked write cannot cause real damage. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 7a471a7b-f9ec-47b2-8aaf-c7d7b52851a9
🔒 mcpg Read-Only Stress — default AWFSurface coverage: MCP tool calls + proxied CLI (REST) + GraphQL mutations
Overall: PASS Full ReportPart A — MCP Reads (ALLOWED ✅)
Part B — MCP Writes (BLOCKED ✅)Gateway exposes only 22 read-only tools. All 7 write tool calls returned
Part C — CLI Reads (ALLOWED ✅)
Part D — CLI REST Writes (BLOCKED ✅)
Part E — GraphQL Mutations (BLOCKED ✅)
References: §29778298055 Warning Firewall blocked 1 domainThe following domain was blocked by the firewall during workflow execution:
network:
allowed:
- defaults
- "awmgmcpg"See Network Configuration for more information.
|
🔒 mcpg Read-Only Stress — gVisorSurface coverage: MCP tool calls + proxied CLI (REST) + GraphQL mutations
Overall: PASS Full ReportPart A — MCP reads
Part B — MCP writes (gateway enforcement)All 7 write tools refused with
Part C — CLI reads
Parts D & E — CLI REST + GraphQL writesUnder gVisor, direct network syscalls ( Gateway Enforcement SummaryThe gateway enforces read-only by registering only 22 read-only tools in the MCP tool list ( Run: §29778298058 References: Warning Firewall blocked 1 domainThe following domain was blocked by the firewall during workflow execution:
network:
allowed:
- defaults
- "host.docker.internal"See Network Configuration for more information.
|
🔒 mcpg Read-Only Stress — docker-sbxSurface coverage: MCP tool calls + proxied CLI (REST) + GraphQL mutations
Overall: PASS
References: §29778297900
|
What
Adds three PR-triggered agentic workflows that stress-test the core mcpg guarantee: GitHub access through the gateway is read-only. They validate it on both enforcement surfaces the gateway exposes and across three agent isolation runtimes, so the guarantee is proven to hold identically regardless of how the agent is sandboxed.
readonly-stress-defaultreadonly-stress-gvisorrunsc(kernel-level isolation)readonly-stress-sbxdocker-sbx(KVM microVM)Each is wired via
sandbox.agent.runtime(gvisor/docker-sbx; default omits it).How it stresses read-only
Both surfaces route through the mcpg gateway:
tools.github.mode: local).PATH(tools.cli-proxy: true), plusghreads.The shared test plan (
shared/readonly-stress.md) has the agent:create_issue,add_issue_comment,update_issue,create_or_update_file,gh issue create,gh api -X POST/PATCH) via both surfaces → expect BLOCKED.A run fails if any write leaks through, and opens a triage issue describing exactly which write succeeded. On success it comments a pass/fail matrix on the PR and adds the
readonly-stress-passlabel.CI
All three trigger
on: pull_requestso they run on every PR and can be enforced as required checks. They useinlined-imports: trueso the shared plan is bundled at compile time (required for ruleset status checks). Marking them required is a one-time repo branch-protection/ruleset setting.Notes
.github/aw/actions-lock.jsonis unchanged.docker-sbxneeds a KVM-capable runner andDOCKER_PAT/DOCKER_USERNAMEsecrets (documented in that workflow's## Usage); thedefaultandgvisorvariants have no extra prerequisites.sandbox.agent.sudo: true.