Skip to content

Commit fe7dfa2

Browse files
Kabuki94claude
andcommitted
fix(driver): replace identity prompts with toml resolver (configurator is SSOT)
Operator correction: the build driver was prompting for username, hostname, AI model, etc. -- but EVERY operator-visible setting is supposed to live in the layered mios.toml chain, edited via /configurator.html in Epiphany. The terminal prompts were a violation of the SSOT rule. > "were all supposed to already be in the toml/html file that is > overriden/user defined on build entry" Plus the broader scope clarification: > "no!!!! not just that but all the packages to host, hosting, dev, > build, run, etc-etc!!!!!!" Identity (username/hostname), AI choices (model/embed/bake), locale, network, image, desktop, and EVERY [packages.*] subsection (gpu-nvidia, virt, containers, build-toolchain, ceph, k3s, freeipa, gnome, ai, gaming, ...) all live in mios.toml. The configurator HTML edits them. The driver READS them, never asks. Changes: * Removed _capture_identity() entirely. The terminal-prompt path for user/host/AI was wrong-shaped from the start. * Reordered: Configurator step now FIRST (operator edits the toml in Epiphany via WSLg/Wayland), then Resolve step SECOND (sources the edited toml). Prior order had Resolve before Configurator, which would have locked in stale values from before the operator's edits. * Resolve step sources tools/lib/userenv.sh -- the canonical layered-toml -> MIOS_* env reader that's already used by Justfile, /etc/profile.d, and every entry-point script. No re-implementation of toml parsing in the driver. * Single remaining prompt: password (when password_policy=interactive AND no /etc/mios/secrets.env exists). Per the toml schema's explicit secrets policy, password_hash is NEVER tracked in a checked-in copy of mios.toml. Three policies honored: - interactive: prompt once, write to /etc/mios/secrets.env mode 0600 - hashed: use literal MIOS_USER_PASSWORD_HASH from env (operator pasted hash into configurator's password field, which wrote it to ~/.config/mios/mios.toml) - none: no password set (kiosk / CI) * /etc/mios/install.env is still written for downstream consumers that read flat shell-format env (sysusers, tmpfiles, profile.d, automation/build.sh during podman build). It's now a DERIVED artifact -- mios.toml is the source. Bash syntax validated with bash -n: 0 errors. NOT covered in this commit (separate scope -- larger work item): * The configurator HTML at /usr/share/mios/configurator/index.html currently exposes 6 sections (Identity & AI / Defaults / Appearance / Apps & Desktop / Services / Advanced TOML preview). It does NOT yet expose the 40+ [packages.*] subsections (gpu-nvidia, virt, containers, build-toolchain, ceph, k3s, freeipa, etc.) as toggle fields. Nor does it expose [hwcaps], [security], [bootstrap], [profile], [quadlets.enable], or [env]. The user's expanded requirement -- "all the packages to host, hosting, dev, build, run" -- means the HTML needs a Packages section with categorized checkboxes for every [packages.X]. AND the toml schema needs an `enable = true|false` field per package section so the operator's choice translates to "lay this group in the OCI image / skip this group". That's a multi-part change spanning the toml schema, the Containerfile build args, and the HTML form. Worth its own commit chain so each piece can be tested separately. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 9fde591 commit fe7dfa2

1 file changed

Lines changed: 120 additions & 117 deletions

File tree

usr/libexec/mios/mios-build-driver

Lines changed: 120 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -90,123 +90,9 @@ else
9090
fi
9191
_log "mios-bootstrap repo: $BOOT_REPO"
9292

93-
# ── Identity ─────────────────────────────────────────────────────────────────
94-
# /etc/mios/install.env is written by the Windows side BEFORE handoff
95-
# (Phase 7 in build-mios.ps1) so the prompts already happened on the
96-
# Windows side this round. Future migration chunks move the prompts
97-
# in here so the operator answers them in the MiOS-DEV terminal --
98-
# NOT in Windows -- per the architecture memo.
99-
# ── Identity capture ─────────────────────────────────────────────────────────
100-
# Per the self-replication architecture (memo:
101-
# project_mios_self_replication_vision.md), identity prompts run INSIDE
102-
# MiOS-DEV's tty -- not on the Windows side. This is migration chunk 3:
103-
# port what was build-mios.ps1's Phase 6 (Read-Line / Read-Password /
104-
# Read-Model) into bash here.
105-
#
106-
# If /etc/mios/install.env already has all the required keys (set by
107-
# either a previous driver invocation or, transitionally, by the
108-
# Windows-side Phase 7 code that's still in place pending its removal
109-
# in chunk 6), source it and skip prompts. Otherwise capture
110-
# interactively.
111-
_capture_identity() {
112-
echo
113-
echo " +-- MiOS Identity ----------------------------------------+"
114-
echo " | Settings persist to /etc/mios/install.env. Defaults |"
115-
echo " | in [brackets]; press Enter to accept. |"
116-
echo " +---------------------------------------------------------+"
117-
118-
read -r -p " Linux username [mios]: " MIOS_USER
119-
: "${MIOS_USER:=mios}"
120-
121-
read -r -p " Hostname [mios]: " MIOS_HOSTNAME
122-
: "${MIOS_HOSTNAME:=mios}"
123-
124-
# Password capture: silent (-s) read, default to literal 'mios' if blank.
125-
read -rsp " Password (sha512crypt-hashed) [mios]: " _pw_plain
126-
echo
127-
: "${_pw_plain:=mios}"
128-
129-
# Hash via mkpasswd if available, else python3 (always present on
130-
# FCOS-based MiOS-DEV), else last-resort openssl. The result is what
131-
# /usr/lib/sysusers.d/10-mios.conf reads at first boot to set the
132-
# mios user's password without ever materializing the cleartext
133-
# anywhere on disk.
134-
if command -v mkpasswd >/dev/null 2>&1; then
135-
MIOS_USER_PASSWORD_HASH=$(mkpasswd -m sha-512 "$_pw_plain")
136-
elif command -v python3 >/dev/null 2>&1; then
137-
MIOS_USER_PASSWORD_HASH=$(python3 -c 'import crypt,sys;print(crypt.crypt(sys.argv[1], crypt.METHOD_SHA512))' "$_pw_plain")
138-
elif command -v openssl >/dev/null 2>&1; then
139-
MIOS_USER_PASSWORD_HASH=$(openssl passwd -6 "$_pw_plain")
140-
else
141-
_log "WARN: no password-hash tool available (mkpasswd / python3 / openssl all missing) -- storing plaintext"
142-
MIOS_USER_PASSWORD_HASH="$_pw_plain"
143-
fi
144-
unset _pw_plain
145-
146-
# AI model menu -- default set sized for the 12 GB system-RAM
147-
# baseline. The 14b option is for hosts with 24+ GB RAM that can
148-
# comfortably run a larger code model in CPU-only inference.
149-
echo
150-
echo " AI model:"
151-
echo " 1) qwen2.5-coder:7b [default; ~5 GB on disk, 12 GB host RAM]"
152-
echo " 2) qwen2.5-coder:14b [~10 GB on disk, 24 GB host RAM]"
153-
echo " 3) llama3.2:3b [low-RAM / fast-response profile]"
154-
echo " 4) custom [type your own ollama model id]"
155-
read -r -p " Choice [1]: " _model_choice
156-
case "${_model_choice:-1}" in
157-
2) MIOS_AI_MODEL="qwen2.5-coder:14b" ;;
158-
3) MIOS_AI_MODEL="llama3.2:3b" ;;
159-
4) read -r -p " Custom model id (e.g. mistral:7b): " MIOS_AI_MODEL
160-
: "${MIOS_AI_MODEL:=qwen2.5-coder:7b}" ;;
161-
*) MIOS_AI_MODEL="qwen2.5-coder:7b" ;;
162-
esac
163-
164-
read -r -p " AI embedding model [nomic-embed-text]: " MIOS_AI_EMBED_MODEL
165-
: "${MIOS_AI_EMBED_MODEL:=nomic-embed-text}"
166-
167-
MIOS_OLLAMA_BAKE_MODELS="${MIOS_AI_MODEL},${MIOS_AI_EMBED_MODEL}"
168-
169-
# Persist. install.env is sourced by /etc/profile.d/mios-env.sh
170-
# at every interactive login + by automation/build.sh during the
171-
# OCI build, so writing it here propagates to every downstream
172-
# consumer without further action.
173-
sudo install -d -m 0755 /etc/mios
174-
{
175-
printf 'MIOS_USER="%s"\n' "$MIOS_USER"
176-
printf 'MIOS_HOSTNAME="%s"\n' "$MIOS_HOSTNAME"
177-
printf 'MIOS_USER_PASSWORD_HASH="%s"\n' "$MIOS_USER_PASSWORD_HASH"
178-
printf 'MIOS_AI_MODEL="%s"\n' "$MIOS_AI_MODEL"
179-
printf 'MIOS_AI_EMBED_MODEL="%s"\n' "$MIOS_AI_EMBED_MODEL"
180-
printf 'MIOS_OLLAMA_BAKE_MODELS="%s"\n' "$MIOS_OLLAMA_BAKE_MODELS"
181-
} | sudo tee /etc/mios/install.env >/dev/null
182-
sudo chmod 0640 /etc/mios/install.env
183-
_log "identity persisted: user=$MIOS_USER host=$MIOS_HOSTNAME ai=$MIOS_AI_MODEL embed=$MIOS_AI_EMBED_MODEL"
184-
185-
export MIOS_USER MIOS_HOSTNAME MIOS_USER_PASSWORD_HASH \
186-
MIOS_AI_MODEL MIOS_AI_EMBED_MODEL MIOS_OLLAMA_BAKE_MODELS
187-
}
188-
189-
if [[ -f /etc/mios/install.env ]] \
190-
&& grep -q '^MIOS_USER=' /etc/mios/install.env \
191-
&& grep -q '^MIOS_HOSTNAME=' /etc/mios/install.env \
192-
&& grep -q '^MIOS_AI_MODEL=' /etc/mios/install.env; then
193-
_log "identity loaded from /etc/mios/install.env"
194-
# shellcheck disable=SC1091
195-
source /etc/mios/install.env
196-
else
197-
_log "no usable /etc/mios/install.env -- prompting for identity"
198-
if [[ "${MIOS_NONINTERACTIVE:-0}" == "1" ]]; then
199-
_log "MIOS_NONINTERACTIVE=1 -- using vendor defaults instead of prompting"
200-
MIOS_USER='mios'
201-
MIOS_HOSTNAME='mios'
202-
MIOS_AI_MODEL='qwen2.5-coder:7b'
203-
MIOS_AI_EMBED_MODEL='nomic-embed-text'
204-
MIOS_OLLAMA_BAKE_MODELS="${MIOS_AI_MODEL},${MIOS_AI_EMBED_MODEL}"
205-
export MIOS_USER MIOS_HOSTNAME MIOS_AI_MODEL MIOS_AI_EMBED_MODEL MIOS_OLLAMA_BAKE_MODELS
206-
else
207-
_capture_identity
208-
fi
209-
fi
93+
# CRITICAL ORDERING: Configurator FIRST (operator edits the toml in
94+
# Epiphany), then Resolve (sources the edited toml). Don't reverse;
95+
# resolving before the operator has edited would lock in stale values.
21096

21197
# ── Configurator step: Epiphany on /configurator.html ────────────────────────
21298
# Per the self-replication-vision memo:
@@ -281,6 +167,123 @@ else
281167
_log "WARN: /usr/libexec/mios/mios-configurator-launch not present -- skipping configurator step"
282168
fi
283169

170+
# ── Resolve all settings from the layered mios.toml chain ───────────────────
171+
# Runs AFTER the configurator step so the operator's edits in Epiphany
172+
# (now landed at /etc/mios/mios.toml) are sourced into env.
173+
#
174+
# CANONICAL: identity, AI choices, locale, image, network, desktop,
175+
# packages-to-layer (every [packages.*] enable flag), hosting/dev/build/
176+
# run profile flags -- EVERY operator-visible setting comes from the
177+
# layered mios.toml, edited via /configurator.html. The driver does NOT
178+
# prompt for any of these values; they're set in the toml.
179+
#
180+
# Layer chain (highest wins):
181+
# /usr/share/mios/mios.toml vendor defaults baked into the image
182+
# /etc/mios/mios.toml host overlay (configurator promotes
183+
# ~/Downloads/mios.toml here when the
184+
# operator clicks Save in Epiphany)
185+
# ~/.config/mios/mios.toml per-user XDG overlay
186+
#
187+
# tools/lib/userenv.sh resolves the chain, exports MIOS_* env vars, and
188+
# is the single canonical reader. Source it so the entire build pipeline
189+
# downstream (automation/build.sh, sysusers, tmpfiles, profile.d,
190+
# Containerfile build args) inherits the resolved values without
191+
# re-parsing toml in 12 different ways.
192+
USERENV_SH=""
193+
for cand in \
194+
/tools/lib/userenv.sh \
195+
"${MIOS_REPO:-}/tools/lib/userenv.sh" \
196+
/usr/share/mios/lib/userenv.sh \
197+
; do
198+
if [[ -n "$cand" && -r "$cand" ]]; then USERENV_SH="$cand"; break; fi
199+
done
200+
if [[ -n "$USERENV_SH" ]]; then
201+
_log "Sourcing layered config: $USERENV_SH"
202+
# shellcheck disable=SC1090
203+
source "$USERENV_SH"
204+
else
205+
_log "WARN: tools/lib/userenv.sh not found -- using vendor-default env"
206+
fi
207+
208+
# Vendor-shipped fallbacks for any MIOS_* the toml didn't define. Never
209+
# prompt -- the principle is "configurator is SSOT". Missing means the
210+
# operator hasn't edited that field and the vendor default applies.
211+
: "${MIOS_USER:=mios}"
212+
: "${MIOS_HOSTNAME:=mios}"
213+
: "${MIOS_AI_MODEL:=qwen2.5-coder:7b}"
214+
: "${MIOS_AI_EMBED_MODEL:=nomic-embed-text}"
215+
: "${MIOS_OLLAMA_BAKE_MODELS:=${MIOS_AI_MODEL},${MIOS_AI_EMBED_MODEL}}"
216+
: "${MIOS_PASSWORD_POLICY:=interactive}"
217+
export MIOS_USER MIOS_HOSTNAME MIOS_AI_MODEL MIOS_AI_EMBED_MODEL \
218+
MIOS_OLLAMA_BAKE_MODELS MIOS_PASSWORD_POLICY
219+
220+
# Password handling. The toml schema says password_hash is NEVER
221+
# tracked in a checked-in copy. Three policies:
222+
# * interactive: prompt once if no /etc/mios/secrets.env exists --
223+
# the ONLY operator prompt; everything else came from the toml
224+
# * hashed : use literal MIOS_USER_PASSWORD_HASH already in env
225+
# (operator pasted a sha512crypt hash into the
226+
# configurator's password field)
227+
# * none : skip password setup; useful for kiosk / CI
228+
case "${MIOS_PASSWORD_POLICY}" in
229+
none)
230+
_log "MIOS_PASSWORD_POLICY=none -- no password set"
231+
MIOS_USER_PASSWORD_HASH=""
232+
;;
233+
hashed)
234+
if [[ -z "${MIOS_USER_PASSWORD_HASH:-}" ]]; then
235+
_log "WARN: password_policy=hashed but MIOS_USER_PASSWORD_HASH is empty -- falling back to 'mios'"
236+
MIOS_USER_PASSWORD_HASH=$(python3 -c 'import crypt;print(crypt.crypt("mios", crypt.METHOD_SHA512))')
237+
fi
238+
;;
239+
interactive|*)
240+
if [[ -r /etc/mios/secrets.env ]] && grep -q '^MIOS_USER_PASSWORD_HASH=' /etc/mios/secrets.env; then
241+
_log "password hash loaded from /etc/mios/secrets.env"
242+
# shellcheck disable=SC1091
243+
source /etc/mios/secrets.env
244+
elif [[ "${MIOS_NONINTERACTIVE:-0}" == "1" ]]; then
245+
_log "MIOS_NONINTERACTIVE=1 -- defaulting password to 'mios'"
246+
MIOS_USER_PASSWORD_HASH=$(python3 -c 'import crypt;print(crypt.crypt("mios", crypt.METHOD_SHA512))')
247+
else
248+
echo
249+
echo " password_policy=interactive and no /etc/mios/secrets.env yet."
250+
echo " This is the ONLY operator prompt -- everything else came from"
251+
echo " /mios.toml (edited via the Epiphany configurator above)."
252+
read -rsp " Set password for ${MIOS_USER} (default: 'mios'): " _pw_plain
253+
echo
254+
: "${_pw_plain:=mios}"
255+
if command -v mkpasswd >/dev/null 2>&1; then
256+
MIOS_USER_PASSWORD_HASH=$(mkpasswd -m sha-512 "$_pw_plain")
257+
else
258+
MIOS_USER_PASSWORD_HASH=$(python3 -c 'import crypt,sys;print(crypt.crypt(sys.argv[1], crypt.METHOD_SHA512))' "$_pw_plain")
259+
fi
260+
unset _pw_plain
261+
sudo install -d -m 0755 /etc/mios
262+
printf 'MIOS_USER_PASSWORD_HASH="%s"\n' "$MIOS_USER_PASSWORD_HASH" |
263+
sudo tee /etc/mios/secrets.env >/dev/null
264+
sudo chmod 0600 /etc/mios/secrets.env
265+
fi
266+
;;
267+
esac
268+
export MIOS_USER_PASSWORD_HASH
269+
270+
# Persist a flat install.env for downstream consumers that don't grok
271+
# layered toml directly: /etc/profile.d/mios-env.sh, automation/build.sh
272+
# during `podman build`, sysusers/tmpfiles generators. install.env
273+
# mirrors a subset of the resolved env.
274+
sudo install -d -m 0755 /etc/mios
275+
{
276+
printf 'MIOS_USER="%s"\n' "$MIOS_USER"
277+
printf 'MIOS_HOSTNAME="%s"\n' "$MIOS_HOSTNAME"
278+
printf 'MIOS_USER_PASSWORD_HASH="%s"\n' "$MIOS_USER_PASSWORD_HASH"
279+
printf 'MIOS_AI_MODEL="%s"\n' "$MIOS_AI_MODEL"
280+
printf 'MIOS_AI_EMBED_MODEL="%s"\n' "$MIOS_AI_EMBED_MODEL"
281+
printf 'MIOS_OLLAMA_BAKE_MODELS="%s"\n' "$MIOS_OLLAMA_BAKE_MODELS"
282+
} | sudo tee /etc/mios/install.env >/dev/null
283+
sudo chmod 0640 /etc/mios/install.env
284+
285+
_log "Resolved settings: user=$MIOS_USER host=$MIOS_HOSTNAME ai=$MIOS_AI_MODEL embed=$MIOS_AI_EMBED_MODEL pwpolicy=$MIOS_PASSWORD_POLICY"
286+
284287
# ── Build invocation ─────────────────────────────────────────────────────────
285288
# automation/build.sh expects to run inside a `podman build` against the
286289
# Containerfile. Outside that context it's a no-op driver entry. The

0 commit comments

Comments
 (0)