From 195c903f6332b29e7950d277d8be1a448f6f94e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Budai?= Date: Thu, 28 May 2026 15:16:02 +0200 Subject: [PATCH] many: fix non-determistic manifest generation We want manifests to be generated in a deterministic way. A common source of non-determinism is Go is iterating over maps - Go actually doesn't guarantee the iteration order. Thus, when creating an array from a map, we always need to sort the map deterministically before creating the array. My research found 3 places like this in the codebase, and this commit fixes them. --- pkg/distro/generic/images.go | 6 ++++-- pkg/manifest/bootc_pxetree.go | 4 +++- pkg/manifest/build.go | 5 ++++- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/pkg/distro/generic/images.go b/pkg/distro/generic/images.go index 773552da7e..138d528abc 100644 --- a/pkg/distro/generic/images.go +++ b/pkg/distro/generic/images.go @@ -2,7 +2,9 @@ package generic import ( "fmt" + "maps" "math/rand" + "slices" "strings" "sync" @@ -242,8 +244,8 @@ func osCustomizations(t *imageType, osPackageSet rpmmd.PackageSet, options distr osc.Files = append(osc.Files, gpgKeyFiles...) } - for filename, repos := range yumRepos { - osc.YUMRepos = append(osc.YUMRepos, osbuild.NewYumReposStageOptions(filename, repos)) + for _, filename := range slices.Sorted(maps.Keys(yumRepos)) { + osc.YUMRepos = append(osc.YUMRepos, osbuild.NewYumReposStageOptions(filename, yumRepos[filename])) } if oscapConfig := c.GetOpenSCAP(); oscapConfig != nil { diff --git a/pkg/manifest/bootc_pxetree.go b/pkg/manifest/bootc_pxetree.go index 92444265ca..1186ae8228 100644 --- a/pkg/manifest/bootc_pxetree.go +++ b/pkg/manifest/bootc_pxetree.go @@ -2,6 +2,8 @@ package manifest import ( "fmt" + "maps" + "slices" "strings" "github.com/osbuild/images/internal/common" @@ -237,7 +239,7 @@ func (p *BootcPXETree) getChmodFiles() map[string]osbuild.ChmodStagePathOptions // GetTarFiles returns the list of files in the tree to be included in a tar func (p *BootcPXETree) GetTarFiles() []string { var files []string - for f := range p.getChmodFiles() { + for _, f := range slices.Sorted(maps.Keys(p.getChmodFiles())) { // Tar needs relative paths files = append(files, strings.TrimPrefix(f, "/")) } diff --git a/pkg/manifest/build.go b/pkg/manifest/build.go index 16169b9bf1..44825a64e1 100644 --- a/pkg/manifest/build.go +++ b/pkg/manifest/build.go @@ -3,6 +3,8 @@ package manifest import ( "errors" "fmt" + "maps" + "slices" "github.com/osbuild/images/pkg/container" "github.com/osbuild/images/pkg/customizations/fsnode" @@ -356,7 +358,8 @@ func (p *BuildrootFromContainer) serialize() (osbuild.Pipeline, error) { pipeline.AddStage(stage) } - for copyFilesFrom, copyFiles := range p.copyFilesFrom { + for _, copyFilesFrom := range slices.Sorted(maps.Keys(p.copyFilesFrom)) { + copyFiles := p.copyFilesFrom[copyFilesFrom] inputName := "copy-tree" paths := []osbuild.CopyStagePath{} for _, copyPath := range copyFiles {