Files
jschoubben b78a911e34 catalogue: deliver a keyless same-node provider's served facts
A node-scope provider that answers a requirement on the same machine and
serves connection facts (a port) but mints no credential delivered
nothing to a co-located consumer. resolve.go only built the delivering
Needed when brokered[want] was set — true only for mesh-scope providers;
a node-scope keyless provider set local[want] instead and fell through,
so knownFor saw no binding and boundInto refused the consumer's
${bound:model-access:port} file.

Deliver the served facts as a need whenever the same-node answer serves a
non-empty set, with a loopback fallback for the address when the node is
off the private network — the reachability rule does not apply to two ends
on one machine. The brokered (credentialed, mesh-scope) path is untouched.

Claude-Session: https://claude.ai/code/session_01LrgweAeERJYBg88c5cKDzF
2026-09-07 05:08:04 +02:00

270 lines
11 KiB
Go

package catalogue
import (
"strings"
"testing"
)
func aModelUser() Manifest {
return Manifest{Module: "assistant", Requires: []string{"model-access"},
Binds: map[string]string{"model-access": "/etc/assistant/model.json"},
Secrets: map[string]string{"model-access": "/etc/assistant/key"}}
}
// A provision answered by a record rather than a node.
//
// novox/hq ADR 0024: a hosted model is on nobody's machine and is reached over the public
// internet, so the rule that refuses two ends sharing no private network must not apply. This
// node is deliberately not on the private network at all — under the old rule that alone would
// refuse it.
func TestAProvisionAnsweredByARecordDoesNotNeedAPrivateNetwork(t *testing.T) {
got, err := Resolve(
map[string]Manifest{"assistant": aModelUser()},
[]string{"assistant"},
Node{Name: "workstation"},
World{
Licences: map[string][]Record{"model-access": {{Name: "personal",
Serves: map[string]any{"model": "a-model"}}}},
Using: map[string]map[string]Record{"assistant": {"model-access": {Name: "personal",
Serves: map[string]any{"model": "a-model"}}}},
})
if err != nil {
t.Fatalf("a machine off the private network could not be given model access: %v", err)
}
if len(got.Needs) != 1 {
t.Fatalf("the licence was not recorded as something this node takes: %+v", got.Needs)
}
if !got.Needs[0].ByRecord {
t.Fatal("the licence was treated as a machine, so the reachability rule would apply to it")
}
if got.Needs[0].From != "personal" {
t.Fatalf("the licence is not named by what a person calls it: %+v", got.Needs[0])
}
}
// Refused when the consumer has not said which — and the refusal names the candidates and the
// command, because ADR 0024 warns this will be felt: a mesh holding three ways to reach a model
// refuses every consumer that has not chosen.
func TestAConsumerThatHasNotSaidWhichLicenceIsRefusedWithTheCandidates(t *testing.T) {
_, err := Resolve(
map[string]Manifest{"assistant": aModelUser()},
[]string{"assistant"},
Node{Name: "workstation"},
World{Licences: map[string][]Record{"model-access": {
{Name: "personal"}, {Name: "the-organisation"},
}}})
if err == nil {
t.Fatal("a consumer was given model access without anybody saying which")
}
said := err.Error()
for _, want := range []string{"personal", "the-organisation", "licence use"} {
if !strings.Contains(said, want) {
t.Fatalf("the refusal does not name %q, so it is correct and unusable:\n%s", want, said)
}
}
}
// A model the mesh runs itself answers it locally, and a record is not consulted.
func TestAModelInTheMeshsOwnSetAnswersItWithoutALicence(t *testing.T) {
got, err := Resolve(
map[string]Manifest{
"assistant": aModelUser(),
"ollama": {Module: "ollama",
Provides: []Offer{{Name: "model-access", Scope: ScopeNode}}},
},
[]string{"assistant", "ollama"},
Node{Name: "workstation"},
World{Licences: map[string][]Record{"model-access": {{Name: "personal"}}}})
if err != nil {
t.Fatalf("a machine running its own model was asked to choose a licence: %v", err)
}
for _, n := range got.Needs {
if n.ByRecord {
t.Fatal("a record was used although the answer was on this machine")
}
}
}
// A key that was never supplied is refused by name rather than silently not written.
//
// The mesh discarded the plaintext when the key was accepted and cannot seal another, so a
// machine that resolved cleanly would receive no file and fail at whatever read it.
func TestAModuleOnALicenceWithNoKeyIsRefusedRatherThanLeftEmpty(t *testing.T) {
r := Resolution{
Node: "workstation",
Modules: []Manifest{aModelUser()},
Needs: []Needed{{Name: "model-access", From: "personal", ByRecord: true, For: "assistant"}},
}
_, err := r.Declaration(Rendering{})
if err == nil {
t.Fatal("a module was given a licence with no key, so it receives nothing and fails later")
}
if !strings.Contains(err.Error(), "licence key personal") {
t.Fatalf("the refusal does not say how to fix it: %v", err)
}
}
// And with a key, both files arrive: what is public, and what is not.
func TestALicenceDeliversWhatIsPublicAndWhatIsSealed(t *testing.T) {
r := Resolution{
Node: "workstation",
Modules: []Manifest{aModelUser()},
Needs: []Needed{{Name: "model-access", From: "personal", ByRecord: true, For: "assistant",
Serves: map[string]any{"model": "a-model"}, Sealed: "sealed-blob"}},
}
out, err := r.Declaration(Rendering{})
if err != nil {
t.Fatal(err)
}
files := map[string]map[string]any{}
for _, res := range out {
if path, ok := res["path"].(string); ok {
files[path] = res
}
}
bound, given := files["/etc/assistant/model.json"]
if !given {
t.Fatal("the consumer was not told what it needs to know that is not secret")
}
content, _ := bound["content"].(string)
if !strings.Contains(content, "a-model") {
t.Fatalf("the binding does not carry what the licence serves:\n%s", content)
}
// The binding says it is a record rather than leaving an empty address, which a reader would
// take for something the mesh failed to fill in.
if !strings.Contains(content, "not a machine") {
t.Fatalf("the binding leaves an empty address with no explanation:\n%s", content)
}
key, delivered := files["/etc/assistant/key"]
if !delivered {
t.Fatal("the key was not delivered")
}
if key["sealed"] != "sealed-blob" {
t.Fatalf("the key is not the sealed one: %+v", key)
}
// And never in the open. The whole arrangement is that what travels is unreadable by
// everything between here and the machine.
if strings.Contains(content, "sealed-blob") {
t.Fatal("the key was written into the public file as well")
}
}
// One machine's unresolvable module must not remove it from the private network.
//
// The pass that answers *what does this node offer* takes a failed resolution to mean it learned
// nothing — so refusing an unanswerable requirement there makes the machine disappear, and every
// other machine is then told, wrongly, that the two of them share no network. A wrong answer about
// a machine nobody asked about, caused by a fault on a third.
func TestAnUnanswerableRequirementDoesNotRemoveAMachineFromTheMesh(t *testing.T) {
shelf := map[string]Manifest{
"assistant": aModelUser(),
"networking": {Module: "networking",
Provides: []Offer{{Name: "mesh-network", Scope: ScopeNode}}},
}
// The first pass: what does this machine offer? It is assigned something nothing answers.
got, err := Resolve(shelf, []string{"assistant", "networking"},
Node{Name: "laptop"}, World{Unchecked: true})
if err != nil {
t.Fatalf("a machine with one unanswerable requirement was lost entirely: %v", err)
}
var offers bool
for _, m := range got.Modules {
for _, o := range m.Offers() {
if o == "mesh-network" {
offers = true
}
}
}
if !offers {
t.Fatal("the machine's own network module was not seen, so it looks off the network")
}
// And the second pass, where the question is actually being asked, still refuses it.
if _, err := Resolve(shelf, []string{"assistant", "networking"},
Node{Name: "laptop"}, World{}); err == nil {
t.Fatal("the requirement nothing answers was accepted when it was actually asked")
}
}
// A same-node provider that mints no credential but serves a port the consumer cannot guess must
// still deliver that port. A `local-model` provider (ollama) provides `model-access` at node scope
// and serves a port and a model name, minting nothing; a co-located consumer requires and binds it
// and has a file that names `${bound:model-access:port}`. The served facts never reached the
// consumer's needs — node scope set `local`, not `brokered`, so the delivering branch was skipped —
// and the consumer's file was refused for naming a provision it "did not require". The endpoint is
// keyless, but a port is still a fact nobody can invent.
func TestAKeylessSameNodeProviderStillDeliversWhatItServes(t *testing.T) {
provider := Manifest{Module: "local-model",
Provides: []Offer{{Name: "model-access", Scope: ScopeNode}},
Serves: map[string]map[string]any{
"model-access": {"port": 11434, "model": "a-model"}}}
consumer := Manifest{Module: "assistant", Requires: []string{"model-access"},
Binds: map[string]string{"model-access": "/etc/assistant/model.json"}}
// node.At empty: a single-node deployment with no private network. The delivered binding must
// still carry a usable address — loopback, because a machine off the network still reaches
// itself, and an empty `at` would be written into the consumer's file as a host that resolves
// to nothing.
got, err := Resolve(
map[string]Manifest{"local-model": provider, "assistant": consumer},
[]string{"assistant", "local-model"},
Node{Name: "workstation"},
World{})
if err != nil {
t.Fatalf("a keyless same-node model endpoint was refused: %v", err)
}
var found *Needed
for i := range got.Needs {
if got.Needs[i].Name == "model-access" && got.Needs[i].For == "assistant" {
found = &got.Needs[i]
}
}
if found == nil {
t.Fatalf("the served endpoint was not delivered to the consumer at all: %+v", got.Needs)
}
if found.ByRecord {
t.Fatal("a same-node endpoint was treated as a record, so the reachability rule would apply")
}
if found.At == "" {
t.Fatalf("the binding carries no address, so its file names a host that resolves to nothing: %+v", found)
}
if found.At != "127.0.0.1" {
t.Fatalf("off the private network the address must fall back to loopback, got %q", found.At)
}
if got, want := plainly(found.Serves["port"]), "11434"; got != want {
t.Fatalf("the port the consumer cannot guess was not delivered: got %q want %q", got, found.Serves)
}
if found.Serves["model"] != "a-model" {
t.Fatalf("the extra served fact was not delivered: %+v", found.Serves)
}
// End to end: a file that names ${bound:model-access:...} is filled rather than refused, which
// is the whole failure this fixes — boundInto reads knownFor, and knownFor reads the needs.
consumer.Resources = []map[string]any{{
"id": "env", "type": "file", "path": "/etc/assistant/.env",
"content": "OPENAI_BASE_URL=http://${bound:model-access:at}:${bound:model-access:port}/v1\n",
}}
got, err = Resolve(
map[string]Manifest{"local-model": provider, "assistant": consumer},
[]string{"assistant", "local-model"},
Node{Name: "workstation"},
World{})
if err != nil {
t.Fatalf("resolution refused the consumer with a bound file: %v", err)
}
out, err := got.Declaration(Rendering{})
if err != nil {
t.Fatalf("the declaration refused the consumer's bound file: %v", err)
}
var env string
for _, res := range out {
if res["path"] == "/etc/assistant/.env" {
env, _ = res["content"].(string)
}
}
if want := "http://127.0.0.1:11434/v1"; !strings.Contains(env, want) {
t.Fatalf("the bound file was not filled with the served endpoint, want %q:\n%s", want, env)
}
}