Files
jschoubben f06eea5fa3 declaration: an access is mounted, and the host owns nothing about it
The tenth shape (novox/hq ADR 0051). Shared, pre-existing data — a media
library, a download spool several modules use — is the operator's, not
the mesh's. A `directory` resource is the host's own: it creates it,
chowns it, sets its mode and removes it when empty. An access is the
opposite on every axis.

Add the `access` type to the vocabulary. Its applier confirms the path is
present and changes nothing: it does not create, chown, reconcile or set
a mode. Absent is refused clearly — the operator must provide it — rather
than created, because a bind mount whose source is missing is made as
root by the container runtime with the wrong ownership (04-ISSUES/026).
Undeclaring an access forgets the record and never touches the path,
which is the data loss ADR 0030 prevents, on a directory the mesh never
made.

Full hosts speak it (it gates a bind mount, which needs the container
runtime); the vocabulary guard test records the decision that made it the
tenth shape. Unit tests cover present, absent-refused, and
undeclared-left-alone.

Claude-Session: https://claude.ai/code/session_01LrgweAeERJYBg88c5cKDzF
2026-09-05 22:19:33 +02:00

99 lines
3.8 KiB
Go

package apply
import (
"context"
"os"
"strings"
"testing"
"github.com/novox/mesh-host/internal/store"
)
// An operator-owned path the module reaches but does not own (novox/hq ADR 0051).
//
// The host confirms it is present and changes nothing: it does not create it, chown it or set its
// mode, because the media library and the download spool are the operator's and several modules
// share them. This is the opposite of a directory on every axis, and the whole reason the two are
// different shapes.
func TestAnAccessPresentIsConfirmedAndNothingIsChanged(t *testing.T) {
dir := t.TempDir() // the operator's directory, already there
d := declare(t, `{"id":"lib","type":"access","path":"`+dir+`","mode":"read-write"}`)
report, _, err := Apply(context.Background(), archHost(t), d, store.State{},
store.OriginDeclared, noServices, nil, nil)
if err != nil {
t.Fatalf("an operator-owned path that is present was refused: %v", err)
}
if report.Changed() {
t.Fatalf("confirming an access reported a change; the host owns nothing about it")
}
if _, statErr := os.Stat(dir); statErr != nil {
t.Fatalf("the operator's directory was disturbed: %v", statErr)
}
}
// Absent is refused, not created. A bind mount whose source does not exist is made by the
// container runtime as root, with whatever mode it picks — the silent wrong-ownership
// 04-ISSUES/026 records. So the host says plainly that the operator must provide the path, rather
// than conjuring a directory it does not own.
func TestAnAccessThatIsAbsentIsRefusedClearlyAndNotCreated(t *testing.T) {
missing := t.TempDir() + "/media/library" // named, never created
d := declare(t, `{"id":"lib","type":"access","path":"`+missing+`"}`)
_, _, err := Apply(context.Background(), archHost(t), d, store.State{},
store.OriginDeclared, noServices, nil, nil)
if err == nil {
t.Fatal("an absent operator-owned path was accepted, and would be created as root by the runtime")
}
if !strings.Contains(err.Error(), "the operator must provide") ||
!strings.Contains(err.Error(), "does not own") {
t.Fatalf("the refusal does not say whose the path is: %v", err)
}
if _, statErr := os.Stat(missing); statErr == nil {
t.Fatal("the host created the path it does not own")
}
}
// Undeclaring an access never removes the path. Unassigning the module that reached the media
// library must not delete the library — that is the data loss ADR 0030 exists to prevent, on a
// directory the mesh never made. The record is dropped; the operator's data is left exactly as it
// is.
func TestAnUndeclaredAccessLeavesTheOperatorsPathAlone(t *testing.T) {
lib := t.TempDir() // the operator's library
keep := t.TempDir()
if err := os.WriteFile(lib+"/a-real-file", []byte("the operator's data"), 0o644); err != nil {
t.Fatal(err)
}
d := declare(t, `{"id":"lib","type":"access","path":"`+lib+`","mode":"read"}`)
_, state, err := Apply(context.Background(), archHost(t), d, store.State{},
store.OriginDeclared, noServices, nil, nil)
if err != nil {
t.Fatal(err)
}
// The module is unassigned: the mesh no longer declares the access.
empty := declare(t, `{"id":"unrelated","type":"directory","path":"`+keep+`"}`)
report, _, err := Apply(context.Background(), archHost(t), empty, state,
store.OriginDeclared, noServices, nil, nil)
if err != nil {
t.Fatal(err)
}
if _, statErr := os.Stat(lib); statErr != nil {
t.Fatalf("the operator's library was removed when the module stopped reaching it: %v", statErr)
}
if _, statErr := os.Stat(lib + "/a-real-file"); statErr != nil {
t.Fatalf("the operator's data was removed: %v", statErr)
}
var forgot bool
for _, o := range report.Outcomes {
if o.Type == "access" && o.Action == "forgotten" {
forgot = true
}
}
if !forgot {
t.Errorf("dropping an access was not reported as forgotten: %+v", report.Outcomes)
}
}