The node composes again when the vault says a secret changed, so a rotated secret or credential reaches it at once (issue 1126, ADR 0547 §2)
mesh/delivery closed: a newer head of the same pull request
mesh/check failed: integration: meshbuildgo/cmd/mesh-build-go.TestIntegrationLevelRunsAgainstARealStoreAndBusAndLeavesNothing: result = &{Level:integr…
mesh/delivery closed: a newer head of the same pull request
mesh/check failed: integration: meshbuildgo/cmd/mesh-build-go.TestIntegrationLevelRunsAgainstARealStoreAndBusAndLeavesNothing: result = &{Level:integr…
This commit is contained in:
@@ -814,5 +814,7 @@ func selfComposer(ctx context.Context, session *link.Session, node string, say f
|
||||
// Its modules' own secrets, sealed by the vault to this machine's key (ADR 0550 §5).
|
||||
Own: func(ctx context.Context, args map[string]any) (json.RawMessage, error) {
|
||||
return session.AskVault(ctx, "own", args)
|
||||
}})
|
||||
},
|
||||
// And the vault's word that a secret changed, on which it composes again (ADR 0547 §2).
|
||||
Hear: session.Hear})
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ module github.com/novox/mesh-host
|
||||
go 1.26.0
|
||||
|
||||
require (
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261026182306-944a35d200c9
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261026182519-53c2def1a520
|
||||
github.com/nats-io/nats-server/v2 v2.11.17
|
||||
github.com/nats-io/nats.go v1.54.0
|
||||
golang.org/x/crypto v0.57.0
|
||||
|
||||
@@ -14,6 +14,8 @@ git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261026181846-91413de33516 h1:xbbss6kQ
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261026181846-91413de33516/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261026182306-944a35d200c9 h1:ls5Jwxw4CZ9aPVhjQm9/qM88erjUU0ENRWajhD7lfb0=
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261026182306-944a35d200c9/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261026182519-53c2def1a520 h1:twiziR88X6ttKmw5JTd3aW6xb5bMZZ3Bl7WS2QOP3PE=
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261026182519-53c2def1a520/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
|
||||
github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op h1:Z/MZK75wC/NSrkgqeNIa7jexam9uWzhLmFTSCPI/kn0=
|
||||
github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op/go.mod h1:FQyySiasQQM8735Ddel3MRojmy4dA1IqCeyJ5jmPMbI=
|
||||
github.com/google/go-tpm v0.9.8 h1:slArAR9Ft+1ybZu0lBwpSmpwhRXaa85hWtMinMyRAWo=
|
||||
|
||||
@@ -42,8 +42,14 @@ type Env struct {
|
||||
// Own asks the vault's `own` in this node's engine's name, with the arguments given: its modules' own secrets and the
|
||||
// pair credentials asked, sealed to its key (ADR 0550 §5). Nil asks nothing, and a module with either does not compose.
|
||||
Own func(ctx context.Context, args map[string]any) (json.RawMessage, error)
|
||||
// Hear subscribes a subject: here the vault's word that a secret changed (VaultSecretChanged), on which the node
|
||||
// composes again, so a rotated secret or credential reaches it at once (ADR 0547 §2). Nil hears nothing.
|
||||
Hear func(subject string) (<-chan []byte, func(), error)
|
||||
}
|
||||
|
||||
// VaultSecretChanged is the vault's event that a secret changed: a name and its generation, never a value.
|
||||
const VaultSecretChanged = "mesh.mod.mesh-vault.event.secret-changed"
|
||||
|
||||
// Composer composes the node and is the agent's watcher of its compositions (agent.Env.Composed).
|
||||
type Composer struct {
|
||||
env Env
|
||||
@@ -128,6 +134,30 @@ func (c *Composer) Watch(ctx context.Context, _ string) (<-chan agent.Update, er
|
||||
}
|
||||
}(i, ch)
|
||||
}
|
||||
if c.env.Hear != nil {
|
||||
heard, stop, err := c.env.Hear(VaultSecretChanged)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("the node composes again when a secret changes, and cannot hear the vault say so: %w", err)
|
||||
}
|
||||
go func() {
|
||||
defer stop()
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case _, ok := <-heard:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
select {
|
||||
case merged <- tagged{in: -1, ok: true}:
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
out := make(chan agent.Update, 64)
|
||||
go func() {
|
||||
defer close(out)
|
||||
@@ -144,9 +174,12 @@ func (c *Composer) Watch(ctx context.Context, _ string) (<-chan agent.Update, er
|
||||
c.env.Say(fmt.Sprintf("the watch of %s ended; the node composes no more until its agent starts again", ins[t.in].bucket))
|
||||
return
|
||||
}
|
||||
if t.u.Caught {
|
||||
switch {
|
||||
case t.in < 0:
|
||||
dirty = true // a secret changed: its new generation is asked of the vault at the compose
|
||||
case t.u.Caught:
|
||||
caught[t.in] = true
|
||||
} else {
|
||||
default:
|
||||
ins[t.in].take(c, t.u)
|
||||
dirty = true
|
||||
}
|
||||
|
||||
@@ -97,6 +97,13 @@ func TestTheNodeComposesItsWantsFromTheBus(t *testing.T) {
|
||||
return json.RawMessage(fmt.Sprintf(`{"node":"n1","key":"sk","own":[{"module":"keeper","name":"password","origin":"made",`+
|
||||
`"generation":%d,"sealed":{"ask":%d}}]}`, generation+1, asks)), nil
|
||||
}
|
||||
secretChanged := make(chan []byte, 1)
|
||||
env.Hear = func(subject string) (<-chan []byte, func(), error) {
|
||||
if subject != VaultSecretChanged {
|
||||
t.Errorf("heard %s", subject)
|
||||
}
|
||||
return secretChanged, func() {}, nil
|
||||
}
|
||||
c := New(env)
|
||||
out, err := c.Watch(ctx, "n1.>")
|
||||
if err != nil {
|
||||
@@ -205,7 +212,8 @@ func TestTheNodeComposesItsWantsFromTheBus(t *testing.T) {
|
||||
b.mu.Lock()
|
||||
generation++
|
||||
b.mu.Unlock()
|
||||
b.put(t, ResolvedBucket, "n1.other.k", []byte(`{"value":3}`))
|
||||
// The vault says the secret changed: the node composes again on that word, with no other input moving.
|
||||
secretChanged <- []byte(`{"name":"own/n1/keeper/password","generation":2}`)
|
||||
if u := next(t, out); u.Key != keeperKey {
|
||||
t.Fatalf("a new generation handed %s, want keeper again", u.Key)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user