From 50bc6ead7f4ca387eb502957f7e00b9b3f0579e2 Mon Sep 17 00:00:00 2001 From: Allen Conlon Date: Tue, 7 Apr 2026 18:45:38 -0400 Subject: [PATCH 1/3] feat: expose sbom generation tools Signed-off-by: Allen Conlon --- src/pkg/packager/layout/assemble.go | 14 +++++++------- src/pkg/packager/layout/assemble_test.go | 4 ++-- src/pkg/packager/layout/package_test.go | 2 +- src/pkg/packager/layout/sbom.go | 16 ++++++++-------- src/pkg/packager/layout/sbom_test.go | 4 ++-- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/pkg/packager/layout/assemble.go b/src/pkg/packager/layout/assemble.go index 83d83c30a7..d34a550b91 100644 --- a/src/pkg/packager/layout/assemble.go +++ b/src/pkg/packager/layout/assemble.go @@ -191,7 +191,7 @@ func AssemblePackage(ctx context.Context, pkg v1alpha1.ZarfPackage, packagePath return nil, err } - checksumContent, checksumSha, err := getChecksum(buildPath) + checksumContent, checksumSha, err := GetChecksum(buildPath) if err != nil { return nil, err } @@ -265,7 +265,7 @@ func AssembleSkeleton(ctx context.Context, pkg v1alpha1.ZarfPackage, packagePath } } - checksumContent, checksumSha, err := getChecksum(buildPath) + checksumContent, checksumSha, err := GetChecksum(buildPath) if err != nil { return nil, err } @@ -524,7 +524,7 @@ func assemblePackageComponent(ctx context.Context, component v1alpha1.ZarfCompon if err != nil { return err } - err = createReproducibleTarballFromDir(compBuildPath, component.Name, tarPath, false) + err = CreateReproducibleTarballFromDir(compBuildPath, component.Name, tarPath, false) if err != nil { return err } @@ -773,7 +773,7 @@ func assembleSkeletonComponent(ctx context.Context, component v1alpha1.ZarfCompo if err != nil { return err } - err = createReproducibleTarballFromDir(compBuildPath, component.Name, tarPath, true) + err = CreateReproducibleTarballFromDir(compBuildPath, component.Name, tarPath, true) if err != nil { return err } @@ -844,7 +844,7 @@ func recordPackageMetadata(pkg v1alpha1.ZarfPackage, flavor string, registryOver return pkg } -func getChecksum(dirPath string) (string, string, error) { +func GetChecksum(dirPath string) (string, string, error) { checksumData := []string{} err := filepath.Walk(dirPath, func(path string, info fs.FileInfo, err error) error { if err != nil { @@ -877,7 +877,7 @@ func getChecksum(dirPath string) (string, string, error) { return checksumContent, hex.EncodeToString(sha[:]), nil } -func createReproducibleTarballFromDir(dirPath, dirPrefix, tarballPath string, overrideMode bool) (err error) { +func CreateReproducibleTarballFromDir(dirPath, dirPrefix, tarballPath string, overrideMode bool) (err error) { tb, err := os.Create(tarballPath) if err != nil { return fmt.Errorf("error creating tarball: %w", err) @@ -1070,7 +1070,7 @@ func createDocumentationTar(pkg v1alpha1.ZarfPackage, packagePath, buildPath str } tarPath := filepath.Join(buildPath, DocumentationTar) - if err := createReproducibleTarballFromDir(tmpDir, "", tarPath, true); err != nil { + if err := CreateReproducibleTarballFromDir(tmpDir, "", tarPath, true); err != nil { return fmt.Errorf("failed to create documentation tarball: %w", err) } diff --git a/src/pkg/packager/layout/assemble_test.go b/src/pkg/packager/layout/assemble_test.go index 7fab8bc464..d4951b4490 100644 --- a/src/pkg/packager/layout/assemble_test.go +++ b/src/pkg/packager/layout/assemble_test.go @@ -31,7 +31,7 @@ func TestGetChecksum(t *testing.T) { require.NoError(t, err) } - checksumContent, checksumHash, err := getChecksum(tmpDir) + checksumContent, checksumHash, err := GetChecksum(tmpDir) require.NoError(t, err) expectedContent := `233562de1a0288b139c4fa40b7d189f806e906eeb048517aeb67f34ac0e2faf1 nested/directory/file.md @@ -50,7 +50,7 @@ func TestCreateReproducibleTarballFromDir(t *testing.T) { require.NoError(t, err) tarPath := filepath.Join(t.TempDir(), "data.tar") - err = createReproducibleTarballFromDir(tmpDir, "", tarPath, true) + err = CreateReproducibleTarballFromDir(tmpDir, "", tarPath, true) require.NoError(t, err) shaSum, err := helpers.GetSHA256OfFile(tarPath) diff --git a/src/pkg/packager/layout/package_test.go b/src/pkg/packager/layout/package_test.go index 0038f59b21..7a1fb13bfe 100644 --- a/src/pkg/packager/layout/package_test.go +++ b/src/pkg/packager/layout/package_test.go @@ -1202,7 +1202,7 @@ func TestGetDocumentation(t *testing.T) { } tarPath := filepath.Join(pkgDir, DocumentationTar) - err := createReproducibleTarballFromDir(docTempDir, "", tarPath, false) + err := CreateReproducibleTarballFromDir(docTempDir, "", tarPath, false) require.NoError(t, err) } diff --git a/src/pkg/packager/layout/sbom.go b/src/pkg/packager/layout/sbom.go index 32726dba0d..445369fefe 100644 --- a/src/pkg/packager/layout/sbom.go +++ b/src/pkg/packager/layout/sbom.go @@ -73,11 +73,11 @@ func generateSBOM(ctx context.Context, pkg v1alpha1.ZarfPackage, buildPath strin return fmt.Errorf("failed to load OCI image: %w", err) } l.Info("creating image SBOM", "reference", refInfo.Reference) - b, err := createImageSBOM(ctx, cachePath, outputPath, img, refInfo.Reference) + b, err := CreateImageSBOM(ctx, cachePath, outputPath, img, refInfo.Reference) if err != nil { return fmt.Errorf("failed to create image sbom: %w", err) } - err = createSBOMViewerAsset(outputPath, refInfo.Reference, b, jsonList) + err = CreateSBOMViewerAsset(outputPath, refInfo.Reference, b, jsonList) if err != nil { return err } @@ -92,19 +92,19 @@ func generateSBOM(ctx context.Context, pkg v1alpha1.ZarfPackage, buildPath strin if err != nil { return err } - err = createSBOMViewerAsset(outputPath, fmt.Sprintf("%s%s", componentPrefix, comp.Name), jsonData, jsonList) + err = CreateSBOMViewerAsset(outputPath, fmt.Sprintf("%s%s", componentPrefix, comp.Name), jsonData, jsonList) if err != nil { return err } } // Include the compare tool if there are any image SBOMs OR component SBOMs - err = createSBOMCompareAsset(outputPath) + err = CreateSBOMCompareAsset(outputPath) if err != nil { return err } - err = createReproducibleTarballFromDir(outputPath, "", filepath.Join(buildPath, "sboms.tar"), false) + err = CreateReproducibleTarballFromDir(outputPath, "", filepath.Join(buildPath, "sboms.tar"), false) if err != nil { return err } @@ -112,7 +112,7 @@ func generateSBOM(ctx context.Context, pkg v1alpha1.ZarfPackage, buildPath strin return nil } -func createImageSBOM(ctx context.Context, cachePath, outputPath string, img v1.Image, src string) ([]byte, error) { +func CreateImageSBOM(ctx context.Context, cachePath, outputPath string, img v1.Image, src string) ([]byte, error) { imageCachePath := filepath.Join(cachePath, ImagesDir) // This is a write cache @@ -270,12 +270,12 @@ func createFileSBOM(ctx context.Context, component v1alpha1.ZarfComponent, outpu return jsonData, nil } -func createSBOMViewerAsset(outputDir, identifier string, jsonData, jsonList []byte) error { +func CreateSBOMViewerAsset(outputDir, identifier string, jsonData, jsonList []byte) error { filename := fmt.Sprintf("sbom-viewer-%s.html", getNormalizedFileName(identifier)) return createSBOMHTML(outputDir, filename, "viewer/template.gohtml", jsonData, jsonList) } -func createSBOMCompareAsset(outputDir string) error { +func CreateSBOMCompareAsset(outputDir string) error { return createSBOMHTML(outputDir, "compare.html", "viewer/compare.gohtml", nil, nil) } diff --git a/src/pkg/packager/layout/sbom_test.go b/src/pkg/packager/layout/sbom_test.go index c4026cb498..47a0621bbb 100644 --- a/src/pkg/packager/layout/sbom_test.go +++ b/src/pkg/packager/layout/sbom_test.go @@ -20,7 +20,7 @@ func TestCreateImageSBOM(t *testing.T) { outputPath := t.TempDir() img := empty.Image - b, err := createImageSBOM(ctx, t.TempDir(), outputPath, img, "docker.io/foo/bar:latest") + b, err := CreateImageSBOM(ctx, t.TempDir(), outputPath, img, "docker.io/foo/bar:latest") require.NoError(t, err) require.NotEmpty(t, b) @@ -38,7 +38,7 @@ func TestCreateImageSBOMNonExistentCachePath(t *testing.T) { // Cache path that doesn't exist yet cachePath := filepath.Join(t.TempDir(), "non-existent-cache") img := empty.Image - b, err := createImageSBOM(ctx, cachePath, outputPath, img, "docker.io/foo/bar:latest") + b, err := CreateImageSBOM(ctx, cachePath, outputPath, img, "docker.io/foo/bar:latest") require.NoError(t, err) require.NotEmpty(t, b) } From 9e00b0226d4f558459226e7d406a04f7b784c599 Mon Sep 17 00:00:00 2001 From: Allen Conlon Date: Tue, 7 Apr 2026 18:45:38 -0400 Subject: [PATCH 2/3] ci: add comments Signed-off-by: Allen Conlon --- src/pkg/packager/layout/assemble.go | 7 ++++++- src/pkg/packager/layout/sbom.go | 5 +++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/pkg/packager/layout/assemble.go b/src/pkg/packager/layout/assemble.go index d34a550b91..12022d9887 100644 --- a/src/pkg/packager/layout/assemble.go +++ b/src/pkg/packager/layout/assemble.go @@ -844,6 +844,8 @@ func recordPackageMetadata(pkg v1alpha1.ZarfPackage, flavor string, registryOver return pkg } +// GetChecksum takes a directory then creates a sha256 check sum for each files in the +// directory recursively, then creates a global checksum for all the files together. func GetChecksum(dirPath string) (string, string, error) { checksumData := []string{} err := filepath.Walk(dirPath, func(path string, info fs.FileInfo, err error) error { @@ -877,7 +879,10 @@ func GetChecksum(dirPath string) (string, string, error) { return checksumContent, hex.EncodeToString(sha[:]), nil } -func CreateReproducibleTarballFromDir(dirPath, dirPrefix, tarballPath string, overrideMode bool) (err error) { +// CreateReproducibleTarballFromDir takes a directory then walks thru every file in that directory and adds it +// to a tar ball; the reproducible part comes from changing all the file user and group to 0, and settings the +// file creation, access, and mod time to midnight on January 1st 1970, UTC. +func CreateReproducibleTarballFromDir(dirPath string, dirPrefix string, tarballPath string, overrideMode bool) (err error) { tb, err := os.Create(tarballPath) if err != nil { return fmt.Errorf("error creating tarball: %w", err) diff --git a/src/pkg/packager/layout/sbom.go b/src/pkg/packager/layout/sbom.go index 445369fefe..89f0f744b8 100644 --- a/src/pkg/packager/layout/sbom.go +++ b/src/pkg/packager/layout/sbom.go @@ -112,6 +112,7 @@ func generateSBOM(ctx context.Context, pkg v1alpha1.ZarfPackage, buildPath strin return nil } +// CreateImageSBOM is used to generate a syft SBOM for a provided image reference. func CreateImageSBOM(ctx context.Context, cachePath, outputPath string, img v1.Image, src string) ([]byte, error) { imageCachePath := filepath.Join(cachePath, ImagesDir) @@ -270,11 +271,15 @@ func createFileSBOM(ctx context.Context, component v1alpha1.ZarfComponent, outpu return jsonData, nil } +// CreateSBOMViewerAsset creates an offline software bill of material html webpage that +// that can be used to viewed before installing any packages into a cluster. func CreateSBOMViewerAsset(outputDir, identifier string, jsonData, jsonList []byte) error { filename := fmt.Sprintf("sbom-viewer-%s.html", getNormalizedFileName(identifier)) return createSBOMHTML(outputDir, filename, "viewer/template.gohtml", jsonData, jsonList) } +// CreateSBOMCompareAsset creates an offline html webpage used to to compare the all the +// images and files associated with a package. func CreateSBOMCompareAsset(outputDir string) error { return createSBOMHTML(outputDir, "compare.html", "viewer/compare.gohtml", nil, nil) } From 6b85095b0ffdd144dea08b093754ef77e0ce174f Mon Sep 17 00:00:00 2001 From: Allen Conlon Date: Tue, 28 Apr 2026 19:55:32 -0400 Subject: [PATCH 3/3] feat: revert some public methods Signed-off-by: Allen Conlon --- src/pkg/packager/layout/assemble.go | 10 +++++----- src/pkg/packager/layout/assemble_test.go | 2 +- src/pkg/packager/layout/package_test.go | 2 +- src/pkg/packager/layout/sbom.go | 16 ++++++++-------- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/pkg/packager/layout/assemble.go b/src/pkg/packager/layout/assemble.go index 12022d9887..a1c58a6392 100644 --- a/src/pkg/packager/layout/assemble.go +++ b/src/pkg/packager/layout/assemble.go @@ -524,7 +524,7 @@ func assemblePackageComponent(ctx context.Context, component v1alpha1.ZarfCompon if err != nil { return err } - err = CreateReproducibleTarballFromDir(compBuildPath, component.Name, tarPath, false) + err = createReproducibleTarballFromDir(compBuildPath, component.Name, tarPath, false) if err != nil { return err } @@ -773,7 +773,7 @@ func assembleSkeletonComponent(ctx context.Context, component v1alpha1.ZarfCompo if err != nil { return err } - err = CreateReproducibleTarballFromDir(compBuildPath, component.Name, tarPath, true) + err = createReproducibleTarballFromDir(compBuildPath, component.Name, tarPath, true) if err != nil { return err } @@ -879,10 +879,10 @@ func GetChecksum(dirPath string) (string, string, error) { return checksumContent, hex.EncodeToString(sha[:]), nil } -// CreateReproducibleTarballFromDir takes a directory then walks thru every file in that directory and adds it +// createReproducibleTarballFromDir takes a directory then walks thru every file in that directory and adds it // to a tar ball; the reproducible part comes from changing all the file user and group to 0, and settings the // file creation, access, and mod time to midnight on January 1st 1970, UTC. -func CreateReproducibleTarballFromDir(dirPath string, dirPrefix string, tarballPath string, overrideMode bool) (err error) { +func createReproducibleTarballFromDir(dirPath string, dirPrefix string, tarballPath string, overrideMode bool) (err error) { tb, err := os.Create(tarballPath) if err != nil { return fmt.Errorf("error creating tarball: %w", err) @@ -1075,7 +1075,7 @@ func createDocumentationTar(pkg v1alpha1.ZarfPackage, packagePath, buildPath str } tarPath := filepath.Join(buildPath, DocumentationTar) - if err := CreateReproducibleTarballFromDir(tmpDir, "", tarPath, true); err != nil { + if err := createReproducibleTarballFromDir(tmpDir, "", tarPath, true); err != nil { return fmt.Errorf("failed to create documentation tarball: %w", err) } diff --git a/src/pkg/packager/layout/assemble_test.go b/src/pkg/packager/layout/assemble_test.go index d4951b4490..ec16fab08e 100644 --- a/src/pkg/packager/layout/assemble_test.go +++ b/src/pkg/packager/layout/assemble_test.go @@ -50,7 +50,7 @@ func TestCreateReproducibleTarballFromDir(t *testing.T) { require.NoError(t, err) tarPath := filepath.Join(t.TempDir(), "data.tar") - err = CreateReproducibleTarballFromDir(tmpDir, "", tarPath, true) + err = createReproducibleTarballFromDir(tmpDir, "", tarPath, true) require.NoError(t, err) shaSum, err := helpers.GetSHA256OfFile(tarPath) diff --git a/src/pkg/packager/layout/package_test.go b/src/pkg/packager/layout/package_test.go index 7a1fb13bfe..0038f59b21 100644 --- a/src/pkg/packager/layout/package_test.go +++ b/src/pkg/packager/layout/package_test.go @@ -1202,7 +1202,7 @@ func TestGetDocumentation(t *testing.T) { } tarPath := filepath.Join(pkgDir, DocumentationTar) - err := CreateReproducibleTarballFromDir(docTempDir, "", tarPath, false) + err := createReproducibleTarballFromDir(docTempDir, "", tarPath, false) require.NoError(t, err) } diff --git a/src/pkg/packager/layout/sbom.go b/src/pkg/packager/layout/sbom.go index 89f0f744b8..911840e01b 100644 --- a/src/pkg/packager/layout/sbom.go +++ b/src/pkg/packager/layout/sbom.go @@ -77,7 +77,7 @@ func generateSBOM(ctx context.Context, pkg v1alpha1.ZarfPackage, buildPath strin if err != nil { return fmt.Errorf("failed to create image sbom: %w", err) } - err = CreateSBOMViewerAsset(outputPath, refInfo.Reference, b, jsonList) + err = createSBOMViewerAsset(outputPath, refInfo.Reference, b, jsonList) if err != nil { return err } @@ -92,19 +92,19 @@ func generateSBOM(ctx context.Context, pkg v1alpha1.ZarfPackage, buildPath strin if err != nil { return err } - err = CreateSBOMViewerAsset(outputPath, fmt.Sprintf("%s%s", componentPrefix, comp.Name), jsonData, jsonList) + err = createSBOMViewerAsset(outputPath, fmt.Sprintf("%s%s", componentPrefix, comp.Name), jsonData, jsonList) if err != nil { return err } } // Include the compare tool if there are any image SBOMs OR component SBOMs - err = CreateSBOMCompareAsset(outputPath) + err = createSBOMCompareAsset(outputPath) if err != nil { return err } - err = CreateReproducibleTarballFromDir(outputPath, "", filepath.Join(buildPath, "sboms.tar"), false) + err = createReproducibleTarballFromDir(outputPath, "", filepath.Join(buildPath, "sboms.tar"), false) if err != nil { return err } @@ -271,16 +271,16 @@ func createFileSBOM(ctx context.Context, component v1alpha1.ZarfComponent, outpu return jsonData, nil } -// CreateSBOMViewerAsset creates an offline software bill of material html webpage that +// createSBOMViewerAsset creates an offline software bill of material html webpage that // that can be used to viewed before installing any packages into a cluster. -func CreateSBOMViewerAsset(outputDir, identifier string, jsonData, jsonList []byte) error { +func createSBOMViewerAsset(outputDir, identifier string, jsonData, jsonList []byte) error { filename := fmt.Sprintf("sbom-viewer-%s.html", getNormalizedFileName(identifier)) return createSBOMHTML(outputDir, filename, "viewer/template.gohtml", jsonData, jsonList) } -// CreateSBOMCompareAsset creates an offline html webpage used to to compare the all the +// createSBOMCompareAsset creates an offline html webpage used to to compare the all the // images and files associated with a package. -func CreateSBOMCompareAsset(outputDir string) error { +func createSBOMCompareAsset(outputDir string) error { return createSBOMHTML(outputDir, "compare.html", "viewer/compare.gohtml", nil, nil) }