diff --git a/Dockerfile b/Dockerfile
index 1c4d172..1924a60 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -18,8 +18,8 @@ RUN apk add --no-cache \
musl-dev \
musl-utils \
pkgconfig \
- openssl-dev \
- perl \
+ openssl openssl-dev \
+ shadow \
bash \
findutils \
grep \
diff --git a/config/build.conf b/config/build.conf
index 3c63d47..29c5616 100644
--- a/config/build.conf
+++ b/config/build.conf
@@ -49,6 +49,13 @@ KERNEL_SOURCE_URL="https://cdn.kernel.org/pub/linux/kernel"
ZEROOS_BRANDING="true"
ZEROOS_REBRANDING="true"
+# Root account configuration
+# Provide either ZEROOS_ROOT_PASSWORD_HASH (preferred, SHA-512 crypt) or ZEROOS_ROOT_PASSWORD (plain, will be hashed during build)
+# Legacy variable names also supported: ROOT_PASSWORD_HASH / ROOT_PASSWORD
+# Passwordless root is the default for branded builds when no password is provided.
+ZEROOS_PASSWORDLESS_ROOT="true"
+# ZEROOS_ROOT_PASSWORD_HASH="" # optional, preferred when setting a password
+# ZEROOS_ROOT_PASSWORD="" # optional, dev-only; if set, overrides passwordless
# Feature flags
ENABLE_STRIP="true"
ENABLE_UPX="true"
diff --git a/config/packages.list b/config/packages.list
index db74e3d..1646f9a 100644
--- a/config/packages.list
+++ b/config/packages.list
@@ -7,6 +7,7 @@ alpine-baselayout
alpine-baselayout-data
busybox
musl
+agetty
# Module loading & hardware detection
eudev
@@ -17,6 +18,7 @@ kmod
# Console/terminal management
util-linux
+wget
# Essential networking (for Zero-OS connectivity)
iproute2
diff --git a/config/zinit/getty.yaml b/config/zinit/getty.yaml
index cc962a5..4e1da77 100644
--- a/config/zinit/getty.yaml
+++ b/config/zinit/getty.yaml
@@ -1,2 +1,2 @@
-exec: /sbin/getty -L 115200 ttyS0 vt100
+exec: /sbin/agetty -a root -L 115200 ttyS0 vt100
restart: always
\ No newline at end of file
diff --git a/config/zinit/gettyconsole.yaml b/config/zinit/gettyconsole.yaml
index 006ac89..4094b01 100644
--- a/config/zinit/gettyconsole.yaml
+++ b/config/zinit/gettyconsole.yaml
@@ -1,2 +1,2 @@
-exec: /sbin/getty -L 115200 console vt100
+exec: /bin/sh
restart: always
diff --git a/config/zinit/init/network.sh b/config/zinit/init/network.sh
index 21dffba..b0fa4ea 100755
--- a/config/zinit/init/network.sh
+++ b/config/zinit/init/network.sh
@@ -4,4 +4,5 @@ set -e
if ! getent group dhcpcd >/dev/null 2>&1; then addgroup -S dhcpcd 2>/dev/null || true; fi
if ! getent passwd dhcpcd >/dev/null 2>&1; then adduser -S -H -D -s /sbin/nologin -G dhcpcd dhcpcd 2>/dev/null || true; fi
# Exec dhcpcd (will run as root if it cannot drop to dhcpcd user)
-exec dhcpcd ""
+interfaces=$(ip -br l | awk '!/lo/&&!/my0/{print $1}')
+exec dhcpcd $interfaces
\ No newline at end of file
diff --git a/docs/NOTES.md b/docs/NOTES.md
new file mode 100644
index 0000000..3b440aa
--- /dev/null
+++ b/docs/NOTES.md
@@ -0,0 +1,57 @@
+Zero-OS Branding Diagnostics and Notes
+
+Context
+- Goal: Branding flags should enable passwordless root in initramfs and update /etc/{issue,motd}.
+- Source of truth for flags: [config/build.conf](config/build.conf)
+- Implementation hook: [bash.initramfs_finalize_customization()](scripts/lib/initramfs.sh:575) called from [bash.initramfs_create_cpio()](scripts/lib/initramfs.sh:663) just before CPIO creation.
+
+Observed issue in latest build
+- Branding flags were set: logs showed "Branding debug: ZEROOS_BRANDING=true ... _branding=true".
+- Both /etc/passwd and /etc/shadow exist in initramfs; Alpine uses shadow for authentication.
+- The script only edited /etc/passwd, leaving /etc/shadow unchanged; login still required a password.
+- Evidence (from build logs):
+ - Preview /etc/passwd (pre): root:(x):0:0:root:/root:/bin/sh
+ - Preview /etc/shadow (pre): root:(***):...
+ - Preview /etc/passwd (post): root:(x):0:0:root:/root:/bin/sh
+ - Preview /etc/shadow (post): root:(***):...
+
+Root cause
+- Editing /etc/passwd is ineffective when /etc/shadow is present; the pw field is ignored in passwd and 'x' indicates to consult shadow.
+
+Fix implemented
+- Change in [bash.initramfs_finalize_customization()](scripts/lib/initramfs.sh:575):
+ - Prefer editing /etc/shadow for root’s password field; fallback to /etc/passwd if shadow is absent.
+ - Command used:
+ - sed -i 's/^root:[^:]*:/root::/' "${initramfs_dir}/etc/shadow"
+- Diagnostics retained:
+ - Logs branding vars, presence/perms of /etc/{shadow,passwd}, and sanitized previews pre/post.
+
+Verification plan
+- Minimal rebuild to re-run finalize:
+ - rm -f .build-stages/initramfs_create.done .build-stages/initramfs_test.done
+ - DEBUG=1 ./scripts/build.sh --skip-tests
+- Confirm in logs:
+ - "✓ Root password removed in /etc/shadow (passwordless root)"
+ - Preview /etc/shadow (post): root:(***): with empty field notation "root::" internally.
+- Optional deeper check by inspecting the archive:
+ - cd dist && mkdir tmp && cd tmp
+ - xz -dc ../initramfs.cpio.xz | cpio -idv
+ - grep '^root:' ./etc/shadow | sed 's/^\(root:\)[^:]*:/\1(***):/'
+ - Expected: the second field is empty (root::...).
+
+Behavior and safety notes
+- Permissions: /etc/shadow typically 640 root:shadow; the fix does not alter permissions.
+- Passwordless root in initramfs is intended only when [config/build.conf](config/build.conf) sets ZEROOS_BRANDING="true" (or ZEROOS_REBRANDING="true").
+- The change affects only the initramfs image; not the host system.
+
+Code references
+- Branding guard and customization: [bash.initramfs_finalize_customization()](scripts/lib/initramfs.sh:575)
+- Archive creation entry point: [bash.initramfs_create_cpio()](scripts/lib/initramfs.sh:663)
+- Build orchestrator: [bash.main_build_process()](scripts/build.sh:213)
+
+Notes usage
+- This file (docs/NOTES.md) is the session-to-session log of debugging and decisions.
+- For finalized policies, consider adding docs/DECISIONS.md.
+
+Change log
+- 2025-09-09: Added diagnostics and implemented shadow-first passwordless root; documented verification steps.
\ No newline at end of file
diff --git a/initramfs/etc/apk/world b/initramfs/etc/apk/world
index 1fabb92..879eaec 100644
--- a/initramfs/etc/apk/world
+++ b/initramfs/etc/apk/world
@@ -1,3 +1,4 @@
+agetty
alpine-baselayout
alpine-baselayout-data
alpine-keys
@@ -27,5 +28,6 @@ nftables
openssh-server
tcpdump
util-linux
+wget
zellij
zlib
diff --git a/initramfs/etc/issue b/initramfs/etc/issue
index 87ab9b4..6365385 100644
--- a/initramfs/etc/issue
+++ b/initramfs/etc/issue
@@ -1,3 +1,3 @@
-Welcome to Alpine Linux 3.22
-Kernel \r on \m (\l)
+Zero-OS \r \m
+Built on \l
diff --git a/initramfs/etc/motd b/initramfs/etc/motd
index 06dbae4..a2cf942 100644
--- a/initramfs/etc/motd
+++ b/initramfs/etc/motd
@@ -1,10 +1,8 @@
-Welcome to Alpine!
-The Alpine Wiki contains a large amount of how-to guides and general
-information about administrating Alpine systems.
-See .
+Welcome to Zero-OS!
-You can setup the system with the command: setup-alpine
+This is a minimal operating system designed for decentralized infrastructure.
+Built on Alpine Linux with ThreeFold components.
-You may change this message by editing /etc/motd.
+For more information: https://github.com/threefoldtech/zos
diff --git a/initramfs/etc/shadow b/initramfs/etc/shadow
index aac5caf..fd6b0a8 100644
--- a/initramfs/etc/shadow
+++ b/initramfs/etc/shadow
@@ -1,4 +1,4 @@
-root:*::0:::::
+root::20340:0:::::
bin:!::0:::::
daemon:!::0:::::
lp:!::0:::::
diff --git a/initramfs/usr/bin/wget b/initramfs/usr/bin/wget
deleted file mode 120000
index a3aaff7..0000000
--- a/initramfs/usr/bin/wget
+++ /dev/null
@@ -1 +0,0 @@
-/bin/busybox
\ No newline at end of file
diff --git a/initramfs/usr/bin/wget b/initramfs/usr/bin/wget
new file mode 100755
index 0000000..b799651
Binary files /dev/null and b/initramfs/usr/bin/wget differ
diff --git a/scripts/lib/common.sh b/scripts/lib/common.sh
index 5240346..9b827a5 100644
--- a/scripts/lib/common.sh
+++ b/scripts/lib/common.sh
@@ -226,14 +226,42 @@ trap cleanup_on_exit EXIT INT TERM
BUILD_CONF="${PROJECT_ROOT}/config/build.conf"
if [[ -f "$BUILD_CONF" ]]; then
log_debug "Loading build configuration from: ${BUILD_CONF}"
+ # shellcheck source=/dev/null
source "$BUILD_CONF"
else
log_warn "Build configuration not found: ${BUILD_CONF}"
log_warn "Using default values"
fi
+# Normalize key directory variables to absolute paths anchored at PROJECT_ROOT.
+# This prevents later re-sourcing from accidentally re-introducing relative paths.
+if [[ -z "${INSTALL_DIR:-}" ]]; then
+ INSTALL_DIR="${PROJECT_ROOT}/initramfs"
+elif [[ "${INSTALL_DIR}" != /* ]]; then
+ INSTALL_DIR="${PROJECT_ROOT}/${INSTALL_DIR#./}"
+fi
+
+if [[ -z "${COMPONENTS_DIR:-}" ]]; then
+ COMPONENTS_DIR="${PROJECT_ROOT}/components"
+elif [[ "${COMPONENTS_DIR}" != /* ]]; then
+ COMPONENTS_DIR="${PROJECT_ROOT}/${COMPONENTS_DIR#./}"
+fi
+
+if [[ -z "${KERNEL_DIR:-}" ]]; then
+ KERNEL_DIR="${PROJECT_ROOT}/kernel"
+elif [[ "${KERNEL_DIR}" != /* ]]; then
+ KERNEL_DIR="${PROJECT_ROOT}/${KERNEL_DIR#./}"
+fi
+
+if [[ -z "${DIST_DIR:-}" ]]; then
+ DIST_DIR="${PROJECT_ROOT}/dist"
+elif [[ "${DIST_DIR}" != /* ]]; then
+ DIST_DIR="${PROJECT_ROOT}/${DIST_DIR#./}"
+fi
+
# Export common variables
export SCRIPT_DIR PROJECT_ROOT
+export INSTALL_DIR COMPONENTS_DIR KERNEL_DIR DIST_DIR
export -f log_info log_warn log_error log_debug
export -f safe_execute section_header
export -f command_exists in_container check_dependencies
diff --git a/scripts/lib/initramfs.sh b/scripts/lib/initramfs.sh
index 35e6912..1fb8bbb 100644
--- a/scripts/lib/initramfs.sh
+++ b/scripts/lib/initramfs.sh
@@ -580,14 +580,31 @@ function initramfs_finalize_customization() {
# Branding guard (default disabled). Enable by setting ZEROOS_BRANDING=true (or ZEROOS_REBRANDING=true)
local _branding="${ZEROOS_BRANDING:-${ZEROOS_REBRANDING:-false}}"
+ # Diagnostics: branding variables and environment
+ log_info "Branding debug: ZEROOS_BRANDING=${ZEROOS_BRANDING:-unset} ZEROOS_REBRANDING=${ZEROOS_REBRANDING:-unset} _branding=${_branding}"
+ log_info "Branding debug: PROJECT_ROOT=${PROJECT_ROOT:-unset} BUILD_CONF=${BUILD_CONF:-unset} PWD=$(pwd)"
+
+ # Diagnostics: which auth files exist and their perms/owners
if [[ "${_branding}" == "true" ]]; then
- # Remove root password for passwordless login
- log_info "Branding enabled: removing root password for passwordless login"
- if [[ -f "${initramfs_dir}/etc/passwd" ]]; then
- safe_execute sed -i 's/^root:[^:]*:/root::/' "${initramfs_dir}/etc/passwd"
- log_info "✓ Root password removed"
+ # Passwordless root (legacy behavior aligned with 9423b708): remove root password
+ if command_exists "passwd"; then
+ log_info "Branding enabled: deleting root password via passwd -d -R '${initramfs_dir}'"
+ safe_execute chroot ${initramfs_dir} passwd -d root
+ log_info "✓ Root password deleted (passwordless root)"
else
- log_warn "/etc/passwd not found, skipping password removal"
+ log_error "passwd not available in build container; install 'shadow' package to enable password deletion."
+ fi
+
+ # Diagnostics: sanitized previews (post-change)
+ if [[ -f "${initramfs_dir}/etc/passwd" ]]; then
+ local _passwd_post
+ _passwd_post=$(grep '^root:' "${initramfs_dir}/etc/passwd" 2>/dev/null | sed 's/^\(root:\)[^:]*:/\1(x):/')
+ log_info "Preview /etc/passwd (post): ${_passwd_post:-}"
+ fi
+ if [[ -f "${initramfs_dir}/etc/shadow" ]]; then
+ local _shadow_post
+ _shadow_post=$(grep '^root:' "${initramfs_dir}/etc/shadow" 2>/dev/null | sed 's/^\(root:\)[^:]*:/\1(***):/')
+ log_info "Preview /etc/shadow (post): ${_shadow_post:-}"
fi
# Update /etc/motd to Zero-OS
@@ -774,7 +791,12 @@ function initramfs_create_cpio() {
function initramfs_validate() {
local initramfs_dir_in="$1"
local initramfs_dir
+
+ # Diagnostics to catch path/WD issues during validation
+ log_info "Validation debug: input='${initramfs_dir_in}' PWD=$(pwd) PROJECT_ROOT=${PROJECT_ROOT:-unset} INSTALL_DIR=${INSTALL_DIR:-unset}"
+
initramfs_dir=$(resolve_path "${initramfs_dir_in}")
+ log_info "Validation debug: resolved initramfs_dir='${initramfs_dir}'"
section_header "Validating initramfs contents"