diff --git a/admission/cocoonhibernation_validator.go b/admission/cocoonhibernation_validator.go index 87ecd64..a81f9cb 100644 --- a/admission/cocoonhibernation_validator.go +++ b/admission/cocoonhibernation_validator.go @@ -35,6 +35,13 @@ func (s *Server) validateCocoonHibernation(ctx context.Context, review *admissio return recordDeny(metrics.HandlerValidateHibernation, metrics.ResultError, metrics.ReasonDecode, fmt.Sprintf("decode CocoonHibernation: %v", err)) } + if !hib.Spec.Desire.IsValid() { + msg := fmt.Sprintf("cocoon-webhook: spec.desire must be %s or %s, got %q", + cocoonv1.HibernationDesireHibernate, cocoonv1.HibernationDesireWake, hib.Spec.Desire) + logger.Warnf(ctx, "validate %s/%s DENY: %s", req.Namespace, req.Name, msg) + return recordDeny(metrics.HandlerValidateHibernation, metrics.ResultDeny, "", msg) + } + if hib.Name != hib.Spec.PodRef.Name { msg := fmt.Sprintf("cocoon-webhook: metadata.name %q must equal spec.podRef.name %q (one CocoonHibernation per pod, named after it)", hib.Name, hib.Spec.PodRef.Name) diff --git a/admission/cocoonhibernation_validator_test.go b/admission/cocoonhibernation_validator_test.go index 0174083..80c445d 100644 --- a/admission/cocoonhibernation_validator_test.go +++ b/admission/cocoonhibernation_validator_test.go @@ -49,6 +49,31 @@ func TestValidateCocoonHibernationRejectsTerminatingPredecessor(t *testing.T) { } } +func TestValidateCocoonHibernationRejectsInvalidDesire(t *testing.T) { + srv := newHibernationServer(t) + hib := hibernation("pod-a", "pod-a", nil) + hib.Spec.Desire = "Sleep" + raw, err := json.Marshal(hib) + if err != nil { + t.Fatalf("marshal: %v", err) + } + resp := srv.validateCocoonHibernation(t.Context(), &admissionv1.AdmissionReview{ + Request: &admissionv1.AdmissionRequest{ + UID: "uid", + Namespace: "ns", + Name: "pod-a", + Operation: admissionv1.Create, + Object: runtime.RawExtension{Raw: raw}, + }, + }) + if resp.Allowed { + t.Fatalf("invalid spec.desire should be denied") + } + if !strings.Contains(resp.Result.Message, "spec.desire") { + t.Errorf("denial should name spec.desire, got %q", resp.Result.Message) + } +} + func TestValidateCocoonHibernationAllowsDistinctPods(t *testing.T) { srv := newHibernationServer(t, hibernation("legacy-name", "pod-a", nil)) resp := srv.validateCocoonHibernation(t.Context(), hibernationReview(t, admissionv1.Create, "pod-b", "pod-b")) diff --git a/go.mod b/go.mod index 547bc22..21f491b 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/cocoonstack/cocoon-webhook go 1.26.5 require ( - github.com/cocoonstack/cocoon-common v0.2.8-0.20260724145826-4363e4ff03ee + github.com/cocoonstack/cocoon-common v0.2.8-0.20260726095001-32dacef3f4c1 github.com/projecteru2/core v0.0.0-20241016125006-ff909eefe04c github.com/prometheus/client_golang v1.23.2 github.com/prometheus/client_model v0.6.2 diff --git a/go.sum b/go.sum index 69fd193..a83d615 100644 --- a/go.sum +++ b/go.sum @@ -27,8 +27,8 @@ github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZe github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= github.com/cockroachdb/redact v1.1.3 h1:AKZds10rFSIj7qADf0g46UixK8NNLwWTNdCIGS5wfSQ= github.com/cockroachdb/redact v1.1.3/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= -github.com/cocoonstack/cocoon-common v0.2.8-0.20260724145826-4363e4ff03ee h1:KshBIXkOlQMNdL7DPoYXitxq+qeWyQSqQsvIpDV0gv4= -github.com/cocoonstack/cocoon-common v0.2.8-0.20260724145826-4363e4ff03ee/go.mod h1:VSfgYiWxoHRnWybzQNaxmK4kVoLT9ffiMKll5/i92CM= +github.com/cocoonstack/cocoon-common v0.2.8-0.20260726095001-32dacef3f4c1 h1:JTQr97YGwJ71druXkVHYb6m1HIIzY/J3pputWAeYHUM= +github.com/cocoonstack/cocoon-common v0.2.8-0.20260726095001-32dacef3f4c1/go.mod h1:VSfgYiWxoHRnWybzQNaxmK4kVoLT9ffiMKll5/i92CM= github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=