- 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
550 lines
13 KiB
Markdown
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.
|