diff --git a/client/client_test.go b/client/client_test.go index c2d8cce253fb..495283c34288 100644 --- a/client/client_test.go +++ b/client/client_test.go @@ -206,6 +206,7 @@ func TestIntegration(t *testing.T) { testMultipleRecordsWithSameLayersCacheImportExport, testExportLocalNoPlatformSplit, testExportLocalNoPlatformSplitOverwrite, + testValidateNullConfig, ) } diff --git a/client/validation_test.go b/client/validation_test.go new file mode 100644 index 000000000000..40cde42a532f --- /dev/null +++ b/client/validation_test.go @@ -0,0 +1,50 @@ +package client + +import ( + "context" + "io" + "testing" + + "github.com/moby/buildkit/client/llb" + "github.com/moby/buildkit/frontend/gateway/client" + "github.com/moby/buildkit/util/testutil/integration" + "github.com/stretchr/testify/require" +) + +func testValidateNullConfig(t *testing.T, sb integration.Sandbox) { + requiresLinux(t) + + ctx := sb.Context() + + c, err := New(ctx, sb.Address()) + require.NoError(t, err) + defer c.Close() + + b := func(ctx context.Context, c client.Client) (*client.Result, error) { + def, err := llb.Scratch().Marshal(ctx) + if err != nil { + return nil, err + } + + res, err := c.Solve(ctx, client.SolveRequest{ + Evaluate: true, + Definition: def.ToPB(), + }) + if err != nil { + return nil, err + } + res.AddMeta("containerimage.config", []byte("null")) + return res, nil + } + + _, err = c.Build(ctx, SolveOpt{ + Exports: []ExportEntry{ + { + Type: ExporterOCI, + Output: fixedWriteCloser(nopWriteCloser{io.Discard}), + }, + }, + }, "", b, nil) + require.Error(t, err) + require.Contains(t, err.Error(), "invalid null image config for export") +} diff --git a/exporter/containerimage/writer.go b/exporter/containerimage/writer.go index 186f415b18c8..05b8a28477e8 100644 --- a/exporter/containerimage/writer.go +++ b/exporter/containerimage/writer.go @@ -569,11 +569,20 @@ func parseHistoryFromConfig(dt []byte) ([]ocispecs.History, error) { } func patchImageConfig(dt []byte, descs []ocispecs.Descriptor, history []ocispecs.History, cache []byte, epoch *time.Time) ([]byte, error) { + var img ocispecs.Image + if err := json.Unmarshal(dt, &img); err != nil { + return nil, errors.Wrap(err, "invalid image config for export") + } + m := map[string]json.RawMessage{} if err := json.Unmarshal(dt, &m); err != nil { return nil, errors.Wrap(err, "failed to parse image config for patch") } + if m == nil { + return nil, errors.Errorf("invalid null image config for export") + } + var rootFS ocispecs.RootFS rootFS.Type = "layers" for _, desc := range descs {