From 44994b38042c550adf631c1a2a177f6662a0818f Mon Sep 17 00:00:00 2001 From: nmccready Date: Fri, 3 Jul 2026 03:52:38 -0400 Subject: [PATCH 1/2] feat(quarantine): static scan + review gate for remote installs (SPEC-005 Part B, fixes #52) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remote content is guilty until reviewed: - pull/update park fetched artifacts in .agents/.quarantine/ (dot-dir: invisible to sync and index by construction) after a static scan — net-exec (curl|bash), credential access + network, obfuscation (base64 blobs, zero-width/bidi Unicode), prompt-injection phrasing - `sync-agents quarantine` lists pending artifacts with findings; `approve |--all` promotes (CRITICAL findings block without --force; forced approvals recorded in sources.lock as approved_with_findings); `reject` deletes - tree entries quarantine as a unit; the entry lock applies only when the last artifact is approved — a half-approved tree never reads as current - `--trust` bypasses the gate per invocation (scan still prints); `quarantine = off` in .agents/config disables (default ON) Part A (fetch hardening) shipped in #62; Part C (sandboxed exec wrapper) remains future work. Co-Authored-By: Claude Fable 5 --- README.md | 17 ++ internal/agent/source/manifest.go | 6 +- internal/agent/source/pull.go | 130 +++++++++++- internal/agent/source/quarantine.go | 231 ++++++++++++++++++++++ internal/agent/source/quarantine_test.go | 240 +++++++++++++++++++++++ internal/agent/source/scan.go | 176 +++++++++++++++++ internal/agent/sourcecmd.go | 119 ++++++++++- main.go | 53 ++++- specs/SPEC-005-sandboxing-quarantine.md | 2 +- 9 files changed, 965 insertions(+), 9 deletions(-) create mode 100644 internal/agent/source/quarantine.go create mode 100644 internal/agent/source/quarantine_test.go create mode 100644 internal/agent/source/scan.go diff --git a/README.md b/README.md index c402737..8d7b891 100644 --- a/README.md +++ b/README.md @@ -113,6 +113,9 @@ AGENTS.md is also symlinked to CLAUDE.md so that Claude reads the index natively | `source list [--json]` | Show each entry's local state: `ok` / `outdated` / `modified` / `missing` | | `source bundle` | Rebuild `sources.yaml` from installed artifacts' origin metadata | | `source detach ` | Un-manage an artifact: flip its origin to manual and drop the manifest entry | +| `quarantine` | List remotely-fetched artifacts awaiting review, with their scan findings | +| `approve \|--all [--force]` | Promote a quarantined artifact into `.agents/` (`--force` accepts critical findings, recorded in the lock) | +| `reject \|--all` | Delete a quarantined artifact without installing it | | `git-hook` | Install a pre-commit git hook for auto-sync (`hook` remains as a deprecated alias) | | `inherit