package licences import ( "strings" "testing" "github.com/novox/mesh-control/internal/secrets" ) // SubmitRefresh is the boundary a manager NODE crosses to publish a refresh it performed: the control // plane is given only the access token in the clear and an opaque re-sealed refresh box — never the // refresh token. These tests defend that the boundary keeps its shape. // A submitted refresh seals the access token to every CONSUMER holder, exactly as an in-process // refresh does, and delivers no refresh token to a consumer. func TestSubmitRefreshSealsTheAccessTokenAndNeverTheRefreshToken(t *testing.T) { held, ctx := fresh(t) // No in-process refresher registered: the anthropic production path uses SubmitRefresh, not // Refresh, precisely so nothing opens the box inside this process. _, _, _, holders, keys := aRefreshableLicence(t, held, ctx, &fakeRefresher{}) sealed, err := held.SubmitRefresh(ctx, "personal", "at-from-the-manager-node", "", "", keys) if err != nil { t.Fatal(err) } if sealed != 2 { t.Fatalf("%d consumer holder(s) were resealed, expected 2", sealed) } for node, open := range holders { blob, err := held.KeyFor(ctx, "personal", node, "assistant") if err != nil { t.Fatal(err) } got, err := open(blob) if err != nil { t.Fatalf("%s cannot open what it was delivered", node) } if string(got) != "at-from-the-manager-node" { t.Fatalf("%s was delivered %q, not the access token", node, got) } if string(got) == "rt-the-refresh-token" || strings.Contains(blob, "rt-the-refresh-token") { t.Fatalf("%s was delivered the refresh token", node) } } } // The refresh token is untouched by a submit that carried no rotation, and the manager node — and // only it — still opens it. The submit path never saw the refresh token in the clear. func TestSubmitRefreshWithoutRotationLeavesTheGrantOpenableByTheManagerAlone(t *testing.T) { held, ctx := fresh(t) managerPub, managerPriv, _, _, keys := aRefreshableLicence(t, held, ctx, &fakeRefresher{}) before := grantRow(t, held, ctx) if _, err := held.SubmitRefresh(ctx, "personal", "at-access", "", "", keys); err != nil { t.Fatal(err) } if grantRow(t, held, ctx) != before { t.Fatal("a submit with no rotation changed the stored refresh token") } sealed, _, ok, err := held.RefreshGrant(ctx, "personal") if err != nil || !ok { t.Fatalf("the grant is not stored: ok=%v err=%v", ok, err) } got := openAnon(t, sealed, managerPub, managerPriv) if string(got) != "rt-the-refresh-token" { t.Fatalf("the manager read back %q", got) } // A node that is not the manager cannot: the whole of "the manager node only". otherPub, otherPriv, _ := managerPair(t) if _, ok := tryOpenAnon(sealed, otherPub, otherPriv); ok { t.Fatal("a node that is not the manager opened the refresh token") } } // A submit that carries a rotated box replaces the stored one — and the control plane stored it // without opening it: only the manager node reads the rotated token back. func TestSubmitRefreshWithRotationReplacesTheBoxUnopened(t *testing.T) { held, ctx := fresh(t) managerPub, managerPriv, _, _, keys := aRefreshableLicence(t, held, ctx, &fakeRefresher{}) before := grantRow(t, held, ctx) // The manager node re-sealed the rotated refresh token to its own key; the control plane is handed // only this box. rotated, err := secrets.Seal(managerPub, []byte("rt-a-rotated-refresh-token")) if err != nil { t.Fatal(err) } if _, err := held.SubmitRefresh(ctx, "personal", "at-access", rotated, managerPub, keys); err != nil { t.Fatal(err) } if grantRow(t, held, ctx) == before { t.Fatal("the rotated refresh token did not replace the stored box") } sealed, _, ok, err := held.RefreshGrant(ctx, "personal") if err != nil || !ok { t.Fatalf("the rotated grant is not stored: ok=%v err=%v", ok, err) } got := openAnon(t, sealed, managerPub, managerPriv) if string(got) != "rt-a-rotated-refresh-token" { t.Fatalf("the stored grant opened to %q, not the rotated token", got) } } // A submit with an empty access token is refused before anything is sealed: publishing nothing while // reporting success is the failure this whole design refuses. func TestSubmitRefreshRefusesAnEmptyAccessToken(t *testing.T) { held, ctx := fresh(t) _, _, _, _, keys := aRefreshableLicence(t, held, ctx, &fakeRefresher{}) if _, err := held.SubmitRefresh(ctx, "personal", " ", "", "", keys); err == nil { t.Fatal("a refresh with no access token was published") } } // A static-key licence cannot have a refresh submitted for it: the carve-out never fires, so the // machinery that holds a token readably is unreachable. func TestSubmitRefreshRefusesAStaticKeyLicence(t *testing.T) { held, ctx := fresh(t) if err := held.Add(ctx, "plain", "anthropic-api-key", nil); err != nil { t.Fatal(err) } if err := held.Use(ctx, "plain", "workstation", "assistant"); err != nil { t.Fatal(err) } _, err := held.SubmitRefresh(ctx, "plain", "at-access", "", "", func(string) (string, error) { return ASealingKey(t), nil }) if err == nil { t.Fatal("a refresh was submitted for a static-key licence") } if !strings.Contains(err.Error(), "refreshable-grant") { t.Fatalf("the refusal does not name the shape: %v", err) } } // A refreshable licence with no manager named refuses a submit and says how to name one: a refresh // cannot be published for a licence no node is responsible for. func TestSubmitRefreshRefusesWithoutAManager(t *testing.T) { held, ctx := fresh(t) if err := held.Add(ctx, "personal", "anthropic", nil); err != nil { t.Fatal(err) } _, err := held.SubmitRefresh(ctx, "personal", "at-access", "", "", func(string) (string, error) { return "", nil }) if err == nil { t.Fatal("a refresh was submitted for a licence with no manager") } if !strings.Contains(err.Error(), "manager") { t.Fatalf("the refusal does not point at the missing manager: %v", err) } }