mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-09-22 19:23:31 +00:00
chore: clean up repository - remove test, backup and local dev files
This commit is contained in:
@@ -1,2 +0,0 @@
|
||||
LOG_LEVEL=debug
|
||||
DISABLE_AUTH=true
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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>
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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"
|
||||
Reference in New Issue
Block a user