Files
orca/internal/transport/mtls_test.go
T
Jon Chery d9d0beda3b test(P03): coverage uplift — engine/transport/proxmox/audit ≥50% + dispatch.go EOF fix (REQ-055)
94 new tests across 4 packages. Coverage: engine 8.3%→65.1%, transport
26.3%→84.6%, proxmox 5.1%→82.7%, audit 0%→100%. Bug fix: dispatch.go
bytesReadCloser.Read returned fmt.Errorf("EOF") instead of io.EOF —
broke HTTP request body transmission (latent since v0.2 P02).

---ci---
project: orca
phase: 3
milestone: v0.7
status: verify
requirements:
  covered: [REQ-055]
  partial: []
---/ci---
2026-08-04 00:18:58 +00:00

224 lines
6.1 KiB
Go

package transport
import (
"crypto/tls"
"crypto/x509"
"encoding/pem"
"os"
"path/filepath"
"testing"
"git.cloudinit.dev/coreci/orca/internal/security"
)
func generateTestCerts(t *testing.T, dir, serverName string) (certPath, keyPath, caPath string) {
t.Helper()
ca, err := security.CAInit(dir, "orca-test-ca")
if err != nil {
t.Fatalf("CAInit: %v", err)
}
keyPEM, csrPEM, err := security.GenerateCSR(serverName, []string{serverName, "127.0.0.1"})
if err != nil {
t.Fatalf("GenerateCSR: %v", err)
}
signedPEM, err := ca.SignCSR(csrPEM)
if err != nil {
t.Fatalf("SignCSR: %v", err)
}
certPath = filepath.Join(dir, "server.crt")
keyPath = filepath.Join(dir, "server.key")
caPath = filepath.Join(dir, security.CACertFile)
if err := os.WriteFile(certPath, signedPEM, 0o644); err != nil {
t.Fatalf("write cert: %v", err)
}
if err := os.WriteFile(keyPath, keyPEM, 0o600); err != nil {
t.Fatalf("write key: %v", err)
}
return certPath, keyPath, caPath
}
func TestServerTLSConfig(t *testing.T) {
dir := t.TempDir()
certPath, keyPath, caPath := generateTestCerts(t, dir, "localhost")
cfg, err := security.ServerTLSConfig(certPath, keyPath, caPath)
if err != nil {
t.Fatalf("ServerTLSConfig: %v", err)
}
if cfg.MinVersion != tls.VersionTLS13 {
t.Errorf("MinVersion = %d, want %d", cfg.MinVersion, tls.VersionTLS13)
}
if cfg.MaxVersion != tls.VersionTLS13 {
t.Errorf("MaxVersion = %d, want %d", cfg.MaxVersion, tls.VersionTLS13)
}
if cfg.ClientAuth != tls.RequireAndVerifyClientCert {
t.Errorf("ClientAuth = %v, want RequireAndVerifyClientCert", cfg.ClientAuth)
}
if cfg.ClientCAs == nil {
t.Error("ClientCAs is nil")
}
if len(cfg.CipherSuites) == 0 {
t.Error("CipherSuites is empty")
}
}
func TestServerTLSConfig_MissingFiles(t *testing.T) {
dir := t.TempDir()
_, err := security.ServerTLSConfig(
filepath.Join(dir, "nope.crt"),
filepath.Join(dir, "nope.key"),
filepath.Join(dir, "nope.ca"),
)
if err == nil {
t.Fatal("expected error for missing files")
}
}
func TestClientTLSConfig(t *testing.T) {
dir := t.TempDir()
certPath, keyPath, caPath := generateTestCerts(t, dir, "localhost")
cfg, err := security.ClientTLSConfig(caPath, "localhost", certPath, keyPath)
if err != nil {
t.Fatalf("ClientTLSConfig: %v", err)
}
if cfg.MinVersion != tls.VersionTLS13 {
t.Errorf("MinVersion = %d, want %d", cfg.MinVersion, tls.VersionTLS13)
}
if cfg.RootCAs == nil {
t.Error("RootCAs is nil")
}
if cfg.ServerName != "localhost" {
t.Errorf("ServerName = %q, want localhost", cfg.ServerName)
}
if len(cfg.Certificates) != 1 {
t.Errorf("Certificates len = %d, want 1", len(cfg.Certificates))
}
}
func TestClientTLSConfig_NoClientCert(t *testing.T) {
dir := t.TempDir()
_, _, caPath := generateTestCerts(t, dir, "localhost")
cfg, err := security.ClientTLSConfig(caPath, "localhost", "", "")
if err != nil {
t.Fatalf("ClientTLSConfig: %v", err)
}
if len(cfg.Certificates) != 0 {
t.Errorf("Certificates len = %d, want 0", len(cfg.Certificates))
}
}
func TestClientTLSConfig_MismatchedCertKey(t *testing.T) {
dir := t.TempDir()
_, _, caPath := generateTestCerts(t, dir, "localhost")
if _, err := security.ClientTLSConfig(caPath, "localhost", "only-cert", ""); err == nil {
t.Error("expected error for cert without key")
}
if _, err := security.ClientTLSConfig(caPath, "localhost", "", "only-key"); err == nil {
t.Error("expected error for key without cert")
}
}
func TestNewMTLSClient(t *testing.T) {
dir := t.TempDir()
_, _, caPath := generateTestCerts(t, dir, "localhost")
c, err := NewMTLSClient(caPath, "localhost", "", "")
if err != nil {
t.Fatalf("NewMTLSClient: %v", err)
}
if c == nil {
t.Fatal("client is nil")
}
}
func TestNewMTLSClient_EmptyCAPath(t *testing.T) {
_, err := NewMTLSClient("", "localhost", "", "")
if err == nil {
t.Fatal("expected error for empty caPath")
}
}
func TestNewMTLSClient_EmptyServerName(t *testing.T) {
dir := t.TempDir()
_, _, caPath := generateTestCerts(t, dir, "localhost")
_, err := NewMTLSClient(caPath, "", "", "")
if err == nil {
t.Fatal("expected error for empty serverName")
}
}
func TestNewMTLSClient_MissingCAFile(t *testing.T) {
_, err := NewMTLSClient("/nonexistent/ca.crt", "localhost", "", "")
if err == nil {
t.Fatal("expected error for missing CA file")
}
}
func TestMTLSClient_Do_NilReceiver(t *testing.T) {
var c *MTLSClient
_, err := c.Do(nil)
if err == nil {
t.Fatal("expected error for nil receiver")
}
}
func TestVerifyPeerCertificate_NoCerts(t *testing.T) {
cb := VerifyPeerCertificate("expected")
if err := cb(nil, nil); err == nil {
t.Error("expected error for no peer certs")
}
}
func TestVerifyPeerCertificate_Mismatch(t *testing.T) {
dir := t.TempDir()
certPath, _, _ := generateTestCerts(t, dir, "localhost")
certPEM, err := os.ReadFile(certPath)
if err != nil {
t.Fatalf("read cert: %v", err)
}
block, _ := pem.Decode(certPEM)
if block == nil {
t.Fatal("pem.Decode: no cert block")
}
cb := VerifyPeerCertificate("wrong-fingerprint")
if err := cb([][]byte{block.Bytes}, nil); err == nil {
t.Error("expected error for fingerprint mismatch")
}
}
func TestVerifyPeerCertificate_Match(t *testing.T) {
dir := t.TempDir()
certPath, _, _ := generateTestCerts(t, dir, "localhost")
certPEM, err := os.ReadFile(certPath)
if err != nil {
t.Fatalf("read cert: %v", err)
}
block, _ := pem.Decode(certPEM)
if block == nil {
t.Fatal("pem.Decode: no cert block")
}
leaf, err := x509.ParseCertificate(block.Bytes)
if err != nil {
t.Fatalf("ParseCertificate: %v", err)
}
expected := security.FingerprintOf(leaf.Raw)
cb := VerifyPeerCertificate(expected)
if err := cb([][]byte{block.Bytes}, nil); err != nil {
t.Errorf("expected match, got: %v", err)
}
}
func TestDialContext_EmptyCAPath(t *testing.T) {
_, err := DialContext(t.Context(), "tcp", "127.0.0.1:0", "", "localhost")
if err == nil {
t.Fatal("expected error for empty caPath")
}
}
func TestDialContext_ConnectionRefused(t *testing.T) {
dir := t.TempDir()
_, _, caPath := generateTestCerts(t, dir, "localhost")
_, err := DialContext(t.Context(), "tcp", "127.0.0.1:1", caPath, "localhost")
if err == nil {
t.Fatal("expected error for connection refused")
}
}