spec: fix alwaysHostNetwork invariant to be relational, not hardcoded - #23
Merged
Conversation
The invariant literally checked c.networkMode == "host", but all three implementations copy whatever network_mode the matched policy configures into the container's HostConfig — they don't hardcode "host" the way ContainerConfigMutator hardcodes privileged=false. The real security property is: the untrusted create-request body cannot override the operator's policy-configured network mode. Changed the invariant to check networkMode against the matched policy's configured value (same relational pattern as volumesInWhitelist/flagsInAllowlist), rather than a hardcoded literal. Behavior is unchanged under simulation (beacon.yaml still configures network_mode: host), but the invariant now models the actual guarantee instead of an incidental property of the one existing policy file. Also documents in spec/README.md that proxyLives and routingTableComplete are structurally tautological in the model (can't be falsified by any action sequence) and notes what actually provides real coverage for each. Verified: quint typecheck passes; quint run --invariants allInvariants reports no violation (1615 traces/sec, 100-step traces). Part of #5
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Reviewed all 9 Quint invariants against the actual guard/mutator behavior in Go, Rust, and TypeScript (issue #5). Result: 7 of 9 map cleanly and identically across all three languages. One real spec-vs-code mismatch found:
alwaysHostNetwork(spec/docker_socket_policy.qnt:384) checkedc.networkMode == "host"— a hardcoded literal. But none of the three implementations hardcode "host";ContainerConfigMutatorcopies whatevernetwork_modethe matched policy configures.spec/README.mdeven documented it as "ContainerConfigMutator enforces networkMode=host", implying it's hardcoded likeprivileged=false" — it isn't. It only held because the one existing policy (config/beacon.yaml) happens to setnetwork_mode: host`.Fix
Changed the invariant to be relational — matching the pattern already used by
volumesInWhitelist/flagsInAllowlist— checking that each container'snetworkModeequals its matched policy's configured value, rather than a hardcoded literal:The real security property is "the untrusted create-request body cannot override the policy-configured network mode" — not "network mode must always be the string host". Behavior under simulation is unchanged (
beacon.yamlstill setshost); this just makes the model check the actual guarantee instead of an incidental property of the one config file that currently exists.Also updated
spec/README.md:alwaysHostNetworkrow to describe the relational checkproxyLivesandroutingTableCompleteare structurally tautological in the model (can't be falsified by any action sequence the simulator generates) and what actually provides real coverage for each guarantee outside the modelVerification
Other issue #5 findings (no code change needed)
extractContainerNamedoesn't exclude reserved path segments (json/create/exec) the way Rust/TS do — filing a follow-up issue for this.Closes #5