feat(ci): assert every rendered NetworkPolicy against its own render
The part that carries the rollout of Gitea #5. 29 charts get a policy that is on by default, and every way one of them can be wrong is SILENT: the API server accepts a policy that filters nothing just as readily as one that filters everything, and neither is a render error, so neither the build nor a rollout sees it. ci/run-networkpolicy-test.sh holds every rendered NetworkPolicy against the pod specs, probes and Services of the SAME render: 1. the podSelector really matches a pod of that render - otherwise the object sits in the namespace, is listed by kubectl, reads as a boundary and filters nothing, usually because a label was renamed in another file; 2. every INGRESS port is a containerPort of the selected pods, which catches the NodePort mistake mechanically. Egress ports are deliberately excluded: an egress port belongs to the DESTINATION, and comparing it would fail every chart that reaches a database; 3. no ingress rule allows every source by accident. "from: []" always fails - it allows everything while reading as a restriction. A MISSING "from" is the documented open form and is accepted only where the render justifies it: every port of the rule is addressed by a network probe, or published by a NodePort Service. That is stricter than the plan's wording, which banned both forms, and it had to be, because the precedents use the second one on purpose; 4. the probe path. For every port a NETWORK probe addresses, the policy either leaves it unrestricted or the chart offers networkPolicy.probeSources AND says in NOTES.txt that a list missing the node's IP leaves the pod permanently un-Ready. exec probes are excluded by design - they run inside the container and put no packet on the network, which is exactly why valkey and minecraft-server can restrict their port by source with no probeSources at all. Two guards beyond the four: a chart that renders NO policy fails, because that is how this issue decayed in the first place - garage and keycloak were both created after #5 and both arrived without one. And a "#" comment inside a rendered policy fails, because it is part of the object and is shipped to the cluster. Helm is the parser through ci/yaml2json, as in the other render tests: the runners have neither pyyaml nor yq, and a hand-written parser could read nothing, find nothing and leave this green over a chart it never looked at. Every failure path was run, not just the green ones, and one of them earned its keep immediately: the probeSources check was a substring test, so a chart whose key had been deleted while the comment above it still discussed the value passed. It now looks for the key. Part of #5
This commit is contained in:
3 files changed
+918
No files matched your search
@@ -303,6 +303,52 @@ jobs:
|
||||
- name: "Check every rendered scalar that must be a string"
|
||||
run: ci/run-yaml-scalar-render-test.sh
|
||||
|
||||
networkpolicy:
|
||||
name: "NetworkPolicy"
|
||||
runs-on: ubuntu-latest
|
||||
# The sixth job that ignores the changed-chart matrix and the fifth that runs
|
||||
# over *every* chart (Gitea #5), for the same reason as the render tests
|
||||
# above: the mistake arrives by copy into a chart whose own diff nobody reads
|
||||
# for it - and since #5 this convention is in all 29 installable charts, so
|
||||
# there is a lot of copy.
|
||||
#
|
||||
# What it asserts, on every NetworkPolicy a chart renders, against the pod
|
||||
# specs, probes and Services of the SAME render: the podSelector really
|
||||
# matches a pod; every ingress port is a containerPort of those pods; no
|
||||
# ingress rule allows every source by accident; and every port a NETWORK
|
||||
# probe addresses is either left unrestricted or comes with
|
||||
# networkPolicy.probeSources and the consequence written into NOTES.txt.
|
||||
# Plus two guards of its own: a chart that renders NO policy fails, and a
|
||||
# rendered "#" comment fails.
|
||||
#
|
||||
# Every one of those failures is SILENT. The API server accepts a policy
|
||||
# whose selector matches nothing - it then sits in the namespace, is listed
|
||||
# by kubectl, reads as a boundary and filters exactly nothing - just as
|
||||
# readily as it accepts one naming a NodePort number, which matches no
|
||||
# traffic at all because the policy is evaluated at the pod's interface
|
||||
# after kube-proxy has already translated the port. Neither is a render
|
||||
# error and neither denies anything, so neither the build nor a rollout can
|
||||
# see it.
|
||||
#
|
||||
# It does NOT replace the install-test, which is the real net under this
|
||||
# convention: that one proves ENFORCEMENT on a live k3s with its policy
|
||||
# controller running, and it is what makes "all charts at once, default on"
|
||||
# defensible. This job is the cheap half, and it covers the two charts the
|
||||
# install-test cannot reach at all - satisfactory and template-chart, both
|
||||
# in ci/excluded-charts.txt.
|
||||
#
|
||||
# No cluster and no Trivy; a few seconds for the whole repository, depends
|
||||
# on no other job. The YAML is parsed by Helm through ci/yaml2json, because
|
||||
# the runners have neither pyyaml nor yq and a hand-written parser could read
|
||||
# nothing and report nothing - see the script's header.
|
||||
steps:
|
||||
- name: "Checkout Repository"
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
||||
- name: "Install Helm"
|
||||
uses: azure/setup-helm@9bc31f4ebc9c6b171d7bfbaa5d006ae7abdb4310 # v5
|
||||
- name: "Check every rendered NetworkPolicy against the render it belongs to"
|
||||
run: ci/run-networkpolicy-test.sh
|
||||
|
||||
trivy-config:
|
||||
name: "Trivy config ${{ matrix.chart }}"
|
||||
needs: detect-changed-charts
|
||||
|
||||
Reference in new issue
Block a user