Files
mesh-controller/internal/inventory/core_box.go
T
mesh-tools 97a2d841c7 Land feature 57's controller work on its release branch
The controller plans config, templates and moved providers' provisions,
hands bus accounts to the vault and judges the new manifest words, on the
feature's SDK and node-engine validator (feature 57, config and provisioning).
2026-10-15 21:27:33 +00:00

66 lines
2.2 KiB
Go

package inventory
import (
"context"
"encoding/json"
"fmt"
"time"
)
// CoreBox is a core module's own credential as the vault sealed it to its machine (novox/hq ADR 0349 §16, issue 755):
// the vault's generation, the machine's sealing key it was sealed to, and the box. Never a value: the controller
// cannot open it.
type CoreBox struct {
Module string
Name string
Generation int
SealedTo string
Box json.RawMessage
GotAt time.Time
}
// KeptCoreBoxes is every box kept for a machine, by module and name.
func (i *Inventory) KeptCoreBoxes(ctx context.Context, node string) (map[string]map[string]CoreBox, error) {
rows, err := i.store.Pool().Query(ctx,
`select b.module, b.name, b.generation, b.sealed_to, b.box, b.got_at
from core_box b join node n on n.id = b.node where n.name = $1`, node)
if err != nil {
return nil, err
}
defer rows.Close()
out := map[string]map[string]CoreBox{}
for rows.Next() {
var b CoreBox
var box string
if err := rows.Scan(&b.Module, &b.Name, &b.Generation, &b.SealedTo, &box, &b.GotAt); err != nil {
return nil, err
}
b.Box = json.RawMessage(box)
if out[b.Module] == nil {
out[b.Module] = map[string]CoreBox{}
}
out[b.Module][b.Name] = b
}
return out, rows.Err()
}
// KeepCoreBox keeps the box the vault answered for one of a machine's core credentials, over the one kept before.
func (i *Inventory) KeepCoreBox(ctx context.Context, node string, b CoreBox) error {
if b.Generation <= 0 || b.SealedTo == "" || len(b.Box) == 0 || !json.Valid(b.Box) {
return fmt.Errorf("the vault's box for %s/%s on %s is not whole: nothing kept", b.Module, b.Name, node)
}
tag, err := i.store.Pool().Exec(ctx,
`insert into core_box (node, module, name, generation, sealed_to, box)
select n.id, $2, $3, $4, $5, $6 from node n where n.name = $1
on conflict (node, module, name) do update set generation = excluded.generation,
sealed_to = excluded.sealed_to, box = excluded.box, got_at = now()`,
node, b.Module, b.Name, b.Generation, b.SealedTo, string(b.Box))
if err != nil {
return err
}
if tag.RowsAffected() == 0 {
return fmt.Errorf("%w: %s", ErrNoSuchNode, node)
}
return nil
}