From b44c435bed126255dd7daf92507a6113d8edd5f2 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Wed, 9 Sep 2026 18:42:14 +0200 Subject: [PATCH 1/2] Add configuration file support Implement nullboot.conf and nullboot.conf.d - yaml files. At this point parse only kernel-priority (similar to GRUB_FLAVOUR_ORDER in grub). Assisted-by: LLM --- efibootmgr/config.go | 108 ++++++++++++++++++++++++++++++++++++ efibootmgr/config_test.go | 114 ++++++++++++++++++++++++++++++++++++++ go.mod | 2 +- 3 files changed, 223 insertions(+), 1 deletion(-) create mode 100644 efibootmgr/config.go create mode 100644 efibootmgr/config_test.go diff --git a/efibootmgr/config.go b/efibootmgr/config.go new file mode 100644 index 0000000..ece8e90 --- /dev/null +++ b/efibootmgr/config.go @@ -0,0 +1,108 @@ +// This file is part of nullboot +// Copyright 2026 Canonical Ltd. +// SPDX-License-Identifier: GPL-3.0-only + +package efibootmgr + +import ( + "fmt" + "io" + "os" + "path" + "regexp" + "strings" + + "gopkg.in/yaml.v2" +) + +// DefaultConfigPath is the default nullboot configuration file. +const DefaultConfigPath = "/etc/nullboot.conf" + +// Configuration describes kernel boot priorities, like +// GRUB_FLAVOUR_ORDER (see debian/grub-sort-version). Each flavour is +// compiled to [\s\S]*-(\s*\d*)$ and matched against the +// kernel ABI. Higher priority flavours sort first; unlisted flavours +// have priority 0. +type Configuration struct { + priorities map[int][]*regexp.Regexp + + KernelPriority map[string]int `yaml:"kernel-priority"` +} + +// ReadConfig reads YAML configuration from configPath and any +// drop-ins in configPath.d, e.g.: +// +// kernel-priority: +// fips: 1000 +// azure-fde: 100 +// +// All files are optional; drop-ins merge kernel-priority keys, +// overriding earlier files. +func ReadConfig(configPath string) (*Configuration, error) { + config := &Configuration{KernelPriority: map[string]int{}} + + paths := []string{configPath} + entries, err := appFs.ReadDir(configPath + ".d") + if err != nil && !os.IsNotExist(err) { + return nil, fmt.Errorf("cannot read configuration drop-in directory: %w", err) + } + for _, e := range entries { + if !e.IsDir() && strings.HasSuffix(e.Name(), ".conf") { + paths = append(paths, path.Join(configPath+".d", e.Name())) + } + } + + for _, p := range paths { + if err := config.readFile(p); err != nil { + return nil, err + } + } + + config.priorities = map[int][]*regexp.Regexp{} + for flavour, priority := range config.KernelPriority { + re, err := regexp.Compile(`[\s\S]*-` + regexp.QuoteMeta(flavour) + `(\s*\d*)$`) + if err != nil { + return nil, fmt.Errorf("invalid flavour %q: %w", flavour, err) + } + config.priorities[priority] = append(config.priorities[priority], re) + } + return config, nil +} + +// readFile merges a single YAML configuration file into c. Missing +// files are ignored; yaml.v2 merges map keys into existing maps. +func (c *Configuration) readFile(configPath string) error { + file, err := appFs.Open(configPath) + if err != nil { + if os.IsNotExist(err) { + return nil + } + return fmt.Errorf("cannot open configuration file %s: %w", configPath, err) + } + defer func() { _ = file.Close() }() + + data, err := io.ReadAll(file) + if err != nil { + return fmt.Errorf("cannot read configuration file %s: %w", configPath, err) + } + if err := yaml.Unmarshal(data, c); err != nil { + return fmt.Errorf("cannot parse configuration file %s: %w", configPath, err) + } + return nil +} + +// weight returns the priority of the flavour matching abi, or 0 if +// none matches. +func (c *Configuration) weight(abi string) int { + if c == nil { + return 0 + } + for priority, res := range c.priorities { + for _, re := range res { + if re.MatchString(abi) { + return priority + } + } + } + return 0 +} diff --git a/efibootmgr/config_test.go b/efibootmgr/config_test.go new file mode 100644 index 0000000..7a6deff --- /dev/null +++ b/efibootmgr/config_test.go @@ -0,0 +1,114 @@ +// This file is part of nullboot +// Copyright 2026 Canonical Ltd. +// SPDX-License-Identifier: GPL-3.0-only + +package efibootmgr + +import ( + "reflect" + "testing" + + "github.com/spf13/afero" +) + +func TestReadConfig(t *testing.T) { + memFs := afero.NewMemMapFs() + appFs = MapFS{memFs} + + config, err := ReadConfig("/etc/nullboot.conf") + if err != nil { + t.Fatalf("unexpected error reading missing configuration: %v", err) + } + if len(config.KernelPriority) != 0 { + t.Errorf("expected no priorities for missing file, got %v", config.KernelPriority) + } + if got := config.weight("6.8.0-52-fips"); got != 0 { + t.Errorf("expected weight 0 without configuration, got %d", got) + } + + if err := afero.WriteFile(memFs, "/etc/nullboot.conf", []byte(`# Prefer FIPS kernels over Azure FDE kernels +kernel-priority: + fips: 1000 + azure-fde: 100 +`), 0644); err != nil { + t.Fatal(err) + } + + config, err = ReadConfig("/etc/nullboot.conf") + if err != nil { + t.Fatalf("unexpected error reading configuration: %v", err) + } + want := map[string]int{"fips": 1000, "azure-fde": 100} + if !reflect.DeepEqual(config.KernelPriority, want) { + t.Errorf("unexpected kernel priorities: %v", config.KernelPriority) + } +} + +func TestConfigWeight(t *testing.T) { + memFs := afero.NewMemMapFs() + appFs = MapFS{memFs} + if err := afero.WriteFile(memFs, "/etc/nullboot.conf", []byte(`kernel-priority: + fips: 1000 + azure-fde: 100 +`), 0644); err != nil { + t.Fatal(err) + } + + config, err := ReadConfig("/etc/nullboot.conf") + if err != nil { + t.Fatalf("unexpected error reading configuration: %v", err) + } + + tests := []struct { + abi string + want int + }{ + {"6.8.0-52-fips", 1000}, + {"6.8.0-52-azure-fde", 100}, // multi-dash flavour + {"6.8.0-1003-azure-fde", 100}, + {"6.8.0-52-generic", 0}, // unlisted flavour has no priority + {"6.8.0-52-lowlatency", 0}, + } + for _, tt := range tests { + if got := config.weight(tt.abi); got != tt.want { + t.Errorf("weight(%q): expected %d, got %d", tt.abi, tt.want, got) + } + } +} + +func TestReadConfigDropIns(t *testing.T) { + memFs := afero.NewMemMapFs() + appFs = MapFS{memFs} + + for name, content := range map[string]string{ + "/etc/nullboot.conf": "kernel-priority: {fips: 1000, azure-fde: 100}\n", + "/etc/nullboot.conf.d/10-override.conf": "kernel-priority: {fips: 500}\n", + "/etc/nullboot.conf.d/20-lowlatency.conf": "kernel-priority: {lowlatency: 10}\n", + "/etc/nullboot.conf.d/ignored.txt": "kernel-priority: {generic: 1}\n", + } { + if err := afero.WriteFile(memFs, name, []byte(content), 0644); err != nil { + t.Fatal(err) + } + } + + config, err := ReadConfig("/etc/nullboot.conf") + if err != nil { + t.Fatalf("unexpected error reading configuration: %v", err) + } + want := map[string]int{"fips": 500, "azure-fde": 100, "lowlatency": 10} + if !reflect.DeepEqual(config.KernelPriority, want) { + t.Errorf("expected kernel priorities %v, got %v", want, config.KernelPriority) + } +} + +func TestReadConfigInvalidYAML(t *testing.T) { + memFs := afero.NewMemMapFs() + appFs = MapFS{memFs} + if err := afero.WriteFile(memFs, "/etc/nullboot.conf", []byte("kernel-priority: [not a map"), 0644); err != nil { + t.Fatal(err) + } + + if _, err := ReadConfig("/etc/nullboot.conf"); err == nil { + t.Error("expected error for malformed YAML, got nil") + } +} diff --git a/go.mod b/go.mod index 729b5bc..566a745 100644 --- a/go.mod +++ b/go.mod @@ -12,6 +12,7 @@ require ( golang.org/x/sys v0.38.0 golang.org/x/text v0.34.0 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c + gopkg.in/yaml.v2 v2.4.0 ) require ( @@ -31,6 +32,5 @@ require ( golang.org/x/net v0.47.0 // indirect golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect maze.io/x/crypto v0.0.0-20190131090603-9b94c9afe066 // indirect ) From 82ad415ae74b6d0757dc26780d014738f3790a70 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Wed, 9 Sep 2026 18:42:23 +0200 Subject: [PATCH 2/2] Respect kernel-priority set in nullboot.conf Wrap version.Version in a WeightedVersion that carries a priority computed from the kernel-priority configuration. Kernels with higher priority sort first; equal priorities fall back to version order. Assisted-by: LLM --- cmd/nullbootctl/main.go | 11 ++- efibootmgr/kernel.go | 43 +++++++++--- efibootmgr/kernel_test.go | 140 ++++++++++++++++++++++++++++++++++---- efibootmgr/reseal_test.go | 4 +- 4 files changed, 174 insertions(+), 24 deletions(-) diff --git a/cmd/nullbootctl/main.go b/cmd/nullbootctl/main.go index 80342ce..c5054ed 100644 --- a/cmd/nullbootctl/main.go +++ b/cmd/nullbootctl/main.go @@ -74,7 +74,16 @@ func main() { } } - km, err := efibootmgr.NewKernelManager(esp, kernelSourceDir, vendor, maybeBm) + config, err := efibootmgr.ReadConfig(efibootmgr.DefaultConfigPath) + if err != nil { + log.Print(err) + os.Exit(1) + } + if len(config.KernelPriority) > 0 { + log.Println("using kernel priorities:", config.KernelPriority) + } + + km, err := efibootmgr.NewKernelManager(esp, kernelSourceDir, vendor, maybeBm, config) if err != nil { log.Print(err) os.Exit(1) diff --git a/efibootmgr/kernel.go b/efibootmgr/kernel.go index 61e85fd..0fcc440 100644 --- a/efibootmgr/kernel.go +++ b/efibootmgr/kernel.go @@ -17,8 +17,30 @@ import ( const kernelPrefix = "kernel.efi-" +// WeightedVersion orders versions by priority first, then by +// version. A zero priority sorts like a plain version.Version. +type WeightedVersion struct { + version.Version + weight int +} + +// GreaterThan returns true if v sorts before v2: either a higher +// priority, or the same priority with a greater version. +func (v WeightedVersion) GreaterThan(v2 WeightedVersion) bool { + if v.weight != v2.weight { + return v.weight > v2.weight + } + return v.Version.GreaterThan(v2.Version) +} + +// Equal returns true if the versions are equal; the weight derives +// from the version string, so equal versions have equal weights. +func (v WeightedVersion) Equal(v2 WeightedVersion) bool { + return v.Version.Equal(v2.Version) +} + type Kernel struct { - Version version.Version + Version WeightedVersion FilePath string } @@ -30,14 +52,16 @@ func (k *Kernel) Equals(other Kernel) bool { return k.Version.Equal(other.Version) && k.GetKernelName() == other.GetKernelName() } -func NewKernel(kernelPath string) (Kernel, error) { +// NewKernel creates a Kernel from its path. The kernel's weight is +// computed from config, which may be nil. +func NewKernel(kernelPath string, config *Configuration) (Kernel, error) { kernelName := path.Base(kernelPath) if versionStr, err := getKernelABI(kernelName); err == nil { v, err := version.NewVersion(versionStr) if err != nil { return Kernel{}, fmt.Errorf("could not parse kernel version of %s: %w", kernelName, err) } - return Kernel{v, kernelPath}, nil + return Kernel{WeightedVersion{Version: v, weight: config.weight(versionStr)}, kernelPath}, nil } return Kernel{}, fmt.Errorf("unrecognized kernel naming format: %s", kernelName) } @@ -58,17 +82,20 @@ type KernelManager struct { targetKernels []Kernel // kernels in targetDir kernelEntries []KernelEntry // boot entries filled by InstallKernels kernelOptions string // options to pass to kernel - bootManager *BootManager // The EFI boot manager + bootManager *BootManager // The EFI boot manager + config *Configuration // nullboot configuration } -// NewKernelManager returns a new kernel manager managing kernels in the host system -func NewKernelManager(esp, sourceDir, vendor string, bootManager *BootManager) (*KernelManager, error) { +// NewKernelManager returns a new kernel manager managing kernels in the +// host system. config may be nil. +func NewKernelManager(esp, sourceDir, vendor string, bootManager *BootManager, config *Configuration) (*KernelManager, error) { var km KernelManager var err error km.sourceDir = sourceDir km.targetDir = path.Join(esp, "EFI", vendor) km.bootManager = bootManager + km.config = config if file, err := appFs.Open("/etc/kernel/cmdline"); err == nil { defer file.Close() @@ -103,13 +130,13 @@ func (km *KernelManager) readKernels(dir string) ([]Kernel, error) { if !hasKernelPrefix(e.Name()) { continue } - kernel, err := NewKernel(path.Join(dir, e.Name())) + kernel, err := NewKernel(path.Join(dir, e.Name()), km.config) if err != nil { return []Kernel{}, err } kernels = append(kernels, kernel) } - // Sort descending + // Sort descending by flavour preference group, then by version sort.Slice(kernels, func(i, j int) bool { a := kernels[i].Version b := kernels[j].Version diff --git a/efibootmgr/kernel_test.go b/efibootmgr/kernel_test.go index 944acb2..58d13c6 100644 --- a/efibootmgr/kernel_test.go +++ b/efibootmgr/kernel_test.go @@ -45,7 +45,7 @@ func TestKernelManagerNewAndInstallKernels(t *testing.T) { kernelNames := []string{"kernel.efi-1.0-12-generic", "kernel.efi-1.0-1-generic"} sourceKernels := []Kernel{} for _, kernelName := range kernelNames { - k, err := NewKernel(path.Join(sourceDir, kernelName)) + k, err := NewKernel(path.Join(sourceDir, kernelName), nil) if err != nil { t.Fatalf("Unable to create Kernel %s: %v", kernelName, err) } @@ -68,7 +68,7 @@ func TestKernelManagerNewAndInstallKernels(t *testing.T) { t.Fatal(err) } - km, err := NewKernelManager("/boot/efi", sourceDir, "ubuntu", &bm) + km, err := NewKernelManager("/boot/efi", sourceDir, "ubuntu", &bm, nil) if err != nil { t.Fatalf("Could not create kernel manager: %v", err) } @@ -155,7 +155,10 @@ func TestKernelManager_noCmdLine(t *testing.T) { t.Fatal(err) } - km, err := NewKernelManager("/boot/efi", "/usr/lib/linux", "ubuntu", &bm) + km, err := NewKernelManager("/boot/efi", "/usr/lib/linux", "ubuntu", &bm, nil) + if err != nil { + t.Fatalf("Could not create kernel manager: %v", err) + } if err := km.InstallKernels(); err != nil { t.Errorf("Could not install kernels: %v", err) } @@ -221,7 +224,7 @@ func TestKernelManagerRemoveObsoleteKernels(t *testing.T) { if err != nil { t.Fatalf("Could not create boot manager: %v", err) } - km, err := NewKernelManager("/boot/efi", "/usr/lib/linux", "ubuntu", &bm) + km, err := NewKernelManager("/boot/efi", "/usr/lib/linux", "ubuntu", &bm, nil) if err != nil { t.Fatalf("Could not create kernel manager: %v", err) } @@ -281,7 +284,7 @@ func TestKernelManagerRegisterNewKernelEFIs(t *testing.T) { preGenNum := 2 for i := range preGenNum { kernelName := kernelNames[i] - kernel, err := NewKernel(kernelName) + kernel, err := NewKernel(kernelName, nil) if err != nil { t.Fatalf("error creating Kernel type from %s", kernelName) } @@ -308,7 +311,7 @@ func TestKernelManagerRegisterNewKernelEFIs(t *testing.T) { expectedBootEntryVariables := []BootEntryVariable{} for kNameIdx, bootNumber := range expectedBootNumber { kName := kernelNames[kNameIdx] - k, err := NewKernel(kName) + k, err := NewKernel(kName, nil) if err != nil { t.Fatalf("unable to create kernel for %s: %v", kName, err) } @@ -320,7 +323,7 @@ func TestKernelManagerRegisterNewKernelEFIs(t *testing.T) { expectedBootEntryVariables = append(expectedBootEntryVariables, kEntryVar) } - km, err := NewKernelManager(esp, sourceDir, "ubuntu", &bm) + km, err := NewKernelManager(esp, sourceDir, "ubuntu", &bm, nil) if err != nil { t.Fatalf("unable to create KernelManager: %v", err) } @@ -384,7 +387,7 @@ func TestKernelManagerSetLatestKernelToBootNext(t *testing.T) { afero.WriteFile(memFs, kernelTargetPath, []byte(kernelName), 0644) // NOTE: create entries this way in the test so boot number can be controlled - kernel, err := NewKernel(kernelName) + kernel, err := NewKernel(kernelName, nil) if err != nil { t.Fatalf("error creating Kernel type from %s", kernelName) } @@ -397,9 +400,14 @@ func TestKernelManagerSetLatestKernelToBootNext(t *testing.T) { } // This reads the kernel files in version order - km, err := NewKernelManager("/boot/efi", sourceDir, "ubuntu", &bm) + km, err := NewKernelManager("/boot/efi", sourceDir, "ubuntu", &bm, nil) + if err != nil { + t.Fatalf("Could not create kernel manager: %v", err) + } // Populate km.bootEntries (also in version order) - km.InstallKernels() + if err := km.InstallKernels(); err != nil { + t.Fatalf("Could not install kernels: %v", err) + } if err := km.SetLatestKernelToBootNext(); err != nil { t.Fatalf("unexpected error setting latest kernel to BootNext: %v", err) @@ -481,7 +489,7 @@ func TestKernelManagerIsCurrentBootLatest(t *testing.T) { var latestKernelEntry *KernelEntry for bootNum, version := range tt.kernelVersionMap { kernelName := fmt.Sprintf("kernel.efi-%s", version) - kernel, err := NewKernel(kernelName) + kernel, err := NewKernel(kernelName, nil) if err != nil { t.Fatalf("error creating Kernel type from %s", kernelName) } @@ -523,6 +531,112 @@ func TestKernelManagerIsCurrentBootLatest(t *testing.T) { } } +func TestKernelManagerKernelPriority(t *testing.T) { + appArchitecture = "x64" + memFs := afero.NewMemMapFs() + appFs = MapFS{memFs} + + sourceDir := "/usr/lib/linux" + kernelNames := []string{ + "kernel.efi-6.8.0-52-generic", + "kernel.efi-6.8.0-51-fips", + "kernel.efi-6.8.0-1003-azure-fde", + "kernel.efi-6.8.0-52-fips", + } + for _, kernelName := range kernelNames { + if err := afero.WriteFile(memFs, path.Join(sourceDir, kernelName), []byte(kernelName), 0644); err != nil { + t.Fatal(err) + } + } + if err := afero.WriteFile(memFs, "/boot/efi/EFI/ubuntu/", []byte(""), 0644); err != nil { + t.Fatal(err) + } + if err := afero.WriteFile(memFs, "/etc/kernel/cmdline", []byte("root=magic"), 0644); err != nil { + t.Fatal(err) + } + if err := afero.WriteFile(memFs, "/etc/nullboot.conf", []byte(`kernel-priority: + fips: 1000 + azure-fde: 100 +`), 0644); err != nil { + t.Fatal(err) + } + + config, err := ReadConfig("/etc/nullboot.conf") + if err != nil { + t.Fatalf("unexpected error reading configuration: %v", err) + } + + km, err := NewKernelManager("/boot/efi", sourceDir, "ubuntu", nil, config) + if err != nil { + t.Fatalf("Could not create kernel manager: %v", err) + } + + // Priorities sort before versions: fips (1000) kernels first by + // version, then azure-fde (100), then generic (unlisted, 0). + wantOrder := []string{ + "kernel.efi-6.8.0-52-fips", + "kernel.efi-6.8.0-51-fips", + "kernel.efi-6.8.0-1003-azure-fde", + "kernel.efi-6.8.0-52-generic", + } + if len(km.sourceKernels) != len(wantOrder) { + t.Fatalf("expected %d kernels, got %d", len(wantOrder), len(km.sourceKernels)) + } + for i, want := range wantOrder { + if got := km.sourceKernels[i].GetKernelName(); got != want { + t.Errorf("kernel %d: expected %s, got %s", i, want, got) + } + } + + if err := km.InstallKernels(); err != nil { + t.Errorf("Could not install kernels: %v", err) + } + latest, err := km.GetLatestKernelEntry() + if err != nil { + t.Fatalf("Could not get latest kernel entry: %v", err) + } + // The latest kernel is the newest one of the highest-priority + // flavour, even though a newer generic kernel exists. + if got := latest.kernel.GetKernelName(); got != "kernel.efi-6.8.0-52-fips" { + t.Errorf("expected latest kernel to be kernel.efi-6.8.0-52-fips, got %s", got) + } +} + +func TestKernelManagerNoConfigurationVersionOrder(t *testing.T) { + appArchitecture = "x64" + memFs := afero.NewMemMapFs() + appFs = MapFS{memFs} + + sourceDir := "/usr/lib/linux" + kernelNames := []string{ + "kernel.efi-6.8.0-51-fips", + "kernel.efi-6.8.0-52-generic", + } + for _, kernelName := range kernelNames { + if err := afero.WriteFile(memFs, path.Join(sourceDir, kernelName), []byte(kernelName), 0644); err != nil { + t.Fatal(err) + } + } + if err := afero.WriteFile(memFs, "/boot/efi/EFI/ubuntu/", []byte(""), 0644); err != nil { + t.Fatal(err) + } + + // No configuration: sorting is purely by version + km, err := NewKernelManager("/boot/efi", sourceDir, "ubuntu", nil, nil) + if err != nil { + t.Fatalf("Could not create kernel manager: %v", err) + } + wantOrder := []string{ + "kernel.efi-6.8.0-52-generic", + "kernel.efi-6.8.0-51-fips", + } + for i, want := range wantOrder { + if got := km.sourceKernels[i].GetKernelName(); got != want { + t.Errorf("kernel %d: expected %s, got %s", i, want, got) + } + } +} + func TestKernelManagerGetLatestKernelEntry(t *testing.T) { expectedLatestKPath := "kernel.efi-100" kernelPaths := []string{"kernel.efi-1", "kernel.efi-20", expectedLatestKPath, "kernel.efi-2"} @@ -532,7 +646,7 @@ func TestKernelManagerGetLatestKernelEntry(t *testing.T) { return NewKernelBootEntry("Ubuntu", k, "") } for _, kPath := range kernelPaths { - k, err := NewKernel(kPath) + k, err := NewKernel(kPath, nil) if err != nil { t.Fatalf("Failed to create kernel %s: %v", kPath, err) } @@ -541,7 +655,7 @@ func TestKernelManagerGetLatestKernelEntry(t *testing.T) { kernelEntries = append(kernelEntries, kEntry) } - expectedLatestK, err := NewKernel(expectedLatestKPath) + expectedLatestK, err := NewKernel(expectedLatestKPath, nil) expectedLatestEntry := genTestKernelEntry(expectedLatestK) expectedLatestKEntry := KernelEntry{expectedLatestK, expectedLatestEntry} diff --git a/efibootmgr/reseal_test.go b/efibootmgr/reseal_test.go index 30f4f33..aab3398 100644 --- a/efibootmgr/reseal_test.go +++ b/efibootmgr/reseal_test.go @@ -285,7 +285,7 @@ func (s *resealSuite) testResealKey(c *check.C, data *testResealKeyData) { bm, err := NewBootManagerForVariables(&mockvars) c.Assert(err, check.IsNil) - km, err := NewKernelManager("/boot/efi", "/usr/lib/linux", "ubuntu", &bm) + km, err := NewKernelManager("/boot/efi", "/usr/lib/linux", "ubuntu", &bm, nil) c.Assert(err, check.IsNil) c.Check(ResealKey(assets, km, "/boot/efi", "/usr/lib/nullboot/shim", "ubuntu"), check.IsNil) @@ -668,7 +668,7 @@ func (s *resealSuite) testResealKeyUnhappy(c *check.C, data *testResealKeyUnhapp bm, err := NewBootManagerForVariables(&mockvars) c.Assert(err, check.IsNil) - km, err := NewKernelManager("/boot/efi", "/usr/lib/linux", "ubuntu", &bm) + km, err := NewKernelManager("/boot/efi", "/usr/lib/linux", "ubuntu", &bm, nil) c.Assert(err, check.IsNil) return ResealKey(assets, km, "/boot/efi", "/usr/lib/nullboot/shim", "ubuntu")