Skip to content

Set umask 002 system-wide instead of per-user shell rc files#53

Merged
kurowski merged 1 commit into
mainfrom
fix-umask-noninteractive-zsh
Jun 25, 2026
Merged

Set umask 002 system-wide instead of per-user shell rc files#53
kurowski merged 1 commit into
mainfrom
fix-umask-noninteractive-zsh

Conversation

@kurowski

@kurowski kurowski commented Jun 25, 2026

Copy link
Copy Markdown
Member

Problem

Drush (run by tooling) writes private://logs/debug-*.log as 644 owned by vscode:www-data, so the apache www-data web server can't append to them → pages 500 (notably /user/login, which breaks Cypress in a before all hook).

Why the per-user approach was fragile

The previous setup appended umask 002 to per-user shell rc files (~/.zshrc, ~/.bashrc) and relied on pam_umask. Two things defeat that in this devcontainer:

  • No PAM session. VS Code-spawned terminals and execs don't open a PAM session, so pam_umask never fires for them — that's why the shell-rc appends existed in the first place.
  • Personal dotfiles shadowing. Developers commonly symlink ~/.zshrc / ~/.bashrc from a personal dotfiles repo (e.g. applied after onCreate), which overwrites our per-user edits. The umask line silently disappears.

Change: set it system-wide

System shell files are immune to both problems, so set umask 002 there instead:

File Covers
/etc/zsh/zshenv Every zsh invocation — login/non-login, interactive/not. Covers the drush/tooling path.
/etc/bash.bashrc Interactive non-login bash (VS Code terminals)
/etc/profile.d/umask.sh Login shells (sh and bash)

The per-user appends in devcontainer_on_create are dropped as redundant. Only the in-process umask 002 is kept, because the system-wide config isn't in effect in that shell on the very first run (before the log file that drush deploy creates). pam_umask is kept as a backstop for real PAM sessions (ssh, su, cron).

Caveat (not a regression)

Non-interactive bash (bash -c, #!/bin/bash scripts) has no equivalent hook — bash has nothing like zshenv. This matches the previous behavior (~/.bashrc only covers interactive bash too), and the actual tooling path runs under zsh, which /etc/zsh/zshenv covers completely.

Verification

Reproduced in a running container with ~/.zshrc symlinked to a personal dotfiles repo: non-login zsh ran at 022 and drush wrote 644 logs. With umask 002 reaching the shell, interactive zsh and drush run at 002 and drush-created log files come out 664 (vscode:www-data), which the web server can append to. /etc/bash.bashrc confirmed sourced by interactive non-login bash, and /etc/profile.d/*.sh sourced by /etc/profile, on the mcr.microsoft.com/devcontainers/php:8.3 base image.

🤖 Generated with Claude Code

@kurowski kurowski force-pushed the fix-umask-noninteractive-zsh branch from 40257d8 to d8b27b8 Compare June 25, 2026 17:14
Drush (run by tooling) was writing private://logs/debug-*.log as 644
owned by vscode:www-data, so the apache www-data web server couldn't
append to them and pages 500'd.

The previous approach appended `umask 002` to per-user shell rc files
(~/.zshrc, ~/.bashrc) and relied on pam_umask. That's fragile here:

- VS Code-spawned terminals and `exec`s don't open a PAM session, so
  pam_umask never fires for them.
- Developers commonly symlink ~/.zshrc / ~/.bashrc from a personal
  dotfiles repo, which overwrites our per-user edits.

Set umask 002 in the system shell files instead, which are immune to
both problems:

- /etc/zsh/zshenv         - every zsh invocation (login/non-login,
                            interactive/not); covers the drush/tooling path
- /etc/bash.bashrc        - interactive non-login bash (VS Code terminals)
- /etc/profile.d/umask.sh - login shells (sh and bash)

The per-user appends in devcontainer_on_create are dropped as redundant;
only the in-process `umask 002` is kept, since the system-wide config
isn't in effect in that shell on the very first run (before the log file
that drush deploy creates). pam_umask is kept as a backstop for real PAM
sessions (ssh, su, cron).

Non-interactive bash (`bash -c`, scripts) has no equivalent hook, but
that matches the previous behavior and tooling runs under zsh, which
/etc/zsh/zshenv covers completely.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@kurowski kurowski force-pushed the fix-umask-noninteractive-zsh branch from d8b27b8 to 681641a Compare June 25, 2026 17:19
@kurowski kurowski changed the title Apply umask 002 to non-login zsh shells and personal-dotfiles users Set umask 002 system-wide instead of per-user shell rc files Jun 25, 2026
@kurowski kurowski merged commit 8369be9 into main Jun 25, 2026
1 check passed
@kurowski kurowski deleted the fix-umask-noninteractive-zsh branch June 25, 2026 19:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant