diff --git a/webhook/webhook.go b/webhook/webhook.go index bf3cf3400..b75f6b64a 100644 --- a/webhook/webhook.go +++ b/webhook/webhook.go @@ -120,6 +120,8 @@ type AdmissionController struct { Options ControllerOptions Handlers map[schema.GroupVersionKind]GenericCRD Logger *zap.SugaredLogger + + DisallowUnknownFields bool } // GenericCRD is the interface definition that allows us to perform the generic @@ -527,6 +529,9 @@ func (ac *AdmissionController) mutate(ctx context.Context, req *admissionv1beta1 if len(newBytes) != 0 { newObj = handler.DeepCopyObject().(GenericCRD) newDecoder := json.NewDecoder(bytes.NewBuffer(newBytes)) + if ac.DisallowUnknownFields { + newDecoder.DisallowUnknownFields() + } if err := newDecoder.Decode(&newObj); err != nil { return nil, fmt.Errorf("cannot decode incoming new object: %v", err) } @@ -534,6 +539,9 @@ func (ac *AdmissionController) mutate(ctx context.Context, req *admissionv1beta1 if len(oldBytes) != 0 { oldObj = handler.DeepCopyObject().(GenericCRD) oldDecoder := json.NewDecoder(bytes.NewBuffer(oldBytes)) + if ac.DisallowUnknownFields { + oldDecoder.DisallowUnknownFields() + } if err := oldDecoder.Decode(&oldObj); err != nil { return nil, fmt.Errorf("cannot decode incoming old object: %v", err) } diff --git a/webhook/webhook_test.go b/webhook/webhook_test.go index bce7caeff..b5eac85a7 100644 --- a/webhook/webhook_test.go +++ b/webhook/webhook_test.go @@ -135,6 +135,31 @@ func TestUnknownVersionFails(t *testing.T) { expectFailsWith(t, ac.admit(TestContextWithLogger(t), req), "unhandled kind") } +func TestUnknownFieldFails(t *testing.T) { + _, ac := newNonRunningTestAdmissionController(t, newDefaultOptions()) + req := &admissionv1beta1.AdmissionRequest{ + Operation: admissionv1beta1.Create, + Kind: metav1.GroupVersionKind{ + Group: "pkg.knative.dev", + Version: "v1alpha1", + Kind: "Resource", + }, + } + + marshaled, err := json.Marshal(map[string]interface{}{ + "spec": map[string]interface{}{ + "foo": "bar", + }, + }) + if err != nil { + panic("failed to marshal resource") + } + req.Object.Raw = marshaled + + expectFailsWith(t, ac.admit(TestContextWithLogger(t), req), + `mutation failed: cannot decode incoming new object: json: unknown field "foo"`) +} + func TestValidCreateResourceSucceeds(t *testing.T) { r := createResource("a name") for _, v := range []string{"v1alpha1", "v1beta1"} { @@ -699,8 +724,9 @@ func setUserAnnotation(userC, userU string) jsonpatch.JsonPatchOperation { func NewAdmissionController(client kubernetes.Interface, options ControllerOptions, logger *zap.SugaredLogger) (*AdmissionController, error) { return &AdmissionController{ - Client: client, - Options: options, + Client: client, + Options: options, + DisallowUnknownFields: true, // Use different versions and domains, for coverage. Handlers: map[schema.GroupVersionKind]GenericCRD{ {