//go:build integration package main import ( "slices" "strings" "testing" "github.com/novox/mesh-controller/internal/broker" "github.com/novox/mesh-controller/internal/catalogue" "github.com/novox/mesh-controller/internal/inventory" ) func TestTheProvisionerClientsAccountIsIssuedForItsServiceAndNeverInvented(t *testing.T) { open := aMesh(t) ctx := t.Context() inv := open.inventory m := aProvisioner() register(t, open, m) if _, err := assign(ctx, open, "laptop", m.Module); err != nil { t.Fatal(err) } if err := busCredentialIssued(ctx, inv, "laptop", m.Module, broker.ProvisionerSecret); err == nil { t.Fatal("a push would seal a placeholder for the client's account before it was issued") } if err := issueProvisionerClient(ctx, inv, m, "laptop", broker.Broker{Fingerprint: "ab"}, "10.0.0.1:4222"); err != nil { t.Fatal(err) } if _, minted, err := inv.BusUserHash(ctx, "provisioner.laptop"); err != nil || !minted { t.Fatalf("the client's account is not minted: %v %v", minted, err) } states, err := inv.SecretsOf(ctx, "laptop", m.Module) if err != nil { t.Fatal(err) } if !slices.ContainsFunc(states, func(s inventory.SecretState) bool { return s.Name == broker.ProvisionerSecret }) { t.Fatalf("the client's account is not sealed to the machine for its service: %+v", states) } if err := busCredentialIssued(ctx, inv, "laptop", m.Module, broker.ProvisionerSecret); err != nil { t.Fatalf("an issued client account is refused: %v", err) } if !runsTheProvisionerClient(m) { t.Fatal("the module is not read as running the client") } unread := m unread.OwnSecrets = catalogue.OwnSecrets{"broker": {Path: "/run/broker"}} if runsTheProvisionerClient(unread) { t.Fatal("a module with nowhere to read the client's account is read as running it") } } func TestAssigningTheClientIssuesItsAccount(t *testing.T) { open := aMesh(t) ctx := t.Context() client := aClientModule() register(t, open, client) out, err := assign(ctx, open, "laptop", client.Module) if err != nil { t.Fatal(err) } if !strings.Contains(out, "bus credential") { t.Fatalf("assigning the client said nothing of its account:\n%s", out) } } // A module that runs the client and declares no broker of its own, as the catalogue's mesh-provisioner-client does, // may be issued: the client's account alone (issue 917). Before, `module issue` refused it for having no broker, // while a push refused it for having no account, so no machine could run the client. func TestAClientWithoutABrokerOfItsOwnMayBeIssued(t *testing.T) { if err := mayIssue(aClientModule()); err != nil { t.Fatalf("the client alone is refused an account: %v", err) } neither := aBot("bot", false) if err := mayIssue(neither); err == nil { t.Fatal("a module with nowhere to read any account may be issued one") } }