11 KiB
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
-
attune/web/src/hooks/useKeys.ts- Custom React hooks for keys/secrets API operations
useKeys()- Fetch paginated list with filtersuseKey(ref)- Fetch single key by reference (includes decrypted value)useCreateKey()- Create new key mutationuseUpdateKey()- Update existing key mutationuseDeleteKey()- Delete key mutation- Proper query invalidation for cache management
-
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
-
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, _, -, .)
-
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
-
attune/web/src/App.tsx- Added route for
/keys(KeysPage) - Imported KeysPage component
- Added route for
-
attune/web/src/components/layout/MainLayout.tsx- Added "Keys & Secrets" navigation item
- Positioned before "Pack Management"
- Uses
KeyRoundicon 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 paginationgetKey({ ref })- Get single key with decrypted valuecreateKey({ requestBody })- Create new keyupdateKey({ ref, requestBody })- Update existing keydeleteKey({ 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
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
-
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
-
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
-
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
-
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
- Click "Create Key" button
- Enter reference:
api_config - Enter name: "API Configuration"
- Select format: JSON (encryption checkbox enabled)
- Enter value:
{"url": "https://api.example.com", "timeout": 30} - Check "Encrypt value" (recommended)
- Select scope: System
- Click "Create Key"
- ✅ Key created with encrypted JSON value
Creating a Number Configuration
- Click "Create Key" button
- Enter reference:
max_retries - Enter name: "Maximum Retry Attempts"
- Select format: Number (encryption checkbox disabled)
- Enter value:
3 - Note: Cannot encrypt (checkbox disabled and grayed out)
- Select scope: System
- Click "Create Key"
- ✅ Key created with unencrypted numeric value
Editing a Key
- Click Edit button on any key row
- Modal shows key metadata (read-only)
- Modify name or value
- Toggle show/hide value
- Change encryption (warning displayed)
- Click "Save Changes"
- ✅ Key updated
Known Limitations
-
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
formatcolumn tokeytable in backend
-
Search Pagination:
- Search is client-side, so only searches current page
- Consider adding server-side search parameter in future
-
No Bulk Operations:
- Delete/update one key at a time
- Could add multi-select for batch operations
-
Value Masking:
- CSS-based masking may not work in all browsers
- Consider more robust masking solution
Security Considerations
-
Encryption Enforcement:
- Only Text, JSON, YAML can be encrypted (per requirements)
- Number, Integer, Boolean cannot be encrypted
- UI enforces this with disabled checkbox
-
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
-
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:
- ✅ List page loads and displays keys
- ✅ Search filters by reference and name
- ✅ Scope filter works correctly
- ✅ Create modal validates format-specific values
- ✅ Encryption checkbox disabled for number/int/bool formats
- ✅ JSON validation catches syntax errors
- ✅ Boolean values must be "true" or "false"
- ✅ Edit modal loads existing key data
- ✅ Show/hide value toggle works
- ✅ Delete confirms before deleting
- ✅ Pagination functions properly
- ✅ Empty states display correctly
- ✅ Error states handle failures gracefully
Future Enhancements
-
Backend Format Field:
- Add
formatcolumn tokeytable - Store format in database
- Display format in list view
- Validate format on backend
- Add
-
Advanced Validation:
- More robust YAML parser
- JSON schema validation
- Custom format types
-
Bulk Operations:
- Multi-select keys
- Bulk delete
- Bulk export/import
-
Key Versioning:
- Track value history
- Rollback to previous versions
- Audit trail
-
Server-Side Search:
- Add search parameter to API
- Search across all pages
- More efficient for large datasets
-
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 backenddocs/guides/secrets-management.md- User guide for keys page- Add screenshots to documentation