Repository navigation
Fix /etc/passwd root home to match sandbox HOME - #113
Conversation
synth_user_group_config previously hardcoded root's home as /root in the synthesized /etc/passwd. Programs that read /etc/passwd (e.g. Go's user.Current().HomeDir got /root, which doesn't exist on the read-only sandbox rootfs — breaking tools like Pulumi on macOS. Now the caller passes the actual root home directory, which matches the HOME env var the sandbox sets (either /state/home for isolated sandboxes or the host /Users/bryan for bound-dir sandboxes). Fixes #94 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> EOF )
There was a problem hiding this comment.
iiuc this wires the homedir for the root user to the same home as the main user (uid 1000) ?
Processes in the sandbox run as uid 1000 (build), not root. user.Current() looks up the current uid in /etc/passwd, so fixing only root's home had no effect — build's home still pointed at a nonexistent /home/build path. Apply the computed home to both passwd entries so Go's user.Current().HomeDir works regardless of which uid ends up running (the sandbox sets HOME env var to the same value). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
You're asking the right question, and I was wrong about which user matters. I re-verified inside a fresh sandbox shell and processes actually run as I reproduced the current failure in gominimal/infra without the Same class of bug as the original I pushed a new commit that applies the computed home to both passwd entries so it works regardless of which uid ends up running. The sandbox already sets |
Verify both passwd entries (root and build) get the same home, matching the value passed in. Covers both the BoundDir case (host $HOME) and Isolated case (/state/home). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Processes run as uid 1000, so only that entry needs the fix. Leaving root's home as /root keeps the change minimal. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
Just pushed a smaller version: only the uid 1000 entry gets |
| let home = match &self.wd { | ||
| WdSetup::Isolated { .. } => "/state/home".to_string(), | ||
| WdSetup::BoundDir { .. } => { | ||
| std::env::var("HOME").unwrap_or_else(|_| "/state/home".to_string()) |
There was a problem hiding this comment.
use std::env::home_dir()
Per Tom's review feedback. home_dir() reads $HOME on Unix and falls back to the passwd database, which is more idiomatic than the manual env var lookup. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
A box records its project root, which listing and reading return. An exec into a box not running is refused with exit 2, runs under the box's ceilings, and a detached exec closes stdin. Open questions cite gominimal/arch#112 (prune --stopped) and #113 (override layer). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Re-pin the architecture link to gominimal/arch 823f45f, where every open question citing arch#97, #98, #99, #112, #113, #114 and #123 is merged, and turn those questions into citations. - BOX-163: refuse a held name only for a creation that asks for no fresh instance; a fresh instance is named <name>-<n> (arch#117). - BOX-071: project egress.deny_subnets as network.egress_deny_subnets (Gatehouse v1.26). - BOX-002 and the id-mint invariant: scoped to un-enrolled VM hosts; the STS mints on enrolled nodes (Gatehouse v1.27). - BOX-013 states the 10 s default grace; BOX-025's name refusal is exit 2 (arch#97 row 2). - BOX-165: the implicit [sessions.default] entry (arch#124), marked implicit by BOX-161 and covered by BOX-145's vectors. Three open questions remain: the NET/GWI reading (#2041), [params] delivery (arch#100) and exec_enabled, still proposed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CdRDynXbYoKR6dByN13KsD
…mal#1697) * docs(specs): add BOX, the local-first box spec from inbox#731 One record, one spec, one grammar for every session and task on a stock install: 146 EARS requirements across the box record and lifecycle, the Box Spec in minimal.toml and its deterministic expansion, the min box grammar with one-release aliases, memory admission, and the un-enrolled local provider. T1 property tests on expansion, type constraints and names; T2 Kani harnesses on the record state machine and admission arithmetic; the three local Box Provider API requirements wait on gominimal/arch#45. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(specs): link BOX open questions to gominimal/arch#97–gominimal#100 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(specs): fix box id entropy, rename events, detach stdout, name lookups Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(specs): split BOX into three siblings and apply review cycle 1 BOX keeps the record, the Box Spec and the grammar (122 requirements, ids stable with gaps). Resources move to 26-spec-box-resources (BRES, 13 requirements, T2 admission harnesses intact) and Box Volumes to 27-spec-box-volumes (BVOL, 8 requirements). The dash goes to an amendment of 07-spec-min-dash-tui, the local Box Provider API waits on gominimal/arch#45, and the test-suite meta-requirements are carried by every tier/verify line. Review cycle 1: resume hooks, the bare `min stop` alias window, the projection field set per Gatehouse 6.3.2, `min box spec self` as a nesting non-goal, the brokered-secret enforcer, the generality claim, stopped-record exit codes, a `detached` event, `min provider list --all` (BOX-147), and the first slice. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(specs): review cycle 2 and fold split cases under their parents Cycle 2 across the three siblings: [machine] and on_oom owned by BRES alone, BRES limits scoped to enforced hosts, volumes keyed by project (arch AT21) with an access mode and a hold that survives stop and resume, the type-noun verb aliases (BOX-148), ram_reserved against a resolved auto ram (BRES-015), and the BRES/gominimal#698 overlap recorded as an open question. BOX: 24 refusal and flag cases that were splits of a parent behaviour are now indented sub-bullets of that parent, tier and verify lines kept; references point at the parent. 99 top-level requirements. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(specs): review cycle 3 across BOX, BRES and BVOL BOX-076 admits BVOL-011's volume items; the min shell ambiguity case sits under BOX-090; parent tier lines precede their sub-bullets; the network non-goal range is corrected. BRES-006 covers an omitted ram, BRES-016 adds the advisory-host creation warning arch requires. BVOL mounts at /volumes/<name> (open question for arch) and BVOL-012 keeps prune off held volumes. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(specs): split the min grammar out of BOX into 28-spec-box-cli BOX now specifies the model only: the record, lifecycle, events, exec operations, the Box Spec and its expansion, and the un-enrolled path, with triggers stated as operations rather than verbs (60 requirements). BCLI carries the min box verb set, type nouns, shortcuts, exec flags, output schemas, exit codes, the one-release alias window, docs, and the host and provider commands (52 requirements), each binding to a BOX operation by id and carrying the BOX id it came from. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(specs): consistency pass across BOX, BCLI, BRES and BVOL Exec client loss scoped to non-PTY, non-detached execs; a stopped box's "exists" mapped onto NET-013/015 with an open question for NET and GWI; min box rename bound (BCLI-058) and the alias table completed, with session destroy mapping to box rm --force so BEP-043 still fires; the stop, rm, prune, cp and events verbs bound to their BOX operations (BCLI-059 to 062); verbs removed from the model's remaining text; task end keyed on lifetime; a running record on daemon restart becomes stopped (BOX-154); detached output capture (BOX-155); legacy mode spellings named; stored exit codes stated; BRES-004's reservation cap takes arch's overcommit-policy value; BVOL's hold and bare-name decisions recorded as the owner's. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(specs): review cycle 5: NET "exists" means running, stored signals NET-013/015 and GWI-005's "exists" now maps to the running state and "destroyed" to leaving it; a stopped box is neither kept running nor answers its name. A signal-ended stop stores the signal and min box wait returns 128 + signal (137 for a record the daemon restart marked stopped). The restart-to-stopped and host-stop-stops-boxes-first choices are recorded as the owner's; the bare-volume-name reason matches the record. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(specs): read NET's destroyed as reaped; stopped names answer NODATA Per NET-128 and the networking design §7.1 a not-running box keeps its name in the zone and answers NODATA; NXDOMAIN starts at reap. Resume and name reuse need NET to register at resume as well as at finalise; the open question asks NET and GWI to confirm. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(specs): answer NXDOMAIN at reap only for the last holder of a name A reused name follows its remaining holder (A if running, NODATA if not); own-address NODATA is put to NET as a question; resume cites BOX-025 and BOX-030. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(specs): refuse resume while a running box holds the name NODATA applies while no running box holds a name; BOX-004's property covers resume; BOX-025 refuses a resume whose name a running box holds and BCLI reports it with exit 2 and a rename hint. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(specs): consistency pass over the box specs, cycle 10 Accepted keys are arch's box.toml plus the additions this spec names; legacy mode spellings canonicalise into the spec and expire with the legacy tables; prune reaps only stopped or exited boxes matching all selectors; NET-015's stop list gains timeout, on_oom end_box and entrypoint return; resume applies to any pty_enabled box; the --network/--ingress overrides are the last expansion layer; provider aliases expire with the rest; secrets render as references in every output mode (BCLI-063); issue citations point at the arch#97/gominimal#98 comments that now carry the items. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(specs): min box spec takes the override flags; volume hold ends on exit min box spec <entry> accepts --network and --ingress through the same last expansion layer as start, so the pre-flight render is what the daemon receives. A volume write hold is kept while a box is stopped and released when it reaches exited or is reaped (owner decision), so a task re-runs at once; resume from exited while another box holds the volume is refused with exit 5 (BVOL-013). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(specs): overrides in the expansion properties; resume after volume removal The T1 properties for byte-identical and enrolment-invariant expansion range over command-line overrides too. A resumed box whose volume was removed while it was exited gets a fresh volume created and reattached by project and name. The name-conflict check on resume runs before the volume-hold check, so a resume meeting both exits 2. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(specs): order the resume refusals: PTY check, name check, volume hold BVOL-013 applies only to pty_enabled boxes and runs after BOX-030 and BOX-025's name check; BCLI-007 and BCLI-009 cite that order. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(specs): place the unsatisfiable-spec check in the resume refusal order BOX-025 states the full order once (PTY, name, spec, volume hold); BVOL-013 and BCLI cite it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(specs): min session attach aliases the top-level min attach shortcut Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(specs): the volumes first slice includes the single-writer refusal Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(specs): qualify the fresh-volume claim on resume after removal Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(specs): write the roles lines as prose, not a concatenation Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(specs): an address that resolves to no box exits 4 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(specs): close the arch consistency findings on the box specs Type constraints are checked against the expanded spec and a derived type may not loosen its parent (BOX-061, BOX-156). The flat egress keys the arch examples write get one release of hint-and-canonicalise grace (BOX-157). Rename refuses a held or reserved name (BOX-010) and name resolution is per host with a cross-host ambiguity refusal (BOX-005). Volumes drop the read-only mode until object storage lands and the expanded list is deduplicated by name (BVOL-014). OOM kills end the box per on_oom (BRES-017, BRES-018). min shell --new takes a suffixed name (BCLI-065), min session run is a usage error (BCLI-066), the attached exec id goes to stderr and min box show lists live execs (BCLI-067). BCLI-041 and BCLI-050 duplicated the alias table and are removed; BOX-021 drops the no-op stopped selector. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(specs): settle the BRES split with the guest-memory epic BRES owns admission, the memory limit write, its read-only surface and exec-join (BRES-004 to BRES-009); inbox#698 keeps the guest size, swap, the cgroup2 mount and daemon reserve, pressure warnings, the shell banner and the min ls headroom line. Its S3b clamp rule gives way to BRES-004/005's refusal with figures. Closes the two clarification markers that named the overlap. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(specs): move the resources spec to inbox#698 Resources now belong to gominimal/inbox#698, which will get a fresh BRES spec. BOX and BCLI cite that spec by id without requirement numbers. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(specs): move BVOL and BCLI to their own PRs The volumes and CLI specs now land separately (docs/spec-box-volumes and docs/spec-box-cli) so the BOX model spec is reviewed on its own; both files are byte-identical on their new branches. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(specs): date the BOX spec to its last revision Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(specs): pin the BOX spec's arch link to a commit Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(specs): align BOX-011 with BOX-154 and split BOX-152's event fields Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(specs): apply the BOX arch-conformance review decisions Map the projection onto Gatehouse 6.3.2's field names with the defaults filled before canonicalisation and a base64url digest; scope BOX-001's host-side minting to the box_id; add the daemon's admission constraint check (BOX-160), record listing and reading (BOX-158, BOX-159) for the first slice, and per-value provenance (BOX-161); state the exec contract, every process in the box, and BOX-040's triggers; raise BOX-001 and BOX-072 to T1 and justify the T0 security requirements; name owners for attribute rules, runtime spec change, org types and the unenforced sections, which now warn at creation. Co-Authored-By: Claude Opu 8000 s 5.5 (1M context) <noreply@anthropic.com> * docs(specs): limit BOX-160's admission check to the built-in root Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * docs(specs): drop the daily shortcuts from BOX's grammar non-goal BCLI no longer specifies min shell, min run, min attach or min ls; they are UX work layered on the grammar, so the non-goal names the long forms and the type nouns only. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(specs): credit the OOM end to BRES and cite the DNS reading once Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(specs): re-transcribe BOX's resume and task-run stories The epic now names min session attach, min box resume and min task run in S3 and S4 instead of the daily shortcuts. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(specs): spell out BOX id ranges that span unused numbers Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(specs): renumber the BOX spec to 29, clear of gominimal#1586 and gominimal#1988 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(specs): settle BOX's first-slice type, parent and event reads The first slice records the type from the creating verb. A box created from outside any box has no parent. Events carry box, parent, timestamp and type, and BOX-162 reads the full retained stream and follows it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(specs): record BOX's project root and bound exec to running boxes A box records its project root, which listing and reading return. An exec into a box not running is refused with exit 2, runs under the box's ceilings, and a detached exec closes stdin. Open questions cite gominimal/arch#112 (prune --stopped) and gominimal#113 (override layer). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(specs): limit BOX expansion to sessions and tasks; log from start BOX-046 and BOX-063 expand only session and task entries and refuse the other four built-in types with exit 3 naming gominimal/inbox#678. BOX-155 logs a box's output from its start, attached or not. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(specs): tabulate BOX-011's end data and tidy BOX's minor findings BOX-011's end data and BOX-076's added keys become tables. Timeout and exec client loss end with SIGTERM, a wait, then SIGKILL. The network non-goal points at Design reasoning, and the VM host is local-minvmd0. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(specs): state BOX-001's type property for both creation paths Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(specs): let a BOX exec carry its own timeout A BOX-149 sub-bullet ends an exec at its own timeout with BOX-150's sequence, records exec_exited with reason timeout, and keeps the box running. Design reasoning and the arch-gap open question record it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(specs): date BOX to 2026-10-06 and mark O3 as moved to BCLI Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(specs): cite gominimal/arch#114 for BOX's per-exec timeout gap Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(specs): apply msample's five BOX findings BOX-063 refuses the four excluded types per entry, and BOX-145's vectors are the arch example's session and task entries. BOX-163 names a box at creation and refuses a running holder with exit 2 (gominimal/arch#122). Project file rules are left out like secret-store rules (arch#123). BOX-164 puts the record and log out of the box's reach. Expansion writes store references' upstream and inject into the spec for the projection. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(specs): scope BOX-010's property to successful renames Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(specs): cite BOX-151 for exec timeouts; add store rules to parity The exec-timeout sub-bullet cites BOX-151, which owns the end sequence. BOX-065 and BOX-142 take the client's [secret-store-rules] set as an input, since expansion now resolves store references from it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(specs): name the boxes crate in BOX's verify commands The sessions crate is being renamed to boxes before BOX is implemented, so that the crate holding the box domain types says box. Point BOX's ten `cargo nextest run -p sessions` checks at `-p boxes`. The test names are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CdRDynXbYoKR6dByN13KsD * docs(specs): re-pin BOX to arch 823f45f and adopt its rulings Re-pin the architecture link to gominimal/arch 823f45f, where every open question citing arch#97, gominimal#98, gominimal#99, gominimal#112, gominimal#113, gominimal#114 and gominimal#123 is merged, and turn those questions into citations. - BOX-163: refuse a held name only for a creation that asks for no fresh instance; a fresh instance is named <name>-<n> (arch#117). - BOX-071: project egress.deny_subnets as network.egress_deny_subnets (Gatehouse v1.26). - BOX-002 and the id-mint invariant: scoped to un-enrolled VM hosts; the STS mints on enrolled nodes (Gatehouse v1.27). - BOX-013 states the 10 s default grace; BOX-025's name refusal is exit 2 (arch#97 row 2). - BOX-165: the implicit [sessions.default] entry (arch#124), marked implicit by BOX-161 and covered by BOX-145's vectors. Three open questions remain: the NET/GWI reading (gominimal#2041), [params] delivery (arch#100) and exec_enabled, still proposed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CdRDynXbYoKR6dByN13KsD * docs(specs): move NET's sentences back to its Non-goals bullet Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CdRDynXbYoKR6dByN13KsD --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Summary
synth_user_group_confighardcoded root's home as/rootin synthesized/etc/passwduser.Current().HomeDirreads/etc/passwd(ignores$HOME), gets/root, which doesn't exist on read-only sandbox rootfsHOMEenv var the sandbox setsNo behavior change on Linux —
/roothappened to exist there, but the value was still wrong. Now it's correct on both platforms.Fixes #94
Changes
common/src/lib.rs:synth_user_group_configtakes aroot_homeparametersandbox2/src/config.rs: computes root home fromWdSetup(isolated =/state/home, bound = host$HOME)Tests
65 tests pass (common + graph), fmt + clippy clean in minimal container.
Generated with Claude Code