Skip to content

fix(docker): make venv writes group-writable to survive APP_UID drift - #844

Open
Ahmath-Gadji wants to merge 1 commit into
developfrom
feature/venv-umask-uid-drift-fix
Open

fix(docker): make venv writes group-writable to survive APP_UID drift#844
Ahmath-Gadji wants to merge 1 commit into
developfrom
feature/venv-umask-uid-drift-fix

Conversation

@Ahmath-Gadji

@Ahmath-Gadji Ahmath-Gadji commented Jul 31, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • The openrag_venv named volume persists across container recreations, but its non-root APP_UID can differ between a locally built image (defaults to the host UID via compose's build arg) and a pulled/CI-built image (defaults to the Dockerfile's own 10001) — even when both share the same image tag.
  • Default umask (022) makes uv sync create new venv entries writable only by the exact UID that wrote them, so a later sync under a different APP_UID can't remove/replace existing files (e.g. __editable__.openrag-X.Y.Z.pth, which changes on every version bump), failing with Permission denied.
  • Sets umask 002 before invoking uv run in the entrypoint so all future venv writes stay group (GID 0) writable, letting any APP_UID sharing that group resync without wiping the volume.

Note: this only prevents the issue going forward. Anyone hitting this today still needs a one-time docker volume rm of their openrag_venv volume to clear already-poisoned owner-only files.

Test plan

  • Populate openrag_venv under one APP_UID (e.g. local build with host UID), then re-sync under a different APP_UID (e.g. a pulled image or different APP_UID build arg) and confirm no Permission denied on uv sync.
  • Confirm normal container startup (docker compose up) still works unchanged.

Summary by CodeRabbit

  • Bug Fixes
    • Ensured files and directories created during application startup are writable by the appropriate group, improving compatibility in shared environments.

The openrag_venv named volume persists across container recreations,
but the openrag image's non-root APP_UID can differ between a locally
built image (defaults to the host UID) and a pulled/CI-built image
(defaults to 10001) even though both share the same image tag. The
default umask (022) makes `uv sync` create new venv entries writable
only by the exact UID that wrote them, so a later sync under a
different APP_UID fails to remove/replace files (e.g. the editable
install's __editable__*.pth on every version bump) with
"Permission denied".

Force umask 002 before running uv so venv entries stay group (GID 0)
writable, letting any APP_UID that shares that group resync.
@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The entrypoint now sets umask 002 before environment setup and application startup. This keeps files and directories created during virtual-environment synchronization group-writable for GID 0 users.

Changes

Startup permissions

Layer / File(s) Summary
Configure group-writable umask
infra/scripts/entrypoint.sh
The script documents cross-UID virtual-environment resynchronization and sets umask 002 before startup operations.

Estimated code review effort: 1 (Trivial) | ~2 minutes

Possibly related PRs

  • linagora/openrag#489: Adds arbitrary non-root UID handling with GID 0 membership in the same entrypoint.
  • linagora/openrag#742: Modifies the entrypoint to address GID 0 write permissions during container startup.

Suggested reviewers: enjoybacon7

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the Docker entrypoint change that makes virtual-environment writes group-writable across APP_UID changes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/venv-umask-uid-drift-fix

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@infra/scripts/entrypoint.sh`:
- Around line 33-40: Update the Ray init-container command in the ray cluster
template to set umask 002 immediately before its uv sync invocation, matching
the setting in entrypoint.sh. Ensure this direct sync path creates
group-writable venv entries so resynchronization under different GID-0 UIDs
remains possible.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 92828c79-6f7c-4369-832f-2e21bf547ce8

📥 Commits

Reviewing files that changed from the base of the PR and between 88da8b4 and 3609657.

📒 Files selected for processing (1)
  • infra/scripts/entrypoint.sh

Comment on lines +33 to +40
# The persisted openrag_venv volume can be re-synced by different APP_UIDs
# across the container's lifetime (e.g. a locally-built image bakes in the
# host UID while a pulled/CI-built image bakes in the Dockerfile default) —
# both share GID 0. Default umask (022) makes `uv sync` create new venv
# entries owner-writable only, so a later sync under a different UID can't
# remove/replace them ("Permission denied" on __editable__*.pth). Force
# group-writable new files/dirs so any GID-0 UID can always resync.
umask 002

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

rg -n -C 6 '\buv sync\b|\bumask\b|command:' \
  infra/scripts/entrypoint.sh \
  infra/charts \
  infra/docker

Repository: linagora/openrag

Length of output: 11846


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf '--- entrypoint outline/slice ---\n'
wc -l infra/scripts/entrypoint.sh
sed -n '1,90p' infra/scripts/entrypoint.sh | cat -n

printf '\n--- raycluster relevant slices ---\n'
wc -l infra/charts/openrag-stack/templates/raycluster.yaml
sed -n '1,70p' infra/charts/openrag-stack/templates/raycluster.yaml | cat -n
sed -n '115,145p' infra/charts/openrag-stack/templates/raycluster.yaml | cat -n

printf '\n--- chart values/security/default context references ---\n'
rg -n "mergeSecurityContext|podSecurityContext|containerSecurityContext|APP_UID|openrag_venv|venv" infra/charts openrag charts . -g'*.yaml' -g'*.tpl' -g'*.sh' | head -200

Repository: linagora/openrag

Length of output: 245


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf '%s\n' '--- entrypoint outline/slice ---'
wc -l infra/scripts/entrypoint.sh
sed -n '1,120p' infra/scripts/entrypoint.sh | cat -n

printf '%s\n' ''
printf '%s\n' '--- raycluster relevant slices ---'
wc -l infra/charts/openrag-stack/templates/raycluster.yaml
sed -n '1,80p' infra/charts/openrag-stack/templates/raycluster.yaml | cat -n
sed -n '115,145p' infra/charts/openrag-stack/templates/raycluster.yaml | cat -n

printf '%s\n' ''
printf '%s\n' '--- chart values/security/context references ---'
rg -n "mergeSecurityContext|podSecurityContext|containerSecurityContext|APP_UID|openrag_venv|venv|initContainers" infra/charts/openrag-stack -g'*.yaml' -g'*.tpl' | head -200

Repository: linagora/openrag

Length of output: 20441


🌐 Web query:

uv sync __editable__*.pth permissions Python virtual environment ownership

💡 Result:

In the uv ecosystem, editable*.pth files are standard mechanisms used for editable installations to extend sys.path [1][2]. If you encounter permission errors regarding these files or the.venv directory itself, it typically stems from ownership mismatches—often when a virtual environment is created by a privileged user (e.g., root in Docker) and subsequently accessed by an unprivileged user, or when a file system is read-only [3][4][5]. Permission issues in these contexts generally arise for the following reasons: Ownership and Docker: If uv sync is executed as root during a container build, the resulting.venv and its contents (including the.pth files) are owned by root [3]. Subsequent processes running as a non-privileged user will lack the necessary permissions to modify or, in some cases, properly interact with these files [3][6][7]. To resolve this, you should ensure the virtual environment directory is owned by the user who will be running the application, for instance by using chown after the installation step or by running the uv commands as the intended user [3][7]. Read-Only Filesystems: Python's site module attempts to process.pth files during interpreter initialization [1][5]. If the virtual environment resides on a read-only volume, this attempt will fail [5]. In such environments, you may need to suppress the automatic site initialization using the -S flag (e.g., uv run python -S ...), though this may affect how other packages are loaded [5]. Hidden Filesystem Flags: On macOS, if the.venv directory or the.pth files are marked with the UF_HIDDEN flag, modern Python versions (3.12+) will silently skip them, breaking the editable installation [8]. Verifying file attributes with ls -lO can help diagnose this [8]. To avoid permission issues, it is recommended to manage the virtual environment's creation and ownership explicitly within your workflows, ensuring the user executing the application has full read/write/execute access to the.venv directory [3][9]. If you are working in Docker, consider creating the directory and performing the sync as the non-privileged user, or adjusting permissions after the fact [3][7].

Citations:


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf '%s\n' '--- Dockerfile user setup and app UID defaults ---'
fd -i 'Dockerfile' . -x sh -c 'printf "\n### %s\n" "$1"; rg -n -C 3 "^USER|^ENV .*UID|APP_UID|workdir|COPY infra/scripts/entrypoint|chmod g=u|chmod .7|chmod g=u|groupadd|useradd" "$1" || true' sh {}

printf '%s\n' ''
printf '%s\n' '--- persistence/venv chart references ---'
sed -n '1,130p' infra/charts/openrag-stack/templates/pvc.yaml | cat -n
sed -n '1,80p' infra/charts/openrag-stack/values.yaml | cat -n
sed -n '220,235p' infra/charts/openrag-stack/values.yaml | cat -n

printf '%s\n' ''
printf '%s\n' '--- all containers/volumes using .venv in openrag-stack templates ---'
rg -n -C 3 "mountPath: /app/\.venv|claimName: .*venv|/app/\.venv|openrag_venv" infra/charts/openrag-stack/templates -g'*.yaml'

Repository: linagora/openrag

Length of output: 18613


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf '%s\n' '--- ray Dockerfile full setup section ---'
sed -n '1,75p' infra/docker/ray.Dockerfile | cat -n

printf '%s\n' ''
printf '%s\n' '--- ray env/config references ---'
rg -n -C 3 "APP_UID|APP_iPORT|KUBERAY|entrypoint|raycluster|openrag-stack.fullname|env:" infra/charts/openrag-stack/templates/raycluster.yaml infra/charts/openrag-stack/values.yaml

Repository: linagora/openrag

Length of output: 15965


Apply the umask to the Ray init-container sync path.

infra/scripts/entrypoint.sh sets umask 002, but the Ray init container in infra/charts/openrag-stack/templates/raycluster.yaml runs uv sync directly and does not inherit this setting. A later uv sync under a different UID can then fail when removing or replacing owner-only editable venv entries. Add umask 002 before uv sync in the init-container command, or use a shared startup helper for both sync paths.

Proposed chart fix
                 - |
+                umask 002
                 if [ -f /app/.venv/.ready ]; then
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@infra/scripts/entrypoint.sh` around lines 33 - 40, Update the Ray
init-container command in the ray cluster template to set umask 002 immediately
before its uv sync invocation, matching the setting in entrypoint.sh. Ensure
this direct sync path creates group-writable venv entries so resynchronization
under different GID-0 UIDs remains possible.

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