- Add Workspace domain (entity, repository, service, handler, DTO) - Add multi-tenant K8s client with tenant binding and quota management - Add K8s diagnostics client (instance diagnostics) - Add authorization middleware (authz package) - Restructure frontend to feature-based architecture (features/) - Add User Management page in configuration - Add AccessDenied page and route guards - Refactor shared components (form inputs, layout, UI) - Update Tailwind config for new design system - Add comprehensive documentation (docs/, tasks/, plans) - Improve cluster service with better kubeconfig handling - Add tests for crypto, config, helm client, tenant binding
65 KiB
65 KiB
OCDP Test Scenarios
Platform: OCDP (Open Cloud Deployment Platform) Deployed at: http://10.6.80.114:18080 Scope: Full-stack test scenarios covering authentication, configuration, artifact browser, instance lifecycle, monitoring, user management, multi-tenancy, UI/UX, data persistence, security, and edge cases.
Category 1: Authentication & Authorization (25+ cases)
AUTH-001 — Login with valid credentials
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Admin account exists in the system |
| Steps | 1. Navigate to / 2. Enter valid username and password 3. Click "Login" |
| Expected Result | User is authenticated, redirected to /home, token stored in localStorage/session, toast "Welcome, [username]!" displayed |
AUTH-002 — Login with incorrect password
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Valid username exists |
| Steps | 1. Enter valid username with wrong password 2. Click "Login" |
| Expected Result | Login fails with 401 error, red error message displayed, user stays on login page |
AUTH-003 — Login with non-existent username
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | None |
| Steps | 1. Enter username that does not exist 2. Enter any password 3. Click "Login" |
| Expected Result | 401 returned, error message shown, no user enumerated |
AUTH-004 — Login with empty credentials
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | None |
| Steps | 1. Leave username and password empty 2. Click "Login" |
| Expected Result | HTML5 form validation prevents submission, or backend returns validation error |
AUTH-005 — Login with special characters in username
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | None |
| Steps | 1. Enter username with SQL injection patterns: admin' OR '1'='1 2. Enter password 3. Click "Login" |
| Expected Result | Login fails, no SQL injection succeeds, no data leak |
AUTH-006 — Successful login response contains expected fields
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Valid credentials |
| Steps | 1. Call POST /api/v1/auth/login 2. Inspect response body |
| Expected Result | Response contains accessToken, refreshToken, username, role, permissions, userId, workspaceId |
AUTH-007 — JWT token sent in Authorization header
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Valid token obtained |
| Steps | 1. Capture XHR request to any protected API 2. Inspect Authorization header |
| Expected Result | Header contains Bearer <token> |
AUTH-008 — Access protected route without token
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Clear all auth tokens |
| Steps | 1. Navigate directly to /home 2. Navigate to /artifact/instances 3. API call to /api/v1/clusters without token |
| Expected Result | Frontend redirects to /, backend returns 401 |
AUTH-009 — Access protected API without token
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | None |
| Steps | 1. Call GET /api/v1/clusters without Authorization header |
| Expected Result | 401 Unauthorized returned |
AUTH-010 — Token expiry handling
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Use a token near expiry or manipulate expiry |
| Steps | 1. Make API call with expired token |
| Expected Result | Backend returns 401, frontend should redirect to login page or attempt token refresh |
AUTH-011 — Token refresh flow
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Valid refresh token exists |
| Steps | 1. Call POST /api/v1/auth/refresh with valid refresh token 2. Call with expired/invalid refresh token |
| Expected Result | Valid refresh returns new access token; invalid returns 401 |
AUTH-012 — Logout behavior
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | User is logged in |
| Steps | 1. Click logout/sign out button 2. Try to navigate to previously visited protected page |
| Expected Result | Token cleared from storage, redirected to login page, protected routes inaccessible |
AUTH-013 — Logout clears token from localStorage
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | User is logged in |
| Steps | 1. Inspect localStorage for auth tokens after login 2. Logout 3. Inspect localStorage again |
| Expected Result | Tokens removed after logout |
AUTH-014 — Role-based page access: admin
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Admin user logged in |
| Steps | 1. Navigate to /configuration/users 2. Navigate to /configuration/clusters 3. Navigate to /artifact/instances |
| Expected Result | All pages accessible |
AUTH-015 — Role-based page access: regular user
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Regular user logged in (non-admin) |
| Steps | 1. Navigate to /configuration/users 2. Navigate to /admin |
| Expected Result | Redirected to /forbidden or access denied page |
AUTH-016 — Regular user can access own resources pages
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Regular user logged in |
| Steps | 1. Navigate to /home 2. Navigate to /configuration/clusters 3. Navigate to /configuration/registries 4. Navigate to /artifact/registries 5. Navigate to /artifact/instances |
| Expected Result | All pages accessible (user sees own resources) |
AUTH-017 — Login page redirect when already authenticated
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | User is logged in |
| Steps | 1. Navigate to / 2. Observe behavior |
| Expected Result | Redirected to /home instead of showing login form |
AUTH-018 — Login page UI elements
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | Not authenticated |
| Steps | 1. Observe login page 2. Check for OCDP Console branding, username input, password input, Login button |
| Expected Result | Page displays brand icon, "OCDP Console" title, username/password fields with correct autocomplete attributes, Login button |
AUTH-019 — Login button loading state
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | None |
| Steps | 1. Enter credentials and click Login 2. Observe button state during API call |
| Expected Result | Button shows spinner/loading state, text changes to "Logging in...", button disabled during request |
AUTH-020 — Login error display
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | None |
| Steps | 1. Enter wrong credentials and submit 2. Observe error message |
| Expected Result | Red error text appears below the login button, message is user-friendly (not a raw stack trace) |
AUTH-021 — Password change flow (mustChangePassword)
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | User created with mustChangePassword: true |
| Steps | 1. Login as that user 2. Observe redirect/behavior 3. Change password 4. Login again with new password |
| Expected Result | First login forces password change, old password rejected after change |
AUTH-022 — Refresh token expiry logout
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Both access and refresh tokens expired |
| Steps | 1. Wait for full token expiry 2. Make any API call that triggers refresh |
| Expected Result | User is logged out, redirected to login page |
AUTH-023 — Concurrent login sessions
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | User account exists |
| Steps | 1. Login in browser tab 1 2. Login in browser tab 2 with same credentials 3. Perform operations in both tabs |
| Expected Result | Both sessions work independently, no cross-tab interference |
AUTH-024 — Admin login shows "Admin only" badge on User Management
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | Admin logged in |
| Steps | 1. Navigate to /configuration/users 2. Check for admin badge |
| Expected Result | "Admin only" badge visible in the User Management page header |
AUTH-025 — Token manipulation (tampered JWT)
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Get valid token, modify its payload |
| Steps | 1. Decode JWT, change role to "admin" for a regular user token 2. Re-encode with modified payload and send API request |
| Expected Result | Backend rejects tampered token (signature verification fails), returns 401 |
Category 2: Cluster CRUD (15+ cases)
CLU-001 — Create cluster with all required fields
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Logged in as admin/user with cluster permissions |
| Steps | 1. Navigate to /configuration/clusters 2. Click "Add Cluster" 3. Fill in name, API Server URL, CA cert, client cert, client key 4. Click "Save" |
| Expected Result | Cluster created successfully, success toast shown, cluster appears in the list |
CLU-002 — Create cluster with token auth
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Logged in |
| Steps | 1. Click "Add Cluster" 2. Fill name, API Server URL, Bearer Token (leave cert fields empty) 3. Click "Save" |
| Expected Result | Cluster created using token authentication |
CLU-003 — Create cluster with empty name
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Create modal open |
| Steps | 1. Leave name empty 2. Fill all other required fields 3. Click "Save" |
| Expected Result | Validation error "Cluster name is required" displayed near the name field |
CLU-004 — Create cluster with invalid API Server URL
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Create modal open |
| Steps | 1. Enter name 2. Enter invalid URL (e.g., not-a-url, ftp://...) 3. Click "Save" |
| Expected Result | Validation error "Invalid URL format" displayed |
CLU-005 — Create cluster without auth credentials
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Create modal open |
| Steps | 1. Enter name and URL 2. Leave all cert/key/token fields empty 3. Click "Save" |
| Expected Result | Validation errors on CA/Client Cert/Client Key fields |
CLU-006 — Edit cluster name and URL
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Existing cluster present |
| Steps | 1. Click edit on existing cluster 2. Change name and host 3. Click "Save" |
| Expected Result | Cluster updated, changes reflected in list |
CLU-007 — Edit cluster with new certificate (overwrite)
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Existing cluster with cert auth |
| Steps | 1. Edit cluster 2. Enter new CA cert, client cert, client key in the "new" fields 3. Click "Save" |
| Expected Result | Certificate updated, "hasCaData" still appears as configured |
CLU-008 — Edit cluster leaving cert fields empty (no change)
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Existing cluster with cert auth |
| Steps | 1. Edit cluster 2. Leave the "new" cert fields empty 3. Click "Save" |
| Expected Result | Cluster updated, existing certs retained |
CLU-009 — Delete cluster
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Existing cluster with no running instances (or expected behavior defined) |
| Steps | 1. Click delete icon on a cluster 2. Confirm deletion in browser confirm dialog |
| Expected Result | Cluster removed from list, success toast shown |
CLU-010 — Delete cluster cancellation
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | Existing cluster |
| Steps | 1. Click delete on a cluster 2. Click "Cancel" in the confirmation dialog |
| Expected Result | Cluster not deleted, still visible in the list |
CLU-011 — Health check on reachable cluster
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | A reachable Kubernetes cluster configured |
| Steps | 1. Click health check / test button on the cluster row |
| Expected Result | Success toast with connection healthy message |
CLU-012 — Health check on unreachable cluster
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Cluster with invalid host/cert configured |
| Steps | 1. Click health check / test button on the cluster |
| Expected Result | Error toast with connection failure message |
CLU-013 — Empty clusters state
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | No clusters configured |
| Steps | 1. Navigate to /configuration/clusters |
| Expected Result | Empty state message displayed, add cluster action available |
CLU-014 — Cluster list with multiple clusters
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | 3+ clusters configured |
| Steps | 1. Navigate to /configuration/clusters 2. Scroll list |
| Expected Result | All clusters listed with name, URL, status indicators |
CLU-015 — Cluster description display in list
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | Cluster with description exists |
| Steps | 1. View cluster list 2. Check if description is visible |
| Expected Result | Description shown as subtitle or tooltip in the cluster row |
CLU-016 — Cluster CRUD as regular user
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Regular user logged in |
| Steps | 1. Create a new cluster 2. Edit the cluster 3. Delete the cluster |
| Expected Result | User can manage their own clusters, or see appropriate empty/permission state |
CLU-017 — Cluster form modal close/reset
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | Create modal open with partially filled form |
| Steps | 1. Fill partial data 2. Click Cancel |
| Expected Result | Modal closes, form data cleared when reopened |
Category 3: Registry CRUD (15+ cases)
REG-001 — Create registry with all required fields
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Logged in |
| Steps | 1. Navigate to /configuration/registries 2. Click "Add Registry" 3. Fill name, URL, username, password 4. Click "Save" |
| Expected Result | Registry created, success toast shown, appears in list |
REG-002 — Create registry with insecure flag
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Logged in |
| Steps | 1. Open add registry modal 2. Fill required fields 3. Check "Allow insecure connection" 4. Click "Save" |
| Expected Result | Registry created with insecure: true, works for HTTP/self-signed registries |
REG-003 — Create registry without name
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Create modal open |
| Steps | 1. Leave name empty 2. Fill other fields 3. Click "Save" |
| Expected Result | HTML5 form validation prevents submission (required attribute) |
REG-004 — Create registry with invalid URL
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Create modal open |
| Steps | 1. Enter non-URL string for URL field (type=url) 2. Fill other fields 3. Click "Save" |
| Expected Result | HTML5 form validation prevents submission (type=url validation) |
REG-005 — Test registry connection
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Saved registry exists, it's reachable |
| Steps | 1. Edit an existing registry 2. Click "Test Connection" button |
| Expected Result | Connection test runs, success/error toast based on connectivity |
REG-006 — Test registry connection without saving first
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | Creating new registry (unsaved) |
| Steps | 1. Fill registry form but do not save 2. Check if "Test Connection" is available |
| Expected Result | "Test Connection" button is not shown (only visible for saved registries) |
REG-007 — Edit registry name and URL
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Existing registry |
| Steps | 1. Edit a registry 2. Change its name and URL 3. Save |
| Expected Result | Registry updated, changes reflected |
REG-008 — Edit registry with new password
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Existing registry with password set |
| Steps | 1. Edit registry 2. Enter new password in the "New Password" field 3. Save |
| Expected Result | Password updated, "hasPassword" indicator shows as configured |
REG-009 — Edit registry leaving password empty
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Existing registry |
| Steps | 1. Edit registry 2. Leave new password field empty 3. Save |
| Expected Result | Registry updated, existing password retained |
REG-010 — Delete registry
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Existing registry with no active dependencies |
| Steps | 1. Click delete on a registry 2. Confirm deletion |
| Expected Result | Registry removed from list, success toast |
REG-011 — Delete registry with existing instances
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Registry has active instances deployed from it |
| Steps | 1. Try to delete registry that has active instances deriving from it |
| Expected Result | Backend should return error preventing deletion, or handle cascading gracefully |
REG-012 — Empty registries state
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | No registries configured |
| Steps | 1. Navigate to /configuration/registries |
| Expected Result | Empty state message displayed |
REG-013 — Registry toggle insecure flag
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | Existing registry |
| Steps | 1. Edit registry 2. Toggle insecure checkbox 3. Save |
| Expected Result | Insecure flag updated |
REG-014 — Registry list display
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | Multiple registries exist |
| Steps | 1. View the registries page 2. Check each row |
| Expected Result | Each registry shows name, URL, username, insecure badge (if enabled) |
REG-015 — Registry CRUD as regular user
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Regular user logged in |
| Steps | 1. Create a new registry 2. Edit the registry 3. Delete the registry |
| Expected Result | User can manage their own registries |
Category 4: Chart Browser / Launch Instance (20+ cases)
CHT-001 — Browse registries in chart browser
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Registries configured with Helm charts |
| Steps | 1. Navigate to /artifact/registries 2. Observe left panel |
| Expected Result | Registries listed with expand/collapse toggle, count badge |
CHT-002 — Expand registry tree and list repositories
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Registry has chart repositories |
| Steps | 1. Click on a registry to expand it 2. Observe repositories listed underneath |
| Expected Result | Repositories displayed as clickable items, each showing name |
CHT-003 — Empty repository list message
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Registry exists but has no chart repositories |
| Steps | 1. Expand registry 2. Observe sub-items |
| Expected Result | "No chart repositories found." message shown |
CHT-004 — Select repository and view artifacts
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Repository with chart artifacts exists |
| Steps | 1. Click on a repository in the left panel 2. Observe right panel |
| Expected Result | Repository name displayed in header, artifact tags shown as cards |
CHT-005 — Filter artifacts by Charts / All tags
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Repository has both chart and non-chart artifacts |
| Steps | 1. Select a repository 2. Click "Charts" filter button 3. Click "All tags" filter button |
| Expected Result | "Charts" filter shows only chart artifacts, "All tags" shows all |
CHT-006 — Filter toggle active state
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | Repository selected |
| Steps | 1. Toggle between Charts and All tags |
| Expected Result | Active filter button has blue highlight, inactive has default styling |
CHT-007 — Tag card displays correct info
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Artifact loaded |
| Steps | 1. Observe a tag card |
| Expected Result | Card shows tag name, artifact type badge (chart/image), repository path, size |
CHT-008 — Launch button visible only for chart tags
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Chart and non-chart artifacts exist |
| Steps | 1. Observe a chart tag card 2. Observe a non-chart tag card |
| Expected Result | Chart tag card has blue "Launch" button; non-chart card does not |
CHT-009 — Copy pull command from tag card
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | Tag card displayed |
| Steps | 1. Click "Copy" on a tag card |
| Expected Result | Helm pull command copied to clipboard, success toast shown |
CHT-010 — Search registries/repositories
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Multiple registries with repositories exist |
| Steps | 1. Type in the search box in the left panel 2. Observe filtering |
| Expected Result | List filters to matching registries and repositories; non-matching entries hidden |
CHT-011 — Open Launch modal
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Chart tag selected |
| Steps | 1. Click "Launch" on a chart tag |
| Expected Result | Launch modal opens with repository:tag header, cluster selector, instance name, namespace, values options |
CHT-012 — Launch modal loads clusters
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Clusters exist in the system |
| Steps | 1. Open Launch modal 2. Observe cluster dropdown |
| Expected Result | Cluster dropdown populated with available clusters |
CHT-013 — Launch modal: no clusters available
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | No clusters configured |
| Steps | 1. Open Launch modal 2. Observe cluster section |
| Expected Result | Warning message "No clusters available. Please add a cluster first." displayed, Launch button disabled |
CHT-014 — Launch modal: instance name validation
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Launch modal open with cluster selected |
| Steps | 1. Leave instance name empty 2. Click Launch |
| Expected Result | Toast error "Instance name is required" |
CHT-015 — Launch modal: namespace validation
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Cluster with namespace policy configured |
| Steps | 1. Select a disallowed namespace (not in allowedNamespaces) 2. Click Launch |
| Expected Result | Toast error "Selected namespace is not allowed for this cluster." |
CHT-016 — Launch modal: Quick / Form / YAML input modes
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Launch modal open |
| Steps | 1. Click each mode button (Quick, Guided, YAML) 2. Observe content changes |
| Expected Result | Quick: info panel about chart defaults. Guided: schema form (if schema exists). YAML: textarea for YAML input. Active mode highlighted. |
CHT-017 — Launch modal: YAML validation
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | YAML input mode selected |
| Steps | 1. Enter invalid YAML (e.g., key: [invalid) 2. Observe error state |
| Expected Result | Red error text below textarea, Launch button disabled |
CHT-018 — Launch modal: Load Defaults from values.yaml
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Chart has values.yaml with defaults |
| Steps | 1. Switch to YAML mode 2. Click "Load Defaults from values.yaml" |
| Expected Result | values.yaml content loaded into the textarea |
CHT-019 — Submit launch and navigate to instances
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | All required fields filled with valid data |
| Steps | 1. Fill cluster, instance name, namespace 2. Click Launch 3. Wait for redirect |
| Expected Result | Instance creation API called, success toast, redirected to /artifact/instances, instance shown with "Pending Install" status |
CHT-020 — Launch modal: namespace controlled by workspace policy
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Cluster has namespace readOnly policy |
| Steps | 1. Open Launch modal 2. Select cluster with readonly namespace policy 3. Check namespace field |
| Expected Result | Namespace field is disabled with blue info message: "Namespace is controlled by your workspace policy." |
CHT-021 — Launch modal: namespace dropdown (allowed namespaces)
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Cluster has allowedNamespaces configured |
| Steps | 1. Select such cluster 2. Observe namespace field |
| Expected Result | Namespace becomes a dropdown with only allowed values |
CHT-022 — Launch modal: user's default cluster pre-selected
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | User has defaultClusterId set |
| Steps | 1. Open Launch modal |
| Expected Result | Default cluster auto-selected in the dropdown |
Category 5: Instance Management (20+ cases)
INS-001 — View instances (all clusters)
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Instances exist across clusters |
| Steps | 1. Navigate to /artifact/instances |
| Expected Result | All instances listed grouped by cluster, stats cards show totals |
INS-002 — Filter instances by cluster
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Multiple clusters with instances |
| Steps | 1. Navigate to instances page 2. Select a specific cluster from dropdown |
| Expected Result | Only instances from that cluster displayed |
INS-003 — Instance status: Deployed
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Instance in deployed state |
| Steps | 1. Look for a deployed instance card |
| Expected Result | Green "DEPLOYED" badge with checkmark icon, status reason shown |
INS-004 — Instance status: Failed
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Instance in failed state |
| Steps | 1. Look for a failed instance card |
| Expected Result | Red "FAILED" badge, error details visible (lastError section appears) |
INS-005 — Instance status: Pending (Install/Upgrade/Rollback/Delete)
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Instance in transition state |
| Steps | 1. Look for pending instance card |
| Expected Result | Amber/yellow "PENDING INSTALL/UPGRADE/ROLLBACK/DELETE" badge |
INS-006 — Instance status: Unknown
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | Instance with unknown status |
| Steps | 1. Look for unknown instance card |
| Expected Result | Gray "UNKNOWN" badge |
INS-007 — Refresh instance status
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Instance exists |
| Steps | 1. Click "Refresh" button on the instance card |
| Expected Result | Instance status re-fetched, card updates with latest status |
INS-008 — Instance card displays metadata correctly
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Instance exists |
| Steps | 1. Examine instance card content |
| Expected Result | Card shows: instance name, repository, version tag, namespace, revision, launch date, status reason |
INS-009 — Instance action buttons visibility
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Instance exists |
| Steps | 1. Check the action bar at bottom of instance card |
| Expected Result | Five buttons visible: Refresh, Entries, Diagnostics, Modify, Delete |
INS-010 — View entries (Services)
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Deployed instance with services |
| Steps | 1. Click "Entries" on the instance card 2. Observe modal |
| Expected Result | Modal shows Services with name, type, cluster IP, ports; source badge visible |
INS-011 — View entries (Ingresses)
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Deployed instance with ingresses |
| Steps | 1. Open entries modal 2. Check for Ingresses section |
| Expected Result | Ingresses listed with host, paths, TLS status |
INS-012 — View diagnostics (Describe)
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Deployed instance |
| Steps | 1. Click "Diagnostics" on instance card 2. Observe Describe tab |
| Expected Result | Modal shows Pods (with status, node, restarts, containers) and Services summary |
INS-013 — View diagnostics (Events)
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Deployed instance |
| Steps | 1. Open diagnostics 2. Click "Events" tab |
| Expected Result | Kubernetes events listed with type badge, reason, message, timestamp, count |
INS-014 — View diagnostics (Pod Logs)
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Deployed instance with running pods |
| Steps | 1. Open diagnostics 2. Click "Pod Logs" tab |
| Expected Result | Pod logs displayed in dark terminal-style blocks, copy button available |
INS-015 — Copy pod logs
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | Diagnostics with logs loaded |
| Steps | 1. Open pod logs 2. Click "Copy Logs" |
| Expected Result | Combined logs copied to clipboard, success toast shown |
INS-016 — Modify instance version tag
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Deployed instance, new chart version available |
| Steps | 1. Click "Modify" on instance 2. Change version tag 3. Confirm |
| Expected Result | Instance upgrade initiated, instance moves to "Pending Upgrade" status |
INS-017 — Modify instance with values changes
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Deployed instance |
| Steps | 1. Open modify modal 2. Switch to YAML input 3. Update values 4. Confirm |
| Expected Result | Instance upgraded with modified values |
INS-018 — Terminate/delete instance with confirmation
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Deployed instance exists |
| Steps | 1. Click "Delete" on instance card 2. Confirm in browser dialog |
| Expected Result | Deletion initiated, instance enters "Pending Delete" status, eventually disappears |
INS-019 — Terminate instance cancellation
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | Deployed instance |
| Steps | 1. Click "Delete" 2. Click "Cancel" in the confirmation dialog |
| Expected Result | Instance not deleted, dialog dismissed |
INS-020 — Empty instances state
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | No instances deployed |
| Steps | 1. Navigate to /artifact/instances |
| Expected Result | Empty state displayed: "No instances found. Launch your first service instance from Artifact Registries" |
INS-021 — Instances auto-refresh
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | Instances page open |
| Steps | 1. Stay on instances page 2. Observe network requests for 30+ seconds |
| Expected Result | Background auto-refresh fires every 30 seconds without user interaction |
Category 6: Cluster Monitoring (10+ cases)
MON-001 — View cluster health monitoring
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Clusters configured |
| Steps | 1. Navigate to /monitoring/clusters |
| Expected Result | Cluster monitoring cards displayed with health status badges, metrics grid |
MON-002 — Stats cards display summary
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | 3+ clusters with varying health |
| Steps | 1. Navigate to monitoring page |
| Expected Result | Stats cards show: Total Clusters, Healthy count, Warning count, Error count |
MON-003 — Monitoring card shows cluster metrics
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Healthy cluster |
| Steps | 1. Observe a cluster monitoring card |
| Expected Result | Card shows: cluster name, uptime, node count, pod count, GPU usage, CPU usage bar, memory usage bar, last checked time |
MON-004 — Expand node details
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Cluster has nodes |
| Steps | 1. Click "Show Nodes" button on a cluster card 2. Observe node list |
| Expected Result | Node list expands showing individual node metrics (CPU, memory, GPU per node) |
MON-005 — Healthy cluster status display
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Cluster is healthy |
| Steps | 1. Check card header |
| Expected Result | Green "Healthy" badge, green checkmark icon |
MON-006 — Error cluster status display
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Cluster is unhealthy/error |
| Steps | 1. Check card header |
| Expected Result | Red "Error" badge, red X icon |
MON-007 — Auto-refresh monitoring
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | Monitoring page open |
| Steps | 1. Stay on page 2. Observe metrics updates over time |
| Expected Result | Page auto-refreshes every 30 seconds, "Auto-refresh every 30 seconds" text visible |
MON-008 — Manual refresh
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Monitoring page open |
| Steps | 1. Click "Refresh" button |
| Expected Result | Data reloaded, loading state shown during refresh |
MON-009 — Empty monitoring state
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | No clusters configured |
| Steps | 1. Navigate to monitoring page |
| Expected Result | "No Clusters Available" empty state displayed |
MON-010 — Error state when cluster unreachable
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Cluster monitoring API returns error |
| Steps | 1. Simulate API failure 2. Observe page |
| Expected Result | Error state with retry button shown, error message displayed |
Category 7: User Management (Admin) (15+ cases)
USR-001 — Create user with role "user"
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Admin logged in |
| Steps | 1. Navigate to /configuration/users 2. Fill username, password, role=User 3. Set namespace, default cluster, resource limits 4. Click "Create User" |
| Expected Result | User created, appears in accounts table |
USR-002 — Create user with role "admin"
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Admin logged in |
| Steps | 1. Open create user form 2. Select Role=Admin 3. Fill username and password only (namespace/limits hidden for admin) 4. Click "Create User" |
| Expected Result | Admin user created, namespace/limits not required, role badge shows "admin" |
USR-003 — Create user with mustChangePassword
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Create user modal |
| Steps | 1. Ensure "Require password change after first login" checkbox is checked 2. Create user |
| Expected Result | User created and must change password on first login |
USR-004 — Create user without required fields
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Create form open |
| Steps | 1. Leave username or password empty 2. Click "Create User" |
| Expected Result | Validation error toast "Username and initial password are required." |
USR-005 — Edit user resource limits
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Non-admin user exists |
| Steps | 1. Click "Limits" on a user row 2. Change CPU, Memory, GPU, GPU Mem values 3. Click "Save Limits" |
| Expected Result | Limits modal closes, success toast, updated values shown in table |
USR-006 — Toggle user role (user ↔ admin)
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | User exists |
| Steps | 1. Click "Make Admin" on a user row 2. Observe role change 3. Click "Make User" to revert |
| Expected Result | Role toggled, badge updates, admin users can access all pages after re-login |
USR-007 — Enable/disable user
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Active user exists |
| Steps | 1. Click "Disable" on an active user 2. Observe badge change 3. Try to login as that user |
| Expected Result | Badge changes to "Disabled", disabled user cannot login (returns 401) |
USR-008 — Delete user
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Non-self user exists |
| Steps | 1. Click "Delete" on a user 2. Confirm deletion |
| Expected Result | User removed from table |
USR-009 — Cannot delete own admin account
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Current admin logged in |
| Steps | 1. Look at own user row |
| Expected Result | Delete button is disabled (or not rendered) for the current user |
USR-010 — Cannot disable own admin account
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Current admin logged in |
| Steps | 1. Look at own user row 2. Check Disable button state |
| Expected Result | Disable button is disabled for current user |
USR-011 — User Management page admin-only badge
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Admin logged in |
| Steps | 1. Observe page header |
| Expected Result | "Admin only" badge visible near the title |
USR-012 — User table displays all columns
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | Users exist |
| Steps | 1. Observe the accounts table |
| Expected Result | Columns: User (username+email), Role (badge), Status (Active/Disabled), Namespace, Quota (CPU/Mem/GPU), Actions |
USR-013 — Namespace auto-generation for user
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | Creating user with role=user |
| Steps | 1. Enter username 2. Check namespace field (before user edits it) |
| Expected Result | Namespace auto-populated as ocdp-u-<sanitized-username> |
USR-014 — Create user with resource limits
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Create form open, role=User |
| Steps | 1. Set specific CPU, Memory, GPU, GPU memory limits 2. Create user 3. View user in table |
| Expected Result | Limits stored and displayed in the quota column |
USR-015 — User list refresh
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | Users page open |
| Steps | 1. Click "Refresh" button |
| Expected Result | User list reloaded, loading state shown |
Category 8: Multi-tenancy & Permissions (15+ cases)
MTN-001 — User A cannot see User B's clusters
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Two regular users (A, B), each with their own cluster |
| Steps | 1. Login as User A 2. List clusters via API 3. Login as User B 4. List clusters via API |
| Expected Result | User A sees only their clusters, User B sees only their clusters. No cross-tenant leakage |
MTN-002 — User A cannot see User B's registries
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Two regular users with separate registries |
| Steps | 1. List registries as User A 2. List registries as User B |
| Expected Result | Each user sees only their own registries |
MTN-003 — User A cannot delete User B's instances
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | User A and B each have instances |
| Steps | 1. As User A, try to call DELETE on User B's instance |
| Expected Result | Backend returns 403 Forbidden or 404 Not Found |
MTN-004 — User A cannot modify User B's instances
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | User B has an instance |
| Steps | 1. As User A, try to update User B's instance |
| Expected Result | Backend returns 403 Forbidden |
MTN-005 — Admin can see all clusters
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Admin user, clusters belonging to multiple users exist |
| Steps | 1. Login as admin 2. List clusters |
| Expected Result | Admin sees all clusters across all users |
MTN-006 — Admin can see all registries
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Admin user, registries belonging to multiple users exist |
| Steps | 1. Login as admin 2. List registries |
| Expected Result | Admin sees all registries across all users |
MTN-007 — Admin can see all instances
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Instances exist across different users |
| Steps | 1. Login as admin 2. List instances per cluster |
| Expected Result | Admin sees instances from all users' releases |
MTN-008 — ResourceQuota enforcement (CPU)
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | User with CPU quota set, deploying |
| Steps | 1. As user with CPU quota=4, try to deploy chart requesting >4 CPU 2. Check deployment outcome |
| Expected Result | Deployment should fail or ResourceQuota enforced in the namespace |
MTN-009 — ResourceQuota enforcement (GPU)
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | User with GPU quota=0 |
| Steps | 1. Try to deploy a chart requiring GPU |
| Expected Result | Deployment fails due to quota enforcement |
MTN-010 — Namespace isolation across users
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Users A and B configured with different namespaces |
| Steps | 1. User A deploys instance to their namespace 2. User B deploys instance to their namespace 3. Verify User A cannot see User B's pods/instances |
| Expected Result | Instances isolated by namespace, no cross-tenant visibility |
MTN-011 — Regular user cannot access admin pages
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Regular user logged in |
| Steps | 1. Navigate to /configuration/users 2. Navigate to /admin |
| Expected Result | Redirected to /forbidden, access denied page shown |
MTN-012 — Regular user does not see "Users" in home setup card
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | Regular user logged in |
| Steps | 1. Navigate to /home 2. Check "Setup" section |
| Expected Result | "Users" card is not rendered for non-admin users |
MTN-013 — Default user permissions match expected set
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Regular user created without custom permissions |
| Steps | 1. Get user info from /api/v1/auth/me or similar 2. Inspect permissions array |
| Expected Result | Default permissions include: home:view, configuration:clusters:manage_own, configuration:registries:manage_own, artifact:registries:view, artifact:instances:manage_own |
MTN-014 — User workspace metadata stored and returned
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | User exists |
| Steps | 1. Login and inspect user response 2. Check workspaceId, workspaceName, namespace, defaultClusterId |
| Expected Result | Workspace metadata present and consistent |
MTN-015 — Admin can create resources under any user scope
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Admin logged in |
| Steps | 1. Check if admin can create clusters/registries without ownership restriction |
| Expected Result | Admin-created resources are accessible to admin (global scope) |
Category 9: UI/UX Bugs (20+ cases)
UI-001 — Page layout does not overflow horizontally
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | None |
| Steps | 1. Navigate to each page at 1440px viewport width 2. Check for horizontal scrollbar |
| Expected Result | No horizontal overflow, all content fits within viewport |
UI-002 — Responsive layout at mobile breakpoint (768px)
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | None |
| Steps | 1. Resize browser to 768px width 2. Navigate through all pages |
| Expected Result | Navigation collapses, content stacks vertically, no broken layout |
UI-003 — Responsive layout at tablet breakpoint (1024px)
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | None |
| Steps | 1. Resize to 1024px width 2. Check all pages |
| Expected Result | Content reflows gracefully, no overlap |
UI-004 — Loading state displays correctly
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Slow network (simulated) |
| Steps | 1. Enable network throttling 2. Navigate to each page |
| Expected Result | Loading spinner/message appears while data is being fetched, content appears after load |
UI-005 — No flickering during page transitions
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | None |
| Steps | 1. Navigate between pages rapidly 2. Observe visual transitions |
| Expected Result | Smooth transitions, no white flash or layout shift |
UI-006 — Empty states show informative messages
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Fresh/empty system |
| Steps | 1. Check clusters page (empty) 2. Check registries page (empty) 3. Check instances page (empty) |
| Expected Result | Each page has a distinct, informative empty state message with relevant icon |
UI-007 — Error states show retry action
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | API returns error |
| Steps | 1. Simulate backend error 2. Observe error state |
| Expected Result | Error message displayed with a "Retry" button |
UI-008 — Form validation feedback is visible
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | None |
| Steps | 1. Submit forms with invalid data |
| Expected Result | Red error text appears near the invalid field, or toast notification with specific message |
UI-009 — Toast notifications appear and disappear
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | None |
| Steps | 1. Perform actions that trigger toasts (save, delete, error) 2. Observe toast behavior |
| Expected Result | Toast appears at expected position, auto-dismisses after timeout, can be dismissed manually |
UI-010 — Button states: disabled
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | None |
| Steps | 1. Find disabled buttons (Launch when no clusters, Submit with invalid YAML) |
| Expected Result | Disabled buttons have reduced opacity, no pointer cursor, cannot be clicked |
UI-011 — Button states: loading
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Action in progress |
| Steps | 1. Click a button that triggers an API call 2. Observe button during request |
| Expected Result | Button shows spinner/loading indicator, disabled during request |
UI-012 — Truncation of long text labels
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | Long names exist |
| Steps | 1. Create resources with very long names 2. Observe display in cards and lists |
| Expected Result | Long text is truncated with ellipsis, no layout breakage |
UI-013 — Sidebar navigation highlight matches current page
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | None |
| Steps | 1. Navigate to each page 2. Check sidebar nav item highlight |
| Expected Result | Current page's nav item is highlighted/active |
UI-014 — Page header shows correct title and icon
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | None |
| Steps | 1. Navigate to each page |
| Expected Result | Page header displays correct title, icon, and description |
UI-015 — Color contrast meets readability
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | None |
| Steps | 1. Inspect text colors against backgrounds using DevTools |
| Expected Result | All text meets WCAG AA contrast ratio (4.5:1 for normal text, 3:1 for large text) |
UI-016 — Access denied page renders correctly
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | User with insufficient permissions |
| Steps | 1. Access a restricted page |
| Expected Result | Access denied page shown with "Back Home" button |
UI-017 — Cluster list shows health status indicator
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | Clusters exist |
| Steps | 1. Navigate to cluster config page 2. Check each cluster row |
| Expected Result | Each cluster shows a health status indicator (green/yellow/red dot or similar) |
UI-018 — Search/filter in chart browser works correctly
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Multiple registries/repositories exist |
| Steps | 1. Type partial name in search box 2. Type a query that matches no results |
| Expected Result | Matching entries remain visible, non-matching hidden. "No registries" state when nothing matches. |
UI-019 — Modal backdrop click behavior
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | Any modal open |
| Steps | 1. Open a modal (e.g., Launch modal, Cluster form, Modify modal) 2. Click on the dark backdrop |
| Expected Result | Modal closes (or stays open depending on design). Should not cause errors. |
UI-020 — Home page displays all sections
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | Logged in as admin |
| Steps | 1. Navigate to /home |
| Expected Result | Three sections visible: primary actions (Launch Instance, Instances, Cluster Monitoring), runtime focus sidebar, setup section |
Category 10: Data Persistence (10+ cases)
PER-001 — Data survives page refresh (clusters)
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Clusters exist |
| Steps | 1. Navigate to clusters page 2. Refresh the page (F5) |
| Expected Result | Clusters still displayed after refresh |
PER-002 — Data survives page refresh (registries)
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Registries exist |
| Steps | 1. Navigate to registries page 2. Refresh |
| Expected Result | Registries still displayed |
PER-003 — Data survives page refresh (instances)
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Instances exist |
| Steps | 1. Navigate to instances page 2. Refresh |
| Expected Result | Instances still displayed |
PER-004 — Data survives browser tab close/reopen
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Resources exist |
| Steps | 1. Close browser tab 2. Open new tab and navigate to app 3. Login 4. Check all pages |
| Expected Result | All data intact after session restoration |
PER-005 — Created cluster persists after logout/login
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Cluster was created |
| Steps | 1. Logout 2. Login again 3. Check cluster list |
| Expected Result | Cluster still present |
PER-006 — Created registry persists after logout/login
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Registry was created |
| Steps | 1. Logout 2. Login 3. Check registry list |
| Expected Result | Registry still present |
PER-007 — Instance deployment persists across page navigation
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Instance was launched |
| Steps | 1. Navigate away from instances page 2. Navigate back to instances page |
| Expected Result | Instance still listed with its status |
PER-008 — Cache consistency: new cluster appears in Launch dropdown
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Clusters page and artifact browser cached |
| Steps | 1. Add a new cluster 2. Navigate to chart browser 3. Open Launch modal 4. Check cluster dropdown |
| Expected Result | New cluster visible in dropdown (cache refreshed properly) |
PER-009 — Cache consistency: new registry appears in chart browser
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Registry page open, then chart browser |
| Steps | 1. Add a new registry 2. Navigate to chart browser 3. Check left panel |
| Expected Result | New registry visible (after refresh or auto-reload) |
PER-010 — Delete data persists (no phantom data)
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Item deleted earlier |
| Steps | 1. Delete a cluster/registry 2. Refresh page 3. Check list |
| Expected Result | Deleted item does not reappear |
Category 11: Security (15+ cases)
SEC-001 — XSS via form inputs (cluster name)
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Logged in |
| Steps | 1. Create cluster with name <script>alert('xss')</script> 2. Observe if script executes on the list page |
| Expected Result | Script tag is escaped/rendered as text, no XSS execution |
SEC-002 — XSS via form inputs (registry description)
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Logged in |
| Steps | 1. Create registry with description containing HTML/script tags 2. Observe rendering |
| Expected Result | HTML is escaped, no script execution |
SEC-003 — XSS via instance name
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Logged in |
| Steps | 1. Launch instance with name <img onerror="alert(1)" src=x> 2. Navigate to instances page |
| Expected Result | Name is rendered safely, no XSS |
SEC-004 — IDOR: access another user's instance detail
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | User A has an instance, User B knows its ID |
| Steps | 1. Login as User B 2. Try to access User A's instance detail by ID |
| Expected Result | Backend returns 403 Forbidden or 404 |
SEC-005 — IDOR: modify another user's instance
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | User B has instance ID of User A |
| Steps | 1. Login as User A 2. Attempt PUT on User B's instance |
| Expected Result | 403 Forbidden |
SEC-006 — IDOR: delete another user's cluster
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Two regular users exist |
| Steps | 1. User A creates a cluster 2. User B attempts to delete it using cluster ID |
| Expected Result | 403 Forbidden |
SEC-007 — Sensitive data in API responses
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | None |
| Steps | 1. Call GET /api/v1/clusters 2. Inspect response for raw certs/keys/tokens |
| Expected Result | Sensitive fields are masked or encrypted (e.g., hasCaData: true instead of raw cert) |
SEC-008 — Sensitive data in registry responses
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | None |
| Steps | 1. Call GET /api/v1/registries 2. Check response for password exposure |
| Expected Result | Password not returned in plain text; hasPassword boolean used instead |
SEC-009 — JWT token manipulation: signature removed
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Valid JWT obtained |
| Steps | 1. Strip JWT signature, keep base64 payload 2. Send API request with tampered token |
| Expected Result | Backend rejects token, returns 401 |
SEC-010 — JWT token manipulation: alg changed to "none"
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Valid JWT obtained |
| Steps | 1. Change JWT header alg to none 2. Send modified token |
| Expected Result | Backend rejects, returns 401 |
SEC-011 — Directory traversal in repository name
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | None |
| Steps | 1. Try to access artifacts with ../../etc/passwd as repository name |
| Expected Result | Returns 400 Bad Request or 404, no directory traversal occurs |
SEC-012 — Rate limiting on login endpoint
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | None |
| Steps | 1. Send rapid login requests (20+ in 1 second) with wrong passwords |
| Expected Result | After threshold, rate limiting kicks in (429 Too Many Requests) |
SEC-013 — Brute force protection
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | None |
| Steps | 1. Attempt login with wrong password 10+ times in succession |
| Expected Result | Account should be temporarily locked or delayed responses introduced |
SEC-014 — Session fixation test
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | None |
| Steps | 1. Capture pre-auth token 2. Login 3. Check if pre-auth token is still valid |
| Expected Result | Pre-auth token invalidated, new token issued on login |
SEC-015 — No sensitive data in error messages
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | None |
| Steps | 1. Trigger various API errors (invalid auth, bad request, server error) 2. Inspect error responses |
| Expected Result | Error messages do not reveal stack traces, SQL queries, or system internals |
Category 12: Edge Cases (10+ cases)
EDG-001 — Rapid double-click on submit buttons
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Create modal open |
| Steps | 1. Click "Save" or "Create" button rapidly multiple times |
| Expected Result | Button is disabled after first click (loading state), duplicate submissions prevented |
EDG-002 — Very long instance name
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Launch modal open |
| Steps | 1. Enter instance name of 253+ characters 2. Submit |
| Expected Result | Backend validates Kubernetes naming constraints, returns error if too long |
EDG-003 — Special characters in namespace
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Launch modal open |
| Steps | 1. Enter namespace with uppercase letters or special characters 2. Submit |
| Expected Result | Backend validates DNS-1123 label constraints, returns error |
EDG-004 — Browser back/forward navigation
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | Authenticated |
| Steps | 1. Navigate to page A, then page B 2. Click browser back button 3. Click browser forward button |
| Expected Result | Navigation works correctly, no infinite redirects, no blank pages |
EDG-005 — Concurrent operations: launch instance in two tabs
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | Same user, same cluster, same namespace |
| Steps | 1. Tab 1: Launch instance "test-a" 2. Tab 2 (simultaneously): Launch instance "test-b" |
| Expected Result | Both instances created, no data race or corruption |
EDG-006 — Delete cluster with running instances
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Cluster has active Helm releases |
| Steps | 1. Attempt to delete a cluster that has running instances |
| Expected Result | Backend should reject deletion or return a warning about active instances |
EDG-007 — Instance name collision (same namespace)
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Instance "test" already exists in namespace "default" on cluster X |
| Steps | 1. Try to create another instance named "test" in the same namespace and cluster |
| Expected Result | Backend returns conflict error, instance not created |
EDG-008 — Rapid create/delete/create same resource name
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | None |
| Steps | 1. Create cluster named "test-cluster" 2. Delete it 3. Immediately create another cluster named "test-cluster" |
| Expected Result | Second creation succeeds after deletion completes |
EDG-009 — Helm release name collision across namespaces
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | Helm release exists in namespace-a |
| Steps | 1. Launch instance with same name in namespace-b on the same cluster |
| Expected Result | Helm releases are namespaced, so creation should succeed in different namespace |
EDG-010 — YAML values with non-object top-level structure
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | Launch modal open, YAML mode |
| Steps | 1. Enter just a string "hello" or array [1,2,3] as YAML values 2. Click Launch |
| Expected Result | YAML validation error: "Values YAML must be an object" |
Priority Distribution Summary
| Priority | Count |
|---|---|
| P0 (Critical) | 26 |
| P1 (High) | 87 |
| P2 (Medium) | 34 |
| Total | 147 |
Existing Test Coverage Reference
The following test scripts already exist in test/ and cover portions of these scenarios:
| Test Script | Coverage |
|---|---|
current-platform-smoke.sh |
Login, registry health, chart browsing, optional deploy/cleanup |
frontend-playwright-smoke.py |
Login UI, chart browser rendering, instance page, mobile layout |
frontend-interactions-audit.py |
Auth, navigation, config modals, health buttons, launch modes |
multitenant_rbac_api_contract.py |
Auth denial, RBAC differences, resource isolation, admin cleanup |
multitenant_rbac_ui_playwright.py |
Multi-tenant UI isolation tests |
vllm_k3s_deploy_smoke.py |
Real k3s deployment, GPU quota, ResourceQuota, diagnostics |
chart_values_yaml_api_contract.py |
Values YAML API contract validation |
user_namespace_quota_api_contract.py |
User namespace and quota API contract |
instance_card_action_layout_playwright.py |
Instance card action button layout |