docs(deploy): make minimal Compose the canonical contract

This commit is contained in:
2026-08-11 00:47:09 +02:00
parent b40f4e2e1b
commit 662b8bb078
10 changed files with 57 additions and 77 deletions
+6
View File
@@ -21,6 +21,7 @@ Do not reread all documentation, list every source file, concatenate large files
- Never expose secrets in APIs, logs, audit events, exports, errors or fixtures.
- Preserve player data and backups by default in deletion, update, restore and migration workflows.
- Keep `compose.yaml` minimal; ordinary product settings belong in SQLite and the web UI.
- The public Compose deployment contains only `dogama` and `agent`. Do not add setup sidecars, init containers, user-managed internal secrets, host bootstrap scripts or host-system configuration unless the owner explicitly accepts that architectural change.
- SQLite is the V1 database. Keep the single-host architecture unless an accepted decision changes it.
- Palworld is the reference integration. Check both Palworld examples when a contract affects templates, modules, backups, permissions or instance lifecycle.
@@ -34,6 +35,9 @@ Stop and report any request that would weaken these boundaries.
- Make the smallest coherent change; avoid unrelated redesigns.
- Enforce authorization and validation in the backend, not only the UI.
- Update documentation, schema, examples, implementation and tests together when a contract changes.
- Documentation is part of the product contract. When implementation, deployment behavior, configuration, environment variables, architecture, user-facing workflows or release behavior changes, update every affected canonical document and example in the same branch.
- Before completing a contract change, search the repository for the superseded behavior and resolve stale or contradictory references. A task is not complete while documentation or examples contradict the implementation.
- Do not duplicate canonical configuration files such as `compose.yaml` into `README.md` or other documentation when that copy can drift; reference the canonical file instead.
- Prefer small Go packages, explicit interfaces, deterministic serialization and stable identifiers.
- Add a new migration for persisted changes; never edit a released migration.
- Add negative tests for authorization, paths, archives, module capabilities and agent operation scope when relevant.
@@ -41,6 +45,8 @@ Stop and report any request that would weaken these boundaries.
## Git workflow
- Git operations are explicitly authorized for this repository. Codex must use the normal feature-branch, commit, push and pull-request workflow below; never invent a no-Git constraint.
- Fetch `origin` before branching and base each dedicated feature branch on the current `origin/main`, preserving any user-owned working-tree changes.
- Git delivery is mandatory for every implementation or milestone: create a dedicated feature branch from an up-to-date `main`, make logical commits, push the branch with the `codex` Gitea account, and open a pull request to `main`.
- Work only on a non-`main` feature branch. If the task starts on `main`, create or request a working branch before editing.
- Never modify, commit on, merge into, rebase, reset, delete or push `main`.
+10 -57
View File
@@ -23,66 +23,17 @@ The repository currently includes the official banner above but no maintained pr
## Installation
Install Docker Engine with the Compose plugin on a Linux host. Save the repository's [`compose.yaml`](compose.yaml), optionally copy [`.env.example`](.env.example) to `.env`, then run:
Install Docker Engine with the Compose plugin on a Linux host. Create a directory and save the repository's canonical [`compose.yaml`](compose.yaml) there; optionally copy [`.env.example`](.env.example) to `.env`. A complete start is then:
```sh
mkdir -p data/servers data/backups
mkdir dogama
cd dogama
docker compose pull
docker compose up -d
```
The default web address is `http://HOST:8080`. DoGaMa generates its internal agent token and encryption key automatically on first start; do not create or add them to `.env`.
A complete minimal Compose deployment is:
```yaml
services:
init:
image: git.zaynet.fr/dogama/dogama:${DOGAMA_VERSION:-latest}
user: "0:0"
entrypoint: ["/usr/local/bin/dogama-init"]
volumes:
- ${DOGAMA_DATA_PATH:-./data}:/var/lib/dogama
- agent_state:/var/lib/dogama-agent
- ${DOGAMA_SERVERS_PATH:-./data/servers}:/srv/game-servers
- ${DOGAMA_BACKUPS_PATH:-./data/backups}:/srv/game-backups
cap_add: [CHOWN, DAC_READ_SEARCH, FOWNER]
dogama:
image: git.zaynet.fr/dogama/dogama:${DOGAMA_VERSION:-latest}
restart: unless-stopped
ports:
- "${DOGAMA_HTTP_PORT:-8080}:8080"
environment:
DOGAMA_AGENT_URL: http://agent:8081
volumes:
- ${DOGAMA_DATA_PATH:-./data}:/var/lib/dogama
- agent_state:/var/lib/dogama-agent:ro
- ${DOGAMA_SERVERS_PATH:-./data/servers}:/srv/game-servers
- ${DOGAMA_BACKUPS_PATH:-./data/backups}:/srv/game-backups
depends_on:
init:
condition: service_completed_successfully
agent:
condition: service_started
agent:
image: git.zaynet.fr/dogama/dogama-agent:${DOGAMA_VERSION:-latest}
restart: unless-stopped
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- agent_state:/var/lib/dogama-agent
- ${DOGAMA_SERVERS_PATH:-./data/servers}:/srv/game-servers
- ${DOGAMA_BACKUPS_PATH:-./data/backups}:/srv/game-backups
depends_on:
init:
condition: service_completed_successfully
volumes:
agent_state:
```
Use the repository Compose file for its complete network and container-hardening settings; the excerpt shows only the installation contract.
The repository `compose.yaml` is the single source of truth for service, volume, network and hardening settings. No separate initialization command, host user, internal UID/GID or secret preparation is required.
## Initial setup
@@ -126,16 +77,18 @@ Managed game ports are selected per instance from validated templates.
| `DOGAMA_HTTP_PORT` | `8080` | Published web port |
| `TZ` | `UTC` | Container timezone |
| `DOGAMA_DATA_PATH` | `./data` | Host path for DoGaMa data |
| `DOGAMA_SERVERS_PATH` | `./data/servers` | Host path for game-server data |
| `DOGAMA_BACKUPS_PATH` | `./data/backups` | Host path for backups |
| `DOGAMA_SERVERS_PATH` | `./servers` | Host path for game-server data |
| `DOGAMA_BACKUPS_PATH` | `./backups` | Host path for backups |
| `DOGAMA_NETWORK` | `dogama` | Docker network used to reach the web application, including from a reverse proxy |
| `DOGAMA_GAMES_NETWORK` | `dogama-games` | Approved Docker network attached to every created or recreated game container |
Internal container paths, allowed roots and service authentication are intentionally not configurable through the public Compose interface.
Internal container paths, allowed roots and service authentication are intentionally not configurable through the public Compose interface. `DOGAMA_GAMES_NETWORK` is passed to the restricted agent as its fixed allowed network; lifecycle API requests cannot select another Docker network.
## Security
- The main application never mounts the Docker socket.
- Only the private, non-published agent can access Docker, through typed and deny-by-default operations.
- The application runs non-root with a read-only root filesystem; both long-running services drop Linux capabilities.
- Both images use a root identity inside their container namespaces so fresh bind mounts work without a host-specific image UID. Their root filesystems remain read-only, all Linux capabilities are dropped, and no recursive ownership change is performed on application, server or backup data.
- Internal secrets are generated from the operating system cryptographic random source, stored with restrictive permissions and never logged or exposed in the UI.
- The master key is mounted only through the application data path; the agent has no access to it.
- Agent path checks remain fixed to `/srv/game-servers` and `/srv/game-backups` inside the containers.
+12 -3
View File
@@ -4,7 +4,7 @@ Read this compact operational baseline before starting a milestone. Open detaile
## Baseline
- Current reference: post-milestone-10 production-readiness branch from merged baseline `deb1088`.
- Current reference: minimal-deployment correction based on merged baseline `3ae1236`.
- Released SQLite migrations: `0001` through `0009`; never rewrite them.
- Roadmap milestones 1-10 are implemented; this is the V1 feature baseline.
@@ -34,10 +34,13 @@ Read this compact operational baseline before starting a milestone. Open detaile
- Responsive server-rendered application shell with the official square DoGaMa logo, synthwave-derived design tokens, aligned permission-aware navigation, searchable real instance cards and state summaries above the server grid.
- Dedicated administrator Audit and Settings pages; notification channels, audit retention/purge and game-container labels retain their existing backend contracts outside the Dashboard.
- Restrictive browser headers and bounded public HTTP headers.
- Hardened read-only Compose services, capability dropping, private agent networking and distinct minimal OCI image targets.
- Hardened read-only two-service Compose, capability dropping, private agent networking and distinct minimal OCI image targets.
- Linux black-box bootstrap/authentication E2E coverage plus a documented disposable-Docker V1 release verification matrix.
- Deterministic Linux `amd64`/`arm64` archives with embedded build identity, SPDX module SBOM and SHA-256 checksums.
- Minimal production Compose with automatic persistent internal secrets, fixed container path boundaries and no user-managed application-to-agent settings.
- Minimal production Compose containing only `dogama` and `agent`; `docker compose up -d` is the complete first-start workflow with no initializer, setup command, host UID/GID preparation or user-managed internal secrets.
- Service-owned persistent secrets: the agent atomically creates and validates its mode-`0640` shared token in `agent_state`; the application independently creates and validates its mode-`0600` master key below the application data path. The application tolerates concurrent first start by waiting up to 60 seconds for the token and authenticated agent health.
- Two service networks: an administrator-named application/reverse-proxy network plus a private Compose control network. `DOGAMA_GAMES_NETWORK` creates the approved game network and reaches the agent as a fixed policy applied to every game-container create or replacement; it is not caller-selectable through the lifecycle API.
- Portable fresh bind-mount startup uses root identities inside the read-only, capability-free container namespaces. No recursive ownership change is performed; game-container UID/GID remains per-instance configuration.
- Gitea CI for pull requests and `main`, plus tag-only multi-architecture image publication and Gitea Release creation.
## Durable decisions
@@ -58,6 +61,10 @@ Read this compact operational baseline before starting a milestone. Open detaile
- Mod configuration is data-only. Provider commands, scripts and arbitrary download URLs are forbidden.
- The application generates and retains its 32-byte master key outside SQLite; the agent never receives it. Ciphertext is authenticated AES-GCM and secrets are never returned by list APIs.
- `agent_state` remains durable because it stores both the shared token and the MAC-protected instance-to-container registry; losing it must never trigger automatic adoption.
- The canonical public deployment has exactly two services. Setup sidecars, init containers, host bootstrap scripts and user-managed internal secrets require an explicit architectural decision.
- `compose.yaml` is the sole canonical Compose definition; documentation references it instead of duplicating it.
- `DOGAMA_NETWORK` names the application-facing network. `DOGAMA_GAMES_NETWORK` names the single agent-approved network for all created and recreated game containers; API input cannot override either bootstrap boundary.
- DoGaMa services never recursively change ownership of application, game-server or backup roots.
- Notification delivery attempts are capped at five with exponential minute-scale backoff and never determine the originating operation result.
- Audit retention defaults to 30 days and 10,000 entries; zero explicitly selects unlimited retention/count within documented bounds.
@@ -66,6 +73,8 @@ Read this compact operational baseline before starting a milestone. Open detaile
- Scheduled backup outcomes and repeated authentication blocks are audited/logged, but broader scheduler-origin notification coverage remains intentionally limited to events emitted by implemented workflows.
- Instance detail, catalog and backup management remain API-first; their sidebar entries are deliberately disabled until corresponding web pages exist, so navigation does not imply unavailable routes.
- Linux is the deployment target. Native Windows execution of the full Go suite is blocked by Unix `Statfs` code; use Linux/WSL/CI for complete execution.
- The two DoGaMa services run as root inside their container namespaces for bind-mount portability. Risk is bounded with read-only image filesystems, all capabilities dropped, `no-new-privileges`, no Docker socket in the main application and a private typed agent API; rootless Docker and user-namespace remapping remain host-level deployment choices.
- In-place migration of a successfully initialized v0.1.0 data directory has not been validated because that release wrote the application key under a different container identity. Preserve all stores and test a copied deployment rather than assuming compatibility.
- `staticcheck`, `golangci-lint` and Python specification dependencies may not be installed on every development host; report missing tooling rather than silently skipping or installing it.
## Validation and CI
+4 -2
View File
@@ -71,7 +71,7 @@ Before create or replace, the agent verifies:
- labels use the reserved namespace and cannot be overridden;
- custom labels are bounded, may not use either `dogama.*` or the internal `io.dogama.*` namespace, and are merged before immutable technical labels;
- the optional Docker `User` is either an already validated numeric `UID:GID` value or omitted so the image `USER` applies;
- only approved DoGaMa networks are attached.
- the configured deployment-wide game network is attached; the request schema has no network field and unknown fields are rejected.
The canonical plan digest alone is not treated as approval. The agent embeds and
validates the same catalog, then independently compares every privileged field
@@ -83,7 +83,7 @@ V1 templates do not expose arbitrary Docker security options. The agent applies
## Authentication and replay defense
Requests use a shared token generated automatically in the internal `agent_state` volume before both services start. It is owned by `root:65532`, mode `0640`; the application receives the volume read-only and the agent never receives the application master key. Sign method, path, body digest, timestamp and nonce. Reject clock-skewed or reused nonces. Use constant-time comparison, small body limits and short timeouts. Rotate the token through an explicit maintenance workflow.
At its first start, the agent generates the shared token automatically in the internal `agent_state` volume with mode `0640`. It validates and reuses an existing token and refuses invalid content or permissions without replacement. The application receives the volume read-only, waits for the token and authenticated agent health, and the agent never receives the application master key. Sign method, path, body digest, timestamp and nonce. Reject clock-skewed or reused nonces. Use constant-time comparison, small body limits and short timeouts. Rotate the token through an explicit maintenance workflow.
The wire format is `DoGaMa-HMAC-SHA256 <base64url-signature>` in the
`Authorization` header, with `X-DoGaMa-Timestamp` in RFC 3339 and a random
@@ -106,6 +106,8 @@ raw Docker errors.
The agent listens only on the internal control network and publishes no host port. Authentication remains mandatory even on that network.
`DOGAMA_GAMES_NETWORK` is passed by Compose to the agent's fixed `DOGAMA_DOCKER_NETWORK` bootstrap setting. The Docker runtime applies that value to every create operation, including replacement after configuration changes, updates and rollback. The main API cannot override it, and the agent validates its syntax before opening the Docker socket.
## Failure semantics
- Validate the full plan before pulling or mutating anything.
+1 -1
View File
@@ -59,7 +59,7 @@ Package names express business capabilities. Avoid a generic `utils` package and
## Configuration precedence
1. Internal bootstrap contracts: listen address, database/data root, private agent endpoint, automatically generated token and master-key files, and fixed allowed bind roots. The public Compose interface exposes only host-side storage locations.
1. Internal bootstrap contracts: listen address, database/data root, private agent endpoint, automatically generated token and master-key files, fixed allowed bind roots and the fixed approved game network. The public Compose interface exposes host-side storage locations and administrator-facing Docker network names only.
2. Global administrator settings in SQLite: public game address, defaults, audit retention, notification channels, upload limits and safety policies.
3. Template defaults.
4. Per-instance administrator settings.
+3 -1
View File
@@ -73,7 +73,9 @@ Paths stored in SQLite use stable instance and mount identifiers. User-supplied
## Communication
- Browser to main application: HTTP(S), JSON API, secure cookie session.
- Main application to agent: private Docker network, request authentication, timestamp/nonce replay protection and bounded request bodies. Same-host V1 may use a shared secret; mTLS is reserved for later multi-host work.
- Main application to agent: private Compose control network, automatically generated shared-token authentication, timestamp/nonce replay protection and bounded request bodies. The application waits for authenticated agent readiness during concurrent first start; mTLS is reserved for later multi-host work.
- Reverse proxy to main application: the administrator-named `DOGAMA_NETWORK`; the agent is not attached to it.
- Managed instances: the administrator-named `DOGAMA_GAMES_NETWORK`, enforced as a fixed agent bootstrap policy rather than a caller-selectable plan field.
- Main application to game API: only through the WebAssembly host networking interface bound to the instance.
- Main application to notification endpoints: controlled egress with SSRF protections.
+3 -3
View File
@@ -28,7 +28,7 @@ tests/integration/
## Initial application development
The main application requires Go 1.25. SQLite uses the pure-Go `modernc.org/sqlite` driver, so neither cgo nor a system SQLite development library is required. Standard Compose supplies all internal bootstrap contracts and generates both secrets automatically. Direct developer execution may override `DOGAMA_LISTEN_ADDRESS`, `DOGAMA_DATABASE_PATH`, `DOGAMA_AGENT_URL`, `DOGAMA_AGENT_TOKEN_FILE` and `DOGAMA_MASTER_KEY_FILE`; lifecycle routes remain disabled when both agent overrides are absent. These are development controls, not public deployment settings. Run it with:
The main application requires Go 1.25. SQLite uses the pure-Go `modernc.org/sqlite` driver, so neither cgo nor a system SQLite development library is required. Standard Compose supplies all internal bootstrap contracts. The agent generates its shared token and the application generates its master key independently. Direct developer execution may override `DOGAMA_LISTEN_ADDRESS`, `DOGAMA_DATABASE_PATH`, `DOGAMA_AGENT_URL`, `DOGAMA_AGENT_TOKEN_FILE` and `DOGAMA_MASTER_KEY_FILE`; lifecycle routes remain disabled when both agent overrides are absent. These are development controls, not public deployment settings. Run it with:
```sh
go run ./cmd/dogama
@@ -42,13 +42,13 @@ The restricted agent is a separate binary:
go run ./cmd/dogama-agent
```
It fails closed unless its token file contains a 32-byte-or-longer secret. The
It atomically creates a missing 32-byte token and fails closed when an existing token is invalid. The
standard deployment uses `/var/lib/dogama-agent/secrets/token`, confines paths to
`/srv/game-servers` and `/srv/game-backups`, and stores the authenticated
registry at `/var/lib/dogama-agent/registry.json`. Developer overrides remain
available for isolated tests. The configured roots must already exist
and are canonicalized with symlinks resolved. For normal deployment, use the
secret file and private control network defined in `compose.yaml`; never publish
read-only shared token volume and private control network defined in `compose.yaml`; never publish
the agent port on the host.
The agent loads the same embedded validated catalog as the main application.
+8 -3
View File
@@ -21,9 +21,14 @@ integration tests and disposable-Docker release verification:
| Empty and prior-schema migrations | `internal/persistence/sqlite` |
Before publishing a release, additionally use an isolated Docker daemon with
disposable host roots. Run `docker compose config --quiet`, build both image
targets, confirm that the main container has no socket and the agent has no
published port, then exercise Palworld draft/install/start/stop, backup/restore,
disposable host roots. Render the canonical two-service Compose with default and
custom paths/network names, build both image targets, then start from absent
application state and absent `agent_state` using only `docker compose up -d`.
Confirm that both services become healthy enough for an authenticated agent call,
both secrets appear without entering logs, the main container has no socket and
the agent has no published port. Record the secret digests, run `docker compose
down` without `-v`, start again and confirm identical digests and registry state.
Then exercise Palworld draft/install/start/stop, configured game-network attachment, backup/restore,
an intentionally failing digest update, and container-only deletion. Confirm
that unrelated containers cannot be inspected or mutated and that player and
backup roots remain after deletion and interruption. Never point this test at a
+9 -6
View File
@@ -6,23 +6,26 @@ DoGaMa V1 targets one Linux Docker host with the Compose plugin. Use the root `c
```sh
cp .env.example .env
mkdir -p data/servers data/backups
docker compose config --quiet
docker compose pull
docker compose up -d
```
The one-shot `init` service creates the agent token and master encryption key from the operating system cryptographic random source before either long-running service starts. It uses atomic create-without-replacement behavior and restrictive ownership/modes. Repeated starts validate and reuse the existing files; invalid existing files stop initialization instead of generating a replacement. Secret values never enter Compose environment values or logs.
The deployment has exactly two services: `dogama` and `agent`. On first start, the agent creates its shared token in `agent_state` and the application creates its master encryption key below `DOGAMA_DATA_PATH`. Both use the operating system cryptographic random source, atomic create-without-replacement behavior and restrictive modes. Existing files are validated and reused; an invalid file stops the owning service and is never silently replaced. Secret values never enter `.env`, Compose values, logs, APIs or the UI.
The services may start in either order. The application waits up to 60 seconds for the token and an authenticated agent health response. Compose restart policy provides a clean subsequent attempt if the agent or Docker daemon takes longer. An interrupted atomic write leaves no installed partial secret; the next start retries creation. No initializer, setup command or host permission repair is part of this workflow.
The application data path contains SQLite, import staging and the application-only master key. The internal `agent_state` volume contains the agent token and authenticated container-binding registry. The registry is durable security state: losing it makes existing containers unknown rather than silently adopting them. The agent never receives the master key.
Only host-side storage locations, image version, web port and timezone are public Compose settings. Container paths and allowed agent roots are fixed internal contracts. Back up the application data, game servers, backups and `agent_state` volume together.
Only host-side storage locations, image version, web port, timezone and the two Docker network names are public Compose settings. `DOGAMA_NETWORK` names the application-facing network used by a reverse proxy. `DOGAMA_GAMES_NETWORK` names the sole network that the restricted agent attaches to created and recreated game containers. API plans contain no caller-selectable network. Container paths and allowed agent roots remain fixed internal contracts. Back up the application data, game servers, backups and `agent_state` volume together.
The application image uses numeric UID/GID `65532:65532`. Grant that identity write access to the configured application, server and backup paths. The short-lived initializer runs as root only to establish file ownership and retains `CAP_CHOWN`, `CAP_FOWNER` and read/search access needed to validate an existing mode-`0600` key; long-running services keep their existing restricted profiles.
Both services use root inside their container namespaces so Docker-created bind directories and ordinary administrator-selected paths work without knowledge of an image-specific UID/GID. They keep read-only root filesystems, `no-new-privileges` and an empty Linux capability set. The main application never receives the Docker socket. DoGaMa creates only directories it needs below the configured roots and never performs an automatic recursive `chown` of application, server or backup data. Game-container UID/GID selection remains a separate per-instance setting.
For NAS or server-style paths, set ordinary writable locations in `.env`, for example `/srv/apps/dogama/data`, `/srv/games` and `/srv/backups`, then run `docker compose up -d`. No `/etc` or host `/var/lib` setup, system user, systemd unit or bootstrap script is required.
## Upgrade and rollback
No production deployment predates automatic secret initialization, so this change requires no legacy migration. For future updates, stop DoGaMa, take a filesystem-consistent backup of all four persistent stores, change only `DOGAMA_VERSION`, then run `docker compose pull` and `docker compose up -d`.
The two-service deployment validates and reuses secrets created by its normal first-start contract. The v0.1.0 initializer used a different application-image identity, so do not claim an unverified in-place migration for a v0.1.0 deployment where initialization completed; preserve all four stores and validate that case on a copy before changing production. For normal updates after this correction, stop DoGaMa, take a filesystem-consistent backup of all four persistent stores, replace the canonical `compose.yaml`, change only `DOGAMA_VERSION`, then run `docker compose pull` and `docker compose up -d`.
Startup applies append-only SQLite migrations before serving requests. Never remove or recreate `agent_state`, and never replace an existing master key: doing so would invalidate the agent registry or make encrypted notification data unreadable. On failure, restore all state from the same backup point and select the prior image version.
@@ -51,4 +54,4 @@ make release VERSION=v0.1.0
make images VERSION=v0.1.0
```
On an isolated Docker host, confirm automatic secret initialization and reuse, application bootstrap, Palworld draft/install, lifecycle operations, backup/restore, failed-update rollback, and denial against unrelated containers. Confirm that only the web port is published, the main application lacks the Docker socket, the agent cannot access the master key, and player/backup data survive container recreation and interruption.
On an isolated Docker host, start with empty application paths and no `agent_state`, then run only `docker compose up -d`. Confirm automatic secret initialization and reuse, authenticated agent health, application bootstrap, Palworld draft/install, lifecycle operations, backup/restore, failed-update rollback, configured game-network attachment and denial against unrelated containers or caller-selected networks. Confirm that only the web port is published, the main application lacks the Docker socket, the agent cannot access the master key, and player/backup data survive `docker compose down` followed by `docker compose up -d` without `-v`.
+1 -1
View File
@@ -41,7 +41,7 @@
V1 local accounts use a current password-hashing algorithm with calibrated parameters. Bootstrap accepts the first administrator only through a one-time local setup state. Sessions rotate at login/privilege change, can be revoked, and never appear in URLs. Critical actions require recent password confirmation.
The deployment documentation must recommend TLS through a trusted reverse proxy and restrictive permissions on application data, server and backup paths. Internal secret files use restrictive ownership and permissions and are never public Compose inputs.
The deployment documentation must recommend TLS through a trusted reverse proxy and restrictive host access to application data, server and backup paths. Internal secret files use restrictive modes, are created by their owning services and are never public Compose inputs. The containers add no Linux capabilities and never recursively change ownership of user or game data.
## Template and module trust