runc: parse the full OCI memory block, swappiness as uint64
The resources codec decoded only memory.limit and skip_unknown'd the
rest of linux.resources.memory, so every other field was silently
dropped on a decode/encode round-trip. The lost field that matters in
practice is swappiness: older oci-runtime-tool wrote its "unset"
sentinel as the OCI uint64 2^64-1, and hundreds of real config.json
bundles (e.g. jessfraz/containers) carry {"swappiness":
18446744073709551615} verbatim. nox-json parses that exactly (it never
overflowed our decoder, unlike the rlimit case), but skip_unknown threw
it away.
Model the block as Resources.Memory.t. The byte controls (limit,
reservation, swap, kernel, kernelTCP) decode with Json.Codec.int64 so a
full-width count cannot overflow OCaml's 63-bit int; swappiness decodes
with Json.Codec.uint64, held as the int64 two's-complement bit pattern
(2^64-1 is -1L), mirroring the rlimit and seccomp-arg codecs. The three
flags are tri-state bool option. Resources.t now carries
memory : Memory.t option; multi_tenant and the ocaml-builder call sites
build a Memory.t. The two Seccomp [kernel] argument references become
[~kernel] so the prose does not collide with the new field name.
builder: extract a pure, tested, fuzzed Cache_key module
The step cache-key logic lived inline in the engine, untestable in isolation —
a wrong key silently reuses another step's layer, so it deserves to be pinned.
Factor the plan-only parts (user, command, network, secrets, env keys and the
step id hash) into a pure Cache_key module and have the engine call it.
Add unit tests and Alcobar fuzz properties for the invariants that matter:
- a plain RUN keys on its full argv (distinct commands are distinct steps);
- a package-manager step keys only on its manager tag, NOT the command words —
its identity is the resolved layer carried in the backend run key, so installs
resolving to the same layer share a cache entry (matches the existing runner
"pkg keys on layer not command" test, which catches any change that would fold
the command into a pkg key);
- the step id is deterministic and injective in its op key and parent.
No behaviour change: Cache_key reproduces the engine's previous keys exactly
(all 234 builder tests still pass).
runc: parse the full OCI memory block, swappiness as uint64
The resources codec decoded only memory.limit and skip_unknown'd the
rest of linux.resources.memory, so every other field was silently
dropped on a decode/encode round-trip. The lost field that matters in
practice is swappiness: older oci-runtime-tool wrote its "unset"
sentinel as the OCI uint64 2^64-1, and hundreds of real config.json
bundles (e.g. jessfraz/containers) carry {"swappiness":
18446744073709551615} verbatim. nox-json parses that exactly (it never
overflowed our decoder, unlike the rlimit case), but skip_unknown threw
it away.
Model the block as Resources.Memory.t. The byte controls (limit,
reservation, swap, kernel, kernelTCP) decode with Json.Codec.int64 so a
full-width count cannot overflow OCaml's 63-bit int; swappiness decodes
with Json.Codec.uint64, held as the int64 two's-complement bit pattern
(2^64-1 is -1L), mirroring the rlimit and seccomp-arg codecs. The three
flags are tri-state bool option. Resources.t now carries
memory : Memory.t option; multi_tenant and the ocaml-builder call sites
build a Memory.t. The two Seccomp [kernel] argument references become
[~kernel] so the prose does not collide with the new field name.