feat: implement RBAC permissions helper (Phase 2.3)
Add comprehensive RBAC permission checking using Kubernetes SelfSubjectAccessReview API. Hide/disable UI elements based on user permissions for better security and UX. Features: - RBAC module with permission checking utilities - React hooks for permission management (usePermissions, usePermission, etc.) - Permission-aware UI (hide create/delete/re-encrypt buttons) - Decrypt button disabled if no Secret access - Multi-namespace permission support - Fail-safe design (returns false on error) Technical details: - Uses Kubernetes authorization.k8s.io/v1 SelfSubjectAccessReview API - Concurrent permission checks with Promise.all - Automatic loading states and error handling - React cleanup on unmount prevents memory leaks - Type-safe with Result<T, E> types Files: - src/lib/rbac.ts: NEW RBAC checking module (+168 lines) - src/hooks/usePermissions.ts: NEW React hooks (+138 lines) - src/components/SealedSecretList.tsx: Hide create button if no permission - src/components/SealedSecretDetail.tsx: Hide re-encrypt/delete/decrypt based on permissions - PHASE_2.3_COMPLETE.md: Implementation documentation - .claude/agents/: Add 5 new specialized agents (test, accessibility, docs, orchestration) Bundle size: 348.46 kB (96.05 kB gzipped), +1.81 kB (+0.5%) Build time: 3.93s Zero TypeScript/lint errors Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
This commit is contained in:
@@ -13,6 +13,7 @@ import {
|
||||
} from '@kinvolk/headlamp-plugin/lib/CommonComponents';
|
||||
import { Box, Button } from '@mui/material';
|
||||
import React from 'react';
|
||||
import { usePermission } from '../hooks/usePermissions';
|
||||
import { SealedSecret } from '../lib/SealedSecretCRD';
|
||||
import { SealedSecretScope } from '../types';
|
||||
import { EncryptDialog } from './EncryptDialog';
|
||||
@@ -39,6 +40,7 @@ function formatScope(scope: SealedSecretScope): string {
|
||||
export function SealedSecretList() {
|
||||
const [sealedSecrets, error] = SealedSecret.useList();
|
||||
const [createDialogOpen, setCreateDialogOpen] = React.useState(false);
|
||||
const { allowed: canCreate } = usePermission(undefined, 'canCreate');
|
||||
|
||||
// Show error if CRD is not installed
|
||||
if (error) {
|
||||
@@ -76,16 +78,20 @@ export function SealedSecretList() {
|
||||
<SectionFilterHeader
|
||||
title=""
|
||||
noNamespaceFilter={false}
|
||||
actions={[
|
||||
<Button
|
||||
key="create"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={() => setCreateDialogOpen(true)}
|
||||
>
|
||||
Create Sealed Secret
|
||||
</Button>,
|
||||
]}
|
||||
actions={
|
||||
canCreate
|
||||
? [
|
||||
<Button
|
||||
key="create"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={() => setCreateDialogOpen(true)}
|
||||
>
|
||||
Create Sealed Secret
|
||||
</Button>,
|
||||
]
|
||||
: []
|
||||
}
|
||||
/>
|
||||
<SimpleTable
|
||||
data={sealedSecrets}
|
||||
|
||||
Reference in New Issue
Block a user