diff --git a/README.md b/README.md index 315f19f..c7fba93 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,18 @@ # Deinonyxus   [![bluebuild build badge](https://github.com/randogoth/deinonyxus/actions/workflows/build.yml/badge.svg)](https://github.com/randogoth/deinonyxus/actions/workflows/build.yml) -*Deinonyxus* is a personal spin of the UBlue Bluefin DX image with the 🍦[Lix](https://lix.systems/) flavored Nix package manager baked in. +*Deinonyxus* is a personal spin of the UBlue Bluefin DX image with the 🍦[Lix](https://lix.systems/) flavored Nix package manager baked in and a first-login bootstrap for simple declarative package management using [curator](https://codeberg.org/randogoth/curator). ## What’s inside - Base: `ghcr.io/ublue-os/bluefin-dx:latest` without Cockpit, Docker, Firefox, VS Code +- Lix: multi-user install baked in with persistence at `/var/home/nix`; `nix-daemon.service` enabled. +(D) - First-login bootstrap: installs Lix/nix packages `devbox`, `mc`, and `micro` via `curator` - System packages added: `syncthing`, `uv`, `vscodium`, `waydroid`; -- System flatpaks added: Telegram Desktop, Waterfox browser +- System flatpaks added: Telegram Desktop, Zen Browser + +## First login +- Triggers for each non-root user on their first session. +- Writes state to `~/.local/state/deinonyxus/curator-init.done`; delete it to rerun. +- Bootstraps `~/.config/curator/inventory.toml` and runs `curator switch` with the packages set above. ## Just Recipes - `upgrade-nix`: upgrades to the latest version of Lix via the user profile. Replaces `nix upgrade-nix` which does not work with an immutable lowerdir `/nix/store` folder diff --git a/files/scripts/install-lix.sh b/files/scripts/install-lix.sh index 08d3cba..59ba7dc 100755 --- a/files/scripts/install-lix.sh +++ b/files/scripts/install-lix.sh @@ -5,7 +5,7 @@ set -euo pipefail rpm_url="https://nix-community.github.io/nix-installers/lix/x86_64/lix-multi-user-2.91.1.rpm" -install -d /usr/share/nix-store /var/lib/nix-store /nix /etc/nix +install -d /usr/share/nix-store /var/lib/nix-store /var/cache/nix-store /nix /etc/nix # Avoid systemd calls during RPM %post in the image build environment. export SYSTEMD_OFFLINE=1 @@ -40,9 +40,8 @@ ensure_list_value() { ensure_list_value "substituters" "$lix_cache_url" ensure_list_value "trusted-public-keys" "$lix_cache_key" -# === SEED STORE FOR FIRST BOOT (copied into /var on boot) === +# === MOVE INITIAL NIX STORE TO LOWERDIR === if compgen -G "/nix/*" >/dev/null; then - rsync -aH --delete /nix/ /usr/share/nix-store/ - rm -rf /nix/* + mv /nix/* /usr/share/nix-store/ fi diff --git a/files/system/etc/modules-load.d/overlay.conf b/files/system/etc/modules-load.d/overlay.conf new file mode 100644 index 0000000..08047cf --- /dev/null +++ b/files/system/etc/modules-load.d/overlay.conf @@ -0,0 +1 @@ +overlay diff --git a/files/system/etc/selinux/targeted/contexts/files/file_contexts.local b/files/system/etc/selinux/targeted/contexts/files/file_contexts.local deleted file mode 100644 index 541fc38..0000000 --- a/files/system/etc/selinux/targeted/contexts/files/file_contexts.local +++ /dev/null @@ -1,2 +0,0 @@ -/nix(/.*)? system_u:object_r:bin_t:s0 -/var/lib/nix-store(/.*)? system_u:object_r:bin_t:s0 diff --git a/files/system/etc/systemd/system/nix-daemon.service.d/selinux.conf b/files/system/etc/systemd/system/nix-daemon.service.d/selinux.conf deleted file mode 100644 index 1b14e8b..0000000 --- a/files/system/etc/systemd/system/nix-daemon.service.d/selinux.conf +++ /dev/null @@ -1,5 +0,0 @@ -[Service] -# Run the daemon unconfined to avoid SELinux denials on the Nix store binaries. -SELinuxContext=system_u:system_r:unconfined_service_t:s0 -ExecStart= -ExecStart=/usr/bin/nix-daemon-wrapper.sh --daemon diff --git a/files/system/usr/bin/mount-nix-overlay.sh b/files/system/usr/bin/mount-nix-overlay.sh new file mode 100755 index 0000000..22ad012 --- /dev/null +++ b/files/system/usr/bin/mount-nix-overlay.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -euo pipefail + +mkdir -p /usr/share/nix-store /var/lib/nix-store /var/cache/nix-store /nix + +# Skip if already mounted to avoid errors on reload. +if mountpoint -q /nix; then + exit 0 +fi + +mount -t overlay overlay \ + -o lowerdir=/usr/share/nix-store,upperdir=/var/lib/nix-store,workdir=/var/cache/nix-store \ + /nix diff --git a/files/system/usr/bin/mount-nix.sh b/files/system/usr/bin/mount-nix.sh deleted file mode 100755 index b580557..0000000 --- a/files/system/usr/bin/mount-nix.sh +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -# Bind-mount /var/lib/nix-store to /nix. -# If /var/lib/nix-store is empty, seed it from the baked store in /usr/share/nix-store. - -mkdir -p /usr/share/nix-store /var/lib/nix-store /nix - -copy_seed_store() { - if command -v rsync >/dev/null 2>&1; then - rsync -aH --delete /usr/share/nix-store/ /var/lib/nix-store/ - else - cp -a /usr/share/nix-store/. /var/lib/nix-store/ - fi -} - -sync_missing_store() { - # Ensure any baked store paths exist in /var without clobbering user additions. - if command -v rsync >/dev/null 2>&1; then - rsync -aH --ignore-existing /usr/share/nix-store/store/ /var/lib/nix-store/store/ - fi -} - -ensure_system_profile() { - local seed_profile="/usr/share/nix-store/var/nix/profiles/system" - local target_profile="/var/lib/nix-store/var/nix/profiles/system" - - mkdir -p /var/lib/nix-store/var/nix/profiles - - if { [ ! -e "$target_profile" ] || [ -L "$target_profile" ] && [ ! -e "$(readlink -f "$target_profile")" ]; } \ - && { [ -e "$seed_profile" ] || [ -L "$seed_profile" ]; }; then - cp -a "$seed_profile" "$target_profile" - fi -} - -if ! mountpoint -q /nix; then - if [ -z "$(ls -A /var/lib/nix-store 2>/dev/null)" ] && compgen -G "/usr/share/nix-store/*" >/dev/null; then - copy_seed_store - fi - - ensure_system_profile - sync_missing_store - - mount --bind /var/lib/nix-store /nix - # Force an executable SELinux context on the bind mount so systemd can exec nix-daemon. - # Use a permissive fallback if the label option is rejected. - if ! mount -o remount,bind,exec,context=system_u:object_r:bin_t:s0 /nix 2>/dev/null; then - mount -o remount,bind,exec /nix - fi - - # Ensure daemon paths exist and labels are sane. - if command -v systemd-tmpfiles >/dev/null 2>&1; then - systemd-tmpfiles --create /usr/lib/tmpfiles.d/nix-daemon.conf - fi - if command -v restorecon >/dev/null 2>&1; then - restorecon -RF /var/lib/nix-store /nix || true - fi -fi diff --git a/files/system/usr/bin/nix-daemon-wrapper.sh b/files/system/usr/bin/nix-daemon-wrapper.sh deleted file mode 100644 index bf2cf58..0000000 --- a/files/system/usr/bin/nix-daemon-wrapper.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env bash -exec /nix/var/nix/profiles/system/bin/nix-daemon "$@" diff --git a/files/system/usr/lib/systemd/system/nix-overlay.service b/files/system/usr/lib/systemd/system/nix-overlay.service index e0b8c8e..df9b154 100644 --- a/files/system/usr/lib/systemd/system/nix-overlay.service +++ b/files/system/usr/lib/systemd/system/nix-overlay.service @@ -1,15 +1,14 @@ [Unit] -Description=Bind-mount /var/lib/nix-store to /nix +Description=Mount OverlayFS for /nix DefaultDependencies=no After=local-fs.target -RequiresMountsFor=/var /var/lib/nix-store -Before=nix-daemon.service nix-daemon.socket -ConditionPathExists=/usr/bin/mount-nix.sh +Before=nix-daemon.service +ConditionPathExists=/usr/bin/mount-nix-overlay.sh [Service] Type=oneshot -ExecStart=/usr/bin/mount-nix.sh +ExecStart=/usr/bin/mount-nix-overlay.sh RemainAfterExit=yes [Install] -WantedBy=sysinit.target +WantedBy=multi-user.target diff --git a/files/system/usr/lib/systemd/user/default.target.wants/deinonyxus-curator-init.service b/files/system/usr/lib/systemd/user/default.target.wants/deinonyxus-curator-init.service new file mode 120000 index 0000000..e7af513 --- /dev/null +++ b/files/system/usr/lib/systemd/user/default.target.wants/deinonyxus-curator-init.service @@ -0,0 +1 @@ +/var/home/randogoth/Projects/code/randofin-os/files/system/usr/lib/systemd/user/deinonyxus-curator-init.service \ No newline at end of file diff --git a/files/system/usr/lib/systemd/user/deinonyxus-curator-init.service b/files/system/usr/lib/systemd/user/deinonyxus-curator-init.service new file mode 100644 index 0000000..9963d06 --- /dev/null +++ b/files/system/usr/lib/systemd/user/deinonyxus-curator-init.service @@ -0,0 +1,13 @@ +[Unit] +Description=Install Nix Home Manager and packages on first login +ConditionUser=!root +ConditionPathExists=!%h/.local/state/deinonyxus/curator-init.done + +[Service] +Type=oneshot +ExecStart=/usr/libexec/deinonyxus/curator.sh +ExecStartPost=/usr/bin/mkdir -p %h/.local/state/deinonyxus +ExecStartPost=/usr/bin/touch %h/.local/state/deinonyxus/curator-init.done + +[Install] +WantedBy=default.target diff --git a/files/system/usr/libexec/deinonyxus/curator.sh b/files/system/usr/libexec/deinonyxus/curator.sh new file mode 100755 index 0000000..4fc2b1c --- /dev/null +++ b/files/system/usr/libexec/deinonyxus/curator.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -oue pipefail + +curator_git="--from git+https://codeberg.org/randogoth/curator/" + +uvx $curator_git curator init +uvx $curator_git curator add nix:mc nix:micro nix:devbox +uvx $curator_git curator switch +uv tool install $curator_git curator \ No newline at end of file diff --git a/recipes/recipe.yml b/recipes/recipe.yml index 334c70e..4d5ccf6 100644 --- a/recipes/recipe.yml +++ b/recipes/recipe.yml @@ -13,16 +13,6 @@ image-version: latest # latest is also supported if you want new updates ASAP # you can include multiple instances of the same module modules: - - type: os-release - properties: - ID: deinonyxus - NAME: Deinonyxus - PRETTY_NAME: Deinonyxus (Bluefin DX) - DEFAULT_HOSTNAME: deinonyxus - HOME_URL: https://codeberg.org/randogoth/deinonyxus - SUPPORT_URL: https://codeberg.org/randogoth/deinonyxus/issues - BUG_REPORT_URL: https://codeberg.org/randogoth/deinonyxus/issues - - type: files files: - source: system @@ -37,13 +27,11 @@ modules: enabled: - nix-overlay.service - nix-daemon.service - - nix-daemon.socket - type: dnf repos: - files: - add: - - https://repo.vscodium.dev/vscodium.repo + files: + - https://repo.vscodium.dev/vscodium.repo install: packages: - repo: vscodium @@ -69,6 +57,8 @@ modules: - docker-ce-rootless-extras - docker-compose-plugin - docker-model-plugin + - containerd + - moby-engine - type: justfiles include: @@ -80,7 +70,7 @@ modules: scope: system # If no repo information is specified, Flathub will be used by default install: # system flatpaks we want all users to have and not remove - - net.waterfox.waterfox + - app.zen_browser.zen - org.telegram.desktop remove: # replace default Firefox with Waterfox - org.mozilla.firefox