libfasttree 0.1.0

A Rust library inspired by libostree, but based on distribution repositories.
Documentation

libfasttree

Crates.io Docs.rs License: MIT

A Rust library inspired by libostree, designed for managing immutable system images based on distribution repositories. It provides features like content-addressed storage (CAS), dependency resolution, delta updates, overlays, and more, with a focus on security, efficiency, and extensibility.

Features

  • Supply Chain Security: Supports Sigstore/Cosign for keyless signing, FS-Verity for immutable files, and TPM integration for sealing keys based on system state.
  • Storage Efficiency: Uses Zstandard compression with dictionaries, block-level deduplication via FastCDC, and a garbage collector for unused objects.
  • System Management: Handles OverlayFS for ephemeral changes, Systemd-Sysext for dynamic extensions, and A/B partitioning for seamless updates.
  • Plugin System: Extensible package managers via traits (e.g., APT, RPM, Nix, APK).
  • Async I/O: Leverages Tokio and io_uring for high-performance operations on NVMe drives.

Installation

Add this to your Cargo.toml:

[dependencies]
libfasttree = "0.1.0"

Note: This library requires root privileges for some operations (e.g., mounting, chown). It depends on various crates like sqlx, tokio, nix, and others—see Cargo.toml for the full list.

Quick Start

Configuration

Create a Config struct to initialize the library:

use libfasttree::{Config, DistroType, BootloaderType, FilesystemType, PartitioningType};
use std::path::PathBuf;
use tss_esapi::tcti::Tcti;

let config = Config {
    repo_url: "http://deb.debian.org/debian".to_string(),
    distro_type: DistroType::Apt,
    cas_dir: PathBuf::from("/var/lib/fasttree/objects"),
    db_path: PathBuf::from("/var/lib/fasttree/db.sqlite"),
    deployments_dir: PathBuf::from("/sysroot"),
    current_link: PathBuf::from("/ostree/current"),
    boot_dir: PathBuf::from("/boot"),
    bootloader: BootloaderType::SystemdBoot,
    filesystem: FilesystemType::Btrfs,
    health_check_script: Some(PathBuf::from("/usr/bin/health-check.sh")),
    overlay_dirs: vec![PathBuf::from("/etc"), PathBuf::from("/var")],
    var_volume: Some(PathBuf::from("/dev/sdb1")),
    gpg_keyring: PathBuf::from("/etc/apt/trusted.gpg"),
    use_fsverity: true,
    use_ima: true,
    partitioning: PartitioningType::Subvolumes,
    sysext_dir: PathBuf::from("/var/lib/extensions"),
    zstd_dicts: std::collections::HashMap::new(), // Add dictionaries as needed
    tpm_tcti: Tcti::Tpmtis, // Configure TPM
};

Initialization

use libfasttree::FastTree;
use tokio::runtime::Runtime;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let config = /* ... */;
    let mut ft = FastTree::new(config).await?;
    Ok(())
}

Mini Tutorials

Tutorial 1: Installing a Package

Resolve dependencies, download, extract, store in CAS, build a tree, commit, and deploy:

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let config = /* ... */;
    let mut ft = FastTree::new(config).await?;
    ft.install("nginx", "stable").await?;
    Ok(())
}

This handles dependency resolution using a solver (mocked with libsolv), verifies signatures with Sigstore, compresses with Zstd, deduplicates blocks, and deploys with overlays.

Tutorial 2: Rolling Back

Rollback to the previous tree:

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let config = /* ... */;
    let mut ft = FastTree::new(config).await?;
    ft.rollback().await?;
    Ok(())
}

Tutorial 3: Garbage Collection

Clean up unused objects and chunks:

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let config = /* ... */;
    let mut ft = FastTree::new(config).await?;
    ft.gc().await?;
    Ok(())
}

Tutorial 4: Building a System Extension (Sysext)

Create a sysext image from packages:

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let config = /* ... */;
    let mut ft = FastTree::new(config).await?;
    let packages = vec!["gdb".to_string(), "valgrind".to_string()];
    let output = std::path::Path::new("/tmp/debug-tools.sysext.raw");
    ft.build_sysext(&packages, output).await?;
    Ok(())
}

Load extensions via systemd-sysext merge.

Tutorial 5: Deploying a Reference

Deploy a committed tree:

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let config = /* ... */;
    let mut ft = FastTree::new(config).await?;
    ft.deploy("stable").await?;
    Ok(())
}

This sets up overlays, updates the bootloader, and handles stateless configs.

Security Notes

  • Use FS-Verity for immutable files: Files in CAS are protected at the filesystem level.
  • TPM: Keys are sealed only if PCR values match expected system state.
  • Signatures: Keyless with Sigstore for packages.

Contributing

Contributions welcome! See repository for issues and PRs.

License

MIT - See LICENSE for details.