package licences import ( "context" "strings" "testing" ) // These run against a real PostgreSQL, like every other context's. `make check` raises one. func fresh(t *testing.T) (*Licences, context.Context) { t.Helper() return ForTest(t), t.Context() } func aKey(t *testing.T) string { return ASealingKey(t) } // The mesh does not keep a key it cannot seal to somebody, because keeping it for later means // keeping it readably — which is the whole thing this refuses to do. func TestAKeyWithNobodyToSealItToIsRefused(t *testing.T) { held, ctx := fresh(t) if err := held.Add(ctx, "personal", "anthropic", nil); err != nil { t.Fatal(err) } _, err := held.Accept(ctx, "personal", "sk-test", func(string) (string, error) { return "", nil }) if err == nil { t.Fatal("a key was taken with nobody to seal it to, so it was kept in the open") } if !strings.Contains(err.Error(), "consumer on it first") { t.Fatalf("the refusal does not say what to do: %v", err) } } // Sealed to each holder, and the plaintext discarded. func TestAKeyIsSealedToEachHolderAndNotKept(t *testing.T) { held, ctx := fresh(t) if err := held.Add(ctx, "personal", "anthropic", map[string]any{"model": "a-model"}); err != nil { t.Fatal(err) } for _, node := range []string{"workstation", "laptop"} { if err := held.Use(ctx, "personal", node, "assistant"); err != nil { t.Fatal(err) } } keys := map[string]string{"workstation": aKey(t), "laptop": aKey(t)} const value = "sk-the-operators-own-key" sealed, err := held.Accept(ctx, "personal", value, func(node string) (string, error) { return keys[node], nil }) if err != nil { t.Fatal(err) } if sealed != 2 { t.Fatalf("%d holder(s) were sealed to, and there are two", sealed) } first, err := held.KeyFor(ctx, "personal", "workstation", "assistant") if err != nil { t.Fatal(err) } second, err := held.KeyFor(ctx, "personal", "laptop", "assistant") if err != nil { t.Fatal(err) } if first == "" || second == "" { t.Fatal("a holder was left with no key") } // Sealed to different machines, so the blobs differ even though the key is one key. Two // identical blobs would mean one of them was sealed to a machine that cannot open it. if first == second { t.Fatal("both holders were given the same blob, so one of them cannot open it") } // And nowhere in the open. This is the argument, not a detail. for _, blob := range []string{first, second} { if strings.Contains(blob, value) { t.Fatal("the key is in the stored value in the open") } } } // A holder recorded after the key was supplied has none, and the mesh cannot make one. // // Reported rather than hidden: a machine that resolves cleanly and receives nothing fails later, // somewhere that names neither the licence nor the mesh. func TestAHolderAddedAfterTheKeyHasNone(t *testing.T) { held, ctx := fresh(t) if err := held.Add(ctx, "personal", "anthropic", nil); err != nil { t.Fatal(err) } if err := held.Use(ctx, "personal", "workstation", "assistant"); err != nil { t.Fatal(err) } key := aKey(t) if _, err := held.Accept(ctx, "personal", "sk-test", func(string) (string, error) { return key, nil }); err != nil { t.Fatal(err) } if err := held.Use(ctx, "personal", "laptop", "assistant"); err != nil { t.Fatal(err) } later, err := held.KeyFor(ctx, "personal", "laptop", "assistant") if err != nil { t.Fatal(err) } if later != "" { t.Fatal("a holder added after the key was discarded was somehow given one") } // And the first holder still has theirs — a new holder must not disturb an existing one. first, err := held.KeyFor(ctx, "personal", "workstation", "assistant") if err != nil { t.Fatal(err) } if first == "" { t.Fatal("adding a holder took the key away from one that had it") } } // Taking a consumer off a licence takes its copy of the key with it. func TestReleasingAConsumerTakesItsKey(t *testing.T) { held, ctx := fresh(t) if err := held.Add(ctx, "personal", "anthropic", nil); err != nil { t.Fatal(err) } if err := held.Use(ctx, "personal", "workstation", "assistant"); err != nil { t.Fatal(err) } key := aKey(t) if _, err := held.Accept(ctx, "personal", "sk-test", func(string) (string, error) { return key, nil }); err != nil { t.Fatal(err) } if err := held.StopUsing(ctx, "personal", "workstation", "assistant"); err != nil { t.Fatal(err) } holders, err := held.HoldersOf(ctx, "personal") if err != nil { t.Fatal(err) } if len(holders) != 0 { t.Fatalf("a released consumer is still a holder: %+v", holders) } } // A licence nobody recorded is not a licence somebody can be put on. func TestUsingALicenceThatDoesNotExistIsRefused(t *testing.T) { held, ctx := fresh(t) err := held.Use(ctx, "invented", "workstation", "assistant") if err == nil { t.Fatal("a consumer was put on a licence this mesh has never heard of") } // Named, in words a person can act on. The database's own foreign-key message is true and // mentions a constraint rather than a licence, which sends somebody reading a schema instead // of typing the name they meant. if !strings.Contains(err.Error(), `"invented"`) { t.Fatalf("the refusal does not name the licence: %v", err) } } // Two sessions on one machine, each on its own licence (novox/hq work breakdown 1.2). // // **The case ADR 0026 creates.** The control-plane node runs its own node session and the mesh's, // so a machine is no longer a usable answer to *whose licence is this*. `14-model-access.md` // records that gap as "a consumer that is not a machine", and the question this answers is whether // it needs a new consumer identity or whether the existing one already distinguishes them. // // It does. The two sessions are two modules — the same mechanism started in different context // roots (ADR 0026), and a context root is what a module delivers — so `(node, module)` names them // apart without a schema knowing anything about sessions. func TestTwoSessionsOnOneMachineHoldDifferentLicences(t *testing.T) { held, ctx := fresh(t) for _, l := range []struct{ name, vendor string }{ {"personal", "anthropic"}, {"company", "anthropic"}, } { if err := held.Add(ctx, l.name, l.vendor, map[string]any{"model": "a-model"}); err != nil { t.Fatal(err) } } // Both on the machine that holds the control plane. const machine = "anchor" if err := held.Use(ctx, "personal", machine, "node-session"); err != nil { t.Fatal(err) } if err := held.Use(ctx, "company", machine, "mesh-session"); err != nil { t.Fatal(err) } // Each is asked for separately, and neither answer is the other's. node, err := held.Chosen(ctx, machine, "node-session") if err != nil { t.Fatal(err) } mesh, err := held.Chosen(ctx, machine, "mesh-session") if err != nil { t.Fatal(err) } if node != "personal" || mesh != "company" { t.Fatalf("the node session is on %q and the mesh session on %q; expected personal and company", node, mesh) } // And the keys are separate too, which is the half that matters: a machine-wide answer would // hand both sessions whichever key was sealed last. sealing := aKey(t) for _, l := range []struct{ name, value string }{ {"personal", "sk-the-operators-own-key"}, {"company", "sk-the-companys-key"}, } { if _, err := held.Accept(ctx, l.name, l.value, func(string) (string, error) { return sealing, nil }); err != nil { t.Fatal(err) } } first, err := held.KeyFor(ctx, "personal", machine, "node-session") if err != nil { t.Fatal(err) } second, err := held.KeyFor(ctx, "company", machine, "mesh-session") if err != nil { t.Fatal(err) } if first == "" || second == "" { t.Fatal("a session on a licence was given no key") } if first == second { t.Fatal("both sessions were given the same sealed key, so the machine answered rather " + "than the session") } } // A session put on no licence is not silently given the machine's other one. func TestASessionOnNoLicenceIsAnsweredWithNothing(t *testing.T) { held, ctx := fresh(t) if err := held.Add(ctx, "personal", "anthropic", map[string]any{"model": "a-model"}); err != nil { t.Fatal(err) } if err := held.Use(ctx, "personal", "anchor", "node-session"); err != nil { t.Fatal(err) } chosen, err := held.Chosen(ctx, "anchor", "mesh-session") if err != nil { t.Fatal(err) } if chosen != "" { t.Fatalf("a session nobody put on a licence was answered with %q, which belongs to "+ "something else on the same machine", chosen) } } // Two sessions on one machine and the SAME licence are still two holders. // // **Written because a fault injection stayed silent.** The test above puts them on different // licences, so the licence alone tells them apart and the module argument is never load-bearing — // removing it from the query changed nothing and every assertion still passed. This is the case // that needs `(node, module)` to be the identity: releasing one session must leave the other, // and a machine-shaped answer would take both. func TestReleasingOneSessionLeavesTheOtherOnTheSameMachine(t *testing.T) { held, ctx := fresh(t) if err := held.Add(ctx, "company", "anthropic", map[string]any{"model": "a-model"}); err != nil { t.Fatal(err) } const machine = "anchor" for _, session := range []string{"node-session", "mesh-session"} { if err := held.Use(ctx, "company", machine, session); err != nil { t.Fatal(err) } } if _, err := held.Accept(ctx, "company", "sk-the-companys-key", func(string) (string, error) { return aKey(t), nil }); err != nil { t.Fatal(err) } if err := held.StopUsing(ctx, "company", machine, "node-session"); err != nil { t.Fatal(err) } gone, err := held.Chosen(ctx, machine, "node-session") if err != nil { t.Fatal(err) } if gone != "" { t.Errorf("the released session is still on %q", gone) } kept, err := held.Chosen(ctx, machine, "mesh-session") if err != nil { t.Fatal(err) } if kept != "company" { t.Fatal("releasing one session took the other's licence with it, so the machine was " + "released rather than the session") } key, err := held.KeyFor(ctx, "company", machine, "mesh-session") if err != nil { t.Fatal(err) } if key == "" { t.Fatal("the session that was kept lost its key") } }