Files
mesh-controller/internal/broker/vault_calls_live_integration_test.go
T

131 lines
4.1 KiB
Go

//go:build integration
package broker
import (
"errors"
"os"
"path/filepath"
"testing"
"time"
"github.com/nats-io/nats-server/v2/server"
"github.com/nats-io/nats.go"
"golang.org/x/crypto/bcrypt"
)
func TestOnARealBusTheVaultsAccountIsAnsweredByTheDeskAndTheProviderAndNothingElse(t *testing.T) {
users, err := Users(vaultRecords())
if err != nil {
t.Fatal(err)
}
hash, err := bcrypt.GenerateFromPassword([]byte("pw"), bcrypt.MinCost)
if err != nil {
t.Fatal(err)
}
for i := range users {
users[i].PasswordHash = string(hash)
}
accounts, err := ComposeAccounts(users)
if err != nil {
t.Fatal(err)
}
conf := filepath.Join(t.TempDir(), "bus.conf")
if err := os.WriteFile(conf, []byte("listen: 127.0.0.1:-1\njetstream { store_dir: "+
`"`+t.TempDir()+`"`+" }\n"+accounts), 0o600); err != nil {
t.Fatal(err)
}
opts, err := server.ProcessConfigFile(conf)
if err != nil {
t.Fatalf("the composed accounts do not parse: %v", err)
}
opts.NoLog, opts.NoSigs = true, true
s, err := server.NewServer(opts)
if err != nil {
t.Fatal(err)
}
go s.Start()
if !s.ReadyForConnections(10 * time.Second) {
t.Fatal("the bus did not come up")
}
defer s.Shutdown()
// anchor's runtime serves the desk's prompt and plex's issuing tool, on every subject it is granted, and says
// which subject it heard.
holder, err := nats.Connect(s.ClientURL(), nats.UserInfo("anchor.node-tools", "pw"))
if err != nil {
t.Fatal(err)
}
defer holder.Close()
heard := make(chan string, 8)
answer := func(m *nats.Msg) {
heard <- m.Subject
_ = m.Respond([]byte(`{"result":{"sealed":"c2VhbGVkLXRvLXRoZS1jYWxs"}}`))
}
for _, subject := range []string{"mesh.seat.node-launcher.call.secret.anchor.*",
"mesh.seat.node-launcher.tool.secret.anchor", "mesh.mod.plex.call.plex_issued_credential.anchor.*",
"mesh.mod.other.call.tool.anchor.*", "mesh.seat.node-launcher.call.menu.anchor.*"} {
sub, err := holder.Subscribe(subject, answer)
if err != nil {
t.Fatal(err)
}
_ = holder.Flush()
if !sub.IsValid() {
t.Fatalf("the desk's runtime may not hear %s", subject)
}
}
refusals := make(chan error, 16)
vault, err := nats.Connect(s.ClientURL(), nats.UserInfo("novox.mesh-vault", "pw"),
nats.CustomInboxPrefix("_INBOX.novox.mesh-vault"),
nats.ErrorHandler(func(_ *nats.Conn, _ *nats.Subscription, err error) { refusals <- err }))
if err != nil {
t.Fatalf("the vault's own account cannot connect: %v", err)
}
defer vault.Close()
token := CallerToken("novox.mesh-vault")
for _, subject := range []string{"mesh.seat.node-launcher.call.secret.anchor." + token,
"mesh.mod.plex.call.plex_issued_credential.anchor." + token} {
if _, err := vault.Request(subject, []byte(`{"seal_to":"a2V5LW9mLXRoZS1jYWxs"}`), 3*time.Second); err != nil {
t.Fatalf("the vault's call %s was not answered: %v", subject, err)
}
if got := <-heard; got != subject {
t.Fatalf("the holder heard %s, want %s", got, subject)
}
}
for _, subject := range []string{"mesh.seat.node-launcher.tool.secret.anchor",
"mesh.seat.node-launcher.call.secret.anchor.controller",
"mesh.seat.node-launcher.call.menu.anchor." + token,
"mesh.mod.other.call.tool.anchor." + token} {
if err := vault.Publish(subject, []byte(`{}`)); err != nil {
t.Fatal(err)
}
_ = vault.Flush()
select {
case err := <-refusals:
if !errors.Is(err, nats.ErrPermissionViolation) {
t.Errorf("%s: the server said %v, want a permissions violation", subject, err)
}
case <-time.After(3 * time.Second):
t.Errorf("the server did not refuse the vault %s", subject)
}
}
select {
case got := <-heard:
t.Errorf("a call the vault may not make reached the holder: %s", got)
case <-time.After(200 * time.Millisecond):
}
// The controller is still answered on today's path, for the modules filled the old way (until R1).
controller, err := nats.Connect(s.ClientURL(), nats.UserInfo("controller", "pw"),
nats.CustomInboxPrefix("_INBOX.controller"))
if err != nil {
t.Fatal(err)
}
defer controller.Close()
if _, err := controller.Request("mesh.seat.node-launcher.tool.secret.anchor", []byte(`{}`), 3*time.Second); err != nil {
t.Errorf("the controller's call to the desk on today's path: %v", err)
}
<-heard
}