Files
mesh-host/internal/apply/root_moved.go
T
jochen a7270f00cb
mesh/merge-gate pass: builds mesh-host → ace, g14, novox, shanks; no bus step; every machine composes with the change as it did without (4 of 4 compose)
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery delivered
mesh/delivery-group group fix/361-the-setuid-search-runs-to-completion delivered: every member is delivered
Keep the walk's paths as bytes, forget a walk root superseded, and leave other mounts unread (hq issue 361 review)
The review found a cursor of a name that is not UTF-8 came back changed
from JSON, so a resumed walk skipped what it stood before; an ask to
search again was lost to a restart, which carried the older walk on; a
fresh search judged a filesystem it never walked; a mount point root
cannot read failed or hung the walk; a found file gone before the package
manager was asked failed every resume; and skipped or kept outcomes
started a search on every reconcile, back to back with a long walk.
2026-10-10 01:10:56 +02:00

50 lines
1.8 KiB
Go

package apply
import (
"path/filepath"
"strings"
"github.com/novox/mesh-host/internal/declaration"
)
// rootPaths are the files and directories through which an account comes to root, or by which it is told who it
// is: the user and group databases, sudo's, doas's and polkit's rules. A file written there changes what the
// judge of an agent account reads (novox/hq ADR 0266).
var rootPaths = []string{"/etc/passwd", "/etc/shadow", "/etc/group", "/etc/gshadow", "/etc/sudoers",
"/etc/sudoers.d", "/etc/doas.conf", "/etc/doas.d", "/etc/polkit-1", "/usr/share/polkit-1"}
// MovesRoot says an apply changed something through which root's reach could have changed — an account, a
// package, an action run as root, or a file in rootPaths (novox/hq issue 361). The engine then asks for a new
// search for setuid programs: root acted, and a complete search is sound only until root acts. Outcomes that
// moved nothing (unchanged, held, waiting, held still, skipped, kept, forgotten) do not count.
func MovesRoot(outcomes []Outcome) bool {
for _, o := range outcomes {
// Only what moved the machine: skipped, kept and forgotten touch nothing, and counting them made one
// broken module start a search on every reconcile (the review of 2026-10-10).
switch o.Action {
case "created", "updated", "corrected", "removed":
default:
continue
}
switch declaration.Type(o.Type) {
case declaration.TypeUser, declaration.TypePackage, declaration.TypeAction:
return true
case declaration.TypeFile, declaration.TypeDirectory, declaration.TypeArchive:
if underRootPath(o.Target) {
return true
}
}
}
return false
}
func underRootPath(target string) bool {
t := filepath.Clean(target)
for _, p := range rootPaths {
if t == p || strings.HasPrefix(t, p+"/") {
return true
}
}
return false
}