From d638d64572e1e0086c4e762aee95c6e7a5db1a9e Mon Sep 17 00:00:00 2001 From: Ben Luddy Date: Wed, 16 Oct 2024 17:42:06 -0400 Subject: [PATCH] Add CBOR serializer option to disable JSON transcoding of raw types. --- .../pkg/runtime/serializer/cbor/cbor.go | 25 ++++++++++++++--- .../pkg/runtime/serializer/cbor/cbor_test.go | 27 +++++++++++++++++++ 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/staging/src/k8s.io/apimachinery/pkg/runtime/serializer/cbor/cbor.go b/staging/src/k8s.io/apimachinery/pkg/runtime/serializer/cbor/cbor.go index 46c1b009491..20fa7eb04cf 100644 --- a/staging/src/k8s.io/apimachinery/pkg/runtime/serializer/cbor/cbor.go +++ b/staging/src/k8s.io/apimachinery/pkg/runtime/serializer/cbor/cbor.go @@ -68,17 +68,30 @@ type Serializer interface { var _ Serializer = &serializer{} type options struct { - strict bool + strict bool + transcode bool } type Option func(*options) +// Strict configures a serializer to return a strict decoding error when it encounters map keys that +// do not correspond to a field in the target object of a decode operation. This option is disabled +// by default. func Strict(s bool) Option { return func(opts *options) { opts.strict = s } } +// Transcode configures a serializer to transcode the "raw" bytes of a decoded runtime.RawExtension +// or metav1.FieldsV1 object to JSON. This is enabled by default to support existing programs that +// depend on the assumption that objects of either type contain valid JSON. +func Transcode(s bool) Option { + return func(opts *options) { + opts.transcode = s + } +} + type serializer struct { metaFactory metaFactory creater runtime.ObjectCreater @@ -88,6 +101,8 @@ type serializer struct { func (serializer) private() {} +// NewSerializer creates and returns a serializer configured with the provided options. The default +// options are equivalent to explicitly passing Strict(false) and Transcode(true). func NewSerializer(creater runtime.ObjectCreater, typer runtime.ObjectTyper, options ...Option) Serializer { return newSerializer(&defaultMetaFactory{}, creater, typer, options...) } @@ -98,6 +113,7 @@ func newSerializer(metaFactory metaFactory, creater runtime.ObjectCreater, typer creater: creater, typer: typer, } + s.options.transcode = true for _, o := range options { o(&s.options) } @@ -337,9 +353,10 @@ func (s *serializer) Decode(data []byte, gvk *schema.GroupVersionKind, into runt return nil, actual, err } - // TODO: Make possible to disable this behavior. - if err := transcodeRawTypes(obj); err != nil { - return nil, actual, err + if s.options.transcode { + if err := transcodeRawTypes(obj); err != nil { + return nil, actual, err + } } return obj, actual, strict diff --git a/staging/src/k8s.io/apimachinery/pkg/runtime/serializer/cbor/cbor_test.go b/staging/src/k8s.io/apimachinery/pkg/runtime/serializer/cbor/cbor_test.go index a47858c6ad9..23894a06258 100644 --- a/staging/src/k8s.io/apimachinery/pkg/runtime/serializer/cbor/cbor_test.go +++ b/staging/src/k8s.io/apimachinery/pkg/runtime/serializer/cbor/cbor_test.go @@ -345,6 +345,33 @@ func TestDecode(t *testing.T) { } }, }, + { + name: "raw types not transcoded", + options: []Option{Transcode(false)}, + data: []byte{0xa4, 0x41, 'f', 0xa1, 0x41, 'a', 0x01, 0x42, 'f', 'p', 0xa1, 0x41, 'z', 0x02, 0x41, 'r', 0xa1, 0x41, 'b', 0x03, 0x42, 'r', 'p', 0xa1, 0x41, 'y', 0x04}, + gvk: &schema.GroupVersionKind{}, + metaFactory: stubMetaFactory{gvk: &schema.GroupVersionKind{}}, + typer: stubTyper{gvks: []schema.GroupVersionKind{{Group: "x", Version: "y", Kind: "z"}}}, + into: &structWithRawFields{}, + expectedObj: &structWithRawFields{ + FieldsV1: metav1.FieldsV1{Raw: []byte{0xa1, 0x41, 'a', 0x01}}, + FieldsV1Pointer: &metav1.FieldsV1{Raw: []byte{0xa1, 0x41, 'z', 0x02}}, + // RawExtension's UnmarshalCBOR ensures the self-described CBOR tag + // is present in the result so that there is never any ambiguity in + // distinguishing CBOR from JSON or Protobuf. It is unnecessary for + // FieldsV1 to do the same because the initial byte is always + // sufficient to distinguish a valid JSON-encoded FieldsV1 from a + // valid CBOR-encoded FieldsV1. + RawExtension: runtime.RawExtension{Raw: []byte{0xd9, 0xd9, 0xf7, 0xa1, 0x41, 'b', 0x03}}, + RawExtensionPointer: &runtime.RawExtension{Raw: []byte{0xd9, 0xd9, 0xf7, 0xa1, 0x41, 'y', 0x04}}, + }, + expectedGVK: &schema.GroupVersionKind{Group: "x", Version: "y", Kind: "z"}, + assertOnError: func(t *testing.T, err error) { + if err != nil { + t.Errorf("expected nil error, got: %v", err) + } + }, + }, { name: "object with embedded typemeta and objectmeta", data: []byte("\xa2\x48metadata\xa1\x44name\x43foo\x44spec\xa0"), // {"metadata": {"name": "foo"}}