fix(rbac): enforce operational permission parity (#1736)

This commit is contained in:
Anso
2026-07-29 22:02:53 -04:00
committed by GitHub
parent a65bf4d46a
commit c704cb54d2
68 changed files with 708 additions and 232 deletions
@@ -443,7 +443,6 @@ export function EditorView(props: EditorViewProps) {
safeContainers={safeContainers}
isRunning={isRunning}
can={can}
isAdmin={isAdmin}
trivy={trivy}
backupInfo={backupInfo}
loadingAction={loadingAction}
@@ -147,7 +147,6 @@ export function MobileStackDetail(props: EditorViewProps) {
safeContainers={safeContainers}
isRunning={isRunning}
can={can}
isAdmin={isAdmin}
trivy={trivy}
backupInfo={backupInfo}
loadingAction={loadingAction}
@@ -222,7 +222,7 @@ export function ShellOverlays({
<VulnerabilityScanSheet
scanId={stackMisconfigScanId}
onClose={() => setStackMisconfigScanId(null)}
canManageSuppressions={isAdmin}
canManageSuppressions={can('stack:edit')}
/>
{/* Compose diff preview */}
@@ -39,7 +39,6 @@ function renderHeader(over: Partial<ComponentProps<typeof StackIdentityHeader>>
safeContainers={CONTAINERS}
isRunning
can={() => true}
isAdmin
trivy={{ available: false }}
backupInfo={{ exists: false, timestamp: null }}
loadingAction={null}
@@ -114,4 +113,15 @@ describe('StackIdentityHeader', () => {
expect(onOpenMonitor).toHaveBeenCalledTimes(1);
});
it('shows stack config scanning to a deployer without requiring Admin', async () => {
const user = userEvent.setup();
renderHeader({
trivy: { available: true },
can: (action) => action === 'stack:deploy',
});
await user.click(screen.getByRole('button', { name: 'More actions' }));
expect(screen.getByRole('menuitem', { name: 'Scan config' })).toBeInTheDocument();
});
});
@@ -127,7 +127,6 @@ export interface StackIdentityHeaderProps {
safeContainers: ContainerInfo[];
isRunning: boolean;
can: ReturnType<typeof useAuth>['can'];
isAdmin: boolean;
trivy: { available: boolean };
backupInfo: { exists: boolean; timestamp: number | null };
loadingAction: StackAction | null;
@@ -156,7 +155,6 @@ export function StackIdentityHeader({
safeContainers,
isRunning,
can,
isAdmin,
trivy,
backupInfo,
loadingAction,
@@ -206,7 +204,7 @@ export function StackIdentityHeader({
const canDeploy = can('stack:deploy', 'stack', stackName, activeNode?.id);
const canDelete = can('stack:delete', 'stack', stackName, activeNode?.id);
const canRollback = canDeploy && backupInfo.exists;
const canScan = trivy.available && isAdmin;
const canScan = trivy.available && canDeploy;
const canMute = stackMuteActions?.canMute ?? false;
const hasOverflowExtras = canRollback || canScan;
const hasOverflow = hasOverflowExtras || canDelete || canMute || onOpenMonitor;