mirror of
https://github.com/containers/bootc.git
synced 2026-02-05 15:45:53 +01:00
cli: add container lint
Add an entrypoint that basically everyone can start adding to their builds which performs some basic static analysis for known problems. Closes : #216 Co-authored-by: Joseph Marrero <jmarrero@redhat.com> Co-authored-by: Huijing Hei <hhei@redhat.com> Co-authored-by: Yasmin de Souza <ydesouza@redhat.com> Signed-off-by: Steven Presti <spresti@redhat.com> Signed-off-by: Colin Walters <walters@verbum.org>
This commit is contained in:
committed by
Colin Walters
parent
94ddb2f372
commit
858acbe5dd
23
docs/src/man/bootc-container-lint.md
Normal file
23
docs/src/man/bootc-container-lint.md
Normal file
@@ -0,0 +1,23 @@
|
||||
# NAME
|
||||
|
||||
bootc-container-lint - Perform relatively inexpensive static analysis
|
||||
checks as part of a container build
|
||||
|
||||
# SYNOPSIS
|
||||
|
||||
**bootc container lint** \[**-h**\|**\--help**\]
|
||||
|
||||
# DESCRIPTION
|
||||
|
||||
Perform relatively inexpensive static analysis checks as part of a
|
||||
container build
|
||||
|
||||
# OPTIONS
|
||||
|
||||
**-h**, **\--help**
|
||||
|
||||
: Print help
|
||||
|
||||
# VERSION
|
||||
|
||||
v0.1.11
|
||||
33
docs/src/man/bootc-container.md
Normal file
33
docs/src/man/bootc-container.md
Normal file
@@ -0,0 +1,33 @@
|
||||
# NAME
|
||||
|
||||
bootc-container - Operations which can be executed as part of a
|
||||
container build
|
||||
|
||||
# SYNOPSIS
|
||||
|
||||
**bootc container** \[**-h**\|**\--help**\] \<*subcommands*\>
|
||||
|
||||
# DESCRIPTION
|
||||
|
||||
Operations which can be executed as part of a container build
|
||||
|
||||
# OPTIONS
|
||||
|
||||
**-h**, **\--help**
|
||||
|
||||
: Print help
|
||||
|
||||
# SUBCOMMANDS
|
||||
|
||||
bootc-container-lint(8)
|
||||
|
||||
: Perform relatively inexpensive static analysis checks as part of a
|
||||
container build
|
||||
|
||||
bootc-container-help(8)
|
||||
|
||||
: Print this message or the help of the given subcommand(s)
|
||||
|
||||
# VERSION
|
||||
|
||||
v0.1.11
|
||||
@@ -62,6 +62,10 @@ bootc-install(8)
|
||||
|
||||
: Install the running container to a target
|
||||
|
||||
bootc-container(8)
|
||||
|
||||
: Operations which can be executed as part of a container build
|
||||
|
||||
bootc-help(8)
|
||||
|
||||
: Print this message or the help of the given subcommand(s)
|
||||
|
||||
@@ -16,3 +16,4 @@ FROM $base
|
||||
COPY --from=build /out/bootc.tar.zst /tmp
|
||||
COPY --from=build /build/target/dev-rootfs/ /
|
||||
RUN tar -C / --zstd -xvf /tmp/bootc.tar.zst && rm -vf /tmp/*
|
||||
RUN bootc container lint
|
||||
|
||||
@@ -19,6 +19,7 @@ use std::os::unix::process::CommandExt;
|
||||
use std::process::Command;
|
||||
|
||||
use crate::deploy::RequiredHostSpec;
|
||||
use crate::lints;
|
||||
use crate::spec::Host;
|
||||
use crate::spec::ImageReference;
|
||||
use crate::utils::sigpolicy_from_opts;
|
||||
@@ -143,6 +144,14 @@ pub(crate) struct ManOpts {
|
||||
pub(crate) directory: Utf8PathBuf,
|
||||
}
|
||||
|
||||
/// Subcommands which can be executed as part of a container build.
|
||||
#[derive(Debug, clap::Subcommand, PartialEq, Eq)]
|
||||
pub(crate) enum ContainerOpts {
|
||||
/// Perform relatively inexpensive static analysis checks as part of a container
|
||||
/// build.
|
||||
Lint,
|
||||
}
|
||||
|
||||
/// Hidden, internal only options
|
||||
#[derive(Debug, clap::Subcommand, PartialEq, Eq)]
|
||||
pub(crate) enum InternalsOpts {
|
||||
@@ -292,6 +301,9 @@ pub(crate) enum Opt {
|
||||
#[clap(subcommand)]
|
||||
#[cfg(feature = "install")]
|
||||
Install(InstallOpts),
|
||||
/// Operations which can be executed as part of a container build.
|
||||
#[clap(subcommand)]
|
||||
Container(ContainerOpts),
|
||||
/// Execute the given command in the host mount namespace
|
||||
#[cfg(feature = "install")]
|
||||
#[clap(hide = true)]
|
||||
@@ -662,6 +674,19 @@ async fn run_from_opt(opt: Opt) -> Result<()> {
|
||||
Opt::Rollback(opts) => rollback(opts).await,
|
||||
Opt::Edit(opts) => edit(opts).await,
|
||||
Opt::UsrOverlay => usroverlay().await,
|
||||
Opt::Container(opts) => match opts {
|
||||
ContainerOpts::Lint => {
|
||||
if !ostree_ext::container_utils::is_ostree_container()? {
|
||||
anyhow::bail!(
|
||||
"Not in a ostree container, this command only verifies ostree containers."
|
||||
);
|
||||
}
|
||||
|
||||
let root = cap_std::fs::Dir::open_ambient_dir("/", cap_std::ambient_authority())?;
|
||||
lints::lint(&root)?;
|
||||
Ok(())
|
||||
}
|
||||
},
|
||||
#[cfg(feature = "install")]
|
||||
Opt::Install(opts) => match opts {
|
||||
InstallOpts::ToDisk(opts) => crate::install::install_to_disk(opts).await,
|
||||
|
||||
@@ -21,6 +21,7 @@ pub mod cli;
|
||||
pub(crate) mod deploy;
|
||||
pub(crate) mod generator;
|
||||
pub(crate) mod journal;
|
||||
mod lints;
|
||||
mod lsm;
|
||||
pub(crate) mod metadata;
|
||||
mod reboot;
|
||||
|
||||
72
lib/src/lints.rs
Normal file
72
lib/src/lints.rs
Normal file
@@ -0,0 +1,72 @@
|
||||
//! # Implementation of container build lints
|
||||
//!
|
||||
//! This module implements `bootc container lint`.
|
||||
|
||||
use anyhow::Result;
|
||||
use cap_std::fs::Dir;
|
||||
use cap_std_ext::cap_std;
|
||||
use cap_std_ext::dirext::CapStdExtDirExt as _;
|
||||
use fn_error_context::context;
|
||||
|
||||
/// check for the existence of the /var/run directory
|
||||
/// if it exists we need to check that it links to /run if not error
|
||||
/// if it does not exist error.
|
||||
#[context("Linting")]
|
||||
pub(crate) fn lint(root: &Dir) -> Result<()> {
|
||||
let lints = [check_var_run, check_kernel];
|
||||
for lint in lints {
|
||||
lint(&root)?;
|
||||
}
|
||||
println!("Checks passed: {}", lints.len());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn check_var_run(root: &Dir) -> Result<()> {
|
||||
if let Some(meta) = root.symlink_metadata_optional("var/run")? {
|
||||
if !meta.is_symlink() {
|
||||
anyhow::bail!("Not a symlink: var/run");
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn check_kernel(root: &Dir) -> Result<()> {
|
||||
let result = ostree_ext::bootabletree::find_kernel_dir_fs(&root)?;
|
||||
tracing::debug!("Found kernel: {:?}", result);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn fixture() -> Result<cap_std_ext::cap_tempfile::TempDir> {
|
||||
let tempdir = cap_std_ext::cap_tempfile::tempdir(cap_std::ambient_authority())?;
|
||||
Ok(tempdir)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_var_run() -> Result<()> {
|
||||
let root = &fixture()?;
|
||||
// This one should pass
|
||||
check_var_run(root).unwrap();
|
||||
root.create_dir_all("var/run/foo")?;
|
||||
assert!(check_var_run(root).is_err());
|
||||
root.remove_dir_all("var/run")?;
|
||||
// Now we should pass again
|
||||
check_var_run(root).unwrap();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_kernel_lint() -> Result<()> {
|
||||
let root = &fixture()?;
|
||||
// This one should pass
|
||||
check_kernel(root).unwrap();
|
||||
root.create_dir_all("usr/lib/modules/5.7.2")?;
|
||||
root.write("usr/lib/modules/5.7.2/vmlinuz", "old vmlinuz")?;
|
||||
root.create_dir_all("usr/lib/modules/6.3.1")?;
|
||||
root.write("usr/lib/modules/6.3.1/vmlinuz", "new vmlinuz")?;
|
||||
assert!(check_kernel(root).is_err());
|
||||
root.remove_dir_all("usr/lib/modules/5.7.2")?;
|
||||
// Now we should pass again
|
||||
check_kernel(root).unwrap();
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user