@@ -211,6 +211,17 @@ _section_header
211211echo " "
212212
213213TOTAL_START=$SECONDS
214+
215+ # ── Build-time version manifest (records :latest -> observed-version) ────────
216+ # Project policy: every dependency tracks :latest from upstream. To make
217+ # day-0 images reproducible-after-the-fact, every script that resolves a
218+ # floating tag calls record_version (lib/common.sh). build.sh seeds the
219+ # manifest with image-level metadata; phase scripts append component rows.
220+ rm -f " $MIOS_VERSION_MANIFEST "
221+ record_version mios " $VERSION_STR " " git:$( cat /ctx/VERSION 2> /dev/null || echo unknown) "
222+ record_version base-image " ${BASE_IMAGE:- ghcr.io/ ublue-os/ ucore-hci: stable-nvidia} " " build-time floating tag"
223+ record_version kernel " $( find /usr/lib/modules/ -mindepth 1 -maxdepth 1 -printf ' %f\n' 2> /dev/null | sort -V | tail -1) " " from base image"
224+
214225SCRIPT_COUNT=0
215226SCRIPT_FAIL=0
216227WARN_FAIL=0
@@ -325,28 +336,71 @@ else
325336 _row " WARNING: 99-postcheck.sh not found -- skipping"
326337fi
327338
328- # ── Log preservation (flatten all chain logs into /usr/lib/mios/logs/) ──────
339+ # ── Quadlet image digest capture (build-day :latest snapshot) ───────────────
340+ # Quadlets are pulled by bootc at deploy time, not at OCI-build time, so
341+ # their :latest will re-resolve on every deploy. Record the digest skopeo
342+ # sees right now, so the shipped image carries a precise snapshot of what
343+ # build day's :latest pointed at — even though deploys may differ later.
344+ echo " "
345+ _hline ' -' ' +' ' +'
346+ _row " POST-BUILD: Capturing Quadlet image digests"
347+ _hline ' -' ' +' ' +'
348+ if command -v skopeo > /dev/null 2>&1 ; then
349+ shopt -s nullglob
350+ for q in /usr/share/containers/systemd/* .container /etc/containers/systemd/* .container; do
351+ img=$( awk -F= ' /^Image=/{print $2; exit}' " $q " 2> /dev/null)
352+ [[ -n " $img " ]] || continue
353+ digest=$( skopeo inspect " docker://${img} " 2> /dev/null \
354+ | python3 -c ' import json,sys;d=json.load(sys.stdin);print(d.get("Digest",""))' 2> /dev/null \
355+ || true)
356+ record_version " quadlet:$( basename " $q " .container) " " $img " " ${digest:- <unresolved>} "
357+ done
358+ shopt -u nullglob
359+ else
360+ warn " skopeo not available — Quadlet image digests not captured"
361+ fi
362+
363+ # ── Log preservation (flatten all chain logs + version manifest into /usr) ──
329364echo " "
330365_hline ' -' ' +' ' +'
331- _row " LOG CHAIN: Flattening all build logs -> /usr/lib/mios/logs/"
366+ _row " LOG CHAIN: Flattening logs + version manifest -> /usr/lib/mios/logs/"
332367_hline ' -' ' +' ' +'
333368mkdir -p /usr/lib/mios/logs
334369cp -v /var/log/dnf5.log* /var/log/hawkey.log /usr/lib/mios/logs/ 2> /dev/null || true
335- # Flatten per-step logs into single unified chain log
370+
371+ # Promote machine-readable version manifest (TSV, kept uncompressed for grep/awk)
372+ if [[ -f " $MIOS_VERSION_MANIFEST " ]]; then
373+ install -m 0644 " $MIOS_VERSION_MANIFEST " /usr/lib/mios/logs/mios-build-versions.tsv
374+ _row " Version manifest: /usr/lib/mios/logs/mios-build-versions.tsv ($( wc -l < " $MIOS_VERSION_MANIFEST " ) rows)"
375+ fi
376+
377+ # Flatten per-step logs + manifest + main build log into single unified chain
336378UNIFIED_LOG=" /usr/lib/mios/logs/mios-build-chain.log"
337- echo " # MiOS ${VERSION_STR} Unified Build Log Chain — $( date ' +%Y-%m-%d %H:%M:%S' ) " > " $UNIFIED_LOG "
338- for step_log in /tmp/mios-step-* .log; do
339- [[ -f " $step_log " ]] || continue
340- echo " " >> " $UNIFIED_LOG "
341- echo " # ====== $( basename " $step_log " ) ======" >> " $UNIFIED_LOG "
342- cat " $step_log " >> " $UNIFIED_LOG "
343- done
344- # Append main build log
345- echo " " >> " $UNIFIED_LOG "
346- echo " # ====== mios-build.log ======" >> " $UNIFIED_LOG "
347- [[ -f " $BUILD_LOG " ]] && cat " $BUILD_LOG " >> " $UNIFIED_LOG " || true
379+ {
380+ echo " # MiOS ${VERSION_STR} Unified Build Log Chain — $( date ' +%Y-%m-%d %H:%M:%S' ) "
381+ echo " "
382+ echo " # ====== build-time :latest -> observed-version manifest ======"
383+ if [[ -f " $MIOS_VERSION_MANIFEST " ]]; then
384+ cat " $MIOS_VERSION_MANIFEST "
385+ else
386+ echo " (no manifest produced)"
387+ fi
388+ for step_log in /tmp/mios-step-* .log; do
389+ [[ -f " $step_log " ]] || continue
390+ echo " "
391+ echo " # ====== $( basename " $step_log " ) ======"
392+ cat " $step_log "
393+ done
394+ echo " "
395+ echo " # ====== mios-build.log ======"
396+ [[ -f " $BUILD_LOG " ]] && cat " $BUILD_LOG " || true
397+ } > " $UNIFIED_LOG "
348398cp " $UNIFIED_LOG " /usr/lib/mios/logs/mios-build.log 2> /dev/null || true
349- _row " Unified chain log: /usr/lib/mios/logs/mios-build-chain.log"
399+
400+ # Compress the bulky logs; keep the TSV manifest uncompressed for direct query.
401+ gzip -9f /usr/lib/mios/logs/mios-build-chain.log /usr/lib/mios/logs/mios-build.log 2> /dev/null || true
402+ gzip -9f /usr/lib/mios/logs/dnf5.log* /usr/lib/mios/logs/hawkey.log 2> /dev/null || true
403+ _row " Unified chain log: /usr/lib/mios/logs/mios-build-chain.log.gz"
350404_row " Step count in chain: $( ls /tmp/mios-step-* .log 2> /dev/null | wc -l) "
351405
352406# ── Cleanup ─────────────────────────────────────────────────────────────────
@@ -356,7 +410,7 @@ rm -rf /usr/share/doc/* /usr/share/man/* /usr/share/info/* 2>/dev/null || true
356410rm -rf /usr/share/gnome/help/* /usr/share/help/* 2> /dev/null || true
357411rm -f /var/log/dnf5.log* /var/log/hawkey.log 2> /dev/null || true
358412rm -rf /run/ceph /run/cockpit /run/k3s /tmp/mios-step-* .log 2> /dev/null || true
359- rm -f /var/lib/systemd/random-seed /tmp/mios-build.log 2> /dev/null || true
413+ rm -f /var/lib/systemd/random-seed /tmp/mios-build.log " $MIOS_VERSION_MANIFEST " 2> /dev/null || true
360414
361415# ── Final summary + failure/warn report ──────────────────────────────────────
362416TOTAL_ELAPSED=$(( SECONDS - TOTAL_START ))
0 commit comments