docs(blog): rootless design and PUID/PGID rationale#3105
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds a new blog post documenting why Seerr avoids PUID/PGID (requires starting the container as root to run chown), describes Seerr’s rootless shipping (runs as the node user), and instructs users to pre-own bind-mounted data directories on the host with UID/GID 1000. ChangesSeerr Rootless Security Blog Post
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Poem
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. 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. Comment |
There was a problem hiding this comment.
Pull request overview
Adds a new Docusaurus blog post documenting Seerr’s rootless-by-default container design, explaining why PUID/PGID env-based user switching is not supported, and guiding users toward the correct host-side chown workflow.
Changes:
- Introduces a new blog article detailing the security rationale for avoiding root entrypoints and
PUID/PGID. - Documents the recommended host bind-mount permissions setup (
chownto UID/GID 1000). - Links to upstream references (Docker, OWASP, Node.js Docker image docs) and related Seerr docs (Unraid).
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
864d30e to
ca5d0d3
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
gen-docs/blog/2026-06-03-why-seerr-runs-rootless.md (1)
6-6: ⚡ Quick winConsider using a commit hash or tag for the image URL.
The image URL references
refs/heads/develop, which points to the latest commit on the develop branch. This means the image could change unexpectedly with future commits, or break if the branch is renamed or deleted.📎 Suggested fix: pin to a specific commit or release tag
-image: https://raw.githubusercontent.com/seerr-team/seerr/refs/heads/develop/gen-docs/static/img/logo_full.svg +image: https://raw.githubusercontent.com/seerr-team/seerr/<commit-hash-or-tag>/gen-docs/static/img/logo_full.svg🤖 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 `@gen-docs/blog/2026-06-03-why-seerr-runs-rootless.md` at line 6, The image URL currently uses the mutable path "refs/heads/develop" (the line with image: https://raw.githubusercontent.com/seerr-team/seerr/refs/heads/develop/gen-docs/static/img/logo_full.svg), which can change or break; update that URL to pin to an immutable identifier by replacing "refs/heads/develop" with a specific commit SHA or a release tag (e.g., the commit hash or a vX.Y.Z tag) so the image is stable, and verify the updated URL serves correctly in the blog post (adjust other references to logo_full.svg if necessary).
🤖 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 `@gen-docs/blog/2026-06-03-why-seerr-runs-rootless.md`:
- Line 53: Replace the broken relative link
"./getting-started/third-parties/unraid" in the blog content with an absolute
site path (e.g. "/getting-started/third-parties/unraid") so the link resolves
correctly from /blog/[slug]/ pages; locate the string
"./getting-started/third-parties/unraid" in the blog post and update it to the
absolute path.
- Line 38: Update the sentence about pnpm to tighten security claims: state that
pnpm's content-addressable store, hard links and non-hoisted/symlinked
node_modules layout (mentioning hoist=false/semi-strict hoisting) reduce
phantom-dependency risks, and separately attribute mitigation of
dependency-confusion attacks to correct registry scoping (e.g.,
.npmrc/private-registry scoping) plus hardened install controls
(lockfile/integrity checks, lifecycle-script controls), rather than implying the
CAS/hard-links alone prevent dependency confusion.
---
Nitpick comments:
In `@gen-docs/blog/2026-06-03-why-seerr-runs-rootless.md`:
- Line 6: The image URL currently uses the mutable path "refs/heads/develop"
(the line with image:
https://raw.githubusercontent.com/seerr-team/seerr/refs/heads/develop/gen-docs/static/img/logo_full.svg),
which can change or break; update that URL to pin to an immutable identifier by
replacing "refs/heads/develop" with a specific commit SHA or a release tag
(e.g., the commit hash or a vX.Y.Z tag) so the image is stable, and verify the
updated URL serves correctly in the blog post (adjust other references to
logo_full.svg if necessary).
🪄 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: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: a5effe10-83ff-4b8d-88ee-c2f5544abffc
📒 Files selected for processing (1)
gen-docs/blog/2026-06-03-why-seerr-runs-rootless.md
There was a problem hiding this comment.
♻️ Duplicate comments (1)
gen-docs/blog/2026-06-03-why-seerr-runs-rootless.md (1)
38-38:⚠️ Potential issue | 🟠 Major | ⚡ Quick winTighten pnpm security claims: separate phantom dependencies from dependency confusion mitigation.
As noted in the previous review, the claim about dependency confusion needs refinement. While pnpm's content-addressable store and non-hoisted structure do reduce phantom dependencies, dependency confusion attacks are primarily mitigated through registry scoping (
.npmrcconfiguration for private registries) and install-time controls (lockfile integrity checks, lifecycle script restrictions), not through pnpm's internal architecture alone.Consider rewording to: "Unlike npm, pnpm uses a content-addressable store with hard links and does not hoist packages into a flat
node_modulesstructure, preventing phantom dependencies. Combined with proper registry scoping and strict install controls, this approach strengthens defense against supply chain attacks."🤖 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 `@gen-docs/blog/2026-06-03-why-seerr-runs-rootless.md` at line 38, Update the paragraph that begins "We also use pnpm as our package manager..." to separate claims about phantom dependencies and dependency confusion: keep the explanation that pnpm's content-addressable store, hard links, and non-hoisted node_modules prevent phantom dependencies, but then add that dependency confusion is primarily mitigated by registry scoping and install-time controls (e.g., .npmrc private registries, lockfile integrity, lifecycle script restrictions); replace the existing sentence with the suggested rewording "Unlike npm, pnpm uses a content-addressable store with hard links and does not hoist packages into a flat node_modules structure, preventing phantom dependencies. Combined with proper registry scoping and strict install controls, this approach strengthens defense against supply chain attacks."
🧹 Nitpick comments (1)
gen-docs/blog/2026-06-03-why-seerr-runs-rootless.md (1)
10-10: 💤 Low valueConsider rephrasing for clarity.
The sentence "why chown is not the workaround it might seem like at first glance. It is actually the correct approach" creates unnecessary uncertainty by framing it as "not a workaround" before clarifying it's correct. Consider direct phrasing like: "This post explains the reasoning behind that decision and why using chown on the host is the correct approach."
🤖 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 `@gen-docs/blog/2026-06-03-why-seerr-runs-rootless.md` at line 10, The sentence currently phrased as "why chown is not the workaround it might seem like at first glance. It is actually the correct approach." should be rewritten to a direct, clear statement; replace that fragment in the paragraph that begins "A common question we get..." with a concise alternative such as "This post explains the reasoning behind that decision and why using chown on the host is the correct approach." Update the string in the blog text so the paragraph reads smoothly and removes the contradictory "not a workaround" phrasing.
🤖 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.
Duplicate comments:
In `@gen-docs/blog/2026-06-03-why-seerr-runs-rootless.md`:
- Line 38: Update the paragraph that begins "We also use pnpm as our package
manager..." to separate claims about phantom dependencies and dependency
confusion: keep the explanation that pnpm's content-addressable store, hard
links, and non-hoisted node_modules prevent phantom dependencies, but then add
that dependency confusion is primarily mitigated by registry scoping and
install-time controls (e.g., .npmrc private registries, lockfile integrity,
lifecycle script restrictions); replace the existing sentence with the suggested
rewording "Unlike npm, pnpm uses a content-addressable store with hard links and
does not hoist packages into a flat node_modules structure, preventing phantom
dependencies. Combined with proper registry scoping and strict install controls,
this approach strengthens defense against supply chain attacks."
---
Nitpick comments:
In `@gen-docs/blog/2026-06-03-why-seerr-runs-rootless.md`:
- Line 10: The sentence currently phrased as "why chown is not the workaround it
might seem like at first glance. It is actually the correct approach." should be
rewritten to a direct, clear statement; replace that fragment in the paragraph
that begins "A common question we get..." with a concise alternative such as
"This post explains the reasoning behind that decision and why using chown on
the host is the correct approach." Update the string in the blog text so the
paragraph reads smoothly and removes the contradictory "not a workaround"
phrasing.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 7ac23f92-25cf-4e41-903c-947c2d9b1cdc
📒 Files selected for processing (1)
gen-docs/blog/2026-06-03-why-seerr-runs-rootless.md
ca5d0d3 to
d35f102
Compare
There was a problem hiding this comment.
♻️ Duplicate comments (1)
gen-docs/blog/2026-06-03-why-seerr-runs-rootless.md (1)
38-38:⚠️ Potential issue | 🟠 Major | ⚡ Quick winTighten the pnpm claim to avoid overstatement of default behavior.
The sentence still reads as absolute (“non-hoisted … prevents phantom dependencies”). pnpm’s defaults are nuanced (semi-strict/hoisting behavior), so this should be phrased as risk reduction under strict config, and dependency-confusion mitigation should be attributed primarily to registry scoping plus install-policy controls.
Proposed wording update
-We also use [pnpm](https://pnpm.io) as our package manager, which takes a stricter and more secure approach to dependency management than npm. Unlike npm, pnpm uses a content-addressable store with hard links and a non-hoisted, symlinked `node_modules` layout that prevents phantom dependencies (packages silently relying on undeclared transitive dependencies). pnpm also ships with hardened install defaults, including integrity verification and lifecycle script controls, that reduce the supply-chain attack surface. +We also use [pnpm](https://pnpm.io) as our package manager, which takes a stricter approach to dependency management than npm. Its content-addressable store and symlinked `node_modules` model can reduce accidental reliance on undeclared transitive dependencies (especially with strict hoisting settings). Separately, dependency-confusion risk is primarily mitigated by correct private-registry scoping and hardened install controls (lockfiles, integrity checks, and lifecycle-script policies).What are pnpm's current default hoisting semantics (including "semi-strict" behavior), and which controls are documented for dependency-confusion mitigation (registry scoping, lockfiles, integrity checks, lifecycle script policies)?🤖 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 `@gen-docs/blog/2026-06-03-why-seerr-runs-rootless.md` at line 38, The pnpm description overstates defaults; revise the sentence that begins "Unlike npm, pnpm uses a content-addressable store..." to soften absolutes: note pnpm uses a content-addressable store and a strict/non-hoisted-by-default layout with "semi-strict" hoisting semantics rather than claiming it outright prevents phantom dependencies, and state it can reduce dependency-supply risks when configured correctly (e.g., strict install policies). Also attribute dependency-confusion mitigation to registry scoping, lockfiles, integrity verification, and lifecycle script controls (rather than implying npm-style issues are fully prevented by pnpm alone).
🤖 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.
Duplicate comments:
In `@gen-docs/blog/2026-06-03-why-seerr-runs-rootless.md`:
- Line 38: The pnpm description overstates defaults; revise the sentence that
begins "Unlike npm, pnpm uses a content-addressable store..." to soften
absolutes: note pnpm uses a content-addressable store and a
strict/non-hoisted-by-default layout with "semi-strict" hoisting semantics
rather than claiming it outright prevents phantom dependencies, and state it can
reduce dependency-supply risks when configured correctly (e.g., strict install
policies). Also attribute dependency-confusion mitigation to registry scoping,
lockfiles, integrity verification, and lifecycle script controls (rather than
implying npm-style issues are fully prevented by pnpm alone).
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 1f461edc-d395-4e39-aaf0-dbc115f876ea
📒 Files selected for processing (1)
gen-docs/blog/2026-06-03-why-seerr-runs-rootless.md
d35f102 to
5e86513
Compare
5668438 to
9dcfc97
Compare
9dcfc97 to
79bd30c
Compare
|
Maybe add the blog link into https://docs.seerr.dev/getting-started/docker/ something like "PUID/PGUID is not supported if you want to find out why check our blog blabla" |
| For additional hardening, you can mount the container filesystem as [read-only](https://docs.docker.com/reference/compose-file/services/#read_only) and grant write access only to your data directory. Since all runtime writes go through `CONFIG_DIRECTORY`, nothing outside that volume needs to be writable. | ||
| ::: | ||
|
|
||
| If you need the PUID/PGID pattern, third-party images that implement it already exist. But it is not something we will maintain here, because it would mean knowingly reintroducing a security regression we deliberately moved away from. |
There was a problem hiding this comment.
It might also be worth while to note that "adding PGID/GUID+root, as an option, besides running as a limited user, while possible, also would require significant additional testing and maintenance requirements to an unreasonable degree"
There was a problem hiding this comment.
To be honest, not really. We could use s6-overlay, which is what everyone uses when they support PUID/PGID, like LinuxServer.
There was a problem hiding this comment.
While s6-overlay, in theory, would support offering the two options, it is flaky at best.
Even through s6-overlay supporting both requires the same maintenance and testing burden as doing so with out it.
(I know, having worked with about a hundred s6-overlay based containers in Helm-Charts, its extremely unreliable weither the "offer both options" features work)
There was a problem hiding this comment.
@fallenbagel it might be worth mentioning that then?
0834c2c to
7850bbc
Compare
Follow up pr once this is merged |
Description
Adds a blog post explaining why Seerr runs rootless and does not support
PUID/PGIDenvironment variables, covering the security rationale behind the decision and the correctchownapproach for setting up host directory permissions.How Has This Been Tested?
(This is a blog post).
Screenshots / Logs (if applicable)
Checklist:
pnpm buildpnpm i18n:extractSummary by CodeRabbit