Skip to content

[WIP] Add support for Backstage/RHDH MCP DCR #219

Open
maysunfaisal wants to merge 1 commit into
redhat-ai-dev:developmentfrom
maysunfaisal:feat/dcr-mcp-auth-v2
Open

[WIP] Add support for Backstage/RHDH MCP DCR #219
maysunfaisal wants to merge 1 commit into
redhat-ai-dev:developmentfrom
maysunfaisal:feat/dcr-mcp-auth-v2

Conversation

@maysunfaisal

Copy link
Copy Markdown
Contributor

What does this PR do?

I'll clean up this PR/branch as things progress on redhat-developer/rhdh-plugins#3347

Which issue(s) does this PR fix

https://redhat.atlassian.net/browse/RHIDP-11657

How to test changes / Special notes to the reviewer

@qodo-code-review

qodo-code-review Bot commented Jun 10, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (4) 📘 Rule violations (1) 📎 Requirement gaps (0)

Context used
✅ Tickets: RHIDP-11657
✅ Compliance rules (platform): 4 rules

Grey Divider


Action required

1. rhdh-plugin-lightspeed tag format invalid 📘 Rule violation ≡ Correctness
Description
Several OCI plugin package references in charts/rhdh/values.yaml use non-compliant tag texts
(dcr-0.4.0!… for the Lightspeed and Lightspeed backend plugins, and pr_2498__0.1.6 for a newly
added package) that do not match the required bs_<backstage-version>__<plugin-version> format.
This violates the enforced plugin image tag convention mandated for plugin images in this values
file.
Code

charts/rhdh/values.yaml[R339-341]

    plugins:
-      - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed:bs_1.49.4__2.8.5
+      - package: oci://quay.io/maysunfaisal/rhdh-plugin-lightspeed:dcr-0.4.0!red-hat-developer-hub-backstage-plugin-lightspeed
        disabled: false
Evidence
PR Compliance ID 902156 mandates that OCI plugin image tags in charts/rhdh/values.yaml follow the
format bs_<backstage-version>__<plugin-version>. The cited tags for the Lightspeed and Lightspeed
backend packages use dcr-0.4.0!…, which neither starts with bs_ nor uses the required __
separator pattern, and the newly added tag pr_2498__0.1.6 similarly does not start with bs_,
demonstrating that these references break the required naming convention.

Rule 902156: Enforce OCI plugin image tag format in charts/rhdh/values.yaml
charts/rhdh/values.yaml[339-341]
charts/rhdh/values.yaml[366-368]
charts/rhdh/values.yaml[13-15]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`charts/rhdh/values.yaml` contains multiple OCI plugin package tags that do not follow the required `bs_<backstage-version>__<plugin-version>` convention (including `dcr-0.4.0!…` tags for the Lightspeed and Lightspeed backend plugins and the newly added `pr_2498__0.1.6` tag).

## Issue Context
PR Compliance ID 902156 requires all OCI plugin image tags in `charts/rhdh/values.yaml` to match `bs_<backstage-version>__<plugin-version>` (i.e., start with `bs_` and use the `__` separator between the two non-empty segments). Update the non-compliant tags to conform to this enforced format.

## Fix Focus Areas
- charts/rhdh/values.yaml[13-15]
- charts/rhdh/values.yaml[339-341]
- charts/rhdh/values.yaml[366-368]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. CI Helm index drift 🐞 Bug ☼ Reliability
Description
charts/rhdh/values.yaml prepends new entries to global.dynamic.plugins, shifting the positional
indices that scripts/ci-setup.sh overrides with --set global.dynamic.plugins[8]/[9]. This can
disable unintended plugins in CI (or fail to disable the intended ones), causing CI installs to
behave incorrectly or fail.
Code

charts/rhdh/values.yaml[R7-24]

+      ##### Disable upstream lightspeed (replaced by custom DCR builds) #####
+      - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed:bs_1.49.4__2.8.5
+        disabled: true
+      - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed-backend:bs_1.49.4__2.8.5
+        disabled: true
+
+      ##### OAuth2 consent page plugin (required for DCR) #####
+      - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-plugin-auth:pr_2498__0.1.6
+        disabled: false
+        pluginConfig:
+          dynamicPlugins:
+            frontend:
+              backstage.plugin-auth:
+                dynamicRoutes:
+                  - path: /oauth2
+                    importName: Router
+                    module: PluginRoot
+
Evidence
The PR adds new items at the beginning of the global.dynamic.plugins list, while CI still disables
items by fixed numeric indices; positional overrides will now target different list elements than
before.

charts/rhdh/values.yaml[1-80]
scripts/ci-setup.sh[101-110]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`charts/rhdh/values.yaml` prepends new items to `global.dynamic.plugins`, but CI uses positional Helm overrides (`global.dynamic.plugins[8]` and `[9]`) in `scripts/ci-setup.sh`. After the prepend, the same indices point at different plugin entries.

## Issue Context
Helm array overrides are order-dependent; inserting entries at the head of the list changes the meaning of any `--set ...[N]...` overrides.

## Fix Focus Areas
- scripts/ci-setup.sh[101-110]
- charts/rhdh/values.yaml[1-80]

## Suggested fix approaches
- Preferred: stop using hard-coded indices in CI. Instead, generate a small temporary values file in CI that disables plugins by matching `package:` (e.g., via `yq`), then pass that file to `helm install`.
- Acceptable fallback: if you must keep index-based overrides, update `scripts/ci-setup.sh` indices to match the new ordering **and** add a guard/comment that these must be updated whenever `global.dynamic.plugins` ordering changes.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Wildcard redirect URIs 🐞 Bug ⛨ Security
Description
values.yaml enables experimentalDynamicClientRegistration while allowing
allowedRedirectUriPatterns: ['*'], which permits redirect URIs to match anything. This undermines
OAuth redirect URI validation and can allow authorization code/token exfiltration to
attacker-controlled redirect endpoints.
Code

charts/rhdh/values.yaml[R424-427]

+          experimentalDynamicClientRegistration:
+            enabled: true
+            allowedRedirectUriPatterns:
+              - '*'
Evidence
The chart explicitly sets the only allowed redirect URI pattern to *, which matches any redirect
URI pattern.

charts/rhdh/values.yaml[422-427]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`auth.experimentalDynamicClientRegistration.allowedRedirectUriPatterns` is set to `'*'`, effectively allowing any redirect URI for dynamically registered clients.

## Issue Context
OAuth redirect URI validation is a key security control; wildcard patterns make it possible for a malicious client registration to supply a redirect URI controlled by an attacker.

## Fix Focus Areas
- charts/rhdh/values.yaml[422-427]

## Suggested fix
Replace the wildcard with a narrowly-scoped allowlist (e.g., specific origins/paths you control such as `${RHDH_BASE_URL}/oauth2/*` or exact callback URLs). If multiple environments are needed, make this configurable via chart values with safe defaults (no wildcard).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View more (1)
4. Hardcoded RBAC admin user 🐞 Bug ⛨ Security
Description
The chart hardcodes user:default/mfaisal as a permission RBAC admin and also binds that same user
to role:default/mcp-admin in the shipped rbac-policy.csv. Any environment where that identity
exists will grant elevated permissions unintentionally via default chart install.
Code

charts/rhdh/values.yaml[R575-581]

+        permission:
+          enabled: true
+          rbac:
+            policies-csv-file: /opt/app-root/src/rbac-policy.csv
+            admin:
+              users:
+                - name: user:default/mfaisal
Evidence
The values file explicitly lists user:default/mfaisal under permission.rbac.admin.users, and the
new policy ConfigMap grants that same user the mcp-admin role.

charts/rhdh/values.yaml[563-582]
charts/rhdh/templates/rbac-policy-configmap.yaml[1-23]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A specific human identity (`user:default/mfaisal`) is embedded in the chart defaults as an RBAC admin and is also granted the `mcp-admin` role in the policy CSV ConfigMap.

## Issue Context
Charts are often reused across environments; hardcoding a privileged user can unintentionally grant admin access in clusters where that identity exists.

## Fix Focus Areas
- charts/rhdh/values.yaml[575-581]
- charts/rhdh/templates/rbac-policy-configmap.yaml[1-23]

## Suggested fix
- Remove the hardcoded user from defaults.
- Parameterize admin users and role bindings via values (e.g., `.Values.backstage.upstream.backstage.appConfig.permission.rbac.admin.users` and/or a chart value like `.Values.permission.rbacPolicyCsv`), with an empty default.
- If a demo user is needed, gate it behind an explicit `demo: true`/`unsafeDefaults: true` value so production installs don’t inherit it.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

5. Empty secret values allowed 🐞 Bug ☼ Reliability
Description
scripts/setup-secrets.sh now writes several keys (e.g.,
ENABLE_VLLM/VLLM_URL/VLLM_API_KEY/OPENAI_API_KEY) as empty strings when env vars are unset, instead
of failing fast or omitting them. This weakens misconfiguration detection and can produce
deployments where provider configuration is silently incomplete.
Code

scripts/setup-secrets.sh[R31-36]

+    --from-literal=ENABLE_VLLM="${ENABLE_VLLM:-}" \
+    --from-literal=ENABLE_OPENAI="${ENABLE_OPENAI:-}" \
    --from-literal=ENABLE_VALIDATION="true" \
-    --from-literal=VLLM_URL="$VLLM_URL" \
-    --from-literal=VLLM_API_KEY="$VLLM_API_KEY" \
+    --from-literal=VLLM_URL="${VLLM_URL:-}" \
+    --from-literal=VLLM_API_KEY="${VLLM_API_KEY:-}" \
+    --from-literal=OPENAI_API_KEY="${OPENAI_API_KEY:-}" \
Evidence
The script now defaults several secret literals to empty, while the Llama Stack config consumes
those env vars to decide whether to enable/configure providers.

scripts/setup-secrets.sh[27-41]
charts/rhdh/templates/llama-stack-config.yaml[31-49]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`setup-secrets.sh` uses `${VAR:-}` defaults for several provider-related secret entries, allowing empty values to be written into the secret.

## Issue Context
`llama-stack-config.yaml` consumes these env vars for provider configuration; allowing empty values makes it harder to catch misconfig early and can cause runtime failures or disabled providers.

## Fix Focus Areas
- scripts/setup-secrets.sh[27-41]
- charts/rhdh/templates/llama-stack-config.yaml[31-49]

## Suggested fix
- Add validation logic:
 - If `ENABLE_VLLM` is set/enabled, require non-empty `VLLM_URL` and `VLLM_API_KEY` (exit with an error if missing).
 - If `ENABLE_OPENAI` is set/enabled, require non-empty `OPENAI_API_KEY`.
- Alternatively, only add `--from-literal=...` flags for variables that are set, to avoid creating misleading empty keys.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Enable DCR auth for Lightspeed MCP servers (RHDH/Backstage Helm)
✨ Enhancement ⚙️ Configuration changes 🕐 20-40 Minutes

Grey Divider

Walkthroughs

Description
• Switch Lightspeed frontend/backend to custom OCI builds with DCR support
• Enable Backstage experimental Dynamic Client Registration and OAuth2 consent route
• Turn on RBAC permissions and mount policy CSV via ConfigMap
Diagram
graph TD
  H["Helm values.yaml"] --> B["Backstage (RHDH) pod"] --> A["Auth plugin (/oauth2)"] --> I{{"OIDC provider"}}
  B --> L["Custom Lightspeed plugins"] --> M{{"MCP server"}}
  C[("ConfigMap: rbac-policy.csv")] --> B

  subgraph Legend
    direction LR
    _cfg["Config"] ~~~ _svc["Service/Pod"] ~~~ _cm[("ConfigMap")] ~~~ _ext{{"External"}}
  end
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Wait for upstream Lightspeed DCR images/overlays
  • ➕ Avoids maintaining custom OCI images and overlay references
  • ➕ Reduces drift from supported plugin versions and simplifies upgrades
  • ➖ Blocks enabling DCR until upstream PR/release is available
  • ➖ May still require interim Helm wiring for /oauth2 and permissions
2. Constrain DCR redirect URI patterns (instead of '*')
  • ➕ Reduces risk of mis-redirect or open redirect style misconfiguration
  • ➕ Aligns better with typical production security requirements
  • ➖ Requires knowing/maintaining the exact valid redirect URIs per environment
  • ➖ More setup friction for demos and ephemeral deployments
3. Externalize RBAC policy management (OPA/GitOps-managed policies)
  • ➕ Cleaner separation of concerns (policy lifecycle independent of chart release)
  • ➕ Easier policy auditing and change control
  • ➖ More moving parts than a simple ConfigMap for early iteration
  • ➖ May be overkill if this is only for a demo environment

Recommendation: The PR’s approach is appropriate for enabling DCR quickly (custom plugin builds + Helm wiring), but plan to switch back to upstream plugin overlays once the referenced upstream work lands. Also strongly consider tightening experimentalDynamicClientRegistration.allowedRedirectUriPatterns from &#x27;*&#x27; before production use, and document the intended policy/permission model since RBAC is now enabled and depends on a mounted CSV.

Grey Divider

File Changes

Other (3)
rbac-policy-configmap.yaml Add RBAC policy ConfigMap for MCP/Lightspeed permissions +23/-0

Add RBAC policy ConfigMap for MCP/Lightspeed permissions

• Introduces a new ConfigMap template containing an RBAC policy CSV. Grants a dedicated admin role permissions for catalog, scaffolder, and Lightspeed (chat/MCP/notebooks) actions, and assigns a specific user to the admin role.

charts/rhdh/templates/rbac-policy-configmap.yaml


values.yaml Enable DCR auth flow and swap to custom Lightspeed DCR plugin images +42/-6

Enable DCR auth flow and swap to custom Lightspeed DCR plugin images

• Disables upstream Lightspeed plugin overlays and replaces them with custom DCR-capable OCI images. Enables Backstage experimental Dynamic Client Registration, adds an OAuth2 consent-page dynamic route, configures MCP servers to use 'auth: dcr', and turns on Backstage permissions/RBAC with a mounted policy CSV.

charts/rhdh/values.yaml


setup-secrets.sh Make secret creation tolerate optional VLLM/OpenAI environment variables +5/-3

Make secret creation tolerate optional VLLM/OpenAI environment variables

• Updates the secret creation script to default several literals to empty when environment variables are not set. Adds support for 'ENABLE_OPENAI' and 'OPENAI_API_KEY', and makes existing VLLM-related values optional to reduce setup friction.

scripts/setup-secrets.sh


Grey Divider

Qodo Logo

Comment thread charts/rhdh/values.yaml
Comment on lines 339 to 341
plugins:
- package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed:bs_1.49.4__2.8.5
- package: oci://quay.io/maysunfaisal/rhdh-plugin-lightspeed:dcr-0.4.0!red-hat-developer-hub-backstage-plugin-lightspeed
disabled: false

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

1. rhdh-plugin-lightspeed tag format invalid 📘 Rule violation ≡ Correctness

Several OCI plugin package references in charts/rhdh/values.yaml use non-compliant tag texts
(dcr-0.4.0!… for the Lightspeed and Lightspeed backend plugins, and pr_2498__0.1.6 for a newly
added package) that do not match the required bs_<backstage-version>__<plugin-version> format.
This violates the enforced plugin image tag convention mandated for plugin images in this values
file.
Agent Prompt
## Issue description
`charts/rhdh/values.yaml` contains multiple OCI plugin package tags that do not follow the required `bs_<backstage-version>__<plugin-version>` convention (including `dcr-0.4.0!…` tags for the Lightspeed and Lightspeed backend plugins and the newly added `pr_2498__0.1.6` tag).

## Issue Context
PR Compliance ID 902156 requires all OCI plugin image tags in `charts/rhdh/values.yaml` to match `bs_<backstage-version>__<plugin-version>` (i.e., start with `bs_` and use the `__` separator between the two non-empty segments). Update the non-compliant tags to conform to this enforced format.

## Fix Focus Areas
- charts/rhdh/values.yaml[13-15]
- charts/rhdh/values.yaml[339-341]
- charts/rhdh/values.yaml[366-368]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread charts/rhdh/values.yaml
Comment on lines +7 to +24
##### Disable upstream lightspeed (replaced by custom DCR builds) #####
- package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed:bs_1.49.4__2.8.5
disabled: true
- package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed-backend:bs_1.49.4__2.8.5
disabled: true

##### OAuth2 consent page plugin (required for DCR) #####
- package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-plugin-auth:pr_2498__0.1.6
disabled: false
pluginConfig:
dynamicPlugins:
frontend:
backstage.plugin-auth:
dynamicRoutes:
- path: /oauth2
importName: Router
module: PluginRoot

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

2. Ci helm index drift 🐞 Bug ☼ Reliability

charts/rhdh/values.yaml prepends new entries to global.dynamic.plugins, shifting the positional
indices that scripts/ci-setup.sh overrides with --set global.dynamic.plugins[8]/[9]. This can
disable unintended plugins in CI (or fail to disable the intended ones), causing CI installs to
behave incorrectly or fail.
Agent Prompt
## Issue description
`charts/rhdh/values.yaml` prepends new items to `global.dynamic.plugins`, but CI uses positional Helm overrides (`global.dynamic.plugins[8]` and `[9]`) in `scripts/ci-setup.sh`. After the prepend, the same indices point at different plugin entries.

## Issue Context
Helm array overrides are order-dependent; inserting entries at the head of the list changes the meaning of any `--set ...[N]...` overrides.

## Fix Focus Areas
- scripts/ci-setup.sh[101-110]
- charts/rhdh/values.yaml[1-80]

## Suggested fix approaches
- Preferred: stop using hard-coded indices in CI. Instead, generate a small temporary values file in CI that disables plugins by matching `package:` (e.g., via `yq`), then pass that file to `helm install`.
- Acceptable fallback: if you must keep index-based overrides, update `scripts/ci-setup.sh` indices to match the new ordering **and** add a guard/comment that these must be updated whenever `global.dynamic.plugins` ordering changes.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread charts/rhdh/values.yaml
Comment on lines +424 to +427
experimentalDynamicClientRegistration:
enabled: true
allowedRedirectUriPatterns:
- '*'

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

3. Wildcard redirect uris 🐞 Bug ⛨ Security

values.yaml enables experimentalDynamicClientRegistration while allowing
allowedRedirectUriPatterns: ['*'], which permits redirect URIs to match anything. This undermines
OAuth redirect URI validation and can allow authorization code/token exfiltration to
attacker-controlled redirect endpoints.
Agent Prompt
## Issue description
`auth.experimentalDynamicClientRegistration.allowedRedirectUriPatterns` is set to `'*'`, effectively allowing any redirect URI for dynamically registered clients.

## Issue Context
OAuth redirect URI validation is a key security control; wildcard patterns make it possible for a malicious client registration to supply a redirect URI controlled by an attacker.

## Fix Focus Areas
- charts/rhdh/values.yaml[422-427]

## Suggested fix
Replace the wildcard with a narrowly-scoped allowlist (e.g., specific origins/paths you control such as `${RHDH_BASE_URL}/oauth2/*` or exact callback URLs). If multiple environments are needed, make this configurable via chart values with safe defaults (no wildcard).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread charts/rhdh/values.yaml
Comment on lines +575 to +581
permission:
enabled: true
rbac:
policies-csv-file: /opt/app-root/src/rbac-policy.csv
admin:
users:
- name: user:default/mfaisal

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

4. Hardcoded rbac admin user 🐞 Bug ⛨ Security

The chart hardcodes user:default/mfaisal as a permission RBAC admin and also binds that same user
to role:default/mcp-admin in the shipped rbac-policy.csv. Any environment where that identity
exists will grant elevated permissions unintentionally via default chart install.
Agent Prompt
## Issue description
A specific human identity (`user:default/mfaisal`) is embedded in the chart defaults as an RBAC admin and is also granted the `mcp-admin` role in the policy CSV ConfigMap.

## Issue Context
Charts are often reused across environments; hardcoding a privileged user can unintentionally grant admin access in clusters where that identity exists.

## Fix Focus Areas
- charts/rhdh/values.yaml[575-581]
- charts/rhdh/templates/rbac-policy-configmap.yaml[1-23]

## Suggested fix
- Remove the hardcoded user from defaults.
- Parameterize admin users and role bindings via values (e.g., `.Values.backstage.upstream.backstage.appConfig.permission.rbac.admin.users` and/or a chart value like `.Values.permission.rbacPolicyCsv`), with an empty default.
- If a demo user is needed, gate it behind an explicit `demo: true`/`unsafeDefaults: true` value so production installs don’t inherit it.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

data:
rbac-policy.csv: |
p, role:default/mcp-admin, catalog.entity.read, read, allow
p, role:default/mcp-admin, catalog.entity.create, create, allow

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.

it is going to be very cool to get this level of authorization granularity once the DCR stuff lands @maysunfaisal @johnmcollier :-)

@maysunfaisal maysunfaisal force-pushed the feat/dcr-mcp-auth-v2 branch 3 times, most recently from 4b5a589 to 90948b7 Compare June 16, 2026 23:13
- Add custom Lightspeed OCI images with DCR support (dcr-0.4.0)
- Configure MCP server with auth: dcr in values.yaml
- Enable experimentalDynamicClientRegistration
- Add @backstage/plugin-auth for OAuth2 consent page

Co-authored-by: Cursor <cursoragent@cursor.com>
@maysunfaisal maysunfaisal force-pushed the feat/dcr-mcp-auth-v2 branch from 90948b7 to 5e75e62 Compare June 25, 2026 21:28
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.

2 participants