From ba52a1ee98f5ed3502e6fc74a80527aae85758db Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 6 Nov 2026 18:18:50 +0000 Subject: [PATCH 1/7] docs(specs): add spec 030 security context overrides draft Co-Authored-By: Claude Opus 5.5 Signed-off-by: Claude --- .../OPEN-DECISIONS.md | 28 ++ .../checklists/requirements.md | 38 +++ specs/030-security-context-overrides/spec.md | 244 ++++++++++++++++++ 3 files changed, 310 insertions(+) create mode 100644 specs/030-security-context-overrides/OPEN-DECISIONS.md create mode 100644 specs/030-security-context-overrides/checklists/requirements.md create mode 100644 specs/030-security-context-overrides/spec.md diff --git a/specs/030-security-context-overrides/OPEN-DECISIONS.md b/specs/030-security-context-overrides/OPEN-DECISIONS.md new file mode 100644 index 000000000..d47763c0f --- /dev/null +++ b/specs/030-security-context-overrides/OPEN-DECISIONS.md @@ -0,0 +1,28 @@ +# Open decisions: spec 030 security context overrides + +Each item stays OPEN until valgul answers that exact question. + +## OD-1: Who may set security overrides? (OPEN) + +- A. Anyone with `servers:write` on that server's namespace. +- B. A new permission `servers:security`, granted to admin by default and to no other + built-in role. (Recommended: running a game as another uid, or root, is a node-level + risk, and a separate key lets an admin hand it out deliberately.) +- C. Admins only, no new permission. + +## OD-2: Is run-as user or group 0 (root) allowed as an override? (OPEN) + +- A. Never: overrides must be 1 or more; a module that needs root simply sets no + run-as user. +- B. Allowed, but only for users who hold the OD-1 permission, with an extra warning in + the dashboard. (Recommended: some images, like Palworld's, must start as root to drop + privileges, and "use image default" already covers most of those; 0 stays possible + for the rare image that needs it.) +- C. Allowed only if a cluster-wide setting turns it on (off by default). + +## OD-3: Does changing an override on an existing server restart it? (OPEN) + +- A. No: it applies on the next restart and the dashboard says so. (Recommended: + matches how other settings that change the pod behave, and avoids kicking players + without warning.) +- B. Yes: saving restarts the server right away, after a confirmation. diff --git a/specs/030-security-context-overrides/checklists/requirements.md b/specs/030-security-context-overrides/checklists/requirements.md new file mode 100644 index 000000000..5cfc30ab0 --- /dev/null +++ b/specs/030-security-context-overrides/checklists/requirements.md @@ -0,0 +1,38 @@ +# Specification Quality Checklist: Module security defaults with a per-server override + +**Purpose**: Validate specification completeness and quality before proceeding to planning +**Created**: 2026-11-06 +**Feature**: [spec.md](../spec.md) + +## Content Quality + +- [X] No implementation details (languages, frameworks, APIs) +- [X] Focused on user value and business needs +- [X] Written for non-technical stakeholders +- [X] All mandatory sections completed + +## Requirement Completeness + +- [ ] No [NEEDS CLARIFICATION] markers remain +- [X] Requirements are testable and unambiguous +- [X] Success criteria are measurable +- [X] Success criteria are technology-agnostic (no implementation details) +- [X] All acceptance scenarios are defined +- [X] Edge cases are identified +- [X] Scope is clearly bounded +- [X] Dependencies and assumptions identified + +## Feature Readiness + +- [X] All functional requirements have clear acceptance criteria +- [X] User scenarios cover primary flows +- [X] Feature meets measurable outcomes defined in Success Criteria +- [X] No implementation details leak into specification + +## Notes + +- Open questions are tracked as OD-1..OD-3 in `OPEN-DECISIONS.md` instead of inline + markers (project rule: unsettled values go in OPEN-DECISIONS.md). The first + Requirement Completeness item stays unchecked until all three are answered. +- Names such as "reconciler", "API" and "audit log" refer to existing Gameplane + components the stakeholders already know; no new technology is prescribed. diff --git a/specs/030-security-context-overrides/spec.md b/specs/030-security-context-overrides/spec.md new file mode 100644 index 000000000..f623b6042 --- /dev/null +++ b/specs/030-security-context-overrides/spec.md @@ -0,0 +1,244 @@ +# Feature Specification: Module security defaults with a per-server override + +**Feature Branch**: `spec-030/security-context-overrides` + +**Created**: 2026-11-06 + +**Status**: Draft + +**Input**: User description: "make the different security group controlable with default inside the module and a way in a "advanced" view to force it to something else on the frontend" + +## Context + +A game template can already declare the user id, group id and filesystem group its +game container runs with (the template's `security` block, used today by about 14 +modules, for example ARK at uid 25000 and Minecraft at 1000 in module PR 56). Those +values are fixed: a server owner who hits a host-specific problem (like the gosu +spin on ARM64 that module PR 56 works around), or who mounts a volume already owned +by another uid, has no way to change them without forking the module. + +This feature keeps the module's values as the default and adds a per-server +override that the dashboard exposes in an "Advanced" section. + +The "security settings" in this spec are the three values the template already +supports: **run-as user**, **run-as group** and **filesystem group**. + +## User Scenarios & Testing *(mandatory)* + +### User Story 1 - Server uses the module's security defaults (Priority: P1) + +A server owner creates a server from a module that declares security settings and +does nothing special. The server runs with exactly the module's values, and the +owner can see which values are in effect. + +**Why this priority**: This is today's behaviour and must not regress. Every other +story builds on the module default being the baseline. + +**Independent Test**: Create a server from a module with security settings and one +without; confirm each runs with the module's values (or the image's own default user +when the module sets none), and that the server's settings show those values marked +as "module default". + +**Acceptance Scenarios**: + +1. **Given** a module that sets run-as user 1000, run-as group 1000 and filesystem + group 1000, **When** a server is created without overrides, **Then** the game + runs as 1000/1000 and its data volume is group-owned by 1000. +2. **Given** a module that sets no security settings, **When** a server is created + without overrides, **Then** the game runs exactly as it does today (the image's + own default user), with no extra security settings applied. +3. **Given** a server with no overrides, **When** the module is upgraded to a + version with different security defaults, **Then** the server picks up the new + defaults on its next restart. + +--- + +### User Story 2 - Override the security settings when creating a server (Priority: P1) + +While creating a server, the owner opens an "Advanced" section, sees the module's +default for each of the three settings, and forces one or more of them to a +different value (or explicitly clears one so the image's own default applies). + +**Why this priority**: This is the core ask: a way to force a different value +without editing the module. + +**Independent Test**: In the create-server wizard, open Advanced, set run-as user to +a value different from the module default, create the server, and confirm the game +runs as that user while the other two settings keep the module default. + +**Acceptance Scenarios**: + +1. **Given** the create-server wizard, **When** the owner has not opened Advanced, + **Then** no security values are sent and the module defaults apply. +2. **Given** the Advanced section, **When** the owner views it, **Then** each of the + three settings shows the module default (or "image default" when the module sets + none) and an empty override field. +3. **Given** the owner sets an override for one setting, **When** the server is + created, **Then** only that setting differs from the module default. +4. **Given** the owner explicitly chooses "use image default" for a setting the + module sets, **When** the server is created, **Then** that setting is not applied + to the game container. +5. **Given** an invalid value (negative, non-numeric, above the allowed maximum), + **When** the owner submits, **Then** the wizard rejects it with a clear message + before anything is created. + +--- + +### User Story 3 - Change or remove an override on an existing server (Priority: P2) + +On an existing server's settings page, the owner opens the same Advanced section, +changes or removes an override, and the change takes effect on the next restart. +Removing an override returns that setting to the module default. + +**Why this priority**: Fixes like the gosu one are usually discovered after the +server exists. It is P2 because changing the run-as user on a server with existing +data can lock the game out of its own files, so it needs a warning. + +**Independent Test**: On a running server, set a run-as user override, save, restart, +and confirm the new user; then remove it and confirm the module default returns. + +**Acceptance Scenarios**: + +1. **Given** an existing server, **When** the owner changes an override and saves, + **Then** the dashboard warns that the server must restart and that existing files + may not be readable by the new user, and the change applies on restart. +2. **Given** a server with an override, **When** the owner clears it, **Then** the + setting shows "module default" again and the module's value applies on restart. +3. **Given** a server with an override, **When** the module is upgraded with new + defaults, **Then** the overridden setting keeps the override and the other + settings follow the new defaults. + +--- + +### User Story 4 - Restrict who can force security settings (Priority: P2) + +An administrator controls who may set security overrides, because running a game as +root (user 0) or as an arbitrary uid changes what the container can do on the node. + +**Why this priority**: Without it, any user who can create servers could run a game +container as root, which weakens the threat model in `docs/security.md`. + +**Independent Test**: As a user without the permission, confirm the Advanced +security fields are read-only (module defaults shown) and that an API request +carrying overrides is refused; as a user with it, confirm both work. + +**Acceptance Scenarios**: + +1. **Given** a user without permission to override security settings, **When** they + open Advanced, **Then** they see the effective values but cannot edit them. +2. **Given** such a user sends an override directly to the API, **When** the request + is processed, **Then** it is refused with a permission error and nothing changes. +3. **Given** a request that sets run-as user 0, **When** it is processed, **Then** it + follows the root rule decided in OD-2. + +--- + +### Edge Cases + +- A module sets only the filesystem group (Palworld, whose image must start as root + to drop privileges): an override of run-as user on such a server would break the + image's own privilege drop. The Advanced section shows the module's own note (if + any) and a warning that the module expects the image's default user. +- An override sets the filesystem group but not the run-as user: allowed; it only + changes which group the data volume is shared with. +- A server is restored from a backup made under different security settings: the + restore uses the server's current effective settings. +- The module is uninstalled or its template removed while a server has overrides: + the override stays on the server and is reapplied if the template returns. +- Helper containers (the management agent, config and mod init steps, backups) keep + their own fixed users; only the game container's user/group and the pod's + filesystem group change. Backup and restore jobs use the effective filesystem + group so they keep access to the data. +- The values are numeric ids only; user and group names are not accepted. + +## Requirements *(mandatory)* + +### Functional Requirements + +- **FR-001**: Modules MUST remain the source of the default security settings + (run-as user, run-as group, filesystem group); a server without overrides MUST + behave exactly as it does today. +- **FR-002**: Each server MUST be able to store an override for each of the three + settings independently. Each override is one of: not set (use module default), + a specific numeric id, or "use image default" (do not apply this setting even if + the module sets it). +- **FR-003**: The effective value of each setting MUST be the server's override when + present, otherwise the module default, otherwise nothing (image default). +- **FR-004**: The reconciler MUST be the only place that computes and applies the + effective settings; the API only stores and validates the override. +- **FR-005**: Override values MUST be validated as whole numbers from 0 to + 4294967295, matching the module's own limits, with the root rule from OD-2. +- **FR-006**: The create-server wizard MUST offer a collapsed "Advanced" section that + shows, per setting, the module default and an optional override. +- **FR-007**: The server settings page MUST offer the same Advanced section for an + existing server, with a warning before saving a change to the run-as user or group + of a server that already has data. +- **FR-008**: Changing an override on an existing server MUST take effect on the next + restart and MUST say so in the dashboard; it MUST NOT restart the server by itself + [decided in OD-3]. +- **FR-009**: The server's details MUST show each effective value and whether it comes + from the module or from an override. +- **FR-010**: Setting, changing or removing an override MUST require the permission + decided in OD-1, enforced by the API, and MUST be recorded in the audit log with + before and after values. +- **FR-011**: Backup and restore jobs MUST use the server's effective filesystem + group, not only the module's. +- **FR-012**: Helper containers (agent, init steps, sentinel, tunnel) MUST keep their + existing fixed security settings regardless of overrides. +- **FR-013**: The module authoring docs MUST explain that the template's security + block is now a default that server owners can override, and when a module author + should say so in the module README (for example "must start as root"). +- **FR-014**: All new dashboard text MUST go through the shared language packs. + +### Key Entities + +- **Module security defaults**: the three optional numeric values a game template + declares today. Unchanged by this feature, but now described as defaults. +- **Server security override**: per server, for each of the three settings, either + absent, a numeric id, or "use image default". Owned by the server, survives module + upgrades and reinstalls. +- **Effective security settings**: the result of combining the two, computed by the + reconciler and reported back on the server's status so the dashboard can show where + each value came from. + +## Success Criteria *(mandatory)* + +### Measurable Outcomes + +- **SC-001**: 100% of existing servers keep the same running user, group and + filesystem group after the upgrade that ships this feature (no override means no + change). +- **SC-002**: A server owner with the permission can force a different run-as user + on a new server in under 1 minute, without editing or forking the module. +- **SC-003**: A user without the permission cannot change any of the three settings, + through the dashboard or the API, in 100% of attempts. +- **SC-004**: For every server, the dashboard shows each of the three effective + values and its source (module or override), matching what the game container + actually runs with. +- **SC-005**: Every override change appears in the audit log with who, when, before + and after. + +## Assumptions + +- "Security group" in the request means the three values the template's security + block already supports (run-as user, run-as group, filesystem group). Other + container hardening (capabilities, read-only root, privilege escalation, supplemental + groups, the filesystem group change policy) is out of scope for this spec. +- The override applies to the game container and the pod's filesystem group only, + matching how the module's values are applied today. +- The "Advanced" view is a collapsed section inside the existing create-server wizard + and server settings screens, not a new page. It is designed in `design.pen` first + (on valgul's local machine) before any dashboard code. +- The REST API and the MCP server expose the same override; the read-only MCP server + only reads it. +- Existing data ownership is not changed automatically when the run-as user changes; + the filesystem group is the supported way to share a volume. A one-off + "fix ownership" action is out of scope. +- The end-to-end proof is a Kind E2E test that creates a server with an override and + checks the running uid, per the constitution's E2E principle. + +## Open decisions + +Recorded in [`OPEN-DECISIONS.md`](OPEN-DECISIONS.md): OD-1 (who may override), +OD-2 (whether run-as user/group 0 is allowed), OD-3 (whether a change restarts the +server). The spec is not ready for `/speckit-plan` until all three are answered. From a59ca5f2d7f73af843beb27ff434eb1df0d463a9 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 7 Nov 2026 16:04:50 +0000 Subject: [PATCH 2/7] docs(specs): settle spec 030 OD-1 (servers:security permission) Co-Authored-By: Claude Opus 5.5 Signed-off-by: Claude --- specs/030-security-context-overrides/OPEN-DECISIONS.md | 5 ++++- specs/030-security-context-overrides/spec.md | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/specs/030-security-context-overrides/OPEN-DECISIONS.md b/specs/030-security-context-overrides/OPEN-DECISIONS.md index d47763c0f..64e0ef039 100644 --- a/specs/030-security-context-overrides/OPEN-DECISIONS.md +++ b/specs/030-security-context-overrides/OPEN-DECISIONS.md @@ -2,7 +2,10 @@ Each item stays OPEN until valgul answers that exact question. -## OD-1: Who may set security overrides? (OPEN) +## OD-1: Who may set security overrides? (SETTLED: B) + +**Ruling (valgul, 2026-11-07):** B, a new `servers:security` permission, granted to +admin by default and to no other built-in role. - A. Anyone with `servers:write` on that server's namespace. - B. A new permission `servers:security`, granted to admin by default and to no other diff --git a/specs/030-security-context-overrides/spec.md b/specs/030-security-context-overrides/spec.md index f623b6042..c02cc6ac8 100644 --- a/specs/030-security-context-overrides/spec.md +++ b/specs/030-security-context-overrides/spec.md @@ -180,7 +180,8 @@ carrying overrides is refused; as a user with it, confirm both work. from the module or from an override. - **FR-010**: Setting, changing or removing an override MUST require the permission decided in OD-1, enforced by the API, and MUST be recorded in the audit log with - before and after values. + before and after values. Per OD-1 this is a new namespaced `servers:security` + permission, held by the built-in admin role only; admins can add it to other roles. - **FR-011**: Backup and restore jobs MUST use the server's effective filesystem group, not only the module's. - **FR-012**: Helper containers (agent, init steps, sentinel, tunnel) MUST keep their From ac4339f4240e8aa42c05d8d118f91ae193627cd3 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 7 Nov 2026 16:04:58 +0000 Subject: [PATCH 3/7] docs(specs): settle spec 030 OD-2 (root overrides behind cluster setting) Co-Authored-By: Claude Opus 5.5 Signed-off-by: Claude --- specs/030-security-context-overrides/OPEN-DECISIONS.md | 6 +++++- specs/030-security-context-overrides/spec.md | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/specs/030-security-context-overrides/OPEN-DECISIONS.md b/specs/030-security-context-overrides/OPEN-DECISIONS.md index 64e0ef039..a5123143b 100644 --- a/specs/030-security-context-overrides/OPEN-DECISIONS.md +++ b/specs/030-security-context-overrides/OPEN-DECISIONS.md @@ -13,7 +13,11 @@ admin by default and to no other built-in role. risk, and a separate key lets an admin hand it out deliberately.) - C. Admins only, no new permission. -## OD-2: Is run-as user or group 0 (root) allowed as an override? (OPEN) +## OD-2: Is run-as user or group 0 (root) allowed as an override? (SETTLED: C) + +**Ruling (valgul, 2026-11-07):** C, root overrides are refused until an admin turns on +a cluster-wide setting, which is off by default. Like every override, setting 0 also +needs `servers:security` (OD-1). - A. Never: overrides must be 1 or more; a module that needs root simply sets no run-as user. diff --git a/specs/030-security-context-overrides/spec.md b/specs/030-security-context-overrides/spec.md index c02cc6ac8..e870ad041 100644 --- a/specs/030-security-context-overrides/spec.md +++ b/specs/030-security-context-overrides/spec.md @@ -167,7 +167,11 @@ carrying overrides is refused; as a user with it, confirm both work. - **FR-004**: The reconciler MUST be the only place that computes and applies the effective settings; the API only stores and validates the override. - **FR-005**: Override values MUST be validated as whole numbers from 0 to - 4294967295, matching the module's own limits, with the root rule from OD-2. + 4294967295, matching the module's own limits, with the root rule from OD-2: an + override of 0 for run-as user or run-as group MUST be refused unless an admin has + turned on a cluster-wide "allow root overrides" setting, which is off by default. + The setting lives in global settings (`config:manage`) and turning it on or off is + audited. - **FR-006**: The create-server wizard MUST offer a collapsed "Advanced" section that shows, per setting, the module default and an optional override. - **FR-007**: The server settings page MUST offer the same Advanced section for an From 3ee0ec18077d57496c480a61da3a251ee6dea5e7 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 7 Nov 2026 16:05:20 +0000 Subject: [PATCH 4/7] docs(specs): settle spec 030 OD-3 and mark spec ready for plan Co-Authored-By: Claude Opus 5.5 Signed-off-by: Claude --- .../OPEN-DECISIONS.md | 7 +++++-- .../checklists/requirements.md | 6 +++--- specs/030-security-context-overrides/spec.md | 16 +++++++++------- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/specs/030-security-context-overrides/OPEN-DECISIONS.md b/specs/030-security-context-overrides/OPEN-DECISIONS.md index a5123143b..d7f50a06f 100644 --- a/specs/030-security-context-overrides/OPEN-DECISIONS.md +++ b/specs/030-security-context-overrides/OPEN-DECISIONS.md @@ -1,6 +1,6 @@ # Open decisions: spec 030 security context overrides -Each item stays OPEN until valgul answers that exact question. +All three decisions were answered by valgul on 2026-11-07. ## OD-1: Who may set security overrides? (SETTLED: B) @@ -27,7 +27,10 @@ needs `servers:security` (OD-1). for the rare image that needs it.) - C. Allowed only if a cluster-wide setting turns it on (off by default). -## OD-3: Does changing an override on an existing server restart it? (OPEN) +## OD-3: Does changing an override on an existing server restart it? (SETTLED: A) + +**Ruling (valgul, 2026-11-07):** A, a change is stored and applies on the next restart; +the dashboard says so. Saving never restarts the server. - A. No: it applies on the next restart and the dashboard says so. (Recommended: matches how other settings that change the pod behave, and avoids kicking players diff --git a/specs/030-security-context-overrides/checklists/requirements.md b/specs/030-security-context-overrides/checklists/requirements.md index 5cfc30ab0..a01a8f299 100644 --- a/specs/030-security-context-overrides/checklists/requirements.md +++ b/specs/030-security-context-overrides/checklists/requirements.md @@ -13,7 +13,7 @@ ## Requirement Completeness -- [ ] No [NEEDS CLARIFICATION] markers remain +- [X] No [NEEDS CLARIFICATION] markers remain - [X] Requirements are testable and unambiguous - [X] Success criteria are measurable - [X] Success criteria are technology-agnostic (no implementation details) @@ -32,7 +32,7 @@ ## Notes - Open questions are tracked as OD-1..OD-3 in `OPEN-DECISIONS.md` instead of inline - markers (project rule: unsettled values go in OPEN-DECISIONS.md). The first - Requirement Completeness item stays unchecked until all three are answered. + markers (project rule: unsettled values go in OPEN-DECISIONS.md). All three were + settled by valgul on 2026-11-07. - Names such as "reconciler", "API" and "audit log" refer to existing Gameplane components the stakeholders already know; no new technology is prescribed. diff --git a/specs/030-security-context-overrides/spec.md b/specs/030-security-context-overrides/spec.md index e870ad041..1efc4d617 100644 --- a/specs/030-security-context-overrides/spec.md +++ b/specs/030-security-context-overrides/spec.md @@ -128,8 +128,9 @@ carrying overrides is refused; as a user with it, confirm both work. open Advanced, **Then** they see the effective values but cannot edit them. 2. **Given** such a user sends an override directly to the API, **When** the request is processed, **Then** it is refused with a permission error and nothing changes. -3. **Given** a request that sets run-as user 0, **When** it is processed, **Then** it - follows the root rule decided in OD-2. +3. **Given** a request that sets run-as user 0, **When** it is processed, **Then** it is + refused unless an admin has turned on the cluster-wide "allow root overrides" + setting (OD-2). --- @@ -179,7 +180,7 @@ carrying overrides is refused; as a user with it, confirm both work. of a server that already has data. - **FR-008**: Changing an override on an existing server MUST take effect on the next restart and MUST say so in the dashboard; it MUST NOT restart the server by itself - [decided in OD-3]. + (OD-3). - **FR-009**: The server's details MUST show each effective value and whether it comes from the module or from an override. - **FR-010**: Setting, changing or removing an override MUST require the permission @@ -242,8 +243,9 @@ carrying overrides is refused; as a user with it, confirm both work. - The end-to-end proof is a Kind E2E test that creates a server with an override and checks the running uid, per the constitution's E2E principle. -## Open decisions +## Decisions -Recorded in [`OPEN-DECISIONS.md`](OPEN-DECISIONS.md): OD-1 (who may override), -OD-2 (whether run-as user/group 0 is allowed), OD-3 (whether a change restarts the -server). The spec is not ready for `/speckit-plan` until all three are answered. +All open decisions are settled in [`OPEN-DECISIONS.md`](OPEN-DECISIONS.md) +(valgul, 2026-11-07): OD-1 new `servers:security` permission (admin only by +default), OD-2 root overrides only when a cluster-wide setting allows them (off by +default), OD-3 changes apply on the next restart. From ad8c6a22abeebb69ca74269dc20013974b514738 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 7 Nov 2026 16:10:05 +0000 Subject: [PATCH 5/7] docs(specs): split applied and pending values in spec 030 Co-Authored-By: Claude Opus 5.5 Signed-off-by: Claude --- specs/030-security-context-overrides/spec.md | 41 ++++++++++++-------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/specs/030-security-context-overrides/spec.md b/specs/030-security-context-overrides/spec.md index 1efc4d617..127980878 100644 --- a/specs/030-security-context-overrides/spec.md +++ b/specs/030-security-context-overrides/spec.md @@ -125,7 +125,7 @@ carrying overrides is refused; as a user with it, confirm both work. **Acceptance Scenarios**: 1. **Given** a user without permission to override security settings, **When** they - open Advanced, **Then** they see the effective values but cannot edit them. + open Advanced, **Then** they see the applied values but cannot edit them. 2. **Given** such a user sends an override directly to the API, **When** the request is processed, **Then** it is refused with a permission error and nothing changes. 3. **Given** a request that sets run-as user 0, **When** it is processed, **Then** it is @@ -143,12 +143,12 @@ carrying overrides is refused; as a user with it, confirm both work. - An override sets the filesystem group but not the run-as user: allowed; it only changes which group the data volume is shared with. - A server is restored from a backup made under different security settings: the - restore uses the server's current effective settings. + restore uses the server's current applied settings. - The module is uninstalled or its template removed while a server has overrides: the override stays on the server and is reapplied if the template returns. - Helper containers (the management agent, config and mod init steps, backups) keep their own fixed users; only the game container's user/group and the pod's - filesystem group change. Backup and restore jobs use the effective filesystem + filesystem group change. Backup and restore jobs use the applied filesystem group so they keep access to the data. - The values are numeric ids only; user and group names are not accepted. @@ -163,10 +163,13 @@ carrying overrides is refused; as a user with it, confirm both work. settings independently. Each override is one of: not set (use module default), a specific numeric id, or "use image default" (do not apply this setting even if the module sets it). -- **FR-003**: The effective value of each setting MUST be the server's override when - present, otherwise the module default, otherwise nothing (image default). +- **FR-003**: The desired value of each setting MUST be the server's override when + present, otherwise the module default, otherwise nothing (image default). The + applied value is the one the running game container actually uses; a desired value + becomes the applied value only when the server next (re)starts. Until then the + change is pending. - **FR-004**: The reconciler MUST be the only place that computes and applies the - effective settings; the API only stores and validates the override. + desired and applied settings; the API only stores and validates the override. - **FR-005**: Override values MUST be validated as whole numbers from 0 to 4294967295, matching the module's own limits, with the root rule from OD-2: an override of 0 for run-as user or run-as group MUST be refused unless an admin has @@ -181,14 +184,18 @@ carrying overrides is refused; as a user with it, confirm both work. - **FR-008**: Changing an override on an existing server MUST take effect on the next restart and MUST say so in the dashboard; it MUST NOT restart the server by itself (OD-3). -- **FR-009**: The server's details MUST show each effective value and whether it comes - from the module or from an override. +- **FR-009**: The server's details MUST show, for each setting, the applied value and + its source, one of: module default, override, "use image default" override, or image + default (neither the module nor the server sets it). When a saved change is not yet + applied, the details MUST also show the pending value and that it applies on the + next restart. - **FR-010**: Setting, changing or removing an override MUST require the permission decided in OD-1, enforced by the API, and MUST be recorded in the audit log with before and after values. Per OD-1 this is a new namespaced `servers:security` permission, held by the built-in admin role only; admins can add it to other roles. -- **FR-011**: Backup and restore jobs MUST use the server's effective filesystem - group, not only the module's. +- **FR-011**: Backup and restore jobs MUST use the server's applied filesystem + group (the one the data volume currently uses), not only the module's, so a pending + change never affects a job before the restart. - **FR-012**: Helper containers (agent, init steps, sentinel, tunnel) MUST keep their existing fixed security settings regardless of overrides. - **FR-013**: The module authoring docs MUST explain that the template's security @@ -203,9 +210,11 @@ carrying overrides is refused; as a user with it, confirm both work. - **Server security override**: per server, for each of the three settings, either absent, a numeric id, or "use image default". Owned by the server, survives module upgrades and reinstalls. -- **Effective security settings**: the result of combining the two, computed by the - reconciler and reported back on the server's status so the dashboard can show where - each value came from. +- **Desired and applied security settings**: the desired settings combine the module + defaults and the server override; the applied settings are what the running game + container uses. The reconciler computes both and reports them, with each value's + source, on the server's status so the dashboard can show where each value came from + and whether a change is pending. ## Success Criteria *(mandatory)* @@ -218,9 +227,9 @@ carrying overrides is refused; as a user with it, confirm both work. on a new server in under 1 minute, without editing or forking the module. - **SC-003**: A user without the permission cannot change any of the three settings, through the dashboard or the API, in 100% of attempts. -- **SC-004**: For every server, the dashboard shows each of the three effective - values and its source (module or override), matching what the game container - actually runs with. +- **SC-004**: For every server, the dashboard shows each of the three applied values + and its source, matching what the game container actually runs with, plus any + pending value not yet applied. - **SC-005**: Every override change appears in the audit log with who, when, before and after. From 6d40ca2c246c23310011f20d8fb5fd5a607ebac6 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 7 Nov 2026 16:13:41 +0000 Subject: [PATCH 6/7] docs(specs): spec 030 clarify Q1, modules can mark values risky to override Co-Authored-By: Claude Opus 5.5 Signed-off-by: Claude --- specs/030-security-context-overrides/spec.md | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/specs/030-security-context-overrides/spec.md b/specs/030-security-context-overrides/spec.md index 127980878..31875b7d8 100644 --- a/specs/030-security-context-overrides/spec.md +++ b/specs/030-security-context-overrides/spec.md @@ -23,6 +23,12 @@ override that the dashboard exposes in an "Advanced" section. The "security settings" in this spec are the three values the template already supports: **run-as user**, **run-as group** and **filesystem group**. +## Clarifications + +### Session 2026-11-07 + +- Q: Can a module lock its security values so servers can't override them? → A: No lock. A module can mark any of its security values as risky to override; overriding a risky value stays allowed but needs an extra confirmation. + ## User Scenarios & Testing *(mandatory)* ### User Story 1 - Server uses the module's security defaults (Priority: P1) @@ -138,8 +144,8 @@ carrying overrides is refused; as a user with it, confirm both work. - A module sets only the filesystem group (Palworld, whose image must start as root to drop privileges): an override of run-as user on such a server would break the - image's own privilege drop. The Advanced section shows the module's own note (if - any) and a warning that the module expects the image's default user. + image's own privilege drop. Such a module marks run-as user as risky (FR-006a), so + overriding it needs the extra confirmation with the module's reason. - An override sets the filesystem group but not the run-as user: allowed; it only changes which group the data volume is shared with. - A server is restored from a backup made under different security settings: the @@ -178,6 +184,10 @@ carrying overrides is refused; as a user with it, confirm both work. audited. - **FR-006**: The create-server wizard MUST offer a collapsed "Advanced" section that shows, per setting, the module default and an optional override. +- **FR-006a**: A module MUST be able to mark each of its security values as risky to + override, with an optional short reason. Overriding a risky value (in the wizard or + on the settings page) MUST stay allowed for `servers:security` holders but MUST need + an extra confirmation that shows the module's reason. Modules cannot lock a value. - **FR-007**: The server settings page MUST offer the same Advanced section for an existing server, with a warning before saving a change to the run-as user or group of a server that already has data. @@ -200,13 +210,15 @@ carrying overrides is refused; as a user with it, confirm both work. existing fixed security settings regardless of overrides. - **FR-013**: The module authoring docs MUST explain that the template's security block is now a default that server owners can override, and when a module author - should say so in the module README (for example "must start as root"). + should mark a value as risky to override and give a reason (for example "image + must start as root"). - **FR-014**: All new dashboard text MUST go through the shared language packs. ### Key Entities - **Module security defaults**: the three optional numeric values a game template - declares today. Unchanged by this feature, but now described as defaults. + declares today, now described as defaults, plus an optional per-value "risky to + override" flag with a short reason. - **Server security override**: per server, for each of the three settings, either absent, a numeric id, or "use image default". Owned by the server, survives module upgrades and reinstalls. From 728cbe9f7f027a99cf10cc437b3154140163aa1e Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 7 Nov 2026 16:14:12 +0000 Subject: [PATCH 7/7] docs(specs): spec 030 clarify Q2, add volume ownership check setting Co-Authored-By: Claude Opus 5.5 Signed-off-by: Claude --- specs/030-security-context-overrides/spec.md | 39 +++++++++++++------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/specs/030-security-context-overrides/spec.md b/specs/030-security-context-overrides/spec.md index 31875b7d8..a13d2760a 100644 --- a/specs/030-security-context-overrides/spec.md +++ b/specs/030-security-context-overrides/spec.md @@ -21,13 +21,16 @@ This feature keeps the module's values as the default and adds a per-server override that the dashboard exposes in an "Advanced" section. The "security settings" in this spec are the three values the template already -supports: **run-as user**, **run-as group** and **filesystem group**. +supports, **run-as user**, **run-as group** and **filesystem group**, plus a fourth, +the **volume ownership check**: whether the data volume's group ownership is re-applied +to every file on each start, or only when the volume's top folder has the wrong group. ## Clarifications ### Session 2026-11-07 - Q: Can a module lock its security values so servers can't override them? → A: No lock. A module can mark any of its security values as risky to override; overriding a risky value stays allowed but needs an extra confirmation. +- Q: Should the Advanced view also control how the volume's group is fixed on start? → A: Yes, as a fourth setting (volume ownership check: "every start" or "only when wrong"), defaulting to the faster "only when wrong". ## User Scenarios & Testing *(mandatory)* @@ -62,7 +65,7 @@ as "module default". ### User Story 2 - Override the security settings when creating a server (Priority: P1) While creating a server, the owner opens an "Advanced" section, sees the module's -default for each of the three settings, and forces one or more of them to a +default for each of the four settings, and forces one or more of them to a different value (or explicitly clears one so the image's own default applies). **Why this priority**: This is the core ask: a way to force a different value @@ -77,7 +80,7 @@ runs as that user while the other two settings keep the module default. 1. **Given** the create-server wizard, **When** the owner has not opened Advanced, **Then** no security values are sent and the module defaults apply. 2. **Given** the Advanced section, **When** the owner views it, **Then** each of the - three settings shows the module default (or "image default" when the module sets + four settings shows the module default (or "image default" when the module sets none) and an empty override field. 3. **Given** the owner sets an override for one setting, **When** the server is created, **Then** only that setting differs from the module default. @@ -163,12 +166,19 @@ carrying overrides is refused; as a user with it, confirm both work. ### Functional Requirements - **FR-001**: Modules MUST remain the source of the default security settings - (run-as user, run-as group, filesystem group); a server without overrides MUST - behave exactly as it does today. -- **FR-002**: Each server MUST be able to store an override for each of the three + (run-as user, run-as group, filesystem group, volume ownership check); a server + without overrides MUST run with the same user, group and filesystem group as today. + The one intended change is that servers with a filesystem group switch to the + faster "only when wrong" ownership check unless their module says otherwise. +- **FR-002**: Each server MUST be able to store an override for each of the four settings independently. Each override is one of: not set (use module default), a specific numeric id, or "use image default" (do not apply this setting even if the module sets it). +- **FR-002a**: The volume ownership check MUST have two values: "every start" (all + files re-checked on each start) and "only when wrong" (re-checked only when the + volume's top folder does not have the filesystem group). When neither the server nor + the module sets it, "only when wrong" applies. It only has an effect when a + filesystem group applies. Its override is either not set or one of the two values. - **FR-003**: The desired value of each setting MUST be the server's override when present, otherwise the module default, otherwise nothing (image default). The applied value is the one the running game container actually uses; a desired value @@ -217,9 +227,9 @@ carrying overrides is refused; as a user with it, confirm both work. ### Key Entities - **Module security defaults**: the three optional numeric values a game template - declares today, now described as defaults, plus an optional per-value "risky to + declares today, now described as defaults, an optional volume ownership check mode, plus an optional per-value "risky to override" flag with a short reason. -- **Server security override**: per server, for each of the three settings, either +- **Server security override**: per server, for each of the four settings, either absent, a numeric id, or "use image default". Owned by the server, survives module upgrades and reinstalls. - **Desired and applied security settings**: the desired settings combine the module @@ -237,20 +247,23 @@ carrying overrides is refused; as a user with it, confirm both work. change). - **SC-002**: A server owner with the permission can force a different run-as user on a new server in under 1 minute, without editing or forking the module. -- **SC-003**: A user without the permission cannot change any of the three settings, +- **SC-003**: A user without the permission cannot change any of the four settings, through the dashboard or the API, in 100% of attempts. -- **SC-004**: For every server, the dashboard shows each of the three applied values +- **SC-004**: For every server, the dashboard shows each of the four applied values and its source, matching what the game container actually runs with, plus any pending value not yet applied. - **SC-005**: Every override change appears in the audit log with who, when, before and after. +- **SC-006**: A server with a large world (100,000+ files) and a filesystem group set + starts at least as fast as it does today, and with the default "only when wrong" + check, a restart with unchanged ownership adds no measurable ownership pass. ## Assumptions - "Security group" in the request means the three values the template's security - block already supports (run-as user, run-as group, filesystem group). Other - container hardening (capabilities, read-only root, privilege escalation, supplemental - groups, the filesystem group change policy) is out of scope for this spec. + block already supports (run-as user, run-as group, filesystem group) plus the volume + ownership check (clarified 2026-11-07). Other container hardening (capabilities, + read-only root, privilege escalation, supplemental groups) is out of scope. - The override applies to the game container and the pod's filesystem group only, matching how the module's values are applied today. - The "Advanced" view is a collapsed section inside the existing create-server wizard