diff --git a/Containerfile b/Containerfile index ad67e1d..32dad57 100644 --- a/Containerfile +++ b/Containerfile @@ -20,7 +20,7 @@ RUN --mount=type=bind,from=ctx,source=/,target=/ctx \ --mount=type=tmpfs,dst=/tmp \ apt-get update && \ apt-get install -y wget && \ - wget -O /tmp/nbc.deb https://github.com/frostyard/nbc/releases/download/v0.11.1/nbc_0.11.1_amd64.deb && \ + wget -O /tmp/nbc.deb https://github.com/frostyard/nbc/releases/download/v0.12.0/nbc_0.12.0_amd64.deb && \ wget -O /tmp/snow-first-setup.deb https://github.com/frostyard/first-setup/releases/download/continuous/snow-first-setup.deb && \ wget -O /tmp/chairlift.deb https://github.com/frostyard/chairlift/releases/download/continuous/chairlift.deb && \ apt-get install -y /tmp/snow-first-setup.deb && \ diff --git a/build_files/build b/build_files/build index 6a03b2a..01cfe16 100755 --- a/build_files/build +++ b/build_files/build @@ -1,6 +1,9 @@ #!/bin/bash set -ouex pipefail + + + # Repository setup mkdir -p /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.gpg @@ -176,3 +179,20 @@ sed -i "s/^BUILD_ID=.*/BUILD_ID=\"$BUILD_ID\"/" /usr/lib/os-release # and avoid issues with /var/opt being mounted on top mkdir -p "/usr/share/factory/opt/incus" mv /opt/incus /usr/share/factory/opt/ + +# probably belong in build_files/shared/finalize, but +# Make wrapper scripts executable +chmod +x /usr/libexec/apt-wrapper /usr/libexec/dpkg-wrapper 2>/dev/null || true + + + +# Set up apt/dpkg wrappers for read-only operation +# Move real binaries and replace with wrappers +if [ -f /usr/libexec/apt-wrapper ] && [ ! -f /usr/bin/apt.real ]; then + mv /usr/bin/apt /usr/bin/apt.real + ln -sf /usr/libexec/apt-wrapper /usr/bin/apt +fi +if [ -f /usr/libexec/dpkg-wrapper ] && [ ! -f /usr/bin/dpkg.real ]; then + mv /usr/bin/dpkg /usr/bin/dpkg.real + ln -sf /usr/libexec/dpkg-wrapper /usr/bin/dpkg +fi diff --git a/system_files/usr/libexec/apt-wrapper b/system_files/usr/libexec/apt-wrapper new file mode 100644 index 0000000..e7ac21f --- /dev/null +++ b/system_files/usr/libexec/apt-wrapper @@ -0,0 +1,63 @@ +#!/bin/bash +# Wrapper for apt that allows read-only operations on immutable systems +# but blocks package installation/removal with a helpful message + +REAL_APT=/usr/bin/apt.real + +# Read-only commands that should always work +readonly_commands=( + "list" + "search" + "show" + "showsrc" + "depends" + "rdepends" + "policy" + "madison" + "changelog" + "source" + "download" + "moo" + "help" + "--help" + "-h" + "--version" + "-v" +) + +# Check if the first non-option argument is a read-only command +for arg in "$@"; do + # Skip options + [[ "$arg" == -* ]] && continue + + # Check if it's a read-only command + for cmd in "${readonly_commands[@]}"; do + if [[ "$arg" == "$cmd" ]]; then + exec "$REAL_APT" "$@" + fi + done + + # First non-option arg wasn't a read-only command + break +done + +# For any other command, check if we're on an immutable system +if [[ -f /run/ostree-booted ]] || [[ -f /run/nbc-booted ]] || [[ -d /sysroot/ostree ]]; then + echo "Error: This is an immutable system (bootc/ostree/nbc)." >&2 + echo "" >&2 + echo "Package installation/removal is not supported at runtime." >&2 + echo "To modify the system, you need to:" >&2 + echo " 1. Modify the Containerfile and rebuild the image, or" >&2 + echo " 2. Use 'bootc switch' to switch to a different image" >&2 + echo "" >&2 + echo "For user applications, consider using:" >&2 + echo " - Flatpak: flatpak install " >&2 + echo " - Homebrew: brew install " >&2 + echo " - Distrobox: distrobox create && distrobox enter" >&2 + echo "" >&2 + echo "Read-only apt commands still work: apt list, apt search, apt show" >&2 + exit 1 +fi + +# If not immutable (e.g., in a container build), run normally +exec "$REAL_APT" "$@" diff --git a/system_files/usr/libexec/dpkg-wrapper b/system_files/usr/libexec/dpkg-wrapper new file mode 100644 index 0000000..325cb7f --- /dev/null +++ b/system_files/usr/libexec/dpkg-wrapper @@ -0,0 +1,51 @@ +#!/bin/bash +# Wrapper for dpkg that allows read-only operations on immutable systems +# but blocks package installation/removal with a helpful message + +REAL_DPKG=/usr/bin/dpkg.real + +# Read-only options (these query the database without modifying it) +# Run normally if ANY of these are the primary action +for arg in "$@"; do + case "$arg" in + -l|--list|-L|--listfiles|-s|--status|-S|--search|-p|--print-avail|\ + --get-selections|--print-architecture|--print-foreign-architectures|\ + --compare-versions|--help|--version|-\?|--license|--audit|-C|\ + --yet-to-unpack|--predep-package|--admindir=*|--instdir=*|--root=*) + exec "$REAL_DPKG" "$@" + ;; + esac +done + +# Check for query options that might appear anywhere +has_query_option=false +for arg in "$@"; do + case "$arg" in + -l|--list|-L|--listfiles|-s|--status|-S|--search|-p|--print-avail) + has_query_option=true + break + ;; + esac +done + +if $has_query_option; then + exec "$REAL_DPKG" "$@" +fi + +# For any other command, check if we're on an immutable system +if [[ -f /run/ostree-booted ]] || [[ -f /run/nbc-booted ]] || [[ -d /sysroot/ostree ]]; then + echo "Error: This is an immutable system (bootc/ostree/nbc)." >&2 + echo "" >&2 + echo "Direct package manipulation is not supported at runtime." >&2 + echo "To modify the system, rebuild the container image." >&2 + echo "" >&2 + echo "Read-only dpkg commands still work:" >&2 + echo " dpkg -l # List installed packages" >&2 + echo " dpkg -L # List files in a package" >&2 + echo " dpkg -s # Show package status" >&2 + echo " dpkg -S # Find which package owns a file" >&2 + exit 1 +fi + +# If not immutable (e.g., in a container build), run normally +exec "$REAL_DPKG" "$@"