fix(cost-management): add authorization, validation, and confirmation for Apply Recommendation#2618
Conversation
|
Important This PR includes changes that affect public-facing API. Please ensure you are adding/updating documentation for new features or behavior. Changed Packages
|
Review Summary by QodoAdd authorization, validation, and secure proxy for Apply Recommendation and Cost Management API access
WalkthroughsDescription• Add server-side authorization and input validation for Apply Recommendation workflow via new `POST /apply-recommendation` backend endpoint • Implement secure backend proxy (/api/cost-management/proxy/*) that enforces RBAC server-side and eliminates token exposure to browser • Register ros.apply permission and add confirmation dialog to prevent accidental workflow execution • Remove /token endpoint and dangerously-allow-unauthenticated proxy configuration; route all data fetching through secure backend Diagramflowchart LR
A["Frontend Request"] --> B["Backend Secure Proxy"]
B --> C["Authenticate via httpAuth"]
C --> D["Check RBAC Permissions"]
D --> E["Obtain SSO Token Server-Side"]
E --> F["Strip Client Filters"]
F --> G["Inject Server-Authorized Filters"]
G --> H["Forward to Cost Management API"]
H --> I["Return Filtered Response"]
J["Apply Recommendation Request"] --> K["POST /apply-recommendation"]
K --> L["Validate resourceType Allowlist"]
L --> M["Check ros.apply Permission"]
M --> N["Forward to Orchestrator"]
N --> O["Return Workflow Instance ID"]
File Changes1. workspaces/cost-management/plugins/cost-management-backend/src/routes/applyRecommendation.ts
|
Code Review by Qodo
1.
|
afd87b1 to
90ad7a3
Compare
058dcfe to
0321e9f
Compare
… for Apply Recommendation - New ros.apply permission required to execute Apply Recommendation workflow - New POST /apply-recommendation backend endpoint validates resourceType against server-side allowlist and checks ros.apply permission before forwarding to Orchestrator - Workflow execution now routes through the cost-management backend instead of directly to the Orchestrator plugin, enabling server-side authorization and audit logging - Confirmation dialog prevents accidental workflow execution - Register costPluginPermissions in permission integration router (was previously missing) Fixes: FLPATH-3488, FLPATH-3492, FLPATH-3491 Made-with: Cursor
Run yarn build:api-reports:only to update report-clients.api.md and report.api.md with the correct auto-generated format. Made-with: Cursor
- Wrap decodeURIComponent in try/catch, return 400 on malformed encoding
- Safe JSON parse in applyRecommendation (check content-type first)
- Change router.all('/proxy/*') to router.get (proxy is read-only)
- Delete unused routes/token.ts
Made-with: Cursor
Construct a clean inputData object with only known fields before forwarding to the Orchestrator, preventing extra injected fields from passing through to the workflow execution. Co-Authored-By: Claude Opus 4.6 <[email protected]>
76f8539 to
f9a5eb7
Compare
|
…edhat-developer#2616-redhat-developer#2620 - Remove outdated proxy config from workspace README (PR redhat-developer#2616 moved data fetching server-side) - Fix broken link typo in frontend plugin README - Update backend README: clarify mixed dot/slash permission format, add missing endpoints (access, apply-recommendation), add audit logging section (PR redhat-developer#2619) - Clarify permission name format in docs/rbac.md intro (dot for plugin-level, slash for cluster/project per PR redhat-developer#2620) - Update ADR 0002 status to Accepted with implementation notes documenting the backend gateway pattern (PRs redhat-developer#2616, redhat-developer#2618, redhat-developer#2619) Made-with: Cursor
…edhat-developer#2616-redhat-developer#2620 - Remove outdated proxy config from workspace README (PR redhat-developer#2616 moved data fetching server-side) - Fix broken link typo in frontend plugin README - Update backend README: clarify mixed dot/slash permission format, add missing endpoints (access, apply-recommendation), add audit logging section (PR redhat-developer#2619) - Clarify permission name format in docs/rbac.md intro (dot for plugin-level, slash for cluster/project per PR redhat-developer#2620) - Update ADR 0002 status to Accepted with implementation notes documenting the backend gateway pattern (PRs redhat-developer#2616, redhat-developer#2618, redhat-developer#2619) Made-with: Cursor
…2679) * docs(cost-management): update documentation to reflect security PRs #2616-#2620 - Remove outdated proxy config from workspace README (PR #2616 moved data fetching server-side) - Fix broken link typo in frontend plugin README - Update backend README: clarify mixed dot/slash permission format, add missing endpoints (access, apply-recommendation), add audit logging section (PR #2619) - Clarify permission name format in docs/rbac.md intro (dot for plugin-level, slash for cluster/project per PR #2620) - Update ADR 0002 status to Accepted with implementation notes documenting the backend gateway pattern (PRs #2616, #2618, #2619) Made-with: Cursor * docs(cost-management): address Qodo review findings - Fix inaccurate sanitization claim in ADR 0002: changed to "validated for presence and type" to match actual implementation - Remove non-existent `cost_access_check` audit action from backend README — the code emits `access_check` for both access endpoints Made-with: Cursor



Summary
Stacked on #2616 — review that PR first. This PR adds commits on top.
Addresses FLPATH-3488, FLPATH-3492, FLPATH-3491 from the FLPATH-3503 security epic.
Problem
The "Apply Recommendation" workflow was executed by the frontend calling the Orchestrator API directly. This had three security issues:
ros.applypermission gate.resourceTypefield passed to the workflow was not validated against an allowlist. A malicious user could inject arbitrary resource types.Solution
Created a new backend endpoint
POST /api/cost-management/apply-recommendationthat:httpAuthros.applypermission (returns 403 if denied)resourceTypeagainst a hardcoded allowlist (openshift,containers)inputDatafields (strips control characters, enforces field length limits)ros.apply— no Orchestrator permissions required)Frontend changes
ros.applypermission, usingusePermissionfrom@backstage/plugin-permission-reactResponseErrorPanelinstead of being silently swallowedNew permission:
ros.applyChanges
POST /apply-recommendationroute (applyRecommendation.ts)rosApplyPermissioninpermissions.tspermissionIntegrationRouterusePermissionhook inOptimizationEngineTab.tsxOptimizationsBreakdownPage.tsxOptimizationEngineTab.tsxTest plan
Unit tests
yarn tsc -b— clean compilation, zero errorsapplyRecommendation.test.ts— 6 tests covering:CI
Deployment verification
costmgmt-full-access(hasros.apply): HTTP 200 — workflow instance createdro-read-all(noros.apply): HTTP 403 — correctly deniedcostmgmt-no-access(no permissions): HTTP 403 — correctly deniedQodo bot findings (addressed)