Skip to content

fix: move Keycloak admin credentials from ConfigMap to Secret (rebased #161) - #179

Merged
pdettori merged 3 commits into
rossoctl:mainfrom
mrsabath:fix/cm-to-secret-rebased
Mar 9, 2026
Merged

fix: move Keycloak admin credentials from ConfigMap to Secret (rebased #161)#179
pdettori merged 3 commits into
rossoctl:mainfrom
mrsabath:fix/cm-to-secret-rebased

Conversation

@mrsabath

@mrsabath mrsabath commented Mar 6, 2026

Copy link
Copy Markdown
Contributor

Summary

Changes from original #161

  1. Conflict resolution — 3 files had conflicts due to recent merges (feat: migrate demo-ui.md from demo realm to kagenti realm #149 slimmed demo ConfigMaps, feat: add agent audience scope to platform clients during registration #172 added PLATFORM_CLIENT_IDS)
  2. Demo docs updated — Step 2 (UI) / Step 3 (manual) now include kubectl create secret generic keycloak-admin-secret
  3. Troubleshooting updated — "Invalid client credentials" section mentions checking the Secret
  4. Tests updated — PR FIX resolve #822 changing cm to secret #161 tests adapted to use BuildClientRegistrationContainerWithSpireOption (current API)

Related

Test plan

  • All 8 injector unit tests pass
  • E2E: webhook injects secretKeyRef for admin creds
  • E2E: client-registration reads from Secret and registers successfully
  • E2E: full agent flow works (inbound validation + outbound client_credentials + tool call)

Signed-off-by: Mariusz Sabath mrsabath@gmail.com

cooktheryan and others added 2 commits March 6, 2026 18:04
Signed-off-by: Ryan Cook <rcook@redhat.com>
Update demo-ui.md and demo-manual.md to document the new
keycloak-admin-secret Secret that client-registration reads
admin credentials from (instead of the environments ConfigMap).

Assisted-By: Claude (Anthropic AI) <noreply@anthropic.com>
Signed-off-by: Mariusz Sabath <mrsabath@gmail.com>

@pdettori pdettori left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Good security improvement moving Keycloak admin credentials from ConfigMap to a dedicated Secret. Code, RBAC, examples, docs, and tests are all updated consistently.

Areas reviewed: Go, Helm/RBAC, YAML, Docs
Commits: 2, all signed-off ✓
CI: passing ✓

One suggestion on configmaps-webhook.yaml (misplaced comment block) and two minor test robustness nits. Nothing blocking.

name: keycloak-admin-secret
namespace: team1
type: Opaque
stringData:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

suggestion: The --- + Secret header insertion causes the PLATFORM_CLIENT_IDS comment block (the lines after KEYCLOAK_ADMIN_PASSWORD) to land under the Secret's stringData: instead of the ConfigMap's data:. The comments are YAML comments so it's not functionally broken, but it's misleading — a reader would think PLATFORM_CLIENT_IDS belongs in the Secret. Consider moving the PLATFORM_CLIENT_IDS comment block back above the --- separator under the ConfigMap.

@@ -134,3 +134,45 @@ func TestBuildClientRegistrationContainer_HasPlatformClientIDsEnv(t *testing.T)
t.Error("client-registration container missing PLATFORM_CLIENT_IDS env var")
}
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nit: This test silently passes if neither KEYCLOAK_ADMIN_USERNAME nor KEYCLOAK_ADMIN_PASSWORD is found in the env list at all (the inner loop just skips). Consider adding a found bool or t.Errorf if the key is absent, so the test catches accidental removal of these env vars.

}
}
}
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nit: Same as above — silently passes if KEYCLOAK_URL or KEYCLOAK_REALM are missing from the env list entirely.

verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "list", "watch"]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

👍 Good least-privilege: only get, list, watch on secrets — no write access needed.

- Move PLATFORM_CLIENT_IDS comment block from Secret stringData back
  to the environments ConfigMap data section where it belongs
- Add 'found' checks to AdminCredentialsFromSecret test so it fails
  if KEYCLOAK_ADMIN_USERNAME/PASSWORD env vars are absent entirely
- Add 'found' checks to NonSensitiveKeysFromConfigMap test so it fails
  if KEYCLOAK_URL/KEYCLOAK_REALM env vars are absent entirely

Assisted-By: Claude (Anthropic AI) <noreply@anthropic.com>
Signed-off-by: Mariusz Sabath <mrsabath@gmail.com>
@pdettori
pdettori merged commit 0869305 into rossoctl:main Mar 9, 2026
3 checks passed
vz-ibm added a commit to vz-ibm/kagenti-extensions that referenced this pull request Aug 10, 2026
Reviewer OsherElhadad flagged three blocking issues (plus CodeQL alert rossoctl#179):

1. _patch_watsonx_for_reasoning_models was unconditional — it applied to
   every WatsonX deployment including the default mistral-large-2512, which
   supports response_format natively. That silently regressed structured
   output for existing users. Gate the patch behind a new
   SPARC_SCHEMA_IN_PROMPT=true setting (Settings.schema_in_prompt); the
   default path is now unchanged.

2. All three _patch_* helpers rebound methods on the shared ALTK class
   without a re-entry guard. ReflectionEngine caches components per track
   and lazily builds them, so a track switch would wrap the already-wrapped
   method — retry counts multiplied and debug lines duplicated on every
   subsequent call. Add _sparc_patched_reasoning / _sparc_patched_retry /
   _sparc_patched_debug sentinel attributes; each _patch_* no-ops if its
   sentinel is already set.

3. engine.reflect logged raw tool arguments at INFO. Args are
   caller-controlled — embedded newlines let a caller forge log lines
   (CodeQL alert rossoctl#179) — and can carry payloads (PII, payment ids, etc.).
   The same hunk had also dropped session_id/track from INFO. Restore
   session_id and track at INFO alongside tool/decision/score, and log args
   only at DEBUG when SPARC_LOG_REQUESTS=true.

Also addresses smaller items from the same review:

- tests/test_haiku_empty_response.py: replaced production PII in the
  conversation fixture (user id, names, DOBs, payment id, reservation ids)
  with synthetic values; gated both live-LLM probes behind pytest.skipif so
  they only run when RUN_HAIKU_TESTS=1 plus OAIKEY/OAIBASE are set (matches
  the reviewer's suggested opt-in path).
- tests/test_providers.py: added three deterministic unit tests — retry
  wrapper recovers after two ValueError empty-response failures, retry
  wrapper re-raises unrelated ValueErrors, and all three patches are
  idempotent under repeat application. No credentials or network required;
  fills in the coverage gap the reviewer noted for the retry and
  schema-injection wrappers.

Signed-off-by: Vitaly Zabershinsky <VITALYZ@il.ibm.com>
oblinder pushed a commit to s-and-p-team/cortex that referenced this pull request Aug 12, 2026
Reviewer OsherElhadad flagged three blocking issues (plus CodeQL alert rossoctl#179):

1. _patch_watsonx_for_reasoning_models was unconditional — it applied to
   every WatsonX deployment including the default mistral-large-2512, which
   supports response_format natively. That silently regressed structured
   output for existing users. Gate the patch behind a new
   SPARC_SCHEMA_IN_PROMPT=true setting (Settings.schema_in_prompt); the
   default path is now unchanged.

2. All three _patch_* helpers rebound methods on the shared ALTK class
   without a re-entry guard. ReflectionEngine caches components per track
   and lazily builds them, so a track switch would wrap the already-wrapped
   method — retry counts multiplied and debug lines duplicated on every
   subsequent call. Add _sparc_patched_reasoning / _sparc_patched_retry /
   _sparc_patched_debug sentinel attributes; each _patch_* no-ops if its
   sentinel is already set.

3. engine.reflect logged raw tool arguments at INFO. Args are
   caller-controlled — embedded newlines let a caller forge log lines
   (CodeQL alert rossoctl#179) — and can carry payloads (PII, payment ids, etc.).
   The same hunk had also dropped session_id/track from INFO. Restore
   session_id and track at INFO alongside tool/decision/score, and log args
   only at DEBUG when SPARC_LOG_REQUESTS=true.

Also addresses smaller items from the same review:

- tests/test_haiku_empty_response.py: replaced production PII in the
  conversation fixture (user id, names, DOBs, payment id, reservation ids)
  with synthetic values; gated both live-LLM probes behind pytest.skipif so
  they only run when RUN_HAIKU_TESTS=1 plus OAIKEY/OAIBASE are set (matches
  the reviewer's suggested opt-in path).
- tests/test_providers.py: added three deterministic unit tests — retry
  wrapper recovers after two ValueError empty-response failures, retry
  wrapper re-raises unrelated ValueErrors, and all three patches are
  idempotent under repeat application. No credentials or network required;
  fills in the coverage gap the reviewer noted for the retry and
  schema-injection wrappers.

Signed-off-by: Vitaly Zabershinsky <VITALYZ@il.ibm.com>
Signed-off-by: Oleg Blinder <oblinder@gmail.com>
oblinder pushed a commit to s-and-p-team/cortex that referenced this pull request Aug 12, 2026
Reviewer OsherElhadad flagged three blocking issues (plus CodeQL alert rossoctl#179):

1. _patch_watsonx_for_reasoning_models was unconditional — it applied to
   every WatsonX deployment including the default mistral-large-2512, which
   supports response_format natively. That silently regressed structured
   output for existing users. Gate the patch behind a new
   SPARC_SCHEMA_IN_PROMPT=true setting (Settings.schema_in_prompt); the
   default path is now unchanged.

2. All three _patch_* helpers rebound methods on the shared ALTK class
   without a re-entry guard. ReflectionEngine caches components per track
   and lazily builds them, so a track switch would wrap the already-wrapped
   method — retry counts multiplied and debug lines duplicated on every
   subsequent call. Add _sparc_patched_reasoning / _sparc_patched_retry /
   _sparc_patched_debug sentinel attributes; each _patch_* no-ops if its
   sentinel is already set.

3. engine.reflect logged raw tool arguments at INFO. Args are
   caller-controlled — embedded newlines let a caller forge log lines
   (CodeQL alert rossoctl#179) — and can carry payloads (PII, payment ids, etc.).
   The same hunk had also dropped session_id/track from INFO. Restore
   session_id and track at INFO alongside tool/decision/score, and log args
   only at DEBUG when SPARC_LOG_REQUESTS=true.

Also addresses smaller items from the same review:

- tests/test_haiku_empty_response.py: replaced production PII in the
  conversation fixture (user id, names, DOBs, payment id, reservation ids)
  with synthetic values; gated both live-LLM probes behind pytest.skipif so
  they only run when RUN_HAIKU_TESTS=1 plus OAIKEY/OAIBASE are set (matches
  the reviewer's suggested opt-in path).
- tests/test_providers.py: added three deterministic unit tests — retry
  wrapper recovers after two ValueError empty-response failures, retry
  wrapper re-raises unrelated ValueErrors, and all three patches are
  idempotent under repeat application. No credentials or network required;
  fills in the coverage gap the reviewer noted for the retry and
  schema-injection wrappers.

Signed-off-by: Vitaly Zabershinsky <VITALYZ@il.ibm.com>
Signed-off-by: Oleg Blinder <oblinder@gmail.com>
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