bootc-docs/lint/technical-reference.md
robojerk 526f1c1afd Initial commit: Comprehensive Debian bootc documentation
- Complete documentation for all bootc commands and subcommands
- Debian-specific adaptations and workarounds
- Manual installation methods to bypass bootc reliability issues
- Technical guides with Rust source code analysis
- Flowcharts and external command references
- Hidden command documentation (bootc internals, state, etc.)
- Composefs integration analysis
- Base image creation guides (with and without bootc binary)
- Management scripts and automation
- Comprehensive troubleshooting and examples
2025-09-15 14:02:28 -07:00

13 KiB

bootc container lint - Technical Reference

Architecture Overview

The bootc lint system is built on a distributed slice architecture using the linkme crate, allowing for modular lint registration and execution. The system supports both regular and recursive lints, with configurable execution and output formatting.

Core Components

1. Lint Registration System

// From lints.rs:86-87
#[distributed_slice]
pub(crate) static LINTS: [Lint];

Purpose: Central registry for all lint checks Implementation: Uses linkme distributed slices for automatic registration Benefits: Modular design, easy addition of new lints

2. Lint Types

Fatal Lints

// From lints.rs:92-98
enum LintType {
    Fatal,    // Must pass for installation
    Warning,  // Recommended but not required
}

Fatal Lints: Prevent bootc installation if they fail Warning Lints: Show warnings but allow installation to proceed

3. Root Type Classification

// From lints.rs:106-111
enum RootType {
    Running,     // Running system root
    Alternative, // Alternative/container root
}

Running: Lints that apply to running systems Alternative: Lints that apply to container images

Lint Execution Engine

1. Execution Flow

// From lints.rs:254-364
fn lint_inner<'skip>(
    root: &Dir,
    root_type: RootType,
    config: &LintExecutionConfig,
    skip: impl IntoIterator<Item = &'skip str>,
    mut output: impl std::io::Write,
) -> Result<LintExecutionResult>

Process:

  1. Filter applicable lints based on root type
  2. Separate regular and recursive lints
  3. Execute regular lints
  4. Execute recursive lints via filesystem walk
  5. Collect and report results

2. Recursive Lint Execution

// From lints.rs:295-328
root.walk(
    &WalkConfiguration::default()
        .noxdev()
        .path_base(Path::new("/")),
    |e| -> std::io::Result<_> {
        // Execute recursive lints on each filesystem entry
    },
)?;

Features:

  • Filesystem traversal with noxdev (no cross-device)
  • Early termination on first error
  • Efficient processing of large filesystems

3. Output Formatting

// From lints.rs:200-235
fn format_items<T>(
    config: &LintExecutionConfig,
    header: &str,
    items: impl Iterator<Item = T>,
    o: &mut String,
) -> Result<()>

Features:

  • Configurable truncation (default: 5 items)
  • Consistent formatting across lints
  • Support for custom display implementations

Individual Lint Implementations

1. var-run Lint

// From lints.rs:397-410
static LINT_VAR_RUN: Lint = Lint::new_fatal(
    "var-run",
    "Check for /var/run being a physical directory; this is always a bug.",
    check_var_run,
);

Purpose: Ensures /var/run is a symlink to /run Check: Validates symlink existence and target Rationale: Required for proper systemd operation

2. etc-usretc Lint

// From lints.rs:435-458
static LINT_ETC_USRUSETC: Lint = Lint::new_fatal(
    "etc-usretc",
    "Verify that only one of /etc or /usr/etc exist...",
    check_usretc,
);

Purpose: Prevents both /etc and /usr/etc from existing Check: Validates mutual exclusivity Rationale: /usr/etc is a bootc implementation detail

3. bootc-kargs Lint

// From lints.rs:461-471
static LINT_KARGS: Lint = Lint::new_fatal(
    "bootc-kargs",
    "Verify syntax of /usr/lib/bootc/kargs.d.",
    check_parse_kargs,
);

Purpose: Validates kernel argument configuration Check: Parses TOML files in /usr/lib/bootc/kargs.d/ Integration: Uses crate::bootc_kargs::get_kargs_in_root

4. kernel Lint

// From lints.rs:473-486
static LINT_KERNEL: Lint = Lint::new_fatal(
    "kernel",
    "Check for multiple kernels...",
    check_kernel,
);

Purpose: Ensures exactly one kernel is present Check: Validates /usr/lib/modules/$kver directories Integration: Uses ostree_ext::bootabletree::find_kernel_dir_fs

5. utf8 Lint (Recursive)

// From lints.rs:489-522
static LINT_UTF8: Lint = Lint {
    name: "utf8",
    description: "Check for non-UTF8 filenames...",
    ty: LintType::Fatal,
    root_type: None,
    f: LintFnTy::Recursive(check_utf8),
};

Purpose: Ensures all filenames and symlink targets are UTF-8 Check: Recursively validates filesystem entries Features: Handles symlinks, broken links, and special cases

6. api-base-directories Lint

// From lints.rs:535-558
static LINT_API_DIRS: Lint = Lint::new_fatal(
    "api-base-directories",
    "Verify that expected base API directories exist...",
    check_api_dirs,
);

Purpose: Validates required systemd API directories Check: Ensures /dev, /proc, /sys, /run, /tmp, /var exist Rationale: Required by systemd and Linux standards

7. baseimage-root Lint

// From lints.rs:610-632
static LINT_BASEIMAGE_ROOT: Lint = Lint::new_fatal(
    "baseimage-root",
    "Check that expected files are present in the root...",
    check_baseimage_root,
);

Purpose: Validates bootc-specific root structure Check: Ensures /sysroot exists and /ostree symlinks correctly Integration: Checks embedded documentation for consistency

Warning Lints

1. buildah-injected Lint

// From lints.rs:412-433
static LINT_BUILDAH_INJECTED: Lint = Lint::new_warning(
    "buildah-injected",
    "Check for an invalid /etc/hostname or /etc/resolv.conf...",
    check_buildah_injected,
)
.set_root_type(RootType::Alternative);

Purpose: Detects empty files injected by build systems Check: Looks for empty /etc/hostname or /etc/resolv.conf Scope: Only applies to alternative roots (container images)

2. baseimage-composefs Lint

// From lints.rs:560-581
static LINT_COMPOSEFS: Lint = Lint::new_warning(
    "baseimage-composefs",
    "Check that composefs is enabled for ostree...",
    check_composefs,
);

Purpose: Recommends composefs for ostree Check: Validates composefs configuration Integration: Uses ostree_prepareroot for configuration parsing

3. var-log Lint

// From lints.rs:656-682
static LINT_VARLOG: Lint = Lint::new_warning(
    "var-log",
    "Check for non-empty regular files in /var/log...",
    check_varlog,
);

Purpose: Warns about log files in container images Check: Identifies non-empty files in /var/log Features: Recursive directory scanning with size checking

4. var-tmpfiles Lint

// From lints.rs:684-712
static LINT_VAR_TMPFILES: Lint = Lint::new_warning(
    "var-tmpfiles",
    "Check for content in /var that does not have corresponding systemd tmpfiles.d entries...",
    check_var_tmpfiles,
)
.set_root_type(RootType::Running);

Purpose: Validates tmpfiles.d configuration Check: Ensures /var content has corresponding tmpfiles.d entries Scope: Only applies to running systems Integration: Uses bootc_tmpfiles crate

5. sysusers Lint

// From lints.rs:714-743
static LINT_SYSUSERS: Lint = Lint::new_warning(
    "sysusers",
    "Check for users in /etc/passwd and groups in /etc/group...",
    check_sysusers,
);

Purpose: Validates user/group definitions Check: Ensures sysusers.d entries exist for passwd/group entries Integration: Uses bootc_sysusers crate

6. nonempty-boot Lint

// From lints.rs:745-773
static LINT_NONEMPTY_BOOT: Lint = Lint::new_warning(
    "nonempty-boot",
    "The /boot directory should be present, but empty...",
    check_boot,
);

Purpose: Warns about content in /boot directory Check: Ensures /boot is empty in container images Rationale: Kernel content should be in /usr/lib/modules

Configuration and Options

1. LintExecutionConfig

// From lints.rs:69-72
struct LintExecutionConfig {
    no_truncate: bool,
}

no_truncate: Controls output truncation (default: false, shows 5 items)

2. WarningDisposition

// From lints.rs:101-104
enum WarningDisposition {
    AllowWarnings,    // Warnings don't fail the build
    FatalWarnings,    // Warnings are treated as fatal
}

Purpose: Controls how warnings are handled Default: AllowWarnings

3. RootType

// From lints.rs:106-111
enum RootType {
    Running,     // Running system root
    Alternative, // Alternative/container root
}

Purpose: Determines which lints apply to which root types Filtering: Lints can be restricted to specific root types

Error Handling

1. LintError Type

// From lints.rs:38-67
struct LintError(String);

impl std::fmt::Display for LintError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_str(&self.0)
    }
}

Purpose: Represents lint failures Features: Custom display implementation for formatted output

2. Result Types

// From lints.rs:44
type LintResult = Result<std::result::Result<(), LintError>>;

Outer Result: Runtime errors (file system issues, etc.) Inner Result: Lint success/failure Pattern: Ok(Ok(())) = success, Ok(Err(LintError)) = lint failure

3. Error Reporting

// From lints.rs:340-356
if let Err(e) = r {
    match lint.ty {
        LintType::Fatal => {
            writeln!(output, "Failed lint: {name}: {e}")?;
            fatal += 1;
        }
        LintType::Warning => {
            writeln!(output, "Lint warning: {name}: {e}")?;
            warnings += 1;
        }
    }
}

Format: Consistent error message formatting Categorization: Separate handling for fatal vs warning errors

Performance Optimizations

1. Early Termination

// From lints.rs:300-303
if recursive_lints.is_empty() {
    return Ok(ControlFlow::Break(()));
}

Feature: Stops processing when no recursive lints remain Benefit: Avoids unnecessary filesystem traversal

2. Lint Filtering

// From lints.rs:265-275
let (mut applicable_lints, skipped_lints): (Vec<_>, Vec<_>) = LINTS.iter().partition(|lint| {
    if skip.contains(lint.name) {
        return false;
    }
    if let Some(lint_root_type) = lint.root_type {
        if lint_root_type != root_type {
            return false;
        }
    }
    true
});

Feature: Only runs applicable lints Benefit: Reduces execution time for irrelevant checks

3. Output Truncation

// From lints.rs:221-233
if config.no_truncate {
    // Show all items
} else {
    // Show limited items with count
    if rest > 0 {
        writeln!(o, "  ...and {rest} more")?;
    }
}

Feature: Configurable output length Default: 5 items per lint Benefit: Prevents overwhelming output for large issues

Testing Framework

1. Test Fixtures

// From lints.rs:788-814
fn passing_fixture() -> Result<cap_std_ext::cap_tempfile::TempDir> {
    let root = cap_std_ext::cap_tempfile::tempdir(cap_std::ambient_authority())?;
    for d in API_DIRS {
        root.create_dir(d)?;
    }
    // ... setup valid filesystem structure
    Ok(root)
}

Purpose: Creates test filesystems for lint validation Features: Both passing and failing test cases

2. Individual Lint Tests

// From lints.rs:816-828
#[test]
fn test_var_run() -> Result<()> {
    let root = &fixture()?;
    let config = &LintExecutionConfig::default();
    // Test passing case
    check_var_run(root, config).unwrap().unwrap();
    // Test failing case
    root.create_dir_all("var/run/foo")?;
    assert!(check_var_run(root, config).unwrap().is_err());
    Ok(())
}

Coverage: Each lint has dedicated tests Scenarios: Both success and failure cases

3. Integration Tests

// From lints.rs:844-889
#[test]
fn test_lint_inner() -> Result<()> {
    let root = &passing_fixture()?;
    let config = &LintExecutionConfig::default();
    let mut out = Vec::new();
    let root_type = RootType::Alternative;
    let r = lint_inner(root, root_type, config, [], &mut out).unwrap();
    // Verify results
    assert_eq!(r.passed, *ALTROOT_LINTS);
    Ok(())
}

Purpose: Tests the complete lint execution flow Validation: Verifies correct counting and categorization

Integration Points

1. OSTree Integration

  • Uses ostree_ext::bootabletree for kernel detection
  • Integrates with ostree_prepareroot for composefs validation
  • Leverages OSTree's filesystem understanding

2. Systemd Integration

  • Validates systemd API directories
  • Checks tmpfiles.d configuration
  • Validates sysusers.d entries

3. Container Runtime Integration

  • Designed for container build processes
  • Supports various root filesystem types
  • Handles container-specific issues

Future Enhancements

1. Extensibility

  • Plugin system for custom lints
  • Configuration file support
  • Custom output formats

2. Performance

  • Parallel lint execution
  • Incremental checking
  • Caching mechanisms

3. Integration

  • IDE integration
  • CI/CD pipeline optimization
  • Real-time feedback

This technical reference provides comprehensive understanding of the bootc lint system's architecture, implementation, and usage patterns.