package apply import ( "context" "os" "strings" "testing" "github.com/novox/mesh-host/internal/store" ) // An operator-owned path the module reaches but does not own (novox/hq ADR 0051). // // The host confirms it is present and changes nothing: it does not create it, chown it or set its // mode, because the media library and the download spool are the operator's and several modules // share them. This is the opposite of a directory on every axis, and the whole reason the two are // different shapes. func TestAnAccessPresentIsConfirmedAndNothingIsChanged(t *testing.T) { dir := t.TempDir() // the operator's directory, already there d := declare(t, `{"id":"lib","type":"access","path":"`+dir+`","mode":"read-write"}`) report, _, err := Apply(context.Background(), archHost(t), d, store.State{}, store.OriginDeclared, noServices, nil, nil) if err != nil { t.Fatalf("an operator-owned path that is present was refused: %v", err) } if report.Changed() { t.Fatalf("confirming an access reported a change; the host owns nothing about it") } if _, statErr := os.Stat(dir); statErr != nil { t.Fatalf("the operator's directory was disturbed: %v", statErr) } } // Absent is refused, not created. A bind mount whose source does not exist is made by the // container runtime as root, with whatever mode it picks — the silent wrong-ownership // 04-ISSUES/026 records. So the host says plainly that the operator must provide the path, rather // than conjuring a directory it does not own. func TestAnAccessThatIsAbsentIsRefusedClearlyAndNotCreated(t *testing.T) { missing := t.TempDir() + "/media/library" // named, never created d := declare(t, `{"id":"lib","type":"access","path":"`+missing+`"}`) _, _, err := Apply(context.Background(), archHost(t), d, store.State{}, store.OriginDeclared, noServices, nil, nil) if err == nil { t.Fatal("an absent operator-owned path was accepted, and would be created as root by the runtime") } if !strings.Contains(err.Error(), "the operator must provide") || !strings.Contains(err.Error(), "does not own") { t.Fatalf("the refusal does not say whose the path is: %v", err) } if _, statErr := os.Stat(missing); statErr == nil { t.Fatal("the host created the path it does not own") } } // Undeclaring an access never removes the path. Unassigning the module that reached the media // library must not delete the library — that is the data loss ADR 0030 exists to prevent, on a // directory the mesh never made. The record is dropped; the operator's data is left exactly as it // is. func TestAnUndeclaredAccessLeavesTheOperatorsPathAlone(t *testing.T) { lib := t.TempDir() // the operator's library keep := t.TempDir() if err := os.WriteFile(lib+"/a-real-file", []byte("the operator's data"), 0o644); err != nil { t.Fatal(err) } d := declare(t, `{"id":"lib","type":"access","path":"`+lib+`","mode":"read"}`) _, state, err := Apply(context.Background(), archHost(t), d, store.State{}, store.OriginDeclared, noServices, nil, nil) if err != nil { t.Fatal(err) } // The module is unassigned: the mesh no longer declares the access. empty := declare(t, `{"id":"unrelated","type":"directory","path":"`+keep+`"}`) report, _, err := Apply(context.Background(), archHost(t), empty, state, store.OriginDeclared, noServices, nil, nil) if err != nil { t.Fatal(err) } if _, statErr := os.Stat(lib); statErr != nil { t.Fatalf("the operator's library was removed when the module stopped reaching it: %v", statErr) } if _, statErr := os.Stat(lib + "/a-real-file"); statErr != nil { t.Fatalf("the operator's data was removed: %v", statErr) } var forgot bool for _, o := range report.Outcomes { if o.Type == "access" && o.Action == "forgotten" { forgot = true } } if !forgot { t.Errorf("dropping an access was not reported as forgotten: %+v", report.Outcomes) } }