Skip to content

Commit 1de334f

Browse files
authored
fix: mask file-type bits from chmod, harden staging dir symlink check
- Add `import stat` to imports - Use `stat.S_IMODE(mode)` before chmod in staging write (thread 20, line 1464) - Use `stat.S_IMODE(preserved_mode)` and make chmod best-effort in `_restore_stranded_config_file` (thread 18, line 1492) - Add `not rescue_staging_dir.is_symlink()` guard to cleanup (thread 19, line 1522) Assisted-by: GitHub Copilot (model: claude-sonnet-4.6, autonomous)
1 parent 351e23c commit 1de334f

1 file changed

Lines changed: 7 additions & 3 deletions

File tree

src/specify_cli/extensions/__init__.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import os
1515
import re
1616
import shutil
17+
import stat
1718
import tempfile
1819
import zipfile
1920
from dataclasses import dataclass
@@ -1461,7 +1462,7 @@ def install_from_directory(
14611462
finally:
14621463
os.close(fd)
14631464
try:
1464-
staged.chmod(mode)
1465+
staged.chmod(stat.S_IMODE(mode))
14651466
except (NotImplementedError, OSError):
14661467
pass # Best-effort; chmod may not be supported on all platforms.
14671468
except Exception:
@@ -1489,7 +1490,10 @@ def _restore_stranded_config_file(
14891490
) as tmp:
14901491
tmp_path = Path(tmp.name)
14911492
tmp.write(content)
1492-
tmp_path.chmod(preserved_mode)
1493+
try:
1494+
tmp_path.chmod(stat.S_IMODE(preserved_mode))
1495+
except (NotImplementedError, OSError):
1496+
pass # Best-effort; chmod may not be supported on all platforms.
14931497
os.replace(tmp_path, target)
14941498
except BaseException:
14951499
if tmp_path is not None and tmp_path.exists():
@@ -1518,7 +1522,7 @@ def _restore_stranded_config_file(
15181522
# durable staging backup is no longer needed. Raise on failure so
15191523
# the install is not reported as successful while a stale backup
15201524
# that could be misread on the next retry remains on disk.
1521-
if rescue_staging_dir.is_dir():
1525+
if rescue_staging_dir.is_dir() and not rescue_staging_dir.is_symlink():
15221526
shutil.rmtree(rescue_staging_dir)
15231527

15241528
# Register commands with AI agents

0 commit comments

Comments
 (0)