Skip to content

fix(deployer): grant baseline capabilities to every sandboxed Compose service - #947

Merged
dviejokfs merged 1 commit into
gotempsh:mainfrom
dviejokfs:fix/compose-cap-drop-defaults
Sep 9, 2026
Merged

fix(deployer): grant baseline capabilities to every sandboxed Compose service#947
dviejokfs merged 1 commit into
gotempsh:mainfrom
dviejokfs:fix/compose-cap-drop-defaults

Conversation

@dviejokfs

Copy link
Copy Markdown
Contributor

Summary

  • Every sandboxed Compose service was getting cap_drop: ALL with no capabilities granted back unless the operator explicitly opted the service into relaxed_capability_services (the "Elevated permissions" toggle). Those 5 capabilities (CHOWN, DAC_OVERRIDE, FOWNER, SETUID, SETGID) are exactly what nearly every official image's entrypoint needs to chown a data/cache directory and drop from root to a service user — not just database images, but ordinary ones too (e.g. plain nginx:alpine with no volumes at all). Without the opt-in, a totally standard compose stack reliably failed with "Operation not permitted" only after a full 300s readiness timeout.
  • This set is a strict subset of Docker's own default capability set, so granting it to every sandboxed service by default matches Docker's out-of-the-box behavior rather than introducing new privilege.
  • Removed the now-inert "Elevated permissions" per-service checkbox from the console (GitSettings.tsx) since it no longer changes anything; the relaxedCapabilityServices field/schema is kept only so older stored configs keep deserializing.
  • Updated the pre-deploy advisory and the post-failure capability-denial remediation messaging (compose.rs, deploy_compose.rs) to reflect the new default and point at unsandboxed_services ("Disable sandbox") as the escape hatch for images that need capabilities beyond this default set.

Security review

A security-auditor pass confirmed this does not widen the sandbox's actual attack surface: the granted capabilities operate within a container's own mount/user namespace, cannot cross the :ro secrets bind-mount (kernel-enforced MS_RDONLY, independent of capabilities), and there is no shared cross-tenant volume/network for them to act on. privileged, host namespaces, and cap_add itself remain blocked in tenant-supplied compose files regardless.

Test plan

  • cargo check --lib on temps-deployer, temps-deployments, temps-entities, temps-presets
  • cargo test --lib on the same crates — all green (a few pre-existing Docker-network-pool-exhaustion failures on the local dev box are unrelated to this change)
  • cargo clippy -- -D warnings clean
  • cargo fmt --check clean
  • Updated/added unit tests in compose.rs covering: both a DB image and a plain web-server image get the baseline capability set with no opt-in; a fully unsandboxed service gets no cap_drop/cap_add at all; capability_denial_remediation reflects the new default-granted message

… service

Temps dropped all Linux capabilities from every Compose service by
default, only granting CHOWN/DAC_OVERRIDE/FOWNER/SETUID/SETGID back for
services explicitly opted into `relaxed_capability_services`. Those five
capabilities are exactly what nearly every official image's entrypoint
needs to chown a data/cache directory and drop from root to a service
user — not just database images, but ordinary ones like nginx:alpine —
so a plain compose stack with no opt-in reliably failed with "Operation
not permitted" after a full readiness timeout.

Grant that minimal set by default to every sandboxed service instead,
matching Docker's own out-of-the-box capability set. The opt-in list is
now vestigial (kept for deserializing older stored configs) and the
now-inert "Elevated permissions" per-service toggle is removed from the
console; reactive/pre-deploy messaging now points at "Disable sandbox"
(unsandboxed_services) for images that need capabilities beyond this
default set.

Security-auditor reviewed: the granted capabilities operate within a
container's own mount/user namespace and cannot cross the `:ro` secrets
bind-mount or reach another tenant's containers, so this does not widen
the sandbox's actual attack surface.

Signed-off-by: David Viejo <dviejo@kfs.es>
@greptile-apps

greptile-apps Bot commented Sep 9, 2026

Copy link
Copy Markdown

Greptile Summary

The PR grants a five-capability baseline to every sandboxed Compose service while preserving the remaining sandbox controls.

  • Removes the obsolete per-service elevated-permissions control while retaining backward-compatible stored configuration.
  • Updates deployment diagnostics and remediation guidance to direct genuinely incompatible services toward the existing sandbox exemption.
  • Adds and updates tests covering baseline grants, unsandboxed services, and capability-denial messaging.

Confidence Score: 5/5

The PR appears safe to merge, with the capability change remaining bounded by existing Compose mount and sandbox controls.

The implementation consistently grants the intended baseline only to sandboxed services, leaves unsandboxed behavior unchanged, preserves legacy configuration compatibility, and aligns operator-facing diagnostics with the new behavior.

Important Files Changed

Filename Overview
crates/temps-deployer/src/compose.rs Applies the baseline capability set to all sandboxed services and consistently updates generation, diagnostics, and focused tests.
crates/temps-deployments/src/jobs/deploy_compose.rs Removes obsolete opt-in guidance and updates deployment failure remediation for the new baseline.
crates/temps-entities/src/preset.rs Retains the legacy capability field for deserialization compatibility while documenting that it is inert.
web/src/components/project/settings/GitSettings.tsx Removes the obsolete elevated-permissions checkbox and explains the automatic baseline and sandbox escape hatch.

Reviews (1): Last reviewed commit: "fix(deployer): grant baseline capabiliti..." | Re-trigger Greptile

@dviejokfs
dviejokfs merged commit 009e501 into gotempsh:main Sep 9, 2026
28 of 29 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant