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

550 lines
13 KiB
Markdown

# 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
```rust
// 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
```rust
// 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
```rust
// 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
```rust
// 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
```rust
// 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
```rust
// 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
```rust
// 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
```rust
// 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
```rust
// 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
```rust
// 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)
```rust
// 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
```rust
// 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
```rust
// 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
```rust
// 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
```rust
// 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
```rust
// 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
```rust
// 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
```rust
// 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
```rust
// 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
```rust
// From lints.rs:69-72
struct LintExecutionConfig {
no_truncate: bool,
}
```
**no_truncate**: Controls output truncation (default: false, shows 5 items)
### 2. WarningDisposition
```rust
// 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
```rust
// 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
```rust
// 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
```rust
// 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
```rust
// 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
```rust
// 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
```rust
// 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
```rust
// 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
```rust
// 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
```rust
// 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
```rust
// 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.