Skip to content

Commit 4b920c7

Browse files
feat(orchestrator): handle code review comments
Signed-off-by: Oleksandr Andriienko <oandriie@redhat.com>
1 parent b961ba8 commit 4b920c7

4 files changed

Lines changed: 46 additions & 6 deletions

File tree

workspaces/orchestrator/docs/MIGRATION-CONDITIONAL-POLICIES.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,20 @@ If you created dynamic permissions via REST API, delete them via REST API and re
5454

5555
There is **no automatic migration**. You must manually create the new configuration.
5656

57+
### Performance note on legacy fallback
58+
59+
During this deprecation release, the backend checks conditional policies first. If the conditional policy covers the requested workflow(s), access is resolved immediately — no legacy fallback runs.
60+
61+
Conditional policies are faster than deprecated dynamic permissions. With conditional policies, the backend makes a single `authorizeConditional` call and then filters workflows locally using `matches()` — regardless of how many workflows exist. With deprecated dynamic permissions, the backend makes a separate `authorize` call per workflow, so latency grows linearly with the number of workflows.
62+
63+
The legacy fallback only runs for workflows **not covered** by conditional policies. For each uncovered workflow, an individual `authorize` call is made to check the deprecated dynamic permission. This means:
64+
65+
- **After a complete migration** (conditional policies cover all workflows your users need): the legacy fallback is never triggered. Performance is the same as if dynamic permissions were already removed.
66+
- **During partial migration** (some workflows still rely on deprecated CSV/REST API permissions): the fallback runs only for the uncovered workflows. You may see additional per-workflow authorize calls for those IDs.
67+
- **No migration done yet** (all access via deprecated dynamic permissions): the fallback runs for every workflow, similar to the old behavior.
68+
69+
To avoid unnecessary fallback calls, ensure your conditional policies cover all workflows before this deprecation period ends. You can verify by checking the backend logs — a deprecation warning is logged each time the legacy fallback grants access.
70+
5771
## New Authorization Model
5872

5973
Conditional policies restrict access to specific workflows using the `IS_ALLOWED_WORKFLOW_ID` rule.

workspaces/orchestrator/docs/rbac-policy.csv

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
#p, role:default/workflowUser, orchestrator.workflow.use.yamlgreet, update, allow
44
#p, role:default/workflowUser, orchestrator.workflow.use.wait-or-error, update, allow
55

6-
p, role:default/workflowUser, orchestrator.workflow.use, update, allow
7-
p, role:default/workflowUser, orchestrator.workflow, read, allow
6+
#p, role:default/workflowUser, orchestrator.workflow.use, update, allow
7+
#p, role:default/workflowUser, orchestrator.workflow, read, allow
88

99
p, role:default/workflowAdmin, orchestrator.workflow, read, allow
1010
p, role:default/workflowAdmin, orchestrator.workflowAdminView, read, allow

workspaces/orchestrator/plugins/orchestrator-backend/src/service/permission-rules.test.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,5 +100,27 @@ describe('permission-rules', () => {
100100
{ workflowId: 'workflow-1' },
101101
]);
102102
});
103+
104+
it('should filter out undefined results from fetchWorkflowOverview', async () => {
105+
const service = {
106+
fetchWorkflowOverview: jest
107+
.fn()
108+
.mockResolvedValueOnce({ workflowId: 'workflow-1' })
109+
.mockResolvedValueOnce(undefined)
110+
.mockResolvedValueOnce({ workflowId: 'workflow-3' }),
111+
} as unknown as OrchestratorService;
112+
113+
const resources = await fetchWorkflowResources(service, [
114+
'workflow-1',
115+
'nonexistent',
116+
'workflow-3',
117+
]);
118+
119+
expect(service.fetchWorkflowOverview).toHaveBeenCalledTimes(3);
120+
expect(resources).toEqual([
121+
{ workflowId: 'workflow-1' },
122+
{ workflowId: 'workflow-3' },
123+
]);
124+
});
103125
});
104126
});

workspaces/orchestrator/plugins/orchestrator-backend/src/service/permission-rules.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,10 @@ import {
2121

2222
import { z } from 'zod/v3';
2323

24-
import { ORCHESTRATOR_WORKFLOW_RESOURCE_TYPE } from '@red-hat-developer-hub/backstage-plugin-orchestrator-common';
24+
import {
25+
ORCHESTRATOR_WORKFLOW_RESOURCE_TYPE,
26+
WorkflowOverview,
27+
} from '@red-hat-developer-hub/backstage-plugin-orchestrator-common';
2528

2629
import type { OrchestratorService } from './OrchestratorService';
2730

@@ -85,15 +88,16 @@ export const isWorkflowId = createPermissionRule<
8588
*/
8689
export const orchestratorPermissionRules = [isWorkflowId];
8790

88-
export function fetchWorkflowResources(
91+
export async function fetchWorkflowResources(
8992
orchestratorService: OrchestratorService,
9093
resourceRefs: string[],
91-
) {
92-
return Promise.all(
94+
): Promise<WorkflowOverview[]> {
95+
const results = await Promise.all(
9396
resourceRefs.map(resourceRef =>
9497
orchestratorService.fetchWorkflowOverview({
9598
definitionId: resourceRef,
9699
}),
97100
),
98101
);
102+
return results.filter(r => r !== undefined);
99103
}

0 commit comments

Comments
 (0)