Skip to content

Commit 7d9a160

Browse files
committed
lints: Check base image content
This is mainly a sanity check for people building custom base images. But it also unit tests our own reference content. Signed-off-by: Colin Walters <[email protected]>
1 parent 1ba69d1 commit 7d9a160

File tree

1 file changed

+87
-1
lines changed

1 file changed

+87
-1
lines changed

lib/src/lints.rs

Lines changed: 87 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,19 @@
33
//! This module implements `bootc container lint`.
44
55
use std::env::consts::ARCH;
6+
use std::os::unix::ffi::OsStrExt;
67

7-
use anyhow::{bail, ensure, Result};
8+
use anyhow::{bail, ensure, Context, Result};
89
use cap_std::fs::Dir;
910
use cap_std_ext::cap_std;
1011
use cap_std_ext::dirext::CapStdExtDirExt as _;
1112
use fn_error_context::context;
1213

1314
use crate::utils::openat2_with_retry;
1415

16+
/// Reference to embedded default baseimage content that should exist.
17+
const BASEIMAGE_REF: &str = "usr/share/doc/bootc/baseimage/base";
18+
1519
/// check for the existence of the /var/run directory
1620
/// if it exists we need to check that it links to /run if not error
1721
/// if it does not exist error.
@@ -23,6 +27,7 @@ pub(crate) fn lint(root: &Dir) -> Result<()> {
2327
check_parse_kargs,
2428
check_usretc,
2529
check_utf8,
30+
check_baseimage_root,
2631
];
2732
for lint in lints {
2833
lint(&root)?;
@@ -116,6 +121,57 @@ fn check_utf8(dir: &Dir) -> Result<()> {
116121
Ok(())
117122
}
118123

124+
/// Check for a few files and directories we expect in the base image.
125+
fn check_baseimage_root_norecurse(dir: &Dir) -> Result<()> {
126+
// Check /sysroot
127+
let meta = dir.symlink_metadata_optional("sysroot")?;
128+
match meta {
129+
Some(meta) if !meta.is_dir() => {
130+
anyhow::bail!("Expected a directory for /sysroot")
131+
}
132+
None => anyhow::bail!("Missing /sysroot"),
133+
_ => {}
134+
}
135+
136+
// Check /ostree -> sysroot/ostree
137+
let Some(meta) = dir.symlink_metadata_optional("ostree")? else {
138+
anyhow::bail!("Missing ostree -> sysroot/ostree link")
139+
};
140+
if !meta.is_symlink() {
141+
anyhow::bail!("/ostree should be a symlink");
142+
}
143+
let link = dir.read_link_contents("ostree")?;
144+
let expected = "sysroot/ostree";
145+
if link.as_os_str().as_bytes() != expected.as_bytes() {
146+
anyhow::bail!("Expected /ostree -> {expected}, not {link:?}");
147+
}
148+
149+
// Check the prepare-root config
150+
let prepareroot_path = "usr/lib/ostree/prepare-root.conf";
151+
let config_data = dir
152+
.read_to_string(prepareroot_path)
153+
.context(prepareroot_path)?;
154+
let config = ostree_ext::glib::KeyFile::new();
155+
config.load_from_data(&config_data, ostree_ext::glib::KeyFileFlags::empty())?;
156+
157+
if !ostree_ext::ostree_prepareroot::overlayfs_enabled_in_config(&config)? {
158+
anyhow::bail!("{prepareroot_path} does not have composefs enabled")
159+
}
160+
161+
Ok(())
162+
}
163+
164+
/// Check ostree-related base image content.
165+
fn check_baseimage_root(dir: &Dir) -> Result<()> {
166+
check_baseimage_root_norecurse(dir)?;
167+
// If we have our own documentation with the expected root contents
168+
// embedded, then check that too! Mostly just because recursion is fun.
169+
if let Some(dir) = dir.open_dir_optional(BASEIMAGE_REF)? {
170+
check_baseimage_root_norecurse(&dir)?;
171+
}
172+
Ok(())
173+
}
174+
119175
#[cfg(test)]
120176
mod tests {
121177
use super::*;
@@ -260,4 +316,34 @@ mod tests {
260316
root.remove_file(badfile).unwrap(); // Get rid of the problem
261317
check_utf8(root).unwrap(); // Check it
262318
}
319+
320+
#[test]
321+
fn test_baseimage_root() -> Result<()> {
322+
use bootc_utils::CommandRunExt;
323+
use cap_std_ext::cmdext::CapStdExtCommandExt;
324+
use std::path::Path;
325+
326+
let td = fixture()?;
327+
328+
// An empty root should fail our test
329+
assert!(check_baseimage_root(&td).is_err());
330+
331+
// Copy our reference base image content from the source dir
332+
let manifest = std::env::var_os("CARGO_MANIFEST_PATH").unwrap();
333+
let srcdir = Path::new(&manifest)
334+
.parent()
335+
.unwrap()
336+
.join("../baseimage/base");
337+
for ent in std::fs::read_dir(srcdir)? {
338+
let ent = ent?;
339+
std::process::Command::new("cp")
340+
.cwd_dir(td.try_clone()?)
341+
.arg("-pr")
342+
.arg(ent.path())
343+
.arg(".")
344+
.run()?;
345+
}
346+
check_baseimage_root(&td).unwrap();
347+
Ok(())
348+
}
263349
}

0 commit comments

Comments
 (0)