Skip to content

chore: updating home dirs to not use root#185

Merged
chatton merged 8 commits into
mainfrom
cian/update-root-user
May 14, 2026
Merged

chore: updating home dirs to not use root#185
chatton merged 8 commits into
mainfrom
cian/update-root-user

Conversation

@chatton
Copy link
Copy Markdown
Collaborator

@chatton chatton commented Mar 18, 2026

Overview

ref evstack/ev-node#3082

Summary by CodeRabbit

  • New Features

    • Fluent options to override container home directories for chains, networks, and node builders.
  • Chores

    • Introduced and standardized default container home directories across components.
    • Container images now carry explicit UID:GID mappings to ensure consistent runtime ownership.
  • Bug Fixes

    • More robust concurrent node start/stop/remove handling for reliable network lifecycle operations.

Review Change Stack

@chatton chatton requested a review from tty47 as a code owner March 18, 2026 08:44
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 18, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 347942a8-7a9e-465f-b974-05bd382de1ee

📥 Commits

Reviewing files that changed from the base of the PR and between 0d373f0 and f7a3d82.

📒 Files selected for processing (3)
  • framework/docker/container/node.go
  • framework/docker/hyperlane/hyperlane_config.go
  • framework/docker/ibc_test.go

📝 Walkthrough

Walkthrough

Plumbs customizable container home directories across evstack, dataavailability, and cosmos builders/nodes, adds DefaultHomeDir helpers, and updates container user handling and evmsingle default image UIDGID.

Changes

HomeDir plumbing

Layer / File(s) Summary
evmsingle: config, builder, node
framework/docker/evstack/evmsingle/config.go, framework/docker/evstack/evmsingle/builder.go, framework/docker/evstack/evmsingle/node.go
Adds Config.HomeDir and DefaultHomeDir(), builder homeDir/WithHomeDir, populates Config.HomeDir during Build, newNode uses cfg.HomeDir; DefaultImage() now includes UIDGID.
evstack: package defaults & NewNode
framework/docker/evstack/config.go, framework/docker/evstack/node.go, framework/docker/evstack/chain_builder.go
Adds package-level DefaultHomeDir() and Config.HomeDir; NewNode accepts/resolves homeDir and forwards it to container.NewNode; ChainBuilder wiring to inject HomeDir.
reth: builder, config, node
framework/docker/evstack/reth/config.go, framework/docker/evstack/reth/builder.go, framework/docker/evstack/reth/node.go
Adds Config.HomeDir and DefaultHomeDir(), NodeBuilder.homeDir/WithHomeDir, and passes resolved HomeDir into container.NewNode.
spamoor: builder & node
framework/docker/evstack/spamoor/builder.go, framework/docker/evstack/spamoor/node.go
Adds Builder.homeDir and WithHomeDir, DefaultHomeDir(), and forwards homeDir into newNode and container.NewNode.
dataavailability: config, builder, node, network
framework/docker/dataavailability/config.go, framework/docker/dataavailability/network_builder.go, framework/docker/dataavailability/node.go, framework/docker/dataavailability/network.go
Adds Config.HomeDir and DefaultHomeDir(), NetworkBuilder.WithHomeDir wiring into node Config; NewNode derives homeDir from cfg.HomeDir with fallback; Network Start/Stop/Remove use errgroup with correct loop-var capture.
cosmos: ChainBuilder override
framework/docker/cosmos/chain_builder.go
Adds homeDir to ChainBuilder, WithHomeDir setter; newDockerChainNode prefers builder homeDir when set, otherwise previous defaults.
misc: container create, exec, imports, tests, small fixes
framework/docker/container/lifecycle.go, framework/docker/container/node.go, framework/docker/container/job.go, framework/docker/internal/keyring.go, framework/docker/reth_test.go, framework/docker/da_network_test.go, framework/docker/ibc/relayer/hermes_types.go, framework/docker/hyperlane/hyperlane_config.go, framework/docker/ibc_test.go
CreateContainer builds containerCfg and conditionally sets User from image.UIDGID; Node.Exec sets Docker User; minor import reorderings, test formatting, closing-brace fix, and a few image UIDGID changes (root) for containers that require it.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • mojtaba-esk
  • tty47

Poem

🐰 I hopped through builders late at night,

Tucked HomeDirs in containers snug and tight,
Builders pass defaults, nodes learn the way,
UIDGID on images helps them stay,
Now tests and containers cozy — hurray!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 63.64% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'chore: updating home dirs to not use root' is partially related to the changeset. While the PR does involve changes related to home directories and user/UID management, the title is somewhat misleading—the primary changes actually add configurable home directory support and propagate UIDGID settings, rather than specifically 'not using root.' The title captures only one aspect of a broader refactoring.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cian/update-root-user

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@framework/docker/evstack/evmsingle/config.go`:
- Around line 27-29: DefaultImage sets UIDGID to "10001:10001" but the container
runtime user isn't set, causing permission mismatches; update CreateContainer to
set container.Config.User = image.UIDGID (where image is the container.Image
passed into CreateContainer) so the runtime user matches the volume owner
configured by SetOwner(), ensuring DefaultImage(), UIDGID, CreateContainer,
container.Config and SetOwner are consistent; alternatively document in
DefaultImage that the upstream image already runs as UID 10001 if you choose not
to set User programmatically.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 37c9b244-832b-4869-a619-7ec6eb759c2e

📥 Commits

Reviewing files that changed from the base of the PR and between 227152d and 8856403.

📒 Files selected for processing (2)
  • framework/docker/evstack/evmsingle/config.go
  • framework/docker/evstack/evmsingle/node.go

Comment thread framework/docker/evstack/evmsingle/config.go
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
framework/docker/cosmos/chain_builder.go (1)

183-203: Consider copying homeDir in NewChainBuilderFromChain.

When creating a builder from an existing chain, other configuration values are copied (e.g., Name, ChainID, Bin), but homeDir is not included. If the original chain used a custom home directory, the new builder will use the default instead.

This may be intentional, but worth verifying whether consistency is desired here.

💡 Suggested addition if homeDir should be preserved

You would need to store homeDir in ChainConfig and copy it:

// After line 202, add:
WithHomeDir(cfg.HomeDir)

This requires adding a HomeDir field to ChainConfig as well.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@framework/docker/cosmos/chain_builder.go` around lines 183 - 203,
NewChainBuilderFromChain currently copies many fields from Chain.Config but
omits homeDir; add a HomeDir string field to the ChainConfig struct and update
NewChainBuilderFromChain to call WithHomeDir(cfg.HomeDir) on the ChainBuilder so
the builder preserves custom home directories; ensure the ChainBuilder has a
WithHomeDir method (or add one) to accept and store the HomeDir value.
framework/docker/evstack/spamoor/node.go (1)

49-52: Consider adding a DefaultHomeDir() helper for consistency.

The hardcoded default "/home/spamoor" works correctly, but other modules in this PR (reth, evmsingle, dataavailability, evstack) define a DefaultHomeDir() function. Adding one here would improve maintainability and consistency.

♻️ Suggested refactor

Add to this file or a separate config.go:

// DefaultHomeDir returns the default home directory for spamoor containers.
func DefaultHomeDir() string {
    return "/home/spamoor"
}

Then update the defaulting logic:

 func newNode(ctx context.Context, cfg Config, testName string, index int, name string, homeDir string) (*Node, error) {
     if homeDir == "" {
-        homeDir = "/home/spamoor"
+        homeDir = DefaultHomeDir()
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@framework/docker/evstack/spamoor/node.go` around lines 49 - 52, Add a
DefaultHomeDir() helper that returns "/home/spamoor" (e.g., in this file or a
new config.go) and update newNode to call DefaultHomeDir() instead of hardcoding
the string; specifically, add the function DefaultHomeDir() and change the
defaulting branch in newNode (the homeDir == "" check) to set homeDir =
DefaultHomeDir() so the module follows the same pattern as
reth/evmsingle/dataavailability/evstack.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@framework/docker/cosmos/chain_builder.go`:
- Around line 183-203: NewChainBuilderFromChain currently copies many fields
from Chain.Config but omits homeDir; add a HomeDir string field to the
ChainConfig struct and update NewChainBuilderFromChain to call
WithHomeDir(cfg.HomeDir) on the ChainBuilder so the builder preserves custom
home directories; ensure the ChainBuilder has a WithHomeDir method (or add one)
to accept and store the HomeDir value.

In `@framework/docker/evstack/spamoor/node.go`:
- Around line 49-52: Add a DefaultHomeDir() helper that returns "/home/spamoor"
(e.g., in this file or a new config.go) and update newNode to call
DefaultHomeDir() instead of hardcoding the string; specifically, add the
function DefaultHomeDir() and change the defaulting branch in newNode (the
homeDir == "" check) to set homeDir = DefaultHomeDir() so the module follows the
same pattern as reth/evmsingle/dataavailability/evstack.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e153db36-0a1e-43f5-bc5a-089a252392ca

📥 Commits

Reviewing files that changed from the base of the PR and between 8856403 and 5531019.

📒 Files selected for processing (15)
  • framework/docker/cosmos/chain_builder.go
  • framework/docker/dataavailability/config.go
  • framework/docker/dataavailability/network_builder.go
  • framework/docker/dataavailability/node.go
  • framework/docker/evstack/chain_builder.go
  • framework/docker/evstack/config.go
  • framework/docker/evstack/evmsingle/builder.go
  • framework/docker/evstack/evmsingle/config.go
  • framework/docker/evstack/evmsingle/node.go
  • framework/docker/evstack/node.go
  • framework/docker/evstack/reth/builder.go
  • framework/docker/evstack/reth/config.go
  • framework/docker/evstack/reth/node.go
  • framework/docker/evstack/spamoor/builder.go
  • framework/docker/evstack/spamoor/node.go

chatton added 3 commits May 13, 2026 10:24
Move homeDir from bare function parameter into Config structs for
dataavailability and evstack packages, matching the pattern already
used by evmsingle and reth. Add DefaultHomeDir() to spamoor for
consistency. Fix spaces-to-tabs formatting across several files.
@chatton chatton force-pushed the cian/update-root-user branch from 5531019 to ad70f93 Compare May 13, 2026 10:00
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
framework/docker/evstack/chain_builder.go (1)

154-163: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Propagate HomeDir into chain-level config in Build().

newNode() receives b.homeDir, but Build() drops it from Chain.cfg. That can silently lose the override for any path that reads chain.cfg.HomeDir.

Suggested fix
 	return &Chain{
 		cfg: Config{
 			Logger:               b.logger,
 			DockerClient:         b.dockerClient,
 			DockerNetworkID:      b.dockerNetworkID,
 			ChainID:              b.chainID,
 			Env:                  b.env,
 			Bin:                  b.binaryName,
 			AggregatorPassphrase: b.aggregatorPassphrase,
 			Image:                *b.dockerImage,
+			HomeDir:              b.homeDir,
 		},
 		log:   b.logger,
 		nodes: nodes,
 	}, nil
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@framework/docker/evstack/chain_builder.go` around lines 154 - 163, The Chain
config built in Build() is missing the HomeDir field so any override passed via
b.homeDir isn't propagated; update the Config literal assigned to cfg in Build()
(the Config used to construct Chain.cfg) to include HomeDir: b.homeDir so that
Chain.cfg.HomeDir is set, keeping newNode() unchanged (it already receives
b.homeDir). Ensure you set the HomeDir field on the Config struct used when
creating the Chain so downstream code reading Chain.cfg.HomeDir sees the
override.
framework/docker/dataavailability/network_builder.go (2)

160-169: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Store HomeDir in the Network's Config.

The Build method doesn't include HomeDir in the Network.cfg that it creates. This field is needed so that NewNetworkBuilderFromNetwork can later retrieve the home directory when adding nodes dynamically. Without this, the fix suggested in the NewNetworkBuilderFromNetwork comment cannot work.

🔧 Proposed fix
 	return &Network{
 		cfg: Config{
 			Logger:          b.logger,
 			DockerClient:    b.dockerClient,
 			DockerNetworkID: b.dockerNetworkID,
 			ChainID:         b.chainID,
 			Env:             b.env,
 			Bin:             b.binaryName,
 			Image:           *b.dockerImage,
+			HomeDir:         b.homeDir,
 		},
 		log:         b.logger,
 		nodeMap:     nodeMap,
 		nextNodeIdx: len(nodeMap), // start from the number of initial nodes
 		testName:    b.testName,   // store original test name for dynamic node naming
 	}, nil
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@framework/docker/dataavailability/network_builder.go` around lines 160 - 169,
The Network built in Build() omits the Config.HomeDir so
NewNetworkBuilderFromNetwork can't retrieve the home directory later; update the
Network construction in Build to set Config.HomeDir (e.g., add HomeDir:
b.homeDir) alongside Logger, DockerClient, DockerNetworkID, ChainID, Env, Bin
and Image so the Network.cfg contains the home directory for downstream use by
NewNetworkBuilderFromNetwork.

63-74: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Preserve homeDir when creating builder from existing network.

NewNetworkBuilderFromNetwork doesn't copy homeDir from the original network configuration. When this function is used to add nodes dynamically (via Network.AddNodes), new nodes will use DefaultHomeDir() instead of inheriting the home directory from existing nodes, creating inconsistent state within a single network.

For example:

  1. Create network with WithHomeDir("/custom/path")
  2. Initial nodes correctly use /custom/path
  3. Later call AddNodes to add more nodes
  4. New nodes use /home/celestia (default) instead of /custom/path
🔧 Proposed fix
 func NewNetworkBuilderFromNetwork(network *Network) *NetworkBuilder {
 	return &NetworkBuilder{
 		testName:            network.testName,
 		logger:              network.log,
 		dockerClient:        network.cfg.DockerClient,
 		dockerNetworkID:     network.cfg.DockerNetworkID,
 		dockerImage:         &network.cfg.Image,
 		additionalStartArgs: network.cfg.AdditionalStartArgs,
 		env:                 network.cfg.Env,
 		chainID:             network.cfg.ChainID,
 		binaryName:          network.cfg.Bin,
+		homeDir:             network.cfg.HomeDir,
 	}
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@framework/docker/dataavailability/network_builder.go` around lines 63 - 74,
NewNetworkBuilderFromNetwork currently omits copying the homeDir from the source
Network, so builders created for AddNodes end up using DefaultHomeDir(); update
NewNetworkBuilderFromNetwork to set the NetworkBuilder.homeDir from
network.cfg.HomeDir (or the existing configured value) when constructing the
builder so new nodes inherit the original home directory instead of falling back
to DefaultHomeDir(); modify the constructor that returns &NetworkBuilder{...} to
include homeDir: network.cfg.HomeDir (or equivalent field) while leaving other
behavior unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@framework/docker/dataavailability/network_builder.go`:
- Around line 160-169: The Network built in Build() omits the Config.HomeDir so
NewNetworkBuilderFromNetwork can't retrieve the home directory later; update the
Network construction in Build to set Config.HomeDir (e.g., add HomeDir:
b.homeDir) alongside Logger, DockerClient, DockerNetworkID, ChainID, Env, Bin
and Image so the Network.cfg contains the home directory for downstream use by
NewNetworkBuilderFromNetwork.
- Around line 63-74: NewNetworkBuilderFromNetwork currently omits copying the
homeDir from the source Network, so builders created for AddNodes end up using
DefaultHomeDir(); update NewNetworkBuilderFromNetwork to set the
NetworkBuilder.homeDir from network.cfg.HomeDir (or the existing configured
value) when constructing the builder so new nodes inherit the original home
directory instead of falling back to DefaultHomeDir(); modify the constructor
that returns &NetworkBuilder{...} to include homeDir: network.cfg.HomeDir (or
equivalent field) while leaving other behavior unchanged.

In `@framework/docker/evstack/chain_builder.go`:
- Around line 154-163: The Chain config built in Build() is missing the HomeDir
field so any override passed via b.homeDir isn't propagated; update the Config
literal assigned to cfg in Build() (the Config used to construct Chain.cfg) to
include HomeDir: b.homeDir so that Chain.cfg.HomeDir is set, keeping newNode()
unchanged (it already receives b.homeDir). Ensure you set the HomeDir field on
the Config struct used when creating the Chain so downstream code reading
Chain.cfg.HomeDir sees the override.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 74d55a87-29de-4f31-9b38-092d303d9b47

📥 Commits

Reviewing files that changed from the base of the PR and between 5531019 and ad70f93.

📒 Files selected for processing (21)
  • framework/docker/container/job.go
  • framework/docker/cosmos/chain_builder.go
  • framework/docker/da_network_test.go
  • framework/docker/dataavailability/config.go
  • framework/docker/dataavailability/network.go
  • framework/docker/dataavailability/network_builder.go
  • framework/docker/dataavailability/node.go
  • framework/docker/evstack/chain_builder.go
  • framework/docker/evstack/config.go
  • framework/docker/evstack/evmsingle/builder.go
  • framework/docker/evstack/evmsingle/config.go
  • framework/docker/evstack/evmsingle/node.go
  • framework/docker/evstack/node.go
  • framework/docker/evstack/reth/builder.go
  • framework/docker/evstack/reth/config.go
  • framework/docker/evstack/reth/node.go
  • framework/docker/evstack/spamoor/builder.go
  • framework/docker/evstack/spamoor/node.go
  • framework/docker/ibc/relayer/hermes_types.go
  • framework/docker/internal/keyring.go
  • framework/docker/reth_test.go
✅ Files skipped from review due to trivial changes (5)
  • framework/docker/reth_test.go
  • framework/docker/container/job.go
  • framework/docker/ibc/relayer/hermes_types.go
  • framework/docker/internal/keyring.go
  • framework/docker/da_network_test.go
🚧 Files skipped from review as they are similar to previous changes (10)
  • framework/docker/evstack/evmsingle/node.go
  • framework/docker/evstack/reth/builder.go
  • framework/docker/evstack/reth/node.go
  • framework/docker/evstack/spamoor/node.go
  • framework/docker/evstack/evmsingle/config.go
  • framework/docker/evstack/evmsingle/builder.go
  • framework/docker/evstack/spamoor/builder.go
  • framework/docker/evstack/reth/config.go
  • framework/docker/evstack/node.go
  • framework/docker/cosmos/chain_builder.go

chatton added 5 commits May 13, 2026 11:16
Volume ownership was set via UIDGID but the container runtime user
was not, causing containers to run as root while volumes were owned
by a different UID. Setting User in container.Config ensures the
runtime user matches the volume owner.
Setting User to empty string overrides the image USER directive
and forces the container to run as root. Only set it when UIDGID
is non-empty to preserve the image default.
Pass image UIDGID as User in Node.Exec so init commands run as the
same user as the main container, preventing file ownership mismatches.

Remove UIDGID from ibc-go-simd test image since simd writes to
$HOME/.simapp on startup which fails as non-root.
Binary writes to /app/storage/ outside the volume mount, requires root.
@chatton chatton added this pull request to the merge queue May 13, 2026
@github-merge-queue github-merge-queue Bot removed this pull request from the merge queue due to failed status checks May 13, 2026
@chatton chatton merged commit 287782e into main May 14, 2026
6 checks passed
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.

2 participants