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

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

  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

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