Skip broken symlinks in usr update backups
Avoid aborting self-update backups when /usr contains dangling symlinks, such as host-created virtualenv links inside workdir. Broken file symlinks are logged and skipped so the backup can complete while preserving normal usr files. Fixes #1598
Alessandro committed
May 3, 2026 at 01:11 UTC
29c829b389bef11e662869e81ff15cb3506a8c50
2 files changed
+29
docker/run/fs/exe/self_update_manager.py
+3
@@ -366,6 +366,9 @@ def create_usr_backup(
366
root_path = Path(root)
367
for filename in files:
368
source_file = root_path / filename
369
+ if source_file.is_symlink() and not source_file.exists():
370
+ logger.log(f"Skipping broken symlink during usr backup: {source_file}")
371
+ continue
372
archive_name = Path("usr") / source_file.relative_to(usr_dir)
373
archive.write(source_file, archive_name.as_posix())
374
tests/test_self_update_tag_filter.py
+26
@@ -1,6 +1,7 @@
1
import importlib.util
2
import sys
3
import types
4
+import zipfile
5
from pathlib import Path
6
7
import pytest
@@ -755,6 +756,31 @@ def test_self_update_manager_queues_update_with_main_latest_defaults(monkeypatch
756
assert captured["payload"]["tag"] == "latest"
757
758
759
+def test_self_update_manager_usr_backup_skips_broken_symlinks(tmp_path):
760
+ manager = load_self_update_manager()
761
+ repo_dir = tmp_path / "repo"
762
+ usr_dir = repo_dir / "usr"
763
+ venv_bin = usr_dir / "workdir" / "reachy-mini-mcp" / ".venv" / "bin"
764
+ venv_bin.mkdir(parents=True)
765
+ (usr_dir / "settings.json").write_text('{"ok": true}\n', encoding="utf-8")
766
+ broken_symlink = venv_bin / "python"
767
+ broken_symlink.symlink_to("/missing/host/python")
768
+
769
+ backup_path = manager.create_usr_backup(
770
+ repo_dir=repo_dir,
771
+ backup_path=str(tmp_path / "backups"),
772
+ backup_name="usr-backup.zip",
773
+ conflict_policy="rename",
774
+ logger=manager.NullLogger(),
775
+ )
776
+
777
+ with zipfile.ZipFile(backup_path) as archive:
778
+ names = set(archive.namelist())
779
+
780
+ assert "usr/settings.json" in names
781
+ assert "usr/workdir/reachy-mini-mcp/.venv/bin/python" not in names
782
+
783
+
784
def test_self_update_manager_latest_on_main_uses_current_major_release(monkeypatch):
785
manager = load_self_update_manager()
786
monkeypatch.setattr(