3.8 KiB
Restricted Compose policy
Check(manifest, entrypointBytes) is a pure, offline policy check. The CLI
check-package first calls appbundle.Verify, then passes the authenticated
entrypoint snapshot here. It never reopens the entrypoint, runs Compose, reads
.env, resolves templates, or contacts a daemon. Direct internal callers must
perform the same integrity/trust check first.
Profile: isolated-compose-v1. This is an initial restricted backend profile,
not the finished application's Compose contract. It deliberately rejects public
routing, secrets/config injection, environment settings, healthchecks, dependency
ordering and application-specific privilege exceptions until adapters exist.
Existing YAML packages can still pass verify-package; that does not mean they
pass check-package. Only JSON entrypoint content is accepted by this policy.
Exact shape
All fields below are mandatory, all unlisted fields are rejected:
{
"services": {
"api": {
"image": "example/api@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"user": "1000:1000",
"read_only": true,
"cap_drop": ["ALL"],
"security_opt": ["no-new-privileges:true"],
"restart": "no",
"networks": ["backend"],
"volumes": [
{"type": "volume", "source": "data", "target": "/data", "read_only": false}
]
}
},
"networks": {"backend": {"internal": true}},
"volumes": {"data": {}}
}
The example digest is synthetic, not an installable release.
- 4 MiB input limit. Shared strict decoder rejects duplicate, case-alias, unknown, missing and null fields, including typed map values.
- 1–32 services, exactly matching manifest component names and pinned images.
- UID and GID must be canonical positive uint32 decimals, excluding 4294967295. No root, account-name lookup, interpolation or inherited user defaults.
- Restart must be
noorunless-stopped; root filesystem must be read-only, all capabilities dropped and privilege escalation disabled. - Exactly one network:
backend, withinternal: true. No default network, external network, host networking, published port or arbitrary router label. - At most 128 plain named volumes; every declaration must be mounted exactly once. Empty volume maps/lists are permitted for stateless services. No external names, drivers, driver options, bind mounts or cross-service sharing.
- Mount paths must be absolute canonical ASCII paths, at most 240 bytes, with no root, overlapping mount or system-tree mount. Denied trees: /proc, /sys, /dev, /etc, /run, /var/run, /bin, /sbin, /usr, /lib, /lib64 (including ancestors).
- No command overrides, hooks, build, include, extends, profile, socket access, devices or arbitrary privilege additions. Unknown future keys also fail closed.
What passing does not prove
This check does not authenticate a publisher, validate image contents or mount destinations inside an image, provision usable volume ownership, reserve resource names, verify engine/Compose compatibility, limit resource consumption, prove application readiness, or provide backup/restore. Image defaults and existing Docker resources must still be validated by future adapters and preflight.
Future execution must bind an explicit instance project name, verify resource ownership under the host lock, and use the exact checked snapshot without extra Compose files, ambient overrides or subsequent interpolation. An integrity hash and this restricted policy are not authorization to run a deployment.
References checked during implementation: Compose services, Compose networks, Compose config. No real Docker/Compose execution has been validated in this batch.