Merge remote-tracking branches 'origin/design/adr-0044-sdk-boundary', 'origin/design/adr-0045-what-a-module-is', 'origin/design/adr-0046-events', 'origin/design/adr-0047-event-wire-shape', 'origin/worktree-adr-0048-module-broker-account', 'origin/worktree-adr-reachability-dns-firewall', 'origin/worktree-adr-config-is-the-assignments' and 'origin/worktree-adr-module-runtime' into worktree-issue-provider-seal-key

This commit is contained in:
11 changed files with 884 additions and 11 deletions
@@ -1,9 +1,9 @@
---
status: open
status: fixed
opened: 2026-08-22
located-in: []
fixed-by:
amended-design:
located-in: [mesh-control/internal/catalogue, mesh-catalog/modules/firewall]
fixed-by: the manifest refuses unknown keys, `from` is the field that scopes a port and it is rendered to nftables, and the firewall module applies it
amended-design: 0050-a-machine-firewall-is-the-sum-of-what-it-listens-on.md
---
# 003 — A firewall rule's `scope:` is read by no code
@@ -31,10 +31,27 @@ any check.
- Five manifests carry the key. Zero code paths consume it.
- Recorded as an observation on 2026-08-22.
## Open questions
## Resolution
- Should the manifest reject unknown keys outright? That is the general fix; this is one
instance of it.
- Were the five declarations intended to restrict something that is currently open? Each needs
checking against what the node actually exposes — the declaration cannot be trusted either
way.
Both open questions are answered, and the chain from a declared scope to a packet actually dropped
is closed — recorded as [ADR 0050](../../02-DECISIONS/0050-a-machine-firewall-is-the-sum-of-what-it-listens-on.md).
- **Unknown keys are refused, not accepted.** `ParseManifest` decodes with
`DisallowUnknownFields`, so a `scope:` key the firewall type does not have is now rejected at the
manifest — the general fix, of which this was one instance. A key that reads as a restriction can
no longer be one nothing enforces.
- **The field that scopes a port is `from`, and it is read.** A `listens` entry names its source —
`mesh`, `anywhere` or `machine` — and the control plane renders the union of every module's
`listens` into a node's whole nftables rule set (`AsNftables`), default-drop with an accept scoped
to exactly the source each port named. The five `scope:` declarations were the wrong spelling of
that intent; `from` is the right one, and it is enforced.
- **A module applies it.** The rendered rule set is written to the node (the `filtering` resource),
and the `firewall` module (mesh-catalog) loads it — the last link, without which the rules were
computed and never dropped a packet.
## Original open questions
- Should the manifest reject unknown keys outright? — **Yes; it does now** (`DisallowUnknownFields`).
- Were the five declarations intended to restrict something that is currently open? — They meant to
scope a port and used a key nothing read; expressed through `from`, that intent is now enforced.
Any manifest still carrying `scope:` is refused at parse, so it is found rather than believed.