Bug description
When a Capsule administrator (or any admin-classified identity) adds the
capsule.clastix.io/tenant label to an existing namespace that has no
annotations, the namespaces.validating.projectcapsule.dev webhook panics
and the request is denied:
admission webhook "namespaces.validating.projectcapsule.dev" denied the request:
panic: assignment to entry in nil map [recovered]
Root cause
internal/webhook/namespace/validation/user_metadata.go, userMetadataHandler.OnUpdate:
labels := maps.Clone(oldNs.GetLabels())
annotations := maps.Clone(oldNs.GetAnnotations()) // nil when the ns has no annotations
for key, value := range newNs.GetAnnotations() {
if _, ok := annotations[key]; !ok {
annotations[key] = value // user_metadata.go:107 — write to a nil map → panic
}
}
maps.Clone(nil) returns nil. The mutating webhook injects the tenant's
managed annotations (allowed storage classes, registries, etc.) into newNs,
so newNs.GetAnnotations() is non-empty while the clone of the (absent)
oldNs annotations is nil → annotations[key] = value panics.
This inline diff block also appears to be dead code — labels/annotations
are immediately reassigned by userMetadataForValidation(...) a few lines later
when tnt.Spec.NamespaceOptions != nil. The block looks already removed on
main, but it is still present in the latest release.
How to reproduce
- Install Capsule (chart
v0.13.5 or v0.13.6) with a tenant that has
NamespaceOptions (e.g. allowed storage classes), and an administrator in
CapsuleConfiguration.spec.administrators.
- Create a namespace with no annotations:
kubectl create ns demo
- As the administrator, adopt it:
kubectl label ns demo capsule.clastix.io/tenant=<tenant>
- Observe the panic above.
Workaround: seed any annotation first
(kubectl annotate ns demo x=y) so the annotations map is non-nil, then label.
Logs
controller-manager panic trace
{"level":"error","logger":"admission","msg":"Observed a panic","object":{"name":"sarge-test-1"},"user":"system:admin","panic":"assignment to entry in nil map",
"stacktrace":"... github.com/projectcapsule/capsule/internal/webhook/namespace/validation.(*userMetadataHandler).OnUpdate.func1 ... user_metadata.go:107 ...
github.com/projectcapsule/capsule/internal/webhook/namespace/validation.(*handler).OnUpdate.func1 ... handler.go:200 ..."}
Expected behavior
Adopting an annotation-less namespace into a tenant should succeed (or be
cleanly denied) without panicking the webhook.
Versions
- Capsule chart:
v0.13.5 (also reproduces on v0.13.6)
- Capsule image:
ghcr.io/projectcapsule/capsule:0.13.5
- Kubernetes: RKE2 (server v1.x)
Bug description
When a Capsule administrator (or any admin-classified identity) adds the
capsule.clastix.io/tenantlabel to an existing namespace that has noannotations, the
namespaces.validating.projectcapsule.devwebhook panicsand the request is denied:
Root cause
internal/webhook/namespace/validation/user_metadata.go,userMetadataHandler.OnUpdate:maps.Clone(nil)returnsnil. The mutating webhook injects the tenant'smanaged annotations (allowed storage classes, registries, etc.) into
newNs,so
newNs.GetAnnotations()is non-empty while the clone of the (absent)oldNsannotations isnil→annotations[key] = valuepanics.This inline diff block also appears to be dead code —
labels/annotationsare immediately reassigned by
userMetadataForValidation(...)a few lines laterwhen
tnt.Spec.NamespaceOptions != nil. The block looks already removed onmain, but it is still present in the latest release.How to reproduce
v0.13.5orv0.13.6) with a tenant that hasNamespaceOptions(e.g. allowed storage classes), and an administrator inCapsuleConfiguration.spec.administrators.kubectl create ns demokubectl label ns demo capsule.clastix.io/tenant=<tenant>Workaround: seed any annotation first
(
kubectl annotate ns demo x=y) so the annotations map is non-nil, then label.Logs
controller-manager panic trace
Expected behavior
Adopting an annotation-less namespace into a tenant should succeed (or be
cleanly denied) without panicking the webhook.
Versions
v0.13.5(also reproduces onv0.13.6)ghcr.io/projectcapsule/capsule:0.13.5