commit 13d85b92f16940824fde68a4412da98a0d3ca3aa Author: Jonathan Cremin Date: Sun Apr 6 19:35:03 2025 +0100 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100755 index 0000000..9b1960e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +output/ \ No newline at end of file diff --git a/nvidia/Containerfile b/nvidia/Containerfile new file mode 100755 index 0000000..452f65a --- /dev/null +++ b/nvidia/Containerfile @@ -0,0 +1,103 @@ +FROM ghcr.io/ublue-os/silverblue-nvidia:41 + +COPY etc /etc + +RUN dnf install -y https://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm && \ + dnf install -y https://download1.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-$(rpm -E %fedora).noarch.rpm && \ + dnf clean all + +RUN dnf remove -y \ + ptyxis \ + gnome-software \ + htop \ + gnome-classic-session \ + gnome-shell-extension-apps-menu \ + gnome-shell-extension-background-logo \ + gnome-shell-extension-launch-new-instance \ + gnome-shell-extension-places-menu \ + gnome-shell-extension-window-list \ + open-vm-tools \ + open-vm-tools-desktop \ + qemu-guest-agent \ + spice-vdagent \ + spice-webdavd \ + virtualbox-guest-additions && \ + dnf swap -y ffmpeg-free ffmpeg --allowerasing && \ + dnf swap -y libavcodec-free libavcodec-freeworld --allowerasing && \ + dnf group install -y multimedia --setopt="install_weak_deps=False" --exclude=PackageKit-gstreamer-plugin && \ + dnf copr enable -y alternateved/eza && \ + dnf install -y \ + acpi \ + akmod-v4l2loopback \ + btop \ + direnv \ + distrobox \ + eza \ + git \ + gnome-boxes \ + gstreamer1-vaapi \ + helm \ + kubectl \ + util-linux \ + lm_sensors \ + ncdu \ + pavucontrol \ + qemu-guest-agent \ + sysstat \ + tailscale \ + vdpauinfo \ + vulkan-tools \ + zsh \ + zsh-syntax-highlighting && \ + # Clean up + dnf clean all + +# Remove btop and nvtop shortcuts +RUN rm /usr/share/applications/btop.desktop /usr/share/applications/nvtop.desktop + +# Don't use the ghostty copr for now, it's broken on 42. Download the appimage in userland. +# Todo: Try again when 42 is final. +# RUN dnf copr enable -y pgdev/ghostty && \ +# dnf install -y ghostty + +# Don't install 1password, the browser integration breaks because 1Password uses /opt. +# I think this is polkit related. +# RUN mkdir -p /var/opt +# COPY scripts/1password.sh /tmp/1password.sh +# RUN /bin/sh /tmp/1password.sh + +RUN authselect enable-feature with-fingerprint + +LABEL org.opencontainers.image.description="Built on ublue-os/silverblue-main, adding more batteries" \ + org.opencontainers.image.source="https://cremin.dev/jonathan/bootc" \ + org.opencontainers.image.title="ublue-silverblue-nvidia" \ + org.opencontainers.image.url="https://cremin.dev/jonathan/bootc" \ + org.opencontainers.image.created="" \ + org.opencontainers.image.licenses="Unlicensed" \ + org.opencontainers.image.revision="" \ + org.opencontainers.image.version="" + + + + +# FROM cremin.dev/jonathan/fedora-bootc-base:42 + +# RUN echo "blacklist nouveau" > /etc/modprobe.d/blacklist_nouveau.conf + +# RUN dnf install -y --allowerasing \ +# akmod-nvidia \ +# libva-nvidia-driver \ +# nvidia-container-toolkit \ +# nvidia-vaapi-driver \ +# xorg-x11-drv-nvidia \ +# xorg-x11-drv-nvidia-cuda \ +# xorg-x11-drv-nvidia-cuda-libs \ +# xorg-x11-drv-nvidia-power && \ +# # Clean up +# dnf clean all + +# RUN akmods --force --kernels `rpm -q --queryformat '%{VERSION}-%{RELEASE}.%{ARCH}' kernel-devel` + +# RUN systemctl enable nvidia-toolkit-firstboot.service + +# COPY kargs-nvidia.toml /usr/lib/bootc/kargs.d/nvidia.toml diff --git a/nvidia/build-push.sh b/nvidia/build-push.sh new file mode 100755 index 0000000..96db3b5 --- /dev/null +++ b/nvidia/build-push.sh @@ -0,0 +1,33 @@ +#!/bin/env sh + +set -e + +# Change to the directory where the script is located +cd "$(dirname "$0")" + +DATE_TAG=$(date "+%Y%m%d-%H%M%S") +CURRENT_IMAGE_ID=$(sudo podman images --format "{{.ID}}" cremin.dev/jonathan/ublue-silverblue-main:42) + + +echo "Pulling base image" +# ensure the base image is up to date +sudo -E podman pull ghcr.io/ublue-os/silverblue-main:42 + +echo "Starting build" +sudo -E podman build -t cremin.dev/jonathan/ublue-silverblue-main:42 . + +NEW_IMAGE_ID=$(sudo podman images --format "{{.ID}}" cremin.dev/jonathan/ublue-silverblue-main:42) + + +# Start build and check if any layers were changed (looking for "Using cache" messages) +if [ "$CURRENT_IMAGE_ID" = "$NEW_IMAGE_ID" ]; then + echo "No changes detected, skipping push" +else + echo "Image updated, pushing to registry" + # Add the tags + sudo -E podman tag cremin.dev/jonathan/ublue-silverblue-main:42 cremin.dev/jonathan/ublue-silverblue-main:42-${DATE_TAG} cremin.dev/jonathan/ublue-silverblue-main:latest + # Push the image + sudo -E podman push --authfile ~/.config/containers/auth.json cremin.dev/jonathan/ublue-silverblue-main:42-${DATE_TAG} + sudo -E podman push --authfile ~/.config/containers/auth.json cremin.dev/jonathan/ublue-silverblue-main:42 + sudo -E podman push --authfile ~/.config/containers/auth.json cremin.dev/jonathan/ublue-silverblue-main:latest +fi \ No newline at end of file diff --git a/nvidia/create-installer.sh b/nvidia/create-installer.sh new file mode 100755 index 0000000..3c1c5f6 --- /dev/null +++ b/nvidia/create-installer.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env sh + +set -e + +cd "$(dirname "$0")" + +sudo podman run \ + --rm \ + -it \ + --privileged \ + --pull=newer \ + --security-opt label=type:unconfined_t \ + -v ./config.toml:/config.toml:ro \ + -v ./output:/output \ + -v /var/lib/containers/storage:/var/lib/containers/storage \ + quay.io/centos-bootc/bootc-image-builder:latest \ + --type iso \ + --rootfs btrfs \ + --use-librepo=True \ + --chown 1000:1000 \ + cremin.dev/jonathan/ublue-silverblue-main:42 diff --git a/nvidia/etc/sudoers.d/wheel-nopasswd b/nvidia/etc/sudoers.d/wheel-nopasswd new file mode 100755 index 0000000..a364129 --- /dev/null +++ b/nvidia/etc/sudoers.d/wheel-nopasswd @@ -0,0 +1,2 @@ +# Enable passwordless sudo for the wheel group +%wheel ALL=(ALL) NOPASSWD: ALL \ No newline at end of file diff --git a/nvidia/kargs-nvidia.toml b/nvidia/kargs-nvidia.toml new file mode 100755 index 0000000..71b2cbc --- /dev/null +++ b/nvidia/kargs-nvidia.toml @@ -0,0 +1,8 @@ +kargs = [ + "mitigations=auto,nosmt", + "console=ttyS0,114800n8", + "video=vesafb:mtrr:3", + "rd.driver.blacklist=nouveau", + "modprobe.blacklist=nouveau", + "nvidia-drm.modeset=1" +] \ No newline at end of file diff --git a/ublue-silverblue-main/Containerfile b/ublue-silverblue-main/Containerfile new file mode 100644 index 0000000..17e9243 --- /dev/null +++ b/ublue-silverblue-main/Containerfile @@ -0,0 +1,79 @@ +FROM ghcr.io/ublue-os/silverblue-main:42 + +COPY etc /etc + +RUN dnf install -y https://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm && \ + dnf install -y https://download1.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-$(rpm -E %fedora).noarch.rpm && \ + dnf clean all + +RUN dnf remove -y \ + ptyxis \ + gnome-software \ + htop \ + gnome-classic-session \ + gnome-shell-extension-apps-menu \ + gnome-shell-extension-background-logo \ + gnome-shell-extension-launch-new-instance \ + gnome-shell-extension-places-menu \ + gnome-shell-extension-window-list \ + open-vm-tools \ + open-vm-tools-desktop \ + qemu-guest-agent \ + spice-vdagent \ + spice-webdavd \ + virtualbox-guest-additions && \ + dnf swap -y ffmpeg-free ffmpeg --allowerasing && \ + dnf swap -y libavcodec-free libavcodec-freeworld --allowerasing && \ + dnf group install -y multimedia --setopt="install_weak_deps=False" --exclude=PackageKit-gstreamer-plugin && \ + dnf copr enable -y alternateved/eza && \ + dnf install -y \ + acpi \ + akmod-v4l2loopback \ + btop \ + direnv \ + distrobox \ + eza \ + git \ + gnome-boxes \ + gstreamer1-vaapi \ + helm \ + kubectl \ + util-linux \ + lm_sensors \ + ncdu \ + pavucontrol \ + qemu-guest-agent \ + sysstat \ + tailscale \ + vdpauinfo \ + vulkan-tools \ + zsh \ + zsh-syntax-highlighting && \ + # Clean up + dnf clean all + +# Remove btop and nvtop shortcuts +RUN rm /usr/share/applications/btop.desktop /usr/share/applications/nvtop.desktop + +# Don't use the ghostty copr for now, it's broken on 42. Download the appimage in userland. +# Todo: Try again when 42 is final. +# RUN dnf copr enable -y pgdev/ghostty && \ +# dnf install -y ghostty + +# Don't install 1password, the browser integration breaks because 1Password uses /opt. +# I think this is polkit related. +# RUN mkdir -p /var/opt +# COPY scripts/1password.sh /tmp/1password.sh +# RUN /bin/sh /tmp/1password.sh + +RUN authselect enable-feature with-fingerprint + +LABEL org.opencontainers.image.description="Built on ublue-os/silverblue-main, adding more batteries" \ + org.opencontainers.image.source="https://cremin.dev/jonathan/bootc" \ + org.opencontainers.image.title="ublue-silverblue-main" \ + org.opencontainers.image.url="https://cremin.dev/jonathan/bootc" \ + org.opencontainers.image.created="" \ + org.opencontainers.image.licenses="Unlicensed" \ + org.opencontainers.image.revision="" \ + org.opencontainers.image.version="" + diff --git a/ublue-silverblue-main/build-push.sh b/ublue-silverblue-main/build-push.sh new file mode 100755 index 0000000..96db3b5 --- /dev/null +++ b/ublue-silverblue-main/build-push.sh @@ -0,0 +1,33 @@ +#!/bin/env sh + +set -e + +# Change to the directory where the script is located +cd "$(dirname "$0")" + +DATE_TAG=$(date "+%Y%m%d-%H%M%S") +CURRENT_IMAGE_ID=$(sudo podman images --format "{{.ID}}" cremin.dev/jonathan/ublue-silverblue-main:42) + + +echo "Pulling base image" +# ensure the base image is up to date +sudo -E podman pull ghcr.io/ublue-os/silverblue-main:42 + +echo "Starting build" +sudo -E podman build -t cremin.dev/jonathan/ublue-silverblue-main:42 . + +NEW_IMAGE_ID=$(sudo podman images --format "{{.ID}}" cremin.dev/jonathan/ublue-silverblue-main:42) + + +# Start build and check if any layers were changed (looking for "Using cache" messages) +if [ "$CURRENT_IMAGE_ID" = "$NEW_IMAGE_ID" ]; then + echo "No changes detected, skipping push" +else + echo "Image updated, pushing to registry" + # Add the tags + sudo -E podman tag cremin.dev/jonathan/ublue-silverblue-main:42 cremin.dev/jonathan/ublue-silverblue-main:42-${DATE_TAG} cremin.dev/jonathan/ublue-silverblue-main:latest + # Push the image + sudo -E podman push --authfile ~/.config/containers/auth.json cremin.dev/jonathan/ublue-silverblue-main:42-${DATE_TAG} + sudo -E podman push --authfile ~/.config/containers/auth.json cremin.dev/jonathan/ublue-silverblue-main:42 + sudo -E podman push --authfile ~/.config/containers/auth.json cremin.dev/jonathan/ublue-silverblue-main:latest +fi \ No newline at end of file diff --git a/ublue-silverblue-main/config.toml b/ublue-silverblue-main/config.toml new file mode 100755 index 0000000..8e21f8a --- /dev/null +++ b/ublue-silverblue-main/config.toml @@ -0,0 +1,39 @@ +[customizations.installer.modules] +enable = [ + "org.fedoraproject.Anaconda.Modules.Localization" +] +disable = [ + "org.fedoraproject.Anaconda.Modules.Users" +] + +[customizations.installer.kickstart] +contents = """ + +graphical + +# Basic setup +network --device=link --bootproto=dhcp --onboot=on --activate + +# Basic partitioning +clearpart --all --disklabel=gpt +autopart --encrypted --passphrase changeme --type btrfs --nohome --noswap + +# localisation +keyboard gb +lang en_IE +timezone Europe/Dublin + +reboot + +%post --erroronfail + +# upgrades from this image after install +bootc switch --mutate-in-place --transport registry cremin.dev/jonathan/ublue-silverblue-main:42 + +# used during automatic image testing as finished marker +if [ -c /dev/ttyS0 ]; then + # continue on errors here, because we used to omit --erroronfail + echo "Install finished" > /dev/ttyS0 || true +fi +%end +""" diff --git a/ublue-silverblue-main/create-installer.sh b/ublue-silverblue-main/create-installer.sh new file mode 100755 index 0000000..3c1c5f6 --- /dev/null +++ b/ublue-silverblue-main/create-installer.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env sh + +set -e + +cd "$(dirname "$0")" + +sudo podman run \ + --rm \ + -it \ + --privileged \ + --pull=newer \ + --security-opt label=type:unconfined_t \ + -v ./config.toml:/config.toml:ro \ + -v ./output:/output \ + -v /var/lib/containers/storage:/var/lib/containers/storage \ + quay.io/centos-bootc/bootc-image-builder:latest \ + --type iso \ + --rootfs btrfs \ + --use-librepo=True \ + --chown 1000:1000 \ + cremin.dev/jonathan/ublue-silverblue-main:42 diff --git a/ublue-silverblue-main/etc/sudoers.d/wheel-nopasswd b/ublue-silverblue-main/etc/sudoers.d/wheel-nopasswd new file mode 100755 index 0000000..a364129 --- /dev/null +++ b/ublue-silverblue-main/etc/sudoers.d/wheel-nopasswd @@ -0,0 +1,2 @@ +# Enable passwordless sudo for the wheel group +%wheel ALL=(ALL) NOPASSWD: ALL \ No newline at end of file diff --git a/ublue-silverblue-main/scripts/1password.sh b/ublue-silverblue-main/scripts/1password.sh new file mode 100755 index 0000000..765ea8e --- /dev/null +++ b/ublue-silverblue-main/scripts/1password.sh @@ -0,0 +1,76 @@ +#!/usr/bin/env sh + +# Thanks to bri for the inspiration! My script is mostly based on this example: +# https://github.com/briorg/bluefin/blob/c62c30a04d42fd959ea770722c6b51216b4ec45b/scripts/1password.sh + +set -ouex pipefail + +echo "Installing 1Password" + +# On libostree systems, /opt is a symlink to /var/opt, +# which actually only exists on the live system. /var is +# a separate mutable, stateful FS that's overlaid onto +# the ostree rootfs. Therefore we need to install it into +# /usr/lib/1Password instead, and dynamically create a +# symbolic link /opt/1Password => /usr/lib/1Password upon +# boot. + +# Prepare staging directory +mkdir -p /var/opt # -p just in case it exists +# for some reason... + +# Setup repo +cat << EOF > /etc/yum.repos.d/1password.repo +[1password] +name=1Password Stable Channel +baseurl=https://downloads.1password.com/linux/rpm/stable/\$basearch +enabled=1 +gpgcheck=1 +repo_gpgcheck=1 +gpgkey=https://downloads.1password.com/linux/keys/1password.asc +EOF + +# Import signing key +rpm --import https://downloads.1password.com/linux/keys/1password.asc + +# Prepare 1Password groups +# Normally, when after dnf installs the 1password RPM, an +# 'after-install.sh' script runs to cofigure several things, including +# the creation of a group. Under rpm-ostree, this didn't work quite as +# expected, thus several steps were done to hack around and fix things. +# Now with dnf5, there is a problem where 'after-install.sh' creates +# groups which conflict with default user's GID. This now pre-creates +# the groups, rather than fixing after RPM installation. + +# I hardcode GIDs and cross fingers that nothing else steps on them. +# These numbers _should_ be okay under normal use, but +# if there's a more specific range that I should use here +# please submit a PR! + +# Specifically, GID must be > 1000, and absolutely must not +# conflict with any real groups on the deployed system. +# Normal user group GIDs on Fedora are sequential starting +# at 1000, so let's skip ahead and set to something higher. +GID_ONEPASSWORD="1790" +GID_ONEPASSWORDCLI="1791" +groupadd -g ${GID_ONEPASSWORD} onepassword +groupadd -g ${GID_ONEPASSWORDCLI} onepassword-cli + +# Now let's install the packages. +dnf5 install -y 1password 1password-cli + +# This places the 1Password contents in an image safe location +mv /var/opt/1Password /usr/lib/1Password # move this over here + +# Register path symlink +# We do this via tmpfiles.d so that it is created by the live system. +cat >/usr/lib/tmpfiles.d/onepassword.conf <