@@ -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"
@@ -66,6 +67,7 @@ import (
6667 "github.com/moby/buildkit/util/contentutil"
6768 "github.com/moby/buildkit/util/entitlements"
6869 "github.com/moby/buildkit/util/gitutil/gitobject"
70+ "github.com/moby/buildkit/util/purl"
6971 "github.com/moby/buildkit/util/testutil"
7072 containerdutil "github.com/moby/buildkit/util/testutil/containerd"
7173 "github.com/moby/buildkit/util/testutil/echoserver"
@@ -76,6 +78,7 @@ import (
7678 policyimage "github.com/moby/policy-helpers/image"
7779 digest "github.com/opencontainers/go-digest"
7880 ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
81+ packageurl "github.com/package-url/packageurl-go"
7982 "github.com/pkg/errors"
8083 "github.com/spdx/tools-golang/spdx"
8184 "github.com/stretchr/testify/assert"
@@ -234,6 +237,8 @@ var allTests = []func(t *testing.T, sb integration.Sandbox){
234237 testMultipleRecordsWithSameLayersCacheImportExport ,
235238 testRegistryEmptyCacheExport ,
236239 testSnapshotWithMultipleBlobs ,
240+ testImageBlobSource ,
241+ testOCILayoutBlobSource ,
237242 testExportLocalNoPlatformSplit ,
238243 testExportLocalNoPlatformSplitOverwrite ,
239244 testExportLocalForcePlatformSplit ,
@@ -755,6 +760,9 @@ func testExportBusyboxLocal(t *testing.T, sb integration.Sandbox) {
755760 destDir := t .TempDir ()
756761
757762 _ , err = c .Solve (sb .Context (), def , SolveOpt {
763+ FrontendAttrs : map [string ]string {
764+ "attest:provenance" : "" ,
765+ },
758766 Exports : []ExportEntry {
759767 {
760768 Type : ExporterLocal ,
@@ -11514,6 +11522,212 @@ func testMountStubsTimestamp(t *testing.T, sb integration.Sandbox) {
1151411522 }
1151511523}
1151611524
11525+ func testImageBlobSource (t * testing.T , sb integration.Sandbox ) {
11526+ workers .CheckFeatureCompat (t , sb , workers .FeatureDirectPush )
11527+ requiresLinux (t )
11528+ c , err := New (sb .Context (), sb .Address ())
11529+ require .NoError (t , err )
11530+ defer c .Close ()
11531+
11532+ registry , err := sb .NewRegistry ()
11533+ if errors .Is (err , integration .ErrRequirements ) {
11534+ t .Skip (err .Error ())
11535+ }
11536+ require .NoError (t , err )
11537+
11538+ st := llb .Image ("alpine" )
11539+
11540+ def , err := st .Marshal (sb .Context ())
11541+ require .NoError (t , err )
11542+
11543+ name := registry + "/foo/blobtest:img"
11544+
11545+ _ , err = c .Solve (sb .Context (), def , SolveOpt {
11546+ Exports : []ExportEntry {
11547+ {
11548+ Type : "image" ,
11549+ Attrs : map [string ]string {
11550+ "name" : name ,
11551+ "push" : "true" ,
11552+ },
11553+ },
11554+ },
11555+ }, nil )
11556+ require .NoError (t , err )
11557+
11558+ desc , provider , err := contentutil .ProviderFromRef (name )
11559+ require .NoError (t , err )
11560+
11561+ imgs , err := testutil .ReadImages (sb .Context (), provider , desc )
11562+ require .NoError (t , err )
11563+
11564+ require .Equal (t , 1 , len (imgs .Images ))
11565+ mfst := imgs .Images [0 ].Manifest
11566+ require .GreaterOrEqual (t , len (mfst .Layers ), 1 )
11567+
11568+ l := mfst .Layers [0 ]
11569+
11570+ blob := llb .ImageBlob (registry + "/foo/blobtest@" + l .Digest .String (), llb .Filename ("layer.tar.gz" ), llb .Chown (123 , 456 ))
11571+ 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 ())
11572+
11573+ def , err = st .Marshal (sb .Context ())
11574+ require .NoError (t , err )
11575+
11576+ destDir := t .TempDir ()
11577+
11578+ _ , err = c .Solve (sb .Context (), def , SolveOpt {
11579+ FrontendAttrs : map [string ]string {
11580+ "attest:provenance" : "" ,
11581+ },
11582+ Exports : []ExportEntry {
11583+ {
11584+ Type : ExporterLocal ,
11585+ OutputDir : destDir ,
11586+ },
11587+ },
11588+ }, nil )
11589+ require .NoError (t , err )
11590+
11591+ dt , err := os .ReadFile (filepath .Join (destDir , "stat" ))
11592+ require .NoError (t , err )
11593+
11594+ require .Equal (t , "123-456-" + strconv .FormatInt (l .Size , 10 ), strings .TrimSpace (string (dt )))
11595+
11596+ dt , err = os .ReadFile (filepath .Join (destDir , "checksum" ))
11597+ require .NoError (t , err )
11598+
11599+ require .Equal (t , l .Digest .Hex (), strings .TrimSpace (string (dt )))
11600+
11601+ provDt , err := os .ReadFile (filepath .Join (destDir , "provenance.json" ))
11602+ require .NoError (t , err )
11603+
11604+ var stmt struct {
11605+ intoto.StatementHeader
11606+ Predicate provenancetypes.ProvenancePredicateSLSA1 `json:"predicate"`
11607+ }
11608+ require .NoError (t , json .Unmarshal (provDt , & stmt ))
11609+
11610+ expectedName , err := purl .RefToPURL (packageurl .TypeDocker , registry + "/foo/blobtest@" + l .Digest .String (), nil )
11611+ require .NoError (t , err )
11612+ purlObj , err := packageurl .FromString (expectedName )
11613+ require .NoError (t , err )
11614+ purlObj .Qualifiers = append (purlObj .Qualifiers , packageurl.Qualifier {Key : "ref_type" , Value : "blob" })
11615+ expectedName = purlObj .ToString ()
11616+
11617+ found := false
11618+ for _ , m := range stmt .Predicate .BuildDefinition .ResolvedDependencies {
11619+ if m .URI == expectedName {
11620+ found = true
11621+ require .Equal (t , l .Digest .Hex (), m .Digest ["sha256" ])
11622+ break
11623+ }
11624+ }
11625+ require .True (t , found , "expected to find %q in %+v" , expectedName , stmt .Predicate .BuildDefinition .ResolvedDependencies )
11626+ }
11627+
11628+ func testOCILayoutBlobSource (t * testing.T , sb integration.Sandbox ) {
11629+ workers .CheckFeatureCompat (t , sb , workers .FeatureOCIExporter , workers .FeatureOCILayout )
11630+ requiresLinux (t )
11631+ c , err := New (sb .Context (), sb .Address ())
11632+ require .NoError (t , err )
11633+ defer c .Close ()
11634+
11635+ st := llb .Image ("alpine" )
11636+ def , err := st .Marshal (sb .Context ())
11637+ require .NoError (t , err )
11638+
11639+ ociDir := t .TempDir ()
11640+ _ , err = c .Solve (sb .Context (), def , SolveOpt {
11641+ Exports : []ExportEntry {
11642+ {
11643+ Type : ExporterOCI ,
11644+ Attrs : map [string ]string {
11645+ "tar" : "false" ,
11646+ },
11647+ OutputDir : ociDir ,
11648+ },
11649+ },
11650+ }, nil )
11651+ require .NoError (t , err )
11652+
11653+ indexDt , err := os .ReadFile (filepath .Join (ociDir , ocispecs .ImageIndexFile ))
11654+ require .NoError (t , err )
11655+
11656+ var index ocispecs.Index
11657+ err = json .Unmarshal (indexDt , & index )
11658+ require .NoError (t , err )
11659+ require .Equal (t , 1 , len (index .Manifests ))
11660+
11661+ var mfst ocispecs.Manifest
11662+ mfstDt , err := os .ReadFile (filepath .Join (ociDir , "blobs/sha256" , index .Manifests [0 ].Digest .Hex ()))
11663+ require .NoError (t , err )
11664+ err = json .Unmarshal (mfstDt , & mfst )
11665+ require .NoError (t , err )
11666+ require .GreaterOrEqual (t , len (mfst .Layers ), 1 )
11667+ layer := mfst .Layers [0 ]
11668+
11669+ store , err := local .NewStore (ociDir )
11670+ require .NoError (t , err )
11671+ csID := "my-blob-content-store"
11672+
11673+ blob := llb .OCILayoutBlob ("not/real@" + layer .Digest .String (), llb .ImageBlobOCIStore ("" , csID ), llb .Filename ("layer.tar.gz" ), llb .Chown (123 , 456 ))
11674+ 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 ())
11675+
11676+ def , err = st .Marshal (sb .Context ())
11677+ require .NoError (t , err )
11678+
11679+ destDir := t .TempDir ()
11680+ _ , err = c .Solve (sb .Context (), def , SolveOpt {
11681+ FrontendAttrs : map [string ]string {
11682+ "attest:provenance" : "" ,
11683+ },
11684+ Exports : []ExportEntry {
11685+ {
11686+ Type : ExporterLocal ,
11687+ OutputDir : destDir ,
11688+ },
11689+ },
11690+ OCIStores : map [string ]content.Store {
11691+ csID : store ,
11692+ },
11693+ }, nil )
11694+ require .NoError (t , err )
11695+
11696+ dt , err := os .ReadFile (filepath .Join (destDir , "stat" ))
11697+ require .NoError (t , err )
11698+ require .Equal (t , "123-456-" + strconv .FormatInt (layer .Size , 10 ), strings .TrimSpace (string (dt )))
11699+
11700+ dt , err = os .ReadFile (filepath .Join (destDir , "checksum" ))
11701+ require .NoError (t , err )
11702+ require .Equal (t , layer .Digest .Hex (), strings .TrimSpace (string (dt )))
11703+
11704+ provDt , err := os .ReadFile (filepath .Join (destDir , "provenance.json" ))
11705+ require .NoError (t , err )
11706+
11707+ var stmt struct {
11708+ intoto.StatementHeader
11709+ Predicate provenancetypes.ProvenancePredicateSLSA1 `json:"predicate"`
11710+ }
11711+ require .NoError (t , json .Unmarshal (provDt , & stmt ))
11712+
11713+ expectedName , err := purl .RefToPURL (packageurl .TypeOCI , "not/real@" + layer .Digest .String (), nil )
11714+ require .NoError (t , err )
11715+ purlObj , err := packageurl .FromString (expectedName )
11716+ require .NoError (t , err )
11717+ purlObj .Qualifiers = append (purlObj .Qualifiers , packageurl.Qualifier {Key : "ref_type" , Value : "blob" })
11718+ expectedName = purlObj .ToString ()
11719+
11720+ found := false
11721+ for _ , m := range stmt .Predicate .BuildDefinition .ResolvedDependencies {
11722+ if m .URI == expectedName {
11723+ found = true
11724+ require .Equal (t , layer .Digest .Hex (), m .Digest ["sha256" ])
11725+ break
11726+ }
11727+ }
11728+ require .True (t , found , "expected to find %q in %+v" , expectedName , stmt .Predicate .BuildDefinition .ResolvedDependencies )
11729+ }
11730+
1151711731func testFrontendVerifyPlatforms (t * testing.T , sb integration.Sandbox ) {
1151811732 c , err := New (sb .Context (), sb .Address ())
1151911733 require .NoError (t , err )
0 commit comments