Merge branch 'b6/registry' into feat/registry-milestone

This commit is contained in:
2026-11-05 14:54:25 +01:00
50 changed files with 1097 additions and 1483 deletions
+3 -2
View File
@@ -280,7 +280,8 @@ func ownPackages(t *testing.T) map[string][]string {
}
// 1621/AC2 and AC4: the command imports, through every package of this repository it reaches, only the standard
// library, mesh-sdk and this repository's own packages, and none that reaches a bus, a store, a network service or
// library, mesh-sdk, the private network's overlay package (mesh-wireguard's own pure package: names, graph and
// generator, no bus) and this repository's own packages, and none that reaches a bus, a store, a network service or
// another process.
func TestTheCommandImportsNoBusStoreNetworkOrProcess(t *testing.T) {
forbidden := []string{"net/http", "net/rpc", "net/smtp", "os/exec", "database/sql", "plugin", "syscall"}
@@ -291,7 +292,7 @@ func TestTheCommandImportsNoBusStoreNetworkOrProcess(t *testing.T) {
for path, imports := range own {
for _, imp := range imports {
std := !strings.Contains(strings.SplitN(imp, "/", 2)[0], ".")
if !std && !strings.HasPrefix(imp, "git.novox.be/novox/mesh-sdk/go") && !strings.HasPrefix(imp, "github.com/novox/mesh-host/") {
if !std && !strings.HasPrefix(imp, "git.novox.be/novox/mesh-networking/modules/mesh-wireguard/go/overlay") && !strings.HasPrefix(imp, "git.novox.be/novox/mesh-sdk/go") && !strings.HasPrefix(imp, "github.com/novox/mesh-host/") {
t.Errorf("%s imports %s, which is neither the standard library, mesh-sdk nor this repository", path, imp)
}
for _, f := range forbidden {
+2 -2
View File
@@ -13,9 +13,9 @@ import (
"testing"
"time"
"git.novox.be/novox/mesh-contracts/go/seats/meshvault"
"git.novox.be/novox/mesh-contracts/identity-and-access/go/seats/meshvault"
"git.novox.be/novox/mesh-networking/modules/mesh-wireguard/go/overlay"
"git.novox.be/novox/mesh-sdk/go/delivery"
"git.novox.be/novox/mesh-sdk/go/overlay"
"github.com/novox/mesh-host/internal/identity"
)
+1 -1
View File
@@ -14,8 +14,8 @@ import (
"time"
nec "git.novox.be/novox/mesh-contracts/go/clients/nodeengineclient"
occ "git.novox.be/novox/mesh-contracts/go/clients/operatorchannelclient"
"git.novox.be/novox/mesh-contracts/go/seats/nodeengine"
occ "git.novox.be/novox/mesh-contracts/operator-and-conversation/go/clients/operatorchannelclient"
stdio "git.novox.be/novox/mesh-sdk/go"
"github.com/novox/mesh-host/internal/accounts"
"github.com/novox/mesh-host/internal/apply"
+2 -2
View File
@@ -8,8 +8,8 @@ import (
"testing"
"time"
occ "git.novox.be/novox/mesh-contracts/go/clients/operatorchannelclient"
oc "git.novox.be/novox/mesh-contracts/go/seats/operatorchannel"
occ "git.novox.be/novox/mesh-contracts/operator-and-conversation/go/clients/operatorchannelclient"
oc "git.novox.be/novox/mesh-contracts/operator-and-conversation/go/seats/operatorchannel"
"git.novox.be/novox/mesh-sdk/go/declaration"
"github.com/novox/mesh-host/internal/apply"
"github.com/novox/mesh-host/internal/link"
+4 -3
View File
@@ -6,6 +6,7 @@ import (
"encoding/json"
"errors"
"fmt"
"github.com/novox/mesh-host/internal/compositions"
"os"
"path/filepath"
"sort"
@@ -14,9 +15,9 @@ import (
"sync/atomic"
"time"
"git.novox.be/novox/mesh-networking/modules/mesh-wireguard/go/overlay"
"git.novox.be/novox/mesh-sdk/go/declaration"
"git.novox.be/novox/mesh-sdk/go/delivery"
"git.novox.be/novox/mesh-sdk/go/overlay"
"github.com/novox/mesh-host/internal/agent"
"github.com/novox/mesh-host/internal/apply"
"github.com/novox/mesh-host/internal/compose/frombus"
@@ -603,7 +604,7 @@ func nodeAgent(ctx context.Context, opts options, signer ed25519.PublicKey, trus
unseal: sealOpener(opts.state),
// And what each module's have says it runs sealed: after a restart the agent has applied nothing yet.
// A have the bus did not answer for is said as such, never as one holding no seals (issue 1126, 2026-10-28).
held: func(module string) (delivery.Seals, []string, error) {
held: func(module string) (compositions.Seals, []string, error) {
if module == agent.NodeModule {
got, _, err := session.ReadNodeHaveErr(linked)
return got.SealedAt, got.Sealed, err
@@ -985,7 +986,7 @@ type composerHooks struct {
unseal func(string) ([]byte, error)
refused func(why string, held map[string]string)
kept func(kept map[string][]string)
held func(module string) (delivery.Seals, []string, error)
held func(module string) (compositions.Seals, []string, error)
// vaultAuthority and certify are selfcompose.Env's VaultAuthority and Certify.
vaultAuthority func() string
certify func(ctx context.Context) error
@@ -1019,3 +1019,25 @@ func TestNatsANodeThatCannotReadTheSeatListActsOnNothingNew(t *testing.T) {
t.Errorf("web does not stay as it ran after a start with the seat gone: %q", b.file("web"))
}
}
// The first read of the seat list ends the wait whether or not it changed what the reader held: Start returns at once, and
// the node waits on the reader's Ready before it says the read is over (ADR 0636 §1).
func TestNatsTheFirstReadOfTheSeatListEndsTheNodesWait(t *testing.T) {
clock := &fiveMinutes{}
was := seatWaitClock
seatWaitClock = clock
t.Cleanup(func() { seatWaitClock = was })
b := newItBedAs(t, nodegrant.For(itNode, "it2.mailer.domain"))
stop, _ := h8(t, b, false)
defer stop()
within(t, 30*time.Second, "the node did not end its wait at the first read of the seat list", func() bool {
st := seatListNow.Load()
if st == nil {
return false
}
<-st.reader.Ready()
waiting, _ := st.waiter.Waiting()
return st.reader.Status().Heard && !waiting
})
}
+18 -5
View File
@@ -138,12 +138,13 @@ func (w findingsOfTheNode) Delete(f views.Finding) error {
// it holds again, saying so to the composer and to the waiter that writes the five-minute finding.
func startSeatList(ctx context.Context, session *link.Session, node string, say func(string)) (*seatListState, error) {
st := &seatListState{changed: make(chan struct{}, 1)}
var announce func()
// Start returns at once and reads the seat on a goroutine, which may announce a change before the waiter exists.
var announce atomic.Pointer[func()]
reader, err := seatlist.Start(seatlist.Config{Bus: sessionBus{ctx, session}, Bootstrap: seatlist.Bootstrapped(),
OnChange: func(seats []catalogue.Seat) {
catalogue.UseSeats(seats)
if announce != nil { // the first read happens inside Start, before the waiter exists
announce()
if f := announce.Load(); f != nil { // the first read may end before the waiter exists
(*f)()
}
}})
if err != nil {
@@ -152,15 +153,27 @@ func startSeatList(ctx context.Context, session *link.Session, node string, say
st.reader = reader
st.waiter = &seatwait.Waiter{Node: node, Observer: "node-engine", Reader: reader, Findings: findingsOfTheNode{session},
Clock: seatWaitClock, Say: say}
announce = func() {
told := func() {
st.waiter.Changed()
select {
case st.changed <- struct{}{}:
default:
}
}
announce.Store(&told)
catalogue.UseSeats(reader.Seats())
announce()
told()
// The first read ends whether the seat answered or not, and a read that held what the reader held already says no
// change: its end is told to the waiter and the composer, so a status that moved from reading to heard starts or ends
// the bound (ADR 0636 §1). Start's return held nobody's start.
go func() {
select {
case <-reader.Ready():
catalogue.UseSeats(reader.Seats())
told()
case <-ctx.Done():
}
}()
seatListNow.Store(st)
return st, nil
}
+2 -2
View File
@@ -13,9 +13,9 @@ import (
"sync"
"time"
"git.novox.be/novox/mesh-contracts/go/seats/meshvault"
"git.novox.be/novox/mesh-contracts/identity-and-access/go/seats/meshvault"
"git.novox.be/novox/mesh-networking/modules/mesh-wireguard/go/overlay"
"git.novox.be/novox/mesh-sdk/go/delivery"
"git.novox.be/novox/mesh-sdk/go/overlay"
"github.com/novox/mesh-host/internal/identity"
"github.com/novox/mesh-host/internal/link"
+1 -1
View File
@@ -10,9 +10,9 @@ import (
"strings"
"testing"
"git.novox.be/novox/mesh-networking/modules/mesh-wireguard/go/overlay"
"git.novox.be/novox/mesh-sdk/go/declaration"
"git.novox.be/novox/mesh-sdk/go/delivery"
"git.novox.be/novox/mesh-sdk/go/overlay"
"github.com/novox/mesh-host/internal/agent"
"github.com/novox/mesh-host/internal/liveness"