M-8: current answers the licence and its health, never the token

The vault hands every token (ADR 0550 §3); current names the licence, its key, kind,
generation, health and access expiry, and keeps the account's identity for the agent's
account file. bindings takes an optional consumer, answered unpaged.

Builds: design 39 bus-and-switch §18, B7, B10, B19

Claude-Session: https://claude.ai/code/session_01NcbgfHb9d4T9nq5Q6WqdiJ
This commit is contained in:
2026-11-11 23:11:09 +01:00
parent 4179be7a56
commit f29a9ad563
3 changed files with 69 additions and 48 deletions
@@ -259,8 +259,12 @@ func tools() []stdio.Tool {
return []stdio.Tool{
verb("licences", "Every licence the manager holds — account, kind, when its token and its refresh token expire, failures in a row, which consumers are bound to it. Never a token.",
nil, func(ctx context.Context, m *Manager, _ map[string]any) (any, error) { return m.Licences(ctx) }),
verb("bindings", "Which licence each consumer (a node's agent, by the node's name) is bound to, and the generation it was last given.",
nil, func(ctx context.Context, m *Manager, _ map[string]any) (any, error) { return m.Store.Bindings(ctx) }),
verb("bindings", "Which licence each consumer (a node's agent, by the node's name) is bound to, and the generation it was last given; with consumer, that consumer's alone.",
map[string]any{"consumer": str("a consumer; absent for every one")},
func(ctx context.Context, m *Manager, a map[string]any) (any, error) {
c, _ := a["consumer"].(string)
return m.BindingsOf(ctx, strings.TrimSpace(c))
}),
verb("bind", "Bind a consumer — a node's agent, by the node's name — to a licence. Its node fetches the licence's token at once.",
map[string]any{"consumer": consumer, "licence": str("a licence, as `licences` names it")},
func(ctx context.Context, m *Manager, a map[string]any) (any, error) {
@@ -334,14 +338,14 @@ func tools() []stdio.Tool {
nil, func(_ context.Context, m *Manager, _ map[string]any) (any, error) {
return map[string]any{"public_key": m.Keys.PublicKey}, nil
}),
verb("current", "For a consumer's agent module (ADR 0206): its token, sealed to the public key it sends, with the licence, kind and generation. Null when it is bound to nothing.",
map[string]any{"consumer": consumer, "public_key": str("the consumer's public key, PEM")},
verb("current", "For a consumer's agent module: which licence it is bound to, the licence's key, kind and generation, its health (ok, failing or expiring) and when its access token expires; never the token, which the vault hands. Null when it is bound to nothing.",
map[string]any{"consumer": consumer},
func(ctx context.Context, m *Manager, a map[string]any) (any, error) {
c, k, err := two(a, "consumer", "public_key")
c, err := text(a, "consumer")
if err != nil {
return nil, err
}
return m.Current(ctx, c, k)
return m.Current(ctx, c)
}),
}
}
@@ -636,47 +636,57 @@ func (m *Manager) ReadUsage(ctx context.Context) error {
// ---- the seat's verbs --------------------------------------------------------------------------------
// Current is a consumer's token sealed to the key it sent (ADR 0206 §6): for a subscription the access
// token and its expiries only — never the refresh token, which no node holds. Nil when it is bound to
// Current is which licence a consumer is bound to and its health, never the token (design 39 bus-and-switch §18, B7,
// B19): the licence, its key (the name of its secrets in the vault), kind, generation, health and accessExpiresAt, and
// for a subscription the account's identity the agent module points its account file at. Nil when it is bound to
// nothing.
func (m *Manager) Current(ctx context.Context, consumer, publicKey string) (map[string]any, error) {
if !strings.Contains(publicKey, "PUBLIC KEY") {
return nil, errors.New("current seals to the consumer's public key, and none was given")
}
func (m *Manager) Current(ctx context.Context, consumer string) (map[string]any, error) {
b, err := m.Store.Binding(ctx, consumer)
if err != nil || b == nil {
return nil, err
}
l, err := m.Store.Licence(ctx, b.Licence)
if err != nil || l == nil || l.Sealed == "" {
if err != nil || l == nil {
return nil, err
}
plain, err := m.Crypt.Open(l.Sealed)
if err != nil {
return nil, err
out := map[string]any{"licence": l.Name, "key": KeyFor(l.Name), "kind": l.Kind, "generation": b.Generation,
"health": Health(*l, m.Now(), m.Settings)}
if l.AccessExpiresAt != 0 {
out["accessExpiresAt"] = time.UnixMilli(l.AccessExpiresAt).UTC().Format(time.RFC3339)
}
handed := plain
if l.Kind == "subscription" {
var g FullGrant
if err := json.Unmarshal([]byte(plain), &g); err != nil {
return nil, err
}
access, _ := json.Marshal(map[string]any{"accessToken": g.AccessToken, "expiresAt": g.ExpiresAt,
"refreshTokenExpiresAt": g.RefreshTokenExpiresAt, "scopes": g.Scopes,
"subscriptionType": g.SubscriptionType, "rateLimitTier": g.RateLimitTier})
handed = string(access)
}
box, err := Seal(handed, publicKey)
if err != nil {
return nil, err
}
out := map[string]any{"licence": l.Name, "kind": l.Kind, "generation": b.Generation, "sealed": box}
if l.AccountUUID != "" {
out["identity"] = Identity{AccountUUID: l.AccountUUID, EmailAddress: l.Email, OrganizationUUID: l.OrganizationUUID}
}
return out, nil
}
// Health is a licence's health (B19): `failing` once its refresh failed failures_to_notify times in a row, `expiring`
// when its refresh token expires within refresh_warn_days, else `ok`.
func Health(l Licence, now time.Time, s Settings) string {
switch {
case l.Failures >= s.FailuresToNotify:
return "failing"
case l.RefreshExpiresAt != 0 && l.RefreshExpiresAt-now.UnixMilli() < s.RefreshWarn.Milliseconds():
return "expiring"
}
return "ok"
}
// BindingsOf is every binding, or the one of consumer when one is named (B10): a list either way, unpaged.
func (m *Manager) BindingsOf(ctx context.Context, consumer string) ([]Binding, error) {
all, err := m.Store.Bindings(ctx)
if err != nil || consumer == "" {
return all, err
}
out := []Binding{}
for _, b := range all {
if b.Consumer == consumer {
out = append(out, b)
}
}
return out, nil
}
// Bind binds or switches a consumer: a person's act (ADR 0183), told to the consumer as a new generation, and
// recorded with the cause ctx carries — the verb and its proven caller (novox/hq issue 625).
func (m *Manager) Bind(ctx context.Context, consumer, licence string) (map[string]any, error) {
@@ -253,32 +253,39 @@ func TestARotationAndASwitchEachGiveANewerGeneration(t *testing.T) {
}
}
func TestCurrentHandsAnAccessTokenOnlySealedToTheConsumersKey(t *testing.T) {
// design 39 bus-and-switch §18, B7, B19: no answer of current holds a token; it names the licence's key and health.
func TestCurrentHoldsNoToken(t *testing.T) {
mm := newMesh(t)
ctx := context.Background()
_, _ = mm.m.Consider(ctx, []Holdings{mm.login("laptop", "rt-a", true, t0)})
node, _ := GenerateKeyPair()
answer, err := mm.m.Current(ctx, "laptop", node.PublicKey)
if err != nil || answer["kind"] != "subscription" {
answer, err := mm.m.Current(ctx, "laptop")
if err != nil || answer["kind"] != "subscription" || answer["key"] != KeyFor(licence1) || answer["health"] != "ok" ||
answer["accessExpiresAt"] == nil || answer["identity"] == nil {
t.Fatalf("%v %v", answer, err)
}
box := answer["sealed"].(SealedBox)
plain, err := Open(box, node.PrivateKey)
if err != nil {
t.Fatal(err)
raw, _ := json.Marshal(answer)
for _, token := range []string{"rt-", "at-", "sealed"} {
if strings.Contains(string(raw), token) {
t.Fatalf("current answered %s: %s", token, raw)
}
}
var handed map[string]any
_ = json.Unmarshal([]byte(plain), &handed)
if !strings.HasPrefix(handed["accessToken"].(string), "at-") || handed["refreshToken"] != nil {
t.Fatalf("handed %v", handed)
l, _ := mm.store.Licence(ctx, licence1)
for failures, health := range map[int]string{0: "ok", 3: "failing"} {
l.Failures = failures
if got := Health(*l, mm.now, mm.m.Settings); got != health {
t.Errorf("%d failures: %s, want %s", failures, got, health)
}
}
other, _ := GenerateKeyPair()
if _, err := Open(box, other.PrivateKey); err == nil {
t.Fatal("the hand-over opened with another key")
l.Failures, l.RefreshExpiresAt = 0, mm.now.Add(48*time.Hour).UnixMilli()
if got := Health(*l, mm.now, mm.m.Settings); got != "expiring" {
t.Errorf("a refresh token expiring in two days: %s", got)
}
if a, _ := mm.m.Current(ctx, "nobody", node.PublicKey); a != nil {
if a, _ := mm.m.Current(ctx, "nobody"); a != nil {
t.Fatalf("a consumer bound to nothing was answered %v", a)
}
if bs, _ := mm.m.BindingsOf(ctx, "laptop"); len(bs) != 1 || bs[0].Consumer != "laptop" {
t.Fatalf("bindings of laptop: %v", bs)
}
}
func TestNothingTheManagerPublishesKeepsOrListsCarriesAToken(t *testing.T) {