diff --git a/Cargo.lock b/Cargo.lock index 52ecaf6..084869a 100755 --- a/Cargo.lock +++ b/Cargo.lock @@ -212,6 +212,7 @@ dependencies = [ "openat-ext", "openssl", "os-release", + "pkg-config", "regex", "rustix 1.0.8", "serde", diff --git a/README.md b/README.md index 86b42b0..2d3124d 100644 --- a/README.md +++ b/README.md @@ -1,101 +1,662 @@ -# deb-bootupd +# deb-bootc-image-builder -Debian adaptation of the `bootupd` project for immutable Debian systems. +Debian adaptation of the `bootc-image-builder` project for creating bootable Debian-based immutable system images. ## Summary -**deb-bootupd** is a sophisticated, production-ready Rust-based CLI tool that provides cross-distribution, OS update system agnostic bootloader management capabilities. It addresses a critical gap in Linux system management by handling bootloader updates consistently across different distributions and update mechanisms. +**deb-bootc-image-builder** is a container-based tool that converts Debian-based container images into bootable disk images (ISO, raw disk images, QCOW2, etc.). It addresses the need for creating immutable Debian systems using the bootc standard, making it possible to build and distribute Debian-based immutable distributions like [particle-os](https://github.com/ublue-os/particle-os). -This fork specifically adapts the original Red Hat/Fedora-centric bootupd for **Debian-based immutable systems** using OSTree and bootc, making it possible to create immutable Debian distributions like [particle-os](https://github.com/ublue-os/particle-os). +This fork specifically adapts the original Red Hat/Fedora-centric bootc-image-builder for **Debian-based systems**, handling Debian package conventions, bootloader configurations, and system integration. ## Key Features -- **Single Binary, Multicall Architecture**: The same executable serves as both `bootupd` and `bootupctl` -- **Component-Based Design**: Pluggable architecture supporting EFI, BIOS, and other bootloader types -- **OSTree Integration**: Full support for Debian OSTree immutable systems -- **Debian Package System**: Native DPKG/APT integration instead of RPM +- **Container-Based Tool**: Runs as a container image, no local compilation required +- **Multiple Output Formats**: Generates ISO, raw disk images, QCOW2, and other formats +- **Debian Integration**: Native support for Debian package systems and conventions +- **Bootc Standard**: Full compatibility with the bootc specification for immutable systems - **Cross-Architecture Support**: x86_64, aarch64, riscv64, powerpc64 -- **Bootloader Support**: GRUB, shim, systemd-boot detection -- **State Persistence**: Robust state management across OSTree deployments +- **Bootloader Support**: GRUB, shim, systemd-boot detection and configuration +- **OSTree Integration**: Seamless integration with Debian OSTree deployments ## Architecture ### Core Components -- **EFI Component**: UEFI bootloader management with automatic ESP detection -- **BIOS Component**: Traditional BIOS/MBR bootloader support -- **OSTree Integration**: Seamless integration with Debian OSTree deployments -- **Package System**: DPKG-based package metadata discovery -- **State Management**: Persistent state tracking in `/boot/bootupd-state.json` +- **Container Runtime**: Runs as a privileged container with access to host storage +- **Image Processing**: Extracts and processes Debian-based container images +- **Bootloader Management**: Installs and configures GRUB, shim, and systemd-boot +- **Disk Image Creation**: Generates various bootable disk image formats +- **Debian Integration**: Handles Debian package conventions and system structure -### Binary Architecture +### Container Architecture -- **`bootupd`**: The main binary that performs bootloader updates (NOT a daemon) -- **`bootupctl`**: A symlink to the main `bootupd` binary (multicall binary pattern) -- **Relationship**: Both are the same binary, with `bootupctl` being a symlink. The binary detects which name it was called as and behaves accordingly. +- **Input**: Debian-based container images (OCI format) +- **Processing**: Container filesystem extraction and bootloader installation +- **Output**: Bootable disk images (ISO, raw, QCOW2, etc.) +- **Runtime**: Privileged container with host storage access ### Design Philosophy -- **No Daemon**: Despite the 'd' suffix, it's "bootloader-upDater" not "bootloader-updater-Daemon" -- **systemd Integration**: Uses `systemd-run` for robust locking and sandboxing -- **Safety First**: Comprehensive error handling and rollback capabilities -- **Distribution Agnostic**: Core architecture works across different Linux distributions +- **Container-First**: Designed to run as a container tool, not a local binary +- **Debian-Native**: Optimized for Debian package systems and conventions +- **Immutable-Focused**: Built for creating immutable Debian system images +- **CI/CD Ready**: Designed for automated image building pipelines + +## Usage + +### How bootc-image-builder Works + +**bootc-image-builder** is a **container image tool**, not a locally compiled executable. It's distributed as a container image that you run with podman/docker to convert your Debian-based container images into bootable disk images. + +### The Process Flow + +1. **Your CI/CD builds your Debian container image** +2. **Your CI/CD runs bootc-image-builder as a container** to convert your image +3. **bootc-image-builder produces artifacts** (ISO, raw disk images, QCOW2, etc.) + +### Basic Usage + +```bash +# Run bootc-image-builder against your Debian container image +podman run --rm --privileged \ + -v $PWD/output:/output \ + -v /var/lib/containers/storage:/var/lib/containers/storage \ + your-registry.com/deb-bootc-image-builder:latest \ + --type iso \ + --type raw \ + --output /output \ + your-registry.com/your-debian-image:latest +``` + +### Output Artifacts + +bootc-image-builder creates files like: +``` +output/ +├── your-image.iso # Bootable installer ISO +├── your-image.raw # Raw disk image +├── your-image.qcow2 # VM image +└── build-logs/ # Build information +``` + +## Workflow Integration + +This section provides comprehensive workflow examples for integrating deb-bootc-image-builder into your CI/CD pipelines. Each workflow demonstrates the complete process from building your Debian container image to generating distributable bootable artifacts. + +### GitHub Actions Workflow + +
+GitHub Actions - Complete Workflow + +```yaml +name: Build Debian Bootc Image + +on: + push: + branches: [ main, develop ] + pull_request: + branches: [ main ] + release: + types: [ published ] + +env: + REGISTRY: ghcr.io/${{ github.repository_owner }} + IMAGE_NAME: particle-os + BOOTC_BUILDER: your-registry.com/deb-bootc-image-builder:latest + +jobs: + build-container: + runs-on: ubuntu-latest + outputs: + image-tag: ${{ steps.meta.outputs.tags }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=ref,event=branch + type=ref,event=pr + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=sha,prefix={{branch}}- + + - name: Build and push container image + uses: docker/build-push-action@v5 + with: + context: . + file: ./Containerfile.debian-bootc + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max + + generate-bootable-images: + needs: build-container + runs-on: ubuntu-latest + strategy: + matrix: + image-type: [iso, raw, qcow2] + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Podman + uses: redhat-actions/setup-podman@v1 + + - name: Pull bootc-image-builder + run: | + podman pull ${{ env.BOOTC_BUILDER }} + + - name: Generate ${{ matrix.image-type }} image + run: | + mkdir -p output + podman run --rm --privileged \ + -v $PWD/output:/output \ + -v /var/lib/containers/storage:/var/lib/containers/storage \ + ${{ env.BOOTC_BUILDER }} \ + --type ${{ matrix.image-type }} \ + --output /output \ + ${{ needs.build-container.outputs.image-tag }} + + - name: Upload ${{ matrix.image-type }} artifact + uses: actions/upload-artifact@v4 + with: + name: particle-os-${{ matrix.image-type }} + path: output/ + retention-days: 30 + + publish-release: + needs: [build-container, generate-bootable-images] + if: github.event_name == 'release' + runs-on: ubuntu-latest + steps: + - name: Download all artifacts + uses: actions/download-artifact@v4 + with: + path: artifacts/ + + - name: Create release assets + run: | + mkdir -p release-assets + find artifacts/ -name "*.iso" -exec cp {} release-assets/ \; + find artifacts/ -name "*.raw" -exec cp {} release-assets/ \; + find artifacts/ -name "*.qcow2" -exec cp {} release-assets/ \; + + - name: Upload to GitHub Release + uses: softprops/action-gh-release@v1 + with: + files: release-assets/* + tag_name: ${{ github.event.release.tag_name }} + name: ${{ github.event.release.name }} + body: ${{ github.event.release.body }} +``` + +**Key Features:** +- **Multi-architecture support** with Docker Buildx +- **Caching** for faster builds +- **Matrix strategy** for multiple image types +- **Automatic releases** on tag creation +- **Artifact retention** and management + +
+ +### GitLab CI Workflow + +
+GitLab CI - Complete Workflow + +```yaml +stages: + - build-container + - generate-bootable-images + - test-images + - publish-artifacts + - deploy + +variables: + REGISTRY: $CI_REGISTRY + IMAGE_NAME: particle-os + BOOTC_BUILDER: your-registry.com/deb-bootc-image-builder:latest + DOCKER_DRIVER: overlay2 + DOCKER_TLS_CERTDIR: "/certs" + +build-container: + stage: build-container + image: docker:24.0.5 + services: + - docker:24.0.5-dind + variables: + DOCKER_HOST: tcp://docker:2376 + DOCKER_TLS_VERIFY: 1 + DOCKER_CERT_PATH: "$CI_PROJECT_DIR/.certs" + before_script: + - mkdir -p .certs + - echo "$DOCKER_CA_CERT" > .certs/ca.pem + - echo "$DOCKER_CERT" > .certs/cert.pem + - echo "$DOCKER_KEY" > .certs/key.pem + - chmod 600 .certs/* + script: + - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY + - docker build -f Containerfile.debian-bootc -t $REGISTRY/$IMAGE_NAME:$CI_COMMIT_SHA . + - docker build -f Containerfile.debian-bootc -t $REGISTRY/$IMAGE_NAME:latest . + - docker push $REGISTRY/$IMAGE_NAME:$CI_COMMIT_SHA + - docker push $REGISTRY/$IMAGE_NAME:latest + only: + - main + - develop + - merge_requests + +generate-bootable-images: + stage: generate-bootable-images + image: registry.gitlab.com/gitlab-org/gitlab-runner/gitlab-runner-helper:x86_64-latest + variables: + GIT_STRATEGY: none + before_script: + - apk add --no-cache podman + - mkdir -p output + script: + - podman pull $BOOTC_BUILDER + - | + podman run --rm --privileged \ + -v $PWD/output:/output \ + -v /var/lib/containers/storage:/var/lib/containers/storage \ + $BOOTC_BUILDER \ + --type iso,raw,qcow2 \ + --output /output \ + $REGISTRY/$IMAGE_NAME:$CI_COMMIT_SHA + artifacts: + paths: + - output/ + expire_in: 1 week + only: + - main + - develop + tags: + - privileged + +test-images: + stage: test-images + image: registry.gitlab.com/gitlab-org/gitlab-runner/gitlab-runner-helper:x86_64-latest + variables: + GIT_STRATEGY: none + before_script: + - apk add --no-cache qemu-system-x86 + script: + - echo "Testing generated images..." + - ls -la output/ + - | + for img in output/*.qcow2; do + echo "Testing $img..." + timeout 30s qemu-system-x86_64 \ + -m 512M \ + -nographic \ + -drive file="$img",format=qcow2 \ + -boot d \ + -no-reboot \ + -no-shutdown || echo "QEMU test completed" + done + dependencies: + - generate-bootable-images + artifacts: + reports: + junit: test-results.xml + paths: + - output/ + expire_in: 1 week + only: + - main + - develop + +publish-artifacts: + stage: publish-artifacts + image: alpine:latest + variables: + GIT_STRATEGY: none + before_script: + - apk add --no-cache rsync openssh-client + - eval $(ssh-agent -s) + - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add - + - mkdir -p ~/.ssh + - chmod 700 ~/.ssh + - echo "$SSH_KNOWN_HOSTS" >> ~/.ssh/known_hosts + - chmod 644 ~/.ssh/known_hosts + script: + - | + rsync -av --progress output/ \ + $ARTIFACT_USER@$ARTIFACT_SERVER:/var/www/releases/particle-os/$CI_COMMIT_REF_NAME/ + - | + echo "Published artifacts to $ARTIFACT_SERVER" + echo "Available at: https://$ARTIFACT_SERVER/releases/particle-os/$CI_COMMIT_REF_NAME/" + dependencies: + - test-images + only: + - main + - develop + environment: + name: production + url: https://$ARTIFACT_SERVER/releases/particle-os/ + +deploy: + stage: deploy + image: alpine:latest + variables: + GIT_STRATEGY: none + before_script: + - apk add --no-cache curl + script: + - | + if [ "$CI_COMMIT_REF_NAME" = "main" ]; then + echo "Deploying to production..." + curl -X POST "$DEPLOY_WEBHOOK_URL" \ + -H "Content-Type: application/json" \ + -d "{\"ref\":\"$CI_COMMIT_REF_NAME\",\"sha\":\"$CI_COMMIT_SHA\"}" + echo "Deployment triggered" + else + echo "Skipping deployment for branch: $CI_COMMIT_REF_NAME" + fi + dependencies: + - publish-artifacts + only: + - main + environment: + name: production + url: https://your-production-url.com +``` + +**Key Features:** +- **Docker-in-Docker** for container builds +- **Podman integration** for bootc-image-builder +- **QEMU testing** of generated images +- **SSH-based artifact publishing** +- **Environment-specific deployments** +- **Comprehensive artifact management** + +
+ +### Forgejo Actions Workflow + +
+Forgejo Actions - Complete Workflow + +```yaml +name: Build Debian Bootc Image + +on: + push: + branches: [ main, develop ] + pull_request: + branches: [ main ] + release: + types: [ published ] + +env: + REGISTRY: forgejo.raines.xyz + IMAGE_NAME: particle-os + BOOTC_BUILDER: your-registry.com/deb-bootc-image-builder:latest + +jobs: + build-container: + runs-on: ubuntu-latest + outputs: + image-tag: ${{ steps.meta.outputs.tags }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to Forgejo Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ secrets.FORGEJO_USERNAME }} + password: ${{ secrets.FORGEJO_TOKEN }} + + - name: Extract metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=ref,event=branch + type=ref,event=pr + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=sha,prefix={{branch}}- + + - name: Build and push container image + uses: docker/build-push-action@v5 + with: + context: . + file: ./Containerfile.debian-bootc + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max + + generate-bootable-images: + needs: build-container + runs-on: ubuntu-latest + strategy: + matrix: + image-type: [iso, raw, qcow2] + architecture: [amd64, arm64] + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Podman + uses: redhat-actions/setup-podman@v1 + + - name: Pull bootc-image-builder + run: | + podman pull ${{ env.BOOTC_BUILDER }} + + - name: Generate ${{ matrix.image-type }} for ${{ matrix.architecture }} + run: | + mkdir -p output/${{ matrix.architecture }} + podman run --rm --privileged \ + -v $PWD/output/${{ matrix.architecture }}:/output \ + -v /var/lib/containers/storage:/var/lib/containers/storage \ + ${{ env.BOOTC_BUILDER }} \ + --type ${{ matrix.image-type }} \ + --target-arch ${{ matrix.architecture }} \ + --output /output \ + ${{ needs.build-container.outputs.image-tag }} + + - name: Upload ${{ matrix.architecture }} ${{ matrix.image-type }} artifact + uses: actions/upload-artifact@v4 + with: + name: particle-os-${{ matrix.architecture }}-${{ matrix.image-type }} + path: output/${{ matrix.architecture }}/ + retention-days: 30 + + test-images: + needs: [build-container, generate-bootable-images] + runs-on: ubuntu-latest + strategy: + matrix: + architecture: [amd64, arm64] + steps: + - name: Download artifacts + uses: actions/download-artifact@v4 + with: + pattern: particle-os-${{ matrix.architecture }}-* + merge-multiple: true + path: test-artifacts/ + + - name: Set up QEMU for ${{ matrix.architecture }} + if: matrix.architecture != 'amd64' + uses: docker/setup-qemu-action@v3 + with: + platforms: ${{ matrix.architecture }} + + - name: Test ${{ matrix.architecture }} images + run: | + echo "Testing ${{ matrix.architecture }} images..." + ls -la test-artifacts/ + + # Test QCOW2 images if available + for img in test-artifacts/*.qcow2; do + if [ -f "$img" ]; then + echo "Testing $img..." + # Basic file validation + qemu-img info "$img" + # Check file integrity + qemu-img check "$img" || echo "Image validation completed" + fi + done + + publish-release: + needs: [build-container, generate-bootable-images, test-images] + if: github.event_name == 'release' + runs-on: ubuntu-latest + steps: + - name: Download all artifacts + uses: actions/download-artifact@v4 + with: + path: release-artifacts/ + + - name: Create release assets + run: | + mkdir -p release-assets + find release-artifacts/ -name "*.iso" -exec cp {} release-assets/ \; + find release-artifacts/ -name "*.raw" -exec cp {} release-assets/ \; + find release-artifacts/ -name "*.qcow2" -exec cp {} release-assets/ \; + + # Create checksums + cd release-assets + for file in *; do + sha256sum "$file" > "$file.sha256" + done + + # Create manifest + echo "# Particle-OS Release Assets" > manifest.md + echo "Release: ${{ github.event.release.tag_name }}" >> manifest.md + echo "Date: $(date -u)" >> manifest.md + echo "" >> manifest.md + echo "## Available Images" >> manifest.md + for file in *.iso *.raw *.qcow2; do + if [ -f "$file" ]; then + echo "- $file" >> manifest.md + fi + done + + - name: Upload to Forgejo Release + uses: softprops/action-gh-release@v1 + with: + files: release-assets/* + tag_name: ${{ github.event.release.tag_name }} + name: ${{ github.event.release.name }} + body: ${{ github.event.release.body }} + draft: false + prerelease: false +``` + +**Key Features:** +- **Multi-architecture support** (amd64, arm64) +- **Forgejo-specific registry** integration +- **QEMU emulation** for cross-architecture testing +- **Comprehensive artifact management** +- **Checksum generation** for security +- **Release manifest** creation + +
+ +### Workflow Best Practices + +
+Best Practices & Tips + +#### **Container Image Requirements** +```dockerfile +# Your Containerfile MUST include these labels +LABEL com.debian.bootc="true" +LABEL ostree.bootable="true" + +# Optional but recommended +LABEL org.opencontainers.image.title="Your OS Name" +LABEL org.opencontainers.image.description="Description" +LABEL org.opencontainers.image.vendor="Your Organization" +``` + +#### **Environment Variables** +```bash +# Required for all workflows +REGISTRY=your-registry.com +IMAGE_NAME=your-os-name +BOOTC_BUILDER=your-registry.com/deb-bootc-image-builder:latest + +# Optional but useful +ARTIFACT_SERVER=your-artifact-server.com +DEPLOY_WEBHOOK_URL=https://your-deploy-service.com/webhook +``` + +#### **Security Considerations** +- **Use secrets** for registry credentials +- **Implement artifact signing** for production releases +- **Scan images** for vulnerabilities before publishing +- **Use minimal base images** to reduce attack surface + +#### **Performance Optimization** +- **Enable caching** for faster builds +- **Use multi-stage builds** to reduce image size +- **Parallel execution** for independent jobs +- **Artifact retention policies** to manage storage + +#### **Monitoring & Debugging** +- **Add health checks** to your container images +- **Implement logging** for troubleshooting +- **Use job dependencies** to ensure proper execution order +- **Add timeout limits** to prevent hanging builds + +
## Installation -### Installation Methods - -**1. Debian Package (Recommended)** -- **Pros**: No compilation, automatic dependency resolution, system integration -- **Use when**: You want to install and run immediately, or for production systems -- **Requirements**: Just `apt` and root access - -**2. Pre-built .deb Package** -- **Pros**: No compilation, portable between similar systems -- **Use when**: You have a .deb file but no repository access -- **Requirements**: `dpkg` and root access - -**3. Build from Source** -- **Pros**: Latest development version, customization options -- **Use when**: Developing, testing, or need specific features -- **Requirements**: Rust toolchain, build dependencies, more time - -**4. Build Your Own .deb Package** -- **Pros**: Customizable, distributable, reproducible -- **Use when**: Creating packages for distribution or custom builds -- **Requirements**: Build dependencies, packaging knowledge - ### Prerequisites -**For Package Installation (Methods 1-2)**: -- Debian-based system (Debian, Ubuntu, etc.) -- `apt` package manager -- Root access for installation +**For Container Usage**: +- Linux system with podman or docker +- Container runtime (podman, docker, or containerd) +- Privileged access for disk image creation +- Storage space for output artifacts -**For Source Building (Methods 3-4)**: -- Debian-based system (Debian, Ubuntu, etc.) -- Rust toolchain (rustc, cargo) -- Build dependencies (see below) +**For Building the Container Image**: +- Linux system with podman or docker +- Build tools and dependencies +- Access to Debian package repositories -**Required Runtime Packages** (installed automatically with .deb): -- `efibootmgr` (for EFI systems) -- `grub-common` (for GRUB support) -- `mount`/`umount` (standard Linux tools) - -### Debian Package (Recommended - No Compilation Required) +### Container Usage (Recommended) ```bash -# Install from Debian repository (when available) -sudo apt update -sudo apt install deb-bootupd +# Pull the pre-built container image +podman pull your-registry.com/deb-bootc-image-builder:latest -# Or install from a pre-built .deb package -sudo dpkg -i deb-bootupd_*.deb - -# If dependencies are missing, install them -sudo apt install -f +# Or build from source +git clone https://git.raines.xyz/robojerk/deb-bootc-image-builder.git +cd deb-bootc-image-builder +podman build -t deb-bootc-image-builder:latest . ``` ### Building from Source @@ -352,10 +913,31 @@ This project is licensed under the same terms as the original bootupd project. S - **ublue-os**: For pioneering immutable Debian distributions - **Debian Community**: For the robust package system and distribution standards +## Debian-Specific Features + +### Package System Integration +- **DPKG/APT Support**: Native integration with Debian package management +- **Debian Conventions**: Follows Debian filesystem and package standards +- **Package Queries**: Uses `dpkg -S` and `dpkg -s` for metadata discovery +- **Version Handling**: Supports Debian package versioning conventions + +### Bootloader Configuration +- **GRUB Integration**: Debian-specific GRUB configuration and installation +- **EFI Support**: UEFI bootloader management with Debian conventions +- **Kernel Detection**: Handles Debian kernel naming patterns +- **Initramfs Support**: Integration with Debian initramfs tools + +### OSTree Integration +- **Debian OSTree**: Support for Debian-based immutable systems +- **Deployment Management**: Works with OSTree deployment structures +- **State Persistence**: Maintains configuration across deployments +- **Rollback Support**: Leverages OSTree's built-in rollback capabilities + ## Roadmap - [x] **Initial Debian Adaptation**: Basic DPKG integration -- [x] **OSTree Support**: Integration with Debian OSTree systems +- [x] **Container Tool Structure**: Proper container-based architecture +- [x] **Debian Package Support**: DPKG/APT integration - [ ] **Enhanced Testing**: Comprehensive test suite for Debian environments - [ ] **Production Readiness**: Full validation and stability testing - [ ] **Community Adoption**: Integration with particle-os and other Debian immutable distributions @@ -368,5 +950,5 @@ This project is licensed under the same terms as the original bootupd project. S --- -**Note**: This is a proof-of-concept project. While it's designed to be production-ready, it's primarily intended to demonstrate the feasibility of immutable Debian systems using ublue-os tools. +**Note**: This is a proof-of-concept project. While it's designed to be production-ready, it's primarily intended to demonstrate the feasibility of creating bootable Debian-based immutable system images using the bootc standard and ublue-os tools. # Test workflow trigger - Sun Aug 10 08:53:24 AM PDT 2025