Skip to content

fix(file_ops): replace umask arithmetic with chmod "=rw" — zsh silently corrupts new-file perms - #74918

Merged
kshitijk4poor merged 1 commit into
NousResearch:mainfrom
kshitijk4poor:fix/70856-umask-chmod-portability
Jul 31, 2026
Merged

fix(file_ops): replace umask arithmetic with chmod "=rw" — zsh silently corrupts new-file perms#74918
kshitijk4poor merged 1 commit into
NousResearch:mainfrom
kshitijk4poor:fix/70856-umask-chmod-portability

Conversation

@kshitijk4poor

Copy link
Copy Markdown
Collaborator

Summary

Hardens the new-file umask fix that just merged in #74897: the $((0666 & ~0$u)) shell arithmetic silently corrupts permissions under zsh, which is a reachable backend shell via _find_bash()'s $SHELL fallback on bash-less hosts.

Root cause

zsh parses leading-zero constants as decimal (no octal_zeroes), so the arithmetic computes a garbage mode and chmod applies it without error. Reproduced against current main: new file chmodded to 0210 under umask 022 (expected 0644), 0230 under 002.

Changes

  • tools/file_operations.py: replace the arithmetic with POSIX who-less chmod "=rw" — spec-mandated to apply the umask (verified empirically on BSD, GNU coreutils 9.7, and busybox 1.37 chmod × bash/dash/ash/zsh; correct mode in every cell). Quoted so zsh doesn't =word-expand it; || true-guarded so an exotic chmod degrades to mktemp's 0600 (pre-fix behavior) instead of corrupting. Moved after cat so a write-masking umask can't EACCES the content stream. Also corrects the stale perms comment tools/file_operations.py::_atomic_write leaves newly-created files at mktemp's 0600, umask never applied (third instance of #14181/#23613's bug class) #70856 called out.
  • tests/tools/test_file_operations.py: parametrize the behavioral test over umasks 0022/0002/0077, add an overwrite mode-preservation regression guard (0755 script stays 0755), dedupe the real-subprocess env fake into make_real_subprocess_env() shared with TestSearchFilesFallbackHiddenPaths.

Validation

main (arithmetic) this PR (chmod "=rw")
bash/dash umask 022 0644 ✓ 0644 ✓
zsh umask 022 0210 (corrupt) 0644 ✓
zsh umask 002 0230 (corrupt) 0664 ✓
overwrite 0755 file preserved ✓ preserved ✓

tests/tools/test_file_operations.py: 42 passed. E2E real-subprocess matrix (4 umasks × new/overwrite): 8/8. ruff clean.

Surfaced during the final-diff review of #74897 / #70888 (salvage of @webtecnica's fix).

Follow-ups on top of NousResearch#70888's cherry-picked fix:

- Replace the $((0666 & ~0$u)) shell arithmetic with POSIX who-less
  'chmod "=rw"'. zsh (reachable via _find_bash's $SHELL fallback on
  bash-less hosts) parses leading-zero constants as decimal and silently
  chmods a garbage mode (e.g. 0210); the symbolic form is spec-identical
  across bash/dash/busybox-ash/zsh and degrades to mktemp's 0600
  (pre-fix behavior) rather than corrupting perms if chmod rejects it.
- Move the new-file chmod after the content stream so the temp file
  stays owner-writable while cat runs.
- Run the chmod on a '[ ! -e "$t" ]' check after cat instead of the
  stat/else branch, keeping the overwrite path untouched.
- Update the stale perms comment NousResearch#70856 called out (new files did NOT
  land with default umask perms pre-fix).
- Tests: select the atomic-write script by content instead of call
  order (the previous last-call capture only worked because the bare
  MagicMock's falsy-exit early return suppressed later execs), assert
  behavior at explicit umasks 0022/0002/0077 via parametrize, add an
  overwrite mode-preservation regression guard, and dedupe the
  real-subprocess env fake into make_real_subprocess_env() shared with
  TestSearchFilesFallbackHiddenPaths.

(webtecnica's email mapping already exists in contributors/emails/ on
current main; the PR's check-attribution red was stale-base only.)

# Conflicts:
#	tests/tools/test_file_operations.py
@alt-glitch alt-glitch added type/bug Something isn't working tool/file File tools (read, write, patch, search) P2 Medium — degraded but workaround exists labels Jul 30, 2026
@kshitijk4poor
kshitijk4poor enabled auto-merge (rebase) July 31, 2026 08:52
@kshitijk4poor
kshitijk4poor merged commit 98105f3 into NousResearch:main Jul 31, 2026
41 checks passed
@kshitijk4poor
kshitijk4poor deleted the fix/70856-umask-chmod-portability branch August 5, 2026 07:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

P2 Medium — degraded but workaround exists tool/file File tools (read, write, patch, search) type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants