From 385c8d2ddfdb5c1a1790956e3736697363a01f9e Mon Sep 17 00:00:00 2001 From: YueKang <2389080918@qq.com> Date: Sat, 28 Mar 2026 16:47:38 +0800 Subject: [PATCH] fix: prevent self-referential symlinks in sync_scripts_to_workspaces When install.sh link_resources() creates workspace-*/scripts as a directory-level symlink pointing to the project scripts/ dir, iterating over it in sync_scripts_to_workspaces() produces dst_file paths that resolve to the same real file as src_file. The old idempotency check only skipped when dst_file itself was already a symlink: if dst_file.is_symlink() and dst_file.resolve() == src_resolved: return False For a workspace whose scripts/ directory is a symlink-to-directory, dst_file appears as a regular file (is_symlink() == False), so the check passes, the real source file is unlinked, and os.symlink() re-creates it as a self-referential link (foo.py -> foo.py). Running run_loop.sh every 15 s makes the whole scripts/ directory unusable within one cycle. Fix: resolve dst_file before any other check and bail out early when dst_resolved == src_resolved, regardless of whether dst_file itself is stored as a symlink entry. --- scripts/sync_agent_config.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/scripts/sync_agent_config.py b/scripts/sync_agent_config.py index c8d8ac1..0e7eda3 100644 --- a/scripts/sync_agent_config.py +++ b/scripts/sync_agent_config.py @@ -222,8 +222,19 @@ def _sync_script_symlink(src_file: pathlib.Path, dst_file: pathlib.Path) -> bool Returns True if the link was (re-)created, False if already up-to-date. """ src_resolved = src_file.resolve() + # Guard: skip if dst resolves to the same real path as src. + # This happens when ws_scripts is itself a directory-level symlink pointing + # to the project scripts/ dir (created by install.sh link_resources). + # Without this check the function would unlink the real source file and + # then create a self-referential symlink (foo.py -> foo.py). + try: + dst_resolved = dst_file.resolve() + except OSError: + dst_resolved = None + if dst_resolved == src_resolved: + return False # Already a correct symlink? - if dst_file.is_symlink() and dst_file.resolve() == src_resolved: + if dst_file.is_symlink() and dst_resolved == src_resolved: return False # Remove stale file / old physical copy / broken symlink if dst_file.exists() or dst_file.is_symlink():