Skip to content

fix(cost-management): register dynamic RBAC permissions for cluster/project tiers (FLPATH-4207)#3193

Open
hardengl wants to merge 2 commits into
redhat-developer:mainfrom
hardengl:fix/rbac-cluster-permissions
Open

fix(cost-management): register dynamic RBAC permissions for cluster/project tiers (FLPATH-4207)#3193
hardengl wants to merge 2 commits into
redhat-developer:mainfrom
hardengl:fix/rbac-cluster-permissions

Conversation

@hardengl
Copy link
Copy Markdown
Contributor

Summary

Cluster-specific RBAC permissions (ros/<cluster>, ros/<cluster>/<project>, and their cost/ equivalents) are created dynamically at runtime by fetchDynamicPermissions() but were never registered with createPermissionIntegrationRouter. The RHDH RBAC backend's PluginPermissionMetadataCollector only evaluates registered permissions — unregistered ones get DENY by default. This broke the entire 3-tier RBAC model: only ros.plugin (tier 1) ever worked.

Changes

router.ts — At router init, fetch cluster/project data from the upstream Cost Management APIs and register all ros/<cluster>, ros/<cluster>/<project>, cost/<cluster>, and cost/<cluster>/<project> permissions with the integration router. Uses Promise.allSettled so a partial failure (e.g. one API down) doesn't block other permissions from registering.

secureProxy.ts — Improved error logging and response messages. Previously returned opaque "Internal proxy error" for all non-SSO exceptions; now includes the request path and error details for easier debugging.

Proof the fix works

Verified on a live RHDH instance (ocp-edge73) with OCI image quay.io/gharden/cost-management-dynamic-plugins:2.2.0-rc.1.

Tier 1: ros.plugin — full access (396 containers, no filters)

costmgmt-full-access-optimizations

No permissions — access denied

costmgmt-no-access-optimizations

Tier 2: ros/<cluster> only — cluster-filtered (10 containers, down from 396)

ro-cluster-only-optimizations

Tier 3: ros/<cluster>/<project> only — cluster+project filtered

ro-project-only-optimizations

Backend audit logs

costmgmt-full-access: {"decision":"ALLOW","filters":{"clusters":[],"projects":[]}}            ← no filters
ro-cluster-only:      {"decision":"ALLOW","filters":{"clusters":["696794b9-..."],"projects":[]}}  ← cluster filter
ro-project-only:      {"decision":"ALLOW","filters":{"clusters":["696794b9-..."],"projects":["rhdh-operator"]}}
costmgmt-no-access:   {"decision":"DENY"}

CI

flightpath-ros #95 — 89 passed, 2 failed (pre-existing flaky), 4 skipped. All 21 RBAC E2E tests passed.

Limitation

Dynamic permissions are registered once at startup. New clusters added after RHDH starts won't be recognized until the pod restarts. A periodic refresh mechanism would be a more complete solution.

Related

Made with Cursor

…roject tiers (FLPATH-4207)

Cluster-specific permissions (ros/<cluster>, ros/<cluster>/<project>) were
created at runtime but never registered with createPermissionIntegrationRouter.
The RHDH RBAC backend only evaluates registered permissions — unregistered ones
get DENY by default, breaking the entire 3-tier RBAC model.

At router init, fetch cluster/project data from upstream APIs and register all
dynamic permissions. Also improve secureProxy.ts error messages (include path
and error details instead of opaque "Internal proxy error").

Co-authored-by: Cursor <cursoragent@cursor.com>
@rhdh-gh-app
Copy link
Copy Markdown

rhdh-gh-app Bot commented May 20, 2026

Changed Packages

Package Name Package Path Changeset Bump Current Version
@red-hat-developer-hub/plugin-cost-management-backend workspaces/cost-management/plugins/cost-management-backend patch v2.2.0

@codecov
Copy link
Copy Markdown

codecov Bot commented May 20, 2026

Codecov Report

❌ Patch coverage is 60.46512% with 17 lines in your changes missing coverage. Please review.
✅ Project coverage is 60.99%. Comparing base (815580b) to head (e0b1627).
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3193      +/-   ##
==========================================
+ Coverage   60.97%   60.99%   +0.01%     
==========================================
  Files        2098     2098              
  Lines       65140    65181      +41     
  Branches    17029    17034       +5     
==========================================
+ Hits        39721    39756      +35     
- Misses      25180    25186       +6     
  Partials      239      239              
Flag Coverage Δ *Carryforward flag
adoption-insights 83.58% <ø> (ø) Carriedforward from e1cc0cc
ai-integrations 70.03% <ø> (ø) Carriedforward from e1cc0cc
app-defaults 69.60% <ø> (ø) Carriedforward from e1cc0cc
augment 69.36% <ø> (ø) Carriedforward from e1cc0cc
bulk-import 72.86% <ø> (ø) Carriedforward from e1cc0cc
cost-management 17.48% <60.46%> (+0.99%) ⬆️
dcm 32.85% <ø> (ø) Carriedforward from e1cc0cc
extensions 61.79% <ø> (ø) Carriedforward from e1cc0cc
global-floating-action-button 74.30% <ø> (ø) Carriedforward from e1cc0cc
global-header 61.68% <ø> (ø) Carriedforward from e1cc0cc
homepage 50.95% <ø> (ø) Carriedforward from e1cc0cc
konflux 91.01% <ø> (ø) Carriedforward from e1cc0cc
lightspeed 68.33% <ø> (ø) Carriedforward from e1cc0cc
mcp-integrations 81.59% <ø> (ø) Carriedforward from e1cc0cc
orchestrator 36.36% <ø> (ø) Carriedforward from e1cc0cc
quickstart 62.88% <ø> (ø) Carriedforward from e1cc0cc
sandbox 79.42% <ø> (ø) Carriedforward from e1cc0cc
scorecard 83.72% <ø> (ø) Carriedforward from e1cc0cc
theme 64.54% <ø> (ø) Carriedforward from e1cc0cc
translations 8.49% <ø> (ø) Carriedforward from e1cc0cc
x2a 78.28% <ø> (ø) Carriedforward from e1cc0cc

*This pull request uses carry forward flags. Click here to find out more.


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 815580b...e0b1627. Read the comment docs.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

- Extract extractStrings() and buildClusterProjectPermissions() helpers
  to flatten nested if/for blocks (SonarCloud cognitive complexity 33→8)
- Add 8 unit tests covering both helpers (fulfilled/rejected/empty/dedup)
- Add changeset for cost-management-backend patch release

Co-authored-by: Cursor <cursoragent@cursor.com>
@sonarqubecloud
Copy link
Copy Markdown

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant