Repository navigation
fix(security): R-11 — the image's code is not writable by the process that runs it - #529
Merged
Merged
Conversation
… that runs it The source and the virtual environment were owned by uid 65532, the user the app runs as, so code execution in the app could persist by rewriting a module. Both now belong to root. The runtime user writes only /app/logs, /app/uploads and a new /app/data, which holds the settings page's state (STATE_FILE, new, set by the image) and fine-tuned rerankers (RERANKER_MODEL_PATH, set by the image). A fine-tune now writes beside RERANKER_MODEL_PATH rather than a fixed ./models/reranker. Compose mounts app_data, so the state also survives a container recreation, which it never did. docker-smoke asserts each path's write access in the built image. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KkWPqAcWbxfqz1aCP6Qsdx
The hardened base already runs as 65532, and WORKDIR creates its directory as the current user, so /app was still the runtime user's even with its contents owned by root: a module dropped there would shadow any import, since /app is first on sys.path. Found by building the image and checking write access. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KkWPqAcWbxfqz1aCP6Qsdx
jwvanderstam
force-pushed
the
fix/r11-image-source-root-owned
branch
from
November 8, 2026 21:35
1767602 to
db306a1
Compare
From the separate review of #529. A model named by the pointer file or a version row is loaded only if it lies beside RERANKER_MODEL_PATH, and no model may bring its own code (trust_remote_code=False, explicitly). A promotion checks that first and writes the pointer before activating the row, so a version trained into ./models before this change is refused rather than marked active while the old model keeps serving. docker-smoke now walks /app and /opt/venv and fails on anything writable outside logs, uploads and data, on anything writable on sys.path, and on user site. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KkWPqAcWbxfqz1aCP6Qsdx
Owner
Author
Separate security review (CONTRIBUTING / QP-9)A separate agent session reviewed this PR. It built the image under a throwaway tag and walked the filesystem as uid 65532. No finding at Medium or above.
Findings and answers:
🤖 Generated with Claude Code |
Conflicts were side-by-side additions to CHANGELOG, file-map and the docs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



What
QP-9 review finding R-11 (Low): the image's source was owned by the runtime user. The virtual environment was too. So code execution in the app could persist by rewriting a module, or by dropping a new one into
/app(first onsys.path) that shadows any import.Change
/opt/venvare copied without--chown, so root owns them.USER 0:0at the start of the runtime stage. The hardened base already runs as 65532, andWORKDIRcreates its directory as the current user, so without this/appitself stayed writable. I found that by building the image and checking; it is the second commit./app/logs,/app/uploadsand a new/app/data.STATE_FILE=/app/data/app_state.jsonandRERANKER_MODEL_PATH=/app/data/reranker/latest.src/config.py:STATE_FILEis read from the environment. The default staysapp_state.json, so host runs are unchanged.src/rag/feedback_pipeline.py: a fine-tune writes its versions besideRERANKER_MODEL_PATH, wherepromote_model'slatest.txtpointer and the reranker look. Before, it wrote to a fixed./models/reranker, which is no longer writable in the image.docker-compose.yml: a newapp_datavolume on/app/data. A fresh volume is seeded from the image, owned by 65532, so no upgradechownis needed.docker-smoke: a new step asserts write access in the built image:/app,/app/src, a module and/opt/venv/libread-only; logs, uploads and data writable.Behaviour change (CHANGELOG, Changed)
The active model and RAG parameters now survive a container recreation. They were lost on every
up -d --build(ROADMAP's accepted-debt entry). When upgrading, values held in the old container are not carried over and must be set once more. A fine-tuned reranker in the old container falls back to the base model until retrained. The ROADMAP entry's real fix, anapp_settingstable, still stands for coherence; its Docker bullet is annotated.Verification
localchat:r11-smoke(the live stack untouched):src.configimports with production variables, andset_active_modelwrites/app/data/app_state.json.output_dirwrites besideRERANKER_MODEL_PATHand pointslatest.txtat it. The config-doc, env-example and compose tests pass, and ruff is clean.docker-smokeboot andsecurity-smoke(full compose) will exercise the rest in CI.🤖 Generated with Claude Code
https://claude.ai/code/session_01KkWPqAcWbxfqz1aCP6Qsdx