Files
attune/work-summary/2026-02-keys-management-page.md
2026-02-04 17:46:30 -06:00

359 lines
11 KiB
Markdown

# Keys & Secrets Management Page Implementation
**Date:** 2026-02-05
**Status:** Complete
## Overview
Implemented a comprehensive Keys & Secrets management page for the Attune web UI, enabling users to perform CRUD operations on encrypted secrets and configuration values with proper scoping and format validation.
## Changes Made
### New Files Created
1. **`attune/web/src/hooks/useKeys.ts`**
- Custom React hooks for keys/secrets API operations
- `useKeys()` - Fetch paginated list with filters
- `useKey(ref)` - Fetch single key by reference (includes decrypted value)
- `useCreateKey()` - Create new key mutation
- `useUpdateKey()` - Update existing key mutation
- `useDeleteKey()` - Delete key mutation
- Proper query invalidation for cache management
2. **`attune/web/src/pages/keys/KeysPage.tsx`**
- Main list view for keys and secrets
- Search functionality (by reference or name)
- Filter by scope (System, User, Pack, Action, Sensor)
- Client-side search with server-side scope filtering
- Pagination (20 items per page)
- Color-coded scope badges
- Encryption status indicators
- Inline edit and delete actions
- Empty states and error handling
3. **`attune/web/src/pages/keys/KeyCreateModal.tsx`**
- Modal dialog for creating new keys
- **Value format selection** with validation:
- **Text** (can be encrypted)
- **JSON** (can be encrypted, validates JSON syntax)
- **YAML** (can be encrypted, basic validation)
- **Number** (cannot be encrypted, validates numeric)
- **Integer** (cannot be encrypted, validates integer)
- **Boolean** (cannot be encrypted, validates true/false)
- Encryption toggle (automatically disabled for non-encryptable formats)
- Scope selection (System, User, Pack, Action, Sensor)
- Owner identifier field (conditional based on scope)
- Format-aware validation before submission
- Reference format validation (alphanumeric, _, -, .)
4. **`attune/web/src/pages/keys/KeyEditModal.tsx`**
- Modal dialog for editing existing keys
- Shows key metadata (reference, scope, owner) as read-only
- Editable name and value fields
- Show/hide value toggle for security
- Encryption toggle with warning when changing encryption status
- Validates changes before submission
- Visual warnings when changing encryption settings
### Modified Files
1. **`attune/web/src/App.tsx`**
- Added route for `/keys` (KeysPage)
- Imported KeysPage component
2. **`attune/web/src/components/layout/MainLayout.tsx`**
- Added "Keys & Secrets" navigation item
- Positioned before "Pack Management"
- Uses `KeyRound` icon from lucide-react
## Features Implemented
### List Page (`/keys`)
- **Display Columns:**
- Reference (with key icon)
- Name (human-readable)
- Scope (color-coded badge)
- Owner (identifier or "—")
- Encrypted status (Yes/No with icons)
- Created timestamp
- Actions (Edit/Delete buttons)
- **Search & Filtering:**
- Real-time search by reference or name (client-side)
- Scope filter dropdown (System, User, Pack, Action, Sensor)
- Clear filters button
- Shows filtered count
- **Actions:**
- Create Key button (top-right)
- Edit button per row (opens modal)
- Delete button per row (with confirmation)
- **Pagination:**
- 20 items per page
- Previous/Next navigation
- Page indicator
### Create Modal
- **Required Fields:**
- Reference (unique identifier with validation)
- Name (human-readable description)
- Value (format-dependent validation)
- Scope (owner type)
- **Value Format Options:**
- **Text:** Plain text, can be encrypted
- **JSON:** Validates JSON syntax, can be encrypted
- **YAML:** Basic validation, can be encrypted
- **Number:** Validates numeric, **cannot be encrypted**
- **Integer:** Validates integer, **cannot be encrypted**
- **Boolean:** Validates true/false, **cannot be encrypted**
- **Encryption Rules:**
- Text, JSON, YAML formats: Encryption checkbox enabled
- Number, Integer, Boolean formats: Encryption checkbox disabled
- Automatic encryption toggle disable for non-encryptable formats
- Clear UI indication of encryption capability per format
- **Scope Configuration:**
- System: Global scope, no owner required
- User (Identity): Optional owner identifier
- Pack: Optional pack reference
- Action: Optional action reference
- Sensor: Optional sensor reference
- **Validation:**
- Reference format: alphanumeric, underscores, hyphens, dots only
- Value format-specific validation
- Required field checks
- Error messages displayed in modal
### Edit Modal
- **Features:**
- Load existing key data
- Display read-only metadata (reference, scope, owner)
- Edit name and value
- Show/Hide value toggle (Eye/EyeOff icons)
- Encryption toggle
- Warning when changing encryption status
- Only sends changed fields to API
- **Security:**
- Value masked by default (can be toggled)
- Clear indication of current encryption status
- Warnings for encryption changes
## Technical Implementation
### API Integration
Uses `SecretsService` from generated API client:
- `listKeys({ page, perPage, ownerType, owner })` - List with pagination
- `getKey({ ref })` - Get single key with decrypted value
- `createKey({ requestBody })` - Create new key
- `updateKey({ ref, requestBody })` - Update existing key
- `deleteKey({ ref })` - Delete key
### State Management
- React Query for server state and caching
- Local state for UI (search, filters, modals)
- Optimistic updates with cache invalidation
- Proper loading and error states
### Scope (Owner Type) Badges
Color-coded badges for quick identification:
- **System**: Purple (bg-purple-100, text-purple-800)
- **User (Identity)**: Blue (bg-blue-100, text-blue-800)
- **Pack**: Green (bg-green-100, text-green-800)
- **Action**: Yellow (bg-yellow-100, text-yellow-800)
- **Sensor**: Indigo (bg-indigo-100, text-indigo-800)
### Encryption Indicators
- **Encrypted**: EyeOff icon (green) + "Yes" text
- **Not Encrypted**: Eye icon (gray) + "No" text
### Format Validation Logic
```typescript
export type KeyFormat = "text" | "json" | "yaml" | "number" | "int" | "bool";
// Encryptable formats
const canEncrypt = format === "text" || format === "json" || format === "yaml";
// Validation examples:
- JSON: JSON.parse(value)
- Number/Int: Number(value), isNaN check
- Boolean: value.toLowerCase() === "true" || "false"
```
## Design Patterns
1. **Consistent Modal Pattern:**
- Fixed overlay with centered modal
- Header with title and close button
- Form with validation
- Footer with Cancel and Submit buttons
- Loading states during mutation
2. **Format-Aware UI:**
- Dynamic textarea rows based on format
- Placeholder text matches expected format
- Validation errors specific to format
- Auto-disable encryption for incompatible formats
3. **Security-First Approach:**
- Encryption enabled by default for encryptable formats
- Values masked in edit modal
- Confirmation dialogs for destructive actions
- Clear warnings when changing encryption
4. **Responsive Design:**
- Grid layout for filters
- Responsive table with horizontal scroll
- Mobile-friendly pagination
- Consistent with other pages (Events, Enforcements)
## User Flow Examples
### Creating a JSON Secret
1. Click "Create Key" button
2. Enter reference: `api_config`
3. Enter name: "API Configuration"
4. Select format: **JSON** (encryption checkbox enabled)
5. Enter value: `{"url": "https://api.example.com", "timeout": 30}`
6. Check "Encrypt value" (recommended)
7. Select scope: System
8. Click "Create Key"
9. ✅ Key created with encrypted JSON value
### Creating a Number Configuration
1. Click "Create Key" button
2. Enter reference: `max_retries`
3. Enter name: "Maximum Retry Attempts"
4. Select format: **Number** (encryption checkbox disabled)
5. Enter value: `3`
6. Note: Cannot encrypt (checkbox disabled and grayed out)
7. Select scope: System
8. Click "Create Key"
9. ✅ Key created with unencrypted numeric value
### Editing a Key
1. Click Edit button on any key row
2. Modal shows key metadata (read-only)
3. Modify name or value
4. Toggle show/hide value
5. Change encryption (warning displayed)
6. Click "Save Changes"
7. ✅ Key updated
## Known Limitations
1. **Format Field Client-Side Only:**
- The "format" field is not stored in the backend database
- Format is used for client-side validation only
- All values are stored as text in the database
- Future enhancement: Add `format` column to `key` table in backend
2. **Search Pagination:**
- Search is client-side, so only searches current page
- Consider adding server-side search parameter in future
3. **No Bulk Operations:**
- Delete/update one key at a time
- Could add multi-select for batch operations
4. **Value Masking:**
- CSS-based masking may not work in all browsers
- Consider more robust masking solution
## Security Considerations
1. **Encryption Enforcement:**
- Only Text, JSON, YAML can be encrypted (per requirements)
- Number, Integer, Boolean cannot be encrypted
- UI enforces this with disabled checkbox
2. **Value Exposure:**
- List view: Values are redacted (API behavior)
- Detail view: Values are decrypted (requires explicit fetch)
- Edit modal: Values are masked by default with toggle
3. **Access Control:**
- Keys are scoped by owner type
- Users can only access keys they have permissions for
- Enforced at API level (frontend follows)
## Build Status
✅ TypeScript compilation successful
✅ Vite build successful (584.69 kB gzip: 152.21 kB)
✅ No compiler warnings or errors
✅ All routes registered correctly
## Testing Recommendations
Manual testing should verify:
1. ✅ List page loads and displays keys
2. ✅ Search filters by reference and name
3. ✅ Scope filter works correctly
4. ✅ Create modal validates format-specific values
5. ✅ Encryption checkbox disabled for number/int/bool formats
6. ✅ JSON validation catches syntax errors
7. ✅ Boolean values must be "true" or "false"
8. ✅ Edit modal loads existing key data
9. ✅ Show/hide value toggle works
10. ✅ Delete confirms before deleting
11. ✅ Pagination functions properly
12. ✅ Empty states display correctly
13. ✅ Error states handle failures gracefully
## Future Enhancements
1. **Backend Format Field:**
- Add `format` column to `key` table
- Store format in database
- Display format in list view
- Validate format on backend
2. **Advanced Validation:**
- More robust YAML parser
- JSON schema validation
- Custom format types
3. **Bulk Operations:**
- Multi-select keys
- Bulk delete
- Bulk export/import
4. **Key Versioning:**
- Track value history
- Rollback to previous versions
- Audit trail
5. **Server-Side Search:**
- Add search parameter to API
- Search across all pages
- More efficient for large datasets
6. **Enhanced Security:**
- Role-based key access
- Key rotation policies
- Expiration dates
- Usage logging
## Documentation Updates Needed
Consider updating:
- `docs/api/api-secrets.md` - Document format field if added to backend
- `docs/guides/secrets-management.md` - User guide for keys page
- Add screenshots to documentation