Retire the found firewall only once the mesh's own filter is loaded on the machine (hq ADR 0100)

This commit is contained in:
2026-09-22 19:54:43 +02:00
parent 5f126021b7
commit 9839006d48
3 changed files with 70 additions and 2 deletions
+33 -2
View File
@@ -163,8 +163,10 @@ func TestConvergingRetiresTheFoundFirewallAndReturningRestoresIt(t *testing.T) {
t.Fatalf("adopted: firewall recorded as %+v", state.Firewall)
}
// Converged: the opening's rule goes, and only then is ufw disabled — never reset.
// Converged: the derived filter is loaded, the opening's rule goes, and only then is ufw
// disabled — never reset.
u.asked = nil
u.ruleset = "table inet mesh\n"
converged := parse(t, `{"declaration":1,"resources":[`+withConf(dir)+`]}`)
_, state, err = applyWith(t, converged, state, u.run)
if err != nil {
@@ -274,6 +276,7 @@ func TestAFlipThatFailsKeepsTheGuardAndTheOpenings(t *testing.T) {
filter := `{"id":"nftables.config","type":"file","path":"` + filepath.Join(blocked, "nftables.conf") + `","content":"table inet mesh {}\n"}`
converged := parse(t, `{"declaration":1,"resources":[`+withConf(dir)+`,`+filter+`]}`)
u.asked = nil
u.ruleset = "table inet mesh\n" // what the filter's unit loads once the file is written
_, state, err = applyWith(t, converged, state, u.run)
if err == nil {
t.Fatal("the failing flip reported success")
@@ -403,7 +406,7 @@ func TestARetiredFirewallRetriedStillPutsBackTheForwardPolicy(t *testing.T) {
// The forward policy is recorded before ufw is disabled, so a retirement that failed after
// the disable restores what the machine had, not what the disable left (novox/hq ADR 0100).
dir := t.TempDir()
u := &ufwMachine{installed: true, active: true, forward: "DROP", failP: 1}
u := &ufwMachine{installed: true, active: true, forward: "DROP", failP: 1, ruleset: "table inet mesh\n"}
_, state, err := applyWith(t, adopted(t, `{"taken":[]}`, withConf(dir)), store.State{}, u.run)
if err != nil {
t.Fatal(err)
@@ -459,3 +462,31 @@ func TestAGuardThatFailsLeavesTheDerivedFilterInForce(t *testing.T) {
t.Error("the filter was forgotten, so nothing would ever stop it")
}
}
func TestUfwIsNotRetiredUntilTheMeshsOwnFilterIsLoaded(t *testing.T) {
// The flip retires the found firewall because the mesh's derived filter takes its place. If
// that table is not loaded, retiring would leave the machine filtering nothing (novox/hq ADR 0100).
dir := t.TempDir()
u := &ufwMachine{installed: true, active: true, rules: []string{"allow 22/tcp"}}
_, state, err := applyWith(t, adopted(t, `{"taken":[]}`, busOpening+","+withConf(dir)), store.State{}, u.run)
if err != nil {
t.Fatal(err)
}
converged := parse(t, `{"declaration":1,"resources":[`+withConf(dir)+`]}`)
_, state, err = applyWith(t, converged, state, u.run)
if err == nil || !strings.Contains(err.Error(), "table inet mesh") {
t.Fatalf("ufw was retired with nothing in its place: %v", err)
}
if !u.active || state.Firewall.DisabledByMesh {
t.Errorf("ufw was disabled: active %v, %+v", u.active, state.Firewall)
}
// Once the table is loaded, the same declaration retires it.
u.ruleset = "table inet mesh\n"
if _, state, err = applyWith(t, converged, state, u.run); err != nil {
t.Fatal(err)
}
if u.active || !state.Firewall.DisabledByMesh {
t.Errorf("ufw was not retired once the mesh's filter was loaded: active %v, %+v", u.active, state.Firewall)
}
}