| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283 |
- === BAMBUDDY FILE DELETION ISSUE - Jan 8, 2026 ===
- === ROOT CAUSE IDENTIFIED ===
- WHAT HAPPENED:
- - /opt was COMPLETELY DELETED on TWO containers:
- - Container 109 (claude): ~11:22 and ~12:22
- - Container 107 (3dp): ~13:28
- - Container 107 was "untouched" (no SSH, no Claude Code) - just running BamBuddy
- ROOT CAUSE FOUND:
- Bug in backend/app/services/archive.py delete_archive() function (lines 914-929):
- file_path = settings.base_dir / archive.file_path
- if file_path.exists():
- archive_dir = file_path.parent
- shutil.rmtree(archive_dir, ignore_errors=True) # <-- THE BUG
- If archive.file_path is EMPTY or MALFORMED:
- - file_path = /opt/bambuddy / "" = /opt/bambuddy
- - archive_dir = file_path.parent = /opt
- - shutil.rmtree("/opt") --> DELETES ENTIRE /opt DIRECTORY!
- TRIGGER:
- - User was deleting archives via BamBuddy web UI on container 107 (3dp)
- - One archive had corrupted/empty file_path in database
- - Deleting that archive triggered shutil.rmtree("/opt")
- - This deleted the entire /opt directory including BamBuddy itself
- TIMELINE FOR CONTAINER 107 (3dp):
- - 13:28:19 - Normal operation (WebSocket disconnect)
- - 13:28:44 - DELETE /api/v1/archives/* requests failing with 500
- (database already gone because /opt was deleted)
- - ls -la / shows root directory modified at 13:28
- FIX APPLIED (on container 109):
- Safety checks added to delete_archive() in archive.py:
- 1. Check if file_path is not empty
- 2. Verify archive_dir is inside settings.archive_dir
- 3. Ensure archive_dir is at least 2 levels deep
- 4. Log error and refuse to delete if checks fail
- TO INVESTIGATE AFTER ROLLBACK:
- On container 107, after rolling back to autodaily260108003006:
- # Find corrupted archive records
- sqlite3 /opt/bambuddy/data/bambuddy.db \
- "SELECT id, filename, file_path FROM print_archives
- WHERE file_path = '' OR file_path IS NULL
- OR file_path NOT LIKE 'archive/%';"
- # Check all file_path values
- sqlite3 /opt/bambuddy/data/bambuddy.db \
- "SELECT id, file_path FROM print_archives ORDER BY id;"
- CONTAINER 109 (this host):
- - Were you also deleting archives around 11:22 and 12:22?
- - Same bug could have been triggered here too
- PROXMOX COMMANDS FOR ROLLBACK:
- # Container 107 (3dp)
- pct rollback 107 autodaily260108003006
- pct start 107
- # Container 109 (claude) - already done via UI
- # Current snapshot: autodaily260108003004
- WHAT TO DO NEXT:
- 1. Rollback container 107 to morning snapshot
- 2. Run the SQL query above to find corrupted archive
- 3. Apply the fix from container 109 to container 107
- 4. Understand how the file_path got corrupted in the first place
- THE FIX (apply to both containers):
- In backend/app/services/archive.py, the delete_archive function now has:
- - Empty file_path check
- - Path traversal protection (relative_to check)
- - Minimum depth check (must be 2+ levels inside archive dir)
- - Error logging for refused deletions
- NOT CLAUDE CODE'S FAULT:
- This was a bug in BamBuddy's own code that was triggered by:
- 1. Corrupted database record (unknown how it got corrupted)
- 2. User action (deleting archives via web UI)
|