diff --git a/tools/spec-loop/.last-sync b/tools/spec-loop/.last-sync index df2c2a69..c697e74c 100644 --- a/tools/spec-loop/.last-sync +++ b/tools/spec-loop/.last-sync @@ -1 +1 @@ -0e7012bac91017e2255a4a34cdf7c47e84438767 +5c75abd216d798efce7257749cbdb3e26844b3c0 diff --git a/tools/spec-loop/specs/agent-isolation-sandbox.md b/tools/spec-loop/specs/agent-isolation-sandbox.md index 42ac9919..3e983c8d 100644 --- a/tools/spec-loop/specs/agent-isolation-sandbox.md +++ b/tools/spec-loop/specs/agent-isolation-sandbox.md @@ -155,6 +155,21 @@ The reference model is four layers, layered: `.pre-commit-config.yaml` or the three whitespace hooks abort the run (#1309). + A second, independent deny protects the vetted-ops **policy** — the + file the dispatcher consults to decide which caller may run which + operation — on both surfaces it can resolve to: the + `magpie-vetted-ops` plugin-cache install and the committed + `.apache-magpie-overrides/tools/vetted-ops/**` override. An agent + able to rewrite the policy grants itself the whole write catalogue + regardless of which dispatcher binary handles the call, so this + deny applies even though the write dispatcher (`vetted-op`) is + never excluded from the sandbox. The override is the in-repo case + described above, `sandbox_write_denied` entry included (#1308, + #1309). The framework's own dispatcher source at + `tools/vetted-ops/` is deliberately left un-denied — it is PR-gated + code, and a write-deny there would make the whole tree read-only to + every sandboxed subprocess, `prek`'s fixers included. + The `gh` exemption applies only to invocations made of `cd …` / `gh …` parts; the same whole-command shape rule governs the other entries. The rule and its failure signature are in diff --git a/tools/spec-loop/specs/sandbox-diagnostics.md b/tools/spec-loop/specs/sandbox-diagnostics.md index 4dc9fa61..7c167b5f 100644 --- a/tools/spec-loop/specs/sandbox-diagnostics.md +++ b/tools/spec-loop/specs/sandbox-diagnostics.md @@ -47,12 +47,16 @@ error, and two skills that probe or verify the setup on demand. **Root cause** (which sandbox layer blocks it and why), **Fix** (a settings widening with per-entry rationale, or — for the `gh` entry — an invocation-shape rule, because there is nothing to widen), and - **Notes**. Seven entries today: SSH agent / Yubikey, signed commit + **Notes**. Eight entries today: SSH agent / Yubikey, signed commit failing before any touch (`gpg.format=ssh` key unreadable), signed commit failing with `cannot exec` of the touch-overlay wrapper (`gpg.ssh.program` under the read-denied `~/.claude/scripts/`), - localhost port bind, Docker / Podman socket, `/tmp` read-only, and - `gh` inside the sandbox (TLS `OSStatus -26276` / `HTTP 401`). + signed commit failing with the agent refusing and the overlay never + appearing (the touch overlay's runtime-state directory denied — + `/tmp` on a platform with no `$XDG_RUNTIME_DIR`, before the + per-user cache-dir fallback), localhost port bind, Docker / Podman + socket, `/tmp` read-only, and `gh` inside the sandbox (TLS + `OSStatus -26276` / `HTTP 401`). - `tools/agent-isolation/sandbox-error-hint.sh` — a Claude Code `PostToolUse` hook on the `Bash` matcher. Scans the tool's stdout + stderr for the catalogued symptom strings and, on a match, prints @@ -88,6 +92,11 @@ error, and two skills that probe or verify the setup on demand. so a grep into the catalog finds them; the hook matches those same strings with anchored, specific regexes. False-positive hints are noise, so the pattern set errs on the side of missing a variant. + Branch order matters when two entries' error text overlaps: the + touch-overlay runtime-state branch is checked before the SSH-agent + branch because both end in `agent refused operation`, and the more + specific pattern has to win or the reader is sent to the entry about + an unreachable key when the key was never the problem. - **The hook never changes the outcome.** It exits 0 silently on no match, on a non-`Bash` tool, on unparsable JSON, or on any unexpected envelope shape (fail-open), and exits 1 — never 2 — on a match, so diff --git a/tools/spec-loop/specs/security-reporting.md b/tools/spec-loop/specs/security-reporting.md index 4347fc3d..fe5a07e2 100644 --- a/tools/spec-loop/specs/security-reporting.md +++ b/tools/spec-loop/specs/security-reporting.md @@ -46,7 +46,10 @@ health without navigating the tracker issue-by-issue. - **Self-contained output.** The rendered HTML embeds all data; no external service is needed to view it. - **Incremental by default.** Resume behaviour extends an existing dataset - without re-fetching all history; a full rebuild is an opt-in flag. + without re-fetching all history; a full rebuild is an opt-in flag. The + per-issue event cache is trusted only when it was written after that + issue's `updatedAt`; an issue relabelled since the cache was written is + refetched rather than silently served its stale label history. - **Config-driven.** Lifecycle category bands, time-to-triage signal, milestone vertical annotations, and the null-`upstream_repo` path are declared in the tool's `default-config.yaml` and overridden per-adopter.