From 285e137aa48de3f2da6534baf92782059b544ba9 Mon Sep 17 00:00:00 2001 From: Justin Chadwell Date: Fri, 27 Jan 2023 10:31:07 +0000 Subject: [PATCH] manifest: explicitly error if whitespace reconstruction has failed This behavior should not break any more use cases than before. Previously, if the mismatch occured, we would actually push a manifest that we then never referred to in the manifest list! If this was done in a new repository, the command would fail with an obscure error from the registry - the content wouldn't exist with the descriptor we expect it to. Signed-off-by: Justin Chadwell --- cli/command/manifest/push.go | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/cli/command/manifest/push.go b/cli/command/manifest/push.go index 7091a2d804..848f18c8f0 100644 --- a/cli/command/manifest/push.go +++ b/cli/command/manifest/push.go @@ -218,28 +218,41 @@ func buildPutManifestRequest(imageManifest types.ImageManifest, targetRef refere return mountRequest{}, err } + // Attempt to reconstruct indentation of the manifest to ensure sha parity + // with the registry. + // + // This is necessary because our previous internal storage format did not + // preserve whitespace. If we don't have the newer format present, we can + // attempt the reconstruction like before, but explicitly error if the + // reconstruction failed! switch { case imageManifest.SchemaV2Manifest != nil: - // This indentation has to be added to ensure sha parity with the registry dt, err := json.MarshalIndent(imageManifest.SchemaV2Manifest, "", " ") if err != nil { return mountRequest{}, err } - // indent only the DeserializedManifest portion of this, in order to maintain parity with the registry - // and not alter the sha + + dig := imageManifest.Descriptor.Digest + if dig2 := dig.Algorithm().FromBytes(dt); dig != dig2 { + return mountRequest{}, errors.Errorf("internal digest mismatch for %s: expected %s, got %s", imageManifest.Ref, dig, dig2) + } + var manifest schema2.DeserializedManifest if err = manifest.UnmarshalJSON(dt); err != nil { return mountRequest{}, err } imageManifest.SchemaV2Manifest = &manifest case imageManifest.OCIManifest != nil: - // This indentation has to be added to ensure sha parity with the registry dt, err := json.MarshalIndent(imageManifest.OCIManifest, "", " ") if err != nil { return mountRequest{}, err } - // indent only the DeserializedManifest portion of this, in order to maintain parity with the registry - // and not alter the sha + + dig := imageManifest.Descriptor.Digest + if dig2 := dig.Algorithm().FromBytes(dt); dig != dig2 { + return mountRequest{}, errors.Errorf("internal digest mismatch for %s: expected %s, got %s", imageManifest.Ref, dig, dig2) + } + var manifest ocischema.DeserializedManifest if err = manifest.UnmarshalJSON(dt); err != nil { return mountRequest{}, err