Planekeeper E2E Test Plan
Manual end-to-end test scenarios for validating the Planekeeper application. This is a living document updated with each release.
Last Updated: 2026-02-06 Current Branch: feature/improvedhealthcheck
Table of Contents
- Test Environment Setup
- Authentication & Authorization
- Onboarding & Organization Management
- Dashboard
- Gather Jobs
- Scrape Jobs
- Helm Sync Jobs
- Releases
- Monitoring Rules
- Alert Configs
- Alerts
- Notification Channels
- Notification Rules
- Notification Deliveries
- Notification Settings & Templates
- API Keys
- Agents
- Settings
- Health Check
- Cross-Feature Workflows
- Security
- Release Checklist
How to Use This Document
Each test case follows this format:
| Field | Description |
|---|---|
| ID | Unique identifier (AREA-NNN) |
| Priority | P0 (blocker), P1 (critical), P2 (important), P3 (nice-to-have) |
| Preconditions | Required state before running the test |
| Steps | Numbered actions to perform |
| Expected Result | What should happen |
| Status | Pass / Fail / Blocked / Not Tested |
| Notes | Observations, bugs found, release-specific notes |
Status should be updated each release cycle. Use Not Tested for new tests that haven’t been executed yet.
1. Test Environment Setup
Before running tests, ensure the following environment is available:
Prerequisites
- Docker Compose stack running (
docker compose -f go/planekeeper/docker/go/planekeeper/docker/docker-compose.yml up -d) - PostgreSQL accessible and migrations applied (auto on server start)
- At least one organization created (seed data provides “Global” org)
- At least one API key available for Internal UI login
- Supabase project configured (for Supabase auth tests) OR legacy API key mode
- Agent binary running and connected to server
- A GitHub repository with releases available for gather job testing
- A Git repository with a version file (e.g.,
Chart.yaml) for scrape job testing - A webhook receiver (e.g., https://webhook.site) for notification testing
Test Data
| Item | Value |
|---|---|
| Internal UI URL | https://localhost:8443 |
| Client UI URL | http://localhost:80 |
| API Base URL | http://localhost:3000 |
| Health endpoint | http://localhost:3000/health |
| Test GitHub repo | (configure per environment) |
| Test webhook URL | (configure per environment) |
2. Authentication & Authorization
Supabase Auth Flow
AUTH-001: Email/Password Login
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Supabase configured, approved user account exists |
| Steps | 1. Navigate to /login 2. Enter valid email and password 3. Click “Sign In” |
| Expected Result | Redirected to /dashboard. Session cookie planekeeper_session set. Org cookie planekeeper_org set. |
| Status | Not Tested |
AUTH-002: Email/Password Login - Invalid Credentials
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Supabase configured |
| Steps | 1. Navigate to /login 2. Enter invalid email/password 3. Click “Sign In” |
| Expected Result | Error message displayed on login page. No session cookie set. User remains on /login. |
| Status | Not Tested |
AUTH-003: New User Signup (Email/Password)
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Supabase configured |
| Steps | 1. Navigate to /auth/signup 2. Fill in email and password 3. Submit signup form |
| Expected Result | Account created with is_approved = FALSE. Success message shown: “Please check your email to confirm your account.” |
| Status | Not Tested |
AUTH-004: Pending Approval Flow
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Unapproved user account exists |
| Steps | 1. Login as unapproved user 2. Verify /pending-approval page shown 3. Attempt to navigate to /dashboard directly |
| Expected Result | Step 2: Page shows “pending approval” message with user’s email. Step 3: Redirected back to /pending-approval. |
| Status | Not Tested |
AUTH-005: OAuth Login (Auto-Detected Providers)
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Supabase configured with at least one OAuth provider enabled |
| Steps | 1. Navigate to /login 2. Verify OAuth buttons appear only for enabled providers 3. Click an OAuth provider button 4. Complete OAuth flow at provider 5. Verify callback at /auth/callback |
| Expected Result | Only enabled providers shown (auto-detected via GET /auth/v1/settings). Tokens extracted from URL hash, exchanged via /auth/token-exchange, redirected to appropriate page (dashboard or onboarding). |
| Status | Not Tested |
AUTH-005a: OAuth Signup (Same Flow as Login)
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Supabase configured with at least one OAuth provider enabled |
| Steps | 1. Navigate to /auth/signup 2. Verify OAuth buttons appear (same providers as login page) 3. Click an OAuth provider button 4. Complete OAuth flow at provider |
| Expected Result | OAuth buttons shown on signup page with “or sign up with” divider. Flow creates new user if not existing. Redirected to onboarding (new user) or dashboard (existing user). |
| Status | Not Tested |
AUTH-005b: OAuth Buttons Hidden When No Providers Enabled
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | Supabase configured but no OAuth providers enabled |
| Steps | 1. Navigate to /login 2. Navigate to /auth/signup |
| Expected Result | No OAuth buttons or divider shown on either page. Email/password form works normally. |
| Status | Not Tested |
AUTH-006: Logout
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Logged-in user session |
| Steps | 1. Click “Logout” in navigation 2. Verify redirect to /login 3. Attempt to navigate to /dashboard directly |
| Expected Result | All cookies cleared. Step 3: Redirected to /login. |
| Status | Not Tested |
AUTH-007: Session Expiry
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Logged-in user session |
| Steps | 1. Login successfully 2. Wait for session/JWT to expire (or manually delete session cookie) 3. Attempt to access protected page |
| Expected Result | Redirected to /login. No stale data displayed. |
| Status | Not Tested |
Legacy API Key Auth
AUTH-008: API Key Login (Internal UI)
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Active API key exists |
| Steps | 1. Navigate to Internal UI /login 2. Enter valid API key 3. Submit |
| Expected Result | planekeeper_api_key cookie set. Redirected to dashboard. |
| Status | Not Tested |
AUTH-009: API Key Login - Invalid Key
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | None |
| Steps | 1. Navigate to Internal UI /login 2. Enter invalid API key 3. Submit |
| Expected Result | Error message displayed. No cookie set. |
| Status | Not Tested |
AUTH-010: API Key Login - Expired Key
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | API key exists with past expiration date |
| Steps | 1. Attempt login with expired key |
| Expected Result | Authentication rejected. Error message displayed. |
| Status | Not Tested |
AUTH-011: API Key Login - Inactive Key
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | API key exists but is inactive |
| Steps | 1. Attempt login with inactive key |
| Expected Result | Authentication rejected. Error message displayed. |
| Status | Not Tested |
3. Onboarding & Organization Management
ONB-001: New User Onboarding - Create Organization
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Approved user with no org membership |
| Steps | 1. Login as approved user without org 2. Verify redirect to /onboarding 3. Fill in organization name and description 4. Submit “Create Organization” |
| Expected Result | Organization created. User added as owner. Org cookie set. Redirected to /dashboard. |
| Status | Not Tested |
ONB-002: New User Onboarding - Accept Invite
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Approved user with pending org invite |
| Steps | 1. Login as invited user 2. Verify /onboarding page shows pending invites 3. Click “Accept” on invite |
| Expected Result | Membership created with correct role. Org cookie set. Redirected to /dashboard. |
| Status | Not Tested |
ONB-003: Organization Switching
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | User is member of multiple organizations |
| Steps | 1. Login and verify current org in nav 2. Use org switcher to select different org 3. Verify dashboard data changes |
| Expected Result | Org cookie updated. Dashboard shows data for new org. All subsequent API calls use new org context. |
| Status | Not Tested |
4. Dashboard
DASH-001: Dashboard Loads with Metrics
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Authenticated user, some data exists |
| Steps | 1. Navigate to /dashboard |
| Expected Result | Page loads with metric cards: Alert counts (Critical, High, Moderate, Unacknowledged), Job stats (Total, Pending, Completed, Failed), Release stats (Total, Unique Artifacts, Stable), System Health. Recent jobs table displayed. |
| Status | Not Tested |
DASH-002: Dashboard Scope Filter - Organization
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Both org-specific and global data exist |
| Steps | 1. Navigate to /dashboard (defaults to org scope) 2. Verify only org-scoped data shown |
| Expected Result | Metrics and recent jobs reflect only the current organization’s data. |
| Status | Not Tested |
DASH-003: Dashboard Scope Filter - Global
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Global data exists |
| Steps | 1. On dashboard, change scope filter to “Global” |
| Expected Result | Metrics and recent jobs reflect only global (system) data. URL updates to ?scope=global. |
| Status | Not Tested |
DASH-004: Dashboard Scope Filter - All
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Both org and global data exist |
| Steps | 1. On dashboard, change scope filter to “All” |
| Expected Result | Metrics and recent jobs show combined org + global data. URL updates to ?scope=all. |
| Status | Not Tested |
DASH-005: Dashboard with No Data
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | Fresh organization with no jobs, rules, or alerts |
| Steps | 1. Navigate to /dashboard |
| Expected Result | All metric cards show zero values. Recent jobs table shows empty state. No errors. |
| Status | Not Tested |
5. Gather Jobs
GJ-001: List Gather Jobs
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Authenticated, gather jobs exist |
| Steps | 1. Navigate to /jobs |
| Expected Result | Table shows gather jobs with columns: Name, Artifact, Source, Status, Schedule, Last Run, Actions. Pagination controls visible if >50 items. |
| Status | Not Tested |
GJ-002: Create Gather Job - GitHub Releases
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Authenticated |
| Steps | 1. Navigate to /jobs 2. Click “Create” 3. Fill: Name, Artifact (e.g., kubernetes/kubernetes), Source Type = github_releases, optional cron schedule 4. Submit |
| Expected Result | Job created with pending status. Redirected to jobs list. New job appears in table. |
| Status | Not Tested |
GJ-003: Create Gather Job - Validation Error
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Authenticated |
| Steps | 1. Click “Create” 2. Submit with empty required fields |
| Expected Result | Error message displayed. Form not submitted. User stays on form. |
| Status | Not Tested |
GJ-004: Edit Gather Job
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Gather job exists |
| Steps | 1. Click “Edit” on a gather job 2. Modify name or artifact 3. Submit |
| Expected Result | Job updated. Redirected to jobs list. Changes reflected in table. |
| Status | Not Tested |
GJ-005: Trigger Gather Job Manually
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Gather job exists, agent is running |
| Steps | 1. Click “Run” on a gather job 2. Wait for agent to pick up and complete the job |
| Expected Result | Job status transitions: pending → in_progress → completed. Releases populated after completion. |
| Status | Not Tested |
GJ-006: Delete Gather Job
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Gather job exists |
| Steps | 1. Click “Delete” on a gather job 2. Confirm deletion in browser dialog |
| Expected Result | Job removed from list. Confirmation dialog appears before deletion. |
| Status | Not Tested |
GJ-007: Delete Gather Job - Cancel
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | Gather job exists |
| Steps | 1. Click “Delete” on a gather job 2. Cancel the confirmation dialog |
| Expected Result | Job remains in list. No changes made. |
| Status | Not Tested |
GJ-008: Clear Releases for Gather Job
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | Gather job exists with releases |
| Steps | 1. Click “Clear Releases” on a gather job 2. Confirm action |
| Expected Result | All cached releases for this job are deleted. Release count resets to 0. |
| Status | Not Tested |
GJ-009: Gather Jobs - Search Filter
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | Multiple gather jobs exist |
| Steps | 1. On /jobs, enter a search term 2. Submit search |
| Expected Result | Table filters to show only jobs matching the search term (by name or artifact). |
| Status | Not Tested |
GJ-010: Gather Jobs - Scope Filter
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Org-scoped and global gather jobs exist |
| Steps | 1. Toggle scope filter between Org, Global, All |
| Expected Result | Table updates to show jobs matching selected scope. |
| Status | Not Tested |
GJ-011: Gather Jobs - Pagination
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | >50 gather jobs exist |
| Steps | 1. Navigate to /jobs 2. Verify first page shows 50 items 3. Click “Next” |
| Expected Result | Page 2 loads with remaining items. Previous/Next controls work correctly. |
| Status | Not Tested |
6. Scrape Jobs
SJ-001: List Scrape Jobs
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Scrape jobs exist |
| Steps | 1. Navigate to /scrape-jobs |
| Expected Result | Table shows scrape jobs with columns: Name, Repository, Parser Type, Status, Latest Version, Actions. |
| Status | Not Tested |
SJ-002: Create Scrape Job
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Authenticated |
| Steps | 1. Click “Create” on scrape jobs page 2. Fill: Name, Repository URL, File Path, Parse Type (yq/jq/regex), Expression, optional cron 3. Submit |
| Expected Result | Job created with pending status. Appears in list. |
| Status | Not Tested |
SJ-003: Create Scrape Job - Regex Validation
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Authenticated |
| Steps | 1. Create scrape job with Parse Type = regex 2. Enter invalid regex expression 3. Use “Validate” button (HTMX) |
| Expected Result | Inline validation shows regex is invalid. Form does not submit with invalid regex. |
| Status | Not Tested |
SJ-004: Trigger Scrape Job
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Scrape job exists, agent running, repository accessible |
| Steps | 1. Click “Run” on a scrape job 2. Wait for completion |
| Expected Result | Job completes. Version snapshot created. Latest version shown in table. |
| Status | Not Tested |
SJ-005: View Version History
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Scrape job with multiple completed runs |
| Steps | 1. Navigate to /scrape-jobs/:id/versions |
| Expected Result | Shows chronological list of discovered versions with timestamps. Most recent first. |
| Status | Not Tested |
SJ-006: Edit Scrape Job
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Scrape job exists |
| Steps | 1. Click “Edit” 2. Modify repository URL or expression 3. Submit |
| Expected Result | Job updated. Changes reflected in list. |
| Status | Not Tested |
SJ-007: Delete Scrape Job
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Scrape job exists |
| Steps | 1. Click “Delete” 2. Confirm deletion |
| Expected Result | Job removed. Confirmation dialog shown before deletion. |
| Status | Not Tested |
7. Helm Sync Jobs
HS-001: Create Helm Sync Job
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Authenticated, Helm chart repository available |
| Steps | 1. Create a Helm sync job with repository URL 2. Submit |
| Expected Result | Helm sync job created. Appears in list. |
| Status | Not Tested |
HS-002: Trigger Helm Sync
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Helm sync job exists, agent running |
| Steps | 1. Click “Run” on Helm sync job 2. Wait for completion |
| Expected Result | Charts discovered. Child gather jobs created for each chart. |
| Status | Not Tested |
HS-003: Helm Sync - Orphan Cleanup
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | Helm sync job with auto_delete_orphans=true, previously synced charts |
| Steps | 1. Remove a chart from the Helm repo 2. Re-run Helm sync |
| Expected Result | Child gather job for removed chart is deleted. Remaining jobs unaffected. |
| Status | Not Tested |
8. Releases
REL-001: List Releases
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Gather jobs have completed and fetched releases |
| Steps | 1. Navigate to /releases |
| Expected Result | Releases listed with: Artifact, Version, Release Date, Prerelease flag. Default sort by date descending. |
| Status | Not Tested |
REL-002: Filter by Artifact
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Releases from multiple artifacts exist |
| Steps | 1. Select artifact from dropdown filter |
| Expected Result | Only releases for selected artifact shown. |
| Status | Not Tested |
REL-003: Filter by Version Substring
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | Releases exist |
| Steps | 1. Enter version substring (e.g., “1.28”) in version filter |
| Expected Result | Only releases matching the version substring shown. |
| Status | Not Tested |
REL-004: Toggle Prerelease Visibility
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | Both stable and prerelease versions exist |
| Steps | 1. Toggle “Show Prereleases” filter |
| Expected Result | When off: only stable releases shown. When on: all releases shown including alpha/beta/rc. |
| Status | Not Tested |
REL-005: Sort Order Toggle
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | Releases exist |
| Steps | 1. Change sort from “Newest” to “Oldest” |
| Expected Result | Release list reverses order. |
| Status | Not Tested |
REL-006: View Mode - List vs Grouped
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | Releases exist |
| Steps | 1. Switch between “List” and “Grouped” view modes |
| Expected Result | List mode: flat table. Grouped mode: releases grouped by artifact. |
| Status | Not Tested |
REL-007: Releases - Scope Filter
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Org and global releases exist |
| Steps | 1. Toggle scope filter between Org, Global, All |
| Expected Result | Release list updates to match selected scope. |
| Status | Not Tested |
9. Monitoring Rules
RULE-001: List Rules
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Rules exist |
| Steps | 1. Navigate to /rules |
| Expected Result | Table shows rules with: Name, Type, Thresholds, Active Status, Actions. |
| Status | Not Tested |
RULE-002: Create Rule - Days Behind
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Authenticated |
| Steps | 1. Click “Create” 2. Fill: Name, Type = days_behind, thresholds (moderate, high, critical), optional stable_only 3. Submit |
| Expected Result | Rule created. Appears in list with correct type and thresholds. |
| Status | Not Tested |
RULE-003: Create Rule - Majors Behind
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Authenticated |
| Steps | 1. Create rule with Type = majors_behind and appropriate thresholds |
| Expected Result | Rule created with correct type. |
| Status | Not Tested |
RULE-004: Create Rule - Minors Behind
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Authenticated |
| Steps | 1. Create rule with Type = minors_behind and appropriate thresholds |
| Expected Result | Rule created with correct type. |
| Status | Not Tested |
RULE-005: Toggle Rule Active/Inactive (HTMX)
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Active rule exists |
| Steps | 1. Click the active/inactive badge on a rule row |
| Expected Result | Badge toggles without full page reload. HTMX replaces the row fragment. State persists on page refresh. |
| Status | Not Tested |
RULE-006: Edit Rule
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Rule exists |
| Steps | 1. Navigate to rule detail 2. Modify thresholds 3. Submit |
| Expected Result | Rule updated. Changes reflected in detail and list views. |
| Status | Not Tested |
RULE-007: Delete Rule
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Rule exists (preferably one NOT linked to alert configs) |
| Steps | 1. Click “Delete” on rule 2. Confirm |
| Expected Result | Rule removed from list. Confirmation dialog shown. |
| Status | Not Tested |
RULE-008: Trigger Rule Evaluation
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Rules, alert configs, scrape job with version, gather job with releases all configured |
| Steps | 1. Click “Evaluate Rules” button |
| Expected Result | Rules evaluated against current data. Alerts created/updated as appropriate. Success message shown. |
| Status | Not Tested |
RULE-009: Create Rule - Threshold Validation
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | Authenticated |
| Steps | 1. Attempt to create rule with moderate > high or high > critical thresholds |
| Expected Result | Validation error. Thresholds must be moderate <= high <= critical. |
| Status | Not Tested |
10. Alert Configs
AC-001: List Alert Configs
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Alert configs exist |
| Steps | 1. Navigate to /alert-configs |
| Expected Result | Table shows configs with: Name, Scrape Job, Gather Job, Rule, Active Status. |
| Status | Not Tested |
AC-002: Create Alert Config
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | At least one scrape job, one gather job, one rule exist |
| Steps | 1. Click “Create” 2. Select Scrape Job, Gather Job (org or global), Rule from dropdowns 3. Fill name 4. Submit |
| Expected Result | Alert config created. Dropdown options load correctly from API. Triggers async rule evaluation. |
| Status | Not Tested |
AC-003: Edit Alert Config
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Alert config exists |
| Steps | 1. Navigate to alert config detail 2. Modify linked rule or name 3. Submit |
| Expected Result | Config updated. Triggers async rule re-evaluation. |
| Status | Not Tested |
AC-004: Toggle Alert Config Active/Inactive
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Active alert config exists |
| Steps | 1. Click toggle badge on config row |
| Expected Result | Badge toggles via HTMX. Inactive configs skip rule evaluation. |
| Status | Not Tested |
AC-005: Delete Alert Config
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Alert config exists |
| Steps | 1. Click “Delete” 2. Confirm |
| Expected Result | Config removed. Associated alerts resolved (soft-deleted). |
| Status | Not Tested |
11. Alerts
ALT-001: List Alerts
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Alerts have been generated by rule evaluation |
| Steps | 1. Navigate to /alerts |
| Expected Result | Table shows alerts with: Config Name, Severity badge, Discovered Version, Latest Version, Behind By, Acknowledged status, Actions. Summary cards show counts. |
| Status | Not Tested |
ALT-002: Filter Alerts by Severity
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Alerts of different severities exist |
| Steps | 1. Select “Critical” from severity filter 2. Then “High” 3. Then “Moderate” |
| Expected Result | Each filter shows only alerts of that severity. Counts in summary cards update. |
| Status | Not Tested |
ALT-003: Filter Unacknowledged Only
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Both acknowledged and unacknowledged alerts exist |
| Steps | 1. Enable “Unacknowledged only” filter |
| Expected Result | Only unacknowledged alerts shown. |
| Status | Not Tested |
ALT-004: Acknowledge Single Alert (HTMX)
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Unacknowledged alert exists |
| Steps | 1. Click “Acknowledge” button on alert row |
| Expected Result | Alert row updates via HTMX (no full reload). Badge changes to “Acknowledged”. alert.acknowledged event dispatched. |
| Status | Not Tested |
ALT-005: Unacknowledge Alert (HTMX)
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | Acknowledged alert exists |
| Steps | 1. Click “Unacknowledge” on an acknowledged alert row |
| Expected Result | Alert reverts to unacknowledged state. Row updates via HTMX. |
| Status | Not Tested |
ALT-006: Bulk Acknowledge Alerts
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Multiple unacknowledged alerts exist |
| Steps | 1. Select multiple alert checkboxes 2. Click “Acknowledge Selected” |
| Expected Result | All selected alerts acknowledged. Page refreshes showing updated statuses. |
| Status | Not Tested |
ALT-007: Alerts Pagination
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | >50 alerts exist |
| Steps | 1. Verify first page shows correct count 2. Navigate to next page |
| Expected Result | Pagination works. Items don’t repeat across pages. |
| Status | Not Tested |
12. Notification Channels
NC-001: List Notification Channels
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Notification channels exist |
| Steps | 1. Navigate to /notification-channels |
| Expected Result | Table shows channels with: Name, Type badge, URL (truncated), Active badge, Last Test result, Actions. |
| Status | Not Tested |
NC-002: Create Webhook Channel
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Authenticated |
| Steps | 1. Click “Create” 2. Fill: Name, URL (use webhook.site), optional headers, optional HMAC secret 3. Submit |
| Expected Result | Channel created and active. Appears in list. |
| Status | Not Tested |
NC-003: Test Channel Connectivity
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Channel exists with valid webhook URL |
| Steps | 1. Click “Test” on channel 2. Wait for test delivery |
| Expected Result | Success message displayed with HTTP status. Webhook receiver gets test payload. Last test timestamp updated. |
| Status | Not Tested |
NC-004: Test Channel - Failed Delivery
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Channel exists with invalid/unreachable URL |
| Steps | 1. Click “Test” on channel with bad URL |
| Expected Result | Error message displayed with details (HTTP status, error message). User-friendly formatting via formatTestErrorMessage(). |
| Status | Not Tested |
NC-005: Edit Channel
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Channel exists |
| Steps | 1. Navigate to channel detail 2. Modify URL or headers 3. Submit |
| Expected Result | Channel updated. Changes reflected in detail view. |
| Status | Not Tested |
NC-006: Toggle Channel Active/Inactive
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Active channel exists |
| Steps | 1. Click active/inactive badge |
| Expected Result | Badge toggles via HTMX. Inactive channels skip delivery. |
| Status | Not Tested |
NC-007: Delete Channel
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Channel exists |
| Steps | 1. Click “Delete” 2. Confirm |
| Expected Result | Channel removed. Confirmation dialog shown. |
| Status | Not Tested |
NC-008: Create Channel with Custom Headers
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | Authenticated |
| Steps | 1. Create channel with custom headers (e.g., Authorization: Bearer token123) 2. Test the channel |
| Expected Result | Channel created. Test payload includes custom headers (verify at webhook receiver). |
| Status | Not Tested |
NC-009: Create Channel with HMAC Secret
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | Authenticated |
| Steps | 1. Create channel with HMAC signing secret 2. Trigger a notification delivery |
| Expected Result | Webhook payload includes HMAC signature header. Signature is valid against configured secret. |
| Status | Not Tested |
NC-010: SSRF Protection - Private URL Blocked
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | NOTIFICATION_ALLOW_PRIVATE_URLS=false (default) |
| Steps | 1. Create channel with URL pointing to localhost or RFC1918 address (e.g., http://192.168.1.1/webhook) 2. Test the channel |
| Expected Result | Request blocked. Error message indicates private URLs not allowed. |
| Status | Not Tested |
13. Notification Rules
NR-001: List Notification Rules
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Notification rules exist |
| Steps | 1. Navigate to /notification-rules |
| Expected Result | Table shows rules with: Name, Channel, Severity filter, Event filter, Active badge, Actions. |
| Status | Not Tested |
NR-002: Create Notification Rule
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | At least one active notification channel exists |
| Steps | 1. Click “Create” 2. Fill: Name, select Channel, set Severity filters (critical/high/moderate), set Event filters (created/escalated/acknowledged/resolved) 3. Submit |
| Expected Result | Rule created and active. Appears in list. |
| Status | Not Tested |
NR-003: Edit Notification Rule
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Rule exists |
| Steps | 1. Navigate to rule detail 2. Modify severity or event filters 3. Submit |
| Expected Result | Rule updated. Changes reflected in detail view. |
| Status | Not Tested |
NR-004: Toggle Notification Rule
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Active notification rule exists |
| Steps | 1. Click active/inactive badge |
| Expected Result | Badge toggles via HTMX. Inactive rules skip matching. |
| Status | Not Tested |
NR-005: Delete Notification Rule
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Rule exists |
| Steps | 1. Click “Delete” 2. Confirm |
| Expected Result | Rule removed from list. |
| Status | Not Tested |
14. Notification Deliveries
ND-001: List Deliveries
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Notification deliveries exist |
| Steps | 1. Navigate to /notification-deliveries |
| Expected Result | Table shows deliveries with: Alert, Channel, Status badge, Attempts, Created, Actions. |
| Status | Not Tested |
ND-002: Filter Deliveries by Status
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | Deliveries of different statuses exist |
| Steps | 1. Select “Failed” from status filter 2. Then “Succeeded” 3. Then “Dead Letter” |
| Expected Result | Table filters to show only deliveries matching selected status. |
| Status | Not Tested |
ND-003: Retry Dead Letter Delivery
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Dead letter delivery exists, channel URL now reachable |
| Steps | 1. Navigate to dead letter deliveries 2. Click “Retry” on a dead letter 3. Wait for delivery attempt |
| Expected Result | Delivery status changes from dead_letter to pending then processes. If webhook now reachable, succeeds. |
| Status | Not Tested |
15. Notification Settings & Templates
NS-001: View Notification Settings
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Authenticated |
| Steps | 1. Navigate to /notification-settings |
| Expected Result | Page shows global default templates for each category (new_alert, acknowledged, resolved). Shows effective (merged) settings. |
| Status | Not Tested |
NS-002: Edit Notification Template
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Authenticated |
| Steps | 1. Navigate to notification settings 2. Click edit on a template category (e.g., new_alert) 3. Modify template text 4. Save |
| Expected Result | Template updated. Org-level override saved. Used for subsequent deliveries. |
| Status | Not Tested |
NS-003: Reset Template to Default
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | Org-level template override exists |
| Steps | 1. Navigate to template with org override 2. Click “Reset to Default” |
| Expected Result | Org override removed. Template reverts to global default. |
| Status | Not Tested |
NS-004: Template Variable Rendering
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | Template with variables configured |
| Steps | 1. Configure template using variables: {{.Alert.Severity}}, {{.Alert.ConfigName}}, {{.AcknowledgeURL}} 2. Trigger an alert notification 3. Check webhook payload |
| Expected Result | Variables replaced with actual values. No raw {{...}} in payload. |
| Status | Not Tested |
16. API Keys
AK-001: List API Keys
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | API keys exist |
| Steps | 1. Navigate to /api-keys |
| Expected Result | Table shows: Name, Key ID (prefix), Last Used, Expires, Active badge, Actions. Summary cards: Total, Active, Inactive. |
| Status | Not Tested |
AK-002: Create API Key
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Authenticated |
| Steps | 1. Click “Create” 2. Fill: Name, optional Description, optional Expiration date 3. Submit |
| Expected Result | Key created. Plaintext key shown ONCE (format: pk_<id>_<secret>). Warning to store securely displayed. Key never retrievable again. |
| Status | Not Tested |
AK-003: API Key - Plaintext Not Retrievable
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | API key just created |
| Steps | 1. Note the plaintext key 2. Navigate away 3. Return to key detail |
| Expected Result | Only key prefix shown (pk_<id>_...). Full secret NOT displayed. |
| Status | Not Tested |
AK-004: Toggle API Key Active/Inactive
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Active API key exists |
| Steps | 1. Click active/inactive badge on key row |
| Expected Result | Badge toggles via HTMX. Inactive key immediately rejected by auth middleware on subsequent use. |
| Status | Not Tested |
AK-005: Deactivate API Key
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Active API key exists |
| Steps | 1. Navigate to key detail 2. Click “Deactivate” 3. Confirm |
| Expected Result | Key soft-deleted. Cannot be reactivated. Audit trail preserved. |
| Status | Not Tested |
AK-006: Edit API Key
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | API key exists |
| Steps | 1. Navigate to key detail 2. Edit name or description 3. Submit |
| Expected Result | Metadata updated. Key itself unchanged. |
| Status | Not Tested |
AK-007: API Key Expiration Enforcement
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | API key with past expiration |
| Steps | 1. Attempt API call with expired key (via curl or agent config) |
| Expected Result | Request rejected with 401. Key shows as expired in UI. |
| Status | Not Tested |
17. Agents
AGT-001: List Agents
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | At least one agent has sent a heartbeat |
| Steps | 1. Navigate to /agents |
| Expected Result | Table shows agents with: UUID, Hostname, Health badge, Last Heartbeat, Version, Capabilities. |
| Status | Not Tested |
AGT-002: Agent Health Status
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Agent is running and sending heartbeats |
| Steps | 1. View agent in list 2. Stop the agent 3. Wait >2 minutes 4. Refresh page |
| Expected Result | Step 2: Health badge shows “Healthy”. Step 4: Health badge changes to “Unhealthy” or “Unknown”. |
| Status | Not Tested |
AGT-003: View Agent Submission Logs
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | Agent has submitted task results |
| Steps | 1. Click on agent to expand submission logs (HTMX) |
| Expected Result | Logs show recent task submissions with success/failure status and timestamps. |
| Status | Not Tested |
18. Settings
SET-001: View Settings
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Authenticated |
| Steps | 1. Navigate to /settings |
| Expected Result | Shows settings list with effective values (global defaults + org overrides). Indicates which are org-overridden. |
| Status | Not Tested |
SET-002: Edit Organization Setting Override
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Authenticated |
| Steps | 1. Click “Edit” on a setting (HTMX inline edit) 2. Change value 3. Save |
| Expected Result | Org override saved. Setting shows new effective value. Edit form replaces with view mode via HTMX. |
| Status | Not Tested |
SET-003: Clear Organization Setting Override
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | Org override exists on a setting |
| Steps | 1. Click “Clear Override” on a setting 2. Confirm |
| Expected Result | Org override removed. Setting reverts to global default value. |
| Status | Not Tested |
19. Health Check
HC-001: Health Endpoint Accessible
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Server running |
| Steps | 1. curl http://localhost:3000/health |
| Expected Result | Returns 200 with {"status":"healthy"} (or similar). No auth required. |
| Status | Not Tested |
HC-002: Health Endpoint - Database Down
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Server running, database stopped |
| Steps | 1. Stop PostgreSQL container 2. curl http://localhost:3000/health |
| Expected Result | Returns unhealthy status with database connectivity error. |
| Status | Not Tested |
20. Cross-Feature Workflows
These tests validate the end-to-end integration between multiple features.
E2E-001: Full Alert Lifecycle
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Clean environment with no existing alerts |
| Steps | 1. Create a gather job for a GitHub repo with many releases 2. Run the gather job → wait for completion 3. Create a scrape job for a repo with an older version 4. Run the scrape job → wait for completion 5. Create a days_behind rule with low thresholds 6. Create an alert config linking the scrape job, gather job, and rule 7. Verify alert is created on /alerts page 8. Check alert severity matches expected threshold 9. Acknowledge the alert 10. Update the scraped repo to latest version 11. Re-run the scrape job 12. Verify alert is resolved |
| Expected Result | Full lifecycle: Creation → Severity assignment → Acknowledgment → Resolution. Each state visible in UI. |
| Status | Not Tested |
E2E-002: Full Notification Lifecycle
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Working webhook receiver (webhook.site) |
| Steps | 1. Create a notification channel (webhook to webhook.site) 2. Test the channel → verify success 3. Create a notification rule routing critical alerts to the channel 4. Trigger an alert (via E2E-001 steps or rule evaluation) 5. Check /notification-deliveries for delivery attempt 6. Verify webhook receiver got the payload 7. Check payload contains correct alert data and acknowledge URL 8. Call acknowledge URL from webhook payload 9. Verify alert acknowledged in /alerts |
| Expected Result | End-to-end: Alert → Notification Rule Match → Delivery → Webhook Received → External Acknowledgment |
| Status | Not Tested |
E2E-003: Smart Acknowledgment Reset
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Alert config with active alert |
| Steps | 1. Acknowledge an existing alert 2. Re-run the scrape job (same version discovered) 3. Trigger rule evaluation 4. Verify alert stays acknowledged 5. Change the scrape target to discover a DIFFERENT version 6. Re-run the scrape job 7. Trigger rule evaluation 8. Verify alert acknowledgment is RESET |
| Expected Result | Step 4: is_acknowledged remains TRUE (same version). Step 8: is_acknowledged reset to FALSE (different version). |
| Status | Not Tested |
E2E-004: Alert Escalation
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Alert config with active moderate-severity alert |
| Steps | 1. Start with a moderate alert (version slightly behind) 2. Wait for more releases to be gathered (or add releases to make version further behind) 3. Trigger rule evaluation 4. Verify alert severity escalates to high or critical 5. Check that alert.escalated event is dispatched |
| Expected Result | Alert severity increases. Escalation event triggers notification if rules match. |
| Status | Not Tested |
E2E-005: Job Failure and Recovery
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Agent running |
| Steps | 1. Create a gather job with an invalid repository (e.g., nonexistent/repo) 2. Run the job 3. Verify job fails 4. Update the job with a valid repository 5. Run again 6. Verify job completes successfully |
| Expected Result | Step 3: Job status = failed. Step 6: Job status = completed, releases populated. |
| Status | Not Tested |
E2E-006: Orphan Job Recovery
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Job in in_progress state |
| Steps | 1. Trigger a job 2. Kill the agent while job is in_progress 3. Wait >1 hour (or adjust timeout for testing) 4. Verify job status resets to pending 5. Restart agent 6. Verify job is picked up and completes |
| Expected Result | Stale job detection resets orphaned jobs. Agent picks them up on restart. |
| Status | Not Tested |
E2E-007: Multi-Tenant Data Isolation
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Two organizations with separate data |
| Steps | 1. Login as Org A user 2. Create jobs, rules, alerts in Org A 3. Switch to Org B (or login as Org B user) 4. Verify Org A’s data is NOT visible 5. Create data in Org B 6. Switch back to Org A 7. Verify Org B’s data is NOT visible |
| Expected Result | Complete data isolation between organizations. No cross-tenant data leakage. |
| Status | Not Tested |
E2E-008: Stable-Only Rule Filtering
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | Gather job with both stable and prerelease versions |
| Steps | 1. Create rule with stable_only = true 2. Create alert config 3. Trigger evaluation 4. Verify prerelease versions (alpha, beta, rc) are excluded from comparison 5. Create same rule with stable_only = false 6. Verify prereleases are included |
| Expected Result | With stable_only: comparison uses only stable releases. Without: all releases considered. |
| Status | Not Tested |
E2E-009: Notification Retry and Dead Letter
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Channel with unreachable URL |
| Steps | 1. Create channel with intentionally broken URL 2. Create notification rule 3. Trigger alert (creates delivery) 4. Watch delivery status over time: pending → failed → retry → dead_letter 5. Fix the channel URL 6. Retry the dead letter delivery 7. Verify delivery succeeds |
| Expected Result | Retry backoff observed. After max retries, delivery enters dead_letter. Manual retry succeeds after URL fix. |
| Status | Not Tested |
E2E-010: Cron-Scheduled Job Execution
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Agent running |
| Steps | 1. Create gather job with cron schedule (e.g., */2 * * * * for every 2 minutes) 2. Trigger initial run 3. Wait for cron activation 4. Verify job runs again automatically |
| Expected Result | Job automatically re-enters pending at scheduled time. Agent picks up and executes. |
| Status | Not Tested |
21. Security
SEC-001: Unauthenticated Access Blocked
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | No active session |
| Steps | 1. Clear all cookies 2. Attempt to access /dashboard, /jobs, /alerts, /api-keys directly |
| Expected Result | All protected routes redirect to /login. No data leakage. |
| Status | Not Tested |
SEC-002: API Key Not Logged in Plaintext
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Access to server logs |
| Steps | 1. Create an API key 2. Use it in API calls 3. Search server logs for the plaintext secret |
| Expected Result | Plaintext API key secret never appears in logs. Only key ID/prefix logged. |
| Status | Not Tested |
SEC-003: API Key Argon2id Storage
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Database access |
| Steps | 1. Create an API key 2. Query api_keys table directly 3. Check key_hash column |
| Expected Result | Key stored as Argon2id hash. Raw secret not in any database column. |
| Status | Not Tested |
SEC-004: Cross-Organization API Access
| Field | Value |
|---|---|
| Priority | P0 |
| Preconditions | Two organizations, API keys for each |
| Steps | 1. Use Org A’s API key 2. Attempt to access Org B’s resources via API (modify X-Organization-Id header) |
| Expected Result | Request rejected or returns only Org A’s data. No cross-tenant access. |
| Status | Not Tested |
SEC-005: Session Cookie Security
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | HTTPS enabled |
| Steps | 1. Login and inspect planekeeper_session cookie in browser dev tools |
| Expected Result | Cookie has: HttpOnly, Secure (when AUTH_COOKIE_SECURE=true), SameSite=Lax. Cookie value is encrypted (AES-GCM), not readable base64 JWT. |
| Status | Not Tested |
SEC-006: Rate Limiting
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | Server running with rate limiting enabled |
| Steps | 1. Send >100 API requests within 60 seconds (or configured limits) |
| Expected Result | After limit exceeded, server returns 429 Too Many Requests. Requests resume after window resets. |
| Status | Not Tested |
SEC-007: SSRF Protection on Webhooks
| Field | Value |
|---|---|
| Priority | P1 |
| Preconditions | NOTIFICATION_ALLOW_PRIVATE_URLS=false |
| Steps | 1. Create channel with http://127.0.0.1:8080/hook 2. Create channel with http://10.0.0.1/hook 3. Create channel with http://192.168.1.1/hook 4. Test each channel |
| Expected Result | All blocked with appropriate error message. No requests sent to private addresses. |
| Status | Not Tested |
SEC-008: Webhook HMAC Signature Validation
| Field | Value |
|---|---|
| Priority | P2 |
| Preconditions | Channel configured with HMAC secret |
| Steps | 1. Configure channel with known HMAC secret 2. Trigger delivery 3. Capture webhook request at receiver 4. Validate HMAC signature header against payload using the secret |
| Expected Result | HMAC signature present in headers. Signature validates correctly. |
| Status | Not Tested |
22. Release Checklist
Use this checklist before each release. Tests marked P0 are blockers.
Pre-Release Smoke Test (All P0 Tests)
- AUTH-001: Email/Password Login
- AUTH-002: Invalid Credentials Rejected
- AUTH-006: Logout
- AUTH-008: API Key Login (Internal UI)
- AUTH-009: Invalid API Key Rejected
- DASH-001: Dashboard Loads
- GJ-001: List Gather Jobs
- GJ-002: Create Gather Job
- GJ-005: Trigger Gather Job
- SJ-001: List Scrape Jobs
- SJ-002: Create Scrape Job
- SJ-004: Trigger Scrape Job
- REL-001: List Releases
- RULE-001: List Rules
- RULE-002: Create Rule
- AC-001: List Alert Configs
- AC-002: Create Alert Config
- ALT-001: List Alerts
- ALT-004: Acknowledge Alert
- NC-001: List Notification Channels
- NC-002: Create Webhook Channel
- NC-003: Test Channel
- NR-001: List Notification Rules
- NR-002: Create Notification Rule
- AK-001: List API Keys
- AK-002: Create API Key
- AK-003: Plaintext Not Retrievable
- AGT-001: List Agents
- HC-001: Health Endpoint
- E2E-001: Full Alert Lifecycle
- E2E-002: Full Notification Lifecycle
- E2E-007: Multi-Tenant Data Isolation
- SEC-001: Unauthenticated Access Blocked
- SEC-002: API Key Not Logged
- SEC-003: API Key Argon2id Storage
- SEC-004: Cross-Org Access Blocked
Full Regression (All P0 + P1 Tests)
Run all P0 tests above plus:
- AUTH-003: Signup
- AUTH-004: Pending Approval
- AUTH-005: OAuth Login
- AUTH-007: Session Expiry
- AUTH-010: Expired Key Rejected
- AUTH-011: Inactive Key Rejected
- ONB-001: Create Organization
- ONB-002: Accept Invite
- ONB-003: Org Switching
- DASH-002: Scope Filter - Org
- DASH-003: Scope Filter - Global
- DASH-004: Scope Filter - All
- GJ-004: Edit Gather Job
- GJ-006: Delete Gather Job
- GJ-010: Scope Filter
- SJ-005: Version History
- SJ-006: Edit Scrape Job
- SJ-007: Delete Scrape Job
- HS-001: Create Helm Sync
- HS-002: Trigger Helm Sync
- REL-002: Filter by Artifact
- REL-007: Scope Filter
- RULE-005: Toggle Rule
- RULE-006: Edit Rule
- RULE-007: Delete Rule
- RULE-008: Trigger Evaluation
- AC-003: Edit Alert Config
- AC-004: Toggle Alert Config
- AC-005: Delete Alert Config
- ALT-002: Filter by Severity
- ALT-003: Filter Unacknowledged
- ALT-006: Bulk Acknowledge
- NC-004: Test Channel - Failed
- NC-005: Edit Channel
- NC-006: Toggle Channel
- NC-007: Delete Channel
- NC-010: SSRF Protection
- NR-003: Edit Notification Rule
- NR-004: Toggle Notification Rule
- NR-005: Delete Notification Rule
- ND-001: List Deliveries
- ND-003: Retry Dead Letter
- NS-001: View Settings
- NS-002: Edit Template
- AK-004: Toggle API Key
- AK-005: Deactivate Key
- AK-007: Key Expiration
- AGT-002: Agent Health Status
- SET-001: View Settings
- SET-002: Edit Setting Override
- HC-002: Health - DB Down
- E2E-003: Smart Ack Reset
- E2E-004: Alert Escalation
- E2E-005: Job Failure Recovery
- E2E-006: Orphan Recovery
- E2E-009: Notification Retry
- E2E-010: Cron Scheduling
- SEC-005: Cookie Security
- SEC-006: Rate Limiting
- SEC-007: SSRF Protection