chore: clean .gitignore cache

This commit is contained in:
GitHub Actions
2026-01-26 19:21:33 +00:00
parent 1b1b3a70b1
commit e5f0fec5db
1483 changed files with 0 additions and 472793 deletions

View File

@@ -1 +0,0 @@
# Processed issue files are moved here after GitHub Issues are created

View File

@@ -1,59 +0,0 @@
Tasks
Repository: Wikid82/Charon
Branch: feature/beta-release
Purpose
-------
Create a tracked issue and sub-tasks to validate ACL-related changes introduced on the `feature/beta-release` branch. This file records the scope, test steps, and sub-issues so we can open a GitHub issue later or link this file in the issue body.
Top-level checklist
- [ ] Open GitHub Issue "ACL: Test and validate ACL changes (feature/beta-release)" and link this file
- [ ] Assign owner and target date
Sub-tasks (suggested GitHub issue checklist items)
1) Unit & Service Tests
- [ ] Add/verify unit tests for `internal/services/access_list_service.go` CRUD + validation
- [ ] Add tests for `internal/api/handlers/access_list_handler.go` endpoints (create/list/get/update/delete)
- Acceptance: all handler tests pass and coverage for `internal/api/handlers` rises by at least 3%.
2) Integration Tests
- [ ] Test ACL interactions with proxy hosts: ensure blocked/allowed behavior when ACLs applied to hosts
- [ ] Test ACL import via Caddy import workflow (multi-site) — ensure imported ACLs attach correctly
- Acceptance: end-to-end requests are blocked/allowed per ACL rules in an integration harness.
3) UI & API Validation
- [ ] Validate frontend UI toggles for ACL enable/disable reflect DB state
- [ ] Verify API endpoints that toggle ACL mode return correct status and persist in `settings`
- Acceptance: toggles update DB and the UI shows consistent state after refresh.
4) Security & Edge Cases
- [ ] Test denied webhook payloads / WAF interactions when ACLs are present
- [ ] Confirm rate-limit and CrowdSec interactions do not conflict with ACL rules
- Acceptance: no regressions found; documented edge cases.
5) Documentation & Release Notes
- [ ] Update `docs/features.md` with any behavior changes
- [ ] Add a short note in release notes describing ACL test coverage and migration steps
Manual Test Steps (quick guide)
- Set up local environment:
1. `cd backend && go run ./cmd/api` (or use docker compose)
2. Run frontend dev server: `cd frontend && npm run dev`
- Create an ACL via API or UI; attach it to a Proxy Host; verify request behavior.
- Import Caddyfiles (single & multi-site) with ACL directives and validate mapping.
Issue metadata (suggested)
- Title: ACL: Test and validate ACL changes (feature/beta-release)
- Labels: testing, needs-triage, acl, regression
- Assignees: @<owner-placeholder>
- Milestone: to be set
Notes
- Keep this file as the canonical checklist and paste into the GitHub issue body when opening the issue.

View File

@@ -1,50 +0,0 @@
### Additional Security Threats to Consider
**1. Supply Chain Attacks**
- **Threat:** Compromised Docker images, npm packages, Go modules
- **Current Protection:** ❌ None
- **Recommendation:** Add Trivy scanning (already in CI) + SBOM generation
**2. DNS Hijacking / Cache Poisoning**
- **Threat:** Attacker redirects DNS queries to malicious servers
- **Current Protection:** ❌ None (relies on system DNS resolver)
- **Recommendation:** Document use of encrypted DNS (DoH/DoT) in deployment guide
**3. TLS Downgrade Attacks**
- **Threat:** Force clients to use weak TLS versions
- **Current Protection:** ✅ Caddy enforces TLS 1.2+ by default
- **Recommendation:** Document minimum TLS version in security.md
**4. Certificate Transparency (CT) Log Poisoning**
- **Threat:** Attacker registers fraudulent certs for your domains
- **Current Protection:** ❌ None
- **Recommendation:** Add CT log monitoring (future feature)
**5. Privilege Escalation (Container Escape)**
- **Threat:** Attacker escapes Docker container to host OS
- **Current Protection:** ⚠️ Partial (Docker security best practices)
- **Recommendation:** Document running with least-privilege, read-only root filesystem
**6. Session Hijacking / Cookie Theft**
- **Threat:** Steal user session tokens via XSS or network sniffing
- **Current Protection:** ✅ HTTPOnly cookies, Secure flag, SameSite (verify implementation)
- **Recommendation:** Add CSP (Content Security Policy) headers
**7. Timing Attacks (Cryptographic Side-Channel)**
- **Threat:** Infer secrets by measuring response times
- **Current Protection:** ❌ Unknown (need bcrypt timing audit)
- **Recommendation:** Use constant-time comparison for tokens
**Enterprise-Level Security Gaps:**
- **Missing:** Security Incident Response Plan (SIRP)
- **Missing:** Automated security update notifications
- **Missing:** Multi-factor authentication (MFA) for admin accounts (Use Authentik via built in. No extra external containers. Consider adding SSO as well just for Charon. These are not meant to pass auth to Proxy Hosts. Charon is a reverse proxy, not a secure dashboard.)
- **Missing:** Audit logging for compliance (GDPR, SOC 2)

View File

@@ -1,261 +0,0 @@
# Sub-Issues for Bulk ACL Testing
## Parent Issue
[Link to main testing issue]
---
## Sub-Issue #1: Basic Functionality Testing
**Title**: `[Bulk ACL Testing] Basic Functionality - Selection and Application`
**Labels**: `testing`, `manual-testing`, `bulk-acl`
**Description**:
Test the core functionality of the bulk ACL feature - selecting hosts and applying access lists.
**Test Checklist:**
- [ ] Navigate to Proxy Hosts page
- [ ] Verify checkbox column appears in table
- [ ] Select individual hosts using checkboxes
- [ ] Verify "Select All" checkbox works correctly
- [ ] Confirm selection count displays accurately
- [ ] Click "Bulk Actions" button - modal should appear
- [ ] Select an ACL from dropdown - hosts should update
- [ ] Verify toast notification shows success message
- [ ] Confirm hosts table refreshes with updated ACL assignments
- [ ] Check database to verify `access_list_id` fields updated
**Expected Results:**
- All checkboxes functional
- Selection count accurate
- Modal displays correctly
- ACL applies to all selected hosts
- Database reflects changes
**Test Environment:** Local development
---
## Sub-Issue #2: ACL Removal Testing
**Title**: `[Bulk ACL Testing] ACL Removal Functionality`
**Labels**: `testing`, `manual-testing`, `bulk-acl`
**Description**:
Test the ability to remove access lists from multiple hosts simultaneously.
**Test Checklist:**
- [ ] Select hosts that have ACLs assigned
- [ ] Open Bulk Actions modal
- [ ] Select "🚫 Remove Access List" option
- [ ] Confirm removal dialog appears
- [ ] Proceed with removal
- [ ] Verify toast shows "Access list removed from X host(s)"
- [ ] Confirm hosts no longer have ACL assigned in UI
- [ ] Check database to verify `access_list_id` is NULL
**Expected Results:**
- Removal option clearly visible
- Confirmation dialog prevents accidental removal
- All selected hosts have ACL removed
- Database updated correctly (NULL values)
**Test Environment:** Local development
---
## Sub-Issue #3: Error Handling Testing
**Title**: `[Bulk ACL Testing] Error Handling and Edge Cases`
**Labels**: `testing`, `manual-testing`, `bulk-acl`, `error-handling`
**Description**:
Test error scenarios and edge cases to ensure graceful degradation.
**Test Checklist:**
- [ ] Select multiple hosts including one that doesn't exist
- [ ] Apply ACL via bulk action
- [ ] Verify toast shows partial success: "Updated X host(s), Y failed"
- [ ] Confirm successful hosts were updated
- [ ] Test with no hosts selected (button should not appear)
- [ ] Test with empty ACL list (dropdown should show appropriate message)
- [ ] Disconnect backend - verify network error handling
- [ ] Test applying invalid ACL ID (edge case)
**Expected Results:**
- Partial failures handled gracefully
- Clear error messages displayed
- No data corruption on partial failures
- Network errors caught and reported
**Test Environment:** Local development + simulated failures
---
## Sub-Issue #4: UI/UX Testing
**Title**: `[Bulk ACL Testing] UI/UX and Usability`
**Labels**: `testing`, `manual-testing`, `bulk-acl`, `ui-ux`
**Description**:
Test the user interface and experience aspects of the bulk ACL feature.
**Test Checklist:**
- [ ] Verify checkboxes align properly in table
- [ ] Test checkbox hover states
- [ ] Verify "Bulk Actions" button appears/disappears based on selection
- [ ] Test modal appearance and dismissal (click outside, ESC key)
- [ ] Verify dropdown styling and readability
- [ ] Test loading state (`isBulkUpdating`) - button should show "Updating..."
- [ ] Verify selection persists during table sorting
- [ ] Test selection persistence during table filtering (if applicable)
- [ ] Verify toast notifications don't overlap
- [ ] Test on mobile viewport (responsive design)
**Expected Results:**
- Clean, professional UI
- Intuitive user flow
- Proper loading states
- Mobile-friendly
- Accessible (keyboard navigation)
**Test Environment:** Local development (multiple screen sizes)
---
## Sub-Issue #5: Integration Testing
**Title**: `[Bulk ACL Testing] Integration and Performance`
**Labels**: `testing`, `manual-testing`, `bulk-acl`, `integration`, `performance`
**Description**:
Test the feature in realistic scenarios and with varying data loads.
**Test Checklist:**
- [ ] Create new ACL, immediately apply to multiple hosts
- [ ] Verify Caddy config reloads once (not per host)
- [ ] Test with 1 host selected
- [ ] Test with 10+ hosts selected (performance)
- [ ] Test with 50+ hosts selected (edge case)
- [ ] Apply ACL, then immediately remove it (rapid operations)
- [ ] Apply different ACLs sequentially to same host group
- [ ] Delete a host that's selected, then bulk apply ACL
- [ ] Disable an ACL, verify it doesn't appear in dropdown
- [ ] Test concurrent user scenarios (multi-tab if possible)
**Expected Results:**
- Single Caddy reload per bulk operation
- Performance acceptable up to 50+ hosts
- No race conditions with rapid operations
- Graceful handling of deleted/disabled entities
**Test Environment:** Docker production build
---
## Sub-Issue #6: Cross-Browser Testing
**Title**: `[Bulk ACL Testing] Cross-Browser Compatibility`
**Labels**: `testing`, `manual-testing`, `bulk-acl`, `cross-browser`
**Description**:
Verify the feature works across all major browsers and devices.
**Test Checklist:**
- [ ] Chrome/Chromium (latest)
- [ ] Firefox (latest)
- [ ] Safari (macOS/iOS)
- [ ] Edge (latest)
- [ ] Mobile Chrome (Android)
- [ ] Mobile Safari (iOS)
**Expected Results:**
- Feature works identically across all browsers
- No CSS layout issues
- No JavaScript errors in console
- Touch interactions work on mobile
**Test Environment:** Multiple browsers/devices
---
## Sub-Issue #7: Regression Testing
**Title**: `[Bulk ACL Testing] Regression Testing - Existing Features`
**Labels**: `testing`, `manual-testing`, `bulk-acl`, `regression`
**Description**:
Ensure the new bulk ACL feature doesn't break existing functionality.
**Test Checklist:**
- [ ] Verify individual proxy host edit still works
- [ ] Confirm single-host ACL assignment unchanged
- [ ] Test proxy host creation with ACL pre-selected
- [ ] Verify ACL deletion prevents assignment
- [ ] Confirm existing ACL features unaffected:
- [ ] IP-based rules
- [ ] Geo-blocking rules
- [ ] Local network only rules
- [ ] Test IP functionality
- [ ] Verify certificate assignment still works
- [ ] Test proxy host enable/disable toggle
**Expected Results:**
- Zero regressions
- All existing features work as before
- No performance degradation
- No new bugs introduced
**Test Environment:** Docker production build
---
## Creating Sub-Issues on GitHub
For each sub-issue above:
1. Go to the repository's Issues tab
2. Click "New Issue"
3. Copy the content from the relevant section
4. Add to the parent issue description: "Part of #[parent-issue-number]"
5. Assign appropriate labels
6. Set milestone to `v0.2.0-beta.2`
7. Assign to tester if known
## Testing Progress Tracking
Update the parent issue with:
```markdown
## Sub-Issues Progress
- [ ] #XXX - Basic Functionality Testing
- [ ] #XXX - ACL Removal Testing
- [ ] #XXX - Error Handling Testing
- [ ] #XXX - UI/UX Testing
- [ ] #XXX - Integration Testing
- [ ] #XXX - Cross-Browser Testing
- [ ] #XXX - Regression Testing
```

View File

@@ -1,223 +0,0 @@
# Issue: Test Bulk ACL Application Feature
**Labels**: `testing`, `enhancement`, `needs-testing`
**Milestone**: v0.2.0-beta.2
**Priority**: High
## Description
Comprehensive testing required for the newly implemented Bulk ACL (Access Control List) application feature. This feature allows users to apply or remove access lists from multiple proxy hosts simultaneously, replacing the previous manual per-host workflow.
## Feature Overview
**Implementation PR**: [Link to PR]
The bulk ACL feature introduces:
- Multi-select checkboxes in Proxy Hosts table
- Bulk Actions button with ACL selection modal
- Backend endpoint: `PUT /api/v1/proxy-hosts/bulk-update-acl`
- Comprehensive error handling for partial failures
## Testing Scope
### Backend Testing ✅ (Completed)
- [x] Unit tests for `BulkUpdateACL` handler (5 tests)
- [x] Success scenario: Apply ACL to multiple hosts
- [x] Success scenario: Remove ACL (null value)
- [x] Error handling: Partial failures (some hosts fail)
- [x] Validation: Empty UUIDs array
- [x] Validation: Invalid JSON payload
- **Coverage**: 82.2% maintained
### Frontend Testing ✅ (Completed)
- [x] Unit tests for `bulkUpdateACL` API client (5 tests)
- [x] Unit tests for `useBulkUpdateACL` hook (5 tests)
- [x] Build verification (TypeScript compilation)
- **Coverage**: 86.06% (improved from 85.57%)
### Manual Testing 🔴 (Required)
#### Sub-Issue #1: Basic Functionality Testing
**Checklist:**
- [ ] Navigate to Proxy Hosts page
- [ ] Verify checkbox column appears in table
- [ ] Select individual hosts using checkboxes
- [ ] Verify "Select All" checkbox works correctly
- [ ] Confirm selection count displays accurately
- [ ] Click "Bulk Actions" button - modal should appear
- [ ] Select an ACL from dropdown - hosts should update
- [ ] Verify toast notification shows success message
- [ ] Confirm hosts table refreshes with updated ACL assignments
- [ ] Check database to verify `access_list_id` fields updated
#### Sub-Issue #2: ACL Removal Testing
**Checklist:**
- [ ] Select hosts that have ACLs assigned
- [ ] Open Bulk Actions modal
- [ ] Select "🚫 Remove Access List" option
- [ ] Confirm removal dialog appears
- [ ] Proceed with removal
- [ ] Verify toast shows "Access list removed from X host(s)"
- [ ] Confirm hosts no longer have ACL assigned in UI
- [ ] Check database to verify `access_list_id` is NULL
#### Sub-Issue #3: Error Handling Testing
**Checklist:**
- [ ] Select multiple hosts including one that doesn't exist
- [ ] Apply ACL via bulk action
- [ ] Verify toast shows partial success: "Updated X host(s), Y failed"
- [ ] Confirm successful hosts were updated
- [ ] Test with no hosts selected (button should not appear)
- [ ] Test with empty ACL list (dropdown should show appropriate message)
- [ ] Disconnect backend - verify network error handling
- [ ] Test applying invalid ACL ID (edge case)
#### Sub-Issue #4: UI/UX Testing
**Checklist:**
- [ ] Verify checkboxes align properly in table
- [ ] Test checkbox hover states
- [ ] Verify "Bulk Actions" button appears/disappears based on selection
- [ ] Test modal appearance and dismissal (click outside, ESC key)
- [ ] Verify dropdown styling and readability
- [ ] Test loading state (`isBulkUpdating`) - button should show "Updating..."
- [ ] Verify selection persists during table sorting
- [ ] Test selection persistence during table filtering (if applicable)
- [ ] Verify toast notifications don't overlap
- [ ] Test on mobile viewport (responsive design)
#### Sub-Issue #5: Integration Testing
**Checklist:**
- [ ] Create new ACL, immediately apply to multiple hosts
- [ ] Verify Caddy config reloads once (not per host)
- [ ] Test with 1 host selected
- [ ] Test with 10+ hosts selected (performance)
- [ ] Test with 50+ hosts selected (edge case)
- [ ] Apply ACL, then immediately remove it (rapid operations)
- [ ] Apply different ACLs sequentially to same host group
- [ ] Delete a host that's selected, then bulk apply ACL
- [ ] Disable an ACL, verify it doesn't appear in dropdown
- [ ] Test concurrent user scenarios (multi-tab if possible)
#### Sub-Issue #6: Cross-Browser Testing
**Checklist:**
- [ ] Chrome/Chromium (latest)
- [ ] Firefox (latest)
- [ ] Safari (macOS/iOS)
- [ ] Edge (latest)
- [ ] Mobile Chrome (Android)
- [ ] Mobile Safari (iOS)
#### Sub-Issue #7: Regression Testing
**Checklist:**
- [ ] Verify individual proxy host edit still works
- [ ] Confirm single-host ACL assignment unchanged
- [ ] Test proxy host creation with ACL pre-selected
- [ ] Verify ACL deletion prevents assignment
- [ ] Confirm existing ACL features unaffected:
- [ ] IP-based rules
- [ ] Geo-blocking rules
- [ ] Local network only rules
- [ ] Test IP functionality
- [ ] Verify certificate assignment still works
- [ ] Test proxy host enable/disable toggle
## Test Environments
1. **Local Development**
- Docker: `docker-compose.local.yml`
- Backend: `http://localhost:8080`
- Frontend: `http://localhost:5173`
2. **Docker Production Build**
- Docker: `docker-compose.yml`
- Full stack: `http://localhost:80`
3. **VPS/Staging** (if available)
- Remote environment testing
- Real SSL certificates
- Multiple concurrent users
## Success Criteria
- ✅ All manual test checklists completed
- ✅ No critical bugs found
- ✅ Performance acceptable with 50+ hosts
- ✅ UI/UX meets design standards
- ✅ Cross-browser compatibility confirmed
- ✅ No regressions in existing features
- ✅ Documentation updated (if needed)
## Known Limitations
1. Selection state resets on page navigation
2. No "Select hosts without ACL" filter (potential enhancement)
3. No bulk operations from Access Lists page (future feature)
4. Maximum practical limit untested (100+ hosts)
## Related Files
**Backend:**
- `backend/internal/api/handlers/proxy_host_handler.go`
- `backend/internal/api/handlers/proxy_host_handler_test.go`
**Frontend:**
- `frontend/src/pages/ProxyHosts.tsx`
- `frontend/src/api/proxyHosts.ts`
- `frontend/src/hooks/useProxyHosts.ts`
- `frontend/src/api/__tests__/proxyHosts-bulk.test.ts`
- `frontend/src/hooks/__tests__/useProxyHosts-bulk.test.tsx`
**Documentation:**
- `BULK_ACL_FEATURE.md`
## Testing Timeline
**Suggested Schedule:**
- Day 1: Sub-issues #1-3 (Basic + Error Handling)
- Day 2: Sub-issues #4-5 (UI/UX + Integration)
- Day 3: Sub-issues #6-7 (Cross-browser + Regression)
## Reporting Issues
When bugs are found:
1. Create a new bug report with `[Bulk ACL]` prefix
2. Reference this testing issue
3. Include screenshots/videos
4. Provide reproduction steps
5. Tag with `bug`, `bulk-acl` labels
## Notes
- Feature has 100% backend test coverage for new code
- Feature has 100% frontend test coverage for new code
- Performance testing with large datasets (100+ hosts) recommended
- Consider adding E2E tests with Playwright/Cypress in future
---
**Implementation Date**: November 27, 2025
**Developer**: @copilot
**Reviewer**: TBD
**Tester**: TBD

View File

@@ -1,185 +0,0 @@
# Hecate: Tunnel & Pathway Manager
## 1. Overview
**Hecate** is the internal module within Charon responsible for managing third-party tunneling services. It serves as the "Goddess of Pathways," allowing Charon to route traffic not just to local ports, but through encrypted tunnels to remote networks without exposing ports on the public internet.
## 2. Architecture
Hecate is not a separate binary; it is a **Go package** (`internal/hecate`) running within the main Charon daemon.
### 2.1 The Provider Interface
To support multiple services (Tailscale, Cloudflare, Netbird), Hecate uses a strict Interface pattern.
```go
type TunnelProvider interface {
// Name returns the unique ID of the provider (e.g., "tailscale-01")
Name() string
// Status returns the current health (Connected, Connecting, Error)
Status() TunnelState
// Start initiates the tunnel daemon
Start(ctx context.Context) error
// Stop gracefully terminates the connection
Stop() error
// GetAddress returns the internal IP/DNS routed through the tunnel
GetAddress() string
}
```
### 2.2 Supported Integrations (Phase 1)
#### Cloudflare Tunnels (cloudflared)
- **Mechanism**: Charon manages the `cloudflared` binary via `os/exec`.
- **Config**: User provides the Token via the UI.
- **Outcome**: Exposes Charon directly to the edge without opening port 80/443 on the router.
#### Tailscale / Headscale
- **Mechanism**: Uses `tsnet` (Tailscale's Go library) to embed the node directly into Charon, OR manages the `tailscaled` socket.
- **Outcome**: Charon becomes a node on the Mesh VPN.
## 3. Dashboard Implementation (Unified UI)
**Hecate does NOT have a separate "Tunnels" tab.**
Instead, it is fully integrated into the **Remote Servers** dashboard to provide a unified experience for managing connectivity.
### 3.1 "Add Server" Workflow
When a user clicks "Add Server" in the dashboard, they are presented with a **Connection Type** dropdown that determines how Charon reaches the target.
#### Connection Types
1. **Direct / Manual (Existing)**
- **Use Case**: The server is on the same LAN or reachable via a static IP/DNS.
- **Fields**: `Host`, `Port`, `TLS Toggle`.
- **Backend**: Standard TCP dialer.
2. **Orthrus Agent (New)**
- **Use Case**: The server is behind a NAT/Firewall and cannot accept inbound connections.
- **Workflow**:
- User selects "Orthrus Agent".
- Charon generates a unique `AUTH_KEY`.
- UI displays a `docker-compose.yml` snippet pre-filled with the key and `CHARON_LINK`.
- User deploys the agent on the remote host.
- Hecate waits for the incoming WebSocket connection.
3. **Cloudflare Tunnel (Future)**
- **Use Case**: Exposing a service via Cloudflare's edge network.
- **Fields**: `Tunnel Token`.
- **Backend**: Hecate spawns/manages the `cloudflared` process.
### 3.2 Hecate's Role
Hecate acts as the invisible backend engine for these non-direct connection types. It manages the lifecycle of the tunnels and agents, while the UI simply shows the status (Online/Offline) of the "Server".
### 3.3 Install Options & UX Snippets
When a user selects `Orthrus Agent` or chooses a `Managed Tunnel` flow, the UI should offer multiple installation options so both containerized and non-containerized environments are supported.
Provide these install options as tabs/snippets in the `Add Server` flow:
- **Docker Compose**: A one-file snippet the user can copy/paste (already covered in `orthrus` docs).
- **Standalone Binary + systemd**: Download URL, SHA256, install+`systemd` unit snippet for Linux hosts.
- **Tarball + Installer**: For offline installs with checksum verification.
- **Deb / RPM**: `apt`/`yum` install commands (when packages are available).
- **Homebrew**: `brew tap` + `brew install` for macOS / Linuxbrew users.
- **Kubernetes DaemonSet**: YAML for fleet or cluster-based deployments.
UI Requirements:
- Show the generated `AUTH_KEY` prominently and a single-copy button.
- Provide checksum and GPG signature links for any downloadable artifact.
- Offer a small troubleshooting panel with commands like `journalctl -u orthrus -f` and `systemctl status orthrus`.
- Allow the user to copy a recommended sidecar snippet that runs a VPN client (e.g., Tailscale) next to Orthrus when desired.
## 4. API Endpoints
- `GET /api/hecate/status` - Returns health of all tunnels.
- `POST /api/hecate/configure` - Accepts auth tokens and provider types.
- `POST /api/hecate/logs` - Streams logs from the underlying tunnel binary (e.g., cloudflared logs) for debugging.
## 5. Security (Cerberus Integration)
Traffic entering through Hecate must still pass through Cerberus.
- Tunnels terminate **before** the middleware chain.
- Requests from a Cloudflare Tunnel are tagged `source:tunnel` and subjected to the same WAF rules as standard traffic.
## 6. Implementation Details
### 6.1 Process Supervision
Hecate will act as a process supervisor for external binaries like `cloudflared`.
- **Supervisor Pattern**: A `TunnelManager` struct will maintain a map of active `TunnelProvider` instances.
- **Lifecycle**:
- On startup, `TunnelManager` loads enabled configs from the DB.
- It launches the binary using `os/exec`.
- It monitors the process state. If the process exits unexpectedly, it triggers a **Restart Policy** (Exponential Backoff: 5s, 10s, 30s, 1m).
- **Graceful Shutdown**: When Charon shuts down, Hecate must send `SIGTERM` to all child processes and wait (with timeout) for them to exit.
### 6.2 Secrets Management
API tokens and sensitive credentials must not be stored in plaintext.
- **Encryption**: Sensitive fields (like Cloudflare Tokens) will be encrypted at rest in the SQLite database using AES-GCM.
- **Key Management**: An encryption key will be generated on first run and stored in `data/keys/hecate.key` (secured with 600 permissions), or provided via `CHARON_SECRET_KEY` env var.
### 6.3 Logging & Observability
- **Capture**: The `TunnelProvider` implementation will attach to the `Stdout` and `Stderr` pipes of the child process.
- **Storage**:
- **Hot Logs**: A circular buffer (Ring Buffer) in memory (last 1000 lines) for real-time dashboard viewing.
- **Cold Logs**: Rotated log files stored in `data/logs/tunnels/<provider>.log`.
- **Streaming**: The frontend will consume logs via a WebSocket endpoint (`/api/ws/hecate/logs/:id`) or Server-Sent Events (SSE) to display real-time output.
### 6.4 Frontend Components
- **TunnelStatusBadge**: Visual indicator (Green=Connected, Yellow=Starting, Red=Error/Stopped).
- **LogViewer**: A terminal-like component (using `xterm.js` or a virtualized list) to display the log stream.
- **ConfigForm**: A dynamic form that renders fields based on the selected provider (e.g., "Token" for Cloudflare, "Auth Key" for Tailscale).
## 7. Database Schema
We will introduce a new GORM model `TunnelConfig` in `internal/models`.
```go
package models
import (
"time"
"github.com/google/uuid"
"gorm.io/datatypes"
)
type TunnelProviderType string
const (
ProviderCloudflare TunnelProviderType = "cloudflare"
ProviderTailscale TunnelProviderType = "tailscale"
)
type TunnelConfig struct {
ID uuid.UUID `gorm:"type:uuid;primaryKey" json:"id"`
Name string `gorm:"not null" json:"name"` // User-friendly name (e.g., "Home Lab Tunnel")
Provider TunnelProviderType `gorm:"not null" json:"provider"`
// EncryptedCredentials stores the API token or Auth Key.
// It is encrypted at rest and decrypted only when starting the process.
EncryptedCredentials []byte `gorm:"not null" json:"-"`
// Configuration stores provider-specific settings (JSON).
// e.g., Cloudflare specific flags, region settings, etc.
Configuration datatypes.JSON `json:"configuration"`
IsActive bool `gorm:"default:false" json:"is_active"` // User's desired state
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
```

View File

@@ -1,257 +0,0 @@
# Orthrus: Remote Socket Proxy Agent
## 1. Overview
**Orthrus** is a lightweight, standalone agent designed to run on remote servers. Named after the brother of Cerberus, its job is to guard the remote resource and securely transport it back to Charon.
It eliminates the need for SSH tunneling or complex port forwarding by utilizing the tunneling protocols managed by Hecate.
## 2. Operational Logic
Orthrus operates in **Reverse Mode**. It does not listen on a public port. Instead, it dials *out* to the tunneling network to connect with Charon.
++-
### 2.1 Core Functions
1. **Docker Socket Proxy:** Securely proxies the remote server's `/var/run/docker.sock` so Charon can auto-discover containers on the remote host.
2. **Service Proxy:** Proxies specific localhost ports (e.g., a database on port 5432) over the tunnel.
## 3. Technical Implementation
### 3.1 Tech Stack
* **Language:** Go (Golang)
* **Base Image:** `scratch` or `alpine` (Goal: < 20MB image size)
### 3.2 Configuration (Environment Variables)
Orthrus is configured entirely via Environment Variables for easy Docker Compose deployment.
| Variable | Description |
| :--- | :--- |
| `ORTHRUS_NAME` | Unique identifier for this agent (e.g., `vps-london-01`) |
| `ORTHRUS_MODE` | `socket` (Docker Socket) or `port` (Specific Port) |
| `CHARON_LINK` | The IP/DNS of the main Charon server (e.g., `100.x.y.z:8080` or `charon.example.com`) |
| `AUTH_KEY` | A shared secret or JWT generated by Charon to authorize this agent |
### 3.3 External Connectivity
**Orthrus does NOT manage VPNs or network tunnels internally.**
It relies entirely on the host operating system for network connectivity.
1. **User Responsibility**: The user must ensure the host running Orthrus can reach the `CHARON_LINK` address.
2. **VPNs**: If you are using Tailscale, WireGuard, or ZeroTier, you must install and configure the VPN client on the **Host OS** (or a sidecar container). Orthrus simply dials the IP provided in `CHARON_LINK`.
3. **Reverse Mode**: Orthrus initiates the connection. Charon waits for the incoming handshake. This means you do not need to open inbound ports on the Orthrus side, but Charon must be reachable.
### 3.4 The "Leash" Protocol (Communication)
Orthrus communicates with Charon via a custom gRPC stream or WebSocket called "The Leash."
1. **Handshake**: Orthrus connects to `Charon:InternalIP`.
2. **Auth**: Orthrus presents the `AUTH_KEY`.
3. **Registration**: Orthrus tells Charon: *"I have access to Docker Network X and Port Y."*
4. **Tunneling**: Charon requests a resource; Orthrus pipes the data securely over "The Leash."
## 4. Deployment Example (Docker Compose)
```yaml
services:
orthrus:
image: wikid82/orthrus:latest
container_name: orthrus-agent
restart: always
environment:
- ORTHRUS_NAME=remote-media-server
- CHARON_LINK=100.x.y.z:8080
- AUTH_KEY=ch_xxxxx_secret
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
# No ports required!
```
## 5. Security Considerations
* **Read-Only Socket**: By default, Orthrus mounts the Docker socket as Read-Only to prevent Charon (or a compromised Charon) from destroying the remote server.
* **Mutual TLS (mTLS)**: All communication between Charon and Orthrus should be encrypted via mTLS if not running inside an encrypted VPN (like Tailscale).
## 6. Implementation Details
### 6.1 Communication Architecture
Orthrus uses a **Reverse Tunnel** architecture established via **WebSockets** with **Yamux** multiplexing.
1. **Transport**: Secure WebSocket (`wss://`) initiates the connection from Orthrus to Charon. This bypasses inbound firewall rules on the remote network.
2. **Multiplexing**: [Yamux](https://github.com/hashicorp/yamux) is used over the WebSocket stream to create multiple logical channels.
* **Control Channel (Stream ID 0)**: Handles heartbeats, configuration updates, and command signals.
* **Data Channels (Stream ID > 0)**: Ephemeral streams created for each proxied request (e.g., a single HTTP request to the Docker socket or a TCP connection to a database).
### 6.2 Authentication & Security
* **Token-Based Handshake**: The `AUTH_KEY` is passed in the `Authorization` header during the WebSocket Upgrade request.
* **mTLS (Mutual TLS)**:
* **Charon as CA**: Charon maintains an internal Certificate Authority.
* **Enrollment**: On first connect with a valid `AUTH_KEY`, Orthrus generates a private key and sends a CSR. Charon signs it and returns the certificate.
* **Rotation**: Orthrus monitors certificate expiry and initiates a renewal request over the Control Channel 24 hours before expiration.
* **Encryption**: All traffic is TLS 1.3 encrypted.
### 6.3 Docker Socket Proxying (The "Muzzle")
To prevent security risks, Orthrus does not blindly pipe traffic to `/var/run/docker.sock`. It implements an application-level filter (The "Muzzle"):
1. **Parser**: Intercepts HTTP requests destined for the socket.
2. **Allowlist**: Only permits safe methods/endpoints (e.g., `GET /v1.xx/containers/json`, `GET /v1.xx/info`).
3. **Blocking**: Rejects `POST`, `DELETE`, `PUT` requests (unless explicitly configured to allow specific actions like "Restart Container") with a `403 Forbidden`.
### 6.4 Heartbeat & Health
* **Mechanism**: Orthrus sends a custom "Ping" packet over the Control Channel every 5 seconds.
* **Timeout**: Charon expects a "Ping" within 10 seconds. If missed, the agent is marked `Offline`.
* **Reconnection**: Orthrus implements exponential backoff (1s, 2s, 4s... max 30s) to reconnect if the link is severed.
## 7. Protocol Specification ("The Leash")
### 7.1 Handshake
```http
GET /api/v1/orthrus/connect HTTP/1.1
Host: charon.example.com
Upgrade: websocket
Connection: Upgrade
Authorization: Bearer <AUTH_KEY>
X-Orthrus-Version: 1.0.0
X-Orthrus-ID: <ORTHRUS_NAME>
```
### 7.2 Message Types (Control Channel)
Messages are Protobuf-encoded for efficiency.
* `HEARTBEAT`: `{ timestamp: int64, load_avg: float, memory_usage: int }`
* `PROXY_REQUEST`: Sent by Charon to request a new stream. `{ stream_id: int, target_type: "docker"|"tcp", target_addr: "localhost:5432" }`
* `CONFIG_UPDATE`: Sent by Charon to update allowlists or rotation policies.
### 7.3 Data Flow
1. **Charon** receives a request for a remote container (e.g., user views logs).
2. **Charon** sends `PROXY_REQUEST` on Control Channel.
3. **Orthrus** accepts, opens a new Yamux stream.
4. **Orthrus** dials the local Docker socket.
5. **Orthrus** pipes the stream, applying "The Muzzle" filter in real-time.
## 8. Repository Structure (Monorepo)
Orthrus resides in the **same repository** as Charon to ensure protocol synchronization and simplified CI/CD.
### 8.1 Directory Layout
To maintain a lightweight footprint (< 20MB), Orthrus uses a separate Go module within the `agent/` directory. This prevents it from inheriting Charon's heavy backend dependencies (GORM, SQLite, etc.).
```text
/projects/Charon
├── go.work # Manages the workspace (includes ./backend and ./agent)
├── backend/ # The Main Server (Heavy)
│ ├── go.mod
│ └── ...
├── agent/ # Orthrus (Lightweight)
│ ├── go.mod # Separate dependencies (Standard Lib + Yamux)
│ ├── main.go
│ └── Dockerfile # Separate build process
└── protocol/ # Shared Definitions (Protobufs)
├── go.mod
└── leash.proto
```
### 8.2 Build Strategy
* **Charon**: Built from `backend/Dockerfile`.
* **Orthrus**: Built from `agent/Dockerfile`.
* **CI/CD**: A single GitHub Action workflow builds and pushes both images (`charon:latest` and `orthrus:latest`) synchronously.
## 9. Packaging & Install Options
Orthrus should be distributed in multiple formats so users can choose one that fits their environment and security posture.
### 9.1 Supported Distribution Formats
* **Docker / Docker Compose**: easiest for container-based hosts.
* **Standalone static binary (recommended)**: small, copy to `/usr/local/bin`, run via `systemd`.
* **Deb / RPM packages**: for managed installs via `apt`/`yum`.
* **Homebrew formula**: for macOS / Linuxbrew users.
* **Tarball with installer**: for offline or custom installs.
* **Kubernetes DaemonSet**: for fleet deployment inside clusters.
### 9.2 Quick Install Snippets (copyable)
1) Docker Compose
```yaml
version: "3.8"
services:
orthrus:
image: wikid82/orthrus:latest
restart: always
environment:
- ORTHRUS_NAME=remote-media-server
- CHARON_LINK=100.x.y.z:8080
- AUTH_KEY=REPLACE_WITH_AUTH_KEY
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
```
1) Standalone binary + `systemd` (Linux)
```bash
# download and install
curl -L https://example.com/orthrus/latest/orthrus-linux-amd64 -o /usr/local/bin/orthrus
chmod +x /usr/local/bin/orthrus
# systemd unit (/etc/systemd/system/orthrus.service)
cat > /etc/systemd/system/orthrus.service <<'EOF'
[Unit]
Description=Orthrus agent
After=network.target
[Service]
Environment=ORTHRUS_NAME=remote-media-server
Environment=CHARON_LINK=100.x.y.z:8080
Environment=AUTH_KEY=REPLACE_WITH_AUTH_KEY
ExecStart=/usr/local/bin/orthrus
Restart=on-failure
User=root
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable --now orthrus
```
1) Tarball + install script
```bash
curl -L -o orthrus.tar.gz https://example.com/orthrus/vX.Y.Z/orthrus-linux-amd64.tar.gz
sha256sum orthrus.tar.gz # compare with UI-provided hash
tar -xzf orthrus.tar.gz -C /usr/local/bin
chmod +x /usr/local/bin/orthrus
# then use the systemd unit above
```
1) Homebrew (macOS / Linuxbrew)
```
brew tap wikid82/charon
brew install orthrus
```
1) Kubernetes DaemonSet
Provide a DaemonSet YAML referencing the `orthrus` image and the required env vars (`AUTH_KEY`, `CHARON_LINK`), optionally mounting the Docker socket or using hostNetworking.
### 9.3 Security & UX Notes
* Provide SHA256 checksums and GPG signatures for binary downloads.
* Avoid recommending `curl | sh`; prefer explicit steps and checksum verification.
* The Hecate UI should present each snippet as a selectable tab with a copy button and an inline checksum.
* Offer a one-click `AUTH_KEY` regenerate action in the UI and mark old keys revoked.

View File

@@ -1,187 +0,0 @@
# Plex Remote Access Helper & CGNAT Solver
> **GitHub Issue Template** - Copy this content to create a new GitHub issue
---
## Issue Title
`Plex Remote Access Helper & CGNAT Solver`
## Labels
`beta`, `feature`, `plus`, `ui`, `caddy`
---
## Description
Implement a "Plex Remote Access Helper" feature that assists users stuck behind CGNAT (Carrier-Grade NAT) to properly configure their Plex Media Server for remote streaming via a reverse proxy like Caddy. This feature addresses the common pain point of Plex remote access failures when users cannot open ports due to ISP limitations.
## Parent Issue
Extends #44 (Tailscale Network Integration) and #43 (Remote Servers Management)
## Why This Feature?
- **CGNAT is increasingly common** - Many ISPs (especially mobile carriers like T-Mobile) use Carrier-Grade NAT, preventing users from forwarding ports
- **Plex is one of the most popular homelab applications** - A significant portion of Charon users will have Plex
- **Manual configuration is error-prone** - Users often struggle with the correct Caddy configuration and Plex settings
- **Tailscale/VPN integration makes this possible** - With #44, users can access their home network, but Plex requires specific proxy headers for proper remote client handling
- **User story origin** - This feature was conceived from a real user experience solving CGNAT issues with Plex + Tailscale
## Use Cases
1. **T-Mobile/Starlink Home Internet users** - Cannot port forward, need VPN tunnel + reverse proxy
2. **Apartment/Dorm residents** - Shared internet without port access
3. **Privacy-conscious users** - Prefer VPN tunnel over exposing ports
4. **Multi-server Plex setups** - Proxying to multiple Plex instances
## Tasks
- [ ] Design "Plex Mode" toggle or "Media Server Helper" option in proxy host creation
- [ ] Implement automatic header injection for Plex compatibility:
- `X-Forwarded-For` - Client's real IP address
- `X-Forwarded-Proto` - HTTPS
- `X-Real-IP` - Client IP
- `X-Plex-Client-Identifier` - Passthrough
- [ ] Create "External Domain" text input for Plex custom URL setting
- [ ] Generate copy-paste snippet for Plex Settings → Network → Custom server access URLs
- [ ] Add Plex-specific Caddy configuration template
- [ ] Implement WebSocket support toggle (required for Plex Companion)
- [ ] Create validation/test button to verify proxy is working
- [ ] Add documentation/guide for CGNAT + Tailscale + Plex setup
- [ ] Implement connection type detection (show if traffic appears Local vs Remote in proxy logs)
- [ ] Add warning about bandwidth limiting implications when headers are missing
## Acceptance Criteria
- [ ] User can enable "Plex Mode" when creating a proxy host
- [ ] Correct headers are automatically added to Caddy config
- [ ] Copy-paste snippet generated for Plex custom URL setting
- [ ] WebSocket connections work for Plex Companion features
- [ ] Documentation explains full CGNAT + Tailscale + Plex workflow
- [ ] Remote streams correctly show as "Remote" in Plex dashboard (not "Local")
- [ ] Works with both HTTP and HTTPS upstream Plex servers
## Technical Considerations
### Caddy Configuration Template
```caddyfile
plex.example.com {
reverse_proxy localhost:32400 {
# Required headers for proper Plex remote access
header_up X-Forwarded-For {remote_host}
header_up X-Forwarded-Proto {scheme}
header_up X-Real-IP {remote_host}
# Preserve Plex-specific headers
header_up X-Plex-Client-Identifier {header.X-Plex-Client-Identifier}
header_up X-Plex-Device {header.X-Plex-Device}
header_up X-Plex-Device-Name {header.X-Plex-Device-Name}
header_up X-Plex-Platform {header.X-Plex-Platform}
header_up X-Plex-Platform-Version {header.X-Plex-Platform-Version}
header_up X-Plex-Product {header.X-Plex-Product}
header_up X-Plex-Token {header.X-Plex-Token}
header_up X-Plex-Version {header.X-Plex-Version}
# WebSocket support for Plex Companion
transport http {
read_buffer 8192
}
}
}
```
### Plex Settings Required
Users must configure in Plex Settings → Network:
- **Secure connections**: Preferred (not Required, to allow proxy)
- **Custom server access URLs**: `https://plex.example.com:443`
### Integration with Existing Features
- Leverage Remote Servers (#43) for Plex server discovery
- Use Tailscale integration (#44) for CGNAT bypass
- Apply to Cloudflare Tunnel (#47) for additional NAT traversal option
### Header Behavior Notes
- Without `X-Forwarded-For`: Plex sees all traffic as coming from the proxy's IP (e.g., Tailscale 100.x.x.x)
- This may cause Plex to treat remote traffic as "Local," bypassing bandwidth limits
- Users should be warned about this behavior in the UI
## UI/UX Design Notes
### Proxy Host Creation Form
Add a collapsible "Media Server Settings" section:
```
☑ Enable Plex Mode
External Domain for Plex: [ plex.example.com ]
[📋 Copy Plex Custom URL]
→ https://plex.example.com:443
Add this URL to Plex Settings → Network → Custom server access URLs
☑ Forward client IP headers (recommended)
☑ Enable WebSocket support
```
### Quick Start Template
In Onboarding Wizard (#30), add "Plex" as a Quick Start template option:
- Pre-configures port 32400
- Enables Plex Mode automatically
- Provides step-by-step instructions
## Documentation Sections to Add
1. **CGNAT Explained** - What is CGNAT and why it blocks remote access
2. **Tailscale + Plex Setup Guide** - Complete walkthrough
3. **Troubleshooting Remote Access** - Common issues and solutions
4. **Local vs Remote Traffic** - Explaining header behavior
5. **Bandwidth Limiting Gotcha** - Why headers matter for throttling
## Priority
Medium - Valuable user experience improvement, builds on #44
## Milestone
Beta
## Related Issues
- #44 (Tailscale Network Integration) - Provides the VPN tunnel
- #43 (Remote Servers Management) - Server discovery
- #47 (Cloudflare Tunnel Integration) - Alternative NAT traversal
- #30 (Onboarding Wizard) - Quick Start templates
## Future Extensions
- Support for other media servers (Jellyfin, Emby)
- Automatic Plex server detection via UPnP/SSDP
- Integration with Tautulli for monitoring
- Plex claim token setup assistance
---
## How to Create This Issue
1. Go to <https://github.com/Wikid82/charon/issues/new>
2. Use title: `Plex Remote Access Helper & CGNAT Solver`
3. Add labels: `beta`, `feature`, `plus`, `ui`, `caddy`
4. Copy the content from "## Description" through "## Future Extensions"
5. Submit the issue
---
*Issue specification created: 2025-11-27*
*Origin: Gemini-assisted Plex remote streaming solution using Tailscale*

View File

@@ -1,364 +0,0 @@
# Enhancement: Rotating Thematic Loading Animations
**Issue Type**: Enhancement
**Priority**: Low
**Status**: Future
**Component**: Frontend UI
**Related**: Caddy Reload UI Feedback Implementation
---
## 📋 Summary
Implement a hybrid approach for loading animations that randomly rotates between multiple thematic variations for both Charon (proxy operations) and Cerberus (security operations) themes. This adds visual variety and reinforces the mythological branding of the application.
---
## 🎯 Motivation
Currently, each operation type displays the same loading animation every time. While functional, this creates a repetitive user experience. By rotating between thematically consistent animation variants, we can:
1. **Reduce Visual Fatigue**: Users won't see the exact same animation on every operation
2. **Enhance Branding**: Multiple mythological references deepen the Charon/Cerberus theme
3. **Maintain Consistency**: All variants stay within their respective theme (blue/Charon or red/Cerberus)
4. **Add Delight**: Small surprises in UI create more engaging user experience
5. **Educational**: Each variant can teach users more about the mythology (e.g., Charon's obol coin)
---
## 🎨 Proposed Animation Variants
### Charon Theme (Proxy/General Operations)
**Color Palette**: Blue (#3B82F6, #60A5FA), Slate (#64748B, #475569)
| Animation | Description | Key Message Examples |
|-----------|-------------|---------------------|
| **Boat on Waves** (Current) | Boat silhouette bobbing on animated waves | "Ferrying across the Styx..." |
| **Rowing Oar** | Animated oar rowing motion in water | "Pulling through the mist..." / "The oar dips and rises..." |
| **River Flow** | Flowing water with current lines | "Drifting down the Styx..." / "Waters carry the change..." |
### Coin Theme (Authentication)
**Color Palette**: Gold (#F59E0B, #FBBF24), Amber (#D97706, #F59E0B)
| Animation | Description | Key Message Examples |
|-----------|-------------|---------------------|
| **Coin Flip** (Current) | Spinning obol (ancient Greek coin) on Y-axis | "Paying the ferryman..." / "Your obol grants passage" |
| **Coin Drop** | Coin falling and landing in palm | "The coin drops..." / "Payment accepted" |
| **Token Glow** | Glowing authentication token/key | "Token gleams..." / "The key turns..." |
| **Gate Opening** | Stone gate/door opening animation | "Gates part..." / "Passage granted" |
### Cerberus Theme (Security Operations)
**Color Palette**: Red (#DC2626, #EF4444), Amber (#F59E0B), Red-900 (#7F1D1D)
| Animation | Description | Key Message Examples |
|-----------|-------------|---------------------|
| **Three Heads Alert** (Current) | Three heads with glowing eyes and pulsing shield | "Guardian stands watch..." / "Three heads turn..." |
| **Shield Pulse** | Centered shield with pulsing defensive aura | "Barriers strengthen..." / "The ward pulses..." |
| **Guardian Stance** | Simplified Cerberus silhouette in alert pose | "Guarding the threshold..." / "Sentinel awakens..." |
| **Chain Links** | Animated chain links representing binding/security | "Chains of protection..." / "Bonds tighten..." |
---
## 🛠️ Technical Implementation
### Architecture
```tsx
// frontend/src/components/LoadingStates.tsx
type CharonVariant = 'boat' | 'coin' | 'oar' | 'river'
type CerberusVariant = 'heads' | 'shield' | 'stance' | 'chains'
interface LoadingMessages {
message: string
submessage: string
}
const CHARON_MESSAGES: Record<CharonVariant, LoadingMessages[]> = {
boat: [
{ message: "Ferrying across...", submessage: "Charon guides the way" },
{ message: "Crossing the Styx...", submessage: "The journey begins" }
],
coin: [
{ message: "Paying the ferryman...", submessage: "The obol tumbles" },
{ message: "Coin accepted...", submessage: "Passage granted" }
],
oar: [
{ message: "Pulling through the mist...", submessage: "The oar dips and rises" },
{ message: "Rowing steadily...", submessage: "Progress across dark waters" }
],
river: [
{ message: "Drifting down the Styx...", submessage: "Waters carry the change" },
{ message: "Current flows...", submessage: "The river guides all" }
]
}
const CERBERUS_MESSAGES: Record<CerberusVariant, LoadingMessages[]> = {
heads: [
{ message: "Three heads turn...", submessage: "Guardian stands watch" },
{ message: "Cerberus awakens...", submessage: "The gate is guarded" }
],
shield: [
{ message: "Barriers strengthen...", submessage: "The ward pulses" },
{ message: "Defenses activate...", submessage: "Protection grows" }
],
stance: [
{ message: "Guarding the threshold...", submessage: "Sentinel awakens" },
{ message: "Taking position...", submessage: "The guardian stands firm" }
],
chains: [
{ message: "Chains of protection...", submessage: "Bonds tighten" },
{ message: "Links secure...", submessage: "Nothing passes unchecked" }
]
}
// Randomly select variant on component mount
export function ConfigReloadOverlay({ type = 'charon', operationType }: Props) {
const [variant] = useState(() => {
if (type === 'cerberus') {
const variants: CerberusVariant[] = ['heads', 'shield', 'stance', 'chains']
return variants[Math.floor(Math.random() * variants.length)]
} else {
const variants: CharonVariant[] = ['boat', 'coin', 'oar', 'river']
return variants[Math.floor(Math.random() * variants.length)]
}
})
const [messages] = useState(() => {
const messageSet = type === 'cerberus'
? CERBERUS_MESSAGES[variant as CerberusVariant]
: CHARON_MESSAGES[variant as CharonVariant]
return messageSet[Math.floor(Math.random() * messageSet.length)]
})
// Render appropriate loader component based on variant
const Loader = getLoaderComponent(type, variant)
return (
<div className="fixed inset-0 bg-slate-900/70 backdrop-blur-sm flex items-center justify-center z-50">
<div className={/* theme styling */}>
<Loader size="lg" />
<div className="text-center">
<p className="text-slate-200 font-medium text-lg">{messages.message}</p>
<p className="text-slate-400 text-sm mt-2">{messages.submessage}</p>
</div>
</div>
</div>
)
}
```
### New Loader Components
Each variant needs its own component:
```tsx
// Charon Variants
export function CharonCoinLoader({ size }: LoaderProps) {
// Spinning coin with heads/tails alternating
}
export function CharonOarLoader({ size }: LoaderProps) {
// Rowing oar motion
}
export function CharonRiverLoader({ size }: LoaderProps) {
// Flowing water lines
}
// Cerberus Variants
export function CerberusShieldLoader({ size }: LoaderProps) {
// Pulsing shield with defensive aura
}
export function CerberusStanceLoader({ size }: LoaderProps) {
// Guardian dog in alert pose
}
export function CerberusChainsLoader({ size }: LoaderProps) {
// Animated chain links
}
```
---
## 📐 Animation Specifications
### Charon: Coin Flip
- **Visual**: Ancient Greek obol coin spinning on Y-axis
- **Animation**: 360° rotation every 2s, slight wobble
- **Colors**: Gold (#F59E0B) glint, slate shadow
- **Message Timing**: Change text on coin flip (heads vs tails)
### Charon: Rowing Oar
- **Visual**: Oar blade dipping into water, pulling back
- **Animation**: Arc motion, water ripples on dip
- **Colors**: Brown (#92400E) oar, blue (#3B82F6) water
- **Timing**: 3s cycle (dip 1s, pull 1.5s, lift 0.5s)
### Charon: River Flow
- **Visual**: Horizontal flowing lines with subtle particle drift
- **Animation**: Lines translate-x infinitely, particles bob
- **Colors**: Blue gradient (#1E3A8A#3B82F6)
- **Timing**: Continuous flow, particles move slower than lines
### Cerberus: Shield Pulse
- **Visual**: Shield outline with expanding aura rings
- **Animation**: Rings pulse outward and fade (like sonar)
- **Colors**: Red (#DC2626) shield, amber (#F59E0B) aura
- **Timing**: 2s pulse interval
### Cerberus: Guardian Stance
- **Visual**: Simplified three-headed dog silhouette, alert posture
- **Animation**: Heads swivel slightly, ears perk
- **Colors**: Red (#7F1D1D) body, amber (#F59E0B) eyes
- **Timing**: 3s head rotation cycle
### Cerberus: Chain Links
- **Visual**: 4-5 interlocking chain links
- **Animation**: Links tighten/loosen (scale transform)
- **Colors**: Gray (#475569) chains, red (#DC2626) accents
- **Timing**: 2.5s cycle (tighten 1s, loosen 1.5s)
---
## 🧪 Testing Strategy
### Visual Regression Tests
- Capture screenshots of each variant at key animation frames
- Verify animations play smoothly (no janky SVG rendering)
- Test across browsers (Chrome, Firefox, Safari)
### Unit Tests
```tsx
describe('ConfigReloadOverlay - Variant Selection', () => {
it('randomly selects Charon variant', () => {
const variants = new Set()
for (let i = 0; i < 20; i++) {
const { container } = render(<ConfigReloadOverlay type="charon" />)
// Extract which variant was rendered
variants.add(getRenderedVariant(container))
}
expect(variants.size).toBeGreaterThan(1) // Should see variety
})
it('randomly selects Cerberus variant', () => {
const variants = new Set()
for (let i = 0; i < 20; i++) {
const { container } = render(<ConfigReloadOverlay type="cerberus" />)
variants.add(getRenderedVariant(container))
}
expect(variants.size).toBeGreaterThan(1)
})
it('uses variant-specific messages', () => {
const { getByText } = render(<ConfigReloadOverlay type="charon" />)
// Should find ONE of the Charon messages
const hasCharonMessage =
getByText(/ferrying/i) ||
getByText(/coin/i) ||
getByText(/oar/i) ||
getByText(/river/i)
expect(hasCharonMessage).toBeTruthy()
})
})
```
### Manual Testing
- [ ] Trigger same operation 10 times, verify different animations appear
- [ ] Verify messages match animation theme (e.g., "Coin" messages with coin animation)
- [ ] Check performance (should be smooth at 60fps)
- [ ] Verify accessibility (screen readers announce state)
---
## 📦 Implementation Phases
### Phase 1: Core Infrastructure (2-3 hours)
- [ ] Create variant selection logic
- [ ] Create message mapping system
- [ ] Update `ConfigReloadOverlay` to accept variant prop
- [ ] Write unit tests for variant selection
### Phase 2: Charon Variants (3-4 hours)
- [ ] Implement `CharonOarLoader` component
- [ ] Implement `CharonRiverLoader` component
- [ ] Create messages for each variant
- [ ] Add Tailwind animations
### Phase 3: Coin Variants (3-4 hours)
- [ ] Implement `CoinDropLoader` component
- [ ] Implement `TokenGlowLoader` component
- [ ] Implement `GateOpeningLoader` component
- [ ] Create messages for each variant
- [ ] Add Tailwind animations
### Phase 4: Cerberus Variants (4-5 hours)
- [ ] Implement `CerberusShieldLoader` component
- [ ] Implement `CerberusStanceLoader` component
- [ ] Implement `CerberusChainsLoader` component
- [ ] Create messages for each variant
- [ ] Add Tailwind animations
### Phase 5: Integration & Polish (2-3 hours)
- [ ] Update all usage sites (ProxyHosts, WafConfig, etc.)
- [ ] Visual regression tests
- [ ] Performance profiling
- [ ] Documentation updates
**Total Estimated Time**: 15-19 hours
---
## 🎯 Success Metrics
- Users see at least 3 different animations within 10 operations
- Animation performance: 60fps on mid-range devices
- Zero accessibility regressions (WCAG 2.1 AA)
- Positive user feedback on visual variety
- Code coverage: >90% for variant selection logic
---
## 🚫 Out of Scope
- User preference for specific variant (always random)
- Custom animation timing controls
- Additional themes beyond Charon/Cerberus
- Sound effects or haptic feedback
- Animation of background overlay entrance/exit
---
## 📚 Research References
- **Charon Mythology**: [Wikipedia - Charon](https://en.wikipedia.org/wiki/Charon)
- **Cerberus Mythology**: [Wikipedia - Cerberus](https://en.wikipedia.org/wiki/Cerberus)
- **Obol Coin**: Payment for Charon's ferry service in Greek mythology
- **SVG Animation Performance**: [CSS-Tricks SVG Guide](https://css-tricks.com/guide-svg-animations-smil/)
- **React Loading States**: Best practices for UX during async operations
---
## 🔗 See Also
- Main Implementation: `docs/plans/current_spec.md`
- Charon Documentation: `docs/features.md`
- Cerberus Documentation: `docs/cerberus.md`

View File

@@ -1,484 +0,0 @@
---
title: "Application URL Feature - Manual Test Plan"
labels:
- manual-testing
- feature
- user-management
type: testing
priority: high
---
# Application URL Feature - Manual Test Plan
**Feature**: Application URL Configuration & User Invitation Preview
**Status**: Ready for Manual Testing
---
## Overview
This test plan covers the new Application URL configuration feature and its integration with user invitations. The feature allows administrators to configure the public URL used in invitation emails and provides a preview function to verify invite links before sending.
---
## Test Scenarios
### 1. Application URL Configuration - Valid URLs
**Objective**: Verify that valid URLs can be configured and saved correctly.
**Prerequisites**:
- Logged in as an administrator
- Access to System Settings page
**Steps**:
1. Navigate to **System Settings** (gear icon in sidebar)
2. Scroll to the **"Application URL"** section
3. Test each of the following valid URLs:
a. **HTTPS with domain**:
- Enter: `https://charon.example.com`
- Click **"Validate"**
- Verify: Shows normalized URL without errors
- Click **"Test"**
- Verify: New browser tab opens to the URL
- Click **"Save Changes"**
- Verify: Success toast appears
- Refresh page
- Verify: URL is still set
b. **HTTPS with custom port**:
- Enter: `https://charon.example.com:8443`
- Click **"Validate"**
- Verify: Shows normalized URL without errors
- Click **"Save Changes"**
- Verify: Saves successfully
c. **HTTP with warning** (internal testing):
- Enter: `http://192.168.1.100:8080`
- Click **"Validate"**
- Verify: Shows warning about using HTTP instead of HTTPS
- Verify: URL is still marked as valid
- Click **"Save Changes"**
- Verify: Saves successfully
**Expected Results**:
- [ ] All valid URLs are accepted
- [ ] Normalized URLs are displayed correctly
- [ ] HTTP URLs show security warning but still save
- [ ] Test button opens URLs in new tab
- [ ] Settings persist after page refresh
- [ ] Success toast appears after saving
---
### 2. Application URL Configuration - Invalid URLs
**Objective**: Verify that invalid URLs are rejected with appropriate error messages.
**Prerequisites**:
- Logged in as an administrator
- Access to System Settings page
**Steps**:
1. Navigate to **System Settings****Application URL**
2. Test each of the following invalid URLs:
a. **Missing protocol**:
- Enter: `charon.example.com`
- Click **"Validate"**
- Verify: Shows error "URL must start with http:// or https://"
- Verify: Cannot save (Save button disabled or shows error)
b. **URL with path**:
- Enter: `https://charon.example.com/admin`
- Click **"Validate"**
- Verify: Shows error "cannot include path components"
- Verify: Cannot save
c. **URL with trailing slash**:
- Enter: `https://charon.example.com/`
- Click **"Validate"**
- Verify: Either auto-corrects to `https://charon.example.com` OR shows error
d. **Wrong protocol**:
- Enter: `ftp://charon.example.com`
- Click **"Validate"**
- Verify: Shows error about invalid protocol
e. **Empty URL**:
- Leave field empty
- Click **"Validate"**
- Verify: Shows error or disables validate button
**Expected Results**:
- [ ] All invalid URLs are rejected
- [ ] Clear error messages are displayed
- [ ] Save button is disabled for invalid URLs
- [ ] No invalid URLs can be persisted to database
---
### 3. User Invitation Preview - With Configured URL
**Objective**: Verify invite preview works correctly when Application URL is configured.
**Prerequisites**:
- Logged in as an administrator
- Application URL configured (e.g., `https://charon.example.com`)
**Steps**:
1. Navigate to **Users** page
2. Click **"Add User"** or **"Invite User"** button
3. Enter email: `testuser@example.com`
4. Click **"Preview Invite"** button
5. Observe the preview modal/section
**Expected Results**:
- [ ] Preview shows full invite URL: `https://charon.example.com/accept-invite?token=SAMPLE_TOKEN_PREVIEW`
- [ ] Base URL displayed: `https://charon.example.com`
- [ ] Configuration status shows: ✅ Configured
- [ ] No warning message is displayed
- [ ] Warning indicator is not shown
---
### 4. User Invitation Preview - Without Configured URL
**Objective**: Verify warning message appears when Application URL is not configured.
**Prerequisites**:
- Logged in as an administrator
- Application URL NOT configured (clear the setting first)
**Steps**:
1. Go to **System Settings** → Clear Application URL setting → Save
2. Navigate to **Users** page
3. Click **"Add User"** or **"Invite User"** button
4. Enter email: `testuser@example.com`
5. Click **"Preview Invite"** button
6. Observe the preview modal/section
**Expected Results**:
- [ ] Preview shows localhost URL: `http://localhost:8080/accept-invite?token=SAMPLE_TOKEN_PREVIEW`
- [ ] Warning indicator is displayed (⚠️)
- [ ] Warning message: "Application URL not configured. The invite link may not be accessible from external networks."
- [ ] Configuration status shows: ❌ Not Configured
- [ ] Helpful link or button to navigate to System Settings
---
### 5. Multi-Language Support
**Objective**: Verify feature works correctly in all supported languages.
**Prerequisites**:
- Logged in as an administrator
**Steps**:
1. Test in each language:
- English
- Spanish (Español)
- French (Français)
- German (Deutsch)
- Chinese (中文)
2. For each language:
- Go to **System Settings** → Change language
- Navigate to **Application URL** section
- Verify section title is translated
- Verify description is translated
- Enter invalid URL: `charon.example.com`
- Click **"Validate"**
- Verify error message is translated
- Go to **Users** → Preview Invite
- Verify warning message is translated
**Expected Results**:
- [ ] All UI text is properly translated
- [ ] No English fallbacks appear (except for technical terms)
- [ ] Error and warning messages are localized
- [ ] Button labels are translated
- [ ] Help text is translated
---
### 6. Admin-Only Access Control
**Objective**: Verify non-admin users cannot access Application URL configuration.
**Prerequisites**:
- Admin account and non-admin user account
**Steps**:
1. **As Admin**:
- Navigate to System Settings
- Verify Application URL section is visible
- Verify can modify settings
2. **As Non-Admin User**:
- Log out and log in as regular user
- Navigate to System Settings (if accessible)
- Verify Application URL section is either:
- Not visible at all, OR
- Visible but disabled/read-only
3. **API Access Test** (optional, requires curl/Postman):
- Get non-admin user token
- Attempt to call: `POST /api/v1/settings/validate-url`
- Verify: Returns 403 Forbidden
- Attempt to call: `POST /api/v1/users/preview-invite-url`
- Verify: Returns 403 Forbidden
**Expected Results**:
- [ ] Admin users can access and modify Application URL
- [ ] Non-admin users cannot access or modify settings
- [ ] API endpoints return 403 for non-admin requests
- [ ] No privilege escalation is possible
---
### 7. Settings Persistence & Integration
**Objective**: Verify Application URL setting persists correctly and integrates with user invitation flow.
**Prerequisites**:
- Logged in as administrator
- Clean database state
**Steps**:
1. **Configure URL**:
- Go to System Settings
- Set Application URL: `https://test.example.com`
- Save and verify success
2. **Restart Container** (Docker only):
- `docker restart charon`
- Wait for container to start
- Log back in
3. **Verify Persistence**:
- Go to System Settings
- Verify Application URL is still: `https://test.example.com`
4. **Create Actual User Invitation**:
- Go to Users page
- Click "Add User"
- Enter email, role, etc.
- Submit invitation
- Check email inbox (if SMTP configured)
- Verify invite link uses configured URL
5. **Database Check** (optional):
- Query database: `SELECT * FROM settings WHERE key = 'app.public_url';`
- Verify value is `https://test.example.com`
**Expected Results**:
- [ ] Application URL persists after save
- [ ] Setting survives container restart
- [ ] Actual invite emails use configured URL
- [ ] Database stores correct value
- [ ] No corruption or data loss
---
### 8. Edge Cases & Error Handling
**Objective**: Verify robust error handling for edge cases.
**Prerequisites**:
- Logged in as administrator
**Steps**:
1. **Very Long URL**:
- Enter URL with 500+ characters
- Attempt to validate and save
- Verify: Shows appropriate error or truncation
2. **Special Characters**:
- Try URL: `https://charon.example.com?test=1&foo=bar`
- Verify: Rejected (query params not allowed)
3. **Unicode Domain**:
- Try URL: `https://例え.jp` (internationalized domain)
- Verify: Either accepted or shows clear error
4. **Rapid Clicks**:
- Enter valid URL
- Click "Validate" multiple times rapidly
- Verify: No duplicate requests or UI freezing
- Click "Test" multiple times rapidly
- Verify: Doesn't open excessive tabs
5. **Network Error Simulation** (optional):
- Disconnect network
- Try to save Application URL
- Verify: Shows network error message
- Reconnect network
- Retry save
- Verify: Works correctly after reconnection
**Expected Results**:
- [ ] Long URLs handled gracefully
- [ ] Special characters rejected with clear messages
- [ ] No duplicate API requests
- [ ] Network errors handled gracefully
- [ ] UI remains responsive during errors
---
### 9. UI/UX Verification
**Objective**: Verify user interface is intuitive and accessible.
**Prerequisites**:
- Logged in as administrator
**Steps**:
1. **Visual Design**:
- Navigate to System Settings → Application URL
- Verify:
- Section has clear title and description
- Input field is properly sized
- Buttons are visually distinct
- Error messages are color-coded (red)
- Warnings are color-coded (yellow/orange)
- Success states are color-coded (green)
2. **Keyboard Navigation**:
- Tab through all elements in order
- Verify: Focus indicators are visible
- Press Enter on "Validate" button
- Verify: Triggers validation
- Press Enter on "Test" button
- Verify: Opens URL in new tab
3. **Mobile Responsive** (if applicable):
- Open System Settings on mobile device or narrow browser window
- Verify: Application URL section is usable
- Verify: Buttons don't overflow
- Verify: Input field adapts to screen width
4. **Loading States**:
- Enter URL and click "Validate"
- Observe: Loading indicator appears during validation
- Click "Save Changes"
- Observe: Loading indicator appears during save
5. **Help Text**:
- Verify: Helper text explains URL format requirements
- Verify: Examples are provided
- Verify: Link to documentation (if present)
**Expected Results**:
- [ ] UI is visually consistent with rest of application
- [ ] Keyboard navigation works correctly
- [ ] Mobile layout is usable
- [ ] Loading states are clear
- [ ] Help text is informative and accurate
---
### 10. Documentation Accuracy
**Objective**: Verify all documentation matches actual behavior.
**Prerequisites**:
- Access to documentation
**Pages to Review**:
- [ ] `docs/getting-started.md` - Application URL configuration section
- [ ] `docs/features.md` - Application URL feature description
- [ ] `docs/api.md` - API endpoint documentation
**Check for**:
- [ ] Correct endpoint URLs
- [ ] Accurate request/response examples
- [ ] No broken links
- [ ] Screenshots or references are accurate (if present)
- [ ] Examples can be copy-pasted and work
- [ ] No typos or formatting issues
- [ ] Matches actual UI labels and messages
---
## Acceptance Criteria
All test scenarios must pass with the following results:
- [ ] All valid URLs are accepted and saved
- [ ] All invalid URLs are rejected with clear errors
- [ ] Invite preview shows correct URL when configured
- [ ] Warning appears when URL is not configured
- [ ] Multi-language support works in all 5 languages
- [ ] Admin-only access is enforced
- [ ] Settings persist across restarts
- [ ] Edge cases are handled gracefully
- [ ] UI is intuitive and accessible
- [ ] Documentation is accurate and helpful
---
## Testing Notes
**Test Environment**:
- Charon Version: _________________
- Browser: _________________
- OS: _________________
- Database: SQLite / PostgreSQL (circle one)
**Special Considerations**:
- Test with both HTTP and HTTPS configured URLs
- Verify SMTP integration if configured
- Test on actual external network if possible
- Consider firewall/proxy configurations
---
**Tester**: ________________
**Date**: ________________
**Result**: [ ] PASS / [ ] FAIL
**Issues Found** (if any):
1. ___________________________________________
2. ___________________________________________
3. ___________________________________________
**Notes**:
________________________________________________________________
________________________________________________________________
________________________________________________________________

View File

@@ -1,117 +0,0 @@
---
title: "Issue #365: Additional Security Enhancements - Manual Test Plan"
labels:
- manual-testing
- security
- testing
type: testing
priority: medium
parent_issue: 365
---
# Issue #365: Additional Security Enhancements - Manual Test Plan
**Issue**: <https://github.com/Wikid82/Charon/issues/365>
**PRs**: #436, #437
**Status**: Ready for Manual Testing
---
## Test Scenarios
### 1. Invite Token Security
**Objective**: Verify constant-time token comparison doesn't leak timing information.
**Steps**:
1. Create a new user invite via the admin UI
2. Copy the invite token from the generated link
3. Attempt to accept the invite with the correct token - should succeed
4. Attempt to accept with a token that differs only in the last character - should fail with same response time
5. Attempt to accept with a completely wrong token - should fail with same response time
**Expected**: Response times should be consistent regardless of where the token differs.
---
### 2. Security Headers Verification
**Objective**: Verify all security headers are present.
**Steps**:
1. Start Charon with HTTPS enabled
2. Use browser dev tools or curl to inspect response headers
3. Verify presence of:
- `Content-Security-Policy`
- `Strict-Transport-Security` (with preload)
- `X-Frame-Options: DENY`
- `X-Content-Type-Options: nosniff`
- `Referrer-Policy`
- `Permissions-Policy`
**curl command**:
```bash
curl -I https://your-charon-instance.com/
```
---
### 3. Container Hardening (Optional - Production)
**Objective**: Verify documented container hardening works.
**Steps**:
1. Deploy Charon using the hardened docker-compose config from docs/security.md
2. Verify container starts successfully with `read_only: true`
3. Verify all functionality works (proxy hosts, certificates, etc.)
4. Verify logs are written to tmpfs mount
---
### 4. Documentation Review
**Objective**: Verify all documentation is accurate and complete.
**Pages to Review**:
- [ ] `docs/security.md` - TLS, DNS, Container Hardening sections
- [ ] `docs/security-incident-response.md` - SIRP document
- [ ] `docs/getting-started.md` - Security Update Notifications section
**Check for**:
- Correct code examples
- Working links
- No typos or formatting issues
---
### 5. SBOM Generation (CI/CD)
**Objective**: Verify SBOM is generated on release builds.
**Steps**:
1. Push a commit to trigger a non-PR build
2. Check GitHub Actions workflow run
3. Verify "Generate SBOM" step completes successfully
4. Verify "Attest SBOM" step completes successfully
5. Verify attestation is visible in GitHub container registry
---
## Acceptance Criteria
- [ ] All test scenarios pass
- [ ] No regressions in existing functionality
- [ ] Documentation is accurate and helpful
---
**Tester**: ________________
**Date**: ________________
**Result**: [ ] PASS / [ ] FAIL

View File

@@ -1,601 +0,0 @@
# Manual Testing Plan: Sidebar Scrolling & Fixed Header UI/UX
**Feature**: Sidebar Navigation Scrolling and Fixed Header Bar
**Branch**: `feature/beta-release`
**Created**: December 21, 2025
**Status**: Ready for Manual Testing
---
## Overview
This manual test plan focuses on validating the UI/UX improvements for:
1. **Scrollable Sidebar Navigation**: Ensures logout button remains accessible when submenus expand
2. **Fixed Header Bar**: Keeps header visible when scrolling page content
---
## Test Environment Setup
### Prerequisites
- [ ] Latest code from `feature/beta-release` branch pulled
- [ ] Frontend dependencies installed: `cd frontend && npm install`
- [ ] Development server running: `npm run dev`
- [ ] Browser DevTools open for console error monitoring
### Test Browsers
- [ ] Chrome/Edge (Chromium-based)
- [ ] Firefox
- [ ] Safari (if available)
### Test Modes
- [ ] Light theme
- [ ] Dark theme
- [ ] Desktop viewport (≥1024px width)
- [ ] Mobile viewport (<1024px width)
---
## Test Suite 1: Sidebar Navigation Scrolling
### Test Case 1.1: Expanded Sidebar with All Submenus Open
**Steps**:
1. Open Charon in browser at desktop resolution (≥1024px)
2. Ensure sidebar is expanded (click hamburger if collapsed)
3. Click "Settings" menu item to expand its submenu
4. Click "Tasks" menu item to expand its submenu
5. Expand any nested submenus within Tasks
6. Click "Security" menu item to expand its submenu
7. Scroll within the sidebar navigation area
**Expected Results**:
- [ ] Sidebar navigation area shows a subtle scrollbar when content overflows
- [ ] Scrollbar is styled with custom colors matching the theme
- [ ] Logout button remains visible at the bottom of the sidebar
- [ ] Version info remains visible above the logout button
- [ ] Scrollbar thumb color is semi-transparent gray in light mode
- [ ] Scrollbar thumb color is lighter in dark mode
- [ ] Smooth scrolling behavior (no jank or stutter)
**Bug Indicators**:
- ❌ Logout button pushed off-screen
- ❌ Harsh default scrollbar styling
- ❌ No scrollbar when content overflows
- ❌ Layout jumps or visual glitches
---
### Test Case 1.2: Collapsed Sidebar State
**Steps**:
1. Click the hamburger menu icon to collapse the sidebar
2. Observe the compact icon-only sidebar
**Expected Results**:
- [ ] Collapsed sidebar shows only icons
- [ ] Logout icon remains visible at bottom
- [ ] No scrollbar needed (all items fit in viewport height)
- [ ] Hover tooltips work for each icon
- [ ] Smooth transition animation when collapsing
**Bug Indicators**:
- ❌ Logout icon not visible
- ❌ Jerky collapse animation
- ❌ Icons overlapping or misaligned
---
### Test Case 1.3: Sidebar Scrollbar Interactivity
**Steps**:
1. Expand sidebar with multiple submenus open (repeat Test Case 1.1 steps 2-6)
2. Hover over the scrollbar
3. Click and drag the scrollbar thumb
4. Use mouse wheel to scroll
5. Use keyboard arrow keys to navigate menu items
**Expected Results**:
- [ ] Scrollbar thumb becomes slightly more opaque on hover
- [ ] Dragging scrollbar thumb scrolls content smoothly
- [ ] Mouse wheel scrolling works within sidebar
- [ ] Keyboard navigation (Tab, Arrow keys) works
- [ ] Active menu item scrolls into view when selected via keyboard
**Bug Indicators**:
- ❌ Scrollbar not interactive
- ❌ Keyboard navigation broken
- ❌ Scrolling feels laggy or stutters
---
### Test Case 1.4: Mobile Sidebar Behavior
**Steps**:
1. Resize browser to mobile viewport (<1024px) or use DevTools device emulation
2. Click hamburger menu to open mobile sidebar overlay
3. Expand multiple submenus
4. Scroll within the sidebar
**Expected Results**:
- [ ] Sidebar appears as overlay with backdrop
- [ ] Navigation area is scrollable if content overflows
- [ ] Logout button remains at bottom
- [ ] Same scrollbar styling as desktop
- [ ] Closing sidebar (click backdrop or X) works smoothly
**Bug Indicators**:
- ❌ Mobile sidebar not scrollable
- ❌ Logout button hidden on mobile
- ❌ Backdrop not dismissing sidebar
---
## Test Suite 2: Fixed Header Bar
### Test Case 2.1: Header Visibility During Content Scroll
**Steps**:
1. Navigate to a page with long content (e.g., Proxy Hosts with many entries)
2. Scroll down the page content at least 500px
3. Continue scrolling to bottom of page
4. Scroll back to top
**Expected Results**:
- [ ] Desktop header bar remains fixed at top of viewport
- [ ] Header does not scroll with content
- [ ] Header background and border remain visible
- [ ] All header elements remain interactive (notifications, theme toggle, etc.)
- [ ] No layout shift or jank when scrolling
- [ ] Content scrolls smoothly beneath the header
**Bug Indicators**:
- ❌ Header scrolls off-screen with content
- ❌ Header jumps or stutters
- ❌ Buttons in header become unresponsive
- ❌ Layout shifts causing horizontal scrollbar
---
### Test Case 2.2: Header Element Interactivity
**Steps**:
1. With page scrolled down (header should be at top of viewport)
2. Click the sidebar collapse/expand button in header
3. Click the notifications icon
4. Click the theme toggle button
5. Open the user menu dropdown (if present)
**Expected Results**:
- [ ] Sidebar collapse button works correctly
- [ ] Notifications dropdown opens anchored to header
- [ ] Theme toggle switches between light/dark mode
- [ ] Dropdowns appear above content (correct z-index)
- [ ] All click targets remain accurate (no misalignment)
**Bug Indicators**:
- ❌ Dropdowns appear behind header or content
- ❌ Buttons not responding to clicks
- ❌ Dropdowns positioned incorrectly
---
### Test Case 2.3: Mobile Header Behavior
**Steps**:
1. Resize to mobile viewport (<1024px)
2. Scroll page content down
3. Observe mobile header behavior
**Expected Results**:
- [ ] Mobile header remains fixed at top (existing behavior preserved)
- [ ] No regressions in mobile header functionality
- [ ] Sidebar toggle button works
- [ ] Content scrolls beneath mobile header
**Bug Indicators**:
- ❌ Mobile header scrolls away
- ❌ Mobile header overlaps with content
- ❌ Hamburger menu not working
---
### Test Case 2.4: Header Z-Index Hierarchy
**Steps**:
1. Desktop viewport (≥1024px)
2. Open the notifications dropdown from header
3. Observe dropdown positioning relative to header
4. Open sidebar (expand if collapsed)
5. Observe sidebar relative to header
**Expected Results**:
- [ ] Sidebar (z-30) appears above header (z-10) ✅
- [ ] Dropdowns in header appear correctly (not behind content)
- [ ] No visual overlapping issues
- [ ] Proper layering: Content < Header < Dropdowns < Sidebar < Modals
**Bug Indicators**:
- ❌ Dropdown hidden behind header
- ❌ Sidebar hidden behind header
- ❌ Content appearing above header
---
## Test Suite 3: Responsive Design & Theme Switching
### Test Case 3.1: Viewport Resize Behavior
**Steps**:
1. Start at desktop viewport (≥1024px)
2. Expand sidebar with submenus
3. Slowly resize browser width from 1400px → 1000px → 768px → 375px
4. Observe layout transitions at breakpoints
**Expected Results**:
- [ ] Smooth transition at 1024px breakpoint (desktop ↔ mobile)
- [ ] Sidebar transitions from expanded to overlay mode
- [ ] Header transitions from desktop to mobile style
- [ ] No horizontal scrollbars at any viewport size
- [ ] Content remains readable and accessible
- [ ] Scrolling continues to work in both modes
**Bug Indicators**:
- ❌ Layout breaks at specific widths
- ❌ Horizontal scrollbar appears
- ❌ Elements overlap or get cut off
- ❌ Sudden jumps instead of smooth transitions
---
### Test Case 3.2: Dark/Light Theme Toggle with Scroll State
**Steps**:
1. Expand sidebar with multiple submenus
2. Scroll sidebar to middle position (logout button out of view above)
3. Toggle between light and dark themes
4. Scroll page content down
5. Toggle theme again
**Expected Results**:
- [ ] Sidebar scroll position preserved after theme toggle
- [ ] Scrollbar styling updates to match new theme
- [ ] Header background color updates correctly
- [ ] Content scroll position preserved after theme toggle
- [ ] No flashing or visual glitches during theme transition
**Bug Indicators**:
- ❌ Scroll position resets to top
- ❌ Scrollbar styling not updating
- ❌ Layout shifts during theme change
- ❌ Flash of unstyled content
---
### Test Case 3.3: Browser Zoom Levels
**Steps**:
1. Set browser zoom to 50% (Ctrl/Cmd + Mouse wheel or View menu)
2. Verify sidebar scrolling and header behavior
3. Set browser zoom to 100% (default)
4. Verify functionality
5. Set browser zoom to 200%
6. Verify functionality
**Expected Results**:
- [ ] Sidebar scrolling works at all zoom levels
- [ ] Header remains fixed at all zoom levels
- [ ] No horizontal scrollbars introduced by zoom
- [ ] Text remains readable
- [ ] Layout remains functional
**Bug Indicators**:
- ❌ Horizontal scrollbars at high zoom
- ❌ Elements overlap at extreme zoom levels
- ❌ Scrolling broken at specific zoom
- ❌ Text or icons cut off
---
## Test Suite 4: Cross-Browser Compatibility
### Test Case 4.1: Chrome/Edge (Chromium)
**Steps**:
1. Run all test suites 1-3 in Chrome or Edge
2. Open DevTools Console and check for errors
3. Monitor Performance tab for any issues
**Expected Results**:
- [ ] All features work as expected
- [ ] No console errors related to layout or scrolling
- [ ] Smooth 60fps scrolling in Performance tab
- [ ] Custom scrollbar styling applied correctly
---
### Test Case 4.2: Firefox
**Steps**:
1. Open Charon in Firefox
2. Run all test suites 1-3
3. Verify Firefox-specific scrollbar styling (`scrollbar-width: thin`)
**Expected Results**:
- [ ] All features work as expected
- [ ] Firefox thin scrollbar styling applied
- [ ] Scrollbar color matches theme (via `scrollbar-color` property)
- [ ] No layout differences compared to Chrome
**Bug Indicators**:
- ❌ Thick default scrollbar in Firefox
- ❌ Layout differences from Chrome
---
### Test Case 4.3: Safari (if available)
**Steps**:
1. Open Charon in Safari (macOS)
2. Run all test suites 1-3
3. Verify `position: sticky` works correctly
**Expected Results**:
- [ ] Header `position: sticky` works (Safari 13+ supports this)
- [ ] All features work as expected
- [ ] WebKit scrollbar styling applied
- [ ] Smooth scrolling on trackpad
**Bug Indicators**:
- ❌ Header not sticking in Safari
- ❌ Scrollbar styling not applied
- ❌ Stuttery scrolling
---
## Test Suite 5: Accessibility & Keyboard Navigation
### Test Case 5.1: Keyboard Navigation Through Sidebar
**Steps**:
1. Click in browser address bar, then press Tab to enter page
2. Use Tab key to navigate through sidebar menu items
3. Expand submenus using Enter or Space keys
4. Continue tabbing through all menu items
5. Tab to logout button
**Expected Results**:
- [ ] Focus indicator visible on each menu item
- [ ] Focused items scroll into view automatically
- [ ] Can reach and activate logout button via keyboard
- [ ] No keyboard traps (can Tab out of sidebar)
- [ ] Focus order is logical (top to bottom)
**Bug Indicators**:
- ❌ Focused items not scrolling into view
- ❌ Cannot reach logout button via keyboard
- ❌ Focus indicator not visible
- ❌ Keyboard trapped in sidebar
---
### Test Case 5.2: Screen Reader Testing (Optional)
**Steps**:
1. Enable screen reader (NVDA, JAWS, VoiceOver)
2. Navigate through sidebar menu
3. Navigate through header elements
**Expected Results**:
- [ ] Sidebar navigation announced as "navigation" landmark
- [ ] Menu items announced with proper labels
- [ ] Current page announced correctly
- [ ] Header elements announced with proper labels
- [ ] No unexpected focus changes
---
## Test Suite 6: Performance & Edge Cases
### Test Case 6.1: Rapid Sidebar Collapse/Expand
**Steps**:
1. Rapidly click sidebar collapse button 10 times
2. Observe for memory leaks or performance degradation
**Expected Results**:
- [ ] Smooth transitions even with rapid toggling
- [ ] No memory leaks (check DevTools Memory tab)
- [ ] No console errors
- [ ] Animations complete correctly
**Bug Indicators**:
- ❌ Animations stuttering after multiple toggles
- ❌ Memory usage increasing
- ❌ Console errors appearing
---
### Test Case 6.2: Long Page Content Stress Test
**Steps**:
1. Navigate to Proxy Hosts page
2. If limited data, use browser DevTools to inject 100+ fake host entries into the list
3. Scroll from top to bottom of the page rapidly
**Expected Results**:
- [ ] Header remains fixed throughout scroll
- [ ] No layout thrashing or repaints (check DevTools Performance)
- [ ] Smooth scrolling even with large DOM
- [ ] No memory leaks
**Bug Indicators**:
- ❌ Stuttering during scroll
- ❌ Header jumping or flickering
- ❌ Performance degradation with large lists
---
### Test Case 6.3: Focus Management After Scroll
**Steps**:
1. Focus an element in header (e.g., notifications button)
2. Scroll page content down 500px
3. Click focused element
4. Expand sidebar and scroll it
5. Focus logout button
6. Verify button remains visible
**Expected Results**:
- [ ] Focused elements in header remain accessible
- [ ] Clicking focused elements works correctly
- [ ] Focused elements in sidebar scroll into view
- [ ] No focus lost during scrolling
**Bug Indicators**:
- ❌ Focused element not visible after scroll
- ❌ Click targets misaligned
- ❌ Focus lost unexpectedly
---
## Known Issues & Expected Behavior
### Not a Bug (Expected)
- **Existing Linting Warnings**: 40 pre-existing TypeScript warnings unrelated to this change
- **Nested Sticky Elements**: Child components using `position: sticky` will be relative to content scroll container, not viewport (documented limitation)
- **Safari <13**: `position: sticky` not supported in very old Safari versions (not a target)
### Future Enhancements
- Smooth scroll to active menu item on page load
- Header shadow effect when content scrolls beneath
- Collapse sidebar automatically on mobile after navigation
---
## Bug Reporting Template
If you find a bug during testing, please report it with the following details:
```markdown
**Test Case**: [e.g., Test Case 1.1]
**Browser**: [e.g., Chrome 120 on Windows 11]
**Viewport**: [e.g., Desktop 1920x1080]
**Theme**: [e.g., Dark mode]
**Steps to Reproduce**:
1. [Step 1]
2. [Step 2]
3. [Step 3]
**Expected Result**:
[What should happen]
**Actual Result**:
[What actually happened]
**Screenshot/Video**:
[Attach if possible]
**Console Errors**:
```
[Paste any console errors]
```
**Severity**: [Critical / High / Medium / Low]
```
---
## Sign-Off Checklist
After completing all test suites, verify:
- [ ] All Test Suite 1 tests passed (Sidebar Scrolling)
- [ ] All Test Suite 2 tests passed (Fixed Header)
- [ ] All Test Suite 3 tests passed (Responsive & Themes)
- [ ] All Test Suite 4 tests passed (Cross-Browser)
- [ ] All Test Suite 5 tests passed (Accessibility)
- [ ] All Test Suite 6 tests passed (Performance)
- [ ] No Critical or High severity bugs found
- [ ] Medium/Low bugs documented and triaged
- [ ] Tested in at least 2 browsers (Chrome + Firefox/Safari)
- [ ] Tested in both light and dark themes
- [ ] Tested at mobile and desktop viewports
---
**Tester Name**: ___________________________
**Date Tested**: ___________________________
**Branch**: `feature/beta-release`
**Commit SHA**: ___________________________
**Overall Result**: [ ] PASS / [ ] FAIL
---
## Additional Notes
[Add any observations, edge cases discovered, or suggestions here]

View File

@@ -1,457 +0,0 @@
# Manual Test Plan: CodeQL CI Alignment
**Test Date:** December 24, 2025
**Feature:** CodeQL CI/Local Execution Alignment
**Target Release:** Next release after implementation merge
**Testers:** Development team, QA, Security reviewers
## Test Objective
Validate that local CodeQL scans match CI execution and that developers can catch security issues before pushing code.
---
## Prerequisites
- [ ] Implementation merged to main branch
- [ ] CodeQL CLI installed (minimum v2.17.0)
- Check version: `codeql version`
- Upgrade if needed: `gh codeql set-version latest`
- [ ] Pre-commit installed: `pip install pre-commit`
- [ ] Pre-commit hooks installed: `pre-commit install`
- [ ] VS Code with workspace open
---
## Test Cases
### TC1: VS Code Task Execution - Go Scan
**Objective:** Verify Go CodeQL scan runs successfully with CI-aligned parameters
**Steps:**
1. Open VS Code Command Palette (`Ctrl+Shift+P`)
2. Type "Tasks: Run Task"
3. Select `Security: CodeQL Go Scan (CI-Aligned) [~60s]`
4. Wait for completion (~60 seconds)
**Expected Results:**
- [ ] Task completes successfully (no errors)
- [ ] Output shows database creation progress
- [ ] Output shows query execution progress
- [ ] SARIF file generated: `codeql-results-go.sarif`
- [ ] Database created: `codeql-db-go/`
- [ ] Terminal output includes findings count (e.g., "79 results")
- [ ] Uses `security-and-quality` suite (visible in output)
**Pass Criteria:** All items checked ✅
---
### TC2: VS Code Task Execution - JavaScript Scan
**Objective:** Verify JavaScript/TypeScript CodeQL scan runs with CI-aligned parameters
**Steps:**
1. Open VS Code Command Palette
2. Type "Tasks: Run Task"
3. Select `Security: CodeQL JS Scan (CI-Aligned) [~90s]`
4. Wait for completion (~90 seconds)
**Expected Results:**
- [ ] Task completes successfully
- [ ] Output shows database creation for frontend source
- [ ] Output shows query execution progress (202 queries)
- [ ] SARIF file generated: `codeql-results-js.sarif`
- [ ] Database created: `codeql-db-js/`
- [ ] Terminal output includes findings count (e.g., "105 results")
- [ ] Uses `security-and-quality` suite
**Pass Criteria:** All items checked ✅
---
### TC3: VS Code Combined Task
**Objective:** Verify sequential execution of both scans
**Steps:**
1. Open VS Code Command Palette
2. Type "Tasks: Run Task"
3. Select `Security: CodeQL All (CI-Aligned)`
4. Wait for completion (~3 minutes)
**Expected Results:**
- [ ] Go scan executes first
- [ ] JavaScript scan executes second (after Go completes)
- [ ] Both SARIF files generated
- [ ] Both databases created
- [ ] No errors or failures
- [ ] Terminal shows sequential progress
**Pass Criteria:** All items checked ✅
---
### TC4: Pre-Commit Hook - Quick Security Check
**Objective:** Verify govulncheck runs on commit
**Steps:**
1. Open terminal in project root
2. Make a trivial change to any `.go` file (add comment)
3. Stage file: `git add <file>`
4. Attempt commit: `git commit -m "test: manual test"`
5. Observe pre-commit execution
**Expected Results:**
- [ ] Pre-commit hook triggers automatically
- [ ] `security-scan` stage executes
- [ ] `govulncheck` runs on backend code
- [ ] Completes in < 10 seconds
- [ ] Shows "Passed" if no vulnerabilities
- [ ] Commit succeeds if all hooks pass
**Pass Criteria:** All items checked ✅
**Note:** This is a fast check. Full CodeQL scans are manual stage (next test).
---
### TC5: Pre-Commit Hook - Manual CodeQL Scan
**Objective:** Verify manual-stage CodeQL scans work via pre-commit
**Steps:**
1. Open terminal in project root
2. Run manual stage: `pre-commit run --hook-stage manual codeql-go-scan --all-files`
3. Wait for completion (~60s)
4. Run: `pre-commit run --hook-stage manual codeql-js-scan --all-files`
5. Run: `pre-commit run --hook-stage manual codeql-check-findings --all-files`
**Expected Results:**
- [ ] `codeql-go-scan` executes successfully
- [ ] `codeql-js-scan` executes successfully
- [ ] `codeql-check-findings` checks SARIF files
- [ ] All hooks show "Passed" status
- [ ] SARIF files generated/updated
- [ ] Error-level findings reported (if any)
**Pass Criteria:** All items checked ✅
---
### TC6: Pre-Commit Hook - Severity Blocking
**Objective:** Verify that ERROR-level findings block the hook
**Steps:**
1. Temporarily introduce a known security issue (e.g., SQL injection)
```go
// In any handler file, add:
query := "SELECT * FROM users WHERE id = " + userInput
```
2. Run: `pre-commit run --hook-stage manual codeql-go-scan --all-files`
3. Run: `pre-commit run --hook-stage manual codeql-check-findings --all-files`
4. Observe output
**Expected Results:**
- [ ] CodeQL scan completes
- [ ] `codeql-check-findings` hook **FAILS**
- [ ] Error message shows high-severity finding
- [ ] Hook exit code is non-zero (blocks commit)
- [ ] Error includes CWE number and description
**Pass Criteria:** Hook fails as expected ✅
**Cleanup:** Remove test code before proceeding.
---
### TC7: SARIF File Validation
**Objective:** Verify SARIF files are GitHub-compatible
**Steps:**
1. Run any CodeQL scan (TC1 or TC2)
2. Open generated SARIF file in text editor
3. Validate JSON structure
4. Check for required fields
**Expected Results:**
- [ ] File is valid JSON
- [ ] Contains `$schema` property
- [ ] Contains `runs` array with results
- [ ] Each result has:
- [ ] `ruleId` (e.g., "go/sql-injection")
- [ ] `level` (e.g., "error", "warning")
- [ ] `message` with description
- [ ] `locations` with file path and line number
- [ ] Compatible with GitHub Code Scanning API
**Pass Criteria:** All items checked ✅
---
### TC8: CI Workflow Verification
**Objective:** Verify CI behavior matches local execution
**Steps:**
1. Create test branch: `git checkout -b test/codeql-alignment`
2. Make trivial change and commit
3. Push to GitHub: `git push origin test/codeql-alignment`
4. Open pull request
5. Monitor CI workflow execution
6. Review security findings in PR
**Expected Results:**
- [ ] CodeQL workflow triggers on PR
- [ ] Go and JavaScript scans execute
- [ ] Workflow uses `security-and-quality` suite
- [ ] Finding count similar to local scans
- [ ] SARIF uploaded to GitHub Security tab
- [ ] PR shows security findings (if any)
- [ ] Workflow summary shows counts and links
**Pass Criteria:** All items checked ✅
---
### TC9: Documentation Accuracy
**Objective:** Validate user-facing documentation
**Steps:**
1. Review: `docs/security/codeql-scanning.md`
2. Follow quick start instructions
3. Review: `.github/instructions/copilot-instructions.md`
4. Verify Definition of Done section
**Expected Results:**
- [ ] Quick start instructions work as documented
- [ ] Command examples are accurate
- [ ] Task names match VS Code tasks
- [ ] Pre-commit commands execute correctly
- [ ] DoD includes security scan requirements
- [ ] Links to documentation are valid
**Pass Criteria:** All items checked ✅
---
### TC10: Performance Validation
**Objective:** Verify scan execution times are reasonable
**Steps:**
1. Run Go scan via VS Code task
2. Measure execution time
3. Run JS scan via VS Code task
4. Measure execution time
**Expected Results:**
- [ ] Go scan completes in **50-70 seconds**
- [ ] JS scan completes in **80-100 seconds**
- [ ] Combined scan completes in **2.5-3.5 minutes**
- [ ] No memory exhaustion errors
- [ ] No timeout errors
**Pass Criteria:** All times within acceptable range ✅
---
## Regression Tests
### RT1: Existing Workflows Unaffected
**Objective:** Ensure other CI workflows still pass
**Steps:**
1. Run full CI suite on test branch
2. Check all workflow statuses
**Expected Results:**
- [ ] Build workflows pass
- [ ] Test workflows pass
- [ ] Lint workflows pass
- [ ] Other security scans pass (Trivy, gosec)
- [ ] Coverage requirements met
**Pass Criteria:** No regressions ✅
---
### RT2: Developer Workflow Unchanged
**Objective:** Verify normal development isn't disrupted
**Steps:**
1. Make code changes (normal development)
2. Run existing VS Code tasks (Build, Test, Lint)
3. Commit changes with pre-commit hooks
4. Push to branch
**Expected Results:**
- [ ] Existing tasks work normally
- [ ] Fast pre-commit hooks run automatically
- [ ] Manual CodeQL scans are opt-in
- [ ] No unexpected delays or errors
- [ ] Developer experience is smooth
**Pass Criteria:** No disruptions ✅
---
## Known Issues / Expected Findings
### Expected CodeQL Findings (as of test date)
Based on QA report, these findings are expected:
**Go (79 findings):**
- Email injection (CWE-640): 3 findings
- SSRF (CWE-918): 2 findings
- Log injection (CWE-117): 10 findings
- Quality issues: 64 findings (redundant code, missing checks)
**JavaScript (105 findings):**
- DOM-based XSS (CWE-079): 1 finding
- Incomplete validation (CWE-020): 4 findings
- Quality issues: 100 findings (mostly in minified dist/ bundles)
**Note:** These are not test failures. They are real findings that should be triaged and addressed in future work.
---
## Test Summary Template
**Tester Name:** _________________
**Test Date:** _________________
**Branch Tested:** _________________
**CodeQL Version:** _________________
| Test Case | Status | Notes |
|-----------|--------|-------|
| TC1: Go Scan | ☐ Pass ☐ Fail | |
| TC2: JS Scan | ☐ Pass ☐ Fail | |
| TC3: Combined | ☐ Pass ☐ Fail | |
| TC4: Quick Check | ☐ Pass ☐ Fail | |
| TC5: Manual Scan | ☐ Pass ☐ Fail | |
| TC6: Severity Block | ☐ Pass ☐ Fail | |
| TC7: SARIF Valid | ☐ Pass ☐ Fail | |
| TC8: CI Match | ☐ Pass ☐ Fail | |
| TC9: Docs Accurate | ☐ Pass ☐ Fail | |
| TC10: Performance | ☐ Pass ☐ Fail | |
| RT1: No Regressions | ☐ Pass ☐ Fail | |
| RT2: Dev Workflow | ☐ Pass ☐ Fail | |
**Overall Result:** ☐ **PASS** ☐ **FAIL**
**Blockers Found:**
- None / List blockers here
**Recommendations:**
- None / List improvements here
**Sign-Off:**
- [ ] All critical tests passed
- [ ] Documentation is accurate
- [ ] No major issues found
- [ ] Ready for production use
**Tester Signature:** _________________
**Date:** _________________
---
## Appendix: Troubleshooting
### Issue: CodeQL not found
**Solution:**
```bash
# Install/upgrade CodeQL
gh codeql set-version latest
codeql version # Verify installation
```
### Issue: Predicate compatibility error
**Symptom:** Error about missing predicates or incompatible query packs
**Solution:**
```bash
# Upgrade CodeQL to v2.17.0 or newer
gh codeql set-version latest
# Clear cache
rm -rf ~/.codeql/
# Re-run scan
```
### Issue: Pre-commit hooks not running
**Solution:**
```bash
# Reinstall hooks
pre-commit uninstall
pre-commit install
# Verify
pre-commit run --all-files
```
### Issue: SARIF file not generated
**Solution:**
```bash
# Check permissions
ls -la codeql-*.sarif
# Check disk space
df -h
# Re-run with verbose output
codeql database analyze --verbose ...
```
---
**End of Manual Test Plan**

File diff suppressed because it is too large Load Diff

View File

@@ -1,166 +0,0 @@
# SSRF Protection Manual Test Plan
**Issue Tracking**: Manual QA Verification for SSRF Remediation
**Status**: Ready for QA
**Priority**: HIGH
**Related**: [ssrf-protection.md](../security/ssrf-protection.md)
---
## Prerequisites
- Charon instance running (Docker or local)
- Admin credentials
- Access to API endpoints
- cURL or similar HTTP client
---
## Test Cases
### 1. Private IP Blocking (RFC 1918)
| Test ID | Input URL | Expected Result |
|---------|-----------|-----------------|
| SSRF-001 | `http://10.0.0.1/webhook` | ❌ Blocked: "private IP address" |
| SSRF-002 | `http://10.255.255.255/webhook` | ❌ Blocked |
| SSRF-003 | `http://172.16.0.1/webhook` | ❌ Blocked |
| SSRF-004 | `http://172.31.255.255/webhook` | ❌ Blocked |
| SSRF-005 | `http://192.168.0.1/webhook` | ❌ Blocked |
| SSRF-006 | `http://192.168.255.255/webhook` | ❌ Blocked |
**Command**:
```bash
curl -X POST http://localhost:8080/api/v1/settings/test-url \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <token>" \
-d '{"url": "http://10.0.0.1/webhook"}'
```
**Expected Response**: HTTP 400 with error containing "private IP"
---
### 2. Localhost Blocking
| Test ID | Input URL | Expected Result |
|---------|-----------|-----------------|
| SSRF-010 | `http://127.0.0.1/admin` | ❌ Blocked: "localhost" |
| SSRF-011 | `http://127.0.0.2/admin` | ❌ Blocked |
| SSRF-012 | `http://localhost/admin` | ❌ Blocked |
| SSRF-013 | `http://localhost:8080/api` | ❌ Blocked |
| SSRF-014 | `http://[::1]/admin` | ❌ Blocked |
**Expected Response**: HTTP 400 with error containing "localhost"
---
### 3. Cloud Metadata Blocking
| Test ID | Input URL | Expected Result |
|---------|-----------|-----------------|
| SSRF-020 | `http://169.254.169.254/` | ❌ Blocked: "private IP" |
| SSRF-021 | `http://169.254.169.254/latest/meta-data/` | ❌ Blocked |
| SSRF-022 | `http://169.254.169.254/latest/meta-data/iam/security-credentials/` | ❌ Blocked |
| SSRF-023 | `http://169.254.0.1/` | ❌ Blocked (link-local range) |
**Command**:
```bash
curl -X POST http://localhost:8080/api/v1/settings/test-url \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <token>" \
-d '{"url": "http://169.254.169.254/latest/meta-data/"}'
```
---
### 4. Legitimate External URLs
| Test ID | Input URL | Expected Result |
|---------|-----------|-----------------|
| SSRF-030 | `https://httpbin.org/post` | ✅ Allowed |
| SSRF-031 | `https://hooks.slack.com/services/test` | ✅ Allowed (may 404) |
| SSRF-032 | `https://api.github.com/` | ✅ Allowed |
| SSRF-033 | `https://example.com/webhook` | ✅ Allowed |
**Expected Response**: HTTP 200 with `reachable: true` or network error (not SSRF block)
---
### 5. Protocol Bypass Attempts
| Test ID | Input URL | Expected Result |
|---------|-----------|-----------------|
| SSRF-040 | `file:///etc/passwd` | ❌ Blocked: "HTTP or HTTPS" |
| SSRF-041 | `ftp://internal.server/file` | ❌ Blocked |
| SSRF-042 | `gopher://localhost:25/` | ❌ Blocked |
| SSRF-043 | `data:text/html,<script>` | ❌ Blocked |
---
### 6. IPv6-Mapped IPv4 Blocking
| Test ID | Input URL | Expected Result |
|---------|-----------|-----------------|
| SSRF-050 | `http://[::ffff:127.0.0.1]/` | ❌ Blocked |
| SSRF-051 | `http://[::ffff:10.0.0.1]/` | ❌ Blocked |
| SSRF-052 | `http://[::ffff:192.168.1.1]/` | ❌ Blocked |
| SSRF-053 | `http://[::ffff:169.254.169.254]/` | ❌ Blocked |
---
### 7. Redirect Protection
| Test ID | Scenario | Expected Result |
|---------|----------|-----------------|
| SSRF-060 | URL redirects to 127.0.0.1 | ❌ Blocked at redirect |
| SSRF-061 | URL redirects > 2 times | ❌ Stopped after 2 redirects |
| SSRF-062 | URL redirects to private IP | ❌ Blocked |
**Test Setup**: Use httpbin.org redirect:
```bash
# This should be blocked if final destination is private
curl -X POST http://localhost:8080/api/v1/settings/test-url \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <token>" \
-d '{"url": "https://httpbin.org/redirect-to?url=http://127.0.0.1/"}'
```
---
### 8. Webhook Configuration Endpoints
| Test ID | Endpoint | Payload | Expected |
|---------|----------|---------|----------|
| SSRF-070 | `POST /api/v1/settings/security/webhook` | `{"webhook_url": "http://10.0.0.1/"}` | ❌ 400 |
| SSRF-071 | `POST /api/v1/notifications/custom-webhook` | `{"webhook_url": "http://192.168.1.1/"}` | ❌ 400 |
| SSRF-072 | `POST /api/v1/settings/security/webhook` | `{"webhook_url": "https://hooks.slack.com/test"}` | ✅ 200 |
---
## Verification Checklist
- [ ] All private IP ranges blocked (10.x, 172.16-31.x, 192.168.x)
- [ ] Localhost/loopback blocked (127.x, ::1)
- [ ] Cloud metadata blocked (169.254.169.254)
- [ ] Link-local blocked (169.254.x.x, fe80::)
- [ ] Invalid schemes blocked (file, ftp, gopher, data)
- [ ] IPv6-mapped IPv4 blocked
- [ ] Redirect to private IP blocked
- [ ] Legitimate external URLs allowed
- [ ] Error messages don't leak internal details
---
## Pass Criteria
- All SSRF-0xx tests marked "Blocked" return HTTP 400
- All SSRF-0xx tests marked "Allowed" return HTTP 200 or non-security error
- No test reveals internal IP addresses or hostnames in error messages
---
**Last Updated**: December 31, 2025

View File

@@ -1,267 +0,0 @@
# Pre-Existing Test Failures
**Discovery Date:** December 23, 2025
**Discovered During:** CrowdSec Startup Fix QA Audit
**Status:** Open
**Priority:** Medium
## Overview
During comprehensive QA audit of the CrowdSec startup fix (commit `c71c996`), two categories of pre-existing test failures were discovered. These failures are **NOT related** to the CrowdSec changes and exist on the base branch (`feature/beta-release`).
## Issue 1: Handler Tests Timeout
**Package:** `github.com/Wikid82/charon/backend/internal/api/handlers`
**Severity:** Medium
**Impact:** CI/CD pipeline delays
### Symptoms
```bash
FAIL: github.com/Wikid82/charon/backend/internal/api/handlers (timeout 441s)
```
- Test suite takes 7.35 minutes (441 seconds)
- Default timeout is 10 minutes, but this is too close
- All tests eventually pass, but timing is concerning
### Root Cause
- Test suite contains numerous integration tests that make real HTTP requests
- No apparent infinite loop or deadlock
- Tests are comprehensive but slow
### Affected Tests
All handler tests, including:
- Access list handlers
- Auth handlers
- Backup handlers
- CrowdSec handlers
- Docker handlers
- Import handlers
- Notification handlers
- Proxy host handlers
- Security handlers
- User handlers
### Recommended Fix
**Option 1: Increase Timeout**
```bash
go test -timeout 15m ./internal/api/handlers/...
```
**Option 2: Split Test Suite**
```bash
# Fast unit tests
go test -short ./internal/api/handlers/...
# Slow integration tests (separate)
go test -run Integration ./internal/api/handlers/...
```
**Option 3: Optimize Tests**
- Use mocks for external HTTP calls
- Parallelize independent tests with `t.Parallel()`
- Use table-driven tests to reduce setup/teardown overhead
### Priority Justification
- **Medium** because tests do eventually pass
- Not a functional issue, timing concern only
- Can workaround with increased timeout
- Should be fixed to improve CI/CD performance
---
## Issue 2: URL Connectivity Test Failures
**Package:** `github.com/Wikid82/charon/backend/internal/utils`
**Severity:** Medium
**Impact:** URL validation feature may not work correctly for localhost
### Symptoms
```bash
FAIL: github.com/Wikid82/charon/backend/internal/utils
Coverage: 51.5% (below 85% threshold)
Failed Tests:
- TestTestURLConnectivity_Success
- TestTestURLConnectivity_Redirect
- TestTestURLConnectivity_TooManyRedirects
- TestTestURLConnectivity_StatusCodes/200_OK
- TestTestURLConnectivity_StatusCodes/201_Created
- TestTestURLConnectivity_StatusCodes/204_No_Content
- TestTestURLConnectivity_StatusCodes/301_Moved_Permanently
- TestTestURLConnectivity_StatusCodes/302_Found
- TestTestURLConnectivity_StatusCodes/400_Bad_Request
- TestTestURLConnectivity_StatusCodes/401_Unauthorized
- TestTestURLConnectivity_StatusCodes/403_Forbidden
- TestTestURLConnectivity_StatusCodes/404_Not_Found
- TestTestURLConnectivity_StatusCodes/500_Internal_Server_Error
- TestTestURLConnectivity_StatusCodes/503_Service_Unavailable
- TestTestURLConnectivity_InvalidURL/Empty_URL
- TestTestURLConnectivity_InvalidURL/Invalid_scheme
- TestTestURLConnectivity_InvalidURL/No_scheme
- TestTestURLConnectivity_Timeout
```
### Root Cause
**Error Pattern:**
```
Error: "access to private IP addresses is blocked (resolved to 127.0.0.1)"
does not contain "status 404"
```
**Analysis:**
1. Tests use `httptest.NewServer()` which binds to `127.0.0.1` (localhost)
2. URL validation code has private IP blocking for security
3. Private IP check runs BEFORE HTTP request is made
4. Tests expect HTTP status codes but get IP validation errors instead
5. This creates a mismatch between expected and actual error messages
**Code Location:**
```go
// File: backend/internal/utils/url_connectivity_test.go
// Lines: 103, 127-128, 156
// Test expects:
assert.Contains(t, err.Error(), "status 404")
// But gets:
"access to private IP addresses is blocked (resolved to 127.0.0.1)"
```
### Recommended Fix
**Option 1: Use Public Test Endpoints**
```go
func TestTestURLConnectivity_StatusCodes(t *testing.T) {
tests := []struct {
name string
statusCode int
url string
}{
{"200 OK", 200, "https://httpstat.us/200"},
{"404 Not Found", 404, "https://httpstat.us/404"},
// ... use public endpoints
}
}
```
**Option 2: Add Test-Only Bypass**
```go
// In url_connectivity.go
func TestURLConnectivity(url string) error {
// Add env var to disable private IP check for tests
if os.Getenv("CHARON_ALLOW_PRIVATE_IPS_FOR_TESTS") == "true" {
// Skip private IP validation
}
// ... rest of validation
}
// In test setup:
func TestMain(m *testing.M) {
os.Setenv("CHARON_ALLOW_PRIVATE_IPS_FOR_TESTS", "true")
code := m.Run()
os.Unsetenv("CHARON_ALLOW_PRIVATE_IPS_FOR_TESTS")
os.Exit(code)
}
```
**Option 3: Mock DNS Resolution**
```go
// Use custom dialer that returns public IPs for test domains
type testDialer struct {
realDialer *net.Dialer
}
func (d *testDialer) DialContext(ctx context.Context, network, addr string) (net.Conn, error) {
// Intercept localhost and return mock IP
if strings.HasPrefix(addr, "127.0.0.1:") {
// Return connection to test server but with public IP appearance
}
return d.realDialer.DialContext(ctx, network, addr)
}
```
### Priority Justification
- **Medium** because feature works in production
- Tests are catching security feature (private IP blocking) working as intended
- Need to fix test design, not the security feature
- Affects coverage reporting (51.5% < 85% threshold)
---
## Issue 3: Pre-commit Auto-Fix Required
**Severity:** Low
**Impact:** None (auto-fixed)
### Symptoms
```
trim trailing whitespace.................................................Failed
- hook id: trailing-whitespace
- exit code: 1
- files were modified by this hook
Fixing backend/internal/services/crowdsec_startup.go
Fixing backend/cmd/api/main.go
```
### Resolution
Pre-commit hook automatically removed trailing whitespace. Files have been fixed.
**Action Required:****NONE** (auto-fixed)
---
## Tracking
### Issue 1: Handler Tests Timeout
- **Tracking Issue:** [Create GitHub Issue]
- **Assignee:** Backend Team
- **Target Fix Date:** Next sprint
- **Workaround:** `go test -timeout 15m`
### Issue 2: URL Connectivity Tests
- **Tracking Issue:** [Create GitHub Issue]
- **Assignee:** Backend Team
- **Target Fix Date:** Next sprint
- **Workaround:** Skip tests with `-short` flag
### Issue 3: Trailing Whitespace
- **Status:** ✅ **RESOLVED** (auto-fixed)
---
## References
- QA Report: [docs/reports/qa_report_crowdsec_startup_fix.md](../reports/qa_report_crowdsec_startup_fix.md)
- Implementation Plan: [docs/plans/crowdsec_startup_fix.md](../plans/crowdsec_startup_fix.md)
- Commit: `c71c996`
- Branch: `feature/beta-release`
---
**Document Status:** Active
**Last Updated:** December 23, 2025 01:25 UTC

View File

@@ -1,339 +0,0 @@
# Manual Testing Plan: Grype SBOM Remediation
**Issue Type**: Manual Testing
**Priority**: High
**Component**: CI/CD - Supply Chain Verification
**Created**: 2026-01-10
**Related PR**: #461 (DNS Challenge Support)
---
## Objective
Manually validate the Grype SBOM remediation implementation in real-world CI/CD scenarios to ensure:
- Workflow operates correctly in all expected conditions
- Error handling is robust and user-friendly
- No regressions in existing functionality
---
## Test Environment
- **Branch**: `feature/beta-release` (current)
- **Workflow File**: `.github/workflows/supply-chain-verify.yml`
- **Trigger Events**: `pull_request`, `push to main`, `workflow_dispatch`
---
## Test Scenarios
### Scenario 1: PR Without Docker Image (Skip Path)
**Objective**: Verify workflow gracefully skips when image doesn't exist (common in PR workflows before docker-build completes).
**Prerequisites**:
- Create a test PR with code changes
- Ensure docker-build workflow has NOT completed yet
**Steps**:
1. Create/update PR on feature branch
2. Navigate to Actions → Supply Chain Verification workflow
3. Wait for workflow to complete
**Expected Results**:
- ✅ Workflow completes successfully (green check)
- ✅ "Check Image Availability" step shows "Image not found" message
- ✅ "Report Skipped Scan" step shows clear skip reason
- ✅ PR comment appears with "⏭️ Status: Image not yet available" message
- ✅ PR comment explains this is normal for PR workflows
- ✅ No false failures or error messages
**Pass Criteria**:
- [ ] Workflow status: Success (not failed or warning)
- [ ] PR comment is clear and helpful
- [ ] GitHub Step Summary shows skip reason
- [ ] No confusing error messages in logs
---
### Scenario 2: Existing Docker Image (Success Path)
**Objective**: Verify full SBOM generation, validation, and vulnerability scanning when image exists.
**Prerequisites**:
- Use a branch where docker-build has completed (e.g., `main` or merged PR)
- Image exists in GHCR: `ghcr.io/wikid82/charon:latest` or `ghcr.io/wikid82/charon:pr-XXX`
**Steps**:
1. Trigger workflow manually via `workflow_dispatch` on main branch
2. OR merge a PR and wait for automatic workflow trigger
3. Monitor workflow execution
**Expected Results**:
- ✅ "Check Image Availability" step finds image
- ✅ "Verify SBOM Completeness" step generates CycloneDX SBOM
- ✅ Syft version is logged
- ✅ "Validate SBOM File" step passes all checks:
- jq is available
- File exists and non-empty
- Valid JSON structure
- CycloneDX format confirmed
- Components found (count > 0)
- ✅ "Upload SBOM Artifact" step succeeds
- ✅ SBOM artifact available for download
- ✅ "Scan for Vulnerabilities" step:
- Grype DB updates successfully
- Scan completes without "format not recognized" error
- Vulnerability counts reported
- Results table displayed
- ✅ PR comment (if PR) shows vulnerability summary table
- ✅ No "sbom format not recognized" errors
**Pass Criteria**:
- [ ] Workflow status: Success
- [ ] SBOM artifact uploaded and downloadable
- [ ] Grype scan completes without format errors
- [ ] Vulnerability counts accurate (Critical/High/Medium/Low)
- [ ] PR comment shows detailed results (if applicable)
- [ ] No false positives
---
### Scenario 3: Invalid/Corrupted SBOM (Validation Path)
**Objective**: Verify SBOM validation catches malformed files before passing to Grype.
**Prerequisites**:
- Requires temporarily modifying workflow to introduce error (NOT for production testing)
- OR wait for natural occurrence (unlikely)
**Alternative Testing**:
This scenario is validated through code review and unit testing of validation logic. Manual testing in production environment is not recommended as it requires intentionally breaking the workflow.
**Code Review Validation** (Already Completed):
- ✅ jq availability check (lines 125-130)
- ✅ File existence check (lines 133-138)
- ✅ Non-empty check (lines 141-146)
- ✅ Valid JSON check (lines 149-156)
- ✅ CycloneDX format check (lines 159-173)
**Pass Criteria**:
- [ ] Code review confirms all validation checks present
- [ ] Error handling paths use `exit 1` for real errors
- [ ] Clear error messages at each validation point
---
### Scenario 4: Critical Vulnerabilities Detected
**Objective**: Verify workflow correctly identifies and reports critical vulnerabilities.
**Prerequisites**:
- Use an older image tag with known vulnerabilities (if available)
- OR wait for vulnerability to be discovered in current image
**Steps**:
1. Trigger workflow on image with vulnerabilities
2. Monitor vulnerability scan step
3. Check PR comment and workflow logs
**Expected Results**:
- ✅ Grype scan completes successfully
- ✅ Vulnerabilities categorized by severity
- ✅ Critical vulnerabilities trigger GitHub annotation/warning
- ✅ PR comment shows vulnerability table with non-zero counts
- ✅ PR comment includes "⚠️ Action Required" for critical vulns
- ✅ Link to full report is provided
**Pass Criteria**:
- [ ] Vulnerability counts are accurate
- [ ] Critical vulnerabilities highlighted
- [ ] Clear action guidance provided
- [ ] Links to detailed reports work
---
### Scenario 5: Workflow Performance
**Objective**: Verify workflow executes within acceptable time limits.
**Steps**:
1. Monitor workflow execution time across multiple runs
2. Check individual step durations
**Expected Results**:
- ✅ Total workflow time: < 10 minutes
- ✅ Image check: < 30 seconds
- ✅ SBOM generation: < 2 minutes
- ✅ SBOM validation: < 30 seconds
- ✅ Grype scan: < 5 minutes
- ✅ Artifact upload: < 1 minute
**Pass Criteria**:
- [ ] Average workflow time within limits
- [ ] No significant performance degradation vs. previous implementation
- [ ] No timeout failures
---
### Scenario 6: Multiple Parallel PRs
**Objective**: Verify workflow handles concurrent executions without conflicts.
**Prerequisites**:
- Create multiple PRs simultaneously
- Trigger workflows on multiple branches
**Steps**:
1. Create 3-5 PRs from different feature branches
2. Wait for workflows to run concurrently
3. Monitor all workflow executions
**Expected Results**:
- ✅ All workflows complete successfully
- ✅ No resource conflicts or race conditions
- ✅ Correct image checked for each PR (`pr-XXX` tags)
- ✅ Each PR gets its own comment
- ✅ Artifact names are unique (include tag)
**Pass Criteria**:
- [ ] All workflows succeed independently
- [ ] No cross-contamination of results
- [ ] Artifact names unique and correct
---
## Regression Testing
### Verify No Breaking Changes
**Test Areas**:
1. **Other Workflows**: Ensure docker-build.yml, codeql-analysis.yml, etc. still work
2. **Existing Releases**: Verify workflow runs successfully on existing release tags
3. **Backward Compatibility**: Old PRs can be re-run without issues
**Pass Criteria**:
- [ ] No regressions in other workflows
- [ ] Existing functionality preserved
- [ ] No unexpected failures
---
## Bug Hunting Focus Areas
Based on the implementation, pay special attention to:
1. **Conditional Logic**:
- Verify `if: steps.image-check.outputs.exists == 'true'` works correctly
- Check `if: steps.validate-sbom.outputs.valid == 'true'` gates scan properly
2. **Error Messages**:
- Ensure error messages are clear and actionable
- Verify debug output is helpful for troubleshooting
3. **Authentication**:
- GHCR authentication succeeds for private repos
- Token permissions are sufficient
4. **Artifact Handling**:
- SBOM artifacts upload correctly
- Artifact names are unique and descriptive
- Retention period is appropriate (30 days)
5. **PR Comments**:
- Comments appear on all PRs
- Markdown formatting is correct
- Links work and point to correct locations
6. **Edge Cases**:
- Very large images (slow SBOM generation)
- Images with many vulnerabilities (large scan output)
- Network failures during Grype DB update
- Rate limiting from GHCR
---
## Issue Reporting Template
If you find a bug during manual testing, create an issue with:
```markdown
**Title**: [Grype SBOM] Brief description of issue
**Scenario**: Which test scenario revealed the issue
**Expected Behavior**: What should happen
**Actual Behavior**: What actually happened
**Evidence**:
- Workflow run URL
- Relevant log excerpts
- Screenshots if applicable
**Severity**: Critical / High / Medium / Low
**Impact**: Who/what is affected
**Workaround**: If known
```
---
## Sign-Off Checklist
After completing manual testing, verify:
- [ ] Scenario 1 (Skip Path) tested and passed
- [ ] Scenario 2 (Success Path) tested and passed
- [ ] Scenario 3 (Validation) verified via code review
- [ ] Scenario 4 (Vulnerabilities) tested and passed
- [ ] Scenario 5 (Performance) verified within limits
- [ ] Scenario 6 (Parallel PRs) tested and passed
- [ ] Regression testing completed
- [ ] Bug hunting completed
- [ ] All critical issues resolved
- [ ] Documentation reviewed for accuracy
**Tester Signature**: _________________
**Date**: _________________
**Status**: ☐ PASS ☐ PASS WITH MINOR ISSUES ☐ FAIL
---
## Notes
- This manual testing plan complements automated CI/CD checks
- Focus on user experience and real-world scenarios
- Document any unexpected behavior, even if not blocking
- Update this plan based on findings for future use
---
**Status**: Ready for Manual Testing
**Last Updated**: 2026-01-10

View File

@@ -1,265 +0,0 @@
# Manual Test Plan: CI Workflow Fixes
**Created:** 2026-01-11
**PR:** #461
**Feature:** CI/CD Workflow Documentation & Supply Chain Fix
## Objective
Manually verify that the CI workflow fixes work correctly in production, focusing on finding potential bugs in the Supply Chain Verification orchestration.
## Background
**What Was Fixed:**
1. Removed `branches` filter from `supply-chain-verify.yml` to enable `workflow_run` triggering on all branches
2. Added documentation to explain the GitHub Security warning (false positive)
3. Updated SECURITY.md with comprehensive security scanning documentation
**Expected Behavior:**
- Supply Chain Verification should now trigger via `workflow_run` after Docker Build completes on ANY branch
- Previous behavior: Only triggered via `pull_request` fallback (branch filter prevented workflow_run)
## Test Scenarios
### Scenario 1: Push to Feature Branch (workflow_run Test)
**Goal:** Verify `workflow_run` trigger works on feature branches after fix
**Steps:**
1. Create a small test commit on `feature/beta-release`
2. Push the commit
3. Monitor GitHub Actions workflow runs
**Expected Results:**
- ✅ Docker Build workflow triggers and completes successfully
- ✅ Supply Chain Verification triggers **via workflow_run event** (not pull_request)
- ✅ Supply Chain completes successfully
- ✅ GitHub Actions logs show event type is `workflow_run`
**How to Verify Event Type:**
```bash
gh run list --workflow="supply-chain-verify.yml" --limit 1 --json event,conclusion
# Should show: "event": "workflow_run", "conclusion": "success"
```
**Potential Bugs to Watch For:**
- ❌ Supply Chain doesn't trigger at all
- ❌ Supply Chain triggers but fails
- ❌ Multiple simultaneous runs (race condition)
- ❌ Timeout or hang in workflow_run chain
---
### Scenario 2: PR Synchronization (Fallback Still Works)
**Goal:** Verify `pull_request` fallback trigger still works correctly
**Steps:**
1. With PR #461 open, push another small commit
2. Monitor GitHub Actions workflow runs
**Expected Results:**
- ✅ Docker Build triggers via `pull_request` event
- ✅ Supply Chain may trigger via BOTH `workflow_run` AND `pull_request` (race condition possible)
- ✅ If both trigger, both should complete successfully without conflict
- ✅ PR should show both workflow checks passing
**Potential Bugs to Watch For:**
- ❌ Duplicate runs causing conflicts
- ❌ Race condition causing failures
- ❌ PR checks showing "pending" indefinitely
- ❌ One workflow cancels the other
---
### Scenario 3: Main Branch Push (Default Branch Behavior)
**Goal:** Verify fix doesn't break main branch behavior
**Steps:**
1. After PR #461 merges to main, monitor the merge commit
2. Check GitHub Actions runs
**Expected Results:**
- ✅ Docker Build runs on main
- ✅ Supply Chain triggers via `workflow_run`
- ✅ Both complete successfully
- ✅ Weekly scheduled runs continue to work
**Potential Bugs to Watch For:**
- ❌ Main branch workflows broken
- ❌ Weekly schedule interferes with workflow_run
- ❌ Permissions issues on main branch
---
### Scenario 4: Failed Docker Build (Error Handling)
**Goal:** Verify Supply Chain doesn't trigger when Docker Build fails
**Steps:**
1. Intentionally break Docker Build (e.g., invalid Dockerfile syntax)
2. Push to a test branch
3. Monitor workflow behavior
**Expected Results:**
- ✅ Docker Build fails as expected
- ✅ Supply Chain **does NOT trigger** (workflow_run only fires on `completed` and `success`)
- ✅ No cascading failures
**Potential Bugs to Watch For:**
- ❌ Supply Chain triggers on failed builds
- ❌ Error handling missing
- ❌ Workflow stuck in pending state
---
### Scenario 5: Manual Workflow Dispatch
**Goal:** Verify manual trigger still works
**Steps:**
1. Go to GitHub Actions → Supply Chain Verification
2. Click "Run workflow"
3. Select `feature/beta-release` branch
4. Click "Run workflow"
**Expected Results:**
- ✅ Workflow starts via `workflow_dispatch` event
- ✅ Completes successfully
- ✅ SBOM and attestations generated
**Potential Bugs to Watch For:**
- ❌ Manual dispatch broken
- ❌ Branch selector doesn't work
- ❌ Workflow fails with "branch not found"
---
### Scenario 6: Weekly Scheduled Run
**Goal:** Verify scheduled trigger still works
**Steps:**
1. Wait for next Monday 00:00 UTC
2. Check GitHub Actions for scheduled run
**Expected Results:**
- ✅ Workflow triggers via `schedule` event
- ✅ Runs on main branch
- ✅ Completes successfully
**Potential Bugs to Watch For:**
- ❌ Schedule doesn't fire
- ❌ Wrong branch selected
- ❌ Interference with other workflows
---
## Edge Cases to Test
### Edge Case 1: Rapid Pushes (Rate Limiting)
**Test:** Push 3-5 commits rapidly to feature branch
**Expected:** All Docker Builds run, Supply Chain may queue or skip redundant runs
**Watch For:** Workflow queue overflow, cancellations, failures
### Edge Case 2: Long-Running Docker Build
**Test:** Create a commit that makes Docker Build take >10 minutes
**Expected:** Supply Chain waits for completion before triggering
**Watch For:** Timeouts, abandoned runs, state corruption
### Edge Case 3: Branch Deletion During Run
**Test:** Delete feature branch while workflows are running
**Expected:** Workflows complete or cancel gracefully
**Watch For:** Orphaned runs, resource leaks, errors
---
## Success Criteria
- [ ] All 6 scenarios pass without critical bugs
- [ ] `workflow_run` event type confirmed in logs
- [ ] No cascading failures
- [ ] PR checks consistently pass
- [ ] Error handling works correctly
- [ ] Manual and scheduled triggers functional
## Bug Severity Guidelines
**CRITICAL** (Block Merge):
- Supply Chain doesn't run at all
- Cascading failures breaking other workflows
- Security vulnerabilities introduced
**HIGH** (Fix Before Release):
- Race conditions causing frequent failures
- Resource leaks or orphaned workflows
- Error handling missing
**MEDIUM** (Fix in Future PR):
- Duplicate runs (but both succeed)
- Inconsistent behavior (works sometimes)
- Minor UX issues
**LOW** (Document as Known Issue):
- Cosmetic issues in logs
- Non-breaking edge cases
- Timing inconsistencies
---
## Notes for Testers
1. **Event Type Verification is Critical:** The core fix was to enable `workflow_run` on feature branches. If logs still show only `pull_request` events, the fix didn't work.
2. **False Positives are OK:** The GitHub Security warning may persist for 4-8 weeks due to tracking lag. This is expected.
3. **Timing Matters:** There may be a 1-2 second delay between Docker Build completion and Supply Chain trigger. This is normal.
4. **Logs are Essential:** Always check the "Event" field in GitHub Actions run details to confirm the trigger type.
---
## Reporting Bugs
If bugs are found during manual testing:
1. Create a new issue in `docs/issues/bug_*.md`
2. Include:
- Scenario number
- Exact steps to reproduce
- Expected vs actual behavior
- GitHub Actions run ID
- Event type from logs
- Severity classification
3. Link to this test plan
4. Assign to appropriate team member

View File

@@ -1,438 +0,0 @@
# Staticcheck Pre-Commit Integration - Manual Testing Checklist
**Purpose:** Find potential bugs and edge cases in the staticcheck blocking implementation
**Date Created:** 2026-01-11
**Target:** Pre-commit hook blocking behavior and developer workflow
---
## Testing Overview
This checklist focuses on **adversarial testing** - finding ways the implementation might fail or cause developer friction.
---
## 1. Commit Blocking Scenarios
### 1.1 Basic Blocking Behavior
- [ ] **Test:** Create a `.go` file with an unused variable, attempt commit
- **Expected:** Commit blocked, clear error message
- **Actual:** _____________________
- **Issues:** _____________________
- [ ] **Test:** Create a `.go` file with unchecked error return, attempt commit
- **Expected:** Commit blocked with errcheck error
- **Actual:** _____________________
- **Issues:** _____________________
- [ ] **Test:** Create a `.go` file with shadowed variable, attempt commit
- **Expected:** Commit blocked with govet/shadow error
- **Actual:** _____________________
- **Issues:** _____________________
### 1.2 Edge Case Files
- [ ] **Test:** Commit a `_test.go` file with lint issues
- **Expected:** Commit succeeds (test files excluded)
- **Actual:** _____________________
- **Issues:** _____________________
- [ ] **Test:** Commit Go file in subdirectory (e.g., `backend/internal/api/`)
- **Expected:** Commit blocked if issues present
- **Actual:** _____________________
- **Issues:** _____________________
- [ ] **Test:** Commit Go file in nested package (e.g., `backend/internal/api/handlers/proxy/`)
- **Expected:** Recursive linting works correctly
- **Actual:** _____________________
- **Issues:** _____________________
- [ ] **Test:** Commit `.go` file outside backend directory (edge case)
- **Expected:** Hook runs correctly or gracefully handles
- **Actual:** _____________________
- **Issues:** _____________________
### 1.3 Multiple Files
- [ ] **Test:** Stage multiple `.go` files, some with issues, some clean
- **Expected:** Commit blocked if any file has issues
- **Actual:** _____________________
- **Issues:** _____________________
- [ ] **Test:** Stage mix of `.go`, `.js`, `.md` files with only Go issues
- **Expected:** Commit blocked due to Go issues
- **Actual:** _____________________
- **Issues:** _____________________
---
## 2. Lint Error Types
### 2.1 Staticcheck Errors
- [ ] **Test:** SA1019 (deprecated API usage)
- **Example:** `filepath.HasPrefix()`
- **Expected:** Blocked with clear message
- **Actual:** _____________________
- [ ] **Test:** SA4006 (value never used)
- **Example:** `x := 1; x = 2`
- **Expected:** Blocked with clear message
- **Actual:** _____________________
- [ ] **Test:** SA1029 (string key for context.WithValue)
- **Example:** `ctx = context.WithValue(ctx, "key", "value")`
- **Expected:** Blocked with clear message
- **Actual:** _____________________
### 2.2 Other Fast Linters
- [ ] **Test:** Unchecked error (errcheck)
- **Example:** `file.Close()` without error check
- **Expected:** Blocked
- **Actual:** _____________________
- [ ] **Test:** Ineffectual assignment (ineffassign)
- **Example:** Assign value that's never read
- **Expected:** Blocked
- **Actual:** _____________________
- [ ] **Test:** Unused function/variable (unused)
- **Example:** Private function never called
- **Expected:** Blocked
- **Actual:** _____________________
- [ ] **Test:** Shadow variable (govet)
- **Example:** `:=` in inner scope shadowing outer variable
- **Expected:** Blocked
- **Actual:** _____________________
---
## 3. Emergency Bypass Scenarios
### 3.1 --no-verify Flag
- [ ] **Test:** `git commit --no-verify -m "Emergency hotfix"` with lint issues
- **Expected:** Commit succeeds, bypasses hook
- **Actual:** _____________________
- **Issues:** _____________________
- [ ] **Test:** `git commit --no-verify` without `-m` (opens editor)
- **Expected:** Commit succeeds after saving message
- **Actual:** _____________________
- **Issues:** _____________________
### 3.2 SKIP Environment Variable
- [ ] **Test:** `SKIP=golangci-lint-fast git commit -m "Test"` with issues
- **Expected:** Commit succeeds, skips specific hook
- **Actual:** _____________________
- **Issues:** _____________________
- [ ] **Test:** `SKIP=all git commit -m "Test"` (skip all hooks)
- **Expected:** All hooks skipped, commit succeeds
- **Actual:** _____________________
- **Issues:** _____________________
---
## 4. Performance Testing
### 4.1 Small Codebase
- [ ] **Test:** Commit single Go file (~100 lines)
- **Expected:** < 5 seconds
- **Actual:** _____ seconds
- **Issues:** _____________________
### 4.2 Large Commits
- [ ] **Test:** Commit 5+ Go files simultaneously
- **Expected:** < 15 seconds (scales linearly)
- **Actual:** _____ seconds
- **Issues:** _____________________
- [ ] **Test:** Commit with changes to 20+ Go files
- **Expected:** < 20 seconds (acceptable threshold)
- **Actual:** _____ seconds
- **Issues:** _____________________
### 4.3 Edge Case Performance
- [ ] **Test:** Commit Go file while golangci-lint is already running
- **Expected:** Graceful handling or reasonable wait
- **Actual:** _____________________
- **Issues:** _____________________
---
## 5. Error Handling & Messages
### 5.1 Missing golangci-lint
- [ ] **Test:** Temporarily rename golangci-lint binary, attempt commit
- **Expected:** Clear error message with installation instructions
- **Actual:** _____________________
- **Issues:** _____________________
- [ ] **Test:** Remove `$GOPATH/bin` from PATH, attempt commit
- **Expected:** Clear error about missing tool
- **Actual:** _____________________
- **Issues:** _____________________
### 5.2 Configuration Issues
- [ ] **Test:** Corrupt `.golangci-fast.yml` (invalid YAML), attempt commit
- **Expected:** Clear error about config file
- **Actual:** _____________________
- **Issues:** _____________________
- [ ] **Test:** Delete `.golangci-fast.yml`, attempt commit
- **Expected:** Falls back to default config or clear error
- **Actual:** _____________________
- **Issues:** _____________________
### 5.3 Syntax Errors
- [ ] **Test:** Commit `.go` file with syntax error (won't compile)
- **Expected:** Blocked with compilation error
- **Actual:** _____________________
- **Issues:** _____________________
---
## 6. Developer Workflow Integration
### 6.1 First-Time Setup
- [ ] **Test:** Fresh clone, `pre-commit install`, attempt commit with issues
- **Expected:** Hook runs correctly on first commit
- **Actual:** _____________________
- **Issues:** _____________________
- [ ] **Test:** Developer without golangci-lint installed
- **Expected:** Clear pre-flight error with install link
- **Actual:** _____________________
- **Issues:** _____________________
### 6.2 Manual Testing Tools
- [ ] **Test:** `make lint-fast` command
- **Expected:** Runs and reports same issues as pre-commit
- **Actual:** _____________________
- **Issues:** _____________________
- [ ] **Test:** `make lint-staticcheck-only` command
- **Expected:** Runs only staticcheck, reports subset of issues
- **Actual:** _____________________
- **Issues:** _____________________
- [ ] **Test:** VS Code task "Lint: Staticcheck (Fast)"
- **Expected:** Runs in VS Code terminal, displays issues
- **Actual:** _____________________
- **Issues:** _____________________
### 6.3 Iterative Development
- [ ] **Test:** Fix lint issue, save, immediately commit again
- **Expected:** Second commit faster due to caching
- **Actual:** _____ seconds (first), _____ seconds (second)
- **Issues:** _____________________
- [ ] **Test:** Partial fix (fix some issues, leave others), attempt commit
- **Expected:** Still blocked with remaining issues
- **Actual:** _____________________
- **Issues:** _____________________
---
## 7. Multi-Developer Scenarios
### 7.1 Git Operations
- [ ] **Test:** Pull changes with new lint issues, attempt commit unrelated file
- **Expected:** Pre-commit only checks staged files
- **Actual:** _____________________
- **Issues:** _____________________
- [ ] **Test:** Rebase interactive with lint issues in commits
- **Expected:** Each commit checked during rebase
- **Actual:** _____________________
- **Issues:** _____________________
- [ ] **Test:** Cherry-pick commit with lint issues
- **Expected:** Cherry-pick completes, hook runs on final commit
- **Actual:** _____________________
- **Issues:** _____________________
### 7.2 Branch Workflows
- [ ] **Test:** Switch branches, attempt commit with different lint issues
- **Expected:** Hook checks current branch's code
- **Actual:** _____________________
- **Issues:** _____________________
- [ ] **Test:** Merge branch with lint issues, resolve conflicts, commit
- **Expected:** Hook runs on merge commit
- **Actual:** _____________________
- **Issues:** _____________________
---
## 8. False Positive Handling
### 8.1 Legitimate Patterns
- [ ] **Test:** Use `//lint:ignore` comment for legitimate pattern
- **Expected:** Staticcheck respects ignore comment
- **Actual:** _____________________
- **Issues:** _____________________
- [ ] **Test:** Code that staticcheck flags but is correct
- **Expected:** Developer can use ignore directive
- **Actual:** _____________________
- **Issues:** _____________________
### 8.2 Generated Code
- [ ] **Test:** Commit generated Go code (e.g., protobuf)
- **Expected:** Excluded via `.golangci-fast.yml` or passes
- **Actual:** _____________________
- **Issues:** _____________________
---
## 9. Integration with Other Tools
### 9.1 Other Pre-Commit Hooks
- [ ] **Test:** Ensure trailing-whitespace hook still works
- **Expected:** Both hooks run, both can block independently
- **Actual:** _____________________
- **Issues:** _____________________
- [ ] **Test:** Ensure end-of-file-fixer hook still works
- **Expected:** Hooks run in order, all function
- **Actual:** _____________________
- **Issues:** _____________________
### 9.2 VS Code Integration
- [ ] **Test:** VS Code Problems tab updates after running lint
- **Expected:** Problems tab shows same issues as pre-commit
- **Actual:** _____________________
- **Issues:** _____________________
- [ ] **Test:** VS Code auto-format on save with lint issues
- **Expected:** Format succeeds, lint still blocks commit
- **Actual:** _____________________
- **Issues:** _____________________
---
## 10. Documentation Accuracy
### 10.1 README.md
- [ ] **Test:** Follow installation instructions exactly as written
- **Expected:** golangci-lint installs correctly
- **Actual:** _____________________
- **Issues:** _____________________
- [ ] **Test:** Verify troubleshooting section accuracy
- **Expected:** Solutions work as documented
- **Actual:** _____________________
- **Issues:** _____________________
### 10.2 copilot-instructions.md
- [ ] **Test:** Follow "Troubleshooting Pre-Commit Staticcheck Failures" guide
- **Expected:** Each troubleshooting step resolves stated issue
- **Actual:** _____________________
- **Issues:** _____________________
---
## 11. Regression Testing
### 11.1 Existing Functionality
- [ ] **Test:** Commit non-Go files (JS, MD, etc.)
- **Expected:** No impact from Go linter hook
- **Actual:** _____________________
- **Issues:** _____________________
- [ ] **Test:** Backend build still succeeds
- **Expected:** `go build ./...` exits 0
- **Actual:** _____________________
- **Issues:** _____________________
- [ ] **Test:** Backend tests still pass
- **Expected:** All tests pass with coverage > 85%
- **Actual:** _____________________
- **Issues:** _____________________
---
## 12. CI/CD Alignment
### 12.1 Local vs CI Consistency
- [ ] **Test:** Code that passes local pre-commit
- **Expected:** Should pass CI golangci-lint (if continue-on-error removed)
- **Actual:** _____________________
- **Issues:** _____________________
- [ ] **Test:** Code that fails local pre-commit
- **Expected:** CI may still pass (continue-on-error: true)
- **Actual:** _____________________
- **Issues:** _____________________
---
## Summary Template
### Bugs Found
1. **Bug:** [Description]
- **Severity:** [HIGH/MEDIUM/LOW]
- **Impact:** [Developer workflow/correctness/performance]
- **Reproduction:** [Steps]
### Friction Points
1. **Issue:** [Description]
- **Impact:** [How it affects developers]
- **Suggested Fix:** [Improvement idea]
### Documentation Gaps
1. **Gap:** [What's missing or unclear]
- **Location:** [Which file/section]
- **Suggested Addition:** [Content needed]
### Performance Issues
1. **Issue:** [Description]
- **Measured:** [Actual timing]
- **Expected:** [Target timing]
- **Threshold Exceeded:** [YES/NO]
---
## Testing Execution Log
**Tester:** _____________________
**Date:** 2026-01-__
**Environment:** [OS, Go version, golangci-lint version]
**Duration:** _____ hours
**Overall Assessment:** [PASS/FAIL with blockers/FAIL with minor issues]
**Recommendation:** [Approve/Request changes/Block merge]
---
**End of Manual Testing Checklist**

View File

@@ -1,233 +0,0 @@
# Manual Test Plan: CI Docker Build Fix Verification
**Issue**: Docker image artifact save failing with "reference does not exist" error
**Fix Date**: 2026-01-12
**Test Target**: `.github/workflows/docker-build.yml` (Save Docker Image as Artifact step)
**Test Priority**: HIGH (blocks PR builds and supply chain verification)
---
## Test Objective
Verify that the CI Docker build fix resolves the "reference does not exist" error and enables successful PR builds with artifact generation and supply chain verification.
---
## Prerequisites
- [ ] Changes merged to a feature branch or development
- [ ] Ability to create test PRs against the target branch
- [ ] Access to GitHub Actions logs for the test PR
- [ ] Understanding of expected workflow behavior
---
## Test Scenarios
### Scenario 1: Standard PR Build (Happy Path)
**Objective**: Verify normal PR build succeeds with image artifact save
**Steps**:
1. Create a test PR with a minor change (e.g., update README.md)
2. Wait for `docker-build.yml` workflow to trigger
3. Monitor the workflow execution in GitHub Actions
**Expected Results**:
- [ ]`build-and-push` job completes successfully
- [ ] ✅ "Save Docker Image as Artifact" step completes without errors
- [ ] ✅ Step output shows: "🔍 Detected image tag: ghcr.io/wikid82/charon:pr-XXX"
- [ ] ✅ Step output shows: "✅ Artifact created: /tmp/charon-pr-image.tar"
- [ ] ✅ "Upload Image Artifact" step succeeds
- [ ] ✅ Artifact `pr-image-XXX` appears in workflow artifacts
- [ ]`verify-supply-chain-pr` job starts and uses the artifact
- [ ] ✅ Supply chain verification completes successfully
**Pass Criteria**: All checks pass, no "reference does not exist" errors
---
### Scenario 2: Metadata Tag Validation
**Objective**: Verify defensive validation catches missing or invalid tags
**Steps**:
1. Review the "Save Docker Image as Artifact" step logs
2. Check for validation output
**Expected Results**:
- [ ] ✅ Step logs show: "🔍 Detected image tag: ghcr.io/wikid82/charon:pr-XXX"
- [ ] ✅ No error messages about missing tags
- [ ] ✅ Image inspection succeeds (no "not found locally" errors)
**Pass Criteria**: Validation steps execute and pass cleanly
---
### Scenario 3: Supply Chain Verification Integration
**Objective**: Verify downstream job receives and processes the artifact correctly
**Steps**:
1. Wait for `verify-supply-chain-pr` job to start
2. Check "Download Image Artifact" step
3. Check "Load Docker Image" step
4. Check "Verify Loaded Image" step
**Expected Results**:
- [ ] ✅ Artifact downloads successfully
- [ ] ✅ Image loads without errors
- [ ] ✅ Verification step confirms image exists: "✅ Image verified: ghcr.io/wikid82/charon:pr-XXX"
- [ ] ✅ SBOM generation step uses correct image reference
- [ ] ✅ Vulnerability scanning completes
- [ ] ✅ PR comment appears with supply chain verification results
**Pass Criteria**: Full supply chain verification pipeline executes end-to-end
---
### Scenario 4: Error Handling (Edge Case)
**Objective**: Verify defensive validation catches actual errors (if possible to trigger)
**Note**: This scenario is difficult to test without artificially breaking the build. Monitor for this in production if a natural failure occurs.
**Expected Behavior** (if error occurs):
- [ ] Step fails fast with clear diagnostics
- [ ] Error message shows exact issue (missing tag, image not found, etc.)
- [ ] Available images are listed for debugging
- [ ] Workflow fails with actionable error message
**Pass Criteria**: If error occurs, diagnostics are clear and actionable
---
## Regression Testing
### Check Previous Failure Cases
**Steps**:
1. Review previous failed PR builds (before fix)
2. Note the exact error messages
3. Confirm those errors no longer occur
**Expected Results**:
- [ ] ✅ No "reference does not exist" errors
- [ ] ✅ No "image not found" errors during save
- [ ] ✅ No manual tag reconstruction mismatches
**Pass Criteria**: Previous failure patterns are eliminated
---
## Performance Validation
**Objective**: Ensure fix does not introduce performance degradation
**Metrics to Monitor**:
- [ ] Build time (build-and-push job duration)
- [ ] Artifact save time
- [ ] Artifact upload time
- [ ] Total PR workflow duration
**Expected Results**:
- Build time: ~10-15 minutes (no significant change)
- Artifact save: <30 seconds
- Artifact upload: <1 minute
- Total workflow: <20 minutes for PR builds
**Pass Criteria**: No significant performance regression (±10% acceptable variance)
---
## Rollback Plan
**If Tests Fail**:
1. **Immediate Action**:
- Revert commit fixing the artifact save step
- Notify team of rollback
- Create new issue with failure details
2. **Investigation**:
- Capture full workflow logs
- Check docker images output from failing run
- Verify metadata action output format
- Check for platform-specific issues (amd64 vs arm64)
3. **Recovery**:
- Develop alternative fix approach
- Test in isolated branch
- Reapply fix after validation
---
## Test Log Template
**Test Execution Date**: [YYYY-MM-DD]
**Test PR Number**: #XXX
**Workflow Run**: [Link to GitHub Actions run]
**Tester**: [Name]
### Scenario 1: Standard PR Build
- Status: [ ] PASS / [ ] FAIL
- Notes:
### Scenario 2: Metadata Tag Validation
- Status: [ ] PASS / [ ] FAIL
- Notes:
### Scenario 3: Supply Chain Verification Integration
- Status: [ ] PASS / [ ] FAIL
- Notes:
### Scenario 4: Error Handling
- Status: [ ] PASS / [ ] FAIL / [ ] N/A
- Notes:
### Regression Testing
- Status: [ ] PASS / [ ] FAIL
- Notes:
### Performance Validation
- Status: [ ] PASS / [ ] FAIL
- Build time: X minutes
- Artifact save: X seconds
- Total workflow: X minutes
- Notes:
---
## Sign-Off
**Test Result**: [ ] PASS / [ ] FAIL
**Tested By**: _____________________
**Date**: _____________________
**Approved By**: _____________________
**Date**: _____________________
---
## References
- Original issue: See `current_spec.md` for root cause analysis
- Workflow file: `.github/workflows/docker-build.yml`
- Related fix: Lines 135-167 (Save Docker Image as Artifact step)
- CHANGELOG entry: See "Fixed" section under "Unreleased"

View File

@@ -1,58 +0,0 @@
# Manual Testing: Security Test Helpers
**Created**: June 2025
**Priority**: Medium
**Status**: Open
## Objective
Verify the security test helpers implementation prevents ACL deadlock during E2E test execution.
## Test Scenarios
### Scenario 1: ACL Toggle Isolation
1. Run security dashboard tests that toggle ACL on
2. Intentionally cancel mid-test (Ctrl+C)
3. Run any other E2E test (e.g., manual-dns-provider)
4. **Expected**: Tests should pass - global-setup.ts should reset ACL
### Scenario 2: State Restoration After Failure
1. Modify a security dashboard toggle test to throw an error after enabling ACL
2. Run the test (it will fail)
3. Run a different test file
4. **Expected**: ACL should be disabled, other tests should pass
### Scenario 3: Concurrent Test Runs
1. Run full E2E suite: `npx playwright test --project=chromium`
2. **Expected**: No tests fail due to ACL blocking (@api-tagged requests)
3. **Expected**: Security dashboard toggle tests complete without deadlock
### Scenario 4: Fresh Container State
1. Stop all containers: `docker compose -f .docker/compose/docker-compose.yml down -v`
2. Start fresh: `docker compose -f .docker/compose/docker-compose.ci.yml up -d`
3. Run security dashboard tests
4. **Expected**: Tests pass, ACL state properly managed
## Verification Commands
```bash
# Full E2E suite
npx playwright test --project=chromium
# Security-specific tests
npx playwright test tests/security/*.spec.ts --project=chromium
# Check ACL is disabled after tests
curl -s http://localhost:8080/api/v1/security/status | jq '.acl_enabled'
```
## Acceptance Criteria
- [ ] Security dashboard toggle tests pass consistently
- [ ] No "403 Forbidden" errors in unrelated tests after security tests run
- [ ] global-setup.ts emergency reset works when ACL is stuck enabled
- [ ] afterAll cleanup creates fresh request context (no fixture reuse errors)