From 5fa523f6088ead1c6b5423a682ddcce53e6c25b5 Mon Sep 17 00:00:00 2001 From: jochen Date: Fri, 16 Oct 2026 11:30:59 +0200 Subject: [PATCH] issue 900: restore takes a reason and an override; owned paths cite ADR 0394 section 5 --- internal/catalogue/files.go | 12 +++++------- internal/catalogue/files_test.go | 21 +++++++++++++++++++++ 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/internal/catalogue/files.go b/internal/catalogue/files.go index 451b2cca..f1356ed1 100644 --- a/internal/catalogue/files.go +++ b/internal/catalogue/files.go @@ -19,7 +19,7 @@ import ( const FilesSeat = "node-files" // FilesOwnedPaths is the word the holder of node-files is given beside the secret places: a JSON object from -// each absolute path a module owns on its node to "module (tool to use)" (novox/hq ADR 0394 §4). +// each absolute path a module owns on its node to "module (tool to use)" (novox/hq ADR 0394 §5). const FilesOwnedPaths = "MESH_OWNED_PATHS" const ( @@ -77,10 +77,8 @@ func filesVerbs() []Verb { Verb{Name: "trash", Description: "What the node's trash holds: each deleted or replaced item with its id, " + "original path and when it went.", Input: schema(map[string]string{}, nil), Replaces: []string{"ls ~/.local/share/Trash"}}, - Verb{Name: "restore", Description: "Put an item of the node's trash back where it was; refuses when " + - "something is there now.", - Input: schema(map[string]string{"id": "an id from trash"}, []string{"id"}), - Replaces: []string{"trash-restore"}}, + write("restore", "Put an item of the node's trash back where it was; refuses when something is there now.", + map[string]string{"id": "an id from trash"}, []string{"id"}, nil, "trash-restore"), ) } @@ -94,7 +92,7 @@ func FilesHolderProblems(m Manifest) []string { "the node's operator account (novox/hq ADR 0394 §2)", m.Module, FilesSeat, m.RunsAs)} } -// ownedPaths is every path a module owns on this node, as the holder is told (novox/hq ADR 0394 §4): the +// ownedPaths is every path a module owns on this node, as the holder is told (novox/hq ADR 0394 §5): the // paths every seat declares (ADR 0287) with the module holding the seat here, and the paths and files each // module's manifest places (declaredPaths). A seat's path wins where both name one. func (r Resolution) ownedPaths() map[string]string { @@ -140,7 +138,7 @@ func (r Resolution) filesWords(m Manifest, words map[string]string, with Renderi for _, w := range []string{ReadsSecretPlaces, FilesOwnedPaths} { if _, has := words[w]; has { return nil, fmt.Errorf("%s gives its own %s; the node's secret places and owned paths are the mesh's to "+ - "say (novox/hq ADR 0394 §4)", m.Module, w) + "say (novox/hq ADR 0394 §5)", m.Module, w) } } words[ReadsSecretPlaces] = string(places2) diff --git a/internal/catalogue/files_test.go b/internal/catalogue/files_test.go index b6ba2575..63f69233 100644 --- a/internal/catalogue/files_test.go +++ b/internal/catalogue/files_test.go @@ -88,3 +88,24 @@ func TestTheHolderOfNodeFilesIsToldSecretPlacesAndOwnedPaths(t *testing.T) { t.Error("a module not holding node-files is told the owned paths") } } + +// issue 900: restore, like every write verb, takes a reason and an override. +func TestNodeFilesRestoreTakesIdAndReason(t *testing.T) { + s, _ := SeatNamed(FilesSeat) + for _, v := range s.Serves { + if v.Name != "restore" { + continue + } + props, _ := v.Input["properties"].(map[string]any) + for _, p := range []string{"id", "reason", "override"} { + if _, has := props[p]; !has { + t.Errorf("restore has no input %s", p) + } + } + if req, _ := v.Input["required"].([]string); strings.Join(req, ",") != "id,reason" { + t.Errorf("restore requires %v, want id and reason", req) + } + return + } + t.Error("no restore verb") +}