diff --git a/pkg/attestation/crafter/materials/csaf.go b/pkg/attestation/crafter/materials/csaf.go index 90dfbce1e..fb09f0bc7 100644 --- a/pkg/attestation/crafter/materials/csaf.go +++ b/pkg/attestation/crafter/materials/csaf.go @@ -102,14 +102,22 @@ func (i *CSAFCrafter) Craft(ctx context.Context, filepath string) (*api.Attestat } // Validate the CSAF file against the specified category. - document, docExists := v.(map[string]interface{})["document"] - if docExists { - documentMap, docMapOk := document.(map[string]interface{}) - category, categoryExists := documentMap["category"].(string) - - if docMapOk && categoryExists && category != "" && category != i.category { - return nil, fmt.Errorf("invalid CSAF category field in file, expected: %v", i.category) - } + // First check that the content is a map with a `document` root + doc, ok := v.(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("invalid CSAF file: %w", ErrInvalidMaterialType) + } + + // Map its content + documentMap, ok := doc["document"].(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("invalid CSAF file: %w", ErrInvalidMaterialType) + } + + // extract category: not mandatory but if it comes we check it + category, categoryExists := documentMap["category"].(string) + if categoryExists && category != "" && category != i.category { + return nil, fmt.Errorf("invalid CSAF category field in file, expected: %v", i.category) } // The validator will try in cascade the different schemas since CSAF specification diff --git a/pkg/attestation/crafter/materials/csaf_test.go b/pkg/attestation/crafter/materials/csaf_test.go index db0364417..78cb2da96 100644 --- a/pkg/attestation/crafter/materials/csaf_test.go +++ b/pkg/attestation/crafter/materials/csaf_test.go @@ -1,5 +1,5 @@ // -// Copyright 2023 The Chainloop Authors. +// Copyright 2024 The Chainloop Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -132,6 +132,24 @@ func TestCSAFCraft(t *testing.T) { Type: contractAPI.CraftingSchema_Material_CSAF_VEX, }, }, + { + name: "empty json array", + filePath: "./testdata/empty_array.json", + wantErr: "unexpected material type", + schema: &contractAPI.CraftingSchema_Material{ + Name: "test", + Type: contractAPI.CraftingSchema_Material_CSAF_VEX, + }, + }, + { + name: "empty file", + filePath: "./testdata/empty.txt", + wantErr: "unexpected material type", + schema: &contractAPI.CraftingSchema_Material{ + Name: "test", + Type: contractAPI.CraftingSchema_Material_CSAF_VEX, + }, + }, { name: "valid json file invalid artifact", filePath: "./testdata/random.json", diff --git a/pkg/attestation/crafter/materials/materials.go b/pkg/attestation/crafter/materials/materials.go index 6467fa31a..35f416fe7 100644 --- a/pkg/attestation/crafter/materials/materials.go +++ b/pkg/attestation/crafter/materials/materials.go @@ -57,6 +57,10 @@ func uploadAndCraft(ctx context.Context, input *schemaapi.CraftingSchema_Materia } defer result.r.Close() + if result.size == 0 { + return nil, fmt.Errorf("%w: %w", ErrBaseUploadAndCraft, errors.New("file is empty")) + } + l.Debug().Str("filename", result.filename).Str("digest", result.digest).Str("path", artifactPath). Str("size", bytefmt.ByteSize(uint64(result.size))). Str("max_size", bytefmt.ByteSize(uint64(backend.MaxSize))). diff --git a/pkg/attestation/crafter/materials/testdata/empty_array.json b/pkg/attestation/crafter/materials/testdata/empty_array.json new file mode 100644 index 000000000..fe51488c7 --- /dev/null +++ b/pkg/attestation/crafter/materials/testdata/empty_array.json @@ -0,0 +1 @@ +[]