The 'domain grouping' item cited ADR 0017 as live guidance. 0044 superseded it -- there is no domain module to group into, so there is no domain list to settle.
3.6 KiB
status, date, deciders, reconstructed, extends
| status | date | deciders | reconstructed | extends |
|---|---|---|---|---|
| accepted | 2026-08-27 | jochen | false | 0043-a-declaration-is-an-ordered-list-of-owned-resources.md |
52. A filter rule names its source, or it is not a rule
Context
Research 004 found this while looking for something else:
Several manifests declare
scope: publicon firewall rules —wireguard,traefik,gitea,mailu,qbittorrent. It is not part of the rule type and is referenced by no code in the firewall path. Real scoping is done withfrom:.
So five manifests appear to restrict a port and restrict nothing. Anyone reading them — including whoever wrote the next one by copying — sees an access control that does not exist.
Research 004 already names the shape: it is how-we-build's an unenforced rule is
indistinguishable from a wrong one, and costs more, because people believe it. This is that
rule, in the firewall, on the modules most worth restricting.
The mechanism that let it happen is worth more than the instance. scope: was accepted because
unknown keys were ignored. Nothing rejected it, nothing warned, and it spread by copying for
long enough to reach five manifests.
Decision
A rule names its source. from: is the only way to scope a rule, and a rule without one is
open — which it must therefore say plainly rather than imply otherwise.
scope: is removed, not implemented. Giving it meaning would leave two ways to express one
thing, and a manifest carrying both would need a precedence rule nobody would remember. The five
manifests are corrected to from: where they meant to restrict something, and left open where
they did not — and finding out which is which is part of the work, not a formality.
An unknown key is refused. This is the general fix and the reason to bother:
A manifest carrying a key the schema does not define is rejected, naming the key.
The host already works this way — its declaration parser sets DisallowUnknownFields and
collects every problem into one refusal
(ADR 0043). Manifests are the
layer where that discipline is missing, and scope: is what missing looks like: not a wrong
value, an invented one, silently accepted for months.
Consequences
- This class of fiction stops at validation rather than at an audit. A misspelled
form:, an inventedscope:, a key from a different schema — each fails on the manifest that introduces it, once, instead of spreading. - Existing manifests will fail validation, and some of those failures will be keys somebody believed were doing something. That is the finding, not the cost — but it means the refusal cannot be switched on without reading every manifest first.
- The firewall becomes reviewable. Today a rule's real effect is only visible by knowing which keys are fictional. Afterwards the manifest says what happens.
- Five manifests need a decision each, and
wireguardandtraefikgenuinely are open to the world — they must be, which the manifest should state rather than appear to deny. - It does not make the rules correct, only honest. A rule that says
from:anywhere is legitimately open; this record ensures it says so.
References
- Research 004 §7 — the finding.
how-we-build.md— the rule about unenforced rules.- ADR 0043 — unknown-is-refused, where it already holds.