103 lines
3.2 KiB
Go
103 lines
3.2 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"
|
|
)
|
|
|
|
// **On a real server, as composed** (novox/hq issue 365): a machine's runtime calls in its own name, and the
|
|
// server refuses it a call naming another — the grant, not the runtime, is what makes the caller a fact.
|
|
func TestAServerComposedFromTheGrantsRefusesACallNamingAnother(t *testing.T) {
|
|
hash, err := bcrypt.GenerateFromPassword([]byte("pw"), bcrypt.MinCost)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
ledger := Seat{Name: "issue-tracker", Scope: "mesh", Serves: []string{"open"}}
|
|
accounts, err := ComposeAccounts([]Principal{
|
|
{Kind: KindNodeTools, Node: "novox", Module: RuntimeModule, PasswordHash: string(hash),
|
|
Carries: []Declared{{Module: "mesh-issues", Holds: []Seat{ledger}}}},
|
|
{Kind: KindNodeTools, Node: "shanks", Module: RuntimeModule, PasswordHash: string(hash)},
|
|
})
|
|
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()
|
|
|
|
holder, err := nats.Connect(s.ClientURL(), nats.UserInfo("novox.node-tools", "pw"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer holder.Close()
|
|
heard := make(chan string, 4)
|
|
sub, err := holder.Subscribe("mesh.seat.issue-tracker.call.open.*", func(m *nats.Msg) {
|
|
heard <- m.Subject
|
|
_ = m.Respond([]byte(`{"result":{}}`))
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
_ = holder.Flush()
|
|
if !sub.IsValid() {
|
|
t.Fatal("the holder may not hear the caller-named calls to its seat")
|
|
}
|
|
|
|
refusals := make(chan error, 4)
|
|
caller, err := nats.Connect(s.ClientURL(), nats.UserInfo("shanks.node-tools", "pw"),
|
|
nats.CustomInboxPrefix("_INBOX.shanks.node-tools"),
|
|
nats.ErrorHandler(func(_ *nats.Conn, _ *nats.Subscription, err error) { refusals <- err }))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer caller.Close()
|
|
if _, err := caller.Request("mesh.seat.issue-tracker.call.open.shanks~node-tools", []byte(`{}`), 3*time.Second); err != nil {
|
|
t.Fatalf("a call in the caller's own name was not answered: %v", err)
|
|
}
|
|
if got := <-heard; got != "mesh.seat.issue-tracker.call.open.shanks~node-tools" {
|
|
t.Fatalf("heard %s", got)
|
|
}
|
|
if err := caller.Publish("mesh.seat.issue-tracker.call.open.novox~node-tools", []byte(`{}`)); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
_ = caller.Flush()
|
|
select {
|
|
case err := <-refusals:
|
|
if !errors.Is(err, nats.ErrPermissionViolation) {
|
|
t.Errorf("the server said %v, want a permissions violation", err)
|
|
}
|
|
case <-time.After(3 * time.Second):
|
|
t.Error("the server did not refuse a call naming another caller")
|
|
}
|
|
select {
|
|
case got := <-heard:
|
|
t.Errorf("a call naming another reached the holder: %s", got)
|
|
case <-time.After(200 * time.Millisecond):
|
|
}
|
|
}
|