Repository navigation
feat: what the filters excluded is named inside the cluster (ADR 0084) - #125
Merged
Merged
Conversation
The agent counts exclusions and never names them, which is the promise about what leaves the cluster — and it has also meant the customer, who owns every one of those annotations, cannot find out which object carries one. The controller now answers that inside the cluster: `/collection` on a loopback listener of its own, one NDJSON line per namespace, pod and Job, with the control that refused it and whether its workload could be read at all. Computed on request from the informer caches through the same Admit* calls the event path makes, so nothing is retained and the answer cannot drift from the decision; reading it moves no counter. Loopback because a NetworkPolicy selects ports and not paths: the health port is open to any source by a rule whose justification is that every path there names nothing in the cluster. A port-forward is the only way in, which leaves authorization to the RBAC the customer already wrote. A non-loopback address is a startup failure rather than a value normalized into something safe. Nothing that can transmit imports the package, and a test on the import graph is what keeps that true. go test -race ./... && golangci-lint run # 0 issues, v2.11.4 as CI pins make chart-lint # three profiles, 0 failed Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KeZECJXTDHL6Nts95eKMJA
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The agent counts what its filters exclude and never names it. That is the promise about what leaves the cluster — and it has also meant the customer, who owns every one of those annotations and can read them with
kubectl, learns from this agent only that nine of something were excluded. Two questions had no answer: which object carries the annotation someone wrote, and why a given workload is missing from the report when five controls could have removed it.What this adds
A second listener on the controller, at
127.0.0.1:9091, serving/collection: one NDJSON line per namespace, pod and Job — collected or not, profilable or not, which control refused it, and whether its workload was a kind the agent cannot read (ADR 0028 §3).Nothing is retained to answer it. The informer caches already hold every object whether admitted or not, so the listing runs the same
Admit*calls the event path makes and cannot drift from the decision. Reading it moves no counter.Why loopback and not a path on 9090
A NetworkPolicy selects ports, not paths. The health port is opened to any source by a rule whose own justification is that every path there "names nothing in the cluster" — the caller is the kubelet, arriving from an address no pod selector can name. A path naming objects does not share that port. The policy is also not rendered at all in a controller-only install, and is inert where the CNI ignores it, so the bind address is the only control that holds in every case.
Loopback also settles authorization without inventing any:
kubectl port-forwardis the only way in, and Kubernetes already gates it oncreateofpods/portforwardin the agent's namespace.A non-loopback
collection.listenAddressis a startup failure rather than a value normalized into something safe.What keeps it inside the cluster
Not the handler — the import graph. Nothing that can write a payload or open a connection imports the package, and
TestNothingThatCanTransmitKnowsThisPackagefails if that changes.Not changed
No payload byte, no RBAC, no new verb, no Service, no container port, no rule in the shipped NetworkPolicy. The inference ADR 0054 named is neither closed nor widened; this is not shipped anywhere.
Evidence
Also built and tested from a clean
git archive HEADextraction.Not exercised against a kind cluster: the endpoint has no e2e test in this PR.
🤖 Generated with Claude Code
https://claude.ai/code/session_01KeZECJXTDHL6Nts95eKMJA