Skip to content

Commit 4b081f8

Browse files
authored
Avoid v1.Manifest in crane edit config (#1583)
Because of how omitempty works, an empty Layers and a nil Layers will both be omitted. We don't want that, because different registries support different variants of that. Instead, we just pass through whatever was there before by treating the manifest as a map[string]any and manipulating that rather than using v1.Manifest-based helpers.
1 parent 1cfe1fc commit 4b081f8

File tree

1 file changed

+32
-8
lines changed

1 file changed

+32
-8
lines changed

Diff for: internal/cmd/edit.go

+32-8
Original file line numberDiff line numberDiff line change
@@ -162,15 +162,37 @@ func editConfig(in io.Reader, out io.Writer, src, dst string, options ...crane.O
162162
return nil, err
163163
}
164164

165-
m, err := img.Manifest()
165+
mt, err := img.MediaType()
166166
if err != nil {
167167
return nil, err
168168
}
169-
mt, err := img.MediaType()
169+
170+
// We want to omit Layers in certain situations, so we don't use v1.Image.Manifest() here.
171+
// Instead, we treat the manifest as a map[string]any and just manipulate the config desc.
172+
mb, err := img.RawManifest()
170173
if err != nil {
171174
return nil, err
172175
}
173176

177+
jsonMap := map[string]any{}
178+
if err := json.Unmarshal(mb, &jsonMap); err != nil {
179+
return nil, err
180+
}
181+
182+
cv, ok := jsonMap["config"]
183+
if !ok {
184+
return nil, fmt.Errorf("config missing")
185+
}
186+
cb, err := json.Marshal(cv)
187+
if err != nil {
188+
return nil, fmt.Errorf("json.Marshal config: %w", err)
189+
}
190+
191+
config := v1.Descriptor{}
192+
if err := json.Unmarshal(cb, &config); err != nil {
193+
return nil, fmt.Errorf("json.Unmarshal config: %w", err)
194+
}
195+
174196
var edited []byte
175197
if interactive(in, out) {
176198
rcf, err := img.RawConfigFile()
@@ -190,21 +212,23 @@ func editConfig(in io.Reader, out io.Writer, src, dst string, options ...crane.O
190212
}
191213

192214
// this has to happen before we modify the descriptor (so we can use verify.Descriptor to validate whether m.Config.Data matches m.Config.Digest/Size)
193-
if m.Config.Data != nil && verify.Descriptor(m.Config) == nil {
215+
if config.Data != nil && verify.Descriptor(config) == nil {
194216
// https://github.com/google/go-containerregistry/issues/1552#issuecomment-1452653875
195217
// "if data is non-empty and correct, we should update it"
196-
m.Config.Data = edited
218+
config.Data = edited
197219
}
198220

199-
l := static.NewLayer(edited, m.Config.MediaType)
221+
l := static.NewLayer(edited, config.MediaType)
200222
layerDigest, err := l.Digest()
201223
if err != nil {
202224
return nil, err
203225
}
204226

205-
m.Config.Digest = layerDigest
206-
m.Config.Size = int64(len(edited))
207-
b, err := json.Marshal(m)
227+
config.Digest = layerDigest
228+
config.Size = int64(len(edited))
229+
230+
jsonMap["config"] = config
231+
b, err := json.Marshal(jsonMap)
208232
if err != nil {
209233
return nil, err
210234
}

0 commit comments

Comments
 (0)