diff --git a/.github/workflows/test-package-create.yml b/.github/workflows/test-package-create.yml new file mode 100644 index 0000000000..8572a3389a --- /dev/null +++ b/.github/workflows/test-package-create.yml @@ -0,0 +1,48 @@ +name: Test Package Create Checksums + +on: + pull_request: + merge_group: + +permissions: + contents: read + +concurrency: + group: package-create-${{ github.ref }} + cancel-in-progress: true + +jobs: + test-checksums: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + + - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 + with: + go-version-file: go.mod + + - name: Build Zarf + run: make build + + - name: Build examples + run: make build-examples ARCH=amd64 + + - name: Compare checksums + run: | + set -e + + for f in hack/examples-checksums/*.txt + do + NAME=$(basename $f .txt) + CHECKSUM=$(tar Oxf build/$NAME.tar.zst checksums.txt | grep -v sboms.tar) + EXPECTED_CHECKSUM=$(cat $f | grep -v sboms.tar) + if [[ "$CHECKSUM" != "$EXPECTED_CHECKSUM" ]] + then + echo "Package $f does not have expected checksum." + echo "$CHECKSUM" + echo "-----" + echo "$EXPECTED_CHECKSUM" + exit 1 + fi + done diff --git a/hack/examples-checksums/zarf-package-component-actions-amd64.txt b/hack/examples-checksums/zarf-package-component-actions-amd64.txt new file mode 100644 index 0000000000..24913a26dd --- /dev/null +++ b/hack/examples-checksums/zarf-package-component-actions-amd64.txt @@ -0,0 +1,3 @@ +cfd67a2aeebf13c632207183e1d5cd57146a28aa22b5ddf8896c6ce593c627c2 components/on-deploy-with-wait-action.tar +d26e18c92ff9f93b296fad6be153f02d4a746f0ec44dbcf4c526f1e121ffe4ec components/on-remove.tar +fbfcd7215652819a3b03084d2a12ca7594d8c610ac6e2ebed2f229a0019a52e2 components/on-deploy-with-template-use-of-variable.tar diff --git a/hack/examples-checksums/zarf-package-component-choice-amd64.txt b/hack/examples-checksums/zarf-package-component-choice-amd64.txt new file mode 100644 index 0000000000..ecce58903a --- /dev/null +++ b/hack/examples-checksums/zarf-package-component-choice-amd64.txt @@ -0,0 +1,2 @@ +fa862d90928e52ccc9faa69b5eae73bb97fa5acb76407ba6a177eb338f7d692d components/first-choice.tar +fb99083f2881d87f556c1a7a163876aeaaf1e6094526ff50b2775fc85f8858a3 components/second-choice.tar diff --git a/hack/examples-checksums/zarf-package-dos-games-amd64-1.1.0.txt b/hack/examples-checksums/zarf-package-dos-games-amd64-1.1.0.txt new file mode 100644 index 0000000000..e0a3ce3493 --- /dev/null +++ b/hack/examples-checksums/zarf-package-dos-games-amd64-1.1.0.txt @@ -0,0 +1,8 @@ +0a44b759e219d9d6f3c7cbbf40c57ede71a1f9bf54da65767c4137be74727662 images/blobs/sha256/0a44b759e219d9d6f3c7cbbf40c57ede71a1f9bf54da65767c4137be74727662 +4752b809555b8767401dfd39638f256c2373763a1f2cc421012301bb48481e6d images/blobs/sha256/4752b809555b8767401dfd39638f256c2373763a1f2cc421012301bb48481e6d +49f63464352d7b53ceea3b60b9cc764c1a810b28217ee9f13ab7f974bb3ed968 components/baseline.tar +4f4fb700ef54461cfa02571ae0db9a0dc1e0cdb5577484a6d75e68dc38e8acc1 images/blobs/sha256/4f4fb700ef54461cfa02571ae0db9a0dc1e0cdb5577484a6d75e68dc38e8acc1 +b66dbb27a73334db6ac9c030475837bd7f4472d835c72b2360534b203edce6cb images/oci-layout +c7ee390ce7fc9b525429312617f5fbff5fe195544c1d95b44b72330bff15a615 images/index.json +cc1421ef2ded4a559feaefe8dc266488d60675fcc995db7e51f0b0a6d893e010 images/blobs/sha256/cc1421ef2ded4a559feaefe8dc266488d60675fcc995db7e51f0b0a6d893e010 +e6886dc0b01f09d19480a3270fd9e7c4b261346cee9490b881b36edf21c7e722 images/blobs/sha256/e6886dc0b01f09d19480a3270fd9e7c4b261346cee9490b881b36edf21c7e722 diff --git a/hack/examples-checksums/zarf-package-manifests-amd64-0.0.1.txt b/hack/examples-checksums/zarf-package-manifests-amd64-0.0.1.txt new file mode 100644 index 0000000000..3553f82efa --- /dev/null +++ b/hack/examples-checksums/zarf-package-manifests-amd64-0.0.1.txt @@ -0,0 +1,27 @@ +0f23e58bd0b7c74311703e20c21c690a6847e62240ed456f8821f4c067d3659b images/blobs/sha256/0f23e58bd0b7c74311703e20c21c690a6847e62240ed456f8821f4c067d3659b +12cba3a8e34081029e840e7ac5454c080835cbc5a7adc1620482e939283a3a49 images/blobs/sha256/12cba3a8e34081029e840e7ac5454c080835cbc5a7adc1620482e939283a3a49 +27833a3ba0a545deda33bb01eaf95a14d05d43bf30bce9267d92d17f069fe897 images/blobs/sha256/27833a3ba0a545deda33bb01eaf95a14d05d43bf30bce9267d92d17f069fe897 +27e17b7ec145d38d0be7b5837639a1206f2f3902f7831a6060d0b897f144decd images/index.json +295c7be079025306c4f1d65997fcf7adb411c88f139ad1d34b537164aa060369 images/blobs/sha256/295c7be079025306c4f1d65997fcf7adb411c88f139ad1d34b537164aa060369 +3a96ca29c7fb133e78765557b2bf29a257467f679c43e4153ad05bcde8a1ce3d images/blobs/sha256/3a96ca29c7fb133e78765557b2bf29a257467f679c43e4153ad05bcde8a1ce3d +45ef08258efc940f6336384ae1f35224b5bdf89a3b7abbb5effcbb6c5d62cabe components/nginx-remote.tar +489db2792d7fc3ed75b6970b2e0e73f782bd5c0ed2462ddd683ae92cce04cdb6 images/blobs/sha256/489db2792d7fc3ed75b6970b2e0e73f782bd5c0ed2462ddd683ae92cce04cdb6 +4db1b89c0bd13344176ddce2d093b9da2ae58336823ffed2009a7ea4b62d2a95 images/blobs/sha256/4db1b89c0bd13344176ddce2d093b9da2ae58336823ffed2009a7ea4b62d2a95 +4f4fb700ef54461cfa02571ae0db9a0dc1e0cdb5577484a6d75e68dc38e8acc1 images/blobs/sha256/4f4fb700ef54461cfa02571ae0db9a0dc1e0cdb5577484a6d75e68dc38e8acc1 +706446e9c6667c0880d5da3f39c09a6c7d2114f5a5d6b74a2fafd24ae30d2078 images/blobs/sha256/706446e9c6667c0880d5da3f39c09a6c7d2114f5a5d6b74a2fafd24ae30d2078 +8ca774778e858d3f97d9ec1bec1de879ac5e10096856dc22ed325a3ad944f78a images/blobs/sha256/8ca774778e858d3f97d9ec1bec1de879ac5e10096856dc22ed325a3ad944f78a +92974acd1b7d5aec7654a2df3a310f97c56b7449fc5d042ba8442dbace9a0da6 images/blobs/sha256/92974acd1b7d5aec7654a2df3a310f97c56b7449fc5d042ba8442dbace9a0da6 +9926d2e1a82b13f28b6b9c720bb6947b34c8eabc943de113a3fbc8fabee82d94 images/blobs/sha256/9926d2e1a82b13f28b6b9c720bb6947b34c8eabc943de113a3fbc8fabee82d94 +9b61d3667e8d8d1d8f14ebb413c1ac3fe62373fd69af6aafb281b7a8733f50aa images/blobs/sha256/9b61d3667e8d8d1d8f14ebb413c1ac3fe62373fd69af6aafb281b7a8733f50aa +ae8092b154d705e09bc77523083da3e93200a476ae3aa2b7a5e1747b1cbb8fef images/blobs/sha256/ae8092b154d705e09bc77523083da3e93200a476ae3aa2b7a5e1747b1cbb8fef +b4cd0df67c961ba7f49c86c2e1e6e89d2fd1b8c40ad6fe59508db060dfac51fe images/blobs/sha256/b4cd0df67c961ba7f49c86c2e1e6e89d2fd1b8c40ad6fe59508db060dfac51fe +b66dbb27a73334db6ac9c030475837bd7f4472d835c72b2360534b203edce6cb images/oci-layout +b9c1296647242c2c9c7ffe8cc3a1b9ecde558e8748969ad6a64428ab5922769a images/blobs/sha256/b9c1296647242c2c9c7ffe8cc3a1b9ecde558e8748969ad6a64428ab5922769a +c398742ba22c44f9bbc08dcbbdf0c978b20928fde49dceacded095bc09a46b84 images/blobs/sha256/c398742ba22c44f9bbc08dcbbdf0c978b20928fde49dceacded095bc09a46b84 +c926b61bad3b94ae7351bafd0c184c159ebf0643b085f7ef1d47ecdc7316833c images/blobs/sha256/c926b61bad3b94ae7351bafd0c184c159ebf0643b085f7ef1d47ecdc7316833c +cadc8652ff5abccc918746eb742e7b9165a48428b2c8cc6a48eb6ce782ce5405 images/blobs/sha256/cadc8652ff5abccc918746eb742e7b9165a48428b2c8cc6a48eb6ce782ce5405 +d37d27b92cce4fb1383d5fbe32540382ea3d9662c7be3555f5a0f6a044099e1b images/blobs/sha256/d37d27b92cce4fb1383d5fbe32540382ea3d9662c7be3555f5a0f6a044099e1b +d8173b5b3d825c1c19acf91cb66599f453187705ca9cdb4608d7be5482768cba images/blobs/sha256/d8173b5b3d825c1c19acf91cb66599f453187705ca9cdb4608d7be5482768cba +d95fa8da986254bcd64c1251b695fe91875383dac1ed1780480fdf70f02cea3b images/blobs/sha256/d95fa8da986254bcd64c1251b695fe91875383dac1ed1780480fdf70f02cea3b +f55cf5db16c790710ce2cd7b3d4fa00db89bdeea9d516aa83a596e910de103b2 components/podinfo-kustomize.tar +f59dcac0742ce66d707aed956c25cd0fc20d162ecaca308637197eac1cef13fc components/httpd-local.tar diff --git a/hack/examples-checksums/zarf-package-variables-amd64.txt b/hack/examples-checksums/zarf-package-variables-amd64.txt new file mode 100644 index 0000000000..a0fdb11006 --- /dev/null +++ b/hack/examples-checksums/zarf-package-variables-amd64.txt @@ -0,0 +1,12 @@ +1ff0f94a80076ab49af75159e23f062a30a75d333a8e9c021bf39669230afcfe images/blobs/sha256/1ff0f94a80076ab49af75159e23f062a30a75d333a8e9c021bf39669230afcfe +291f5d3c8c1742164379dfd09b17eeec4f70bcb165773d65d450dec5ef94d907 images/index.json +4b2a24be75c4766f2d20892ddb84841e3773d0e26249ee57eed530da19c07bb2 components/variables-with-nginx.tar +557c9ede65655e5a70e4a32f1651638ea3bfb0802edd982810884602f700ba25 images/blobs/sha256/557c9ede65655e5a70e4a32f1651638ea3bfb0802edd982810884602f700ba25 +84181e80d10e844350789d3324e848cf728df4f3d0f6c978789dd489f493934a images/blobs/sha256/84181e80d10e844350789d3324e848cf728df4f3d0f6c978789dd489f493934a +a8a737eacb28af35791c2a444d8095ca3d493ba31eca78cd57a6fe3cced79154 components/variables-with-terraform.tar +ac232364af842735579e922641ae2f67d5b8ea97df33a207c5ea05f60c63a92d images/blobs/sha256/ac232364af842735579e922641ae2f67d5b8ea97df33a207c5ea05f60c63a92d +b66dbb27a73334db6ac9c030475837bd7f4472d835c72b2360534b203edce6cb images/oci-layout +d4ceccbfc2696101c94fbf2149036e4ff815e4723e518721ff85105ce5aa8afc images/blobs/sha256/d4ceccbfc2696101c94fbf2149036e4ff815e4723e518721ff85105ce5aa8afc +d776269cad101c9f8e33e2baa0a05993ed0786604d86ea525f62d5d7ae7b9540 images/blobs/sha256/d776269cad101c9f8e33e2baa0a05993ed0786604d86ea525f62d5d7ae7b9540 +e9427fcfa8642f8ddf5106f742a75eca0dbac676cf8145598623d04fa45dd74e images/blobs/sha256/e9427fcfa8642f8ddf5106f742a75eca0dbac676cf8145598623d04fa45dd74e +f1f26f5702560b7e591bef5c4d840f76a232bf13fd5aefc4e22077a1ae4440c7 images/blobs/sha256/f1f26f5702560b7e591bef5c4d840f76a232bf13fd5aefc4e22077a1ae4440c7 diff --git a/hack/examples-checksums/zarf-package-yolo-amd64.txt b/hack/examples-checksums/zarf-package-yolo-amd64.txt new file mode 100644 index 0000000000..e925a4d3d9 --- /dev/null +++ b/hack/examples-checksums/zarf-package-yolo-amd64.txt @@ -0,0 +1 @@ +b31cd4195a94c235f6560274fac9efb9934c517381d16593592d02f212e1cd70 components/yolo-games.tar diff --git a/src/pkg/packager/creator/normal.go b/src/pkg/packager/creator/normal.go index 099fda5e2b..3b7d4a7698 100644 --- a/src/pkg/packager/creator/normal.go +++ b/src/pkg/packager/creator/normal.go @@ -206,6 +206,12 @@ func (pc *PackageCreator) Assemble(ctx context.Context, dst *layout.PackagePaths sbomImageList = append(sbomImageList, info) } } + + // Sort images index to make build reproducible. + err = utils.SortImagesIndex(dst.Images.Base) + if err != nil { + return err + } } // Ignore SBOM creation if the flag is set. diff --git a/src/pkg/utils/image.go b/src/pkg/utils/image.go index 3756a759e1..cd62128159 100644 --- a/src/pkg/utils/image.go +++ b/src/pkg/utils/image.go @@ -9,6 +9,8 @@ import ( "fmt" "os" "path/filepath" + "slices" + "strings" "github.com/defenseunicorns/pkg/helpers/v2" v1 "github.com/google/go-containerregistry/pkg/v1" @@ -102,3 +104,25 @@ func OnlyHasImageLayers(img v1.Image) (bool, error) { } return true, nil } + +// SortImagesIndex sorts the index.json by digest. +func SortImagesIndex(ociPath string) error { + indexPath := filepath.Join(ociPath, "index.json") + b, err := os.ReadFile(indexPath) + if err != nil { + return err + } + var index ocispec.Index + err = json.Unmarshal(b, &index) + if err != nil { + return err + } + slices.SortFunc(index.Manifests, func(a, b ocispec.Descriptor) int { + return strings.Compare(string(a.Digest), string(b.Digest)) + }) + b, err = json.Marshal(index) + if err != nil { + return err + } + return os.WriteFile(indexPath, b, helpers.ReadWriteUser) +}