Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
c80f64d
archiso: modernize profile for current archiso
haiderbassem-swibit Sep 27, 2026
c6b5f22
boot/kernel: make every boot path agree on linux-cachyos
haiderbassem-swibit Sep 27, 2026
90ea10c
desktop: replace inherited personal dotfiles with a shipped Hyprland …
haiderbassem-swibit Sep 27, 2026
5b6c804
live: coherent session, service, network and audio configuration
haiderbassem-swibit Sep 27, 2026
5ef8e4f
installer: SimulationOS Calamares configuration and launcher
haiderbassem-swibit Sep 27, 2026
482851f
branding: SimulationOS identity; remove inherited dead code
haiderbassem-swibit Sep 27, 2026
4d269d3
tooling: profile validator, build, clean and QEMU test scripts
haiderbassem-swibit Sep 27, 2026
ebd7a45
docs: rewrite README and add architecture rationale
haiderbassem-swibit Sep 27, 2026
c60830b
build: single ./build.sh entry point with an x86_64 container builder
haiderbassem-swibit Sep 27, 2026
e8f7d23
docs: README reflects ./build.sh and records new verification evidence
haiderbassem-swibit Sep 27, 2026
a2d30a9
build: keep the work directory off case-insensitive filesystems
haiderbassem-swibit Sep 27, 2026
9797113
ci: L4 automated boot test
haiderbassem-swibit Sep 27, 2026
b5bca60
initramfs: drop PXE hooks and the dead PXE boot configs
haiderbassem-swibit Sep 27, 2026
f706d24
build: fix build-info.json generation and ISO inspection paths
haiderbassem-swibit Sep 27, 2026
5dd0b16
build: record the real git commit in build-info.json
haiderbassem-swibit Sep 27, 2026
0cb1419
docs: record verified ISO build evidence
haiderbassem-swibit Sep 27, 2026
c91b669
test: locate OVMF on macOS/Homebrew and allow accel override
haiderbassem-swibit Sep 27, 2026
7e475cc
boot: emit the kernel console to serial as well as tty0
haiderbassem-swibit Sep 27, 2026
a1265ba
build: do not warn about valid JSON
haiderbassem-swibit Sep 27, 2026
fc58cf0
boot: SimulationOS boots to a login prompt (VERIFIED)
haiderbassem-swibit Sep 27, 2026
fb14994
test(deloop): verify the de-live security contract against the real ISO
haiderbassem-swibit Sep 28, 2026
7bac0f6
test(live): assert on running state inside the booted live system
haiderbassem-swibit Sep 28, 2026
233c663
ci: complete the Alpha acceptance pipeline
haiderbassem-swibit Sep 28, 2026
d01160a
fix(build): choose a container runtime that can actually mount
haiderbassem-swibit Sep 28, 2026
67c3846
fix(ci): install bsdtar before inspecting the ISO
haiderbassem-swibit Sep 28, 2026
2e8994e
fix(test): bind the QEMU audio device to an audiodev
haiderbassem-swibit Sep 28, 2026
38438d7
fix(test): stop pagers and fixed sleeps corrupting the serial session
haiderbassem-swibit Sep 28, 2026
5647aaf
fix(test): markers must come from guest output, not terminal echo
haiderbassem-swibit Sep 28, 2026
1e1aa47
fix(test): clean the console stream before matching, and attach OVMF
haiderbassem-swibit Sep 28, 2026
b2df467
fix(test): normalise markers; test portals by D-Bus activation
haiderbassem-swibit Sep 28, 2026
6bcbb90
fix(test): wait for the desktop to settle; match service states exactly
haiderbassem-swibit Sep 28, 2026
9ca4549
chore: ignore downloaded CI artifacts
haiderbassem-swibit Sep 28, 2026
4a277a5
chore: ignore .DS_Store
haiderbassem-swibit Sep 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 76 additions & 0 deletions .github/workflows/acceptance.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# L4b/L5 - runtime acceptance of the built ISO on an x86_64 runner.
#
# Two jobs, deliberately separate so a live-desktop regression is
# distinguishable from a security-cleanup regression:
#
# live-health boots the ISO, logs in on serial and asserts on RUNNING
# state: graphical.target, SDDM, Hyprland, session
# components, NetworkManager, DNS, PipeWire, portals.
# deloop-contract extracts the SquashFS, runs simulationos-deloop exactly as
# Calamares does, and asserts the installed-system security
# gates (liveuser gone, autologin gone, NOPASSWD gone, root
# locked, archiso initramfs hook gone).
name: acceptance

on:
workflow_dispatch:
workflow_call:
inputs:
artifact:
description: Name of the ISO artifact to test
type: string
required: true

permissions:
contents: read

jobs:
live-health:
name: Live system health
runs-on: ubuntu-latest
timeout-minutes: 60
steps:
- uses: actions/checkout@v4
- name: Install QEMU and OVMF
run: |
sudo apt-get update -qq
sudo apt-get install -y -qq qemu-system-x86 ovmf
- name: Download the ISO
uses: actions/download-artifact@v4
with:
name: ${{ inputs.artifact }}
path: out
- name: KVM availability
run: |
# Hosted runners have no nested virtualisation; TCG is correct but
# slow. This is recorded so a timeout can be attributed correctly.
if [ -e /dev/kvm ]; then echo "KVM available"; else echo "no /dev/kvm -> TCG"; fi
- name: Live health checks
env:
SIMOS_LIVE_TIMEOUT: '2100'
run: ./scripts/live-health.sh
- name: Upload live log
if: always()
uses: actions/upload-artifact@v4
with:
name: live-health-log-${{ github.sha }}
path: out/live-health.log
if-no-files-found: ignore

deloop-contract:
name: De-live security contract
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
- name: Install extraction tools
run: |
sudo apt-get update -qq
sudo apt-get install -y -qq squashfs-tools libarchive-tools
- name: Download the ISO
uses: actions/download-artifact@v4
with:
name: ${{ inputs.artifact }}
path: out
- name: Verify the de-live transformation
run: sudo ./scripts/deloop-test.sh
63 changes: 63 additions & 0 deletions .github/workflows/boot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# L4 - boot the built ISO in QEMU and require proof it reached a target.
#
# Split from iso.yml so a boot regression is distinguishable from a build
# regression at a glance.
name: boot-test

on:
workflow_dispatch:
workflow_call:
inputs:
artifact:
description: Name of the ISO artifact to boot
type: string
required: true

permissions:
contents: read

jobs:
boot:
name: QEMU boot (${{ matrix.firmware }})
runs-on: ubuntu-latest
timeout-minutes: 45
strategy:
fail-fast: false
matrix:
# SimulationOS declares bios.syslinux and uefi.systemd-boot, so both
# are tested. Do not add firmware here that the profile does not
# actually support.
firmware: [uefi, bios]
steps:
- uses: actions/checkout@v4

- name: Install QEMU and OVMF
run: |
sudo apt-get update -qq
sudo apt-get install -y -qq qemu-system-x86 ovmf

- name: Download the ISO built by this pipeline
uses: actions/download-artifact@v4
with:
name: ${{ inputs.artifact }}
path: out

- name: Enable KVM if the runner provides it
run: |
# Hosted runners usually have no nested virtualisation; TCG is the
# fallback and is slow but correct.
[ -e /dev/kvm ] && echo "KVM available" || echo "no /dev/kvm; using TCG"

- name: Boot test
env:
SIMOS_BOOT_TEST_FIRMWARE: ${{ matrix.firmware }}
SIMOS_BOOT_TEST_TIMEOUT: '1500'
run: ./scripts/boot-test.sh

- name: Upload serial console log
if: always()
uses: actions/upload-artifact@v4
with:
name: boot-log-${{ matrix.firmware }}
path: out/boot-test-*.log
if-no-files-found: ignore
100 changes: 100 additions & 0 deletions .github/workflows/iso.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# L2/L3 - build the ISO in a clean environment and inspect the artefact.
#
# Runs ./build.sh, the same entry point developers use. build.sh detects that
# the runner is not Arch and drives an x86_64 Arch container itself, so there
# is exactly one build engine and CI cannot drift from local behaviour.
name: iso

on:
push:
branches: [main, 'feat/**']
paths-ignore: ['**.md', 'docs/**', 'LICENSE']
pull_request:
paths-ignore: ['**.md', 'docs/**', 'LICENSE']
workflow_dispatch:
workflow_call:

permissions:
contents: read

jobs:
validate:
uses: ./.github/workflows/validate.yml

build:
name: Build ISO
needs: validate
runs-on: ubuntu-latest
timeout-minutes: 90
outputs:
iso_name: ${{ steps.meta.outputs.iso_name }}
iso_sha256: ${{ steps.meta.outputs.iso_sha256 }}
steps:
- uses: actions/checkout@v4

- name: Free disk space
# A 2.1 GB ISO plus a ~4 GB unpacked rootfs plus ~1.4 GB of packages
# does not fit alongside the runner's preinstalled toolchains.
run: |
df -h /
sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc \
/usr/local/share/boost "$AGENT_TOOLSDIRECTORY" || true
sudo apt-get clean || true
df -h /

- name: Install inspection tools
# inspect-iso.sh reads the ISO9660 filesystem with bsdtar, which
# ubuntu-latest does not ship (it lives in libarchive-tools).
run: sudo apt-get update -qq && sudo apt-get install -y -qq libarchive-tools

- name: Build (via ./build.sh)
run: ./build.sh

- name: Inspect the artefact
run: ./scripts/inspect-iso.sh

- name: Collect metadata
id: meta
run: |
iso="$(ls -1 out/simulationos-*.iso | head -1)"
echo "iso_name=$(basename "$iso")" >> "$GITHUB_OUTPUT"
echo "iso_sha256=$(cut -d' ' -f1 < "$iso.sha256")" >> "$GITHUB_OUTPUT"
echo "### SimulationOS ISO" >> "$GITHUB_STEP_SUMMARY"
echo '```json' >> "$GITHUB_STEP_SUMMARY"
cat out/build-info.json >> "$GITHUB_STEP_SUMMARY"
echo '```' >> "$GITHUB_STEP_SUMMARY"

- name: Upload ISO
uses: actions/upload-artifact@v4
with:
name: simulationos-alpha-${{ github.sha }}-x86_64
path: |
out/*.iso
out/*.iso.sha256
out/build-info.json
retention-days: 14
if-no-files-found: error
compression-level: 0

- name: Upload build log
if: always()
uses: actions/upload-artifact@v4
with:
name: build-log-${{ github.sha }}
path: out/build.log
retention-days: 14
if-no-files-found: ignore

boot:
name: Boot test
needs: build
uses: ./.github/workflows/boot.yml
with:
artifact: simulationos-alpha-${{ github.sha }}-x86_64

acceptance:
name: Runtime acceptance
needs: [build, boot]
uses: ./.github/workflows/acceptance.yml
with:
artifact: simulationos-alpha-${{ github.sha }}-x86_64
85 changes: 85 additions & 0 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# L1 - fast static validation. Runs on every push and PR.
# Deliberately needs no container and no pacman, so it finishes in seconds.
name: validate

on:
push:
branches: ['**']
pull_request:
workflow_call:

permissions:
contents: read

jobs:
static:
name: Static validation
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Install shellcheck
run: sudo apt-get update -qq && sudo apt-get install -y -qq shellcheck

- name: Validate profile
run: ./scripts/validate-profile.sh

- name: Shell syntax
run: |
fail=0
while IFS= read -r f; do
head -1 "$f" | grep -qE '^#!.*(bash|sh)' || continue
bash -n "$f" || { echo "syntax error: $f"; fail=1; }
done < <(git ls-files | grep -vE '\.(md|png|svg|conf|desc|qml|css|jsonc)$')
exit $fail

- name: ShellCheck
run: |
shellcheck -S warning build.sh scripts/*.sh \
airootfs/usr/local/bin/simos-* \
airootfs/usr/local/bin/simulationos-install \
airootfs/usr/share/simulationos/calamares/scripts/simulationos-deloop

- name: Installer config is valid YAML
run: |
python3 - <<'PY'
import glob, sys, yaml
bad = 0
files = glob.glob("airootfs/usr/share/simulationos/calamares/**/*.conf", recursive=True)
files += glob.glob("airootfs/usr/share/simulationos/calamares/branding/*/branding.desc")
for f in files:
try:
yaml.safe_load(open(f))
except Exception as e:
print(f"YAML ERROR {f}: {e}"); bad = 1
print(f"checked {len(files)} installer config files")
sys.exit(bad)
PY

- name: Waybar config is valid JSON
run: |
python3 - <<'PY'
import json, re, sys
t = open("airootfs/etc/skel/.config/waybar/config.jsonc").read()
json.loads(re.sub(r'^\s*//.*$', '', t, flags=re.M))
print("waybar config.jsonc OK")
PY

- name: No secrets committed
run: |
# Deliberately narrow: private keys and obvious credential material.
if git grep -nIE 'BEGIN (RSA|OPENSSH|PGP|EC) PRIVATE KEY|ghp_[A-Za-z0-9]{30,}|AKIA[0-9A-Z]{16}' -- . ; then
echo "::error::possible secret committed"; exit 1
fi
echo "no secrets found"

- name: Validator must actually catch regressions
run: |
# A validator that never fails is worthless. Prove it still bites.
set -e
tmp=$(mktemp -d); cp -R . "$tmp/repo"; cd "$tmp/repo"
sed -i 's/vmlinuz-linux-cachyos/vmlinuz-linux/' efiboot/loader/entries/01-simulationos-linux.conf
if ./scripts/validate-profile.sh >/dev/null 2>&1; then
echo "::error::validator did NOT catch an injected kernel-name regression"; exit 1
fi
echo "validator correctly rejected the injected regression"
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# mkarchiso build artefacts
/work/
/out/
# local pacman package cache used by the containerised builder
/.cache/
/artifacts/
.DS_Store
Loading
Loading