Let a directory say how it reacts to files it does not know, and move out what a move-out directory does not know (issue 1024, ADR 0422)
mesh/merge-gate head d237dee4c9e3 merged into trunk cd13f7726ef0 — pass: builds mesh-host → ace, g14, novox, shanks; no bus step; every machine composes wi…
mesh/repo-check head d237dee4c9e3 merged into trunk cd13f7726ef0 — fail: its merge-check.sh failed: --- FAIL: TestAMoveOutDirectoryKeepsOnlyWhatItKnows (0.…
mesh/delivery superseded: a newer head of the same pull request

A directory or archive resource carries `unknown` (move-out, module, program) and `knows`. For move-out under a home, every look moves each path the declaration does not know into ~/.local/state/mesh-moved/<module>/<time>/, the list written before each move, without following a link, a young path waiting, a socket or pipe left and reported, nothing made when nothing moved, and another file system refused. Reviewed in two rounds.
This commit is contained in:
2026-10-17 16:09:33 +00:00
parent cd13f7726e
commit d237dee4c9
12 changed files with 1082 additions and 0 deletions
+48
View File
@@ -545,3 +545,51 @@ func TestAContainerMayLogToTheJournalAndNowhereElse(t *testing.T) {
}
}
}
// Issue 1024, ADR 0422: a directory or archive says how it treats files it did not write.
func TestADirectoryAndAnArchiveSayWhatTheyDoWithUnknownFiles(t *testing.T) {
d, err := Parse([]byte(`{"declaration":1,"resources":[
{"id":"d","type":"directory","path":"/home/a/x","unknown":"move-out","knows":["keep","sub/"]},
{"id":"r","type":"archive","source":"https://x/y","digest":"sha256:` + strings.Repeat("a", 64) + `","path":"/home/a/y","unknown":"module"}
]}`))
if err != nil {
t.Fatalf("refused: %v", err)
}
dir := d.Resources[0].(*Directory)
if dir.Unknown != UnknownMoveOut || len(dir.Knows) != 2 {
t.Errorf("directory: %+v", dir)
}
if ar := d.Resources[1].(*Archive); ar.Unknown != UnknownModule {
t.Errorf("archive: %+v", ar)
}
for _, v := range []string{UnknownMoveOut, UnknownModule, UnknownProgram} {
if _, err := Parse([]byte(`{"declaration":1,"resources":[{"id":"d","type":"directory","path":"/x","unknown":"` + v + `"}]}`)); err != nil {
t.Errorf("%s refused: %v", v, err)
}
}
}
func TestBadUnknownAndKnowsFormsAreRefusedNamingTheResource(t *testing.T) {
digest := `"digest":"sha256:` + strings.Repeat("a", 64) + `"`
cases := map[string]string{
"bad value": `{"id":"d","type":"directory","path":"/x","unknown":"delete"}`,
"empty entry": `{"id":"d","type":"directory","path":"/x","unknown":"move-out","knows":[""]}`,
"absolute": `{"id":"d","type":"directory","path":"/x","unknown":"move-out","knows":["/etc"]}`,
"empty comp": `{"id":"d","type":"directory","path":"/x","unknown":"move-out","knows":["a//b"]}`,
"dot": `{"id":"d","type":"directory","path":"/x","unknown":"move-out","knows":["./a"]}`,
"dotdot": `{"id":"d","type":"directory","path":"/x","unknown":"move-out","knows":["a/../b"]}`,
"repeat": `{"id":"d","type":"directory","path":"/x","unknown":"move-out","knows":["a","a"]}`,
"no unknown": `{"id":"d","type":"directory","path":"/x","knows":["a"]}`,
"archive bad": `{"id":"d","type":"archive","source":"s",` + digest + `,"path":"/x","unknown":"nope"}`,
"archive knws": `{"id":"d","type":"archive","source":"s",` + digest + `,"path":"/x","knows":["a"]}`,
}
for name, res := range cases {
t.Run(name, func(t *testing.T) {
refusal := refusalFor(t, `{"declaration":1,"resources":[`+res+`]}`)
if !strings.Contains(strings.Join(refusal.Problems, "\n"), `resource "d"`) {
t.Errorf("resource not named: %v", refusal.Problems)
}
})
}
}