diff --git a/modules/mesh-files/cmd/mesh-files/main.go b/modules/mesh-files/cmd/mesh-files/main.go index 2805919d7..79d07b694 100644 --- a/modules/mesh-files/cmd/mesh-files/main.go +++ b/modules/mesh-files/cmd/mesh-files/main.go @@ -171,7 +171,9 @@ func object(props map[string]any, required ...string) map[string]any { // The descriptions of the reads are the controller's (internal/catalogue/files.go): the reads' own, with // where they are read as restated for the operator's account. -const asAccount = "as the node's operator account, through sudo -n where its rights do not reach; a place a " + +const readsAs = "as the node's operator account, through sudo -n where its rights do not reach" + +const asAccount = readsAs + "; a place a " + "secret is kept, or a known credential file, is refused by name" func boolArg(a map[string]any, k string) bool { return arg(a, k) == "true" } @@ -266,7 +268,7 @@ func tools(f *Files) []stdio.Tool { func readTools(r Reader) []stdio.Tool { ts := rawReadTools(r) for i := range ts { - if !strings.Contains(ts[i].Description, asAccount) { + if !strings.Contains(ts[i].Description, readsAs) { ts[i].Description += " Read " + asAccount + "." } } @@ -288,7 +290,7 @@ func rawReadTools(r Reader) []stdio.Tool { verb("list", "Every entry of one directory with its type, owner, group, mode, size and, for a link, its "+ "target. At most 2000 entries; a longer directory is cut and says so. A place a secret is kept is "+ "listed too, at any depth, and marked secret-place: its entries, never their content; what reaches a "+ - "process's memory or files (/proc//environ, mem, fd, map_files, root, cwd) is refused by name.", + "process's memory or files (/proc//environ, mem, fd, map_files, root, cwd) is refused by name. Read "+readsAs+".", object(map[string]any{"path": str("an absolute path to a directory")}, "path"), func(a map[string]any) (any, error) { return r.List(arg(a, "path")) }), verb("read", "One text file, or a part of it by line: at most 256 KiB in one answer (64 KiB unless more "+ diff --git a/modules/mesh-files/cmd/mesh-files/reads_test.go b/modules/mesh-files/cmd/mesh-files/reads_test.go index 5e5913d4c..399098097 100644 --- a/modules/mesh-files/cmd/mesh-files/reads_test.go +++ b/modules/mesh-files/cmd/mesh-files/reads_test.go @@ -95,6 +95,21 @@ func TestSecretPlacesAreRefusedByNameBeforeAnyRead(t *testing.T) { if a, err := r.List(filepath.Join(dir, "home/ops")); err != nil || a.Secret != "" { t.Errorf("a plain directory is marked: %+v %v", a, err) } + // a link in a secret place: the entry is answered, its target held to the content rule (ADR 0394 ยง8) + if err := os.Symlink(aToken, filepath.Join(vault, "ledger/tokenlink")); err != nil { + t.Fatal(err) + } + if a, err := r.List(filepath.Join(vault, "ledger")); err != nil || a.Secret == "" || len(a.Withheld) != 1 || + a.Withheld[0].At != "a link's target" || strings.Contains(a.Entries[0].Link+a.Entries[1].Link, aToken) { + t.Errorf("a secret-shaped target in a secret place: %+v %v", a, err) + } + // the served text of list says it lists a secret place, and no longer that it refuses one + for _, tl := range readTools(r) { + if tl.Name == "list" && (strings.Contains(tl.Description, "known credential file, is refused") || + !strings.HasSuffix(tl.Description, "where its rights do not reach.")) { + t.Errorf("the list text: %s", tl.Description) + } + } if _, err := r.List("/proc/self/fd"); err == nil || !strings.Contains(err.Error(), "refused by name") { t.Errorf("a process's open files were listed: %v", err) }