Prove Conn offers no Serve by reflection, and build its AC3 test account through ReadAccount (issue 1171, review round 1 findings 3 and 4)
This commit is contained in:
@@ -11,7 +11,10 @@ import (
|
|||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"crypto/x509/pkix"
|
"crypto/x509/pkix"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
"encoding/json"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -61,16 +64,34 @@ func selfSignedServer(t *testing.T) (url, fingerprint string) {
|
|||||||
return s.ClientURL(), fingerprint
|
return s.ClientURL(), fingerprint
|
||||||
}
|
}
|
||||||
|
|
||||||
func mailSenderAccount(url, fingerprint string) Account {
|
// mailSenderAccount is the account novox.mesh-mail.send would be delivered as, the module's own secret
|
||||||
return Account{URL: url, Fingerprint: fingerprint, Node: "novox", Module: "mesh-mail",
|
// broker-send: written to a file and read back through ReadAccount (1171/AC2), exactly as a process
|
||||||
User: "novox.mesh-mail.send", Password: "the-pw"}
|
// reads it, rather than built by hand.
|
||||||
|
func mailSenderAccount(t *testing.T, url, fingerprint string) Account {
|
||||||
|
t.Helper()
|
||||||
|
data, err := json.Marshal(map[string]any{
|
||||||
|
"url": url, "fingerprint": fingerprint, "node": "novox", "module": "mesh-mail",
|
||||||
|
"user": "novox.mesh-mail.send", "password": "the-pw",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
path := filepath.Join(t.TempDir(), "broker-send")
|
||||||
|
if err := os.WriteFile(path, data, 0o600); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
account, err := ReadAccount(path)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("ReadAccount on a well-formed file: %v", err)
|
||||||
|
}
|
||||||
|
return account
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1171/AC3: given a test bus with TLS and the account composed for novox.mesh-mail.send, when the package
|
// 1171/AC3: given a test bus with TLS and the account composed for novox.mesh-mail.send, when the package
|
||||||
// connects with the file, then it connects with the inbox prefix _INBOX.novox.mesh-mail.send.
|
// connects with the file, then it connects with the inbox prefix _INBOX.novox.mesh-mail.send.
|
||||||
func TestConnectPinsTheFingerprintAndSetsTheInboxPrefix(t *testing.T) {
|
func TestConnectPinsTheFingerprintAndSetsTheInboxPrefix(t *testing.T) {
|
||||||
url, fingerprint := selfSignedServer(t)
|
url, fingerprint := selfSignedServer(t)
|
||||||
account := mailSenderAccount(url, fingerprint)
|
account := mailSenderAccount(t, url, fingerprint)
|
||||||
conn, err := Connect(account)
|
conn, err := Connect(account)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("connecting with the right fingerprint was refused: %v", err)
|
t.Fatalf("connecting with the right fingerprint was refused: %v", err)
|
||||||
@@ -87,7 +108,7 @@ func TestConnectPinsTheFingerprintAndSetsTheInboxPrefix(t *testing.T) {
|
|||||||
// 1171/AC3: connecting with a fingerprint that is not the bus's own leaf certificate is refused.
|
// 1171/AC3: connecting with a fingerprint that is not the bus's own leaf certificate is refused.
|
||||||
func TestConnectRefusesTheWrongFingerprint(t *testing.T) {
|
func TestConnectRefusesTheWrongFingerprint(t *testing.T) {
|
||||||
url, _ := selfSignedServer(t)
|
url, _ := selfSignedServer(t)
|
||||||
account := mailSenderAccount(url, "sha256:0000000000000000000000000000000000000000000000000000000000000000")
|
account := mailSenderAccount(t, url, "sha256:0000000000000000000000000000000000000000000000000000000000000000")
|
||||||
if _, err := Connect(account); err == nil {
|
if _, err := Connect(account); err == nil {
|
||||||
t.Fatal("connecting with the wrong fingerprint was not refused")
|
t.Fatal("connecting with the wrong fingerprint was not refused")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package process
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/nats-io/nats.go"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 1171/AC3: it offers no Serve and no way to serve a tool — a process reaches the bus only as itself, and
|
||||||
|
// never answers a call. Checked by reflection over *Conn's whole method set and field list, so a later
|
||||||
|
// addition cannot bring one back without this test naming it.
|
||||||
|
func TestConnOffersNoServeAndExposesNoRawConnection(t *testing.T) {
|
||||||
|
ptrType := reflect.TypeOf(&Conn{})
|
||||||
|
for _, forbidden := range []string{"Serve", "ServeOn", "Handle", "Subscribe", "Respond", "Answer"} {
|
||||||
|
if _, ok := ptrType.MethodByName(forbidden); ok {
|
||||||
|
t.Errorf("*Conn has a method %s: a process offers no way to serve a tool", forbidden)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
natsConnType := reflect.TypeOf(&nats.Conn{})
|
||||||
|
structType := reflect.TypeOf(Conn{})
|
||||||
|
for i := 0; i < structType.NumField(); i++ {
|
||||||
|
f := structType.Field(i)
|
||||||
|
if f.IsExported() && (f.Type == natsConnType || f.Type == natsConnType.Elem()) {
|
||||||
|
t.Errorf("Conn exposes its raw connection through the exported field %s", f.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for i := 0; i < ptrType.NumMethod(); i++ {
|
||||||
|
m := ptrType.Method(i)
|
||||||
|
for o := 0; o < m.Type.NumOut(); o++ {
|
||||||
|
if m.Type.Out(o) == natsConnType || m.Type.Out(o) == natsConnType.Elem() {
|
||||||
|
t.Errorf("*Conn.%s returns the raw *nats.Conn", m.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user