summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/build.rs1
-rw-r--r--src/initramfs.rs20
-rw-r--r--tests/build.rs49
3 files changed, 70 insertions, 0 deletions
diff --git a/src/build.rs b/src/build.rs
index 8b6ebb0..cb6a436 100644
--- a/src/build.rs
+++ b/src/build.rs
@@ -110,6 +110,7 @@ impl<I: PackageInstaller, B: InitramfsBuilder> BuildExecutor<I, B> {
Err(error) => return Self::fail_and_remove_workspace(workspace, error),
};
let result = (|| {
+ initrd.verify_in_rootfs(&rootfs)?;
std::fs::create_dir_all(parent)
.with_context(|| format!("create artifact directory {}", parent.display()))?;
self.tar_writer.write(&rootfs, artifact)?;
diff --git a/src/initramfs.rs b/src/initramfs.rs
index a108b85..4ece24c 100644
--- a/src/initramfs.rs
+++ b/src/initramfs.rs
@@ -249,4 +249,24 @@ impl InitramfsResult {
pub fn sha256(&self) -> &str {
&self.sha256
}
+
+ /// Ensure the initrd recorded by the platform adapter still exists in the
+ /// assembled rootfs and has not changed before native packaging begins.
+ pub fn verify_in_rootfs(&self, rootfs: &Path) -> Result<()> {
+ let contents = fs::read(rootfs.join(&self.initrd_path)).with_context(|| {
+ format!(
+ "read generated initrd {}",
+ rootfs.join(&self.initrd_path).display()
+ )
+ })?;
+ let digest = format!("{:x}", Sha256::digest(contents));
+ if digest != self.sha256 {
+ bail!(
+ "generated initrd digest changed for {}: expected {}, found {digest}",
+ self.initrd_path.display(),
+ self.sha256
+ );
+ }
+ Ok(())
+ }
}
diff --git a/tests/build.rs b/tests/build.rs
index 2fcd1bf..c9cc59f 100644
--- a/tests/build.rs
+++ b/tests/build.rs
@@ -73,6 +73,20 @@ impl PackageInstaller for ArchiveFailingInstaller {
}
}
+struct MutatingInitrdBuilder;
+
+impl InitramfsBuilder for MutatingInitrdBuilder {
+ fn build(&mut self, request: &InitramfsRequest) -> anyhow::Result<InitramfsResult> {
+ let initrd = request
+ .rootfs()
+ .join(format!("boot/initrd-{}.img", request.kernel().as_str()));
+ fs::write(&initrd, "primary initrd")?;
+ let result = InitramfsResult::from_rootfs(request.rootfs(), request.kernel())?;
+ fs::write(initrd, "mutated initrd")?;
+ Ok(result)
+ }
+}
+
#[derive(Default)]
struct FixtureInitramfsBuilder;
@@ -355,3 +369,38 @@ fn removes_the_new_workspace_and_partial_artifact_when_packaging_fails() {
"failed packaging must not leave a companion manifest"
);
}
+
+#[test]
+fn removes_the_new_workspace_and_artifact_when_manifest_collection_fails() {
+ let fixture = tempdir().expect("fixture directory");
+ let spec = ImageSpec::load(std::path::Path::new("profiles/alt-controller.toml"))
+ .expect("load controller spec");
+ let plan = BuildPlan::compile(spec).expect("compile build plan");
+ let mut executor = BuildExecutor::new(FixtureInstaller::default(), MutatingInitrdBuilder);
+ let workspace = fixture.path().join("work");
+ let artifact = fixture.path().join("out/image.tar");
+
+ let error = executor
+ .execute(&plan, &workspace, "profiles/apt.conf", &artifact)
+ .expect_err("mutated initrd must fail before packaging");
+
+ assert!(
+ error
+ .to_string()
+ .contains("generated initrd digest changed")
+ );
+ assert!(
+ !workspace.exists(),
+ "failed build must not leave a workspace"
+ );
+ assert!(
+ !artifact.exists(),
+ "failed manifest collection must not leave an artifact"
+ );
+ assert!(
+ !ArtifactManifest::path_beside(&artifact)
+ .expect("manifest path")
+ .exists(),
+ "failed manifest collection must not leave a companion manifest"
+ );
+}