bambuddy-issue-notes.txt 3.0 KB

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