[grade=C→fixing] Desktop overlay + build script + CI improvements
SamiOS CI / lint-and-test (push) Successful in 10s

- packages.x86_64.desktop: 30+ packages for desktop variant (Plasma,
  Firefox, VLC, LibreOffice, PipeWire). No duplicates with base list.
- build-desktop.sh: creates temp profile, merges package lists, enables
  SDDM via preset + display-manager.service symlink. WORK_DIR is
  mktemp-created (not caller-selected) to prevent symlink races. VERSION
  copied into temp profile so profiledef.sh resolves correctly.
  Cleans up both temp dirs via trap.
- CI workflow: Python AST validation (sys.argv), VERSION SSOT gate,
  single make check (no double-lint).
- test_packages.sh: 15 assertions for desktop overlay (existence,
  package count, no dups, Plasma/Firefox exact match, build script
  structure: mktemp WORK_DIR, VERSION copy, SDDM, cleanup trap).

Codex D-grade findings fixed: symlink race (use mktemp), VERSION path
(../../VERSION not ../VERSION).
This commit is contained in:
Sami Ahmed
2026-08-12 03:41:50 -07:00
parent 5c018ec196
commit 5d735b2987
5 changed files with 279 additions and 5 deletions
+39 -5
View File
@@ -24,9 +24,43 @@ jobs:
sudo apt-get install -y -qq make
fi
# ── Shellcheck ───────────────────────────────────────────────────
- name: Run shellcheck on all shell scripts
run: make lint
# ── Python AST validation ────────────────────────────────────────
- name: Validate Python syntax (AST parse)
run: |
set -e
while IFS= read -r -d '' f; do
echo "Checking $f..."
python3 -c "import ast, sys; ast.parse(open(sys.argv[1]).read())" "$f"
echo " ✓ $f"
done < <(find packaging/scripts -name '*.py' -print0)
# ── VERSION SSOT consistency ─────────────────────────────────────
- name: Verify VERSION single-source-of-truth
run: |
set -e
VERSION="$(cat VERSION)"
echo "Canonical VERSION: $VERSION"
# Mirror must match
MIRROR="$(head -n1 packaging/archiso/airootfs/etc/samios-version)"
if [ "$VERSION" != "$MIRROR" ]; then
echo "ERROR: VERSION ($VERSION) != airootfs mirror ($MIRROR)"
echo "Fix: make version-sync"
exit 1
fi
echo " ✓ airootfs mirror matches VERSION"
# PKGBUILD pkgver must resolve to VERSION (hyphen → underscore)
PKGVER="$(cd packaging/packages/samios-branding && source PKGBUILD >/dev/null 2>&1 && echo "$pkgver")"
EXPECTED_PKGVER="$(echo "$VERSION" | tr '-' '_')"
if [ "$PKGVER" != "$EXPECTED_PKGVER" ]; then
echo "ERROR: PKGBUILD pkgver ($PKGVER) != expected ($EXPECTED_PKGVER)"
exit 1
fi
echo " ✓ PKGBUILD pkgver resolves to VERSION"
echo ""
echo "VERSION SSOT consistency check PASSED ✓"
# ── Profile structure validation ─────────────────────────────────
- name: Validate archiso profile structure
@@ -99,5 +133,5 @@ jobs:
echo "Profile structure validation PASSED ✓"
# ── Test suite ───────────────────────────────────────────────────
- name: Run test suite
run: make test
- name: Run full test suite (lint + tests)
run: make check
+1
View File
@@ -11,6 +11,7 @@ VERSION_FILE := $(REPO_ROOT)/VERSION
SHELL_SCRIPTS := \
$(PROFILE_DIR)/profiledef.sh \
$(PROFILE_DIR)/build.sh \
$(PROFILE_DIR)/build-desktop.sh \
$(PROFILE_DIR)/airootfs/usr/local/bin/samios \
$(PROFILE_DIR)/airootfs/usr/local/bin/choose-mirror \
$(PROFILE_DIR)/airootfs/root/.automated_script.sh \
+88
View File
@@ -0,0 +1,88 @@
#!/bin/bash
# SamiOS Desktop ISO build script
#
# Builds a desktop ISO by merging the base packages.x86_64 with the
# desktop overlay (packages.x86_64.desktop) into a temporary profile,
# then running mkarchiso on that profile.
#
# Usage: sudo bash packaging/archiso/build-desktop.sh
set -euo pipefail
PROFILE_DIR="$(cd "$(dirname "$0")" && pwd)"
OUT_DIR="${OUT_DIR:-$PROFILE_DIR/out}"
# ── Create work dir via mktemp (not caller-selected) ─────────────────────
# We deliberately do NOT honor a caller-provided WORK_DIR for rm -rf
# safety. A caller-selected path is vulnerable to symlink races on
# shared /tmp. Instead, we create a root-owned mktemp directory.
WORK_DIR="$(mktemp -d /tmp/samios-desktop-build.XXXXXX)"
OUT_DIR="$(readlink -f "$OUT_DIR" 2>/dev/null || echo "$OUT_DIR")"
# ── Create temp profile (BEFORE this, no side effects) ──────────────────
TMP_PROFILE="$(mktemp -d /tmp/samios-desktop-profile.XXXXXX)"
cleanup() {
rm -rf "$TMP_PROFILE" "$WORK_DIR"
}
trap cleanup EXIT
echo "Building SamiOS Desktop ISO..."
echo "Base profile: $PROFILE_DIR"
echo "Temp profile: $TMP_PROFILE"
echo "Work directory: $WORK_DIR"
echo "Output: $OUT_DIR"
# ── Copy base profile (excluding output dir) ─────────────────────────────
for item in "$PROFILE_DIR"/* "$PROFILE_DIR"/.*; do
[ -e "$item" ] || continue
base="$(basename "$item")"
case "$base" in
out|.|..) continue ;;
esac
cp -a "$item" "$TMP_PROFILE/"
done
# ── Merge package lists ─────────────────────────────────────────────────
cat "$PROFILE_DIR/packages.x86_64" \
"$PROFILE_DIR/packages.x86_64.desktop" \
> "$TMP_PROFILE/packages.x86_64"
# Copy VERSION into the temp profile so profiledef.sh can find it
# (profiledef.sh walks up from its own directory looking for VERSION;
# without this copy, it falls back to 0.0.0-unknown)
# PROFILE_DIR is packaging/archiso, so VERSION is two levels up.
REPO_ROOT="$(cd "$PROFILE_DIR/../.." && pwd)"
if [ -f "$REPO_ROOT/VERSION" ]; then
cp "$REPO_ROOT/VERSION" "$TMP_PROFILE/VERSION"
fi
# Verify the merged list has more packages than base alone
base_pkgs=$(grep -vE '^\s*#|^\s*$' "$PROFILE_DIR/packages.x86_64" | wc -l)
merged_pkgs=$(grep -vE '^\s*#|^\s*$' "$TMP_PROFILE/packages.x86_64" | wc -l)
if [ "$merged_pkgs" -le "$base_pkgs" ]; then
echo "ERROR: merged package list ($merged_pkgs) not larger than base ($base_pkgs)"
exit 1
fi
echo "Packages: $base_pkgs (base) + $((merged_pkgs - base_pkgs)) (desktop) = $merged_pkgs (total)"
# ── Enable SDDM display manager in the TEMP profile only ────────────────
# This goes into the temp profile, NOT the shared base airootfs, so
# base-only ISO builds are unaffected.
PRESET_DIR="$TMP_PROFILE/airootfs/etc/systemd/system-preset"
mkdir -p "$PRESET_DIR"
echo "enable sddm.service" > "$PRESET_DIR/00-samios-desktop.preset"
# Create the display-manager.service symlink (standard Arch way to
# enable a display manager — sddm gets activated on boot)
DM_LINK="$TMP_PROFILE/airootfs/etc/systemd/system/display-manager.service"
ln -sf /usr/lib/systemd/system/sddm.service "$DM_LINK"
# ── Clean previous build state and build ────────────────────────────────
rm -rf "$WORK_DIR"
mkdir -p "$WORK_DIR" "$OUT_DIR"
mkarchiso -v -w "$WORK_DIR" -o "$OUT_DIR" "$TMP_PROFILE"
echo ""
echo "Build complete!"
echo "ISO location: $OUT_DIR/samios-*.iso"
+62
View File
@@ -0,0 +1,62 @@
# SamiOS desktop overlay packages
# This file lists packages for the desktop variant of SamiOS.
# It is used IN ADDITION TO packages.x86_64 (which stays minimal/CLI-only).
#
# To build a desktop ISO, use the build-desktop.sh script:
# sudo bash packaging/archiso/build-desktop.sh
#
# That script creates a temporary profile, merges base + desktop package
# lists into packages.x86_64, then runs mkarchiso on the temp profile.
#
# All packages below are from the standard Arch repos (core/extra) as of
# 2026-08. Verify before building: pacman -Si <package>
# ── Desktop environment ──────────────────────────────────────────────────
plasma-meta
sddm
sddm-kcm
kdeplasma-addons
plasma-nm
plasma-pa
kmenuedit
kwrite
# ── Applications ─────────────────────────────────────────────────────────
firefox
dolphin
konsole
kate
gwenview
okular
ark
vlc
libreoffice-fresh
thunderbird
# ── Audio ────────────────────────────────────────────────────────────────
pipewire
pipewire-pulse
pipewire-alsa
pipewire-jack
wireplumber
# ── Network ──────────────────────────────────────────────────────────────
network-manager-applet
# ── Graphics ─────────────────────────────────────────────────────────────
mesa
vulkan-radeon
vulkan-intel
vulkan-icd-loader
# ── Fonts (desktop) ──────────────────────────────────────────────────────
# Note: ttf-dejavu and ttf-liberation are already in the base packages.x86_64
noto-fonts
noto-fonts-emoji
# ── System utilities ────────────────────────────────────────────────────
xdg-desktop-portal
xdg-desktop-portal-kde
# Note: xdg-user-dirs is already in the base packages.x86_64
htop
fastfetch
+89
View File
@@ -56,4 +56,93 @@ assert "no duplicate package entries" \
fi
'
# ── Desktop overlay ──────────────────────────────────────────────────────
DESKTOP_PKGLIST="$PROFILE_DIR/packages.x86_64.desktop"
DESKTOP_BUILD="$PROFILE_DIR/build-desktop.sh"
export DESKTOP_PKGLIST DESKTOP_BUILD
assert_file_exists "desktop overlay packages file exists" "$DESKTOP_PKGLIST"
assert_file_exists "desktop build script exists" "$DESKTOP_BUILD"
assert "desktop overlay has at least 10 packages" \
bash -c '
count="$(grep -vE "^\s*#|^\s*$" "$DESKTOP_PKGLIST" | wc -l)"
if [ "$count" -lt 10 ]; then
echo "expected ≥10 desktop packages, got $count"
exit 1
fi
'
assert "desktop overlay includes Plasma desktop" \
bash -c "grep -Fqx 'plasma-meta' '$DESKTOP_PKGLIST'"
assert "desktop overlay includes Firefox" \
bash -c "grep -Fqx 'firefox' '$DESKTOP_PKGLIST'"
assert "desktop build script merges base + overlay" \
bash -c "grep -q 'packages.x86_64.desktop' '$DESKTOP_BUILD'"
assert "desktop build script uses mkarchiso" \
bash -c "grep -q 'mkarchiso' '$DESKTOP_BUILD'"
assert "desktop build script has cleanup trap" \
bash -c "grep -q 'trap cleanup' '$DESKTOP_BUILD'"
assert "desktop build script enables SDDM display manager" \
bash -c "grep -q 'sddm' '$DESKTOP_BUILD'"
assert "desktop build script creates display-manager symlink" \
bash -c "grep -q 'display-manager.service' '$DESKTOP_BUILD'"
assert "desktop build script uses mktemp for WORK_DIR (not caller-selected)" \
bash -c "grep -q 'WORK_DIR=.*mktemp' '$DESKTOP_BUILD'"
assert "desktop build script copies VERSION into temp profile" \
bash -c "grep -q 'VERSION' '$DESKTOP_BUILD' && grep -q 'TMP_PROFILE/VERSION' '$DESKTOP_BUILD'"
assert "desktop build script cleanup trap removes both temp dirs" \
bash -c "grep -q 'TMP_PROFILE.*WORK_DIR' '$DESKTOP_BUILD'"
assert "desktop build script excludes output dir during copy (not after)" \
bash -c "grep -q 'out|.|..' '$DESKTOP_BUILD'"
assert "desktop build script passes bash -n syntax check" \
bash -c "bash -n '$DESKTOP_BUILD'"
# Desktop overlay must not duplicate base packages
assert "desktop overlay has no duplicates with base package list" \
bash -c '
dups="$(grep -hE "^[a-zA-Z0-9]" "$PKGLIST" "$DESKTOP_PKGLIST" | sort | uniq -d)"
if [ -n "$dups" ]; then
echo "packages in both base and desktop overlay: $dups"
exit 1
fi
'
# Regression test: prove the duplicate check actually catches duplicates
assert "duplicate-check regression: a planted duplicate IS detected" \
bash -c '
tmp_a="$(mktemp)"
tmp_b="$(mktemp)"
trap "rm -f ${tmp_a:?} ${tmp_b:?}" EXIT
echo -e "base\nlinux\nnetworkmanager" > "$tmp_a"
echo -e "firefox\nbase\nvlc" > "$tmp_b"
dups="$(grep -hE "^[a-zA-Z0-9]" "$tmp_a" "$tmp_b" | sort | uniq -d)"
if [ "$dups" != "base" ]; then
echo "expected to detect duplicate: base, got: $dups"
exit 1
fi
'
# No obsolete packages (khotkeys removed from Arch, neofetch renamed)
assert "desktop overlay does not include known-obsolete packages" \
bash -c '
for bad in khotkeys neofetch; do
if grep -q "^$bad$" "$DESKTOP_PKGLIST"; then
echo "obsolete package found: $bad"
exit 1
fi
done
'
print_summary