diff --git a/.env.backup.20250904_100353 b/.env.backup.20250904_100353 deleted file mode 100644 index 01be169d0..000000000 --- a/.env.backup.20250904_100353 +++ /dev/null @@ -1,2 +0,0 @@ -LOG_LEVEL=debug -DISABLE_AUTH=true diff --git a/.env.dev b/.env.dev deleted file mode 100644 index 374b0b5c4..000000000 --- a/.env.dev +++ /dev/null @@ -1,2 +0,0 @@ -DISABLE_AUTH=true -PULSE_MOCK_MODE=true \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index 74c3d2a97..000000000 --- a/CLAUDE.md +++ /dev/null @@ -1,588 +0,0 @@ -# Claude Code Access Information - -## CRITICAL: Mock Data System for Testing -**Claude must be able to switch between real and mock data instantly when asked.** - -### Quick Commands for Claude to Use -```bash -# Switch to mock mode (simulated data) -/opt/pulse/scripts/toggle-mock.sh on - -# Switch back to real Proxmox nodes -/opt/pulse/scripts/toggle-mock.sh off - -# Check current mode -/opt/pulse/scripts/toggle-mock.sh status - -# Edit mock configuration (number of nodes, VMs, etc.) -/opt/pulse/scripts/toggle-mock.sh edit -``` - -### When to Use Mock Mode -- **User says "use mock data"** → Run `/opt/pulse/scripts/toggle-mock.sh on` immediately -- **User says "use real nodes"** → Run `/opt/pulse/scripts/toggle-mock.sh off` immediately -- **User says "test with X nodes"** → Edit mock.env, set PULSE_MOCK_NODES=X, restart -- **Testing UI features** → Use mock mode with appropriate node count -- **User will frequently ask to switch** - Do it without questioning - -### Mock Configuration (/opt/pulse/mock.env) -```bash -PULSE_MOCK_MODE=true # Enable/disable -PULSE_MOCK_NODES=7 # Number of nodes (test different UI layouts) -PULSE_MOCK_VMS_PER_NODE=5 # VMs per node -PULSE_MOCK_LXCS_PER_NODE=8 # Containers per node -PULSE_MOCK_RANDOM_METRICS=true # Dynamic changing metrics -PULSE_MOCK_STOPPED_PERCENT=20 # % of stopped guests -``` - -### UI Testing Scenarios -- **1-4 nodes**: Regular node cards -- **5-9 nodes**: Compact cards (default: 7) -- **10+ nodes**: Ultra-compact list -- **25+ nodes**: Stress test - -### Example Usage Patterns -```bash -# User: "use mock data with 15 nodes" -nano /opt/pulse/mock.env # Set PULSE_MOCK_NODES=15 -/opt/pulse/scripts/toggle-mock.sh on -sudo systemctl restart pulse-backend - -# User: "back to real" -/opt/pulse/scripts/toggle-mock.sh off - -# User: "test with lots of VMs" -nano /opt/pulse/mock.env # Set PULSE_MOCK_VMS_PER_NODE=20 -sudo systemctl restart pulse-backend -``` - -### How Mock System Works -1. Located in `/opt/pulse/internal/mock/` (gitignored, local only) -2. Generates realistic fake nodes, VMs, containers with popular app names -3. Creates random alerts and changing metrics -4. Integrated with backend-watch.sh for auto-reload -5. Service automatically rebuilds with mock support when enabled - -### Known Issue & Workaround -Mock mode shows both real and mock data mixed. If user needs PURE mock: -```bash -/opt/pulse/scripts/toggle-mock-pure.sh on # Disables real nodes completely -/opt/pulse/scripts/toggle-mock-pure.sh off # Restores real nodes -``` - -### IMPORTANT FOR CLAUDE -- **The mock system is for Claude's use during development sessions** -- **User will ask Claude to switch modes frequently** - do it immediately -- **Always use the toggle scripts** - never manually move files -- **After switching, wait ~10-15 seconds** for service to restart -- **Mock files are local-only** and not in the repository -- **Default is 7 nodes** which tests the compact card view (5-9 nodes) - -## CRITICAL: Development Session Safety -**NEVER KILL TMUX/TTYD PROCESSES** - These run Claude Code itself: -- **DO NOT run**: `pkill tmux`, `pkill ttyd`, `killall tmux`, `killall ttyd` -- **DO NOT kill**: PIDs associated with tmux or ttyd (port 7681) -- **WHY**: Killing these processes terminates the Claude Code session immediately -- **SAFE to kill**: Only Pulse-related processes (pulse binary, backend-watch.sh) -- **When cleaning up processes**: Use specific PIDs or more targeted commands like `pkill -f pulse` (but NOT tmux/ttyd) - -### DANGEROUS COMMANDS THAT WILL CRASH CLAUDE CODE: -- **`pkill -f pulse`** - This kills EVERYTHING with "pulse" in the command, including the ttyd process running at `/opt/pulse`! -- **`pkill -f /opt/pulse`** - Same problem - kills the ttyd session -- **`killall -u pulse`** - Kills all processes by the pulse user, including Claude Code itself -- **Any broad kill command** - Always use specific process names or PIDs - -### SAFE WAYS TO KILL PULSE PROCESSES: -- **Kill specific binary**: `pkill -x pulse` (exact match for "pulse" binary only) -- **Kill by PID**: First find PID with `pgrep -x pulse` then `kill ` -- **Stop service**: `sudo systemctl stop pulse-backend` or `sudo systemctl stop pulse` -- **Kill backend watch**: `pkill -f backend-watch.sh` (safe - doesn't match ttyd/tmux) - -## CRITICAL: GitHub Issue Link Handling -**When user provides a GitHub issue link (e.g., https://github.com/rcourtman/Pulse/issues/XXX):** - -**AUTOMATIC WORKFLOW - DO THIS WITHOUT ASKING:** -1. **Fetch the issue** - Use `gh issue view` to get all details -2. **Review attachments** - Look at any screenshots or logs attached to the issue -3. **Understand the problem** - Analyze what needs to be fixed or implemented -4. **Determine action**: - - If it's clearly a bug → Fix it immediately - - If it's a feature request → Implement it if straightforward - - If unclear or complex → Ask user what they want you to do -5. **Make the changes** - Fix the bug or implement the feature -6. **Commit with reference** - Use "addresses #XXX" or "potential fix for #XXX" in commit message -7. **DO NOT comment on the issue** - Let the fix speak for itself - -**IMPORTANT:** -- **NEVER comment on issues** unless explicitly asked to "comment on the issue" -- **ALWAYS reference the issue number** in your commit message -- **Use "addresses #XXX"** not "fixes #XXX" (which auto-closes the issue) -- **If unsure about implementation**, ask the user for clarification - -## CRITICAL: GitHub Comment Policy -**DEFAULT BEHAVIOR: Reference issues in commit messages, don't comment on issues.** - -**MANDATORY BEFORE ANY GITHUB COMMENT:** -1. **NEVER post a comment without showing the draft to the user first** -2. **ALWAYS understand the issue completely before suggesting any comment:** - - Read ALL comments in the thread - - Review all attached screenshots/images - - Check the code for the actual problem - - Understand what's already been tried - - Look at any linked issues or PRs -3. **Draft the comment and show it to the user** -4. **WAIT for explicit approval** - User must say "yes", "post it", "send it", or similar -5. **Only then post the comment** - -**Issue Reference Workflow (PREFERRED):** -1. **Fix the issue in code** -2. **Reference in commit message** - Use "addresses #XXX" or "potential fix for #XXX" -3. **Let the fix speak for itself** in the next release -4. **DO NOT comment on the issue** unless explicitly asked - -**Only comment on issues when EXPLICITLY requested:** -- User will say "comment on the issue", "post a comment", or similar -- When asked to comment: - 1. **FIRST thoroughly understand the issue** - Read everything, check code, review all comments - 2. **DRAFT the comment** - Show it to the user - 3. **GET APPROVAL** - User must explicitly approve - 4. **ONLY THEN post the comment** - 5. **NEVER post comments without showing the draft first** - -**CRITICAL USERNAME VERIFICATION** (when commenting): -- **Getting usernames wrong is COMPLETELY UNACCEPTABLE** - It makes the repo owner look incompetent -- **ALWAYS use `gh issue view --json author`** to verify the exact username -- **NEVER make up usernames like "icebreaker2" or "swtrse"** when you haven't verified them - -**When checking issues:** -1. Check and gather all relevant information -2. **ALWAYS look at attached screenshots/images** - They often contain critical details - - Use `wget -O /tmp/image.png ""` to download GitHub issue images - - Then use the Read tool on the downloaded image file to view/OCR it - - Images from GitHub issue attachments redirect to S3, wget handles this properly -3. Present findings to the user clearly -4. Fix the issue and reference it in commit message -5. Only comment if user explicitly asks you to - -**NEVER SKIP THESE STEPS:** -- **Never post without showing draft first** -- **Never suggest a comment without fully understanding the issue** -- **Never assume - always verify by reading everything** - -## CRITICAL: Issue Management Policy -**NEVER close issues without user confirmation of the fix:** -1. **DO NOT close issues** just because you think they're fixed -2. **WAIT for the reporter to confirm** the fix works for them -3. **Comment on the issue** saying "potential fix in version X.X.X, can you test and confirm?" -4. **Only close when**: - - The reporter confirms it's fixed - - The issue is clearly a duplicate - - The issue is very old (6+ months) with no response - - You get explicit permission from the repo owner to close it -5. **When closing old issues**, use: "Closing due to inactivity. Please reopen if still experiencing this issue." -6. **ALWAYS mention reopening** - End every issue closure with: "Feel free to reopen if this is still an issue" or similar -7. **Be patient** - users may take days or weeks to test fixes -8. **Example closing messages:** - - "Closing as this relates to v3 which is no longer supported. Feel free to reopen if you still need this." - - "Closing as stale. Please reopen if you're still experiencing this issue." - - "Should be fixed in v4.1.8. Please reopen if the issue persists after updating." - -## CRITICAL: Understanding Before Action -**Before making ANY recommendations or implementing features:** -1. **UNDERSTAND the existing implementation** - Check how things currently work -2. **ASK questions** if uncertain about design decisions -3. **VERIFY assumptions** by examining the actual code -4. **CONSIDER the implications** of any changes -5. **RESPECT the developer's design choices** - They know their app better than you - -## CRITICAL: Preventing Hallucinations and False Information -**To avoid making incorrect claims about Pulse:** -1. **ALWAYS verify in code first** - Never claim what Pulse does/doesn't support without checking -2. **Say "I'm not sure, let me check"** when uncertain - Better to admit uncertainty than be wrong -3. **Search codebase before answering** - Use Grep/Read to verify features exist before discussing them -4. **Quote the actual code** - When explaining functionality, show the relevant code snippet -5. **Double-check critical claims** - For important statements about how Pulse works, verify twice -6. **If you can't find evidence, ASK** - Don't assume or guess about features or behavior - -**Never give opinions or make changes without first understanding:** -- How the feature currently works -- Why it was designed that way -- What security/UX/technical constraints exist -- What the actual problem is (not what you assume it is) - -## CRITICAL: Commit Messages and Fix Claims -**NEVER claim something is fixed in commit messages until users confirm:** -1. **DO NOT use "fix:" or "fixed"** in commit messages unless users have verified the fix works -2. **Use "attempt to address"** or "potential fix for" instead -3. **Wait for user confirmation** before claiming anything is resolved -4. **Track issues properly** - Keep them open until users confirm resolution -5. **Test thoroughly** before even claiming a potential fix -6. **Be honest about uncertainty** - If you're not sure it's fixed, say so -7. **ALWAYS reference the issue number** in commit messages (e.g., "addresses #123", "potential fix for #456") - - This creates automatic links in GitHub so users can track changes - - Use "addresses #XXX" or "related to #XXX" not "fixes #XXX" (which auto-closes) -8. **AVOID certainty in comments** - Don't say "found the issue" or "fixed it", say "looks like" or "should address this" - -## Binary and Service Naming Consistency -**Important for compatibility with various installation methods:** - -### Binary Location -- **Standard location**: `/opt/pulse/bin/pulse` -- **Symlink**: `/usr/local/bin/pulse` → `/opt/pulse/bin/pulse` -- Keep consistent across releases to avoid breaking existing installations - -### Service Name -- **Our install.sh uses**: `pulse` -- **Legacy installs might use**: `pulse-backend` -- **Code MUST detect both** and handle either service name - -### Configuration Location -- **Config directory**: `/etc/pulse/` -- **Data directory**: `/etc/pulse/` -- **Binary location**: `/opt/pulse/` - -### User and Permissions -- **Service runs as**: `pulse` user (non-root) -- **NO sudo access** - the pulse user has no sudo privileges -- **Shell access**: Limited or removed for security -- **NEVER attempt sudo** in any code paths - -## CRITICAL: Security Model Understanding -**Pulse v4 Security Architecture:** -- Node credentials (passwords, API tokens) are stored ENCRYPTED at rest -- The frontend NEVER receives actual credentials - only `hasPassword: true` or `hasToken: true` -- When editing nodes, the UI cannot display existing credentials -- The ONLY way to extract credentials is through the export API endpoint -- Export/import endpoints MUST require authentication (API_TOKEN) to prevent credential theft -- **Never suggest or implement features that would expose credentials to the frontend UI** -- **Always verify security implications before making recommendations** - -## TypeScript Code Standards -- **NEVER use `any` type** - Always use proper TypeScript types -- **Type everything correctly** - All variables, parameters, and return values must be properly typed -- **Use type guards** - When dealing with union types, use proper type guards (e.g., `'property' in object`) -- **No implicit any** - Ensure TypeScript strict mode catches missing types -- **Prefer interfaces over type aliases** for object shapes -- **Use generics** when appropriate instead of `any` - -## CRITICAL: THIS IS A PERMANENT DEVELOPMENT ENVIRONMENT - -### 🔥 DEVELOPMENT MODE IS ALWAYS ON 🔥 -**This machine (debian-go) is configured as a permanent development environment:** - -- **Dev mode runs automatically** - You don't need to start anything -- **Auto-restarts on crash** - systemd keeps it running always -- **Survives reboots** - Starts automatically on boot -- **No commands to remember** - It just works - -### Development URLs (Always Available): -- **Frontend**: http://192.168.0.123:7655 (with hot-reload - changes appear instantly!) -- **Backend API**: http://localhost:7656 (API only) -- **Logs**: `tail -f /opt/pulse/dev.log` - -### How It Works: -- **systemd service**: `pulse-dev.service` runs permanently -- **Script**: `/opt/pulse/scripts/hot-dev.sh` handles everything -- **Hot-reload**: Frontend changes appear instantly without rebuilding -- **Backend changes**: Restart the service to rebuild -- **Port management**: Automatically cleans up ports on each restart -- **Mock support**: Loads `/opt/pulse/mock.env` if mock mode is enabled - -### 🎭 MOCK DATA TOGGLE (USE THIS FREQUENTLY!) - -**CLAUDE: You should toggle between mock and real data often during development:** - -```bash -# WHEN USER SAYS "use mock data" or "test with fake nodes": -/opt/pulse/scripts/toggle-mock.sh on - -# WHEN USER SAYS "use real data" or "back to real": -/opt/pulse/scripts/toggle-mock.sh off - -# CHECK what mode you're in: -/opt/pulse/scripts/toggle-mock.sh status -``` - -**What Mock Mode Gives You:** -- 7 fake nodes (pve1-pve7) with no real infrastructure -- 35 VMs (5 per node) with popular app names -- 56 containers (8 per node) with realistic metrics -- Random changing metrics every 2 seconds -- Mock alerts that auto-generate -- Perfect for testing UI layouts and features - -**Switching takes 5 seconds** - The service auto-restarts when you toggle. - -**To test different UI layouts:** -```bash -# Edit the mock config -/opt/pulse/scripts/toggle-mock.sh edit -# Change PULSE_MOCK_NODES to: -# 1-4 nodes: Regular cards -# 5-9 nodes: Compact cards (default: 7) -# 10+ nodes: List view -# 25+ nodes: Stress test -# Then restart: sudo systemctl restart pulse-dev -``` - -#### Building & Testing -```bash -# Create a release (only when ready to ship) -/opt/pulse/scripts/build-release.sh - -# Run the complete test suite -/opt/pulse/scripts/run-tests.sh -``` - -### Service Management: -```bash -# Check status -sudo systemctl status pulse-dev - -# View logs -tail -f /opt/pulse/dev.log - -# Restart (needed after backend changes) -sudo systemctl restart pulse-dev - -# Emergency stop -sudo systemctl stop pulse-dev - -# Emergency start -sudo systemctl start pulse-dev -``` - - -### IMPORTANT NOTES: -- **This is NOT for production machines** - Only for debian-go dev environment -- **Port 7655**: Always running with hot-reload -- **Port 7656**: Always running backend API (no embedded frontend) -- **Production service removed**: No pulse-backend.service on this machine -- **Flag file**: `/opt/pulse/.dev-mode` marks this as a dev machine -- **Everything is consolidated**: One service, one main script, simple toggles - -### Production Build Testing -**For actual releases, use the build-release script:** -```bash -./scripts/build-release.sh # Creates release artifacts with proper versioning -# This is only needed at release time, not during development -``` - -### IMPORTANT: Frontend Directory Structure (CLAUDE READ THIS FIRST!) -**⚠️ CLAUDE: The duplicate frontend directory is INTENTIONAL and REQUIRED ⚠️** - -**When you see `/opt/pulse/internal/api/frontend-modern/`:** -- **DO NOT try to "fix" it** - It's supposed to exist -- **DO NOT remove it** - Builds will fail -- **DO NOT edit files there** - Only edit in `/opt/pulse/frontend-modern` -- **DO NOT worry about it** - It's a build artifact like .o files - -**The ONLY frontend source**: `/opt/pulse/frontend-modern` -- Edit all frontend code here -- Vite dev server runs from here -- This is the source of truth - -**Why the duplicate exists**: -- Go's `//go:embed` CANNOT access files outside the module (no `../` or symlinks) -- The Makefile copies the built frontend for embedding -- It's in .gitignore so it won't pollute git -- It gets recreated on every build (that's normal!) - -**What to tell users who ask about it**: -"That's a build artifact required by Go's embed limitations. Only edit files in `/opt/pulse/frontend-modern`. The duplicate is automatically managed by the build process." - -## Development Environment (Current Machine - debian-go) -- **Development Port**: 7655 (frontend with hot-reload) -- **Backend API Port**: 7656 (API only) -- **Production Port**: 7655 (embedded frontend + API) -- **Access URL**: http://192.168.0.123:7655 -- **Service**: `sudo systemctl restart pulse-backend` (for production only) -- **Logs**: `tail -f /opt/pulse/pulse.log` - -## Available SSH Nodes - -Claude Code has SSH access to the following nodes: - -### Proxmox Cluster -- **delly** (delly.lan) - Part of a Proxmox cluster with minipc - - User: root - - Access: SSH key-based authentication - -### Standalone Proxmox Node -- **pimox** (pimox.lan / 192.168.0.2) - Standalone Proxmox VE node - - User: root - - Access: SSH key-based authentication - -### Proxmox Backup Server (PBS) -- **PBS Docker** (192.168.0.8) - PBS running in Docker container - - User: root - - Access: SSH key-based authentication (already configured) - - Container name: pbs - - Docker commands: `ssh root@192.168.0.8 "docker exec pbs "` - - Web Interface: https://192.168.0.8:8007 - - Purpose: Production PBS instance for testing PBS integration - -## Test LXC Container - -### Testing Policy -**ALWAYS test fixes on actual Proxmox test containers before claiming they work** -- Container IDs change - check with `pct list` -- Create fresh test LXCs whenever needed -- Test in real environments, don't assume fixes work -- Clean up test containers when done - -### Pulse Test Container -- **Container ID**: 130 on delly -- **Hostname**: pulse-test -- **IP Address**: 192.168.0.152 -- **Pulse Version**: v4.0.0-rc.1 -- **Web Interface**: http://192.168.0.152:7655 -- **Purpose**: Permanent test container for Pulse development and testing -- **Service**: Running as systemd service (pulse.service) - -### Docker Builder Container -- **Container ID**: 135 on delly -- **Hostname**: docker-builder -- **IP Address**: 192.168.0.174 -- **Purpose**: Dedicated container for building multi-arch Docker images -- **Docker buildx**: Pre-configured with multiarch builder -- **Architectures**: Builds for linux/amd64, linux/arm64, linux/arm/v7 -- **Docker Hub Access**: Already logged in as rcourtman with push permissions -- **Access Method**: SSH through delly (container 135) -- **Note**: Direct SSH to 192.168.0.174 doesn't work, must go through delly - -## Testing Tools - -Automated testing tools are available in `/opt/pulse/testing-tools/`: - -**Automated testing tools in `/opt/pulse/testing-tools/`** -- Email, API, UI button, alerts, thresholds, mobile responsiveness tests available -- Run comprehensive tests after significant changes - -## Commit Message Guidelines - -### NEVER USE ALARMIST LANGUAGE IN COMMITS -- **DO NOT use**: "CRITICAL", "SECURITY FIX", "URGENT", "SEVERE", "VULNERABILITY" -- **DO NOT**: Create panic or alarm users unnecessarily -- **DO NOT**: Make it seem like user data was compromised -- **DO use**: Calm, professional language that describes the improvement -- **Good example**: "fix: remove sensitive data from logs" -- **Bad example**: "CRITICAL SECURITY FIX: passwords exposed in logs!!!" -- **Remember**: Alarmist commits damage user trust and make the project look unprofessional - -When fixing security-related issues: -- Focus on the improvement, not the problem -- Use terms like "improve", "enhance", "update" rather than "fix critical vulnerability" -- Be factual without being dramatic -- Remember that public commit history affects project reputation - -## Git Repository Workflow - -### Repository Structure -- **Single public repo**: `Pulse` (https://github.com/rcourtman/Pulse.git) -- All development, testing, and releases happen in this repository - -### Development Workflow -1. **Main branch development** - Direct commits to main (small team, move fast) -2. **Testing releases** - Use RC/pre-release tags for testing (e.g., v4.1.0-rc.1) -3. **Stable releases** - Full releases when ready for production (e.g., v4.1.0) - -### Release Strategy -- **RC releases** - Mark as pre-release in GitHub to prevent auto-updates -- **Stable releases** - Regular releases for production use -- **Version tags** - Always use semantic versioning with 'v' prefix - - -## Update Mechanism Design -**IMPORTANT**: Pulse does NOT perform self-updates from the UI. Instead: -- The UI detects the deployment type (ProxmoxVE, Docker, systemd, etc.) -- Shows deployment-specific update instructions when updates are available -- ProxmoxVE users type `update` in console -- Docker users pull new image and recreate container -- Manual/systemd users re-run the install script - -**Why**: Security constraints prevent self-updates: -- ProxmoxVE containers run as non-root user without sudo -- Docker containers cannot restart themselves -- Systemd services cannot restart without privileges -This design is intentional and should not be "fixed" - it ensures proper security boundaries. - -## CRITICAL: Remove Redundant Code -**ALWAYS remove old/redundant code when refactoring or consolidating:** -- **Check for duplicate components** - If you update one component, check if there are others doing the same thing -- **Delete unused files immediately** - Don't leave old versions lying around -- **Search for imports** - Before deleting, ensure no other files import it -- **Common patterns to watch for**: - - Multiple components with similar names (e.g., PVENodeTable vs NodeSummaryTable) - - Old implementations left behind after refactoring - - Duplicate utility functions in different files -- **Why this matters**: Leaving redundant code causes bugs where you update one file but the app uses another -- **Example**: We just had PVENodeTable, PBSNodeTable, and NodeSummaryTable all doing the same thing - -## Important Instructions -- **NEVER create documentation files** (*.md) unless explicitly requested by the user -- **NEVER create README files** or other docs to explain changes - just explain in the response -- **DO NOT create markdown files to document findings** - Just explain in the response instead -- **DO NOT create analysis or optimization docs** - The user hates unnecessary documentation -- **ALWAYS prefer editing existing files** over creating new ones -- **RUN TESTS** after making significant changes using the testing tools - -## Documentation Style Guidelines -When writing or updating documentation: -- **BE CONCISE** - Get to the point, no fluff -- **PRACTICAL** - Show how to use it, not theory -- **NO CORPORATE SPEAK** - Write like a developer, not a PR department -- **ESSENTIALS ONLY** - What users actually need to know -- **GOOD EXAMPLES** - Real commands and configs that work -- **AVOID**: Long introductions, obvious advice, redundant sections, unnecessary verbosity - -## Creating Releases -- **ALWAYS USE THE RELEASE CHECKLIST** - There is a `/opt/pulse/RELEASE_CHECKLIST.md` that MUST be followed step-by-step when creating any release -- **MANDATORY - NO EXCEPTIONS**: You MUST open and follow the checklist line by line for EVERY release (stable, RC, or patch) -- **THIS CHECKLIST IS LOCAL-ONLY** - The RELEASE_CHECKLIST.md file exists ONLY on this development machine and should NEVER be committed to the repository -- **Purpose of the checklist**: Ensures consistent, complete releases with all binaries, proper Docker tags, and testing -- **NEVER create a release without following the checklist** - This ensures proper testing, artifact generation, and documentation -- **START HERE**: When asked to create a release, your FIRST action should be: `Read /opt/pulse/RELEASE_CHECKLIST.md` -- The checklist includes critical steps like: - - Running tests before release - - Building release artifacts with `./scripts/build-release.sh` - - Uploading artifacts to GitHub releases - - Testing installation methods - - Proper version management - - Docker multi-arch builds -- Skipping the checklist results in incomplete releases missing binaries that users need -- **The checklist is in .gitignore** - This ensures it stays local and doesn't get accidentally committed - -## GitHub PR and Comment Style -When writing comments on GitHub PRs or issues: -- **Keep it casual and human** - Don't sound like an AI assistant -- **Be humble** - Never oversell or sound big-headed about changes -- **NO emoji checkmarks** (✅) or bullet points with formal structure -- **Explain what went wrong honestly** - Users appreciate transparency -- **Talk like a developer**, not a corporate PR person -- **Avoid dramatic language** - Don't say "completely redesigned", "major overhaul", etc. -- **Use simple descriptions** - "fixed", "changed", "updated" instead of "revolutionized", "transformed" -- **Default response for bug reports**: "thanks for reporting, fixing for the next release" -- **When explaining fixes**: Be specific but humble - "fixed the token display issue" not "completely revolutionized the authentication system" -- **Examples of BAD style**: "Thanks for the feedback! I've completely redesigned the system: ✅ Now uses..." -- **Examples of GOOD style**: "hey @username, thanks for the detailed report. You're right that [problem]. Fixed in the new RC." -- **Avoid**: Overly enthusiastic tone, formatted lists, corporate speak, overselling changes -- **Use**: Lowercase, informal tone, minimal punctuation, get straight to the point -- **AVOID DASHES IN SENTENCES** - Don't write "thanks - really appreciate it", use commas or just flow naturally -- **BAD**: "thanks for the help - means a lot", "fixed the bug - should work now" -- **GOOD**: "thanks for the help, means a lot", "fixed the bug, should work now" -- **NO EXCLAMATION MARKS** - Avoid using ! in comments, keep it casual without fake enthusiasm -- **BAD**: "thanks!", "fixed it!", "works now!" -- **GOOD**: "thanks", "fixed it", "works now" -- **STOP ACKNOWLEDGING USERS ARE RIGHT** - Never write "You're right", "good catch", "absolutely right", etc. -- **BAD**: "good catch", "you're absolutely right", "you're correct that..." -- **GOOD**: Just explain what was fixed without validation-seeking language -- **STOP THANKING FOR REPORTS** - Never write "thanks for the detailed report", "thanks for reporting", etc. -- **BAD**: "thanks for the detailed report", "thanks for reporting this", "thank you for bringing this up" -- **GOOD**: Just acknowledge the issue exists and explain the fix -- **Don't oversell improvements** - Let the changes speak for themselves - -## Docker Build Process -- Use container 135 on delly for multi-arch Docker builds -- Build for linux/amd64, linux/arm64, linux/arm/v7 -- Tag appropriately for stable vs RC releases diff --git a/PMG_BACKUP_DETECTION.md b/PMG_BACKUP_DETECTION.md deleted file mode 100644 index c5efaeeee..000000000 --- a/PMG_BACKUP_DETECTION.md +++ /dev/null @@ -1,126 +0,0 @@ -# PMG Backup Detection - Issue #359 Resolution - -## Problem -PMG (Proxmox Mail Gateway) host configuration backups with VMID=0 were being incorrectly displayed as "LXC" instead of "Host" type. - -## Root Causes Identified - -1. **PBS stores PMG backups as 'ct' type** - PBS (Proxmox Backup Server) stores PMG backups with `backupType: "ct"` and `vmid: "0"` (string) -2. **Type checking inconsistency** - Some code paths weren't checking for VMID=0 -3. **String vs Number VMID** - API returns VMID as string from PBS but as number from storage - -## Solution Implemented - -### 1. Robust VMID=0 Detection -```javascript -const isVmidZero = backup.vmid === '0' || backup.vmid === 0 || parseInt(String(backup.vmid)) === 0; -``` - -### 2. Multiple Detection Points -- PBS backups (`state.pbsBackups`) -- Storage backups (`state.pveBackups.storageBackups`) -- Both check VMID=0 BEFORE checking backup type - -### 3. Debug Mode -Users can enable debug logging: -```javascript -localStorage.setItem('debug-pmg', 'true'); -``` -Then check console for `[PMG Debug]` messages. - -## Testing - -### Test Script -Created `/opt/pulse/test-pmg-backups.js` which tests: -- PBS backups with string VMID "0" -- PBS backups with numeric VMID 0 -- Storage backups with type "host" -- Storage backups with type "lxc" but VMID=0 -- All test cases pass ✓ - -### Test Results -``` -✓ PBS PMG backup (ct type with VMID 0) → Host -✓ PBS PMG backup (ct type with numeric VMID 0) → Host -✓ Storage PMG backup (host type) → Host -✓ Storage PMG backup (lxc type with VMID 0) → Host -✓ Regular LXC backup → LXC -``` - -## How PMG Backups Are Stored - -### In PBS -```json -{ - "backup-type": "ct", - "backup-id": "0", - "backup-time": 1234567890, - "comment": "PMG host configuration backup" -} -``` - -### In PVE Storage -```json -{ - "type": "host", // or sometimes "lxc" - "vmid": 0, - "volid": "local:backup/pmgbackup-...", - "notes": "PMG host config backup" -} -``` - -## User Instructions for Debugging - -If PMG backups still show as LXC: - -1. **Enable debug mode**: - ```javascript - // In browser console - localStorage.setItem('debug-pmg', 'true'); - location.reload(); - ``` - -2. **Check console** for `[PMG Debug]` messages - -3. **Share the debug output** including: - - The vmid value and type - - The backupType or type field - - The volid if available - -4. **Disable debug mode**: - ```javascript - localStorage.removeItem('debug-pmg'); - ``` - -## Files Modified - -1. `/opt/pulse/frontend-modern/src/components/Backups/UnifiedBackups.tsx` - - Lines 203-228: PBS backup type detection - - Lines 279-303: Storage backup type detection - - Added debug logging - -2. `/opt/pulse/internal/monitoring/monitor.go` - - Lines 2591, 2603: Backend detection for "pmgbackup" and VMID=0 - -## Verification Checklist - -- [x] PBS backups with VMID="0" show as Host -- [x] PBS backups with VMID=0 show as Host -- [x] Storage backups with type="host" show as Host -- [x] Storage backups with VMID=0 show as Host (regardless of type) -- [x] Regular LXC backups (VMID≠0) show as LXC -- [x] Debug mode provides useful information -- [x] No regression for VM/LXC detection - -## Known Edge Cases - -1. **Old PMG versions** might not use VMID=0 -2. **Custom backup names** without "pmgbackup" in volid -3. **PBS namespace** differences - -## Monitoring - -To verify in production: -1. Check for backups with VMID=0 in the UI -2. Verify they show "Host" badge (orange color) -3. Enable debug mode if issues persist \ No newline at end of file diff --git a/SAFE_TESTING.md b/SAFE_TESTING.md deleted file mode 100644 index 6d88f46ae..000000000 --- a/SAFE_TESTING.md +++ /dev/null @@ -1,92 +0,0 @@ -# Safe Testing Guide for Pulse - -## The Problem (SOLVED) -Tests were deleting production nodes when cleaning up test data. This has been fixed! - -## The Solution -We've implemented multiple layers of protection: - -### 1. Mock Mode Testing (`run-tests-mock.sh`) -**RECOMMENDED** - Use this for all testing: -```bash -./scripts/run-tests-mock.sh -``` - -This script: -- Automatically enables mock mode before tests -- Runs all tests against fake nodes (pve1-pve7) -- Restores your original mode when done -- **Your production nodes are NEVER touched** - -### 2. Safe Test Helpers -All test scripts now use `test-helpers.sh` which: -- **NEVER deletes nodes matching**: pve*, mock-*, delly, minipc, pimox, 192.168.0.* -- Only deletes nodes with "test" in the name -- Double-checks before any deletion - -### 3. Safety Prompt in Main Test -If you run `./scripts/run-tests.sh` in real mode: -- Shows a BIG WARNING -- Asks for confirmation -- Recommends using mock mode instead - -## Quick Commands - -### Safe Testing (Recommended) -```bash -# Run tests safely with mock data -./scripts/run-tests-mock.sh - -# Check what mode you're in -/opt/pulse/scripts/toggle-mock.sh status - -# Switch to mock mode manually -/opt/pulse/scripts/toggle-mock.sh on - -# Switch back to real nodes -/opt/pulse/scripts/toggle-mock.sh off -``` - -### Configure Mock Data -```bash -# Edit mock settings (node count, VMs, etc) -/opt/pulse/scripts/toggle-mock.sh edit - -# Then restart to apply -sudo systemctl restart pulse-dev -``` - -## Protected Nodes -These patterns are ALWAYS protected from deletion: -- `pve[0-9]` - Mock nodes -- `mock-*` - Any mock-prefixed nodes -- `delly` - Production node -- `minipc` - Production node -- `pimox` - Production node -- `192.168.0.*` - Production IP range - -## Test Node Naming -Test scripts now create nodes with unique names: -- `test-val-[timestamp]` -- `persist-test-[timestamp]-[random]` -- `load-test-[timestamp]` -- `concurrent-[number]` - -This prevents any collision with real node names. - -## Files Modified -- `/opt/pulse/scripts/run-tests.sh` - Added safety prompt -- `/opt/pulse/scripts/run-tests-mock.sh` - New safe test runner -- `/opt/pulse/scripts/test-helpers.sh` - Safe deletion functions -- `/opt/pulse/scripts/test-persistence.sh` - Uses safe helpers -- `/opt/pulse/scripts/test-recovery.sh` - Uses safe helpers -- `/opt/pulse/scripts/test-backup.sh` - Uses safe helpers -- `/opt/pulse/scripts/test-load.sh` - Uses safe helpers -- `/opt/pulse/scripts/test-config-validation.sh` - Uses safe helpers - -## Your Production Nodes Are Safe! -The test suite will never again delete your production nodes. Tests now: -1. Use mock data by default (recommended) -2. Only delete nodes explicitly created for testing -3. Protect all known production node patterns -4. Ask for confirmation before running in real mode \ No newline at end of file diff --git a/frontend-modern/test-pmg.html b/frontend-modern/test-pmg.html deleted file mode 100644 index d91c43f8f..000000000 --- a/frontend-modern/test-pmg.html +++ /dev/null @@ -1,127 +0,0 @@ - - - - PMG Backup Test - - - -

PMG Backup Detection Test

- -
- - - - \ No newline at end of file diff --git a/test-pmg-backups.js b/test-pmg-backups.js deleted file mode 100755 index 50a229008..000000000 --- a/test-pmg-backups.js +++ /dev/null @@ -1,142 +0,0 @@ -#!/usr/bin/env node - -// Test script to verify PMG backup detection -// This simulates various PMG backup scenarios to ensure they're detected as "Host" type - -const testCases = [ - // PBS backup formats (what PBS returns) - { - name: "PBS PMG backup (ct type with VMID 0)", - backup: { - backupType: "ct", - vmid: "0", - comment: "PMG host configuration backup", - instance: "pbs-main" - }, - expected: "Host" - }, - { - name: "PBS PMG backup (ct type with numeric VMID 0)", - backup: { - backupType: "ct", - vmid: 0, - comment: "PMG host configuration backup", - instance: "pbs-main" - }, - expected: "Host" - }, - { - name: "PBS regular LXC backup (ct type with non-zero VMID)", - backup: { - backupType: "ct", - vmid: "100", - comment: "Regular container backup", - instance: "pbs-main" - }, - expected: "LXC" - }, - - // Storage backup formats (what PVE storage returns) - { - name: "Storage PMG backup (host type)", - backup: { - type: "host", - vmid: 0, - volid: "local:backup/pmgbackup-pmg-01-2024_01_15.tar.zst", - notes: "PMG host config backup" - }, - expected: "Host" - }, - { - name: "Storage PMG backup (lxc type with VMID 0)", - backup: { - type: "lxc", - vmid: 0, - volid: "local:backup/vzdump-lxc-0-2024_01_15.tar.gz", - notes: "PMG configuration" - }, - expected: "Host" - }, - { - name: "Storage regular LXC backup", - backup: { - type: "lxc", - vmid: 101, - volid: "local:backup/vzdump-lxc-101-2024_01_15.tar.gz", - notes: "Container backup" - }, - expected: "LXC" - } -]; - -// Test function that mimics the frontend logic -function detectBackupType(backup) { - // For PBS backups (have backupType field) - if ('backupType' in backup) { - // Check for VMID=0 which indicates host backup (handle both string and number) - const isVmidZero = backup.vmid === '0' || backup.vmid === 0 || parseInt(String(backup.vmid)) === 0; - - if (isVmidZero || backup.backupType === 'host') { - return 'Host'; - } else if (backup.backupType === 'vm' || backup.backupType === 'VM') { - return 'VM'; - } else if (backup.backupType === 'ct' || backup.backupType === 'lxc') { - return 'LXC'; - } else { - return 'LXC'; // Default fallback - } - } - - // For storage backups (have type field) - if ('type' in backup) { - // Check for VMID=0 which indicates host backup - const isVmidZero = backup.vmid === 0 || backup.vmid === '0' || parseInt(String(backup.vmid)) === 0; - - if (isVmidZero || backup.type === 'host') { - return 'Host'; - } else if (backup.type === 'qemu' || backup.type === 'vm') { - return 'VM'; - } else if (backup.type === 'lxc' || backup.type === 'ct') { - return 'LXC'; - } else { - return 'LXC'; // Default fallback - } - } - - return 'Unknown'; -} - -// Run tests -console.log('Testing PMG Backup Detection Logic\n'); -console.log('='.repeat(50)); - -let passed = 0; -let failed = 0; - -testCases.forEach(test => { - const result = detectBackupType(test.backup); - const success = result === test.expected; - - if (success) { - console.log(`✓ ${test.name}`); - console.log(` Input: ${JSON.stringify(test.backup)}`); - console.log(` Expected: ${test.expected}, Got: ${result}\n`); - passed++; - } else { - console.log(`✗ ${test.name}`); - console.log(` Input: ${JSON.stringify(test.backup)}`); - console.log(` Expected: ${test.expected}, Got: ${result} ← FAILED\n`); - failed++; - } -}); - -console.log('='.repeat(50)); -console.log(`Results: ${passed} passed, ${failed} failed`); - -if (failed > 0) { - console.log('\n⚠️ Some tests failed! The detection logic needs adjustment.'); - process.exit(1); -} else { - console.log('\n✅ All tests passed! The detection logic should work correctly.'); - process.exit(0); -} \ No newline at end of file diff --git a/test-proxy-auth.sh b/test-proxy-auth.sh deleted file mode 100755 index 946270a39..000000000 --- a/test-proxy-auth.sh +++ /dev/null @@ -1,140 +0,0 @@ -#!/bin/bash - -# Test script for proxy auth admin permissions -# This simulates what Authentik/Caddy would send - -BASE_URL="http://localhost:7656" -PROXY_SECRET="test-secret-123" - -echo "=== Testing Proxy Auth Admin Permissions ===" -echo - -# First, update the config to enable proxy auth -echo "1. Setting up proxy auth configuration..." -cat > /tmp/proxy-test.env << EOF -PROXY_AUTH_SECRET=$PROXY_SECRET -PROXY_AUTH_USER_HEADER=X-Authentik-Username -PROXY_AUTH_ROLE_HEADER=X-Authentik-Groups -PROXY_AUTH_ADMIN_ROLE=admin -PROXY_AUTH_ROLE_SEPARATOR=| -EOF - -# Copy current env and add proxy auth settings -cp /etc/pulse/.env /tmp/backup.env -cat /tmp/proxy-test.env >> /etc/pulse/.env - -# Restart service to pick up new config -echo "2. Restarting service with proxy auth enabled..." -sudo systemctl restart pulse-dev -sleep 5 - -echo "3. Testing API endpoints with different user roles..." -echo - -# Test as non-admin user (should be blocked from write operations) -echo "=== Testing as non-admin user (alice) ===" -echo "Groups: users|staff (no admin role)" -echo - -echo -n "GET /api/security/status (should work): " -curl -s -X GET "$BASE_URL/api/security/status" \ - -H "X-Proxy-Secret: $PROXY_SECRET" \ - -H "X-Authentik-Username: alice" \ - -H "X-Authentik-Groups: users|staff" \ - | jq -r '.proxyAuthIsAdmin // "ERROR"' - -echo -n "GET /api/config/nodes (should work): " -curl -s -X GET "$BASE_URL/api/config/nodes" \ - -H "X-Proxy-Secret: $PROXY_SECRET" \ - -H "X-Authentik-Username: alice" \ - -H "X-Authentik-Groups: users|staff" \ - -o /dev/null -w "%{http_code}\n" - -echo -n "POST /api/config/nodes (should be 403 Forbidden): " -curl -s -X POST "$BASE_URL/api/config/nodes" \ - -H "X-Proxy-Secret: $PROXY_SECRET" \ - -H "X-Authentik-Username: alice" \ - -H "X-Authentik-Groups: users|staff" \ - -H "Content-Type: application/json" \ - -d '{"name":"test","host":"192.168.1.1","type":"pve"}' \ - -o /dev/null -w "%{http_code}\n" - -echo -n "POST /api/system/settings/update (should be 403 Forbidden): " -curl -s -X POST "$BASE_URL/api/system/settings/update" \ - -H "X-Proxy-Secret: $PROXY_SECRET" \ - -H "X-Authentik-Username: alice" \ - -H "X-Authentik-Groups: users|staff" \ - -H "Content-Type: application/json" \ - -d '{"pollingInterval":30}' \ - -o /dev/null -w "%{http_code}\n" - -echo -n "POST /api/config/export (should be 403 Forbidden): " -curl -s -X POST "$BASE_URL/api/config/export" \ - -H "X-Proxy-Secret: $PROXY_SECRET" \ - -H "X-Authentik-Username: alice" \ - -H "X-Authentik-Groups: users|staff" \ - -H "Content-Type: application/json" \ - -d '{"passphrase":"test123456789"}' \ - -o /dev/null -w "%{http_code}\n" - -echo -echo "=== Testing as admin user (bob) ===" -echo "Groups: users|staff|admin (has admin role)" -echo - -echo -n "GET /api/security/status (should work): " -curl -s -X GET "$BASE_URL/api/security/status" \ - -H "X-Proxy-Secret: $PROXY_SECRET" \ - -H "X-Authentik-Username: bob" \ - -H "X-Authentik-Groups: users|staff|admin" \ - | jq -r '.proxyAuthIsAdmin // "ERROR"' - -echo -n "POST /api/config/nodes (should work - 400 due to incomplete data): " -curl -s -X POST "$BASE_URL/api/config/nodes" \ - -H "X-Proxy-Secret: $PROXY_SECRET" \ - -H "X-Authentik-Username: bob" \ - -H "X-Authentik-Groups: users|staff|admin" \ - -H "Content-Type: application/json" \ - -d '{"name":"test","host":"192.168.1.1","type":"pve"}' \ - -o /dev/null -w "%{http_code}\n" - -echo -n "POST /api/system/settings/update (should work - 200): " -curl -s -X POST "$BASE_URL/api/system/settings/update" \ - -H "X-Proxy-Secret: $PROXY_SECRET" \ - -H "X-Authentik-Username: bob" \ - -H "X-Authentik-Groups: users|staff|admin" \ - -H "Content-Type: application/json" \ - -d '{"darkMode":true}' \ - -o /dev/null -w "%{http_code}\n" - -echo -n "POST /api/config/export (should work - 200): " -curl -s -X POST "$BASE_URL/api/config/export" \ - -H "X-Proxy-Secret: $PROXY_SECRET" \ - -H "X-Authentik-Username: bob" \ - -H "X-Authentik-Groups: users|staff|admin" \ - -H "Content-Type: application/json" \ - -d '{"passphrase":"test123456789"}' \ - -o /dev/null -w "%{http_code}\n" - -echo -echo "=== Testing without proxy auth (should fail) ===" -echo - -echo -n "POST /api/config/nodes (should be 401 Unauthorized): " -curl -s -X POST "$BASE_URL/api/config/nodes" \ - -H "Content-Type: application/json" \ - -d '{"name":"test","host":"192.168.1.1","type":"pve"}' \ - -o /dev/null -w "%{http_code}\n" - -# Restore original config -echo -echo "4. Restoring original configuration..." -mv /tmp/backup.env /etc/pulse/.env -sudo systemctl restart pulse-dev - -echo -echo "=== Test Complete ===" -echo "Summary:" -echo "- Non-admin users should get 403 Forbidden on write operations" -echo "- Admin users should be able to perform all operations" -echo "- Users without proxy auth should get 401 Unauthorized" \ No newline at end of file