@@ -58,6 +58,7 @@ import (
5858 "github.com/moby/buildkit/session/secrets/secretsprovider"
5959 "github.com/moby/buildkit/session/sshforward/sshprovider"
6060 "github.com/moby/buildkit/solver/errdefs"
61+ provenancetypes "github.com/moby/buildkit/solver/llbsolver/provenance/types"
6162 "github.com/moby/buildkit/solver/pb"
6263 "github.com/moby/buildkit/solver/result"
6364 "github.com/moby/buildkit/sourcepolicy"
@@ -236,6 +237,7 @@ var allTests = []func(t *testing.T, sb integration.Sandbox){
236237 testRegistryEmptyCacheExport ,
237238 testSnapshotWithMultipleBlobs ,
238239 testImageBlobSource ,
240+ testOCILayoutBlobSource ,
239241 testExportLocalNoPlatformSplit ,
240242 testExportLocalNoPlatformSplitOverwrite ,
241243 testExportLocalForcePlatformSplit ,
@@ -756,6 +758,9 @@ func testExportBusyboxLocal(t *testing.T, sb integration.Sandbox) {
756758 destDir := t .TempDir ()
757759
758760 _ , err = c .Solve (sb .Context (), def , SolveOpt {
761+ FrontendAttrs : map [string ]string {
762+ "attest:provenance" : "" ,
763+ },
759764 Exports : []ExportEntry {
760765 {
761766 Type : ExporterLocal ,
@@ -11508,12 +11513,8 @@ func testImageBlobSource(t *testing.T, sb integration.Sandbox) {
1150811513 require .NoError (t , err )
1150911514
1151011515 var stmt struct {
11511- Predicate struct {
11512- Materials []struct {
11513- URI string `json:"uri"`
11514- Digest map [string ]string `json:"digest"`
11515- } `json:"materials"`
11516- } `json:"predicate"`
11516+ intoto.StatementHeader
11517+ Predicate provenancetypes.ProvenancePredicateSLSA02 `json:"predicate"`
1151711518 }
1151811519 require .NoError (t , json .Unmarshal (provDt , & stmt ))
1151911520
@@ -11535,6 +11536,109 @@ func testImageBlobSource(t *testing.T, sb integration.Sandbox) {
1153511536 require .True (t , found , "expected to find %q in %+v" , expectedName , stmt .Predicate .Materials )
1153611537}
1153711538
11539+ func testOCILayoutBlobSource (t * testing.T , sb integration.Sandbox ) {
11540+ workers .CheckFeatureCompat (t , sb , workers .FeatureOCIExporter , workers .FeatureOCILayout )
11541+ requiresLinux (t )
11542+ c , err := New (sb .Context (), sb .Address ())
11543+ require .NoError (t , err )
11544+ defer c .Close ()
11545+
11546+ st := llb .Image ("alpine" )
11547+ def , err := st .Marshal (sb .Context ())
11548+ require .NoError (t , err )
11549+
11550+ ociDir := t .TempDir ()
11551+ _ , err = c .Solve (sb .Context (), def , SolveOpt {
11552+ Exports : []ExportEntry {
11553+ {
11554+ Type : ExporterOCI ,
11555+ Attrs : map [string ]string {
11556+ "tar" : "false" ,
11557+ },
11558+ OutputDir : ociDir ,
11559+ },
11560+ },
11561+ }, nil )
11562+ require .NoError (t , err )
11563+
11564+ indexDt , err := os .ReadFile (filepath .Join (ociDir , ocispecs .ImageIndexFile ))
11565+ require .NoError (t , err )
11566+
11567+ var index ocispecs.Index
11568+ err = json .Unmarshal (indexDt , & index )
11569+ require .NoError (t , err )
11570+ require .Equal (t , 1 , len (index .Manifests ))
11571+
11572+ var mfst ocispecs.Manifest
11573+ mfstDt , err := os .ReadFile (filepath .Join (ociDir , "blobs/sha256" , index .Manifests [0 ].Digest .Hex ()))
11574+ require .NoError (t , err )
11575+ err = json .Unmarshal (mfstDt , & mfst )
11576+ require .NoError (t , err )
11577+ require .GreaterOrEqual (t , len (mfst .Layers ), 1 )
11578+ layer := mfst .Layers [0 ]
11579+
11580+ store , err := local .NewStore (ociDir )
11581+ require .NoError (t , err )
11582+ csID := "my-blob-content-store"
11583+
11584+ blob := llb .OCILayoutBlob ("not/real@" + layer .Digest .String (), llb .ImageBlobOCIStore ("" , csID ), llb .Filename ("layer.tar.gz" ), llb .Chown (123 , 456 ))
11585+ st = llb .Image ("alpine" ).Run (llb .Shlex (`sh -c 'sha256sum /layers/layer.tar.gz | cut -d" " -f0 > /out/checksum && stat -c "%u-%g-%s" /layers/layer.tar.gz > /out/stat'` ), llb .AddMount ("/layers" , blob , llb .Readonly )).AddMount ("/out" , llb .Scratch ())
11586+
11587+ def , err = st .Marshal (sb .Context ())
11588+ require .NoError (t , err )
11589+
11590+ destDir := t .TempDir ()
11591+ _ , err = c .Solve (sb .Context (), def , SolveOpt {
11592+ FrontendAttrs : map [string ]string {
11593+ "attest:provenance" : "" ,
11594+ },
11595+ Exports : []ExportEntry {
11596+ {
11597+ Type : ExporterLocal ,
11598+ OutputDir : destDir ,
11599+ },
11600+ },
11601+ OCIStores : map [string ]content.Store {
11602+ csID : store ,
11603+ },
11604+ }, nil )
11605+ require .NoError (t , err )
11606+
11607+ dt , err := os .ReadFile (filepath .Join (destDir , "stat" ))
11608+ require .NoError (t , err )
11609+ require .Equal (t , "123-456-" + strconv .FormatInt (layer .Size , 10 ), strings .TrimSpace (string (dt )))
11610+
11611+ dt , err = os .ReadFile (filepath .Join (destDir , "checksum" ))
11612+ require .NoError (t , err )
11613+ require .Equal (t , layer .Digest .Hex (), strings .TrimSpace (string (dt )))
11614+
11615+ provDt , err := os .ReadFile (filepath .Join (destDir , "provenance.json" ))
11616+ require .NoError (t , err )
11617+
11618+ var stmt struct {
11619+ intoto.StatementHeader
11620+ Predicate provenancetypes.ProvenancePredicateSLSA02 `json:"predicate"`
11621+ }
11622+ require .NoError (t , json .Unmarshal (provDt , & stmt ))
11623+
11624+ expectedName , err := purl .RefToPURL (packageurl .TypeOCI , "not/real@" + layer .Digest .String (), nil )
11625+ require .NoError (t , err )
11626+ purlObj , err := packageurl .FromString (expectedName )
11627+ require .NoError (t , err )
11628+ purlObj .Qualifiers = append (purlObj .Qualifiers , packageurl.Qualifier {Key : "ref_type" , Value : "blob" })
11629+ expectedName = purlObj .ToString ()
11630+
11631+ found := false
11632+ for _ , m := range stmt .Predicate .Materials {
11633+ if m .URI == expectedName {
11634+ found = true
11635+ require .Equal (t , layer .Digest .Hex (), m .Digest ["sha256" ])
11636+ break
11637+ }
11638+ }
11639+ require .True (t , found , "expected to find %q in %+v" , expectedName , stmt .Predicate .Materials )
11640+ }
11641+
1153811642func testFrontendVerifyPlatforms (t * testing.T , sb integration.Sandbox ) {
1153911643 c , err := New (sb .Context (), sb .Address ())
1154011644 require .NoError (t , err )
0 commit comments