test(client): secure bus end-to-end (auth + TLS + E2E together)
TestSecureBusEndToEnd boots the server with control-plane enforce, NATS nkey auth, and TLS all on; two registered peers connect with nkey+TLS, A creates a Matrix room, invites B, publishes, and B decrypts — proving the three layers compose. This is the headline golden of issue 0001. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -7,13 +7,16 @@ import (
|
|||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"crypto/x509/pkix"
|
"crypto/x509/pkix"
|
||||||
|
"encoding/hex"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"math/big"
|
"math/big"
|
||||||
"net"
|
"net"
|
||||||
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/enmanuel/unibus/pkg/client"
|
"github.com/enmanuel/unibus/pkg/client"
|
||||||
|
"github.com/enmanuel/unibus/pkg/frame"
|
||||||
"github.com/enmanuel/unibus/pkg/membership"
|
"github.com/enmanuel/unibus/pkg/membership"
|
||||||
"github.com/enmanuel/unibus/pkg/room"
|
"github.com/enmanuel/unibus/pkg/room"
|
||||||
)
|
)
|
||||||
@@ -111,3 +114,72 @@ func TestNatsTLS(t *testing.T) {
|
|||||||
t.Fatalf("client without the CA must fail the TLS handshake")
|
t.Fatalf("client without the CA must fail the TLS handshake")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestSecureBusEndToEnd is the headline golden of issue 0001: with ALL three
|
||||||
|
// layers active at once — control-plane request signing (enforce), NATS nkey
|
||||||
|
// auth, and TLS — two registered peers run an encrypted room end to end. A
|
||||||
|
// creates a Matrix-policy room, invites B, A publishes and B decrypts. This
|
||||||
|
// proves the layers compose: signed HTTP control plane + authenticated,
|
||||||
|
// encrypted data plane + E2E room content.
|
||||||
|
func TestSecureBusEndToEnd(t *testing.T) {
|
||||||
|
serverTLS, caPool := genTestCA(t)
|
||||||
|
h := bootHarness(t, membership.AuthEnforce, true, serverTLS)
|
||||||
|
waitHealth(t, h.ctrlURL)
|
||||||
|
|
||||||
|
clientTLS := &tls.Config{RootCAs: caPool, MinVersion: tls.VersionTLS12}
|
||||||
|
secure := func(t *testing.T, handle string) (*client.Client, membership.AuthMode) {
|
||||||
|
id := mustIdentity(t)
|
||||||
|
if err := h.store.AddUser(hex.EncodeToString(id.SignPub), handle, membership.RoleMember); err != nil {
|
||||||
|
t.Fatalf("register %s: %v", handle, err)
|
||||||
|
}
|
||||||
|
c, err := client.NewWithOptions(h.natsURL, h.ctrlURL, id, client.Options{UseNkey: true, TLS: clientTLS})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("connect %s securely: %v", handle, err)
|
||||||
|
}
|
||||||
|
return c, 0
|
||||||
|
}
|
||||||
|
|
||||||
|
a, _ := secure(t, "alice")
|
||||||
|
defer a.Close()
|
||||||
|
b, _ := secure(t, "bob")
|
||||||
|
defer b.Close()
|
||||||
|
|
||||||
|
roomID, err := a.CreateRoom("room.secure", room.ModeMatrix)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("A create encrypted room over secure bus: %v", err)
|
||||||
|
}
|
||||||
|
if err := a.Invite(roomID, b.Endpoint()); err != nil {
|
||||||
|
t.Fatalf("A invite B: %v", err)
|
||||||
|
}
|
||||||
|
if err := b.Join(roomID); err != nil {
|
||||||
|
t.Fatalf("B join: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var mu sync.Mutex
|
||||||
|
var got []string
|
||||||
|
sub, err := b.Subscribe(roomID, func(_ frame.Frame, plaintext []byte) {
|
||||||
|
mu.Lock()
|
||||||
|
got = append(got, string(plaintext))
|
||||||
|
mu.Unlock()
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("B subscribe: %v", err)
|
||||||
|
}
|
||||||
|
defer sub.Unsubscribe()
|
||||||
|
time.Sleep(150 * time.Millisecond)
|
||||||
|
|
||||||
|
const msg = "mensaje sobre bus seguro (auth+TLS+E2E)"
|
||||||
|
if err := a.Publish(roomID, []byte(msg)); err != nil {
|
||||||
|
t.Fatalf("A publish: %v", err)
|
||||||
|
}
|
||||||
|
if !waitFor(&mu, &got, func(rs []string) bool {
|
||||||
|
for _, r := range rs {
|
||||||
|
if r == msg {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}, 2*time.Second) {
|
||||||
|
t.Fatalf("B did not receive/decrypt the message over the secured bus; got %v", snapshot(&mu, &got))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user