161 lines
4.9 KiB
Go
161 lines
4.9 KiB
Go
package pipeline
|
|
|
|
import (
|
|
"encoding/json"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"git.westgate.pw/ShadowsOverWestgate/sow-tools/internal/buildinfo"
|
|
)
|
|
|
|
const validAsset = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
|
|
|
// directManifestFixture returns a minimal valid direct source manifest using the
|
|
// running builder identity, so validation does not reject it on builder mismatch.
|
|
func directManifestFixture() *SourceBuildManifest {
|
|
return &SourceBuildManifest{
|
|
Schema: 1,
|
|
BuilderID: buildinfo.String(),
|
|
ModuleHAKs: []string{"core_01"},
|
|
HAKs: []SourceManifestHAK{
|
|
{
|
|
Name: "core_01",
|
|
Group: "core",
|
|
Priority: 1,
|
|
MaxBytes: 1024,
|
|
Assets: []string{"core/a.tga"},
|
|
},
|
|
},
|
|
AssetSources: map[string]SourceAsset{
|
|
"core/a.tga": {SHA256: validAsset, SizeBytes: 4},
|
|
},
|
|
}
|
|
}
|
|
|
|
func writeManifestFixture(t *testing.T, manifest *SourceBuildManifest) string {
|
|
t.Helper()
|
|
raw, err := json.Marshal(manifest)
|
|
if err != nil {
|
|
t.Fatalf("marshal fixture: %v", err)
|
|
}
|
|
path := filepath.Join(t.TempDir(), "build-source-manifest.json")
|
|
mustWriteFile(t, path, string(raw))
|
|
return path
|
|
}
|
|
|
|
func TestLoadSourceBuildManifestDirect(t *testing.T) {
|
|
path := writeManifestFixture(t, directManifestFixture())
|
|
|
|
manifest, err := loadSourceBuildManifest(path)
|
|
if err != nil {
|
|
t.Fatalf("load: %v", err)
|
|
}
|
|
if manifest.Schema != 1 {
|
|
t.Fatalf("schema = %d, want 1", manifest.Schema)
|
|
}
|
|
if manifest.BuilderID != buildinfo.String() {
|
|
t.Fatalf("builder_id = %q, want %q", manifest.BuilderID, buildinfo.String())
|
|
}
|
|
if len(manifest.HAKs) != 1 || manifest.HAKs[0].Name != "core_01" {
|
|
t.Fatalf("unexpected haks: %#v", manifest.HAKs)
|
|
}
|
|
source, ok := manifest.AssetSources["core/a.tga"]
|
|
if !ok || source.SHA256 != validAsset || source.SizeBytes != 4 {
|
|
t.Fatalf("unexpected asset source: %#v", manifest.AssetSources)
|
|
}
|
|
if err := validateDirectSourceManifest(manifest); err != nil {
|
|
t.Fatalf("validate valid manifest: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestValidateDirectSourceManifestRejectsUnsupportedSchema(t *testing.T) {
|
|
manifest := directManifestFixture()
|
|
manifest.Schema = 2
|
|
if err := validateDirectSourceManifest(manifest); err == nil {
|
|
t.Fatal("expected schema rejection")
|
|
}
|
|
}
|
|
|
|
func TestValidateDirectSourceManifestRejectsBadSHA(t *testing.T) {
|
|
manifest := directManifestFixture()
|
|
manifest.AssetSources["core/a.tga"] = SourceAsset{SHA256: "NOTHEX", SizeBytes: 4}
|
|
if err := validateDirectSourceManifest(manifest); err == nil {
|
|
t.Fatal("expected bad sha rejection")
|
|
}
|
|
}
|
|
|
|
func TestValidateDirectSourceManifestRejectsNegativeSize(t *testing.T) {
|
|
manifest := directManifestFixture()
|
|
manifest.AssetSources["core/a.tga"] = SourceAsset{SHA256: validAsset, SizeBytes: -1}
|
|
if err := validateDirectSourceManifest(manifest); err == nil {
|
|
t.Fatal("expected negative size rejection")
|
|
}
|
|
}
|
|
|
|
func TestValidateDirectSourceManifestRejectsMissingSource(t *testing.T) {
|
|
manifest := directManifestFixture()
|
|
delete(manifest.AssetSources, "core/a.tga")
|
|
if err := validateDirectSourceManifest(manifest); err == nil {
|
|
t.Fatal("expected missing source rejection")
|
|
}
|
|
}
|
|
|
|
func TestValidateDirectSourceManifestRejectsUnusedSource(t *testing.T) {
|
|
manifest := directManifestFixture()
|
|
manifest.AssetSources["core/orphan.tga"] = SourceAsset{SHA256: validAsset, SizeBytes: 4}
|
|
if err := validateDirectSourceManifest(manifest); err == nil {
|
|
t.Fatal("expected unused source rejection")
|
|
}
|
|
}
|
|
|
|
func TestValidateDirectSourceManifestRejectsDuplicateAssetAcrossHAKs(t *testing.T) {
|
|
manifest := directManifestFixture()
|
|
manifest.HAKs = append(manifest.HAKs, SourceManifestHAK{
|
|
Name: "core_02",
|
|
Group: "core",
|
|
Priority: 1,
|
|
MaxBytes: 1024,
|
|
Assets: []string{"core/a.tga"},
|
|
})
|
|
if err := validateDirectSourceManifest(manifest); err == nil {
|
|
t.Fatal("expected duplicate-asset rejection")
|
|
}
|
|
}
|
|
|
|
func TestValidateDirectSourceManifestRejectsTraversalPath(t *testing.T) {
|
|
manifest := directManifestFixture()
|
|
manifest.HAKs[0].Assets = []string{"../escape.tga"}
|
|
manifest.AssetSources = map[string]SourceAsset{
|
|
"../escape.tga": {SHA256: validAsset, SizeBytes: 4},
|
|
}
|
|
if err := validateDirectSourceManifest(manifest); err == nil {
|
|
t.Fatal("expected traversal rejection")
|
|
}
|
|
}
|
|
|
|
func TestValidateDirectSourceManifestRejectsBuilderMismatch(t *testing.T) {
|
|
manifest := directManifestFixture()
|
|
manifest.BuilderID = "crucible deadbeef"
|
|
if err := validateDirectSourceManifest(manifest); err == nil {
|
|
t.Fatal("expected builder mismatch rejection")
|
|
}
|
|
}
|
|
|
|
func TestContentAddressedBlobPath(t *testing.T) {
|
|
root := "/var/cache/blobs"
|
|
got, err := contentAddressedBlobPath(root, validAsset)
|
|
if err != nil {
|
|
t.Fatalf("blob path: %v", err)
|
|
}
|
|
want := filepath.Join(root, "sha256", "aa", "aa", validAsset)
|
|
if got != want {
|
|
t.Fatalf("blob path = %q, want %q", got, want)
|
|
}
|
|
if _, err := contentAddressedBlobPath(root, "NOTHEX"); err == nil {
|
|
t.Fatal("expected invalid sha rejection")
|
|
}
|
|
if _, err := contentAddressedBlobPath("", validAsset); err == nil {
|
|
t.Fatal("expected empty root rejection")
|
|
}
|
|
}
|