Write .env with 0600 permissions and warn on loose modes#252
Write .env with 0600 permissions and warn on loose modes#252jackson-asmith wants to merge 2 commits into
Conversation
The device password is stored in .env as TC_PASSWORD. This ensures the file is created owner-only and repairs a loose mode on rewrite, and adds a doctor warning when an existing .env is group/world-accessible. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Code Review
This pull request introduces owner-only (0600) permission enforcement and warnings for the .env configuration file, which stores sensitive credentials. It adds a utility function to check for loose permissions on POSIX systems, integrates this check into the doctor command validation steps, and updates write_env_file to explicitly set permissions. Feedback suggests removing a redundant os.chmod call after os.replace, as permissions are already preserved during the replacement and the extra call could cause failures on certain filesystems.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| os.chmod(tmp_name, 0o600) | ||
| os.replace(tmp_name, path) | ||
| os.chmod(path, 0o600) |
There was a problem hiding this comment.
Calling os.chmod(path, 0o600) after os.replace(tmp_name, path) is redundant on POSIX systems. On POSIX, os.replace (which maps to the rename system call) preserves the inode and metadata (including permissions) of the source file. Since tmp_name is already explicitly chmod'ed to 0o600 on line 682, the destination file path will automatically inherit those permissions after the replacement.
Furthermore, calling os.chmod on the final path can introduce unnecessary failure points on certain filesystems (such as NFS, host-shared volumes in Docker/Vagrant, or restricted mount points) where chmod operations are restricted or unsupported, even if the file was successfully written and replaced. Removing the redundant call makes the file write more robust.
| os.chmod(tmp_name, 0o600) | |
| os.replace(tmp_name, path) | |
| os.chmod(path, 0o600) | |
| os.chmod(tmp_name, 0o600) | |
| os.replace(tmp_name, path) |
Addresses review feedback on jamesyc#252. On POSIX, os.replace preserves the temp file's 0600 mode on the destination inode, so the extra chmod on the final path was redundant and could fail on filesystems (NFS, some shared mounts) that restrict chmod even after a successful write. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Good call — removed the redundant |
|
This one breaks workflows where .env needs another user's access for whatever reason; like a docker container, etc. Better to leave it as 0600 for the vast majority of cases, but give power users the ability to set a different value. This is slightly less secure in theory, but in practice not really a big security hole. |
|
Reworked this per your feedback into #258, which defaults to 0600 but adds a |
What
Hardens the on-disk permissions of the local
.env, which stores the device password asTC_PASSWORD.Why
configurewrites the device/root password to.envin plaintext. The atomic write already tended to produce owner-only files, but nothing guaranteed it, and a pre-existing.envwith a looser mode was left as-is. Anyone with read access to that directory (including a synced backup) could read the device password.Changes
write_env_filenow explicitlychmods the file to0600(both the temp file and the final path), so a rewrite also repairs a previously loose mode.env_file_permission_warning(path)returns a message when a POSIX.envis group/other-accessible.doctorsurfaces that as aWARNright after confirming the config file exists, with achmod 600hint..envis0600and should not be cloud-synced.No behavior change for the common case (files were already effectively
0600); this closes the gap where they weren't.Tests
tests/test_config.py:write_env_fileyields0600even over a pre-existing0644file;env_file_permission_warningflags loose modes and is silent for0600/missing files.tests/test_checks.py:doctorconfig validation emits theWARNfor a loose-mode.env.Full suite green (
python -m pytest, 1638 passed). Scoped to.envpermissions only.🤖 Generated with Claude Code