github.com/google/osv-scalibr@v0.4.1/artifact/image/layerscanning/testing/fakev1layer/fake_v1_layer.go (about) 1 // Copyright 2025 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Package fakev1layer provides a fake implementation of the v1.Layer interface for testing 16 // purposes. 17 package fakev1layer 18 19 import ( 20 "bytes" 21 "crypto/sha256" 22 "errors" 23 "io" 24 "io/fs" 25 "path/filepath" 26 "testing" 27 28 "archive/tar" 29 30 v1 "github.com/google/go-containerregistry/pkg/v1" 31 "github.com/google/go-containerregistry/pkg/v1/types" 32 ) 33 34 // ContentAndMode is a struct that contains the content and mode of a file in a fake v1 layer. 35 type ContentAndMode struct { 36 content string 37 mode fs.FileMode 38 } 39 40 // FakeV1Layer is a fake implementation of the v1.Layer interface for testing purposes. 41 type FakeV1Layer struct { 42 diffID string 43 buildCommand string 44 isEmpty bool 45 content []byte 46 failGettingUncompressed bool 47 } 48 49 // DiffID returns the diffID of the layer. 50 func (fakeV1Layer *FakeV1Layer) DiffID() (v1.Hash, error) { 51 if fakeV1Layer.diffID == "" { 52 return v1.Hash{}, errors.New("diffID is empty") 53 } 54 return v1.Hash{ 55 Algorithm: "sha256", 56 Hex: fakeV1Layer.diffID, 57 }, nil 58 } 59 60 // Digest is not used for the purposes of layer scanning, thus an empty hash is returned. 61 func (fakeV1Layer *FakeV1Layer) Digest() (v1.Hash, error) { 62 return v1.Hash{}, nil 63 } 64 65 // Uncompressed returns the uncompressed tar reader. 66 func (fakeV1Layer *FakeV1Layer) Uncompressed() (io.ReadCloser, error) { 67 if fakeV1Layer.failGettingUncompressed { 68 return nil, errors.New("failed to get uncompressed") 69 } 70 return io.NopCloser(bytes.NewBuffer(fakeV1Layer.content)), nil 71 } 72 73 // Compressed is not used for the purposes of layer scanning, thus a nil value is returned. 74 func (fakeV1Layer *FakeV1Layer) Compressed() (io.ReadCloser, error) { 75 return nil, errors.New("not implemented") 76 } 77 78 // Size is not used for the purposes of layer scanning, thus a zero value is returned. 79 func (fakeV1Layer *FakeV1Layer) Size() (int64, error) { 80 return 0, errors.New("not implemented") 81 } 82 83 // MediaType returns a fake media type. 84 func (fakeV1Layer *FakeV1Layer) MediaType() (types.MediaType, error) { 85 return "fake layer", nil 86 } 87 88 // New creates a new FakeV1Layer. 89 func New(t *testing.T, diffID, buildCommand string, isEmpty bool, files map[string]ContentAndMode, failGettingUncompressed bool) *FakeV1Layer { 90 t.Helper() 91 92 var buf bytes.Buffer 93 hasher := sha256.New() 94 mw := io.MultiWriter(&buf, hasher) 95 tarWriter := tar.NewWriter(mw) 96 97 dirWritten := make(map[string]bool) 98 99 // Write all files to tar. 100 for name, cm := range files { 101 content := cm.content 102 mode := int64(cm.mode) 103 104 // Write all directories with more permissions to allow writing folders within directories. 105 dir := filepath.Dir(name) 106 for dir != "" && dir != "." { 107 if err := tarWriter.WriteHeader(&tar.Header{ 108 Typeflag: tar.TypeDir, 109 Name: dir, 110 Mode: int64(fs.FileMode(0766)), 111 }); err != nil { 112 t.Fatalf("tarWriter.WriteHeader: %v", err) 113 } 114 115 dirWritten[dir] = true 116 dir = filepath.Dir(dir) 117 } 118 119 if content == "" { 120 if err := tarWriter.WriteHeader(&tar.Header{ 121 Typeflag: tar.TypeReg, 122 Name: name, 123 Size: 0, 124 Mode: mode, 125 }); err != nil { 126 t.Fatalf("tarWriter.WriteHeader: %v", err) 127 } 128 continue 129 } 130 131 if err := tarWriter.WriteHeader(&tar.Header{ 132 Typeflag: tar.TypeReg, 133 Name: name, 134 Size: int64(len([]byte(content))), 135 Mode: mode, 136 }); err != nil { 137 t.Fatalf("tarWriter.WriteHeader: %v", err) 138 } 139 140 if _, err := tarWriter.Write([]byte(content)); err != nil { 141 t.Fatalf("tarWriter.Write: %v", err) 142 } 143 } 144 145 if err := tarWriter.Close(); err != nil { 146 t.Fatalf("tarWriter.Close: %v", err) 147 } 148 149 return &FakeV1Layer{ 150 diffID: diffID, 151 buildCommand: buildCommand, 152 isEmpty: isEmpty, 153 content: buf.Bytes(), 154 failGettingUncompressed: failGettingUncompressed, 155 } 156 }