chore: clean up repository - remove test, backup and local dev files

This commit is contained in:
Pulse Monitor
2025-09-08 22:02:05 +00:00
parent c78626909b
commit 46eab6ca1f
8 changed files with 0 additions and 1219 deletions
-2
View File
@@ -1,2 +0,0 @@
LOG_LEVEL=debug
DISABLE_AUTH=true
-2
View File
@@ -1,2 +0,0 @@
DISABLE_AUTH=true
PULSE_MOCK_MODE=true
-588
View File
@@ -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 <PID>`
- **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 <number> --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 "<image_url>"` 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 <command>"`
- 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
-126
View File
@@ -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
-92
View File
@@ -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
-127
View File
@@ -1,127 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>PMG Backup Test</title>
<style>
body { font-family: monospace; padding: 20px; }
.backup { margin: 10px 0; padding: 10px; border: 1px solid #ccc; }
.host { background: #ffe6cc; }
.lxc { background: #ccffcc; }
.vm { background: #ccccff; }
.label { display: inline-block; padding: 2px 8px; border-radius: 3px; font-weight: bold; }
</style>
</head>
<body>
<h1>PMG Backup Detection Test</h1>
<button onclick="testBackups()">Run Test</button>
<div id="results"></div>
<script>
// Test data matching what the backend might send
const testBackups = [
// PBS backups
{
source: "PBS",
data: {
backupType: "ct",
vmid: "0",
comment: "PMG host configuration backup",
instance: "pbs-main",
backupTime: "2024-01-15T10:00:00Z"
}
},
{
source: "PBS",
data: {
backupType: "ct",
vmid: 0, // numeric
comment: "PMG backup",
instance: "pbs-main",
backupTime: "2024-01-14T10:00:00Z"
}
},
// Storage backups
{
source: "Storage",
data: {
type: "host",
vmid: 0,
volid: "local:backup/pmgbackup-pmg-01-2024_01_15.tar.zst",
notes: "PMG host config backup"
}
},
{
source: "Storage",
data: {
type: "lxc",
vmid: 0,
volid: "local:backup/vzdump-lxc-0-2024_01_15.tar.gz",
notes: "PMG configuration"
}
},
// Regular backups for comparison
{
source: "Storage",
data: {
type: "lxc",
vmid: 101,
volid: "local:backup/vzdump-lxc-101-2024_01_15.tar.gz",
notes: "Regular LXC"
}
}
];
function detectType(backup) {
// Mimics the frontend logic
if ('backupType' in backup) {
// PBS backup
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 {
return 'LXC';
}
} else if ('type' in backup) {
// Storage 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 {
return 'LXC';
}
}
return 'Unknown';
}
function testBackups() {
const results = document.getElementById('results');
results.innerHTML = '';
testBackups.forEach((test, i) => {
const type = detectType(test.data);
const div = document.createElement('div');
div.className = `backup ${type.toLowerCase()}`;
const isCorrect = (test.data.vmid === 0 || test.data.vmid === '0') ? type === 'Host' : true;
div.innerHTML = `
<strong>Test ${i + 1}: ${test.source} Backup</strong><br>
VMID: ${test.data.vmid} (type: ${typeof test.data.vmid})<br>
Type field: ${test.data.type || test.data.backupType || 'N/A'}<br>
Detected as: <span class="label ${type.toLowerCase()}">${type}</span>
${isCorrect ? '✓' : '✗ SHOULD BE HOST!'}
<br>
<small>${JSON.stringify(test.data)}</small>
`;
results.appendChild(div);
});
}
</script>
</body>
</html>
-142
View File
@@ -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);
}
-140
View File
@@ -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"