Merge pull request 'Let a trusted file that names its keys hold only those keys at the terminal (hq issue 586, ADR 0329 §5)' (#286) from fix/586-a-named-key-is-trusted-alone into main
This commit was merged in pull request #286.
This commit is contained in:
@@ -345,6 +345,37 @@ func TestAnyKeyOfAModuleWithATrustedMergeableFileIsRefusedThroughAVerb(t *testin
|
||||
}
|
||||
}
|
||||
|
||||
// A module whose mergeable files name the keys they take (ADR 0326): a key of a trusted file is refused through a
|
||||
// verb, and a key of a file nothing trusts is set through it (novox/hq ADR 0329 §5, issue 586: betterbird's tags).
|
||||
func TestOnlyATrustedFilesNamedKeyIsRefusedThroughAVerb(t *testing.T) {
|
||||
open := aMesh(t)
|
||||
ctx := t.Context()
|
||||
register(t, open, catalogue.Manifest{Module: "mailer", Version: "1",
|
||||
Resources: []map[string]any{
|
||||
{"id": "accounts", "type": "file", "path": "/var/lib/mailer/accounts.json", "mode": "0600", "merge": "json",
|
||||
"trusted": true, "takes-settings": []any{"accounts"}, "content": `{"accounts": {}}`},
|
||||
{"id": "tags", "type": "file", "path": "/var/lib/mailer/tags.json", "mode": "0644", "merge": "json",
|
||||
"trusted": false, "takes-settings": []any{"tags"}, "content": `{"tags": {}}`}}})
|
||||
if _, err := assign(ctx, open, "anchor", "mailer"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := throughVerb(t, "settings", map[string]any{"module": "mailer", "values": `{"tags":{"todo":{"name":"To do"}}}`}); err != nil {
|
||||
t.Fatalf("a key of a file nothing trusts is the verb's: %v", err)
|
||||
}
|
||||
err := throughVerb(t, "settings", map[string]any{"module": "mailer", "replace": "true",
|
||||
"values": `{"tags":{"todo":{"name":"To do"}},"accounts":{"mail":{"address":"me@mail.example"}}}`})
|
||||
if err == nil || !strings.Contains(err.Error(), "controller's terminal") || !strings.Contains(err.Error(), "accounts") {
|
||||
t.Fatalf("a key of a trusted file is the terminal's: %v", err)
|
||||
}
|
||||
values, _, err := open.inventory.Layer(ctx, "", "mailer")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if raw, _ := json.Marshal(values); string(raw) != `{"tags":{"todo":{"name":"To do"}}}` {
|
||||
t.Fatalf("the layer holds the tags alone: %s", raw)
|
||||
}
|
||||
}
|
||||
|
||||
// Who owns a module's directory is said at the terminal alone (novox/hq issue 279): a directory's owner may name
|
||||
// the settings the module runs as, root chowns the folder to them at the next push, and through the settings verb
|
||||
// any caller could have set puid to 0 or to its own uid. The key is refused through every verb route even where a
|
||||
|
||||
@@ -33,6 +33,10 @@ import (
|
||||
// 4. **A module's whole layer, when it has a mergeable file not marked `"trusted": false`** (novox/hq issue 340,
|
||||
// TrustedMergeable). A mergeable file takes any key a layer sets, not only those its content names, so no list
|
||||
// of keys covers it: an empty runtime configuration a provider reads would take a `url` of the caller's.
|
||||
// **Unless the module's files name the keys they take** (novox/hq ADR 0326, ADR 0329 §5): then a mergeable
|
||||
// file takes exactly its `takes-settings` and no other key, so those keys of a trusted file are terminal keys
|
||||
// and the rest of the layer is not. A key no file names is stray and refused where it is set. So betterbird's
|
||||
// `tags`, in a file nothing trusts, is set through the verb, while its `accounts` and `identities` are not.
|
||||
// 5. **Every setting a directory's owner asks for** (novox/hq issue 279): root chowns the directory to the number
|
||||
// at the next push, so through a verb any caller could hand itself — or uid 0 — a module's folder. Whatever
|
||||
// else asks for the key, a file marked `"trusted": false` included, the owner makes it the terminal's.
|
||||
@@ -109,8 +113,13 @@ func UnsaidTrust(m Manifest) []string {
|
||||
// TrustedMergeable is every mergeable file of a module not marked `"trusted": false`, by id (novox/hq issue 340).
|
||||
// A mergeable file takes any key a layer sets, not only those its content names: an empty runtime configuration a
|
||||
// provider reads takes a `url` of a caller's as surely as a declared one. So a module holding one has its whole
|
||||
// layer set at the controller's terminal; a verb may read it and change nothing.
|
||||
// layer set at the controller's terminal; a verb may read it and change nothing. A module whose mergeable files
|
||||
// name the keys they take (ADR 0326) has none here: each such file takes only its named keys, which TerminalKeys
|
||||
// holds for a trusted one (ADR 0329 §5).
|
||||
func TrustedMergeable(m Manifest) []string {
|
||||
if namesItsKeys(m) {
|
||||
return nil
|
||||
}
|
||||
var out []string
|
||||
for _, r := range m.Resources {
|
||||
if fmt.Sprint(r["type"]) != "file" {
|
||||
@@ -135,6 +144,16 @@ func TrustedMergeable(m Manifest) []string {
|
||||
func asksFor(r map[string]any) []string {
|
||||
content, _ := r["content"].(string)
|
||||
asked := settingsUsed(content)
|
||||
if how, _ := r["merge"].(string); how != "" {
|
||||
if taken, names := takenKeys(r); names {
|
||||
// The file takes exactly the keys it names (ADR 0326), whatever its content holds.
|
||||
for key := range taken {
|
||||
asked = append(asked, key)
|
||||
}
|
||||
sort.Strings(asked)
|
||||
return asked
|
||||
}
|
||||
}
|
||||
if how, _ := r["merge"].(string); how != "" && strings.TrimSpace(content) != "" {
|
||||
var base map[string]any
|
||||
if json.Unmarshal([]byte(content), &base) == nil {
|
||||
|
||||
@@ -166,6 +166,33 @@ func TestTerminalKeysAreDerived(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// A module whose mergeable files name the keys they take (ADR 0326) has no whole layer at the terminal: a
|
||||
// trusted file's named keys are terminal keys, and a file nothing trusts leaves its keys to the verb (novox/hq
|
||||
// ADR 0329 §5, issue 586: betterbird's tags beside its trusted accounts, identities, calendars, address books
|
||||
// and filters). A module whose files name no keys keeps the whole layer at the terminal (issue 340).
|
||||
func TestOnlyANamedKeyOfATrustedFileIsTheTerminals(t *testing.T) {
|
||||
betterbird := Manifest{Module: "betterbird", Resources: []map[string]any{
|
||||
{"id": "prefs", "type": "file", "path": "/home/p/prefs.json", "merge": MergeJSON, "trusted": true,
|
||||
TakesSettingsField: []any{"prefs"}, "content": `{"prefs": {}}`},
|
||||
{"id": "accounts", "type": "file", "path": "/home/p/accounts.json", "merge": MergeJSON, "trusted": true,
|
||||
TakesSettingsField: []any{"accounts"}, "content": `{"accounts": {}}`},
|
||||
{"id": "configuration", "type": "file", "path": "/home/p/configuration.json", "merge": MergeJSON,
|
||||
TakesSettingsField: []any{"identities", "calendars", "address-books", "filters"}, "content": `{}`},
|
||||
{"id": "tags", "type": "file", "path": "/home/p/tags.json", "merge": MergeJSON, "trusted": false,
|
||||
TakesSettingsField: []any{"tags"}, "content": `{"tags": {}}`}}}
|
||||
if got := TrustedMergeable(betterbird); len(got) != 0 {
|
||||
t.Fatalf("files that name their keys put no whole layer at the terminal: %v", got)
|
||||
}
|
||||
if got := strings.Join(TerminalKeys(betterbird), ","); got != "places,accesses,accounts,address-books,calendars,filters,identities,prefs" {
|
||||
t.Fatalf("the named keys of the trusted files, unmarked counting as trusted, and not tags: %s", got)
|
||||
}
|
||||
silent := Manifest{Module: "keycloak", Resources: []map[string]any{{"id": "runtime", "type": "file",
|
||||
"path": "/var/lib/kc/runtime.json", "merge": MergeJSON, "content": `{}`}}}
|
||||
if got := TrustedMergeable(silent); len(got) != 1 {
|
||||
t.Fatalf("a file that names no keys still takes any key, so its module's layer stays the terminal's: %v", got)
|
||||
}
|
||||
}
|
||||
|
||||
// A file that asks for a setting says whether what it asks is trusted (novox/hq issue 339): `trusted` is a
|
||||
// boolean, on a file alone, and a file asking for a setting without it is named.
|
||||
func TestAFileSaysWhetherItsSettingsAreTrusted(t *testing.T) {
|
||||
|
||||
Vendored
+1
@@ -40,3 +40,4 @@
|
||||
./internal/inventory TestAStoredBuildWithASilentMergeableFileIsStillReadAndComposed
|
||||
./cmd/mesh-controller TestPlanAndNodeListAnOptionalRequirementLeftUnbound
|
||||
./cmd/mesh-controller TestReplay340
|
||||
./cmd/mesh-controller TestOnlyATrustedFilesNamedKeyIsRefusedThroughAVerb
|
||||
|
||||
Reference in New Issue
Block a user