Files
mesh-host/internal/upgrade/fallback_test.go
T
jochen fc6c5a92e6
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 superseded: a newer head of the same pull request
Believe a hand-over only signed by the mesh, and give it through no link (hq issue 356, review)
Two holes the review proved. The ask's subject proved nothing — a responder can reach it through a reply — so the engine now verifies the mesh's signature over a fixed context with the key it verifies declarations with, before reading anything, and refuses an ask for another node, expired, good too long, without a nonce, or replayed. And the apply followed a link the hand-over had refused: a component swapped for a link after the record carried root's chmod and chown to its target. A handed-over directory must now still resolve to itself, and is changed only through one descriptor opened from / with no link followed (fchmod, fchown). Tests for the reply guard, the run loop's hook, the fallback renewal on proof and a non-regular fallback; 27 checks each removed in turn, each failing a test.
2026-10-09 19:45:00 +02:00

187 lines
6.5 KiB
Go

package upgrade
import (
"os"
"path/filepath"
"strings"
"testing"
)
// The engine placed by hand becomes a copy of the proved one when the two differ (novox/hq issue 356): the
// command on PATH is the build that runs the machine.
func TestTheFallbackBecomesACopyOfTheProvedEngine(t *testing.T) {
dir := t.TempDir()
self := filepath.Join(dir, VersionsDirName, "v2", BinaryName)
if err := os.MkdirAll(filepath.Dir(self), 0o755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(self, []byte("the proved engine"), 0o755); err != nil {
t.Fatal(err)
}
fallback := filepath.Join(dir, "bin", BinaryName)
if err := os.MkdirAll(filepath.Dir(fallback), 0o755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(fallback, []byte("the stale engine placed by hand"), 0o644); err != nil {
t.Fatal(err)
}
renewed, err := RenewFallback(self, fallback)
if err != nil || !renewed {
t.Fatalf("renewed %v, %v", renewed, err)
}
got, err := os.ReadFile(fallback)
if err != nil || string(got) != "the proved engine" {
t.Fatalf("the fallback holds %q, %v", got, err)
}
info, err := os.Stat(fallback)
if err != nil || info.Mode().Perm() != 0o755 {
t.Fatalf("the fallback's mode is %v, %v; want 0755 so it can be run", info.Mode(), err)
}
if _, err := os.Stat(self); err != nil {
t.Fatalf("the running engine was touched: %v", err)
}
// Already a copy: left alone, so a proof every start does not rewrite it every start.
before, _ := os.Stat(fallback)
renewed, err = RenewFallback(self, fallback)
if err != nil || renewed {
t.Fatalf("a fallback that is already a copy was renewed again: %v, %v", renewed, err)
}
after, _ := os.Stat(fallback)
if !os.SameFile(before, after) {
t.Fatal("a fallback that is already a copy was replaced")
}
if left, _ := filepath.Glob(filepath.Join(filepath.Dir(fallback), "."+BinaryName+"-*")); len(left) > 0 {
t.Fatalf("temporary files left beside the fallback: %v", left)
}
}
// An engine running from the fallback itself — nothing delivered yet — renews nothing: it would copy a file
// over itself.
func TestAnEngineRunningFromTheFallbackRenewsNothing(t *testing.T) {
dir := t.TempDir()
fallback := filepath.Join(dir, BinaryName)
if err := os.WriteFile(fallback, []byte("placed by hand and running"), 0o755); err != nil {
t.Fatal(err)
}
renewed, err := RenewFallback(fallback, fallback)
if err != nil || renewed {
t.Fatalf("renewed %v, %v", renewed, err)
}
}
// Nothing placed by hand: the proved engine is placed, so the launcher has a fallback and the machine a command.
func TestAMissingFallbackIsPlaced(t *testing.T) {
dir := t.TempDir()
self := filepath.Join(dir, "v1", BinaryName)
if err := os.MkdirAll(filepath.Dir(self), 0o755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(self, []byte("proved"), 0o755); err != nil {
t.Fatal(err)
}
fallback := filepath.Join(dir, BinaryName)
renewed, err := RenewFallback(self, fallback)
if err != nil || !renewed {
t.Fatalf("renewed %v, %v", renewed, err)
}
if got, _ := os.ReadFile(fallback); string(got) != "proved" {
t.Fatalf("placed %q", got)
}
}
// A link at the fallback's path is refused and left as it is: the mesh creates no link and writes through none
// (novox/hq ADR 0012). The link's target is untouched too.
func TestALinkAtTheFallbackIsRefusedAndLeft(t *testing.T) {
dir := t.TempDir()
self := filepath.Join(dir, "v1", BinaryName)
if err := os.MkdirAll(filepath.Dir(self), 0o755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(self, []byte("proved"), 0o755); err != nil {
t.Fatal(err)
}
target := filepath.Join(dir, "somebody-elses")
if err := os.WriteFile(target, []byte("theirs"), 0o755); err != nil {
t.Fatal(err)
}
fallback := filepath.Join(dir, BinaryName)
if err := os.Symlink(target, fallback); err != nil {
t.Fatal(err)
}
renewed, err := RenewFallback(self, fallback)
if err == nil || renewed || !strings.Contains(err.Error(), "link") {
t.Fatalf("a link was taken: %v, %v", renewed, err)
}
if got, _ := os.ReadFile(target); string(got) != "theirs" {
t.Fatalf("the link's target was written: %q", got)
}
if info, err := os.Lstat(fallback); err != nil || info.Mode()&os.ModeSymlink == 0 {
t.Fatalf("the link was replaced: %v %v", info, err)
}
}
// A running engine that cannot be read is said, not copied as nothing.
func TestAnUnreadableRunningEngineIsSaid(t *testing.T) {
dir := t.TempDir()
fallback := filepath.Join(dir, BinaryName)
if err := os.WriteFile(fallback, []byte("placed"), 0o755); err != nil {
t.Fatal(err)
}
renewed, err := RenewFallback(filepath.Join(dir, "gone"), fallback)
if err == nil || renewed {
t.Fatalf("renewed %v, %v", renewed, err)
}
if got, _ := os.ReadFile(fallback); string(got) != "placed" {
t.Fatalf("the fallback was written from nothing: %q", got)
}
if _, err := RenewFallback("", fallback); err == nil {
t.Fatal("an empty path was taken")
}
}
// The fallback's path is the launcher's: its environment variable, or the default.
func TestTheFallbackPathIsTheLaunchers(t *testing.T) {
t.Setenv(FallbackVar, "")
if FallbackPath() != DefaultFallback {
t.Fatalf("the default is %q", FallbackPath())
}
t.Setenv(FallbackVar, "/elsewhere/nox-mesh-host")
if FallbackPath() != "/elsewhere/nox-mesh-host" {
t.Fatalf("the override is %q", FallbackPath())
}
}
// A fallback that is not a regular file — a directory where the engine should be — is refused and left: the mesh
// replaces a file, never something else at its name.
func TestAFallbackThatIsNotARegularFileIsRefused(t *testing.T) {
dir := t.TempDir()
self := filepath.Join(dir, "v1", BinaryName)
if err := os.MkdirAll(filepath.Dir(self), 0o755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(self, []byte("proved"), 0o755); err != nil {
t.Fatal(err)
}
fallback := filepath.Join(dir, BinaryName)
if err := os.Mkdir(fallback, 0o755); err != nil {
t.Fatal(err)
}
renewed, err := RenewFallback(self, fallback)
if err == nil || renewed || !strings.Contains(err.Error(), "not a regular file") {
t.Fatalf("a directory at the fallback was taken: %v, %v", renewed, err)
}
if info, err := os.Lstat(fallback); err != nil || !info.IsDir() {
t.Fatalf("the directory was replaced: %v %v", info, err)
}
// And a running engine that is not a regular file is refused before anything is written.
if _, err := RenewFallback(dir, filepath.Join(dir, "elsewhere")); err == nil || !strings.Contains(err.Error(),
"not a regular file") {
t.Fatalf("a directory was taken as the running engine: %v", err)
}
if _, err := os.Lstat(filepath.Join(dir, "elsewhere")); err == nil {
t.Fatal("something was placed from a directory")
}
}