Skip to content

Commit

Permalink
Error on custom (un)marshalers without a CBOR implementation.
Browse files Browse the repository at this point in the history
When CBOR marshaling or unmarshaling a type that implements any of TextMarshaler, TextUnmarshaler,
json.Marshaler, or json.Unmarshaler, without also implementing the corresponding CBOR interface, the
proposed behavior is to automatically use the available interface method by transcoding between CBOR
and JSON or text. As a safety measure, values of these types will be rejected by the CBOR serializer
until that is implemented.

Kubernetes-commit: 40c283908358c7af82f14ba3ea77960d5caf42d9
  • Loading branch information
benluddy authored and k8s-publishing-bot committed Apr 30, 2024
1 parent 4524748 commit c485170
Show file tree
Hide file tree
Showing 4 changed files with 664 additions and 4 deletions.
14 changes: 10 additions & 4 deletions pkg/runtime/serializer/cbor/cbor.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,15 +118,19 @@ func (s *serializer) Encode(obj runtime.Object, w io.Writer) error {
}

func (s *serializer) encode(mode modes.EncMode, obj runtime.Object, w io.Writer) error {
if _, err := w.Write(selfDescribedCBOR); err != nil {
return err
}

var v interface{} = obj
if u, ok := obj.(runtime.Unstructured); ok {
v = u.UnstructuredContent()
}

if err := modes.RejectCustomMarshalers(v); err != nil {
return err
}

if _, err := w.Write(selfDescribedCBOR); err != nil {
return err
}

return mode.MarshalTo(v, w)
}

Expand Down Expand Up @@ -237,6 +241,8 @@ func (s *serializer) unmarshal(data []byte, into interface{}) (strict, lax error
}
}()
into = &content
} else if err := modes.RejectCustomMarshalers(into); err != nil {
return nil, err
}

if !s.options.strict {
Expand Down
63 changes: 63 additions & 0 deletions pkg/runtime/serializer/cbor/cbor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,42 @@ func TestEncode(t *testing.T) {
}
},
},
{
name: "unsupported marshaler",
in: &textMarshalerObject{},
assertOnWriter: func() (io.Writer, func(*testing.T)) {
var b bytes.Buffer
return &b, func(t *testing.T) {
if b.Len() != 0 {
t.Errorf("expected no bytes to be written, got %d", b.Len())
}
}
},
assertOnError: func(t *testing.T, err error) {
if want := "unable to serialize *cbor.textMarshalerObject: *cbor.textMarshalerObject implements encoding.TextMarshaler without corresponding cbor interface"; err == nil || err.Error() != want {
t.Errorf("expected error %q, got: %v", want, err)
}
},
},
{
name: "unsupported marshaler within unstructured content",
in: &unstructured.Unstructured{
Object: map[string]interface{}{"": textMarshalerObject{}},
},
assertOnWriter: func() (io.Writer, func(*testing.T)) {
var b bytes.Buffer
return &b, func(t *testing.T) {
if b.Len() != 0 {
t.Errorf("expected no bytes to be written, got %d", b.Len())
}
}
},
assertOnError: func(t *testing.T, err error) {
if want := "unable to serialize map[string]interface {}: cbor.textMarshalerObject implements encoding.TextMarshaler without corresponding cbor interface"; err == nil || err.Error() != want {
t.Errorf("expected error %q, got: %v", want, err)
}
},
},
} {
t.Run(tc.name, func(t *testing.T) {
s := NewSerializer(nil, nil)
Expand Down Expand Up @@ -625,6 +661,19 @@ func TestDecode(t *testing.T) {
}
},
},
{
name: "into unsupported marshaler",
data: []byte("\xa0"),
into: &textMarshalerObject{},
metaFactory: stubMetaFactory{gvk: &schema.GroupVersionKind{}},
typer: stubTyper{gvks: []schema.GroupVersionKind{{Version: "v", Kind: "k"}}},
expectedGVK: &schema.GroupVersionKind{Version: "v", Kind: "k"},
assertOnError: func(t *testing.T, err error) {
if want := "unable to serialize *cbor.textMarshalerObject: *cbor.textMarshalerObject implements encoding.TextMarshaler without corresponding cbor interface"; err == nil || err.Error() != want {
t.Errorf("expected error %q, got: %v", want, err)
}
},
},
} {
t.Run(tc.name, func(t *testing.T) {
s := newSerializer(tc.metaFactory, tc.creater, tc.typer, tc.options...)
Expand All @@ -643,6 +692,20 @@ func TestDecode(t *testing.T) {
}
}

type textMarshalerObject struct{}

func (p textMarshalerObject) GetObjectKind() schema.ObjectKind {
return schema.EmptyObjectKind
}

func (textMarshalerObject) DeepCopyObject() runtime.Object {
panic("unimplemented")
}

func (textMarshalerObject) MarshalText() ([]byte, error) {
return nil, nil
}

func TestMetaFactoryInterpret(t *testing.T) {
mf := &defaultMetaFactory{}
_, err := mf.Interpret(nil)
Expand Down
Loading

0 comments on commit c485170

Please sign in to comment.