feat: Add multi-version Debian support (Trixie + Forky)

- Added support for Debian 14 (Forky) testing release
- Created examples for both Debian 13 (Trixie) and Debian 14 (Forky)
- Added comprehensive multi-version documentation
- Created automated version switching script with backup/restore
- Updated README with version-specific configuration examples
- Added migration guidance between Debian versions

This enables users to build images for both stable (Trixie) and
testing (Forky) releases with easy switching between versions.
This commit is contained in:
robojerk 2025-08-12 00:34:19 -07:00
parent 544eb61951
commit 93deac1b8c
7 changed files with 954 additions and 22 deletions

126
README.md
View file

@ -490,15 +490,135 @@ make format
### 1. Basic Debian System (`examples/debian-basic.json`)
Creates a minimal Debian system with basic packages and user accounts.
### 2. OSTree System (`examples/debian-ostree.json`)
### 2. Debian 14 Basic System (`examples/debian-forky-basic.json`)
Creates a minimal Debian 14 (Forky) testing system with basic packages and user accounts.
### 3. OSTree System (`examples/debian-ostree.json`)
Builds a Debian system with OSTree repository management.
### 3. Complete System (`examples/debian-complete.json`)
### 4. Complete System (`examples/debian-complete.json`)
Comprehensive Debian system with all basic stages.
### 4. Bootable OSTree System (`examples/debian-ostree-bootable.json`)
### 5. Multi-Version System (`examples/debian-multi-version.json`)
Complete Debian 13 (Trixie) stable system with all stages and OSTree support.
### 6. Debian 14 Complete System (`examples/debian-forky-complete.json`)
Complete Debian 14 (Forky) testing system with all stages and OSTree support.
### 7. Bootable OSTree System (`examples/debian-ostree-bootable.json`)
Complete bootable Debian OSTree system with GRUB2 and bootc.
## 🔄 Multi-Version Debian Support
particle-os supports building images for multiple Debian versions:
### **Debian 13 (Trixie) - Stable Release**
- **Suite**: `trixie`
- **Status**: Current stable release
- **Use case**: Production deployments, long-term support
- **Security updates**: Regular security patches
- **Example**: `examples/debian-basic.json`
### **Debian 14 (Forky) - Testing Release**
- **Suite**: `forky`
- **Status**: Testing release (future stable)
- **Use case**: Development, testing, early adoption
- **Security updates**: Security patches from unstable
- **Example**: `examples/debian-forky-basic.json`
### **Version-Specific Configuration**
#### Sources Configuration
```json
{
"name": "org.osbuild.debian.sources",
"options": {
"suite": "trixie", // or "forky"
"mirror": "https://deb.debian.org/debian",
"components": ["main", "contrib", "non-free"],
"additional_sources": [
"deb https://deb.debian.org/debian-security trixie-security main contrib non-free",
"deb https://deb.debian.org/debian-updates trixie-updates main contrib non-free"
]
}
}
```
#### Debootstrap Configuration
```json
{
"name": "org.osbuild.debian.debootstrap",
"options": {
"suite": "trixie", // or "forky"
"mirror": "https://deb.debian.org/debian",
"variant": "minbase",
"arch": "amd64",
"components": ["main", "contrib", "non-free"]
}
}
```
#### OSTree Branch Naming
```json
{
"name": "org.osbuild.debian.ostree",
"options": {
"branch": "debian/trixie/x86_64/standard", // or "debian/forky/x86_64/standard"
"subject": "Debian Trixie OSTree System", // or "Debian Forky OSTree System"
"body": "Complete Debian OSTree system with GRUB2 and bootc"
}
}
```
### **Choosing the Right Version**
- **Use Trixie (Debian 13)** for:
- Production environments
- Long-term stability
- Security-focused deployments
- Enterprise use cases
- **Use Forky (Debian 14)** for:
- Development and testing
- Early access to new features
- CI/CD pipelines
- Experimental deployments
### **Migration Between Versions**
To migrate from one Debian version to another:
1. **Update manifest files** to use the new suite name
2. **Adjust package lists** for version compatibility
3. **Update OSTree branch names** to reflect new version
4. **Test thoroughly** before production deployment
5. **Consider rolling back** if issues arise
### **Automated Version Switching**
particle-os includes a script to automatically switch between Debian versions:
```bash
# List supported Debian versions
./scripts/switch-debian-version.sh -l
# Switch from Trixie to Forky (with backup)
./scripts/switch-debian-version.sh -b -v forky examples/debian-basic.json
# Switch from Forky to Trixie
./scripts/switch-debian-version.sh -v trixie examples/debian-forky-basic.json
# Restore from backup
./scripts/switch-debian-version.sh -r examples/debian-basic.json
```
The script automatically updates:
- Suite names in sources and debootstrap stages
- Security and update repository URLs
- OSTree branch names
- Subject lines and descriptions
- Output filenames (if version-specific)
## 🏗️ Architecture Deep Dive
### Stage Implementation Pattern

View file

@ -10,7 +10,10 @@
"options": {
"suite": "trixie",
"mirror": "https://deb.debian.org/debian",
"components": ["main", "contrib", "non-free"]
"components": ["main", "contrib", "non-free"],
"additional_sources": [
"deb https://deb.debian.org/debian-security trixie-security main contrib non-free"
]
}
},
{
@ -35,37 +38,45 @@
"vim",
"less",
"locales",
"ca-certificates"
"ca-certificates",
"tzdata",
"net-tools",
"iproute2"
],
"update": true,
"clean": true
}
},
{
"name": "org.osbuild.users",
"name": "org.osbuild.debian.locale",
"options": {
"language": "en_US.UTF-8",
"additional_locales": ["en_GB.UTF-8", "de_DE.UTF-8"],
"default_locale": "en_US.UTF-8"
}
},
{
"name": "org.osbuild.debian.timezone",
"options": {
"timezone": "UTC"
}
},
{
"name": "org.osbuild.debian.users",
"options": {
"users": {
"debian": {
"password": "$6$rounds=656000$salt$hashedpassword",
"shell": "/bin/bash",
"groups": ["sudo", "users"],
"groups": ["sudo", "users", "adm"],
"uid": 1000,
"gid": 1000,
"home": "/home/debian"
"home": "/home/debian",
"comment": "Debian User"
}
}
}
},
{
"name": "org.osbuild.locale",
"options": {
"language": "en_US.UTF-8"
}
},
{
"name": "org.osbuild.timezone",
"options": {
"timezone": "UTC"
},
"default_shell": "/bin/bash",
"default_home": "/home"
}
}
]
@ -74,7 +85,6 @@
"assembler": {
"name": "org.osbuild.tar",
"options": {
"filename": "debian-basic.tar.gz",
"compression": "gzip"
}
}

View file

@ -0,0 +1,91 @@
{
"version": "2",
"pipelines": [
{
"name": "build",
"runner": "org.osbuild.linux",
"stages": [
{
"name": "org.osbuild.debian.sources",
"options": {
"suite": "trixie",
"mirror": "https://deb.debian.org/debian",
"components": ["main", "contrib", "non-free"],
"additional_sources": [
"deb https://deb.debian.org/debian-security trixie-security main contrib non-free"
]
}
},
{
"name": "org.osbuild.debian.debootstrap",
"options": {
"suite": "trixie",
"mirror": "https://deb.debian.org/debian",
"variant": "minbase",
"arch": "amd64",
"components": ["main", "contrib", "non-free"]
}
},
{
"name": "org.osbuild.debian.apt",
"options": {
"packages": [
"sudo",
"openssh-server",
"systemd-sysv",
"curl",
"wget",
"vim",
"less",
"locales",
"ca-certificates",
"tzdata",
"net-tools",
"iproute2"
],
"update": true,
"clean": true
}
},
{
"name": "org.osbuild.debian.locale",
"options": {
"language": "en_US.UTF-8",
"additional_locales": ["en_GB.UTF-8", "de_DE.UTF-8"],
"default_locale": "en_US.UTF-8"
}
},
{
"name": "org.osbuild.debian.timezone",
"options": {
"timezone": "UTC"
}
},
{
"name": "org.osbuild.debian.users",
"options": {
"users": {
"debian": {
"password": "$6$rounds=656000$salt$hashedpassword",
"shell": "/bin/bash",
"groups": ["sudo", "users", "adm"],
"uid": 1000,
"gid": 1000,
"home": "/home/debian",
"comment": "Debian User"
}
},
"default_shell": "/bin/bash",
"default_home": "/home"
}
}
]
}
],
"assembler": {
"name": "org.osbuild.tar",
"options": {
"compression": "gzip"
}
}
}

View file

@ -0,0 +1,91 @@
{
"version": "2",
"pipelines": [
{
"name": "build",
"runner": "org.osbuild.linux",
"stages": [
{
"name": "org.osbuild.debian.sources",
"options": {
"suite": "forky",
"mirror": "https://deb.debian.org/debian",
"components": ["main", "contrib", "non-free"],
"additional_sources": [
"deb https://deb.debian.org/debian-security forky-security main contrib non-free"
]
}
},
{
"name": "org.osbuild.debian.debootstrap",
"options": {
"suite": "forky",
"mirror": "https://deb.debian.org/debian",
"variant": "minbase",
"arch": "amd64",
"components": ["main", "contrib", "non-free"]
}
},
{
"name": "org.osbuild.debian.apt",
"options": {
"packages": [
"sudo",
"openssh-server",
"systemd-sysv",
"curl",
"wget",
"vim",
"less",
"locales",
"ca-certificates",
"tzdata",
"net-tools",
"iproute2"
],
"update": true,
"clean": true
}
},
{
"name": "org.osbuild.debian.locale",
"options": {
"language": "en_US.UTF-8",
"additional_locales": ["en_GB.UTF-8", "de_DE.UTF-8"],
"default_locale": "en_US.UTF-8"
}
},
{
"name": "org.osbuild.debian.timezone",
"options": {
"timezone": "UTC"
}
},
{
"name": "org.osbuild.debian.users",
"options": {
"users": {
"debian": {
"password": "$6$rounds=656000$salt$hashedpassword",
"shell": "/bin/bash",
"groups": ["sudo", "users", "adm"],
"uid": 1000,
"gid": 1000,
"home": "/home/debian",
"comment": "Debian User"
}
},
"default_shell": "/bin/bash",
"default_home": "/home"
}
}
]
}
],
"assembler": {
"name": "org.osbuild.tar",
"options": {
"compression": "gzip"
}
}
}

View file

@ -0,0 +1,175 @@
{
"version": "2",
"pipelines": [
{
"name": "build",
"runner": "org.osbuild.linux",
"stages": [
{
"name": "org.osbuild.debian.sources",
"options": {
"suite": "forky",
"mirror": "https://deb.debian.org/debian",
"components": ["main", "contrib", "non-free"],
"additional_sources": [
"deb https://deb.debian.org/debian-security forky-security main contrib non-free",
"deb https://deb.debian.org/debian-updates forky-updates main contrib non-free"
]
}
},
{
"name": "org.osbuild.debian.debootstrap",
"options": {
"suite": "forky",
"mirror": "https://deb.debian.org/debian",
"variant": "minbase",
"arch": "amd64",
"components": ["main", "contrib", "non-free"]
}
},
{
"name": "org.osbuild.debian.apt",
"options": {
"packages": [
"ostree",
"bootc",
"systemd",
"systemd-sysv",
"linux-image-amd64",
"grub2-efi-amd64",
"grub2-common",
"efibootmgr",
"sudo",
"openssh-server",
"curl",
"wget",
"vim",
"less",
"locales",
"ca-certificates",
"tzdata",
"net-tools",
"iproute2",
"resolvconf",
"firmware-linux",
"firmware-linux-nonfree",
"initramfs-tools"
],
"update": true,
"clean": true
}
},
{
"name": "org.osbuild.debian.locale",
"options": {
"language": "en_US.UTF-8",
"additional_locales": ["en_GB.UTF-8", "de_DE.UTF-8", "fr_FR.UTF-8"],
"default_locale": "en_US.UTF-8"
}
},
{
"name": "org.osbuild.debian.timezone",
"options": {
"timezone": "UTC"
}
},
{
"name": "org.osbuild.debian.users",
"options": {
"users": {
"debian": {
"password": "$6$rounds=656000$salt$hashedpassword",
"shell": "/bin/bash",
"groups": ["sudo", "users", "adm"],
"uid": 1000,
"gid": 1000,
"home": "/home/debian",
"comment": "Debian User"
},
"admin": {
"password": "$6$rounds=656000$salt$hashedpassword",
"shell": "/bin/bash",
"groups": ["sudo", "users", "adm", "wheel"],
"uid": 1001,
"gid": 1001,
"home": "/home/admin",
"comment": "Administrator"
}
},
"default_shell": "/bin/bash",
"default_home": "/home"
}
},
{
"name": "org.osbuild.debian.systemd",
"options": {
"enable_services": [
"ssh",
"systemd-networkd",
"systemd-resolved"
],
"disable_services": [
"systemd-firstboot",
"systemd-machine-id-commit"
],
"mask_services": [
"systemd-remount-fs",
"systemd-machine-id-commit"
],
"config": {
"DefaultDependencies": "no",
"DefaultTimeoutStartSec": "0",
"DefaultTimeoutStopSec": "0"
}
}
},
{
"name": "org.osbuild.debian.bootc",
"options": {
"enable": true,
"config": {
"auto_update": true,
"rollback_enabled": true
},
"kernel_args": [
"console=ttyS0",
"console=tty0",
"root=UUID=ROOT_UUID",
"quiet",
"splash"
]
}
},
{
"name": "org.osbuild.debian.grub2",
"options": {
"root_fs_uuid": "ROOT_UUID",
"kernel_path": "/boot/vmlinuz",
"initrd_path": "/boot/initrd.img",
"bootloader_id": "debian",
"timeout": 5,
"default_entry": "0"
}
},
{
"name": "org.osbuild.debian.ostree",
"options": {
"repository": "/var/lib/ostree/repo",
"branch": "debian/forky/x86_64/standard",
"subject": "Debian Forky OSTree System",
"body": "Complete Debian 14 Forky OSTree system with GRUB2 and bootc"
}
}
]
}
],
"assembler": {
"name": "org.osbuild.debian.qemu",
"options": {
"format": "qcow2",
"filename": "debian-forky-ostree.qcow2",
"size": "20G",
"ptuuid": "12345678-1234-1234-1234-123456789012"
}
}
}

View file

@ -0,0 +1,175 @@
{
"version": "2",
"pipelines": [
{
"name": "build",
"runner": "org.osbuild.linux",
"stages": [
{
"name": "org.osbuild.debian.sources",
"options": {
"suite": "trixie",
"mirror": "https://deb.debian.org/debian",
"components": ["main", "contrib", "non-free"],
"additional_sources": [
"deb https://deb.debian.org/debian-security trixie-security main contrib non-free",
"deb https://deb.debian.org/debian-updates trixie-updates main contrib non-free"
]
}
},
{
"name": "org.osbuild.debian.debootstrap",
"options": {
"suite": "trixie",
"mirror": "https://deb.debian.org/debian",
"variant": "minbase",
"arch": "amd64",
"components": ["main", "contrib", "non-free"]
}
},
{
"name": "org.osbuild.debian.apt",
"options": {
"packages": [
"ostree",
"bootc",
"systemd",
"systemd-sysv",
"linux-image-amd64",
"grub2-efi-amd64",
"grub2-common",
"efibootmgr",
"sudo",
"openssh-server",
"curl",
"wget",
"vim",
"less",
"locales",
"ca-certificates",
"tzdata",
"net-tools",
"iproute2",
"resolvconf",
"firmware-linux",
"firmware-linux-nonfree",
"initramfs-tools"
],
"update": true,
"clean": true
}
},
{
"name": "org.osbuild.debian.locale",
"options": {
"language": "en_US.UTF-8",
"additional_locales": ["en_GB.UTF-8", "de_DE.UTF-8", "fr_FR.UTF-8"],
"default_locale": "en_US.UTF-8"
}
},
{
"name": "org.osbuild.debian.timezone",
"options": {
"timezone": "UTC"
}
},
{
"name": "org.osbuild.debian.users",
"options": {
"users": {
"debian": {
"password": "$6$rounds=656000$salt$hashedpassword",
"shell": "/bin/bash",
"groups": ["sudo", "users", "adm"],
"uid": 1000,
"gid": 1000,
"home": "/home/debian",
"comment": "Debian User"
},
"admin": {
"password": "$6$rounds=656000$salt$hashedpassword",
"shell": "/bin/bash",
"groups": ["sudo", "users", "adm", "wheel"],
"uid": 1001,
"gid": 1001,
"home": "/home/admin",
"comment": "Administrator"
}
},
"default_shell": "/bin/bash",
"default_home": "/home"
}
},
{
"name": "org.osbuild.debian.systemd",
"options": {
"enable_services": [
"ssh",
"systemd-networkd",
"systemd-resolved"
],
"disable_services": [
"systemd-firstboot",
"systemd-machine-id-commit"
],
"mask_services": [
"systemd-remount-fs",
"systemd-machine-id-commit"
],
"config": {
"DefaultDependencies": "no",
"DefaultTimeoutStartSec": "0",
"DefaultTimeoutStopSec": "0"
}
}
},
{
"name": "org.osbuild.debian.bootc",
"options": {
"enable": true,
"config": {
"auto_update": true,
"rollback_enabled": true
},
"kernel_args": [
"console=ttyS0",
"console=tty0",
"root=UUID=ROOT_UUID",
"quiet",
"splash"
]
}
},
{
"name": "org.osbuild.debian.grub2",
"options": {
"root_fs_uuid": "ROOT_UUID",
"kernel_path": "/boot/vmlinuz",
"initrd_path": "/boot/initrd.img",
"bootloader_id": "debian",
"timeout": 5,
"default_entry": "0"
}
},
{
"name": "org.osbuild.debian.ostree",
"options": {
"repository": "/var/lib/ostree/repo",
"branch": "debian/trixie/x86_64/standard",
"subject": "Debian Trixie OSTree System",
"body": "Complete Debian OSTree system with GRUB2 and bootc"
}
}
]
}
],
"assembler": {
"name": "org.osbuild.debian.qemu",
"options": {
"format": "qcow2",
"filename": "debian-trixie-ostree.qcow2",
"size": "20G",
"ptuuid": "12345678-1234-1234-1234-123456789012"
}
}
}

270
scripts/switch-debian-version.sh Executable file
View file

@ -0,0 +1,270 @@
#!/bin/bash
# particle-os Debian Version Switcher
# This script helps you switch between different Debian versions in your manifests
set -e
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Function to print colored output
print_status() {
echo -e "${GREEN}[INFO]${NC} $1"
}
print_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
print_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
print_header() {
echo -e "${BLUE}=== $1 ===${NC}"
}
# Function to show usage
show_usage() {
cat << EOF
Usage: $0 [OPTIONS] <manifest-file>
Options:
-v, --version <version> Debian version to switch to (trixie, forky)
-b, --backup Create backup of original manifest
-r, --restore Restore from backup
-l, --list List supported Debian versions
-h, --help Show this help message
Examples:
$0 -v forky examples/debian-basic.json
$0 -v trixie examples/debian-forky-basic.json
$0 -b -v forky examples/debian-basic.json
$0 -r examples/debian-basic.json
Supported Debian Versions:
trixie - Debian 13 (current stable)
forky - Debian 14 (testing, future stable)
EOF
}
# Function to list supported versions
list_versions() {
cat << EOF
Supported Debian Versions:
1. trixie (Debian 13)
- Status: Current stable release
- Use case: Production deployments
- Security: Regular security patches
- Example: examples/debian-basic.json
2. forky (Debian 14)
- Status: Testing release
- Use case: Development and testing
- Security: Security patches from unstable
- Example: examples/debian-forky-basic.json
Version Mapping:
trixie -> Debian 13 (stable)
forky -> Debian 14 (testing)
EOF
}
# Function to backup manifest
backup_manifest() {
local manifest_file="$1"
local backup_file="${manifest_file}.backup.$(date +%Y%m%d_%H%M%S)"
if cp "$manifest_file" "$backup_file"; then
print_status "Backup created: $backup_file"
echo "$backup_file" > "${manifest_file}.backup"
else
print_error "Failed to create backup"
exit 1
fi
}
# Function to restore from backup
restore_manifest() {
local manifest_file="$1"
local backup_file
if [[ -f "${manifest_file}.backup" ]]; then
backup_file=$(cat "${manifest_file}.backup")
if [[ -f "$backup_file" ]]; then
if cp "$backup_file" "$manifest_file"; then
print_status "Restored from backup: $backup_file"
rm "${manifest_file}.backup"
else
print_error "Failed to restore from backup"
exit 1
fi
else
print_error "Backup file not found: $backup_file"
exit 1
fi
else
print_error "No backup found for: $manifest_file"
exit 1
fi
}
# Function to switch Debian version
switch_version() {
local manifest_file="$1"
local target_version="$2"
# Validate target version
case "$target_version" in
trixie|forky)
;;
*)
print_error "Unsupported Debian version: $target_version"
print_error "Supported versions: trixie, forky"
exit 1
;;
esac
# Check if manifest file exists
if [[ ! -f "$manifest_file" ]]; then
print_error "Manifest file not found: $manifest_file"
exit 1
fi
# Create backup if requested
if [[ "$CREATE_BACKUP" == "true" ]]; then
backup_manifest "$manifest_file"
fi
# Determine source version from current manifest
local current_version
current_version=$(grep -o '"suite": *"[^"]*"' "$manifest_file" | head -1 | cut -d'"' -f4)
if [[ -z "$current_version" ]]; then
print_warning "Could not determine current Debian version from manifest"
print_warning "Proceeding with version switch..."
else
print_status "Current Debian version: $current_version"
fi
print_status "Switching to Debian version: $target_version"
# Update suite references
sed -i "s/\"suite\": \"[^\"]*\"/\"suite\": \"$target_version\"/g" "$manifest_file"
# Update security sources
sed -i "s/debian-security [a-z]*-security/debian-security ${target_version}-security/g" "$manifest_file"
# Update update sources
sed -i "s/debian-updates [a-z]*-updates/debian-updates ${target_version}-updates/g" "$manifest_file"
# Update OSTree branch names
sed -i "s/debian\/[a-z]*\/x86_64/debian\/${target_version}\/x86_64/g" "$manifest_file"
# Update subject lines
sed -i "s/Debian [A-Za-z]* OSTree/Debian ${target_version^} OSTree/g" "$manifest_file"
sed -i "s/Debian [A-Za-z]* System/Debian ${target_version^} System/g" "$manifest_file"
# Update filename if it contains version
if grep -q "debian-[a-z]*-ostree" "$manifest_file"; then
sed -i "s/debian-[a-z]*-ostree/debian-${target_version}-ostree/g" "$manifest_file"
fi
print_status "Successfully switched to Debian $target_version"
print_status "Manifest updated: $manifest_file"
# Show summary of changes
echo
print_header "Summary of Changes"
echo "Suite: $target_version"
echo "Security sources: ${target_version}-security"
echo "Update sources: ${target_version}-updates"
echo "OSTree branch: debian/${target_version}/x86_64"
echo "Subject: Debian ${target_version^} OSTree System"
}
# Main script logic
main() {
local manifest_file=""
local target_version=""
local CREATE_BACKUP="false"
local RESTORE_BACKUP="false"
local LIST_VERSIONS="false"
# Parse command line arguments
while [[ $# -gt 0 ]]; do
case $1 in
-v|--version)
target_version="$2"
shift 2
;;
-b|--backup)
CREATE_BACKUP="true"
shift
;;
-r|--restore)
RESTORE_BACKUP="true"
shift
;;
-l|--list)
LIST_VERSIONS="true"
shift
;;
-h|--help)
show_usage
exit 0
;;
-*)
print_error "Unknown option: $1"
show_usage
exit 1
;;
*)
manifest_file="$1"
shift
;;
esac
done
# Handle list versions
if [[ "$LIST_VERSIONS" == "true" ]]; then
list_versions
exit 0
fi
# Handle restore
if [[ "$RESTORE_BACKUP" == "true" ]]; then
if [[ -z "$manifest_file" ]]; then
print_error "Manifest file required for restore operation"
show_usage
exit 1
fi
restore_manifest "$manifest_file"
exit 0
fi
# Validate required arguments
if [[ -z "$target_version" ]]; then
print_error "Target Debian version is required"
show_usage
exit 1
fi
if [[ -z "$manifest_file" ]]; then
print_error "Manifest file is required"
show_usage
exit 1
fi
# Perform version switch
switch_version "$manifest_file" "$target_version"
}
# Run main function with all arguments
main "$@"