fix: use Windows ACLs for credential file permissions in backup import (#56923) - #56949
AlexFucuson9 wants to merge 1 commit into
Conversation
os.chmod(path, 0o600) is a no-op on Windows — the file keeps its default 0o666 mode bits. This means credential-shaped files restored by 'hermes import' are not tightened on Windows. Add _restrict_file_permissions() helper that: - On POSIX: calls os.chmod(path, 0o600) as before - On Windows: uses ctypes to set NTFS DACL granting full access only to the current user and SYSTEM - Falls back to clearing world-readable bits if Windows API fails Fixes NousResearch#56923
Competing with #56946 (@liuhao1024) for the same fix (#56923). This PR actively sets a Windows DACL (current-user + SYSTEM) via |
teknium1
left a comment
There was a problem hiding this comment.
Thanks for addressing the Windows credential-restore gap; current main still has the two bare chmod(0o600) calls at hermes_cli/backup.py:604 and :648.
Problems
- The proposed
SetNamedSecurityInfoWfallback at PRhermes_cli/backup.py:105-108passes a security descriptor aspDacland ignores the API return code.pDaclmust be an ACL, so a primary-call failure can silently retain the inherited DACL. - The final fallback at PR
hermes_cli/backup.py:116repeats thechmod(0o600)operation the PR identifies as ineffective on Windows. - The diff adds no tests. Current
tests/hermes_cli/test_backup.py:2471asserts POSIX mode bits unconditionally, so it does not validate an NTFS ACL.
Suggested changes
- Use correctly declared ctypes signatures, pass a real ACL to
SetNamedSecurityInfoW(or retain one checkedSetFileSecurityWpath), check every return value, and release native resources. - Add a Windows-gated DACL verification test and restrict the existing mode-bit assertion to POSIX.
Automated hermes-sweeper review.
| str(path), SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, | ||
| None, None, sd, None, | ||
| ) | ||
|
|
There was a problem hiding this comment.
SetNamedSecurityInfoW takes a PACL as its sixth argument, but sd is the PSECURITY_DESCRIPTOR returned by ConvertStringSecurityDescriptorToSecurityDescriptorW; also check its DWORD return value. As written, a failed primary call can reach this branch, silently fail again, and return as though the DACL was restricted.
| except OSError: | ||
| pass | ||
| return | ||
|
|
There was a problem hiding this comment.
This repeats the 0o600 chmod operation that the PR identifies as ineffective on Windows, so it cannot be a security fallback after an ACL API failure. Use a verified ACL-specific fallback or report the failure instead.
Summary
os.chmod(path, 0o600)is a no-op on Windows — the file keeps its default0o666mode bits. This means credential-shaped files restored byhermes importare not tightened on Windows.Changes
Add
_restrict_file_permissions()helper tohermes_cli/backup.py:os.chmod(path, 0o600)as beforectypesto callSetFileSecurityW/SetNamedSecurityInfoWwith a DACL granting full access only to the current user and SYSTEMReplaces two bare
os.chmod(target, 0o600)calls (lines 604, 648) with the cross-platform helper.Why ctypes instead of pywin32
The
pywin32package (win32security) is an optional dependency. Usingctypesto calladvapi32directly avoids adding a hard dependency for a single function.Fixes
Fixes #56923