Skip to content

feat(telemetry): the chart wires jobs-manager to the Collector's token (backend#2274) - #784

Merged
LukasWodka merged 1 commit into
developfrom
feat/2274-collector-token-chart
Aug 21, 2026
Merged

feat(telemetry): the chart wires jobs-manager to the Collector's token (backend#2274)#784
LukasWodka merged 1 commit into
developfrom
feat/2274-collector-token-chart

Conversation

@LukasWodka

@LukasWodkaLukasWodka commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Closes tracebloc/backend#2274. Parent epic: tracebloc/backend#1872.

The write side landed in client-runtime#368; this is the half it was waiting for. It needs telemetryCollector.tokenSecret, which only existed once #779 merged.

⚠️ The RBAC gap isn't in the ticket

jobs-manager's cluster-wide rule in rbac.yaml grants secrets: [create, get] and not patch. So on the chart as it stood, the create would succeed and every refresh would 403.

That failure needs no code change to appear. bearertokenauth watches the projected file, so a rotated token is picked up without restarting the Collector — but only if something rewrites the Secret. Without patch, the Collector works until the first token rotation, then 401s on every export and buffers to disk until the cap. I found it reading the rule while writing the reader and recorded it on the ticket then; this closes it.

Gated on the Collector alone, deliberately unlike its sibling node-agents Roles. Those carry a second condition — that nodeAgents.namespace differs from the release namespace — because the release-namespace grant already covers them when the two coincide. This one isn't covered either way: the missing verb is missing in any namespace. The Role name is release-scoped, so it can't collide when the namespaces do coincide.

Two rules, because resourceNames is not honoured for create — the API server can't match a name that doesn't exist yet. So create is namespace-scoped and get/patch are pinned to the one Secret, which is the half that would otherwise let jobs-manager rewrite anything in the namespace. Same shape and reason as image-refresh-rbac.yaml's collection-verb split.

The coordinates go to one container, and that's a real trap

pods-monitor-container has a byte-identical env: opening and doesn't run jobs_manager.py. My first patch asserted a unique match, found two, and refused — which is the only reason it didn't land on the wrong container, where it would have set three variables on a process that never reads them while the Collector still got no token. Both containers are asserted.

jobs-manager holds no defaults for the name, namespace or key: the chart declares them and passes them here, so the two sides can't disagree.

Four documents, one credential — so it gets a guard

The writer (jobs-manager's env), the reader (the Collector's volume), the key (bearertokenauth.filename), and the Role + RoleBinding. Any one disagreeing produces the same symptom: nothing. The Collector mounts the Secret optional: true on purpose — a missing token must buffer, not CrashLoopBackOff on every customer node — so a wrong name, a wrong namespace, a wrong key, and a Role bound to the wrong ServiceAccount are all indistinguishable from "not deployed yet".

scripts/tests/telemetry-token-agreement.sh compares all four out of one render and writes none of them down. It derives the key the way the Collector actually resolves it — basename(bearertokenauth.filename), since the volume has no items and Secret keys project as files named by key — and checks the mount directory matches, so a filename pointing at a path nothing projects to is caught too.

MutationResult
Role resourceNames renamedKILLED
writer env NAME changedKILLED
writer env KEY changedKILLED
writer env NAMESPACE changedKILLED
RoleBinding bound to the wrong ServiceAccountKILLED
the name-scoped rule droppedKILLED
the Role template deletedKILLED (fails closed)
env wired to the wrong container1 unit test failed
the enabled gate removed2 unit tests failed

Still not done when this merges

Per the ticket, done is a record arriving at /tracebloc/edge/telemetry from a real edge — which now needs someone to flip telemetryCollector.enabled=true on a fleet and confirm. A Secret that exists proves nothing, because the Collector's absent-token behaviour is to buffer quietly.

Test plan

  • helm unittest . — 537 passed
  • make drift — 12/12 guards green (incl. the new one)
  • make check — parse, shellcheck -S warning, helm-lint, helm-vocab
  • Mutation matrix above; every anchor asserted applied
  • Renders inert with the Collector off (no RBAC, no env) and survives telemetryCollector: null
  • Enable on a fleet and confirm a record arrives

🤖 Generated with Claude Code


Note

Medium Risk
Adds a new Role that can create secrets in the node-agents namespace and patch one named token Secret, plus env that points jobs-manager at that credential. Gated on telemetryCollector.enabled and name-scoped for get/patch, but it is still RBAC and secret-handling.

Overview
When telemetryCollector.enabled is true, jobs-manager now receives TELEMETRY_TOKEN_SECRET_{NAMESPACE,NAME,KEY} so it can write the Collector's ingest token. The vars go only on the api container (not pods-monitor). They are omitted when the Collector is off.

A new Role/RoleBinding in the node-agents namespace fills the gap that cluster-wide rbac.yaml grants secrets: [create, get] but not patch. Without that, create would succeed and every token refresh would 403, leaving the Collector 401ing after the first rotation. create is namespace-scoped; get/patch are pinned to the one Secret.

A fail-closed drift guard (telemetry-token-agreement.sh) checks that writer env, Collector volume, bearertokenauth key, and RoleBinding all name the same Secret. Chart version is 1.9.59.

Reviewed by Cursor Bugbot for commit 654aa87. Bugbot is set up for automated code reviews on this repo. Configure here.

…n (backend#2274)
The write side landed in client-runtime#368 and this is the half it was waiting
for: it needs `telemetryCollector.tokenSecret`, which only existed once #779
merged. Two pieces — RBAC, and the coordinates.
THE RBAC IS NOT JUST PLUMBING, AND IT IS NOT IN THE TICKET. jobs-manager's
cluster-wide rule in rbac.yaml grants `secrets: [create, get]` and NOT `patch`.
So on the chart as it stood, the create would succeed and every REFRESH would 403.
That failure needs no code change to appear: `bearertokenauth` watches the
projected file, so a rotated token is picked up without restarting the Collector —
but only if something rewrites the Secret. Without `patch` the Collector works
until the first token rotation, then 401s on every export and buffers to disk
until the cap. I found it reading the rule while writing the reader, and recorded
it on the ticket then; this closes it.
GATED ON THE COLLECTOR ALONE, deliberately unlike its sibling node-agents Roles.
Those carry a second condition — that `nodeAgents.namespace` differs from the
release namespace — because the release-namespace grant already covers them when
the two coincide. This one is not covered either way: the missing verb is missing
in ANY namespace. The Role name is release-scoped, so it cannot collide when the
namespaces do coincide.
TWO RULES, because `resourceNames` IS NOT HONOURED FOR `create` — the API server
cannot match a name that does not exist yet. So `create` is namespace-scoped and
`get`/`patch` are pinned to the one Secret, which is the half that would
otherwise let jobs-manager rewrite anything in the namespace. Same shape and same
reason as image-refresh-rbac.yaml's collection-verb split.
THE COORDINATES GO TO THE `api` CONTAINER ONLY, and that is a real trap rather
than a detail: `pods-monitor-container` has a BYTE-IDENTICAL `env:` opening and
does not run jobs_manager.py. My first patch attempt asserted a unique match,
found two, and refused — which is the only reason it did not land on the wrong
container, where it would have set three variables on a process that never reads
them while the Collector still got no token. Both containers are asserted.
FOUR DOCUMENTS NOW DESCRIBE ONE CREDENTIAL, so they get a guard rather than
review attention: jobs-manager's env (the writer), the Collector's volume (the
reader), `bearertokenauth.filename` (which encodes the key), and the Role +
RoleBinding. Any one disagreeing produces the same symptom — nothing — because the
Collector mounts the Secret `optional: true` on purpose, so a wrong name,
namespace or key and a Role bound to the wrong ServiceAccount are all
indistinguishable from "not deployed yet".
scripts/tests/telemetry-token-agreement.sh compares all four out of one render and
writes none of them down. It derives the KEY the way the Collector actually
resolves it — `basename(bearertokenauth.filename)`, since the volume has no
`items` and Secret keys project as files named by key — and checks the mount
directory matches, so a filename pointing at a path nothing projects to is caught
too.
Mutation-proven, anchors asserted applied:
Role resourceNames renamed KILLED
writer env NAME changed KILLED
writer env KEY changed KILLED
writer env NAMESPACE changed KILLED
RoleBinding bound to the wrong SA KILLED
the name-scoped rule dropped KILLED
the Role template deleted KILLED (fails closed)
env wired to the wrong container 1 unit test failed
the enabled gate removed 2 unit tests failed
Tests: 537 passed, 537 total chart tests, 12/12 drift guards, make check green.
STILL NOT DONE. Per the ticket, done is a record arriving at
/tracebloc/edge/telemetry from a real edge — which now needs someone to flip
`telemetryCollector.enabled=true` on a fleet and confirm. A Secret that exists
proves nothing, because the Collector's absent-token behaviour is to buffer quietly.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@LukasWodkaLukasWodka self-assigned this Aug 21, 2026
@LukasWodka

Copy link
Copy Markdown
ContributorAuthor

bugbot run

@LukasWodka
LukasWodka removed the request for review from aptraceblocAugust 21, 2026 10:50

@cursorcursorBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 654aa87. Configure here.

@aptracebloc

Copy link
Copy Markdown
Contributor

👋 @LukasWodka — Arturo (@aptracebloc) is signing off for the day, so he won't pick this up in the next review passes. @saadqbal is already a co-reviewer here and can carry it; if you'd rather not wait on Arturo's eyes specifically, feel free to route it to another available reviewer so it keeps moving. Arturo will re-engage when he's back.

— drafted with Claude Code

@saadqbalsaadqbal left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The RBAC gap is the reason to read this PR, and finding it by reading the rule while writing the reader — rather than by watching a customer edge stop exporting after the first token rotation — is the good version of this. Confirmed it's real and confirmed it needed no code change to appear.

Four things I checked rather than took on trust:

1. The missing verb — real, and in two rules, not one.rbac.yaml:68 (the ClusterRole) and rbac.yaml:151 (the namespaced Role used when clusterScope: false) both grant secrets: ["create", "get"] with no patch. The description says "jobs-manager's cluster-wide rule" in the singular; there are two, and both are affected. It doesn't change the fix — a Role in the node-agents namespace grants patch there regardless of which of those two a given install renders — but the clusterScope: false path would have hit exactly the same 403, so the fix is broader than described rather than narrower.

2. patch is the verb the writer actually uses. This was my main worry: patch and update are separate RBAC verbs, and a writer calling replace_namespaced_secret (PUT → update) would 403 identically with the grant as written, reproducing the exact symptom this PR fixes. It doesn't — jobs_manager.py::sync_telemetry_token_secret is create-then-patch-on-409 and its docstring records why: "patch rather than replace so the object's metadata survives". Both sides chose patch deliberately and each says so. That's the two-sided agreement this PR is claiming, and it holds.

3. The cross-namespace binding is right. Role and RoleBinding in nodeAgents.namespace.name, subject the jobs-manager ServiceAccount in .Release.Namespace. A RoleBinding grants within its own namespace to a subject from anywhere, so this is the correct shape and the comment naming which object lives where is worth having.

4. The gate looks weaker than every sibling's, and provably isn't. This was the one I expected to be a finding: auto-upgrade-rbac.yaml, docker-registry-secret.yaml, image-refresh-rbac.yaml and node-agents-namespace.yaml all gate on include "tracebloc.nodeAgentsInUse" . before creating anything in that namespace, and this template gates only on $tcTok.enabled — which would put a Role in a namespace nothing created. But the helper is

{{- if or (ne .Values.resourceMonitor false) $tc.enabled }}true{{ end -}}

so telemetryCollector.enabledimpliesnodeAgentsInUse, and the extra condition would be dead. telemetry-collector-daemonset.yaml gates identically ({{- if $tc.enabled }}, namespace at :70), so this is consistent with its own consumer rather than looser than it. Worth one line in the comment saying that, since the omission reads as an oversight against four siblings that all do it the other way.

On the parts I'd normally push back on and won't

The create rule really is namespace-wide — jobs-manager can now create any Secret in the node-agents namespace. That's a genuine widening, and it's also the minimum Kubernetes permits: resourceNames is not honoured for create because the API server cannot match a name that does not exist yet. The half that could be pinned is pinned, which is the half that matters — without the split, patch on the whole collection would let jobs-manager rewrite any Secret in that namespace, including ones it doesn't own. Right call, and the same shape as image-refresh-rbac.yaml.

nodeAgents.namespace.name unguarded — no template in the chart guards it with default (dict), so this matches an established convention rather than departing from one. Not flagging it; adding a guard here alone would be the inconsistent choice.

The two-container trap is the finding I'd have missed.pods-monitor-container having a byte-identical env: opening while not running jobs_manager.py is exactly the kind of thing that lands silently — three variables set on a process that never reads them, the Collector still tokenless, and every symptom identical to "not deployed yet". That the first patch asserted a unique match and refused is why it didn't land there, and asserting both containers is the right permanent answer.

The four-document guard is the right response to "any one disagreeing produces the same symptom: nothing", and deriving the key as basename(bearertokenauth.filename) — the way the Collector actually resolves it, since the volume has no items — is what makes it a check rather than a restatement. The mutation table covers the renames in both directions and the fail-closed case.

Approving.

@saadqbal

Copy link
Copy Markdown
Contributor

Coordination note, unrelated to the review above: this and #765 both bump 1.9.58 → 1.9.59. Whichever lands second will conflict on Chart.yaml and need a re-bump to 1.9.60 — both are approved now, so it's worth knowing before one of you hits it rather than after. #765 has been open longer, so it's the likelier first.

@LukasWodka
LukasWodka merged commit 925ed4d into developAug 21, 2026
48 checks passed
@LukasWodka
LukasWodka deleted the feat/2274-collector-token-chart branch August 21, 2026 11:23
@LukasWodka

Copy link
Copy Markdown
ContributorAuthor

Merged. Both of your non-blocking asks are in #787 rather than pushed here — a comment fix onto an approved PR would have tripped the stale-review dismissal and re-rolled your review for documentation.

Your correction stands and I verified it directly:rbac.yaml:62 (ClusterRole, clusterScope: true) and rbac.yaml:145 (namespaced Role, clusterScope: false) both read verbs: ["create", "get"]. My description said "cluster-wide rule" in the singular, and you're right that the clusterScope: false path would have hit the identical 403 — the comment is now explicit about both, and about why the fix is the same either way.

The gate rationale is in there too, in the form you asked for: one line saying telemetryCollector.enabled implies nodeAgentsInUse so the extra condition would be dead, and that this matches its own consumer's gate rather than being looser than its four siblings.

On the create widening — agreed it's a genuine widening and worth stating plainly rather than burying, which is why the split is in the template comment. It is the minimum Kubernetes permits, and the half that can be pinned is pinned.

One thing I'd flag back: gen-manifest.sh --check passes on #787 because chart templates aren't in the hash manifest — but I measured the render rather than trusting that, after getting "comment-only" wrong on #775. Same tree twice differs by 2 lines (POD_TOKEN_SIGNING_SECRET, generated per render); before/after with the version pinned equal differs by 0 beyond that. So the checksum/config churn in the raw diff is downstream of the mandatory version bump, not the comment.

LukasWodka added a commit that referenced this pull request Aug 21, 2026
…backend#2274) (#787)
* docs(telemetry): the missing verb is in BOTH secrets rules, not one (backend#2274)
@saadqbal's two non-blocking asks from the review of #784, taken as a follow-up
rather than a push onto that PR: branch protection dismisses stale reviews on new
commits, so pushing a comment fix would have re-rolled an approved, green PR for a
documentation change.
1. "THE CLUSTER-WIDE RULE" WAS SINGULAR AND WRONG. Verified before writing it
down: `rbac.yaml:62` (the ClusterRole, `clusterScope: true`) and `rbac.yaml:145`
(the namespaced Role, the `clusterScope: false` branch) BOTH grant
`secrets: ["create", "get"]` with no `patch`. So the create succeeds and every
refresh 403s on either install shape.
The fix does not change — a Role in the node-agents namespace grants `patch`
there whichever branch renders — but the old wording would have sent someone
reading the `clusterScope: false` path looking for a difference that is not
there, which is the specific cost of a comment that is nearly right.
2. THE GATE'S OMISSION READ AS AN OVERSIGHT, so it now says why it is not. Four
siblings — docker-registry-secret.yaml, image-refresh-rbac.yaml,
node-agents-namespace.yaml, secrets.yaml — gate on
`tracebloc.nodeAgentsInUse`, and this template does not. That helper is
`or (ne .Values.resourceMonitor false) $tc.enabled`, so
`telemetryCollector.enabled` IMPLIES it and the extra condition would be dead;
this gates exactly as its own consumer does
(telemetry-collector-daemonset.yaml is `{{- if $tc.enabled }}`), rather than
more loosely than its siblings. Four templates doing it one way and a fifth
doing it another is worth one line, whichever way it resolves.
COMMENT-ONLY, AND PROVEN RATHER THAN ASSERTED. I claimed that on client#775 and
was wrong, because telemetry.sh is hash-pinned and install.sh aborts on a manifest
mismatch. Chart templates are not in the manifest (`gen-manifest.sh --check` is
clean, unchanged), but the render is the thing that matters, so:
* rendering the same tree twice differs by 2 lines — POD_TOKEN_SIGNING_SECRET,
which is generated per render;
* before/after with the version pinned EQUAL differs by 0 lines beyond that.
So the version labels and the two `checksum/config` annotations in the raw diff are
downstream of the mandatory Chart.yaml bump (the checksummed ConfigMap carries the
chart-version label), and nothing is attributable to the comment.
537/537 chart tests, 12/12 drift guards.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* docs(telemetry): stop enumerating the list, and guard the property instead (backend#2274)
@saadqbal, review of #787. He is right, and right about why it is not a nitpick:
this PR exists to fix a comment that was NEARLY right, and its replacement
enumerated the wrong set. Same class of error, one round later, in the one file
where the comment IS the deliverable.
WHAT WAS WRONG. The list named four `tracebloc.nodeAgentsInUse` consumers. It
included secrets.yaml, which does not gate on the helper, and omitted
auto-upgrade-rbac.yaml, which does — so "four" was right only because the two
errors cancelled. Verified before fixing:
git grep -l nodeAgentsInUse origin/develop -- client/templates
_helpers.tpl <- defines it
auto-upgrade-rbac.yaml <- omitted from my list
docker-registry-secret.yaml
image-refresh-rbac.yaml
node-agents-namespace.yaml
<- secrets.yaml absent; I had listed it
ONE CORRECTION BACK, since precision is this PR's whole subject: he wrote that
secrets.yaml "contains no `nodeAgents` reference of any kind". It has two — the
gate at :112 and the namespace at :121. His conclusion is exactly right (it does
not gate on the HELPER, it gates on `resourceMonitor`, which is the deliberate
#779 decision not to mirror customer credentials into that namespace for a
workload that never reads them); the supporting detail is not.
THE COMMENT NO LONGER ENUMERATES ANYTHING. It says "every other consumer of the
helper gates on it; this one does not, because …" — which a reader can reproduce
with one grep, cannot rot, and loses nothing. The rbac.yaml reference is anchored
on the branch and the rule's `resources:` line rather than on `:62`/`:145`: those
were the resources lines while the claim was about verbs (`:68`/`:151`), and
cross-file line numbers drift the first time that file gains a rule.
AND THE PROPERTY IS NOW GUARDED, because his deeper point is the right one — three
hand-maintained lists have gone stale in this area in a week, and rule 1 is derive,
never restate. scripts/tests/node-agents-namespace-safety.sh asserts the OUTCOME
those five gates exist to produce: across all four tenant combinations, if any
rendered resource declares the node-agents namespace, the Namespace must render
too. That is #779's original finding stated as an invariant, and a new template
that forgets its gate fails it without anyone having to notice it was added.
It deliberately does NOT check the gate EXPRESSION. Two spellings are both correct
— `nodeAgentsInUse`, and a bare `telemetryCollector.enabled` which implies it —
so asserting one would flag correct code. Asserting the outcome cannot. It holds no
list of templates, gates or helpers, reads even the namespace NAME out of the
render, is scoped to `namespace.create: true` (an operator who pre-creates the
namespace is legitimately out of scope, said rather than mis-asserted), and fails
closed if no combination populates the namespace at all — an inert chart would
otherwise satisfy the implication vacuously.
Mutation-proven, anchors asserted applied:
the token Role loses its gate KILLED — names the Role and the absent namespace
the namespace stops being created KILLED
Both reproduce the #779 class from opposite directions.
537/537 chart tests, 13/13 drift guards, make check green.
Unrelated, and not mine to fix: #765 is @saqlainsyed007's and still bumps
1.9.58 -> 1.9.59, which develop now holds — it needs 1.9.61 once this lands. He
said he would note it there; flagging only, since I do not touch teammates' PRs.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix(test): the new guard depended on the developer's kube context (backend#2274)
`Source-of-truth drift` went red on #787's first run, and the guard I had just
added to prevent hardcoded values from rotting was itself hardcoding one.
`helm template` with no `--namespace` takes the release namespace from the
CALLER'S KUBECONFIG CONTEXT. On the laptop this was written on that is
`tracebloc`; on a runner with no kubeconfig it is `default`. The comparator found
the node-agents namespace by excluding the literal `"tracebloc"` — so in CI it
concluded the RELEASE namespace was the node-agents one and reported all 35
release-namespace resources as orphaned.
A guard whose verdict depends on the developer's kube context is worse than no
guard: green where it is written, red where it runs. Both helm invocations now pin
`--namespace` and the comparator receives that value instead of assuming one. The
pinned value is deliberately not any real namespace, so a literal creeping back in
cannot silently match.
FIXED IN node-agents-tenancy.sh TOO, which carried the identical literal and
passed CI only because the chart happens to put no DaemonSet in the release
namespace — luck, not design. It would have started lying the first time one
appeared, and silently: its verdict is "which namespace is the node-agents one",
so a wrong answer there produces a comparison between the wrong two sets rather
than an error.
REPRODUCED BEFORE FIXING, AND THE FIX PROVEN AGAINST THE SAME CONDITION — which is
the step I skipped and which would have caught this before pushing:
KUBECONFIG=/nonexistent old code -> [ERROR] ... render into 'default' ...
KUBECONFIG=/nonexistent new code -> green, all four combinations
`make drift` is green under that environment too, so the whole tier is now
independent of ambient kube state rather than just this guard.
537/537 chart tests, 13/13 drift guards.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* test(guard): a set of namespaces, and no prescribed fix (backend#2274)
@saadqbal's review of #787. He diagnosed the release-namespace bug independently
and identically before 5a34fc8 landed; three things he added on top are in here.
1. A SET, NOT `break` ON THE FIRST MATCH. Document order decided which namespace
got checked, and a set is honest about there being possibly more than one —
today there is exactly one, and a third appearing should be checked rather than
shadowed. Every non-release namespace is now checked independently.
2. THE MESSAGE NO LONGER PRESCRIBES A FIX, and this is the part of his review that
matters most. It used to say "gate them on `tracebloc.nodeAgentsInUse`" — which,
while the guard was mis-firing on the release namespace, advised making the
ENTIRE CHART conditional on node agents being in use. Applied as written to
`Deployment/t-jobs-manager` or `PersistentVolumeClaim/client-pvc` it would have
been actively destructive. A false positive that arrives with confident,
specific, harmful advice is worse than one that merely fails, because someone in
a hurry can act on it. It now states the violated property and names the
namespace, and leaves the gate to the reader — there is more than one correct
spelling anyway.
3. HIS MUTATION, WHICH IS THE ONE THAT MATTERED. The guard was built for #779's
DaemonSet-in-an-uncreated-namespace, so that failure is its natural test, and he
was right that a run failing on everything cannot tell you whether it catches
the real thing. Removing the Collector DaemonSet's own gate:
[ERROR] resourceMonitor=false tc=false: 1 resource(s) render into
'tracebloc-node-agents' but the chart does not create it:
['DaemonSet/t-telemetry-collector']
which is #779's original finding, reproduced.
AND ONE THE GUARD CAUGHT ON ITSELF. The vacuity check grepped `resources=N` out of
the formatted summary line, so reformatting that line for (1) made it report "no
combination put anything in the namespace" on a perfectly healthy chart — a check
coupled to a display string, the same class as everything else this file has found.
The two halves now agree on a `POPULATED=` marker emitted on EVERY exit path,
including the early one, so "checked nothing" is distinguishable from "died before
printing". It failed closed while broken, which is the design working.
Mutation-proven, anchors asserted applied, all under KUBECONFIG=/nonexistent:
Collector DaemonSet gate removed KILLED (#779's original failure)
token Role gate removed KILLED
namespace not created KILLED
No survivors; green on restore.
537/537 chart tests, 13/13 drift guards, make check green — all with no kubeconfig,
so none of it depends on ambient kube state.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
@LukasWodka

Copy link
Copy Markdown
ContributorAuthor

/fr-pass

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@LukasWodka@aptracebloc@saadqbal