Skip to content

fix: CreateUser uses wrong /etc path for composefs-native installs #5

Description

@castrojo

Summary

CreateUser in internal/post/user.go uses root = sysroot for composefs-native deployments, but sysroot/etc/ is a ghost btrfs directory — writes to it are silently discarded after first boot.

Root cause

// user.go:30
if isComposeFsNative(sysroot) {
    root = sysroot  // WRONG: sysroot/etc is not writable after boot
} else {
    deployDir, _ := DeploymentDirFn(sysroot)
    root = deployDir  // correct for ostree
}

On composefs-native systems:

  • The writable /etc is bind-mounted from state/deploy/<HASH>/etc/
  • sysroot/etc/ is an orphaned btrfs directory that nothing mounts
  • useradd --root sysroot writes to sysroot/etc/passwd etc., which is silently discarded after first boot
  • The user appears created during install but is gone on first login

Compare with WriteHostname and AppendFstabEntry which both correctly use ComposeFsDeployEtcDirFn(target) for composefs paths.

Current exposure

Zero — all production images with needs_user_creation=True use grub2/ostree path. Only systemd-boot images (Dakota) use composefs-native, and Dakota has needs_user_creation=False, so CreateUser is never called for composefs images.

But this will break silently if a future image uses both composefs-native and user creation.

Fix

if isComposeFsNative(sysroot) {
    var err error
    etcDir, err := ComposeFsDeployEtcDirFn(sysroot)
    if err != nil {
        return fmt.Errorf("finding composefs deploy etc: %w", err)
    }
    root = filepath.Dir(etcDir)  // parent of etc dir = deployment root
} else {
    deployDir, err := DeploymentDirFn(sysroot)
    ...
}

Also: the staterootHome path ostree/deploy/default/var/home should use ComposeFsVarDir(sysroot) for composefs-native.

Assisted-by: Claude Sonnet 4.5 via pi

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions