A file a tools bundle's words name restarts the runtime when it changes (hq ADR 0192)

The tool containers were restarted when their configuration file changed; the runtime now is
too, for every file a module's words name exactly — configuration and own secret alike.
This commit is contained in:
jochen
2026-10-03 15:33:44 +02:00
parent 4f009fff83
commit 5acc763992
3 changed files with 40 additions and 5 deletions
+15 -1
View File
@@ -930,7 +930,21 @@ func (r Resolution) compose(with Rendering, owner map[string]string,
} }
words[m.Module] = w words[m.Module] = w
} }
givenTo(out, owner, words, r.Account) // And a file a module's words name is one the runtime is restarted for when it changes.
if named := givenTo(out, owner, words, r.Account); len(named) > 0 {
restarts, _ := process["restart-on"].([]any)
seen := map[string]bool{}
for _, id := range restarts {
seen[fmt.Sprint(id)] = true
}
for _, id := range named {
if !seen[id] {
restarts = append(restarts, id)
seen[id] = true
}
}
process["restart-on"] = restarts
}
} }
if with.Adopted { if with.Adopted {
// First, before anything a module declares: what the mesh needs reachable, then its guard. // First, before anything a module declares: what the mesh needs reachable, then its guard.
+15 -4
View File
@@ -310,9 +310,13 @@ func bundleWords(m Manifest, with Rendering) (map[string]string, error) {
// is owned by the account — a tool reads its configuration and its secret as the account, and a // is owned by the account — a tool reads its configuration and its secret as the account, and a
// root-owned 0600 file or a 0700 directory is one it cannot. Only where it says no owner already: // root-owned 0600 file or a 0700 directory is one it cannot. Only where it says no owner already:
// a module that named one knew why. Nothing on a machine with no account, where the runtime is root. // a module that named one knew why. Nothing on a machine with no account, where the runtime is root.
func givenTo(out []map[string]any, owner map[string]string, words map[string]map[string]string, account string) { //
if account == "" || len(words) == 0 { // It answers the files a word names exactly: what a tool reads, whose change the runtime must be
return // restarted for, as the container the tools came from was restarted when its configuration changed.
func givenTo(out []map[string]any, owner map[string]string, words map[string]map[string]string, account string) []string {
var named []string
if len(words) == 0 {
return nil
} }
for _, resource := range out { for _, resource := range out {
module := owner[fmt.Sprint(resource["id"])] module := owner[fmt.Sprint(resource["id"])]
@@ -328,7 +332,12 @@ func givenTo(out []map[string]any, owner map[string]string, words map[string]map
if path == "" { if path == "" {
continue continue
} }
if _, said := resource["owner"]; said { for _, value := range mine {
if kind == "file" && value == path {
named = append(named, fmt.Sprint(resource["id"]))
}
}
if _, said := resource["owner"]; said || account == "" {
continue continue
} }
for _, value := range mine { for _, value := range mine {
@@ -338,4 +347,6 @@ func givenTo(out []map[string]any, owner map[string]string, words map[string]map
} }
} }
} }
sort.Strings(named)
return named
} }
+10
View File
@@ -283,6 +283,16 @@ func TestABundleIsGivenItsWordsResolvedForThisMachine(t *testing.T) {
if r := fileNamed(out, "dash.unrelated"); r == nil || r["owner"] != nil { if r := fileNamed(out, "dash.unrelated"); r == nil || r["owner"] != nil {
t.Errorf("a file no word names was given an owner: %v", r) t.Errorf("a file no word names was given an owner: %v", r)
} }
// A file a word names restarts the runtime when it changes, as it restarted the tool container.
restarts := fmt.Sprint(process["restart-on"])
for _, want := range []string{"dash.config", "dash." + NeedID("token")} {
if !strings.Contains(restarts, want) {
t.Errorf("the runtime is not restarted when %s changes: %s", want, restarts)
}
}
if strings.Contains(restarts, "dash.unrelated") || strings.Contains(restarts, "dash.mesh-state") {
t.Errorf("the runtime restarts for something no word names as a file: %s", restarts)
}
t.Run("on a machine with no account the runtime is root and nothing is re-owned", func(t *testing.T) { t.Run("on a machine with no account the runtime is root and nothing is re-owned", func(t *testing.T) {
out, err := Resolution{Node: "anchor", Modules: []Manifest{dash, theRuntime(t)}}.Declaration(with) out, err := Resolution{Node: "anchor", Modules: []Manifest{dash, theRuntime(t)}}.Declaration(with)