# Agent Task You are running inside an OpenShell sandbox. Your job has two steps. Each step starts with a `curl` call that the L7 proxy will deny; for each denial, read `/etc/openshell/skills/policy_advisor.md`, draft a narrow proposal, submit it to `http://policy.local/v1/proposals`, wait on `GET /v1/proposals/{chunk_id}/wait?timeout=300`, then retry. ## Target - Repository: `{{OWNER}}/{{REPO}}` - Branch: `{{BRANCH}}` - File path: `{{FILE_PATH}}` - Run id: `{{RUN_ID}}` ## What to do ### Step 1 — Fetch a public schema (un-credentialed action) 1. Fetch the well-known GitHub OpenAPI description from `https://raw.githubusercontent.com/github/rest-api-description/main/descriptions/api.github.com/api.github.com.json` with `curl`. Do not send any authentication header — this resource is public. Save the response to `/tmp/github-openapi.json`. The first attempt will fail with HTTP 403 and a JSON body containing `"error": "policy_denied"`. Read the body — it tells you which layer denied you, which method/path was missing, and where to learn more. 2. Read `/etc/openshell/skills/policy_advisor.md` and follow it. Submit the narrowest possible proposal to `http://policy.local/v1/proposals` — exact host (`raw.githubusercontent.com`), exact port (443), exact method (`GET`), exact path (`/github/rest-api-description/main/descriptions/api.github.com/api.github.com.json`), binary `/usr/bin/curl`. Do not propose wildcard hosts. Save `accepted_chunk_ids[0]`. 3. Block on the gateway's decision by calling `GET http://policy.local/v1/proposals/{chunk_id}/wait?timeout=300`. - `status: "approved"` — retry the fetch once. Because the host has no credentials in scope (it's a public-content endpoint), the prover sees no findings and the gateway auto-approves the proposal without human review. The whole step typically completes in ~1 second after submission. - `status: "rejected"` — read `rejection_reason`. If it has text, address the specific feedback and submit a revised proposal; otherwise stop and tell the developer you can't proceed. - `status: "pending"` with `timed_out: true` — re-issue the same `/wait` request once. Each `/wait` is one long-lived HTTP call. 4. After the retry, verify the file exists at `/tmp/github-openapi.json` and is non-empty. ### Step 2 — Write to GitHub (credentialed action) 1. PUT the file with `curl` against `https://api.github.com/repos/{{OWNER}}/{{REPO}}/contents/{{FILE_PATH}}`. Authenticate with the `GITHUB_TOKEN` environment variable. Do not echo the token. Body content (base64-encoded into the JSON `content` field): ``` # OpenShell policy advisor demo Run id: {{RUN_ID}} Written from inside an OpenShell sandbox after a narrowly-scoped policy proposal was reviewed by the developer. ``` 2. The first attempt will fail with HTTP 403 and a JSON body containing `"error": "policy_denied"`. Read the body — it tells you which layer denied you (`l7`/`rest`), which method/path was missing, and where to learn more. 3. Submit the narrowest possible proposal to `http://policy.local/v1/proposals` — exact host (`api.github.com`), exact port (443), exact method (`PUT`), exact path (`/repos/{{OWNER}}/{{REPO}}/contents/{{FILE_PATH}}`), binary `/usr/bin/curl`. Do not include query strings. Do not propose wildcard hosts. Save `accepted_chunk_ids[0]`. 4. Block on the developer's decision by calling `GET http://policy.local/v1/proposals/{chunk_id}/wait?timeout=300`. - This time the prover emits a `capability_expansion` finding: PUT is a new method on a host the binary already had credentialed reach to (read-only). That's a stated intent change, so the gateway holds the chunk in `pending` for human review instead of auto-approving. The `/wait` call still parks on a socket — zero LLM tokens burn while the human decides. - `status: "approved"` — retry the PUT once. Policy has hot-reloaded. - `status: "rejected"` — read `rejection_reason`. If it has text, address the specific feedback and submit a revised proposal (back to step 3); otherwise stop and tell the developer you can't proceed. - `status: "pending"` with `timed_out: true` — re-issue the same `/wait` request once. 5. On a successful PUT (HTTP 200 or 201), print a short summary showing `content.path` and `content.html_url` from the GitHub response. Do not print the full response body. If anything is unclear, prefer making a narrower proposal and asking for approval again over widening the rule.