@@ -21,9 +21,6 @@ import (
2121
2222 contractAPI "github.com/chainloop-dev/chainloop/app/controlplane/api/workflowcontract/v1"
2323 "github.com/chainloop-dev/chainloop/pkg/attestation/crafter/materials"
24- "github.com/google/go-containerregistry/pkg/v1/empty"
25- "github.com/google/go-containerregistry/pkg/v1/layout"
26- "github.com/google/go-containerregistry/pkg/v1/random"
2724 "github.com/rs/zerolog"
2825 "github.com/stretchr/testify/assert"
2926 "github.com/stretchr/testify/require"
@@ -65,50 +62,40 @@ func TestNewOCIImageCrafter(t *testing.T) {
6562
6663func TestOCIImageCraft_Layout (t * testing.T ) {
6764 testCases := []struct {
68- name string
69- setupLayout func ( t * testing. T ) string
70- wantErr string
71- wantDigest string
72- wantName string
73- wantTag string
65+ name string
66+ layoutPath string
67+ wantErr string
68+ wantDigest string
69+ wantName string
70+ wantTag string
7471 }{
7572 {
76- name : "valid OCI layout" ,
77- setupLayout : func (t * testing.T ) string {
78- return createTestOCILayout (t , "test-image" , "v1.0.0" )
79- },
80- wantName : "test-image" ,
81- wantTag : "v1.0.0" ,
73+ name : "crane - single image with annotations" ,
74+ layoutPath : "testdata/oci-layouts/crane" ,
75+ wantName : "oci-layout" ,
76+ wantDigest : "sha256:fa6d9058c3d65a33ff565c0e35172f2d99e76fbf8358d91ffaa2208eff2be400" ,
8277 },
8378 {
84- name : "OCI layout without annotations" ,
85- setupLayout : func (t * testing.T ) string {
86- return createTestOCILayout (t , "" , "" )
87- },
88- wantName : "oci-layout" ,
89- wantTag : "" ,
79+ name : "skopeo - single image with tag annotation" ,
80+ layoutPath : "testdata/oci-layouts/skopeo" ,
81+ wantName : "v1.51.0" ,
82+ wantDigest : "sha256:fa6d9058c3d65a33ff565c0e35172f2d99e76fbf8358d91ffaa2208eff2be400" ,
9083 },
9184 {
92- name : "non-existent path" ,
93- setupLayout : func (_ * testing.T ) string {
94- return "/non/existent/path"
95- },
96- wantErr : "UNAUTHORIZED" ,
85+ name : "skopeo-alt - alternative format" ,
86+ layoutPath : "testdata/oci-layouts/skopeo-alt" ,
87+ wantName : "v1.51.0" ,
88+ wantDigest : "sha256:a5303ef28a4bd9b6e06aa92c07831dd151ac64172695971226bdba4a11fc1b88" ,
9789 },
9890 {
99- name : "empty directory" ,
100- setupLayout : func (t * testing.T ) string {
101- dir := t .TempDir ()
102- return dir
103- },
104- wantErr : "could not parse reference" ,
91+ name : "non-existent path" ,
92+ layoutPath : "/non/existent/path" ,
93+ wantErr : "UNAUTHORIZED" ,
10594 },
10695 }
10796
10897 for _ , tc := range testCases {
10998 t .Run (tc .name , func (t * testing.T ) {
110- layoutPath := tc .setupLayout (t )
111-
11299 schema := & contractAPI.CraftingSchema_Material {
113100 Name : "test" ,
114101 Type : contractAPI .CraftingSchema_Material_CONTAINER_IMAGE ,
@@ -117,7 +104,7 @@ func TestOCIImageCraft_Layout(t *testing.T) {
117104 crafter , err := materials .NewOCIImageCrafter (schema , nil , & l )
118105 require .NoError (t , err )
119106
120- got , err := crafter .Craft (context .TODO (), layoutPath )
107+ got , err := crafter .Craft (context .TODO (), tc . layoutPath )
121108 if tc .wantErr != "" {
122109 assert .ErrorContains (t , err , tc .wantErr )
123110 return
@@ -130,63 +117,71 @@ func TestOCIImageCraft_Layout(t *testing.T) {
130117 containerImage := got .GetContainerImage ()
131118 require .NotNil (t , containerImage )
132119 assert .Equal (t , tc .wantName , containerImage .Name )
133- assert .Equal (t , tc .wantTag , containerImage .Tag )
134- assert .NotEmpty (t , containerImage .Digest )
135- assert .True (t , len (containerImage .Digest ) > 0 , "digest should not be empty" )
120+ if tc .wantTag != "" {
121+ assert .Equal (t , tc .wantTag , containerImage .Tag )
122+ }
123+ if tc .wantDigest != "" {
124+ assert .Equal (t , tc .wantDigest , containerImage .Digest )
125+ } else {
126+ assert .NotEmpty (t , containerImage .Digest )
127+ }
136128 })
137129 }
138130}
139131
140132func TestOCIImageCraft_LayoutWithDigestSelector (t * testing.T ) {
141133 testCases := []struct {
142- name string
143- setupLayout func (t * testing.T ) (string , string ) // returns (layoutPath, digestToSelect)
144- wantErr string
145- wantName string
146- wantTag string
134+ name string
135+ layoutPath string
136+ digestSelector string
137+ wantErr string
138+ wantName string
139+ wantDigest string
147140 }{
148141 {
149- name : "select second image by digest" ,
150- setupLayout : func (t * testing.T ) (string , string ) {
151- layoutPath , digests := createTestOCILayoutMultiple (t , []imageSpec {
152- {name : "first-image" , tag : "v1.0.0" },
153- {name : "second-image" , tag : "v2.0.0" },
154- })
155- return layoutPath , digests [1 ] // Select second image
156- },
157- wantName : "second-image" ,
158- wantTag : "v2.0.0" ,
142+ name : "oras - select first image by digest" ,
143+ layoutPath : "testdata/oci-layouts/oras" ,
144+ digestSelector : "sha256:b1747c197a0ab3cb89e109f60a3c5d4ede6946e447fd468fa82d85fa94c6c6e5" ,
145+ wantName : "oci-layout" ,
146+ wantDigest : "sha256:b1747c197a0ab3cb89e109f60a3c5d4ede6946e447fd468fa82d85fa94c6c6e5" ,
159147 },
160148 {
161- name : "digest not found" ,
162- setupLayout : func (t * testing.T ) (string , string ) {
163- layoutPath , _ := createTestOCILayoutMultiple (t , []imageSpec {
164- {name : "test-image" , tag : "v1.0.0" },
165- })
166- return layoutPath , "sha256:nonexistent"
167- },
168- wantErr : "not found in OCI layout" ,
149+ name : "oras - select second image by digest" ,
150+ layoutPath : "testdata/oci-layouts/oras" ,
151+ digestSelector : "sha256:f333056ac987169b2a121c16d06112d88ec3d7cb50b098bb17b0f14b0c52f6f3" ,
152+ wantName : "oci-layout" ,
153+ wantDigest : "sha256:f333056ac987169b2a121c16d06112d88ec3d7cb50b098bb17b0f14b0c52f6f3" ,
169154 },
170155 {
171- name : "multiple images without digest selector" ,
172- setupLayout : func (t * testing.T ) (string , string ) {
173- layoutPath , _ := createTestOCILayoutMultiple (t , []imageSpec {
174- {name : "first-image" , tag : "v1.0.0" },
175- {name : "second-image" , tag : "v2.0.0" },
176- {name : "third-image" , tag : "v3.0.0" },
177- })
178- return layoutPath , "" // No digest selector
179- },
180- wantErr : "contains 3 images, please specify which one" ,
156+ name : "zarf - select specific image from bundle" ,
157+ layoutPath : "testdata/oci-layouts/zarf" ,
158+ digestSelector : "sha256:e8ac056f7b9b44b07935fe23b8383e5e550d479dc5c6261941e76449a8f7e926" ,
159+ wantName : "ghcr.io/chainloop-dev/chainloop/artifact-cas:v1.51.0" ,
160+ wantDigest : "sha256:e8ac056f7b9b44b07935fe23b8383e5e550d479dc5c6261941e76449a8f7e926" ,
161+ },
162+ {
163+ name : "digest not found" ,
164+ layoutPath : "testdata/oci-layouts/oras" ,
165+ digestSelector : "sha256:nonexistent" ,
166+ wantErr : "not found in OCI layout" ,
167+ },
168+ {
169+ name : "oras - multiple images without digest selector" ,
170+ layoutPath : "testdata/oci-layouts/oras" ,
171+ wantErr : "contains 3 images, please specify which one" ,
172+ },
173+ {
174+ name : "zarf - multiple images without digest selector" ,
175+ layoutPath : "testdata/oci-layouts/zarf" ,
176+ wantErr : "contains 3 images, please specify which one" ,
181177 },
182178 }
183179
184180 for _ , tc := range testCases {
185181 t .Run (tc .name , func (t * testing.T ) {
186- layoutPath , digest := tc .setupLayout (t )
187- imageRef := layoutPath
188- if digest != "" {
189- imageRef = layoutPath + "@" + digest
182+ imageRef := tc .layoutPath
183+ if tc .digestSelector != "" {
184+ imageRef = tc .layoutPath + "@" + tc .digestSelector
190185 }
191186
192187 schema := & contractAPI.CraftingSchema_Material {
@@ -209,87 +204,14 @@ func TestOCIImageCraft_LayoutWithDigestSelector(t *testing.T) {
209204 // Check container image fields
210205 containerImage := got .GetContainerImage ()
211206 require .NotNil (t , containerImage )
212- assert .Equal (t , tc .wantName , containerImage .Name )
213- assert .Equal (t , tc .wantTag , containerImage .Tag )
214- assert .NotEmpty (t , containerImage .Digest )
215- })
216- }
217- }
218-
219- type imageSpec struct {
220- name string
221- tag string
222- }
223-
224- // createTestOCILayoutMultiple creates an OCI layout with multiple images for testing
225- func createTestOCILayoutMultiple (t * testing.T , specs []imageSpec ) (string , []string ) {
226- t .Helper ()
227-
228- layoutPath := t .TempDir ()
229- path , err := layout .Write (layoutPath , empty .Index )
230- require .NoError (t , err )
231-
232- digests := make ([]string , 0 , len (specs ))
233- for _ , spec := range specs {
234- img , err := random .Image (1024 , 1 )
235- require .NoError (t , err )
236-
237- var opts []layout.Option
238- if spec .name != "" || spec .tag != "" {
239- annotations := make (map [string ]string )
240- if spec .name != "" {
241- annotations ["org.opencontainers.image.ref.name" ] = spec .name
207+ if tc .wantName != "" {
208+ assert .Equal (t , tc .wantName , containerImage .Name )
242209 }
243- if spec .tag != "" {
244- annotations ["io.containerd.image.name" ] = spec .name + ":" + spec .tag
210+ if tc .wantDigest != "" {
211+ assert .Equal (t , tc .wantDigest , containerImage .Digest )
212+ } else {
213+ assert .NotEmpty (t , containerImage .Digest )
245214 }
246- opts = append (opts , layout .WithAnnotations (annotations ))
247- }
248-
249- err = path .AppendImage (img , opts ... )
250- require .NoError (t , err )
251-
252- // Get the digest of the image we just added
253- index , err := path .ImageIndex ()
254- require .NoError (t , err )
255- manifest , err := index .IndexManifest ()
256- require .NoError (t , err )
257- // The last manifest is the one we just added
258- digests = append (digests , manifest .Manifests [len (manifest .Manifests )- 1 ].Digest .String ())
259- }
260-
261- return layoutPath , digests
262- }
263-
264- // createTestOCILayout creates a minimal valid OCI layout directory for testing
265- func createTestOCILayout (t * testing.T , imageName , tag string ) string {
266- t .Helper ()
267-
268- layoutPath := t .TempDir ()
269-
270- // Use go-containerregistry to create a random image
271- img , err := random .Image (1024 , 1 )
272- require .NoError (t , err )
273-
274- // Write layout with empty index first
275- path , err := layout .Write (layoutPath , empty .Index )
276- require .NoError (t , err )
277-
278- // Append the image with annotations if provided
279- var opts []layout.Option
280- if imageName != "" || tag != "" {
281- annotations := make (map [string ]string )
282- if imageName != "" {
283- annotations ["org.opencontainers.image.ref.name" ] = imageName
284- }
285- if tag != "" {
286- annotations ["io.containerd.image.name" ] = imageName + ":" + tag
287- }
288- opts = append (opts , layout .WithAnnotations (annotations ))
215+ })
289216 }
290-
291- err = path .AppendImage (img , opts ... )
292- require .NoError (t , err )
293-
294- return layoutPath
295217}
0 commit comments