The host applies the newest declaration, a file may be created once, the foundation filters first

031: a window of unacknowledged declarations is drained to the newest; the
rest are set aside and reported as superseded. 035: a file resource may say
create-once — written when absent, kept untouched when present (ADR 0087).
054: the bundle installs nftables and loads a base ruleset before the store
and broker, in the table the filter module later replaces (ADR 0088).
This commit is contained in:
2026-09-21 12:11:52 +02:00
parent d7eea1ab66
commit b72b71a989
8 changed files with 258 additions and 4 deletions
+12
View File
@@ -470,6 +470,18 @@ func applyFile(r *declaration.File, previous store.Applied, unseal Unseal) (Outc
if readErr != nil && !errors.Is(readErr, os.ErrNotExist) {
return out, readErr
}
// A seed that is already there is left exactly as it is — whatever has grown in it since is
// not the mesh's to put back (novox/hq issue 035). What this host records is what it once
// wrote, so a later declaration that changes the seed is not mistaken for drift either.
if r.CreateOnce && existed {
out.wrote = previous.Wrote
if out.wrote == "" {
out.wrote = digestOf(string(existing))
}
out.Action = "kept"
out.Detail = "created once, and present; what is in it now is not the mesh's to change"
return out, nil
}
var beforeMode os.FileMode
if existed {
+37
View File
@@ -1558,3 +1558,40 @@ func TestAContainerStaleFromAnEarlierApplyIsReplaced(t *testing.T) {
"(removed=%v created=%v)", removed, created)
}
}
// A seed is written once. What grows in it afterwards is somebody else's work the mesh asked for,
// and a reconcile leaves it alone — content, mode and owner — and says so (novox/hq issue 035).
func TestASeedIsCreatedOnceAndWhatGrowsInItIsKept(t *testing.T) {
dir := t.TempDir()
path := filepath.Join(dir, "acl.conf")
d := parse(t, fmt.Sprintf(`{"declaration":1,"resources":[
{"id":"acl","type":"file","path":%q,"content":"user default on\n","mode":"0600","create-once":true}
]}`, path))
report, state, err := Apply(context.Background(), archHost(t), d, store.State{},
store.OriginCarried, noServices, nil, nil)
if err != nil {
t.Fatal(err)
}
if got := report.Outcomes[0].Action; got != "created" {
t.Fatalf("first apply: %q", got)
}
// The program persists into it.
if err := os.WriteFile(path, []byte("user default on\nuser app-one on >secret\n"), 0o600); err != nil {
t.Fatal(err)
}
report, _, err = Apply(context.Background(), archHost(t), d, state,
store.OriginCarried, noServices, nil, nil)
if err != nil {
t.Fatal(err)
}
if got := report.Outcomes[0].Action; got != "kept" {
t.Fatalf("second apply: %q — a seed was reconciled", got)
}
grown, _ := os.ReadFile(path)
if string(grown) != "user default on\nuser app-one on >secret\n" {
t.Fatalf("what grew in the seed was wiped: %q", grown)
}
}