feat(containers): per-container user/group/homeDir + config-only isBuilding (RIG-2404) - #4
Merged
Conversation
…ilding (RIG-2404) Ports the Compass agent-image patch set onto `src/modules/containers.nix` so this shared canonical fork carries the container-identity machinery the Compass agent base image needs. This is the L0a slice of the compass forks-reversal (RIG-2336): the patch that lived as a vendored subtree in `compass/forks/devenv/` moves here, into the fork repo it belongs to. ## What changes (all in `src/modules/containers.nix`) - **Per-container `user` / `group` / `homeDir` options.** Upstream hardcodes user `user` with `$HOME=/env` module-wide; these move the passwd/group/shadow rows, the file-ownership `perms`, and the image config's `User`/`HOME`/`USER` together per container. **Upstream's values are kept as the defaults** (`user`, `/env`), so a consumer that sets none of them resolves to a byte-identical image — the identity is preserved by construction (the parameterized script bodies keep upstream's exact bytes, including line breaking, since a comment inside `runCommand`'s text is part of the build command and shifts the derivation hash on its own). - **Config-only `buildingContainer` / `buildingHomeDir` lookup**, replacing the impure `envContainerName = builtins.getEnv "DEVENV_CONTAINER"` and the two config blocks it drove. The env path is dead: the nix backend already forces both `container.isBuilding` and `containers.<name>.isBuilding` (`lib.mkForce true`), and nothing in the tree writes `DEVENV_CONTAINER`. Reading identity out of an impure `getEnv` while the options already carry it is two sources of truth; the config-only lookup keeps one. - **`config.env` serialized directly** into the image config `Env` (plus `HOME`/`USER` from the resolved identity), matching the merged base. No `DEVENV_`-prefix filter in the module: a reusable module applies the minimal fix, not a blanket namespace strip. The one real leak (`DEVENV_PROFILE`, an absolute `/nix/store` path that acts as a closure root) is neutralized consumer-side, gated on `isBuilding`, exactly as orion already ships it — so this module stays byte-faithful to the currently-shipping image and a future consumer can drop its own override once every consumer relies on the module default. ## Base & verification Rebased onto this fork's current `main` (`1a7cae09`, the merged writable-`$HOME` change RIG-2368), not cherry-picked from the vendored bytes — the identity was re-established against the merged base. **Byte-identity nix-eval check (the gate the design requires):** a default-identity container (`copyToRoot = [ ]`, no user/group/homeDir override) resolves to the *same* image-spec store path on both this patched tree and the unpatched base — `myvgpmpylndahwlza46mr4bqkfjhw4nd-image-devenv-shell-probe.json`. The refactor is proven-pure for the default path; upstream devenv CI does not exercise the `$HOME` property, so this check — not the fork repo's own CI — is what proves the port. Spec-impact: none. Refs RIG-2404 Co-authored-by: Matt Wilkinson <matt@rigel.build>
🔍 Suggested ReviewersBased on git blame analysis of the changed lines, the following contributors have significant experience with the modified code:
Please consider reviewing this PR as you have authored significant portions of the code being modified. Your expertise would be valuable! 🙏 This comment was automatically generated by git-blame-auto-reviewer Last updated: 2026-08-21T21:33:44.067Z |
…tions
The container-identity patch (per-container user/group/homeDir +
config-only isBuilding) adds module options that the docs generator
reflects into docs/src/reference/options.md. Regenerate via
`devenv shell devenv-generate-doc-options` so the options reference
carries the new containers.<name>.{user,group,homeDir,isBuilding}
entries and the generate-docs CI check passes.
Generated, not hand-edited (header: DO NOT MODIFY).
rigel-mintaka
marked this pull request as ready for review
August 21, 2026 22:07
mattwilkinsonn
approved these changes
Aug 22, 2026
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.
Ports the Compass agent-image patch set onto
src/modules/containers.nixso this shared canonical fork carries the container-identity machinery the Compass agent base image needs. This is the L0a slice of the compass forks-reversal (RIG-2336): the patch that lived as a vendored subtree incompass/forks/devenv/moves here, into the fork repo it belongs to.What changes (all in
src/modules/containers.nix)user/group/homeDiroptions. Upstream hardcodes useruserwith$HOME=/envmodule-wide; these move the passwd/group/shadow rows, the file-ownershipperms, and the image config'sUser/HOME/USERtogether per container. Upstream's values are kept as the defaults (user,/env), so a consumer that sets none of them resolves to a byte-identical image — the identity is preserved by construction (the parameterized script bodies keep upstream's exact bytes, including line breaking, since a comment insiderunCommand's text is part of the build command and shifts the derivation hash on its own).buildingContainer/buildingHomeDirlookup, replacing the impureenvContainerName = builtins.getEnv "DEVENV_CONTAINER"and the two config blocks it drove. The env path is dead: the nix backend already forces bothcontainer.isBuildingandcontainers.<name>.isBuilding(lib.mkForce true), and nothing in the tree writesDEVENV_CONTAINER. Reading identity out of an impuregetEnvwhile the options already carry it is two sources of truth; the config-only lookup keeps one.config.envserialized directly into the image configEnv(plusHOME/USERfrom the resolved identity), matching the merged base. NoDEVENV_-prefix filter in the module: a reusable module applies the minimal fix, not a blanket namespace strip. The one real leak (DEVENV_PROFILE, an absolute/nix/storepath that acts as a closure root) is neutralized consumer-side, gated onisBuilding, exactly as orion already ships it — so this module stays byte-faithful to the currently-shipping image and a future consumer can drop its own override once every consumer relies on the module default.Base & verification
Rebased onto this fork's current
main(1a7cae09, the merged writable-$HOMEchange RIG-2368), not cherry-picked from the vendored bytes — the identity was re-established against the merged base.Byte-identity nix-eval check (the gate the design requires): a default-identity container (
copyToRoot = [ ], no user/group/homeDir override) resolves to the same image-spec store path on both this patched tree and the unpatched base —myvgpmpylndahwlza46mr4bqkfjhw4nd-image-devenv-shell-probe.json. The refactor is proven-pure for the default path; upstream devenv CI does not exercise the$HOMEproperty, so this check — not the fork repo's own CI — is what proves the port.CI status (triaged)
generate-docs— success. This is the defect L0a targets: the workflow'sEndBug/add-and-commitauto-commit step is push-gated and 403s undergithub-actions[bot], so the regenerateddocs/genoptions were committed locally in this PR. Green confirms the regen matches.assign-reviewers— success.pipeline (aarch64-linux | x86_64-linux | aarch64-darwin) / build— queued indefinitely, expected. These legs requireself-hostedrunners (pr-test.ymlmatrix:["self-hosted", "linux", "ARM64"]etc.) from the upstream devenv fleet that this fork does not have —runnerNamenever assigns. "PR Test" has never completed on this repo (all historical runscancelled/queued). This is an environment gap, not a code defect. They are not merge-blocking:mainhas no branch protection (404) and no rulesets (gh api .../rules/branches/main→ empty).Spec-impact: none. Refs RIG-2404
Co-authored-by: Matt Wilkinson matt@rigel.build