Archipelago runs third-party applications as containers. Without enforcement, containers could:
- Run as root and escalate privileges
- Access the host filesystem
- Modify their own binaries (persistence of malicious code)
- Acquire unnecessary Linux capabilities
- Use unverified or tampered container images
Other node OS projects (Umbrel, Start9) vary in their security enforcement. Archipelago targets a higher security bar suitable for handling Bitcoin private keys and personal data.
## Decision
Enforce security constraints at the **manifest level**, applied automatically during container creation. Every container MUST comply with these non-negotiable defaults:
The decision above stands; this section records how much of it is actually
enforced today, because the "non-negotiable" table overstates it. Verified
against `core/container/src/manifest.rs` and `core/security/src/`:
| Constraint | Reality |
|---|---|
| `capabilities` drop-all + allow-list | ✅ **Enforced.** A capability outside the nine-entry allow-list is a parse error, so the app cannot install |
| Bind-mount confinement | ✅ **Enforced** (stronger than this ADR describes): sources must be under `/var/lib/archipelago/`, a named volume, or one of two reviewed exceptions |
| `readonly_root` / `no_new_privileges` | ◐ **Defaults, not gates.** Both default to `true` when omitted, but `validate_security()` does not reject an explicit `false` — the "reject manifests that violate mandatory defaults" step does not exist |
| `image_tag` pinned | ◐ **Preflight only.**`scripts/validate-app-manifest.sh` grades it; the parser accepts `:latest` and the app installs |
| `user` UID > 1000 | ❌ **Not validated.** The runtime manifest parser has no UID check at all (the marketplace schema has an advisory one, which is a different type) |
| `seccomp_profile` | ❌ **Does not exist.** The string `seccomp` appears nowhere in `core/` — not as code, not as a TODO |
| AppArmor | ❌ **Inert.**`container_policies.rs` can generate and `apparmor_parser -r` a profile, but its own comment says `TODO: Configure Podman to use the profile`. `security.apparmor_profile` is parsed into a manifest field that nothing ever reads |
So the accurate summary is: capability and mount confinement are hard gates,
the process-hardening flags are safe-by-default rather than enforced, and the
kernel-level sandboxing (seccomp/AppArmor) named in the decision was never