helm: quote the label values the policies emit

The same int-coercion the hook templates were fixed for, in the file this PR
adds: unquoted, a release named 123 renders app.kubernetes.io/instance as a
YAML integer in the metadata, the podSelector and both peer selectors, and
the API server rejects the object - a policy that silently never applies.
CI now renders the chart as release "123" and fails if any policy label
comes out as a non-string.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Sebastian Preisner
2026-07-29 14:27:34 +02:00
co-authored by Claude Opus 5
parent 7fc5f6d6bb
commit 180c799474
2 changed files with 44 additions and 11 deletions
+33
View File
@@ -1029,6 +1029,39 @@ jobs:
else:
print(f"{dropped}=null: the key is left out rather than rendered as null")
# Helm allows a release named "123", and an unquoted label value then
# renders as a YAML integer. Label values are strings in the API, so the
# whole object gets rejected - a policy that never applies, silently.
# Every label the policies emit, in metadata and in every selector, has
# to survive that release name as a string.
numeric = subprocess.check_output(
["helm", "template", "123", chart,
"--set", "networkPolicy.enabled=true",
"--set", "networkPolicy.egress.enabled=true",
"--set", "networkPolicy.egress.kubeApiServer.cidrs[0]=10.96.0.1/32",
"--set", "s3.enabled=true", "--set", "s3.createBuckets[0].name=b"],
text=True, stderr=subprocess.STDOUT)
def label_maps(policy):
yield "metadata", policy["metadata"].get("labels", {})
yield "podSelector", policy["spec"]["podSelector"]["matchLabels"]
for direction in ("ingress", "egress"):
for i, rule in enumerate(policy["spec"].get(direction) or []):
for peer in rule.get("to") or rule.get("from") or []:
for key in ("podSelector", "namespaceSelector"):
sel = peer.get(key) or {}
yield f"{direction}[{i}].{key}", sel.get("matchLabels", {})
coerced = [(comp, where, k, v)
for comp, p in policies(numeric).items()
for where, labels in label_maps(p)
for k, v in labels.items() if not isinstance(v, str)]
if coerced:
failed.append(f"release name 123: label values are not strings, so the API "
f"server rejects the policy: {coerced}")
else:
print("a numeric release name keeps every policy label a string")
out = render(egress_on)
pols = policies(out)
@@ -133,11 +133,11 @@ metadata:
name: {{ include "seaweedfs.componentName" (list $ $component) }}
namespace: {{ $.Release.Namespace }}
labels:
app.kubernetes.io/name: {{ template "seaweedfs.name" $ }}
app.kubernetes.io/name: {{ include "seaweedfs.name" $ | quote }}
helm.sh/chart: {{ $.Chart.Name }}-{{ $.Chart.Version | replace "+" "_" }}
app.kubernetes.io/managed-by: {{ $.Release.Service }}
app.kubernetes.io/instance: {{ $.Release.Name }}
app.kubernetes.io/component: {{ $component }}
app.kubernetes.io/managed-by: {{ $.Release.Service | quote }}
app.kubernetes.io/instance: {{ $.Release.Name | quote }}
app.kubernetes.io/component: {{ $component | quote }}
{{- if $target.hook }}
annotations:
{{- /* Only before-hook-creation: the policy has to outlive the Job it
@@ -151,9 +151,9 @@ metadata:
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: {{ template "seaweedfs.name" $ }}
app.kubernetes.io/instance: {{ $.Release.Name }}
app.kubernetes.io/component: {{ $component }}
app.kubernetes.io/name: {{ include "seaweedfs.name" $ | quote }}
app.kubernetes.io/instance: {{ $.Release.Name | quote }}
app.kubernetes.io/component: {{ $component | quote }}
policyTypes:
- Ingress
{{- if $egressCfg.enabled }}
@@ -168,8 +168,8 @@ spec:
- from:
- podSelector:
matchLabels:
app.kubernetes.io/name: {{ template "seaweedfs.name" $ }}
app.kubernetes.io/instance: {{ $.Release.Name }}
app.kubernetes.io/name: {{ include "seaweedfs.name" $ | quote }}
app.kubernetes.io/instance: {{ $.Release.Name | quote }}
ports:
{{- range $port := $target.ports }}
- protocol: TCP
@@ -184,8 +184,8 @@ spec:
- to:
- podSelector:
matchLabels:
app.kubernetes.io/name: {{ template "seaweedfs.name" $ }}
app.kubernetes.io/instance: {{ $.Release.Name }}
app.kubernetes.io/name: {{ include "seaweedfs.name" $ | quote }}
app.kubernetes.io/instance: {{ $.Release.Name | quote }}
{{- if $egressCfg.allowDNS }}
{{- /* Emit only the selectors that are set. An empty one has to be left out
rather than rendered as null: a missing podSelector means every pod in