@@ -23,6 +23,7 @@ import (
2323 "path"
2424 "path/filepath"
2525 "runtime"
26+ "sort"
2627 "strconv"
2728 "strings"
2829 "sync"
@@ -246,6 +247,7 @@ var allTests = []func(t *testing.T, sb integration.Sandbox){
246247 testExportLocalNoPlatformSplit ,
247248 testExportLocalNoPlatformSplitOverwrite ,
248249 testExportLocalForcePlatformSplit ,
250+ testExportTarPlatformIDSanitized ,
249251 testExportLocalModeCopyKeepsStaleDestinationFiles ,
250252 testExportLocalModeDeleteRemovesStaleDestinationFiles ,
251253 testExportLocalModeCopyMultiPlatformKeepsAllPlatforms ,
@@ -8093,6 +8095,90 @@ func testExportLocalForcePlatformSplit(t *testing.T, sb integration.Sandbox) {
80938095 require .Equal (t , "hello" , string (dt ))
80948096}
80958097
8098+ func testExportTarPlatformIDSanitized (t * testing.T , sb integration.Sandbox ) {
8099+ workers .CheckFeatureCompat (t , sb , workers .FeatureOCIExporter , workers .FeatureMultiPlatform )
8100+ c , err := New (sb .Context (), sb .Address ())
8101+ require .NoError (t , err )
8102+ defer c .Close ()
8103+
8104+ const platformID = `..\buildkit-outside`
8105+ platform := platforms .DefaultSpec ()
8106+
8107+ frontend := func (ctx context.Context , c gateway.Client ) (* gateway.Result , error ) {
8108+ st := llb .Scratch ().File (
8109+ llb .Mkfile ("payload.txt" , 0600 , []byte ("payload" )),
8110+ )
8111+
8112+ def , err := st .Marshal (ctx )
8113+ if err != nil {
8114+ return nil , err
8115+ }
8116+
8117+ r , err := c .Solve (ctx , gateway.SolveRequest {
8118+ Definition : def .ToPB (),
8119+ })
8120+ if err != nil {
8121+ return nil , err
8122+ }
8123+
8124+ ref , err := r .SingleRef ()
8125+ if err != nil {
8126+ return nil , err
8127+ }
8128+
8129+ res := gateway .NewResult ()
8130+ res .AddRef (platformID , ref )
8131+
8132+ dt , err := json .Marshal (& exptypes.Platforms {
8133+ Platforms : []exptypes.Platform {{
8134+ ID : platformID ,
8135+ Platform : platform ,
8136+ }},
8137+ })
8138+ if err != nil {
8139+ return nil , err
8140+ }
8141+ res .AddMeta (exptypes .ExporterPlatformsKey , dt )
8142+
8143+ return res , nil
8144+ }
8145+
8146+ outW := bytes .NewBuffer (nil )
8147+ _ , err = c .Build (sb .Context (), SolveOpt {
8148+ Exports : []ExportEntry {
8149+ {
8150+ Type : ExporterTar ,
8151+ Output : fixedWriteCloser (& iohelper.NopWriteCloser {Writer : outW }),
8152+ },
8153+ },
8154+ }, "" , frontend , nil )
8155+ require .NoError (t , err )
8156+
8157+ m , err := testutil .ReadTarToMap (outW .Bytes (), false )
8158+ require .NoError (t , err )
8159+
8160+ for name := range m {
8161+ require .Falsef (t , strings .HasPrefix (name , "../" ) ||
8162+ strings .HasPrefix (name , `..\` ) ||
8163+ strings .Contains (name , `/../` ) ||
8164+ strings .Contains (name , `\..\` ) ||
8165+ strings .Contains (name , `\` ) ||
8166+ strings .Contains (name , ":" ),
8167+ "tar exporter emitted unsafe platform path %q" , name )
8168+ }
8169+
8170+ tarPaths := make ([]string , 0 , len (m ))
8171+ for name := range m {
8172+ tarPaths = append (tarPaths , name )
8173+ }
8174+ sort .Strings (tarPaths )
8175+
8176+ expectedPath := path .Join (".._buildkit-outside" , integration .UnixOrWindows ("payload.txt" , "Files/payload.txt" ))
8177+ item := m [expectedPath ]
8178+ require .NotNilf (t , item , "expected sanitized tar path %q in %v" , expectedPath , tarPaths )
8179+ require .Equal (t , "payload" , string (item .Data ))
8180+ }
8181+
80968182func testExportLocalModeCopyKeepsStaleDestinationFiles (t * testing.T , sb integration.Sandbox ) {
80978183 c , err := New (sb .Context (), sb .Address ())
80988184 require .NoError (t , err )
0 commit comments