From 4ef6957f889b04f2bb1f3e36ddf49b8526e8fc08 Mon Sep 17 00:00:00 2001 From: Raito Bezarius Date: Mon, 24 Apr 2023 23:57:47 +0200 Subject: [PATCH] feat: enable synthesis support Bootspec has a mechanism called synthesis where you can synthesize bootspecs if they are not present based on the generation link only. This is useful for "vanilla bootspec" which does not contain any extensions, as this is what we do right now. If we need extensions, we can also implement our synthesis mechanism on the top of it. Enabling synthesis gives us the superpower to support non-bootspec users. :-) --- nix/tests/lanzaboote.nix | 12 ++++++++++++ rust/tool/src/generation.rs | 13 +++++++++---- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/nix/tests/lanzaboote.nix b/nix/tests/lanzaboote.nix index 94b5afb3..aa340875 100644 --- a/nix/tests/lanzaboote.nix +++ b/nix/tests/lanzaboote.nix @@ -239,6 +239,18 @@ in ''; }; + # We test if we can install Lanzaboote without Bootspec support. + synthesis = mkSecureBootTest { + name = "lanzaboote-synthesis"; + machine = { lib, ... }: { + boot.bootspec.enable = lib.mkForce false; + }; + testScript = '' + machine.start() + assert "Secure Boot: enabled (user)" in machine.succeed("bootctl status") + ''; + }; + systemd-boot-loader-config = mkSecureBootTest { name = "lanzaboote-systemd-boot-loader-config"; machine = { diff --git a/rust/tool/src/generation.rs b/rust/tool/src/generation.rs index db0b9d5a..47ef0bc2 100644 --- a/rust/tool/src/generation.rs +++ b/rust/tool/src/generation.rs @@ -42,10 +42,15 @@ pub struct Generation { impl Generation { pub fn from_link(link: &GenerationLink) -> Result { let bootspec_path = link.path.join("boot.json"); - let boot_json: BootJson = serde_json::from_slice( - &fs::read(bootspec_path).context("Failed to read bootspec file")?, - ) - .context("Failed to parse bootspec json")?; + let boot_json: BootJson = fs::read(bootspec_path) + .context("Failed to read bootspec file") + .and_then(|raw| serde_json::from_slice(&raw).context("Failed to read bootspec JSON")) + // TODO: this should be much easier, add a From for BootspecGeneration + // this should enable us to do `into()` on the Result + // anyhow compatibility of bootspec would be nice too. + .or_else(|_err| BootJson::synthesize_latest(&link.path) + .map_err(|err| anyhow!(err)) + .context("Failed to read a bootspec (missing bootspec?) and failed to synthesize a valid replacement bootspec."))?; // TODO: replace me when https://github.com/DeterminateSystems/bootspec/pull/109 lands. let bootspec: BootSpec = match boot_json.generation {