Skip to content

fix(helm): separate bundled dependency credential keys - #782

Merged
krisztian-gajdar merged 2 commits into
mainfrom
codex/helm-dependency-credentials
Oct 17, 2026
Merged

krisztian-gajdar merged 2 commits into
mainfrom
codex/helm-dependency-credentials

Conversation

@krisztian-gajdar

@krisztian-gajdar krisztian-gajdar commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

An operator can currently point SIE client, worker or upstream credentials at a bundled dependency's credential key without a render error. Extend the existing shared Secret-key inventory to reject those aliases for active, same-namespace Grafana SMTP/LDAP, KEDA TLS/CA, Prometheus admission TLS/CA, trust-manager TLS, Loki gateway basic auth and Loki MinIO root credentials.

Use enabled child contexts and their actual naming/namespace helpers. Preserve literal Secret names, custom data keys, generated/default names, disabled-component behavior and cross-namespace separation. Generation flags do not stand in for consumer gates: KEDA still mounts external TLS, Prometheus's root Issuer can remain active with the operator off, and its certgen Jobs read ca even without TLS/self-monitoring. Pinned certgen source.

The new real-render suite verifies dependency consumers before asserting collisions, covers worker/gateway/extra-env/MCP/upstream roles and inactive/different-key controls, and runs in the prepared Helm CI lane. README documents the finite guarantee. Arbitrary env/volume/provider/whole-Secret file layouts are separately assessed in #780; the inherited trust-manager Helm certificate namespace mismatch is tracked in #781. No dependency versions, auth defaults, deployment or live settings change.

Closes #767.

Validation

  • New dependency credential suite: 359 passed.
  • Existing Helm render + required-CI tests: 654 passed.
  • Public tooling suite (same exclusions as Python CI): 611 passed, 9 deselected.
  • mise run helm -- lint, CI Ruff format/check selections, git diff --check: passed.
  • Independent adversarial review: whole original head, zero blocking findings. The nonblocking nullable-test-helper finding is fixed with enterprise-GEL absent-consumer and generated-token regressions. Final exact-head verification: zero blocking findings, F1 resolved, all 359 assertions independently exercised and 25 original plus five follow-up mutation executions caught (overlap disclosed). CI and CodeRabbit must both finish green.

Sibling-sweep evidence

Bug class: a SIE bearer/upstream credential names the same active Secret/key as another credential owner. The internal helper was run against this isolated public tree with scope cluster; public reproduction below matches its 81 instances in 18 files. These consist of existing first-party guards, the newly covered dependency refs and the explicitly triaged operator configuration in #780/#781. The recursively extracted archives are exactly the Chart.lock dependencies from mise run helm -- dependencies.

rg -n 'secretKeyRef:|secretName:|envFrom:|existingSecret|secretKey:' deploy/helm/sie-cluster --glob '*.yaml' --glob '*.yml' --glob '*.json' --glob '*.tpl' --glob '*.md'
# 81 matches in 18 files (full output below)
rg -n 'secretKeyRef:|secretName:|envFrom:|existingSecret|secretKey:' /tmp/sie-767-dependencies --glob '*.yaml' --glob '*.yml' --glob '*.tpl' --glob '*.md'
# 396 matches in 113 pinned dependency files
Full public-tree sibling sweep
deploy/helm/sie-cluster/values.yaml:1413:    secretName: sie-tls
deploy/helm/sie-cluster/values.yaml:1449:        secretName: sie-root-ca-key-pair
deploy/helm/sie-cluster/values.yaml:1678:    existingSecrets:
deploy/helm/sie-cluster/values.yaml:2233:        existingSecret: ""
deploy/helm/sie-cluster/values.yaml:2451:  # Rendered into a chart-managed Secret when set; or point existingSecretName at
deploy/helm/sie-cluster/values.yaml:2456:  existingSecretName: ""
deploy/helm/sie-cluster/values.yaml:2471:    existingSecretName: ""
deploy/helm/sie-cluster/values.yaml:2472:    secretKey: api-key
deploy/helm/sie-cluster/templates/gateway-deployment.yaml:279:                secretKeyRef:
deploy/helm/sie-cluster/templates/gateway-deployment.yaml:288:                secretKeyRef:
deploy/helm/sie-cluster/templates/gateway-deployment.yaml:295:                secretKeyRef:
deploy/helm/sie-cluster/templates/mcp-edge-secret.yaml:2:       mcpEdge.existingSecretName at a Secret they manage out-of-band. */}}
deploy/helm/sie-cluster/templates/mcp-edge-secret.yaml:3:{{- if and .Values.mcpEdge.enabled .Values.mcpEdge.connectorSecrets (not .Values.mcpEdge.existingSecretName) }}
deploy/helm/sie-cluster/templates/_nats-auth.tpl:38:Secret holding a component's NATS password: nats.auth.existingSecrets.<component>
deploy/helm/sie-cluster/templates/_nats-auth.tpl:43:{{- $existing := dig "existingSecrets" .component "" (.auth | default dict) -}}
deploy/helm/sie-cluster/templates/_nats-auth.tpl:61:    secretKeyRef:
deploy/helm/sie-cluster/templates/_nats-auth.tpl:77:{{- fail (printf "Secret %s exists but has no password key. If it was created by hand, set nats.auth.existingSecrets to it so the chart uses it unchanged. Otherwise delete the Secret so the chart generates a new password, then restart NATS, sie-config, the gateway, and the workers." .name) -}}
deploy/helm/sie-cluster/templates/_nats-auth.tpl:122:{{- if not (dig "existingSecrets" $component "" $auth) -}}
deploy/helm/sie-cluster/templates/_nats-auth.tpl:123:{{- fail (printf "nats.install=false with nats.auth.enabled=true needs nats.auth.existingSecrets.%s: a Secret holding the %s NATS password under the key password, for the user %s on the external server. Set nats.auth.enabled=false if the external server does not require authentication." $component $component (include "sie-cluster.nats.authUser" $component)) -}}
deploy/helm/sie-cluster/templates/_nats-auth.tpl:147:    secretKeyRef:
deploy/helm/sie-cluster/templates/nats-auth-secrets.yaml:9:{{- if not (dig "existingSecrets" $component "" $auth) }}
deploy/helm/sie-cluster/templates/_helpers.tpl:183:{{- if $admin.existingSecret -}}
deploy/helm/sie-cluster/templates/_helpers.tpl:184:{{- tpl ($admin.existingSecret | toString) . -}}
deploy/helm/sie-cluster/templates/_helpers.tpl:415:    secretKeyRef:
deploy/helm/sie-cluster/templates/_helpers.tpl:1037:{{- if and $mcp.enabled (not $mcp.clusterBaseUrl) (not (dig "clusterApiKey" "existingSecretName" "" $mcp)) $mayAuthenticate -}}
deploy/helm/sie-cluster/templates/_helpers.tpl:1040:{{- $example = printf ", for example mcpEdge.clusterApiKey.existingSecretName=%s and mcpEdge.clusterApiKey.secretKey=%s" . (include "sie-cluster.gateway.tokenSecretKey" $) -}}
deploy/helm/sie-cluster/templates/_helpers.tpl:1042:{{- fail (printf "mcpEdge.enabled with gateway token auth (or a gateway auth mode known only at run time) needs mcpEdge.clusterApiKey.existingSecretName: the MCP edge calls the in-cluster gateway, which refuses requests without a token. Point it at a Secret key that holds one gateway client token%s." $example) -}}
deploy/helm/sie-cluster/templates/_helpers.tpl:1144:{{- with $betterStack.existingSecret -}}
deploy/helm/sie-cluster/templates/_helpers.tpl:1145:{{- $keys = append $keys (dict "owner" "observability.otel.collector.betterStack.existingSecret" "name" "Better Stack token" "ref" (printf "%s/%s" . $betterStack.tokenKey)) -}}
deploy/helm/sie-cluster/templates/_helpers.tpl:1151:{{- $secretName := tpl .Values.admin.existingSecret $context | default (include "grafana.fullname" .) -}}
deploy/helm/sie-cluster/templates/_helpers.tpl:1158:{{- if .Values.smtp.existingSecret -}}
deploy/helm/sie-cluster/templates/_helpers.tpl:1159:{{- $smtpSecret := .Values.smtp.existingSecret -}}
deploy/helm/sie-cluster/templates/_helpers.tpl:1165:{{- $ldapSecret := default (include "grafana.fullname" .) .Values.ldap.existingSecret -}}
deploy/helm/sie-cluster/templates/_helpers.tpl:1236:{{- if or $mcp.connectorSecrets $mcp.existingSecretName -}}
deploy/helm/sie-cluster/templates/_helpers.tpl:1239:{{- with $mcp.clusterApiKey.existingSecretName -}}
deploy/helm/sie-cluster/templates/_helpers.tpl:1240:{{- $keys = append $keys (dict "owner" "mcpEdge.clusterApiKey.existingSecretName" "name" "MCP edge cluster API key" "ref" (printf "%s/%s" . $mcp.clusterApiKey.secretKey) "role" "gateway-client") -}}
deploy/helm/sie-cluster/templates/_helpers.tpl:2792:mcpEdge.existingSecretName is set; otherwise the chart-managed one.
deploy/helm/sie-cluster/templates/_helpers.tpl:2795:{{- if .Values.mcpEdge.existingSecretName -}}
deploy/helm/sie-cluster/templates/_helpers.tpl:2796:{{- .Values.mcpEdge.existingSecretName -}}
deploy/helm/sie-cluster/templates/mcp-edge-deployment.yaml:42:            {{- if or .Values.mcpEdge.connectorSecrets .Values.mcpEdge.existingSecretName }}
deploy/helm/sie-cluster/templates/mcp-edge-deployment.yaml:45:                secretKeyRef:
deploy/helm/sie-cluster/templates/mcp-edge-deployment.yaml:61:            {{- if .Values.mcpEdge.clusterApiKey.existingSecretName }}
deploy/helm/sie-cluster/templates/mcp-edge-deployment.yaml:64:                secretKeyRef:
deploy/helm/sie-cluster/templates/mcp-edge-deployment.yaml:65:                  name: {{ .Values.mcpEdge.clusterApiKey.existingSecretName }}
deploy/helm/sie-cluster/templates/threshold-control.yaml:53:                secretKeyRef:
deploy/helm/sie-cluster/templates/config-deployment.yaml:104:                secretKeyRef:
deploy/helm/sie-cluster/templates/config-deployment.yaml:112:                secretKeyRef:
deploy/helm/sie-cluster/templates/otel-collector.yaml:23:{{- if and $betterStack.enabled (not $betterStack.existingSecret) -}}
deploy/helm/sie-cluster/templates/otel-collector.yaml:24:{{- fail "observability.otel.collector.betterStack.enabled=true requires betterStack.existingSecret" -}}
deploy/helm/sie-cluster/templates/otel-collector.yaml:122:                secretKeyRef:
deploy/helm/sie-cluster/templates/otel-collector.yaml:123:                  name: {{ $betterStack.existingSecret | quote }}
deploy/helm/sie-cluster/README.md:1180:To manage a password yourself, set `nats.auth.existingSecrets.<config|gateway|worker|route>`
deploy/helm/sie-cluster/README.md:1187:every render. Use `existingSecrets` with them, or on Argo CD set
deploy/helm/sie-cluster/README.md:1232:server. With `nats.auth.enabled=true`, set `nats.auth.existingSecrets.config`,
deploy/helm/sie-cluster/README.md:1602:`mcpEdge.clusterApiKey.existingSecretName` and `mcpEdge.clusterApiKey.secretKey`
deploy/helm/sie-cluster/README.md:1626:| Grafana SMTP (`smtp.existingSecret` set) | Literal existing Secret, `smtp.userKey` / `smtp.passwordKey` (defaults `user` / `password`). |
deploy/helm/sie-cluster/README.md:1627:| Grafana LDAP (`ldap.enabled`) | Literal `ldap.existingSecret` or Grafana fullname, `ldap-toml`. |
deploy/helm/sie-cluster/README.md:1634:| Loki NGINX gateway basic auth | Literal `gateway.basicAuth.existingSecret` or gateway fullname, `.htpasswd`; excludes the enterprise GEL gateway. |
deploy/helm/sie-cluster/README.md:1635:| Loki's optional MinIO | Literal MinIO `existingSecret` or MinIO fullname, `rootUser` / `rootPassword`. |
deploy/helm/sie-cluster/README.md:2020:    secretName: sie-tls  # default
deploy/helm/sie-cluster/README.md:2106:    secretName: sie-tls
deploy/helm/sie-cluster/README.md:2383:        existingSecret: sie-betterstack-otlp-dev-us-east-1
deploy/helm/sie-cluster/templates/worker-statefulset.yaml:410:                secretKeyRef:
deploy/helm/sie-cluster/templates/worker-statefulset.yaml:462:                secretKeyRef:
deploy/helm/sie-cluster/templates/worker-statefulset.yaml:481:                secretKeyRef:
deploy/helm/sie-cluster/templates/worker-statefulset.yaml:627:                secretKeyRef:
deploy/helm/sie-cluster/templates/worker-statefulset.yaml:874:            secretName: {{ include "sie-cluster.upstreams.secretName" $root }}
deploy/helm/sie-cluster/crds/cert-manager.crds.yaml:838:                secretName:
deploy/helm/sie-cluster/crds/cert-manager.crds.yaml:7593:                    secretName:
deploy/helm/sie-cluster/crds/cert-manager.crds.yaml:7686:                            secretName:
deploy/helm/sie-cluster/crds/cert-manager.crds.yaml:11320:                    secretName:
deploy/helm/sie-cluster/crds/cert-manager.crds.yaml:11413:                            secretName:
deploy/helm/sie-cluster/templates/self-signed-issuer.yaml:27:  secretName: {{ $self.rootCA.secretName | quote }}
deploy/helm/sie-cluster/templates/self-signed-issuer.yaml:49:    secretName: {{ $self.rootCA.secretName | quote }}
deploy/helm/sie-cluster/templates/self-signed-issuer.yaml:59:  secretName: {{ $tls.secretName | quote }}
deploy/helm/sie-cluster/templates/mcp-edge-ingress.yaml:62:      secretName: {{ $tlsSecret }}
deploy/helm/sie-cluster/templates/oauth2-proxy-ingress.yaml:26:      secretName: {{ $tls.secretName }}
deploy/helm/sie-cluster/templates/oauth2-proxy.yaml:61:                secretKeyRef:
deploy/helm/sie-cluster/templates/oauth2-proxy.yaml:66:                secretKeyRef:
deploy/helm/sie-cluster/templates/oauth2-proxy.yaml:71:                secretKeyRef:
deploy/helm/sie-cluster/templates/ingress.yaml:64:      secretName: {{ $tls.secretName }}

Pinned archive dispositions: Grafana SMTP/LDAP plus existing admin refs, KEDA serving/CA Issuer, Prometheus serving/monitor/patch-Job/root Issuer, trust-manager serving, Loki NGINX gateway and MinIO root refs now enter the same inventory. Arbitrary extension/configuration refs, scaler-defined KEDA gRPC/Vault filenames, externally backed Issuers, Prometheus/Alertmanager Secret lists and enterprise/provider layouts remain explicit operator responsibilities (#780). The trust-manager namespace-generation mismatch is not hidden by the guard (#781). Existing first-party NATS/config/gateway/worker/pull/oauth/MCP/ingress credential guards remain unchanged and are exercised by the existing Helm suite. Dependency .tgz contents and Secret payloads are not committed.

Summary by CodeRabbit

  • Bug Fixes
    • Helm deployments now detect when SIE token credentials reuse Secret keys consumed by enabled, same-namespace bundled dependencies, including Grafana, KEDA, Prometheus, trust-manager, Loki, and MinIO.
    • Reusing a different key in the same Secret remains allowed; credentials for inactive or other-namespace dependencies are not treated as collisions.
  • Documentation
    • Updated credential guidance to clarify which bundled dependency credentials are checked and which custom dependency references require separate review.
    • Documented limitations of render-time credential checks and trust-manager certificate generation.

@krisztian-gajdar
krisztian-gajdar requested a review from a team as a code owner October 17, 2026 09:26
@krisztian-gajdar

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

Please verify the pinned dependency consumer/name/key/namespace gates and shared worker/gateway/MCP/upstream alias checks, including Prometheus certgen ca without TLS/self-monitoring and the root Issuer with operator disabled. Finite operator-defined configuration scope is explicitly triaged in #780, inherited trust-manager namespace mismatch in #781. Independent adversarial/mutation report for exact head will follow; all CI must pass before merge.

@coderabbitai

coderabbitai Bot commented Oct 17, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Team
  • Run ID: ea71546e-faf7-431b-a51d-cc8466eaa875
📥 Commits

Reviewing files that changed from the base of the PR and between d5e024a and 68526e9.

📒 Files selected for processing: 5
  • .github/workflows/ci.yml
  • deploy/helm/sie-cluster/README.md
  • deploy/helm/sie-cluster/templates/_helpers.tpl
  • deploy/helm/sie-cluster/values.yaml
  • tools/ci/tests/test_helm_dependency_credentials.py

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 6 remain after this review.

📝 Walkthrough

The Helm chart now tracks selected Secret keys used by enabled, same-namespace bundled dependencies during credential-separation validation. Helm-render tests check collisions, distinct keys, inactive consumers, and namespace cases. CI runs the test suite in the Helm job.

Changes: Dependency Secret-key guard

Layer / File(s) Summary
Extend the credential-key inventory
deploy/helm/sie-cluster/templates/_helpers.tpl, deploy/helm/sie-cluster/values.yaml, deploy/helm/sie-cluster/README.md
The helper adds selected Grafana, KEDA, Prometheus, trust-manager, and Loki Secret keys to the inventory under documented enablement and namespace conditions. The values and README guidance describe checked keys and inventory limits.
Test rendered credential consumers
tools/ci/tests/test_helm_dependency_credentials.py, .github/workflows/ci.yml
Helm-render tests check active dependency Secret references, same-key collisions, distinct-key cases, generated SIE tokens, and inactive or other-namespace cases. CI excludes this suite from the general Python test run and runs it in the Helm job.

Suggested reviewers: huronat

Priority: ⬇️ Low

Merge Risk: ⚪ Minimal · up to 68526

The credential-separation change has no established merge-blocking defect. Complete the required candidate and CI checks before merging.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 10.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 10 functions across 1 files. (4 skipped: … Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly and concisely describes the main change: separating bundled Helm dependency credential keys.
Linked Issues check Passed Issue #767 requires active, same-namespace bundled dependency credentials to enter the shared Secret-key inventory. The change adds Grafana SMTP/LDAP, KEDA, Prometheus admission, trust-manager, Loki g…
Out of Scope Changes check Passed The helper changes, render tests, CI routing, README updates, and values documentation support issue #767. The PR keeps arbitrary dependency environment, volume, provider, whole-Secret, external certi…
Full details: Linked Issues check

Explanation

Issue #767 requires active, same-namespace bundled dependency credentials to enter the shared Secret-key inventory. The change adds Grafana SMTP/LDAP, KEDA, Prometheus admission, trust-manager, Loki gateway, and Loki MinIO references. The real-render tests verify consumers, names, keys, namespaces, enabled contexts, worker/gateway/extra-env/upstream/MCP aliases, generated credentials, inactive cases, cross-namespace cases, and different-key controls. The CI workflow runs the dedicated suite in the Helm lane.

Full details: Out of Scope Changes check

Explanation

The helper changes, render tests, CI routing, README updates, and values documentation support issue #767. The PR keeps arbitrary dependency environment, volume, provider, whole-Secret, external certificate, and enterprise configuration outside the finite inventory. The supplied evidence assigns those cases to #780 and the trust-manager namespace mismatch to #781. No dependency versions, authentication defaults, deployments, or live settings change.

Full details: Docstring Coverage

Explanation

Docstring coverage is 10.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 10 functions across 1 files. (4 skipped: 4 unsupported.)

Resolution

Write docstrings for the functions missing them to satisfy the coverage threshold.

  • Fix all pre-merge checks with AI
✨ Finishing Touches: 💡 2
📝 Generate docstrings: 💡
  • Commit to this branch
  • Create a new PR
🛠️ Fix failing CI checks: 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

@krisztian-gajdar

Copy link
Copy Markdown
Contributor Author

Independent adversarial review of the original PR head, posted verbatim below. F1 is being addressed with a null-safe test inspector, a rendered enterprise-GEL exclusion control and generated-token cases. The final updated head will receive a separate exact-head verification before merge.

Agent-generated adversarial security review

Reviewed head: 491d18a43896e3cab9e1af42f04a77a01d300020.

Whole-PR range: d5e024ad3ba6127b1ee176e2c85c794b76077888...491d18a43896e3cab9e1af42f04a77a01d300020 (five files: credential helper, README, values comments, dependency render tests, CI wiring).

I did not author the change. I reviewed the whole diff and pinned dependency source, independently executed the 326 new test assertions against copied charts, and ran additional generated-token/enterprise probes and 25 mutations. Tests began on the stable worktree snapshot; afterward all five source SHA-256 values were checked against this exact immutable commit and matched. The hashes are recorded in /tmp/sie-767-adversarial-probes/source-sha256.txt. No repository source, refs, services, PRs, or deconflict state were changed by this reviewer. All mutations were under /tmp. Credentials were not technically stripped from the environment; restrictions rested on the review instructions.

Scope and source verification

The extension stays within the existing sie-cluster.wiredSecretKeys inventory. Both token separation and upstream credential separation continue reading that one list; existing first-party keys are unchanged. Each added dependency uses its enabled child context and actual consumer namespace, rather than treating SIE's global.namespace as a dependency relocation.

  • Grafana SMTP/LDAP: _helpers.tpl:1158-1166 matches pinned Grafana _pod.tpl:1120-1131,1261-1272: literal existing SMTP name and configured username/password keys; enabled LDAP with literal existing name or Grafana fullname and ldap-toml. Disabled Grafana, disabled LDAP, unset SMTP, and another namespace do not reserve those keys. Existing admin tpl context behavior is unchanged.
  • KEDA: :1173-1186 reflects unconditional operator/metrics mounts once installed, including generation-off and webhooks-off cases. It checks explicit serving filenames ca.crt, tls.crt, tls.key and the namespaced CA Issuer's tls.crt/tls.key when cert-manager and issuer generation are enabled. generateCA=false still references the existing CA. Names are literal; operator rename does not rename these Secrets.
  • Prometheus: :1188-1211 matches both serving Deployments independently of admissionWebhooks.enabled, switches key filenames with cert-manager mode, and protects the root CA Issuer even with the operator disabled. The independent patch-Job CA predicate at :1200-1203 covers ca while TLS and self-monitoring are disabled. I inspected the official certgen source at its advertised pinned revision: create, patch, and Secret handling. Both Jobs read existing ca; create writes ca, cert, and key only when creating the Secret. It does not read existing cert/key. This is an advertised-source check, not registry binary/digest attestation. Detailed evidence is /tmp/sie-767-prom-certgen-evidence.md.
  • trust-manager: :1213-1220 follows child name/namespace helpers and both certificate-generation modes. It does not mistake app.trust.namespace for the webhook namespace. The inherited Helm-generation/namespace-override mismatch is documented and linked to fix(helm): align trust-manager Helm TLS with its namespace override #781, rather than silently repaired or treated as an actual same-namespace mount.
  • Loki NGINX and MinIO: :1221-1234 matches literal/basic-auth Secret naming and the NGINX/GEL selection. Enabled MinIO uses its own Secret helper and root keys in distributed/standalone modes; another namespace or disabled child does not reserve them. An independent valid GEL render confirmed the .htpasswd Secret is not mounted by GEL, and an alias remains allowed; removing only the GEL exclusion incorrectly rejects this control.

Detailed pinned TLS gates, names, namespaces, root Issuers, and proposed edge cases are retained in /tmp/sie-767-tls-inventory.md. I also inspected the pinned Grafana and Loki/MinIO consumer templates directly for this review.

Abuse cases and independent tests

PYTHONDONTWRITEBYTECODE=1 .venv/bin/python /tmp/sie-767-review-probes.py completed all new suite assertions against a copied chart:

  • 34 real consumer fixtures, each exercised for worker, gateway, gateway extraEnv, upstream, and MCP credential aliases: 170 rejection cases.
  • 34 positive consumer checks and 34 controls permitting a different key in the same Secret.
  • 87 disabled/unused-key/other-namespace controls, including independent SIE/dependency namespace overrides, alternate filenames, external Issuers, and inactive CA settings.
  • The CI-lane assertion: the suite is excluded from the unprepared tooling lane and runs after dependency preparation in the Helm lane.

Total: 326 assertions/test cases passed. All were executed independently here; the author's larger existing-suite/lint results are separate evidence.

Mutation checks also passed:

  • Removing each of the ten new owner entries (SMTP, LDAP, KEDA serving, KEDA signer, Prometheus serving, Prometheus CA, Prometheus root signer, trust-manager, Loki basic auth, MinIO) makes its rejection test fail.
  • Removing namespace checks is caught by six namespace controls.
  • Eight further activation/key mutations are caught: LDAP activation, KEDA cert-manager/issuer predicates, Prometheus TLS consumer predicate, patch-Job CA inclusion, custom root Issuer exclusion, cert-manager filename switch, and MinIO password key.
  • The independent GEL probe catches removal of the enterprise exclusion, making 25 caught mutations overall.

/tmp/sie-767-extra-probes.py independently checked generated worker tokens and generated gateway tokens in both enforced and mode-none upgrade states: making Grafana SMTP reference each generated Secret's SIE_AUTH_TOKEN key fails the intended guard. This checks the generated-credential representation alongside the suite's operator-managed representations. Token values were never printed or read from a live cluster.

Security effects considered include accidental privilege expansion by credential alias, foreign credential presentation upstream, generated and operator-managed names, child naming/helper context, disabled consumers, cross-namespace false positives, alternate key names and certificate modes, CA Issuer consumers, and jobs reading keys without TLS serving. This is static deployment validation; replay, expiry, authentication middleware behavior, and tenant authorization are not changed by this diff.

Finding

F1. Nonblocking: the test consumer inspector rejects a valid nullable initContainers render

Where: tools/ci/tests/test_helm_dependency_credentials.py:265 at this head.

Reproduction: render {**LOKI, "loki.gateway.enabled": true, "loki.gateway.basicAuth.enabled": true, "loki.enterprise.enabled": true, "loki.enterprise.gelGateway": true} using the existing test constants, then pass the resulting documents to consumed_refs. The enterprise Deployment has initContainers: null. Concatenating spec.get("containers", []) + spec.get("initContainers", []) raises TypeError: can only concatenate list (not "NoneType") to list.

The guard itself matches the enterprise exclusion and independently rendered correctly. The defect affects test robustness and prevents using the common consumer inspector for this relevant negative control; it does not change deployed manifests or create an authentication bypass. The current 326 cases remain green because they do not exercise that combination through the inspector.

Recommended fix: normalize nullable container lists with or [] and add the GEL inactive/absent-consumer case. Use the rendered absence of the basic-auth mount as evidence, and require that dropping the enterprise exclusion breaks the negative control. I used a null-safe inspector only in my /tmp probe to finish that independent check; no repository test was changed by this reviewer.

One additional test-quality limit is informational: unrestricted Secret-volume fixtures prove that a Secret is mounted, not which filenames an application reads. Here, explicit serving-argument source checks and the positive/negative certificate-filename cases establish the intended pinned contract. Future dependency upgrades still require source review rather than treating the wildcard fixture alone as proof of per-key correctness.

Sibling coverage and bounded exclusions

The structured inventory covers the known #767 consumers: Grafana SMTP/LDAP, KEDA serving/CA, Prometheus serving/CA/patch/root signer, trust-manager serving, Loki NGINX basic auth, and optional MinIO root credentials. The scan command and full per-file counts are saved at /tmp/sie-767-sibling-sweep.txt; it searched the extracted pinned templates including nested Grafana and MinIO for secretKeyRef:|secretName:|existingSecret|inject-ca-from|--secret-name=. These matches include raw configuration/enterprise/provider and CRD-schema surfaces that are not silently declared protected.

The README explicitly excludes KEDA grpcTLSCertsSecret/hashiCorpVaultTLS, arbitrary env/volume/provider configuration, extra MinIO Secrets, external Issuer backing Secrets, raw enterprise/cloud-storage settings, and custom dependency images, with linked follow-up #780. This is acceptable explicit triage under the security workflow: the optional KEDA fields mount whole Secrets but the pin gives no fixed per-scaler filenames, so adding invented tls.key coverage would overstate the guarantee. A future whole-Secret or user-configured-file-layout design needs separate review. The trust-manager Helm namespace mismatch is likewise explicitly linked to #781. I inspected repository documentation and the author's successful issue-creation record; I did not independently fetch those issue bodies.

No new blocking security defect was found in the implementation. The only new finding is the bounded test-helper issue above. No live Kubernetes upgrade, Secret content lookup, external endpoint, hosted service, or release was exercised. A new immutable head after addressing F1 requires a fresh verification of that delta; this report applies exactly to 491d18a43896e3cab9e1af42f04a77a01d300020.

Blocking findings: 0

@krisztian-gajdar

Copy link
Copy Markdown
Contributor Author

Agent-generated adversarial security verification

Verified head: 68526e9fff6a59b691c7ce884ab43d392e6edf56.

Whole-PR range: d5e024ad3ba6127b1ee176e2c85c794b76077888...68526e9fff6a59b691c7ce884ab43d392e6edf56.

Follow-up delta: 491d18a43896e3cab9e1af42f04a77a01d300020...68526e9fff6a59b691c7ce884ab43d392e6edf56, solely tools/ci/tests/test_helm_dependency_credentials.py. The credential guards, README, values comments, and CI wiring are byte-identical to the whole-PR security review recorded unchanged in /tmp/sie-767-adversarial-run1.md.

I independently verified every reviewed source file against git show at this exact final commit: the four unchanged files match the original review's SHA-256 record; the final test file matches the SHA-256 of the source exercised by the follow-up probes. HEAD was independently confirmed. The earlier review began from a stable snapshot that was subsequently matched to immutable 491d18; this follow-up binds the combined evidence to immutable 68526e9.

F1 disposition

RESOLVED. The consumer inspector now normalizes nullable containers and initContainers lists. The valid enterprise GEL fixture is included among inactive cases, and a rendered-consumer assertion proves that its NGINX basic-auth credential is absent. Its worker, gateway, and upstream aliases remain allowed. This corrects the test-helper failure without broadening or changing deployed credential validation.

The added absent-consumer checks correctly exclude three key-mode cases that still mount the same whole Secret for other known filenames. Those cases retain their explicit alternate-key controls. A whole-Secret mount does not establish which filenames an executable reads; the pinned-source analysis remains part of the contract.

The test delta also adds generated worker-token and generated gateway-token aliases, including the gateway's mode-none preparation step. Each is rejected when a dependency consumer points at the generated Secret's SIE_AUTH_TOKEN key.

Independent execution and mutation evidence

The original review independently executed 326 suite assertions against /tmp chart copies, covering all targeted dependency families, five SIE credential representations, actual consumers, separate keys, disabled gates, namespaces, alternate filenames, external Issuers, and CI lane placement. It also executed 25 mutation runs: ten owner-entry removals, six namespace changes, eight activation/key changes, and the independent GEL-exclusion mutation.

For this follow-up, PYTHONDONTWRITEBYTECODE=1 .venv/bin/python /tmp/sie-767-adversarial-fixed-probes.py independently executed 33 additional suite assertions:

  • 27 absent-consumer fixtures;
  • three GEL alias controls;
  • three generated-token alias cases.

All passed, bringing independently executed suite assertions to 359 across the two reviews. The author's single full-suite run also reports 359 passing tests; that is separate evidence.

Five follow-up mutation runs passed:

  • Reverting the nullable-list fix makes the new GEL absent-consumer test raise the original TypeError.
  • Removing the GEL exclusion makes its new inactive alias control fail.
  • Removing the SMTP inventory entry makes each of the three generated-token alias tests fail.

These are 25 original plus five follow-up mutation executions, not 30 distinct mutation classes. The GEL predicate and SMTP entry properties intentionally overlap the original review; the follow-up proves the newly added repository tests cover those properties and the three generated representations. Every source mutation and test-module mutation was confined to uniquely named /tmp copies.

git diff --check for the final whole-PR range was clean. No new finding was found in the final delta.

Scope and retained limits

The original pinned-source conclusions remain applicable: the shared list protects the documented Grafana SMTP/LDAP, KEDA serving/CA, Prometheus serving/self-monitoring/patch-Job/root-CA, trust-manager serving, Loki NGINX, and optional MinIO credential refs. It uses enabled child contexts, actual consumer namespaces, names, keys, and gates, and feeds all existing SIE token/upstream readers. The independent generated-token probes confirm the same inventory also applies before gateway enforcement.

The explicit exclusions for scaler-defined KEDA gRPC/Vault file layouts and arbitrary dependency env/volume/provider/custom-image configuration remain acceptable bounded triage linked to #780. The inherited trust-manager Helm-certificate namespace mismatch remains documented and linked to #781. Neither is silently claimed fixed by this PR. Detailed source and sibling-sweep records remain /tmp/sie-767-tls-inventory.md, /tmp/sie-767-prom-certgen-evidence.md, and /tmp/sie-767-sibling-sweep.txt.

This reviewer did not author source or change repository files, refs, PRs, services, or deconflict state. Credentials were not technically stripped from the environment; the read-only restriction rests on instructions and observed actions. No live Secret data was read or printed. Except for the explicitly authorized read-only retrieval of official pinned certgen source during the original review, verification remained local; live issue bodies, registry image binaries, Kubernetes installs/upgrades, enforcing CNIs, and hosted endpoints were not independently tested. Static alias rejection does not assert that arbitrary TLS material is a valid runtime bearer token.

Blocking findings: 0

@krisztian-gajdar

Copy link
Copy Markdown
Contributor Author

Current-head release candidate has one setup failure: CPU/default job failed in mise's cache-save action, before buildx/build/smoke/artifact steps ran. Cache upload reported a non-200 response followed by ENOENT opening the runner's temporary cache.tzst. No image was built by that job.

The same head's other tool setups and several artifact builds passed. This points to cache/runner infrastructure; it is not yet classified as transient until an unchanged-head retry passes. The job retry endpoint currently returns The workflow run containing this job is already running. I will retry the failed job after the remaining candidate jobs finish and require the full candidate and CI gates green before merge. No source/default/lock change or check bypass is being used.

@coderabbitai

coderabbitai Bot commented Oct 17, 2026 •

Copy link
Copy Markdown
✅ Action performed

Full review finished.

@krisztian-gajdar
krisztian-gajdar merged commit ac600a5 into main Oct 17, 2026
64 of 66 checks passed
@krisztian-gajdar
krisztian-gajdar deleted the codex/helm-dependency-credentials branch October 17, 2026 10:08
@krisztian-gajdar

Copy link
Copy Markdown
Contributor Author

Merged at ac600a51d1c5ea2af17d495b38e896dd3472b3cc after all42current-head checks passed, exact-head CodeRabbit approval and zero unresolved threads. Both independent security reports are linked in the PR body. The CPU/default setup failure was resolved by one unchanged-head retry: successful retry; the candidate's native package and completion gates also passed on attempt2. No source/check bypass or live cluster/default change was used. #767 is closed. The separate trust-manager configuration guard remains tracked in #781.

Sign up for free to 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.

fix(helm): extend credential separation to bundled dependency Secrets

1 participant