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.
187 lines
6.5 KiB
Go
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")
|
|
}
|
|
}
|