Skip to content

feat(chart): provision per-experiment DB credentials (RFC-0003 D10, backend#1181) - #503

Merged
LukasWodka merged 2 commits into
developfrom
feat/1181-chart-per-experiment-db-creds
Jul 31, 2026
Merged

feat(chart): provision per-experiment DB credentials (RFC-0003 D10, backend#1181)#503
LukasWodka merged 2 commits into
developfrom
feat/1181-chart-per-experiment-db-creds

Conversation

@LukasWodka

@LukasWodka LukasWodka commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Summary

The chart half of RFC-0003 D10 (backend#1181) — flips client-runtime#235 from inert to live. All flag-gated on perExperimentDbCreds (default false); default installs render byte-for-byte unchanged.

  • perExperimentDbCreds value (schema-typed, own banner in values.yaml) → renders PER_EXPERIMENT_DB_CREDS=1, TB_CREDMGR_USER=tb_credmgr, and TB_CREDMGR_PASSWORD (via secretKeyRef, never plain) onto the jobs-manager container.
  • secrets.yaml: generate-once TB_CREDMGR_PASSWORD — same upgrade-stable lookup pattern as POD_TOKEN_SIGNING_SECRET (a regenerated password would needlessly churn the account), emitted only when the flag is on.
  • rbac.yaml: the jobs-manager Role's secrets verbs gain delete — needed for the revoke path (_revoke_db_creds deletes the per-job cred Secret; the Secret is otherwise GC'd via its Job ownerReference).
  • Chart.yaml 1.9.8 → 1.9.9 (chart publishes on version change).

jobs-manager self-provisions the tb_credmgr account from this Secret on startup (client-runtime#235) — no Helm hook Job needed against the digest-frozen mysql image.

Safety

Default false = today's shared-credential behavior, bit-for-bit. Enablement is per environment (dev first), after the OQ4 image check (all task images already read the injected creds — verified). Companion: client-runtime#235 (the mint/inject/revoke code); merge either order — both are inert until this flag is on.

Coordination

Touches the jobs-manager env, secrets, rbac, and values — not the images.ingestor block, so no collision with the #1360 / #490 ingestor-pin work. Chart bumped to 1.9.9; if #490 lands first at 1.9.9, I'll rebase this to 1.9.10.

Tests

2 new helm-unittest cases (env absent by default; flag on renders the 3 env entries incl. the secretKeyRef). 300 helm tests pass.

Epic: backend#1151 · Design: backend#1181 · Code: tracebloc/client-runtime#235

🤖 Generated with Claude Code


Note

Medium Risk
Touches credential material and RBAC for Secret deletion, but behavior stays off by default and is limited to chart templating until operators enable the flag alongside client-runtime mint/revoke code.

Overview
Adds RFC-0003 D10 chart wiring so environments can turn on per-experiment MySQL credentials via perExperimentDbCreds (default false; unchanged installs stay byte-identical). Bumps the chart to 1.9.9.

When the flag is on, the chart exposes PER_EXPERIMENT_DB_CREDS, TB_CREDMGR_USER, and TB_CREDMGR_PASSWORD (from a secretKeyRef) on jobs-manager; materializes upgrade-stable TB_CREDMGR_PASSWORD in the main Secret (generate-once / lookup / optional credmgrPassword pin with alphanumeric validation); and grants jobs-manager delete on Secrets only (ClusterRole and namespace Role) for per-job cred Secret cleanup. Values and schema document the knobs; helm-unittest cases cover default-off behavior and flag-on rendering.

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

…ackend#1181)

The chart half that flips client-runtime#235 from inert to live:
- perExperimentDbCreds value (default false, schema-typed) → renders
  PER_EXPERIMENT_DB_CREDS + TB_CREDMGR_USER + TB_CREDMGR_PASSWORD onto
  jobs-manager (password via secretKeyRef, never plain).
- secrets.yaml: generate-once TB_CREDMGR_PASSWORD (upgrade-stable, same
  lookup pattern as POD_TOKEN_SIGNING_SECRET), emitted only when enabled.
- rbac: secrets verbs gain 'delete' — jobs-manager deletes the per-job
  cred Secret in the revoke path.
- Chart.yaml 1.9.8 -> 1.9.9 (publishes on version change).
Default installs render byte-identically (all flag-gated; 300 helm tests,
both sides pinned). jobs-manager self-provisions the tb_credmgr account
from this Secret on startup.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@LukasWodka

Copy link
Copy Markdown
Contributor Author

👋 Heads-up — Code review queue is at 32 / 30

Above the WIP limit. The team convention is to review existing PRs before opening new work.

Open PRs currently in Code review (oldest first):

Pull from review before opening new work. (This is a nudge from the kanban WIP check, not a block.)

@cursor cursor Bot 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.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 7522412. Configure here.

Comment thread client/Chart.yaml

@saqlainsyed007 saqlainsyed007 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.

Focused, well-documented change — the env/secret material is cleanly flag-gated. The one structural gap: the RBAC grant is not gated on perExperimentDbCreds, so it applies to every install and breaks the "default-off / byte-for-byte unchanged" guarantee this PR is built around. Details inline.

Comment thread client/templates/rbac.yaml Outdated
Comment thread client/templates/secrets.yaml Outdated
Comment thread client/templates/secrets.yaml
Comment thread client/tests/jobs_manager_test.yaml
…Bugbot #503)

- rbac: the Secret `delete` verb is now flag-gated on perExperimentDbCreds
  and scoped to `secrets` alone (was on configmaps+secrets, every install).
  Default-off is byte-for-byte `["create", "get"]` again — a cluster-wide
  delete-on-all-Secrets ClusterRole no longer ships to every install; the
  verb the revoke path needs only appears when the flag is on (Saqlain #A).
- secrets: TB_CREDMGR_PASSWORD gains the 3rd resolution tier — an explicit
  `.Values.credmgrPassword` operator pin (DR / pre-created MySQL account /
  forced rotation), mirroring podTokenSigningSecret; validated alphanumeric
  (jobs-manager's constraint) with a fail-fast. Also documents the
  off->on->off->on regen edge and that the pin is its fix (Saqlain #B/#C).
- Chart appVersion 1.9.8 -> 1.9.9, back in lockstep with version so the
  `app.kubernetes.io/version` labels report the shipped chart (Bugbot).
- tests: secrets.yaml + rbac.yaml helm-unittests for both flag states
  (credmgr key absent/present, pin flows, non-alnum rejected, delete verb
  gated + secrets-only). 307 helm tests pass; helm lint clean (Saqlain #D).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@LukasWodka

Copy link
Copy Markdown
Contributor Author

Thanks — all four addressed in 3afec19, plus Bugbot's appVersion:

  • #A — the Secret delete verb is now flag-gated on perExperimentDbCreds and scoped to secrets alone (both the ClusterRole and the namespace Role). Default-off is back to ["create", "get"] — byte-for-byte unchanged, no cluster-wide delete-on-all-Secrets shipping to every install.
  • #CTB_CREDMGR_PASSWORD gains the 3rd tier: an explicit .Values.credmgrPassword operator pin (DR / pre-created account / forced rotation), mirroring podTokenSigningSecret, validated alphanumeric with a fail-fast.
  • #B — documented the off→on→off→on regen edge in the comment, and that the pin is its fix.
  • #D — added helm-unittests for both secrets.yaml (credmgr key absent off / present on / pin flows / non-alnum rejected) and rbac.yaml (delete verb gated + secrets-only). 307 helm tests, lint clean.
  • BugbotappVersion bumped 1.9.8 → 1.9.9, back in lockstep.

bugbot run

@saqlainsyed007 saqlainsyed007 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.

Re-reviewed after the push — all five points are addressed cleanly. Thanks for the thorough turnaround.

  • RBAC delete gated + secrets-only — now a separate resources: ["secrets"] rule under {{- if .Values.perExperimentDbCreds }} in both the ClusterRole and Role; default installs grant no extra delete, and configmaps stay at create/get. ✅
  • Operator pin.Values.credmgrPassword added as tier 1 of a 3-tier resolution mirroring podTokenSigningSecret, with fail-fast alphanumeric validation, schema, and values docs. ✅
  • Toggle rotation — documented as an edge with the pin named as the mitigation. ✅
  • Testsrbac_test.yaml (default-off no delete; flag-on secrets-only for ClusterRole + Role) and secrets_test.yaml (absent by default, present when on, pin flows through, non-alphanumeric pin rejected). documentIndex usage matches the existing convention. ✅

appVersion bump to 1.9.9 alongside the chart version is a fine tidy-up. LGTM.

@LukasWodka
LukasWodka merged commit 6d6c817 into develop Jul 31, 2026
19 checks passed
@LukasWodka

Copy link
Copy Markdown
Contributor Author

/fr-pass

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.

3 participants