Ctrl K
ComunidadGuías…

failopen_lost_bornmarker_test.go

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
package main

import (
	"context"
	"go/ast"
	"go/parser"
	"go/token"
	"os"
	"reflect"
	"testing"

	"github.com/pingular/pingularity/internal/config"
	"github.com/pingular/pingularity/internal/settings"
	"github.com/pingular/pingularity/internal/store"
)

// A birth marker records something only the daemon that created the database
// can know, so the daemon that watched it happen may still complete a stamp a
// store fault lost (see internal/settings) - but only until it exits. A write
// that fails at birth and is not completed before the process restarts leaves
// the install markerless FOREVER: from that boot on the store is established,
// no later controller witnessed anything, and an established store must never be
// stamped (a marker added later claims a birth that cannot be proven). On disk
// that install becomes byte-identical to a genuinely 0.61-or-earlier one, which
// is the shape these tests are about.
//
// This is the test that matters: that shape must still fail CLOSED. Marker
// absence advises and nothing more - warnAmbiguousContainerAccess writes
// nothing, and TestOnlyExplicitInputPersistsAccess pins that no other path in
// main may persist an access decision - so the worst a lost stamp can do is
// cost a recurring warning, never network-reachable access. If a future change
// ever lets marker absence DECIDE something, a dropped write at birth becomes
// that decision taken wrongly and permanently; this test is the tripwire.

// denyWritesTo / allowWritesTo make a REAL store refuse writes while reads keep
// working - the exact shape of the fault (settings load fine, only the stamp
// cannot land). The :memory: pool is one connection, so the per-connection
// pragma sticks across calls.
func denyWritesTo(t *testing.T, st *store.Store) {
	t.Helper()
	if _, err := st.DB().ExecContext(context.Background(), "PRAGMA query_only = ON"); err != nil {
		t.Fatalf("query_only on: %v", err)
	}
}

func allowWritesTo(t *testing.T, st *store.Store) {
	t.Helper()
	if _, err := st.DB().ExecContext(context.Background(), "PRAGMA query_only = OFF"); err != nil {
		t.Fatalf("query_only off: %v", err)
	}
}

// quietStderr swallows what fn writes to os.Stderr (settings warns there about
// the lost stamp, before any logger exists) so the failure being modelled does
// not look like test output.
func quietStderr(t *testing.T, fn func()) {
	t.Helper()
	f, err := os.CreateTemp(t.TempDir(), "stderr")
	if err != nil {
		t.Fatalf("temp stderr: %v", err)
	}
	defer f.Close()
	orig := os.Stderr
	os.Stderr = f
	defer func() { os.Stderr = orig }()
	fn()
}

// newLostMarkerContainerStore builds the store a container is left with when its
// birth stamp was LOST to a write error: born under a build that fails closed
// from the first boot (so it was never network-reachable), yet carrying no
// marker, and then established by an ordinary life of configuration and
// history. Every step is real - the write genuinely fails, the marker is
// genuinely absent - so this reproduces the shape rather than asserting it.
//
// What makes the loss PERMANENT is the restart. The controller that watched the
// database come into existence may still complete its own stamp (a later reload
// or settings write finishes it - see the settings package), so this fixture
// drops it while the store is still markerless: from here on, every controller
// is one that never saw the store fresh, and those must refuse forever. That is
// also why the store's later life is written directly rather than through the
// witnessing controller - the daemon that witnessed the birth is gone.
//
// cfg is the boot being modelled, and it seeds the controller exactly as main
// does (establishedContainerController -> testDefaultsFor). Seeding local-only
// here while handing an explicit network scope to reconcileAccess would invent a
// disagreement production never has.
func newLostMarkerContainerStore(t *testing.T, cfg config.Config) (*store.Store, *settings.Controller) {
	t.Helper()
	ctx := context.Background()
	st := openStore(t)

	// Birth, with the database refusing writes.
	denyWritesTo(t, st)
	var born *settings.Controller
	var err error
	quietStderr(t, func() {
		born, err = settings.New(ctx, st, testDefaultsFor(cfg), settings.WithBornVersion("0.62.0-test"))
	})
	if err != nil {
		t.Fatalf("settings.New at birth = %v; a failed stamp must not fail the load", err)
	}
	if born.BornMarkerErr() == nil {
		t.Fatal("fixture precondition: the birth stamp must have failed and been recorded")
	}
	if _, marked := settingsSnapshot(t, st)[settings.KeyInstallBornVersion]; marked {
		t.Fatal("fixture precondition: the store must be markerless")
	}
	allowWritesTo(t, st) // the hiccup passes; everything else works from here on

	// The restart, on a later release: `born` is dropped here without ever
	// completing its stamp, and the controller for the boot under test is built
	// the one sanctioned way - over a store the ordinary life of configuration
	// and history has since made ESTABLISHED.
	set := establishedContainerController(t, st, cfg)
	if set.BornMarkerErr() != nil {
		t.Fatalf("BornMarkerErr = %v on a boot that had nothing to stamp", set.BornMarkerErr())
	}
	return st, set
}

// THE PROOF. An install whose birth marker was lost to a write error, running in
// a container with no explicit -access/PINGULARITY_ACCESS, must end its boot
// LOCAL-ONLY with nothing written. The marker's absence is a missing signal, not
// permission to guess: guessing open here would put an unauthenticated dashboard
// on the LAN of an install that was born private and never answered the network.
func TestLostBirthMarkerContainerBootStaysLocalOnlyAndWritesNothing(t *testing.T) {
	ctx := context.Background()
	st, set := newLostMarkerContainerStore(t, config.Config{}) // no explicit access input
	before := settingsSnapshot(t, st)

	warns := bootAccessDecision(t, config.Config{}, st, set, true) // no explicit access input

	if !set.AccessLocalOnly() {
		t.Fatal("a LOST birth-marker write opened the dashboard to the network; marker absence must decide nothing")
	}
	if storedAccessKey(t, st) {
		t.Fatal("an access choice was persisted from a missing marker; only explicit operator input may write access")
	}
	if after := settingsSnapshot(t, st); !reflect.DeepEqual(before, after) {
		t.Fatalf("the boot wrote to settings: before=%v after=%v (this path must write nothing at all)", before, after)
	}
	// Not just in memory: the next boot reads the same fail-closed state.
	if err := set.Reload(ctx); err != nil {
		t.Fatalf("reload: %v", err)
	}
	if !set.AccessLocalOnly() {
		t.Fatal("access did not survive a reload as local-only")
	}
	if _, marked := settingsSnapshot(t, st)[settings.KeyInstallBornVersion]; marked {
		t.Fatal("the reload stamped the marker on an established store")
	}

	// The cost of the lost stamp, stated: this install gets the ambiguity
	// warning on every boot forever, and the operator's way out is the explicit
	// flag. That is the whole damage - a support signal, not an exposure.
	if len(warns) != 1 || warns[0].msg != accessAmbiguousWarnMsg {
		t.Fatalf("got %d warnings (%v), want exactly the ambiguity warning: a permanently markerless install must at least be explained", len(warns), warns)
	}
}

// The surfaced error must also be CONSUMED, or it is dropped again one layer up.
// Settings records WHY the stamp was lost (and warns to stderr, before any
// logger exists); main is what turns it into a log line an operator can still
// find months later, when the only remaining symptom is an ambiguity warning on
// every boot. Source-level, because run()'s boot sequence is not callable from a
// test - the same reason TestOnlyExplicitInputPersistsAccess reads main.go.
func TestBootReportsALostBirthMarker(t *testing.T) {
	fset := token.NewFileSet()
	file, err := parser.ParseFile(fset, "main.go", nil, 0)
	if err != nil {
		t.Fatalf("parse main.go: %v", err)
	}
	found := false
	ast.Inspect(file, func(n ast.Node) bool {
		if sel, ok := n.(*ast.SelectorExpr); ok && sel.Sel.Name == "BornMarkerErr" {
			found = true
		}
		return !found
	})
	if !found {
		t.Error("main.go never reads BornMarkerErr: a birth marker lost to a write error is permanent, and nothing would record why this install is treated as pre-marker for the rest of its life")
	}
}

// The way out is the documented one, unchanged by how the store lost its marker:
// an explicit PINGULARITY_ACCESS=network is authoritative at THIS boot, so the
// install is one env var away from being reachable again - and once access is
// settled, the ambiguity warning stops.
//
// What it does NOT do is write an access row, and the fixture is what makes that
// visible: main seeds the controller from the same config the boot carries (def
// := defaultSettings(p.cfg)), so with no stored choice the network scope is
// already the effective value and reconcileAccess finds nothing to reconcile.
// Persisting is the Access tab's Save - which is why the docs tell operators to
// keep the variable rather than assume one run made it stick. An older version
// of this test seeded local-only defaults while passing network here, and
// "proved" a persistence production never performs.
func TestLostBirthMarkerInstallStillRecoversWithExplicitAccess(t *testing.T) {
	ctx := context.Background()
	cfg := config.Config{Access: "network", AccessExplicit: true}
	st, set := newLostMarkerContainerStore(t, cfg)

	warns := bootAccessDecision(t, cfg, st, set, true)

	if set.AccessLocalOnly() {
		t.Fatal("explicit PINGULARITY_ACCESS=network did not open access; that is the documented way out of the lockout")
	}
	if storedAccessKey(t, st) {
		t.Fatal("the boot wrote an access row: with the scope already seeded from the same config there is nothing to reconcile, and claiming otherwise models a state production never reaches")
	}
	if err := set.Reload(ctx); err != nil {
		t.Fatalf("reload: %v", err)
	}
	// The reload re-overlays the same defaults over a store that still has no
	// access row, so the variable still governs - and still nothing is stored.
	if set.AccessLocalOnly() {
		t.Fatal("the explicit scope did not survive a reload of the same boot's config")
	}
	if storedAccessKey(t, st) {
		t.Fatal("the reload persisted an access choice")
	}
	if len(warns) != 0 {
		t.Fatalf("got %d warnings, want 0: the operator settled access, so there is no ambiguity left to report", len(warns))
	}
}