feat(orchestrators): add Agor+acq sandbox integration (Tier 1 worked example) - #284
Draft
mogul wants to merge 11 commits into
Draft
feat(orchestrators): add Agor+acq sandbox integration (Tier 1 worked example)#284mogul wants to merge 11 commits into
mogul wants to merge 11 commits into
Conversation
Seed the new integrations/orchestrators/agor/ area with the two source exploration documents that motivate the Agor + acq isolation integration: - sandbox-abstraction.md: Agor executor-hook sandbox abstraction design (executor_command_template, sbx/msb CLI shapes, mount strategies, the SandboxProvider abstraction, phased rollout). - sandbox-acq-analysis.md: using acq as the sandbox backend — the four kits, who-owns-what split, USAi credential flow, SSH-agent forwarding. Reproduced verbatim from the source material; status: exploration. Not indexed by generate_index.py (scans only skills/prompts/workflows/agents/ lessons). Refs #258. Co-authored-by: OpenCode Agent <bret.mogilefsky@gsa.gov> (cherry picked from commit b8de4140941e4b9d24391e2aa06c377d35aaea5e)
Establish integrations/orchestrators/ as a new integration class for tools that DRIVE a sandbox/isolation tool from the outside (own the agent+session lifecycle, call acq/sbx/msb), as distinct from isolation kits that acq APPLIES inside a sandbox. Direction of control decides the area. - Area ADR 0001 (proposed): rationale, drives-vs-applied boundary rule, composition corollary (an orchestrator that needs a kit references one under isolation/acq-kits/), mirrors the isolation area ADR. - orchestrators/README.md: boundary rule + what belongs here + index. - integrations/README.md: new area in 'What belongs here', layout, and an Available-integrations row for orchestrators/agor. ADR status is 'proposed' pending human confirmation (drafted AFK via the wayfinder map). Refs #250, #255. Co-authored-by: OpenCode Agent <bret.mogilefsky@gsa.gov> (cherry picked from commit 408ad4e088ca82b08f48957b0b933f12f5e8c97b)
Add sandbox-wrapper-acq.sh: the Agor executor_command_template target that runs agor-executor inside an acq sandbox. - Buffers the stdin JSON payload (mktemp + trap cleanup; payload may carry a session JWT so it is always removed on exit). - Derives mounts from the worktree's own .git with zero daemon calls: worktree mode reads the gitdir pointer to mount the main repo's .git; clone mode mounts the self-contained clone dir only. - v1 safety gate: refuses to mount a LOCAL repo's checkout (would expose the user's working tree/.env); supports Agor-managed remote repos (~/.agor/*) and clone-mode branches only (map #251). - Applies the daemon-egress kit via --kit (acq has no --net-rule; map #259), provisions the per-sandbox secret on stdin (out-of-band, not vended by Agor today; map #252), and pipes the payload to . - Honors a dry-run PRINCIPLE via AGOR_SANDBOX_DRY_RUN=1 (prints the planned acq commands and exits) since the script's job is inherently to mutate and Agor always invokes it live; deviation documented inline per docs/clean-script-standard.md. Authored to the clean-script standard (strict mode, quoted expansions, mktemp + trap, usage, no curl|sh / eval / secret dumps). bash -n clean; four dry-run cases (clone, agor-worktree, local-repo refusal, missing cwd) verified by hand. DRAFT pending human review + live end-to-end validation (map #253, #257). Co-authored-by: OpenCode Agent <bret.mogilefsky@gsa.gov> (cherry picked from commit 578b79137929062591fd16b2c322e8cba43a47dc)
Add integrations/orchestrators/agor/README.md: the copy-into-your-project setup guide for running Agor's executor inside an acq sandbox. Covers how-it-works (executor_command_template → wrapper → acq exec), the executor_command_template config, prerequisites, a dry-run-first setup, the env-var configuration table, the mount strategy (worktree .git derivation + the v1 local-repo refusal gate and the .git-only-staging alternative), residual risks, daemon reachability via the agor-daemon-egress kit (no acq --net-rule), the out-of-band USAi credential flow, a who-owns-what table, backend support (sbx v1; msb/ppp gaps), and the scope/no-compliance-authority disclaimer. Status DRAFT pending human review + live validation (map #254, #257). Local link targets verified to exist. Co-authored-by: OpenCode Agent <bret.mogilefsky@gsa.gov> (cherry picked from commit 83b8dd268f14c16ec64a485e8860973a9cd57453)
Add the agor-daemon-egress hybrid/v1 mixin kit: allow-list outbound egress to the Agor daemon control-plane (host.docker.internal:3030 by default) so an Agor executor running inside an acq sandbox — via the orchestrators/agor integration — can connect back to the daemon over WebSocket. acq has no per-invocation egress flag, so daemon reachability must be a kit's caps.network.allow (research #248/#259); sbx is default-deny. - spec.yaml: single caps.network.allow entry, no files/commands/secret. sbx preserves host:port; msb strips the port (domain-only) — documented. - Security-relevant (widens egress): governed by human review + a prose 'Security posture' note in the README and an ADR, since the hybrid/v1 kit schema (additionalProperties:false) models no governance frontmatter (those are skill-pattern fields). Human-approved for authoring + categorization. - Lives under isolation/acq-kits/ (applied INSIDE the sandbox) per the #250 drives-vs-applied boundary, though its only consumer is orchestrators/agor, which references it via AGOR_EGRESS_KIT. - README (backend parity + security posture), TROUBLESHOOTING, scripts/verify (sbx live check), ADR; registry + acq-kits README updated. validate-kits.py: all 6 kits valid. unsafe-shell scan clean. bash -n clean. Refs #259. Co-authored-by: OpenCode Agent <bret.mogilefsky@gsa.gov> (cherry picked from commit 856fbc6b663acff669df735228e81d56140afcbc)
Replace the hardcoded ~/.agor/* managed-root heuristic in the wrapper's v1 local-repo safety gate with Agor's real path model, per source confirmation: AGOR_DATA_HOME (env) > paths.data_home (config) > AGOR_HOME > ~/.agor. Agor stores repos/ (bare clones) and worktrees/ under AGOR_DATA_HOME, so a main repo under that root is Agor-managed (safe to mount); anything else is treated as a user local repo and refused (would expose .env). - Wrapper resolves AGOR_DATA_HOME|AGOR_HOME|~/.agor and honors an optional colon-separated AGOR_MANAGED_ROOTS allowlist (e.g. an EFS/NFS data_home for k8s deploys). Prefix match with a trailing-slash guard. - Documents that the wrapper cannot read config.yaml, so a config-only paths.data_home must be exported as AGOR_DATA_HOME (or added to AGOR_MANAGED_ROOTS). - README: new env-var rows + updated mount-strategy note. Addresses the B review (Copilot's Agor-source query on worktree storage). Re-verified: bash -n clean; dry-run cases for AGOR_DATA_HOME match, local-repo refusal (rc5), and an AGOR_MANAGED_ROOTS EFS root all behave. Refs #251, #253. Co-authored-by: OpenCode Agent <bret.mogilefsky@gsa.gov> (cherry picked from commit b48b2c4a2a77b9e4f053fcb2096aac4d5d6120a6)
Human owner confirmed the integrations/orchestrators/ area and the drives-vs-applied boundary rule (review item A). Flip ADR 0001 status proposed -> accepted. Co-authored-by: OpenCode Agent <bret.mogilefsky@gsa.gov> (cherry picked from commit 76e16a8d25a6f5c6c03da481d016f84451540178)
…downlint CI-parity fixes for the new orchestrators area and agor-daemon-egress kit: - Correct relative-link depths in the orchestrators area ADR (repo-root docs/, isolation area ADR, agor explorations) and in the egress kit's security ADR (orchestrators/, docs/security-skill-governance.md) — all local links now resolve. - Fix MD028 (blank line inside blockquote) in the egress kit README and the orchestrators area ADR. - Flip orchestrators area ADR 0001 to accepted (review A). Verified: markdownlint-cli2 0 issues; all local links resolve; validate_repo, unsafe-shell scan, validate-kits --strict, INDEX --check, and the usai-provider node tests all pass. Refs #256. Co-authored-by: OpenCode Agent <bret.mogilefsky@gsa.gov> (cherry picked from commit b4fc7c1a41983050410946b860e5b35ed4bbfee2)
Align the egress kit with main's newer kits (quickstart#235 / #273): declare the source repo in the optional hybrid/v1 `provenance` block. As a standalone integration kit (not part of the acq-builtin bundle), it declares `repo` only — no bundle/kit_names — so it does not affect the built-in bundle cross-check. Co-authored-by: OpenCode Agent <bret.mogilefsky@gsa.gov>
Replace the `[ -f ] && ok || { … }` idiom with an if/else so the fallback
block cannot run when the test passes (shellcheck SC2015). No behavior change.
Co-authored-by: OpenCode Agent <bret.mogilefsky@gsa.gov>
…losed upstream quickstart#230 + the #233 parity omnibus made msb mount each workspace at its host path (sbx-parity) with multiple positional mounts, so the worktree `.git` `gitdir:` pointer resolves the same on msb — the wrapper is backend-agnostic here. The engineering gap #260 described no longer exists (#260 closed); the only residual is a live msb run on a KVM host, folded into the live-validation ticket #257. Update the wrapper header, agor/README backend table, and the egress kit spec/README/TROUBLESHOOTING/ADR to reference #257 instead of the closed #260. Co-authored-by: OpenCode Agent <bret.mogilefsky@gsa.gov>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Context
Tier 1 worked example of an Agor +
acqsandbox-isolation integration(map #247): a runnable
executor_command_templatewrapper that runs an Agor executor inside anacqsandbox, a small
agor-daemon-egresskit the wrapper requires, a newintegrations/orchestrators/area with its ADR, and the two source explorationdocs. Zero Agor code changes for the OpenCode path.
All decision/build child issues are closed and AFK-confirmed by the human owner
(#248–#256, #258, #259, #261). This PR rebases that work cleanly onto current
main.AI assistance disclosed: prepared with an AI coding agent (OpenCode);
human-owned and reviewed.
Plan (what changed, and how it maps to the approved plan)
The prior
feat/agor-integrationbranch also carried 6 openchamber commitsthat are a parallel implementation of the "startup owns server" feature that
mainhas since landed authoritatively (#246 + #283). Rather than merge andresolve 13 openchamber conflicts, this branch is a fresh cut of
origin/mainwith only the 8 Agor-deliverable commits cherry-picked; the obsolete
openchamber commits were dropped.
main's openchamber remains authoritative.Files (+2,113 / 14 files, no openchamber files touched):
integrations/orchestrators/— new area:README.md, area ADR0001-orchestrators-area-and-agor-acq.md,agor/README.md(setup guide),agor/sandbox-wrapper-acq.sh, two exploration docs.integrations/isolation/acq-kits/agor-daemon-egress/— new egress kit(
spec.yaml,README.md,TROUBLESHOOTING.md,scripts/verify, kit ADR)kits.yamlregistry row +acq-kits/README.mdlink.integrations/README.md— orchestrators area row.Two additions beyond the cherry-picks:
provenance: {repo: GSA-TTS/agentic-coding-patterns}on the egress kit,aligning it with
main's newer kits (quickstart#235 / PR1: kit-bundle provenance schema field + permission-preservation & acq/sbx drift-guard tests #273). It declaresrepoonly (no bundle/kit_names), so it does not affect the acq-builtinbundle cross-check.
verify([ -f ] && ok || {…}→explicit
if/else; no behavior change).Verification
Run in the project's standard environment (Python 3, shellcheck 0.11.0):
validate-kits.py --strictvalidate_repo.pyscan_unsafe_shell.py .generate_index.py --checkgenerate_catalog.py --checkshellcheck(wrapper + verify)kit-hybrid-v1schema*
pytestis not installable in this container (noensurepip/venv); theprovenance-relevant assertions from
scripts/tests/test_kit_provenance_and_drift.pywere exercised directly with
jsonschema. CI runs the full pytest suite.Live wrapper dry-run against real
acq(quickstartmain): remote /Agor-managed payload emits the correct plan
(
acq create shell <worktree> <repo.git> --name agor-… --kit <egress> … | acq exec … -- agor-executor --stdin,then
acq rmon exit); a worktree whose main repo is outsideAGOR_DATA_HOMEis correctly refused (exit 5).
CLI-surface re-verify vs current quickstart
main(since #248/#249 closed,quickstart landed #233 sbx↔msb parity and #257 fail-closed run):
acq createpositional agent+workspaces +
--name+ repeatable--kit;acq exec <name> -- CMDstdin passthrough;acq secret set <SANDBOX> usaireads value from stdinwith positional scope; sbx-v2 synthesis preserves
caps.network.allowhost:port. The v1 contract still holds.
Live end-to-end validation (#257): BLOCKED
Per the isolation area ADR, a live
acq runcannot execute inside an sbxsandbox (no nested sandboxes). This CI/dev host is itself a Docker container
(
/proc/1/cgroup→0::/docker/…), and sbx is not installed (commercial;brew install docker/tap/sbx+sbx login), msb is absent with no/dev/kvm, and agor/agor-executor are absent (no daemon to spawn theexecutor or mint the scoped JWT). Recorded BLOCKED per AGENTS.md §8.3 rather
than fabricating a pass. Retry trigger: a sandbox-capable, non-nested host —
sbx (installed + logged in) and/or msb (KVM host) — with a running Agor
daemon on
:3030+ an out-of-band USAi key.Rollback
Revert this PR (single squash commit) — the change is purely additive
(a new
orchestrators/area + one new isolation kit + registry/README rows).No existing kit, script, schema, or test is modified, so revert restores the
prior state cleanly with no data or config migration.
Security Impact
agor-daemon-egresssecurity-relevant kit: it widens outboundegress to exactly one host:port (
host.docker.internal:3030, the Agordaemon control-plane). It drops no files, runs no commands, and carries no
secret. Governed by human review (the kit schema models no governance
frontmatter); posture documented in the kit README + its ADR.
acq secret setonstdin) and refuses to mount a non-Agor-managed local repo checkout,
avoiding exposure of a user's
.env/working files.compliance authority (references the playbook, does not restate it).
msb backend note (#260 closed)
The earlier "msb is a gap" framing is stale and removed. #260 was filed
because
acq's msb adapter mounted the workspace at a fixed guest path andwired no extra mounts — but quickstart#230 + the #233 parity omnibus changed msb
to mount each workspace at its host path (sbx-parity) with multiple
positional mounts, so the worktree
.gitgitdir:pointer resolves the sameon msb. The wrapper is backend-agnostic here; #260 is closed as resolved.
The only residual — a live msb create→exec run on a KVM host (msb is not
live-verified upstream) — is folded into #257. This PR's wrapper header,
agor/READMEbackend table, and the egress-kit spec/README/TROUBLESHOOTING/ADRwere updated to reference #257 instead of the closed #260.
Links
Live end-to-end validation: Agor session executing inside an acq sandbox #257
msb backend support for the Agor+acq wrapper (fixed-guest-path mount gap) #260
Co-authored-by: OpenCode Agent bret.mogilefsky@gsa.gov