Skip to content

fix(msb): skip the recursive home chown when the image baked the agent user - #432

Merged
basiliskus merged 2 commits into
mainfrom
fix/issue-422-agent-home-chown
Sep 3, 2026
Merged

basiliskus merged 2 commits into
mainfrom
fix/issue-422-agent-home-chown

Conversation

@basiliskus

@basiliskus basiliskus commented Sep 1, 2026 •

Copy link
Copy Markdown
Contributor

On the msb backend, first provision runs chown -R agent:agent /home/agent unconditionally. On an image with a dense baked agent home (the devenv images ship single-user Nix state, thousands of tiny files) that write-crawl grinds the guest ext4 journal for minutes, with no output, right after "Waiting for the sandbox to finish booting… done". sbx never pays this: its template images bake the agent user and home ownership at image build time, so the create path has nothing to fix.

Fix. The guest setup script now tracks whether acq itself created the agent user. The recursive chown runs only on that path (a plain OCI base can leave a half-created or root-owned home, the case the FATAL rework was about). When the image shipped the user, acq trusts the baked ownership: the top-level chown /home/agent and the su agent -c "test -w /home/agent" writability backstop still run on every path, but they cover the home directory itself, not its contents. A custom image that ships agent yet bakes root-owned content under /home/agent violates the base-image contract and is no longer papered over; the backend guide's contract section now says so and how to fix the image. The default templates and the devenv image are fully agent-owned, so the common path is unaffected.

Spinner. The agent-user step now gets a progress status ("Preparing the agent user"), like the OCI-engine and agent-install steps, so whatever it costs no longer reads as a hang.

Fixes #422


AI-assisted

@basiliskus
basiliskus marked this pull request as ready for review September 1, 2026 13:27
@basiliskus
basiliskus requested a review from a team as a code owner September 1, 2026 13:27
@basiliskus
basiliskus force-pushed the fix/issue-422-agent-home-chown branch from d0bc2ce to 01e6e95 Compare September 1, 2026 21:06

@wz-gsa wz-gsa left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adversarial review — the performance fix is genuinely necessary and correctly implemented, but found a real, live-reproduced gap in the safety claim before deciding approve vs. request-changes.

Performance claim verified, not just plausible: pulled the actual devenv image the linked issue references into a real msb sandbox and timed the pre-fix unconditional chown -R over its real baked Nix home (81,850 files, already correctly owned) — 759 seconds (12.6 minutes), worse than the issue's own quoted figure. The fix genuinely eliminates this on the "agent already exists" path. Not a theoretical justification.

Real gap found in the stated safety property. The PR body claims "a wrong skip fails loudly rather than degrading silently." I built the exact counterexample this implies should be caught: a base image where adduser agent succeeds but a baked subtree under /home/agent is root:root (simulating a COPY --chown=root:root in a custom image's Dockerfile). Loaded it into a real sandbox and ran the actual guest script verbatim:

  • The top-level chown "agent:${_agrp}" /home/agent fixes /home/agent itself.
  • The root-owned subtree underneath is never touched — _acq_created_agent stays 0 because id agent succeeded, so the recursive chown that used to silently heal this is skipped.
  • The su agent -c "test -w /home/agent" backstop only probes the named directory's own write bit — it does not detect the unwritable subtree beneath it, so it passes trivially.
  • Result: the agent user gets a silent, permanent EACCES on that subtree — not the loud failure the PR body describes for this exact scenario.

Also checked the "kits already chown the subtrees they stage" mitigation directly against every kit in agentic-coding-patterns/integrations/isolation/acq-kits/ that stages files under /home/agent — none of them run their own chown; the coverage they get is from acq's own generic file-copy path (_acq_msb_copy_file_verified), which only covers files acq itself copies in via a kit's files: spec, not content the base image baked. So that mitigating claim doesn't actually cover the failure mode it's meant to.

Severity assessment, and why this is a comment not a block: this only affects a custom ACQ_MSB_IMAGE override that ships an agent user but violates the documented base-image contract (docs/BACKEND_GUIDE.md already states complete home ownership as an operator requirement for custom images). The default docker/sandbox-templates:shell-docker and the real devenv image I tested are both fully agent-owned, so the common path — and the actual bug this PR fixes — is unaffected. This is closer to "a documented contract violation is no longer silently papered over" than a new vulnerability, but the silent-vs-loud framing in the PR body is inaccurate for this specific edge case and there's no test covering it either way.

Suggested, non-blocking: a one-line note in docs/KNOWN_FAILURE_MODES.md about this edge case for custom-image operators, and/or a regression test for the half-baked scenario, would close the gap between the claim and the actual guarantee. Both new #422 bats tests are correct as far as they go (verified the refute_regex against both a real captured call log and a synthetic old-form line — sound, not vacuous) but they only cover the mechanical branch wiring, not this safety property.

No objection to merging as-is given the narrow, documented-contract-violation-only blast radius — flagging for the author's/maintainer's call on whether to add the doc note before or after merge.

Base automatically changed from msb-session-parity to main September 2, 2026 15:47
@basiliskus
basiliskus force-pushed the fix/issue-422-agent-home-chown branch from 01e6e95 to e6caa9c Compare September 2, 2026 15:47
basiliskus added a commit that referenced this pull request Sep 2, 2026
…iolation, not healed

Review of #432 showed the writability
backstop only probes /home/agent itself, so a custom image that ships
the agent user with root-owned content beneath the home is no longer
silently chowned. Say so in the base-image contract and drop the two
inaccurate claims (loud failure, kits chowning subtrees) from the guest
script comment.
@basiliskus

Copy link
Copy Markdown
Contributor Author

Confirmed the backstop only probes /home/agent itself. Addressed in abab240: the base-image contract in docs/BACKEND_GUIDE.md now states that a custom image shipping agent with root-owned content under the home is a contract violation acq no longer heals, with the Dockerfile fix. The guest-script comment and the PR description drop the "fails loudly" and "kits chown their subtrees" claims. Skipped the regression test: ownership can't be exercised by the offline suite, and a shape assertion would not catch a real regression.

@basiliskus
basiliskus requested a review from wz-gsa September 2, 2026 16:14

@wz-gsa wz-gsa left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Converting my earlier comment-only review to an approval — my prior adversarial findings (performance claim verified live at 12.6 minutes eliminated; the silent-degradation gap on a custom base image with incompletely-owned baked subtrees) were deliberately non-blocking: the common path (default sandbox template, the real devenv image) is unaffected, and the edge case only bites a custom ACQ_MSB_IMAGE that already violates the documented home-ownership contract in docs/BACKEND_GUIDE.md. Nothing has changed since that assessment that would newly justify blocking.

All CI checks green (the one CANCELLED "Conventional Commit Title" run is a stale duplicate superseded by the SUCCESS run immediately after it). Approved.

…t user

The first-provision agent-user setup ran chown -R /home/agent
unconditionally; on images with a dense baked agent home (single-user Nix
state, thousands of tiny files) the write-crawl grinds the guest ext4
journal for minutes with no output. Reserve the recursive chown for the
path where acq itself created the user (the half-created/root-owned-home
case); keep the top-level chown and the writability backstop on every
path so a wrong skip still fails loudly. Wrap the step in a progress
status like the neighboring provision steps.

Fixes #422
…iolation, not healed

Review of #432 showed the writability
backstop only probes /home/agent itself, so a custom image that ships
the agent user with root-owned content beneath the home is no longer
silently chowned. Say so in the base-image contract and drop the two
inaccurate claims (loud failure, kits chowning subtrees) from the guest
script comment.
@basiliskus
basiliskus force-pushed the fix/issue-422-agent-home-chown branch from abab240 to d7063c1 Compare September 3, 2026 16:11
@basiliskus
basiliskus merged commit d8f66a4 into main Sep 3, 2026
5 checks passed
@basiliskus
basiliskus deleted the fix/issue-422-agent-home-chown branch September 3, 2026 16:15
mogul added a commit that referenced this pull request Oct 6, 2026
🤖 I have created a release *beep* *boop*
---


##
[4.0.0](v3.1.0...v4.0.0)
(2026-10-06)


### ⚠ BREAKING CHANGES

* **kits:** acq no longer installs podman/OCI tooling by default. Users who need docker, docker compose, or rootless podman when the base image doesn't provide it must opt into the oci-engine kit with `acq configure`, `--kit`, or `ACQ_EXTRA_KITS`.
* **kits:** acq no longer performs native OpenCode npm fallback installation. OpenCode is supplied by the pinned opencode agent kit from agentic-coding-patterns v1.12.0, currently delivering OpenCode v2.0.22. If the kit is unavailable or invalid, acq fails closed instead of installing opencode-ai from npm.
* **kits:** existing acq sandboxes with adapter-installed podman are not migrated in place. Recreate affected sandboxes or add the oci-engine kit before relying on OCI behavior after stop/start.

### Features

* **acq:** choose the host port per sandbox, and let --publish pin it
([#526](#526))
([410f332](410f332))
* **acq:** export ACQ_WORKSPACE and ACQ_CLONE into the guest on both
backends
([#457](#457))
([e0b9a3b](e0b9a3b))
* **acq:** interactive `acq configure` UI for extra kits + token-scoping
defaults
([#500](#500))
([13d9d3a](13d9d3a))
* **kits:** adopt pinned agent and capability kits
([#474](#474))
([6a67063](6a67063))
* **secrets:** add Windows-native DPAPI secret backend
([#464](#464))
([907f404](907f404))
* **windows:** add acq preview install path
([#463](#463))
([d6d76f4](d6d76f4))


### Bug Fixes

* **acq:** use sandbox workspace for github scoping
([#476](#476))
([1610835](1610835))
* **ci:** bump js-yaml to 4.3.2 to clear a high-severity CPU-DoS
advisory
([#454](#454))
([3217b49](3217b49))
* **ci:** bump smol-toml to 1.7.1 to clear an infinite-loop DoS advisory
([#459](#459))
([c2291bf](c2291bf))
* **ci:** centralize markdownlint coverage
([#548](#548))
([a27c31e](a27c31e))
* **ci:** pin markdownlint-cli2 once, clear GHSA-253c, unify file
selection
([#527](#527))
([e712685](e712685))
* **ci:** unblock unrelated PRs from the bash32 required-check deadlock
([#513](#513))
([187aa57](187aa57))
* **install:** keep curl | sh stdin intact and tap msb formula first
([#462](#462))
([c808d74](c808d74))
* **install:** trust the microsandbox-acq dependency before brew install
([#534](#534))
([ffac0fa](ffac0fa))
* **kits:** land collapsed kit stack implementation
([#549](#549))
([bcd5b9c](bcd5b9c))
* **msb:** allow Playwright browser downloads
([#477](#477))
([0c399c5](0c399c5))
* **msb:** block unsafe 0.7 migration versions
([#510](#510))
([3634046](3634046))
* **msb:** carry every origin URL, keep the scratch private, fail closed
on a copy miss
([#488](#488))
([babcd49](babcd49))
* **msb:** carry the source checkout's git identity into the --clone
scratch
([#443](#443))
([320d784](320d784))
* **msb:** follow the host resolvers and disable DNS rebind protection
in the guest
([#444](#444))
([d2f4bdc](d2f4bdc))
* **msb:** point the --clone scratch's origin at the source checkout's
remote
([#455](#455))
([7f48b94](7f48b94))
* **msb:** refresh ssh authorization for port publish
([#446](#446))
([72a6bd5](72a6bd5))
* **msb:** session parity for exec/attach/shell (cwd, terminal identity,
login shell)
([#427](#427))
([6261eda](6261eda))
* **msb:** skip the recursive home chown when the image baked the agent
user
([#432](#432))
([d8f66a4](d8f66a4))
* **msb:** thread the merged kit env onto kit lifecycle commands
([#519](#519))
([2248a92](2248a92))
* **msb:** translate kit wildcard network rules
([#451](#451))
([e22bbc3](e22bbc3))
* **msb:** verify post-hoc port forward listener
([#530](#530))
([8ca50e1](8ca50e1))
* **msb:** warn on broadened kit wildcard rules
([#460](#460))
([6ded3ce](6ded3ce))
* **msb:** warn when ssh-agent route is missing
([#448](#448))
([3a767a4](3a767a4))
* **sbx:** emit valid setup.install shape for the git-identity mixin
([#492](#492))
([8e6160c](8e6160c))
* **sbx:** raise the version floor to 0.39.0, where sbx create --env
first exists
([#491](#491))
([30f9ecf](30f9ecf))
* **sbx:** wait for startup barrier before attach
([#512](#512))
([33c83c5](33c83c5))
* **secret:** reject multiline test secret values
([#447](#447))
([f2da950](f2da950))
* **secrets:** propagate rotation across backends
([#509](#509))
([9641958](9641958))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Bret Mogilefsky <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

msb: unconditional chown -R /home/agent adds minutes to create on images with a baked agent home

2 participants