Files

94 lines
3.2 KiB
Go
Raw Permalink Normal View History

package artifact
import (
"crypto/sha256"
"encoding/hex"
"os"
"path/filepath"
"strings"
"testing"
)
func TestBuildManifestSortsNamesAndOmitsEmptySourceOnlyManifest(t *testing.T) {
manifest, err := BuildManifest([]ExpectedAsset{
assetFor("zeta.bin", []byte("zeta")),
assetFor("alpha.bin", []byte("alpha")),
})
if err != nil {
t.Fatal(err)
}
want := assetDigest([]byte("alpha")) + " alpha.bin\n" + assetDigest([]byte("zeta")) + " zeta.bin\n"
if string(manifest.Content) != want || manifest.Filename != ManifestFilename || manifest.SHA256 != assetDigest([]byte(want)) || manifest.Size != int64(len(want)) {
t.Fatalf("manifest = %#v, want content %q", manifest, want)
}
empty, err := BuildManifest(nil)
if err != nil || empty.Filename != "" || len(empty.Content) != 0 {
t.Fatalf("empty manifest = %#v, error = %v", empty, err)
}
}
func TestBuildManifestRejectsInvalidOrDuplicateDeclarations(t *testing.T) {
for _, test := range []struct {
name string
assets []ExpectedAsset
}{
{name: "invalid filename", assets: []ExpectedAsset{assetFor("../app.bin", []byte("app"))}},
{name: "manifest filename", assets: []ExpectedAsset{assetFor(ManifestFilename, []byte("app"))}},
{name: "invalid digest", assets: []ExpectedAsset{{Filename: "app.bin", SHA256: "not-a-digest"}}},
{name: "duplicate filename", assets: []ExpectedAsset{assetFor("app.bin", []byte("one")), assetFor("app.bin", []byte("two"))}},
} {
t.Run(test.name, func(t *testing.T) {
if _, err := BuildManifest(test.assets); err == nil {
t.Fatal("BuildManifest() succeeded for invalid declarations")
}
})
}
}
func TestVerifyLocalAssetsRejectsSameSizeTampering(t *testing.T) {
path := filepath.Join(t.TempDir(), "app.bin")
original := []byte("alpha")
if err := os.WriteFile(path, original, 0o600); err != nil {
t.Fatal(err)
}
asset := assetFor(filepath.Base(path), original)
asset.Content = nil
asset.Path = path
if err := VerifyLocalAssets([]ExpectedAsset{asset}); err != nil {
t.Fatal(err)
}
tampered := []byte("bravo")
if err := os.WriteFile(path, tampered, 0o600); err != nil {
t.Fatal(err)
}
if err := VerifyLocalAssets([]ExpectedAsset{asset}); err == nil || !strings.Contains(err.Error(), "does not match declared asset") {
t.Fatalf("VerifyLocalAssets() error = %v, want content mismatch", err)
}
}
func TestValidateExpectedAssetsRejectsDuplicateAndMismatchedInlineContent(t *testing.T) {
asset := assetFor("app.bin", []byte("alpha"))
if err := ValidateExpectedAssets([]ExpectedAsset{asset, asset}); err == nil || !strings.Contains(err.Error(), "duplicate") {
t.Fatalf("ValidateExpectedAssets() error = %v, want duplicate", err)
}
asset.Content = []byte("bravo")
if err := ValidateExpectedAssets([]ExpectedAsset{asset}); err == nil || !strings.Contains(err.Error(), "does not match identity") {
t.Fatalf("ValidateExpectedAssets() error = %v, want content mismatch", err)
}
}
func assetFor(filename string, content []byte) ExpectedAsset {
return ExpectedAsset{
Filename: filename,
SHA256: assetDigest(content),
Size: int64(len(content)),
Content: append([]byte(nil), content...),
}
}
func assetDigest(content []byte) string {
sum := sha256.Sum256(content)
return hex.EncodeToString(sum[:])
}