Skip to content

Commit 6dd3e32

Browse files
committed
reframe as composefs-os; fix all pre-open-source issues
Project identity: - README rewritten: composefs-os publishes bootable OCI images; cbootc is the embedded management tool, not the release artifact - DESIGN.md: update status ("working implementation"), fix section 8 to describe the actual cbootc install to-disk command, fix file layout paths (/sysroot/composefs, /var/lib/cbootc), fix rollback description to match grub2-editenv implementation - Cargo.toml: add description, license, repository fields Must-fix bugs: - container.yml: fix Containerfile.base path (was examples/fedora/…, now at repo root); rename image to composefs-os-fedora:43; drop CI push of the example derived image (it had a weak root password) - units/cbootc-update.service: fix ConditionPathExists from /etc/cbootc/config.toml to /var/lib/cbootc/config.toml — the auto- update timer was silently doing nothing on every system since the config was moved to /var in an earlier commit Cleanup: - examples/fedora/Containerfile: remove weak root password, serial autologin, and leftover upgrade-test debug block; rewrite as a clean template pointing at the published base image
1 parent 1891a8d commit 6dd3e32

6 files changed

Lines changed: 109 additions & 105 deletions

File tree

.github/workflows/container.yml

Lines changed: 3 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -27,35 +27,12 @@ jobs:
2727

2828
# Build the base image and push it. The build is slow (dnf + dracut)
2929
# so GHA layer cache is critical for subsequent runs.
30-
- name: Build and push fedora-cfs-base:43
30+
- name: Build and push composefs-os-fedora:43
3131
uses: docker/build-push-action@v6
3232
with:
3333
context: .
34-
file: examples/fedora/Containerfile.base
34+
file: Containerfile.base
3535
push: true
36-
tags: ghcr.io/${{ github.repository_owner }}/fedora-cfs-base:43
37-
cache-from: type=gha
38-
cache-to: type=gha,mode=max
39-
40-
# Compute tags for the derived image: always "latest", plus semver on tags
41-
- name: Docker metadata (derived image)
42-
id: meta
43-
uses: docker/metadata-action@v5
44-
with:
45-
images: ghcr.io/${{ github.repository_owner }}/fedora-cfs
46-
tags: |
47-
type=raw,value=latest
48-
type=semver,pattern=v{{version}}
49-
50-
# Build the derived image, pointing BASE_IMAGE at the image we just pushed
51-
- name: Build and push fedora-cfs
52-
uses: docker/build-push-action@v6
53-
with:
54-
context: .
55-
file: examples/fedora/Containerfile
56-
push: true
57-
tags: ${{ steps.meta.outputs.tags }}
58-
build-args: |
59-
BASE_IMAGE=ghcr.io/${{ github.repository_owner }}/fedora-cfs-base:43
36+
tags: ghcr.io/${{ github.repository_owner }}/composefs-os-fedora:43
6037
cache-from: type=gha
6138
cache-to: type=gha,mode=max

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
name = "cbootc"
33
version = "0.1.0"
44
edition = "2024"
5+
description = "Upgrade/rollback tool embedded in composefs-os images"
6+
license = "MIT"
7+
repository = "https://github.com/OWNER/composefs-os"
58

69
[dependencies]
710
anyhow = "1.0"

DESIGN.md

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1-
# cbootc Design Notes
1+
# composefs-os / cbootc Design Notes
22

3-
A minimal bootc-like operational tool built directly on composefs-rs, with no
4-
ostree dependency. Intended as a personal-scale tool, not a bootc replacement.
3+
composefs-os ships bootable Linux OCI images backed by composefs-rs.
4+
cbootc is the embedded upgrade/rollback tool inside those images — a minimal
5+
bootc-like operational layer with no ostree dependency.
56

67
## Status
78

8-
Greenfield. No code yet. This document captures the design decisions made
9-
during initial scoping so we can pick up implementation cleanly.
9+
Working implementation. All core commands (install, upgrade, switch, rollback,
10+
status, verify) are functional on x86-64 EFI systems.
1011

1112
## Goals
1213

@@ -104,21 +105,21 @@ Signature verification before deploy, using `sigstore-rs` or by shelling out
104105
to `cosign verify`. Enforced when a public key is configured; warning-only
105106
when none is. Configuration via `/etc/cbootc/config.toml`.
106107

107-
### 7. Rollback via grub-reboot, not state machines
108+
### 7. Rollback via grubenv next_entry, not state machines
108109

109110
Rather than tracking deployment generations in custom state, lean on the BLS
110-
entries cfsctl writes. Rollback = "boot the previous BLS entry once" via
111-
`grub2-reboot` or equivalent. Simple, debuggable, no custom state to corrupt.
111+
entries cfsctl writes. Rollback = write `next_entry=<digest>` to
112+
`/boot/grub2/grubenv` via `grub2-editenv`, then reboot. GRUB reads the env,
113+
boots that entry once, and clears it. Simple, debuggable, no custom state to
114+
corrupt.
112115

113-
### 8. No installer in the binary
116+
### 8. Installer in the binary
114117

115-
`cbootc install` is out of scope for the binary itself. Installation is done
116-
by the disk-builder script (see `tools/build-disk.sh`) which produces a
117-
qcow2/raw image. For bare-metal install, boot a live environment and run that
118-
script against `/dev/sdX` instead of a disk image file.
119-
120-
This is the single biggest scope cut vs. bootc and is what makes cbootc
121-
buildable in weeks rather than months.
118+
`cbootc install to-disk <DEVICE>` runs inside the container image and writes a
119+
bootable system to a block device or raw file. It handles partitioning (GPT,
120+
via sfdisk), formatting, composefs repo initialisation, GRUB installation, and
121+
shared-var wiring. Running inside the container means the source image is always
122+
the container itself — no separate image reference needed at install time.
122123

123124
## Command Surface
124125

@@ -135,10 +136,11 @@ That's it. Five commands. Compare to bootc's ~15.
135136
## File Layout on Target System
136137

137138
```
138-
/composefs/ cfsctl repo (objects, images, streams)
139+
/sysroot/composefs/ cfsctl repo (objects, images, streams)
139140
/boot/ kernel + initramfs + BLS entries
140-
/boot/loader/entries/*.conf BLS snippets with composefs=<digest>
141-
/etc/cbootc/config.toml tracked image, signing key, update policy
141+
/boot/loader/entries/<digest>.conf BLS snippet with composefs=<digest>
142+
/boot/grub2/grubenv GRUB env block (next_entry for rollback)
143+
/var/lib/cbootc/config.toml tracked image reference
142144
/var/lib/cbootc/state.json last-upgrade time, last-known-good digest
143145
/usr/lib/systemd/system/cbootc-* timer + service for auto-updates (optional)
144146
```

README.md

Lines changed: 67 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,41 @@
1-
# cbootc
1+
# composefs-os
22

3-
A minimal bootc-like tool for systems running on composefs-rs. Personal-scale,
4-
distro-neutral, deliberately small.
3+
Bootable Linux system images built on [composefs-rs](https://github.com/containers/composefs-rs).
4+
Image-based OS management for personal and small-scale systems — no ostree, no fleet tooling.
55

66
## What This Is
77

8-
cbootc deploys and updates Linux systems built as OCI container images, using
9-
[composefs-rs](https://github.com/containers/composefs-rs) (via `cfsctl`) as
10-
the storage backend. It is a thin operational layer above cfsctl: install,
11-
status, upgrade, switch, rollback, signature verification, and a systemd timer
12-
for automatic updates.
8+
composefs-os publishes OCI container images that boot directly via a composefs
9+
overlay filesystem. Each image ships `cbootc`, a small embedded tool that
10+
handles upgrades, rollbacks, and image switching from within the running system.
1311

1412
It is **not**:
1513

16-
- A general-purpose bootc replacement (use [bootc](https://github.com/bootc-dev/bootc))
17-
- An ostree-compatible tool (no ostree code)
14+
- A general-purpose [bootc](https://github.com/bootc-dev/bootc) replacement
15+
- An ostree-compatible tool
1816
- A fleet management system
1917

20-
See [DESIGN.md](DESIGN.md) for full design rationale.
18+
See [DESIGN.md](DESIGN.md) for rationale and architecture.
2119

22-
## Quick Start
20+
## Available Images
2321

24-
```sh
25-
# Build the base image (slow — dnf + dracut inside the container)
26-
podman build -t fedora-cfs-base:43 -f Containerfile.base .
22+
| Image | Status |
23+
|-------|--------|
24+
| `ghcr.io/OWNER/composefs-os-fedora:43` | Working |
25+
| Ubuntu | Planned |
26+
| Arch Linux | Planned |
2727

28-
# Build a derived image (fast)
29-
podman build -t my-fedora-cfs:latest -f examples/fedora/Containerfile .
28+
Replace `OWNER` with the GitHub organisation or username hosting the packages.
29+
30+
## Quick Start
3031

32+
```sh
3133
# Install to a raw disk image (run from inside the container, needs --privileged)
3234
sudo podman run --rm --privileged \
3335
-v $(pwd):/output \
3436
-v /var/lib/containers:/var/lib/containers \
3537
-v /var/tmp:/var/tmp \
36-
my-fedora-cfs:latest \
38+
ghcr.io/OWNER/composefs-os-fedora:43 \
3739
cbootc install to-disk /output/disk.raw --size 10G
3840

3941
# Boot it
@@ -43,35 +45,70 @@ qemu-system-x86_64 -enable-kvm -m 4096 \
4345
-nographic
4446
```
4547

46-
## Upgrading a Running System
48+
## Building a Custom Image
49+
50+
The published base images are a starting point. Add your own packages and
51+
configuration in a derived `Containerfile`:
52+
53+
```dockerfile
54+
FROM ghcr.io/OWNER/composefs-os-fedora:43
55+
56+
# Add packages
57+
RUN dnf install -y vim htop && dnf clean all
58+
59+
# Bake in configuration that must survive upgrades
60+
RUN echo 'myhost' > /etc/hostname
61+
```
62+
63+
Use `examples/fedora/Containerfile` as a full template.
64+
65+
## In-System Management
66+
67+
Once booted, `cbootc` manages the system:
4768

4869
```sh
49-
# Point the system at a registry image
50-
cbootc switch docker://ghcr.io/you/my-fedora-cfs:latest
70+
# Show current deployment status
71+
cbootc status
5172

52-
# Pull latest and stage new boot entry
73+
# Pull the latest image and stage a new boot entry
5374
cbootc upgrade
5475

5576
# Reboot to apply
5677
systemctl reboot
78+
79+
# Roll back to the previous deployment
80+
cbootc rollback
81+
systemctl reboot
82+
83+
# Switch to a different image
84+
cbootc switch docker://ghcr.io/OWNER/composefs-os-fedora:43
5785
```
5886

59-
The image reference is persisted in `/var/lib/cbootc/config.toml` and survives
60-
upgrades. The `cbootc-update.timer` (enabled in the base image) runs
87+
The tracked image reference is stored in `/var/lib/cbootc/config.toml` and
88+
survives upgrades. `cbootc-update.timer` (enabled in the base image) runs
6189
`cbootc upgrade` daily with a randomised delay.
6290

6391
## Repository Layout
6492

6593
```
66-
cbootc/
94+
composefs-os/
6795
Containerfile.base Builds the bootable Fedora 43 base image
68-
src/ Rust source
96+
src/ cbootc source (Rust)
6997
units/
7098
cbootc-update.service Systemd service for automatic upgrades
7199
cbootc-update.timer Systemd timer (daily, randomised delay)
72100
examples/
73101
fedora/
74-
Containerfile Example derived image (your customisations go here)
102+
Containerfile Template for derived Fedora images
103+
arch/
104+
Containerfile Arch Linux (stub — not yet functional)
105+
ubuntu/
106+
Containerfile Ubuntu (stub — not yet functional)
107+
tests/
108+
INTEGRATION.md Manual integration test checklist
109+
.github/workflows/
110+
ci.yml Rust build, test, lint
111+
container.yml Build and push base image to ghcr.io
75112
```
76113

77114
## Known Limitations
@@ -107,9 +144,9 @@ are not pruned automatically. Remove them manually when disk space is a concern.
107144

108145
### x86-64 only
109146

110-
The GRUB install step (`grub2-install --target=x86_64-efi`) is hard-coded to
111-
x86-64 EFI. aarch64 and other architectures are not supported.
147+
The GRUB install step is hard-coded to `--target=x86_64-efi`.
148+
aarch64 and other architectures are not supported.
112149

113150
## License
114151

115-
MIT — see [LICENSE](LICENSE) (if present) or SPDX identifier in source files.
152+
MIT — see [LICENSE](LICENSE).

examples/fedora/Containerfile

Lines changed: 14 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,37 @@
1-
# Example derived image built on fedora-cfs-base:43.
1+
# Template for a custom Fedora composefs-os image.
22
#
33
# Pattern:
4-
# 1. FROM fedora-cfs-base:43
4+
# 1. FROM ghcr.io/OWNER/composefs-os-fedora:43
55
# 2. Install packages, write config — /etc and /var are normal here
6-
# 3. Add LABEL containers.bootc=1
6+
# 3. Keep the LABEL block at the bottom
77
#
8-
# No cfs-layout-apply or FROM scratch step needed. cbootc install to-disk
9-
# handles the composefs layout transformation at install time.
8+
# Build locally:
9+
# podman build -t my-fedora-cfs:latest \
10+
# --build-arg BASE_IMAGE=ghcr.io/OWNER/composefs-os-fedora:43 \
11+
# -f examples/fedora/Containerfile .
1012
#
11-
# Build:
12-
# podman build -t fedora-cfs-base:43 -f examples/fedora/Containerfile.base .
13-
# podman build -t my-fedora-cfs:latest -f examples/fedora/Containerfile .
14-
# Deploy (physical disk):
15-
# sudo podman run --rm --privileged \
16-
# -v /dev:/dev -v /var/lib/containers:/var/lib/containers \
17-
# -v /var/tmp:/var/tmp \
18-
# my-fedora-cfs:latest cbootc install to-disk /dev/vda --wipe
19-
# Deploy (disk image file):
13+
# Deploy to a disk image file:
2014
# sudo podman run --rm --privileged \
2115
# -v $(pwd):/output -v /var/lib/containers:/var/lib/containers \
2216
# -v /var/tmp:/var/tmp \
2317
# my-fedora-cfs:latest cbootc install to-disk /output/disk.raw --size 10G
2418

25-
# BASE_IMAGE can be overridden in CI to reference ghcr.io/…/fedora-cfs-base:43
26-
ARG BASE_IMAGE=fedora-cfs-base:43
19+
ARG BASE_IMAGE=ghcr.io/OWNER/composefs-os-fedora:43
2720
FROM ${BASE_IMAGE}
2821

2922
# --- Customise below this line -------------------------------------------
3023

31-
# Root password — REMOVE FOR PRODUCTION, use SSH keys instead
32-
RUN echo 'root:fedora' | chpasswd
33-
34-
# Serial console autologin — REMOVE FOR PRODUCTION
35-
RUN mkdir -p /usr/lib/systemd/system/serial-getty@ttyS0.service.d && \
36-
printf '[Service]\nExecStart=\nExecStart=-/sbin/agetty --autologin root --noclear %%I 115200,38400,9600 vt220\n' \
37-
> /usr/lib/systemd/system/serial-getty@ttyS0.service.d/autologin.conf
38-
39-
RUN echo 'fedora-cfs' > /etc/hostname
24+
# Set hostname
25+
RUN echo 'myhost' > /etc/hostname
4026

41-
# Add your own packages here:
42-
# RUN dnf install -y --setopt=install_weak_deps=False myapp && dnf clean all
27+
# Add your packages here, e.g.:
28+
# RUN dnf install -y --setopt=install_weak_deps=False vim htop && dnf clean all
4329

4430
# --- Do not edit below this line ------------------------------------------
4531

4632
LABEL containers.bootc=1
4733
LABEL composefs.backend=cfs-rs
48-
LABEL org.opencontainers.image.title="Fedora CFS (example)"
49-
LABEL org.opencontainers.image.description="Example composefs-rs bootable Fedora 43 image"
34+
LABEL org.opencontainers.image.title="My Fedora composefs-os image"
5035
LABEL org.opencontainers.image.version="43"
5136

5237
CMD ["/sbin/init"]

units/cbootc-update.service

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
Description=cbootc automatic image upgrade
33
After=network-online.target
44
Wants=network-online.target
5-
ConditionPathExists=/etc/cbootc/config.toml
5+
ConditionPathExists=/var/lib/cbootc/config.toml
66

77
[Service]
88
Type=oneshot

0 commit comments

Comments
 (0)