Files
rdp-proxy/backend/internal/modules/cluster/service_test.go
T
2026-04-28 22:29:50 +03:00

2506 lines
83 KiB
Go

package cluster
import (
"context"
"encoding/json"
"errors"
"strings"
"testing"
"time"
"github.com/example/remote-access-platform/backend/internal/platform/clusterauth"
"github.com/example/remote-access-platform/backend/internal/platform/secrets"
"github.com/jackc/pgx/v5"
)
func TestHashJoinTokenDoesNotStoreRawToken(t *testing.T) {
raw := "rap_join_example"
hashed, err := hashJoinToken(raw)
if err != nil {
t.Fatalf("hash join token: %v", err)
}
if hashed == raw {
t.Fatal("hash must not equal raw token")
}
if got, wantPrefix := hashed[:len(joinTokenHashPrefix)], joinTokenHashPrefix; got != wantPrefix {
t.Fatalf("hash prefix = %q, want %q", got, wantPrefix)
}
hashedAgain, err := hashJoinToken(raw)
if err != nil {
t.Fatalf("hash join token again: %v", err)
}
if hashed != hashedAgain {
t.Fatal("hash must be deterministic")
}
}
func TestClusterAuthorityPrivateKeyEncodingUsesSecretEncryptor(t *testing.T) {
encryptor, err := secrets.NewEncryptor("MDEyMzQ1Njc4OWFiY2RlZjAxMjM0NTY3ODlhYmNkZWY=", "test-key")
if err != nil {
t.Fatalf("NewEncryptor: %v", err)
}
store := (&PostgresStore{}).WithClusterKeyEncryptor(encryptor)
encoded, err := store.encodeClusterAuthorityPrivateKey("cluster-1", "private-key")
if err != nil {
t.Fatalf("encodeClusterAuthorityPrivateKey: %v", err)
}
if encoded == "private-key" || !strings.HasPrefix(encoded, encryptedClusterAuthorityKeyPrefix) {
t.Fatalf("private key was not encrypted: %q", encoded)
}
decoded, err := store.decodeClusterAuthorityPrivateKey("cluster-1", encoded)
if err != nil {
t.Fatalf("decodeClusterAuthorityPrivateKey: %v", err)
}
if decoded != "private-key" {
t.Fatalf("decoded private key = %q", decoded)
}
if _, err := store.decodeClusterAuthorityPrivateKey("cluster-2", encoded); err == nil {
t.Fatal("expected wrong cluster AAD to fail")
}
}
func TestCreateJoinTokenRequiresPlatformAdmin(t *testing.T) {
store := &fakeRepository{platformRole: "user"}
service := NewService(store)
_, err := service.CreateJoinToken(context.Background(), CreateJoinTokenInput{
ActorUserID: "user-1",
ClusterID: "cluster-1",
})
if !errors.Is(err, ErrAccessDenied) {
t.Fatalf("err = %v, want ErrAccessDenied", err)
}
}
func TestCreateJoinTokenStoresHashOnlyAndReturnsRawOnce(t *testing.T) {
store := &fakeRepository{platformRole: PlatformRoleAdmin}
service := NewService(store)
service.now = func() time.Time { return time.Date(2026, 4, 26, 12, 0, 0, 0, time.UTC) }
created, err := service.CreateJoinToken(context.Background(), CreateJoinTokenInput{
ActorUserID: "admin-1",
ClusterID: "cluster-1",
Scope: json.RawMessage(`{"roles":["rdp-worker"]}`),
MaxUses: 1,
})
if err != nil {
t.Fatalf("create join token: %v", err)
}
if created.Token == "" {
t.Fatal("raw token must be returned to caller once")
}
if store.lastTokenHash == "" || store.lastTokenHash == created.Token {
t.Fatalf("stored token hash = %q, raw token = %q", store.lastTokenHash, created.Token)
}
if created.AuthoritySignature == nil || len(created.AuthorityPayload) == 0 {
t.Fatalf("created token missing authority signature: %+v", created.NodeJoinToken)
}
if err := clusterauth.VerifyRaw(store.clusterAuthority.PublicKey, created.AuthorityPayload, *created.AuthoritySignature); err != nil {
t.Fatalf("verify token authority signature: %v", err)
}
}
func TestUpdateClusterRequiresMutableAuthority(t *testing.T) {
store := &fakeRepository{
platformRole: PlatformRoleAdmin,
authorityState: ClusterAuthorityState{
ClusterID: "cluster-1",
AuthorityState: "minority",
MutationMode: "read_only",
},
}
service := NewService(store)
_, err := service.UpdateCluster(context.Background(), UpdateClusterInput{
ActorUserID: "admin-1",
ClusterID: "cluster-1",
Name: "Cluster One",
Status: ClusterStatusActive,
Metadata: json.RawMessage(`{}`),
})
if !errors.Is(err, ErrClusterReadOnly) {
t.Fatalf("err = %v, want ErrClusterReadOnly", err)
}
}
func TestUpdateClusterValidatesStatusAndMetadata(t *testing.T) {
store := &fakeRepository{platformRole: PlatformRoleAdmin}
service := NewService(store)
_, err := service.UpdateCluster(context.Background(), UpdateClusterInput{
ActorUserID: "admin-1",
ClusterID: "cluster-1",
Name: "Cluster One",
Status: "unknown",
Metadata: json.RawMessage(`{}`),
})
if !errors.Is(err, ErrInvalidPayload) {
t.Fatalf("err = %v, want ErrInvalidPayload", err)
}
_, err = service.UpdateCluster(context.Background(), UpdateClusterInput{
ActorUserID: "admin-1",
ClusterID: "cluster-1",
Name: "Cluster One",
Status: ClusterStatusActive,
Metadata: json.RawMessage(`{`),
})
if err == nil || !strings.Contains(err.Error(), "metadata") {
t.Fatalf("err = %v, want metadata validation error", err)
}
}
func TestCreateNodeGroupValidatesNameAndMetadata(t *testing.T) {
store := &fakeRepository{platformRole: PlatformRoleAdmin}
service := NewService(store)
_, err := service.CreateNodeGroup(context.Background(), CreateNodeGroupInput{
ActorUserID: "admin-1",
ClusterID: "cluster-1",
Name: " ",
})
if !errors.Is(err, ErrInvalidPayload) {
t.Fatalf("err = %v, want ErrInvalidPayload", err)
}
_, err = service.CreateNodeGroup(context.Background(), CreateNodeGroupInput{
ActorUserID: "admin-1",
ClusterID: "cluster-1",
Name: "DC-1",
Metadata: json.RawMessage(`{`),
})
if err == nil || !strings.Contains(err.Error(), "metadata") {
t.Fatalf("err = %v, want metadata validation error", err)
}
}
func TestAssignNodeToGroupPreservesConcreteMembership(t *testing.T) {
groupID := "group-1"
store := &fakeRepository{platformRole: PlatformRoleAdmin}
service := NewService(store)
node, err := service.AssignNodeToGroup(context.Background(), AssignNodeGroupInput{
ActorUserID: "admin-1",
ClusterID: "cluster-1",
NodeID: "node-1",
GroupID: &groupID,
})
if err != nil {
t.Fatalf("assign node group: %v", err)
}
if node.ID != "node-1" || node.NodeGroupID == nil || *node.NodeGroupID != groupID {
t.Fatalf("unexpected node group assignment: %+v", node)
}
if store.lastAssignGroupInput.NodeID != "node-1" || store.lastAssignGroupInput.GroupID == nil {
t.Fatalf("assignment input not preserved: %+v", store.lastAssignGroupInput)
}
}
func TestCreateFabricEntryPointValidatesControlPlanePayload(t *testing.T) {
store := &fakeRepository{platformRole: PlatformRoleAdmin}
service := NewService(store)
_, err := service.CreateFabricEntryPoint(context.Background(), CreateFabricEntryPointInput{
ActorUserID: "admin-1",
ClusterID: "cluster-1",
Name: " ",
EndpointType: "client_access",
})
if !errors.Is(err, ErrInvalidPayload) {
t.Fatalf("err = %v, want ErrInvalidPayload", err)
}
_, err = service.CreateFabricEntryPoint(context.Background(), CreateFabricEntryPointInput{
ActorUserID: "admin-1",
ClusterID: "cluster-1",
Name: "Main Entry",
EndpointType: "client_access",
Policy: json.RawMessage(`{`),
})
if err == nil || !strings.Contains(err.Error(), "valid json") {
t.Fatalf("err = %v, want json validation error", err)
}
}
func TestCreateFabricEgressPoolDefaultsAndAudits(t *testing.T) {
store := &fakeRepository{platformRole: PlatformRoleAdmin}
service := NewService(store)
item, err := service.CreateFabricEgressPool(context.Background(), CreateFabricEgressPoolInput{
ActorUserID: "admin-1",
ClusterID: "cluster-1",
Name: "Office Moscow",
})
if err != nil {
t.Fatalf("create egress pool: %v", err)
}
if item.Status != "active" || string(item.RouteScope) != "{}" {
t.Fatalf("unexpected egress pool defaults: %+v", item)
}
if len(store.auditEvents) == 0 || store.auditEvents[len(store.auditEvents)-1].EventType != "fabric.egress_pool.created" {
t.Fatalf("missing egress pool audit event: %+v", store.auditEvents)
}
}
func TestAssignNodeRoleRejectsUnknownRole(t *testing.T) {
store := &fakeRepository{platformRole: PlatformRoleAdmin}
service := NewService(store)
_, err := service.AssignNodeRole(context.Background(), AssignNodeRoleInput{
ActorUserID: "admin-1",
ClusterID: "cluster-1",
NodeID: "node-1",
Role: "can_run_rdp_worker",
})
if !errors.Is(err, ErrInvalidNodeRole) {
t.Fatalf("err = %v, want ErrInvalidNodeRole", err)
}
}
func TestAttachExistingNodeRequiresPlatformAdmin(t *testing.T) {
store := &fakeRepository{platformRole: "user"}
service := NewService(store)
_, err := service.AttachExistingNodeToCluster(context.Background(), AttachExistingNodeInput{
ActorUserID: "user-1",
ClusterID: "cluster-1",
NodeID: "node-1",
})
if !errors.Is(err, ErrAccessDenied) {
t.Fatalf("err = %v, want ErrAccessDenied", err)
}
}
func TestAttachExistingNodeRejectsUnknownRole(t *testing.T) {
store := &fakeRepository{platformRole: PlatformRoleAdmin}
service := NewService(store)
_, err := service.AttachExistingNodeToCluster(context.Background(), AttachExistingNodeInput{
ActorUserID: "admin-1",
ClusterID: "cluster-1",
NodeID: "node-1",
Roles: []string{"can_run_rdp_worker"},
})
if !errors.Is(err, ErrInvalidNodeRole) {
t.Fatalf("err = %v, want ErrInvalidNodeRole", err)
}
}
func TestAttachExistingNodeUsesConcreteNodeAndRoles(t *testing.T) {
store := &fakeRepository{platformRole: PlatformRoleAdmin}
service := NewService(store)
node, err := service.AttachExistingNodeToCluster(context.Background(), AttachExistingNodeInput{
ActorUserID: "admin-1",
ClusterID: "cluster-1",
NodeID: "node-1",
Roles: []string{"entry-node", "rdp-worker"},
})
if err != nil {
t.Fatalf("attach existing node: %v", err)
}
if node.ID != "node-1" || node.MembershipStatus != "active" {
t.Fatalf("unexpected node: %+v", node)
}
if store.lastAttachInput.NodeID != "node-1" || len(store.lastAttachInput.Roles) != 2 {
t.Fatalf("attach input not preserved: %+v", store.lastAttachInput)
}
}
func TestCreateJoinRequestRejectsExpiredOrRevokedToken(t *testing.T) {
store := &fakeRepository{validTokenErr: ErrInvalidJoinToken}
service := NewService(store)
_, err := service.CreateJoinRequest(context.Background(), CreateJoinRequestInput{
ClusterID: "cluster-1",
JoinToken: "rap_join_invalid",
NodeName: "node-a",
NodeFingerprint: "fingerprint-a",
PublicKey: "public-key",
})
if !errors.Is(err, ErrInvalidJoinToken) {
t.Fatalf("err = %v, want ErrInvalidJoinToken", err)
}
}
func TestRevokeJoinTokenRequiresPlatformAdmin(t *testing.T) {
store := &fakeRepository{platformRole: "user"}
service := NewService(store)
_, err := service.RevokeJoinToken(context.Background(), RevokeJoinTokenInput{
ActorUserID: "user-1",
ClusterID: "cluster-1",
TokenID: "token-1",
})
if !errors.Is(err, ErrAccessDenied) {
t.Fatalf("err = %v, want ErrAccessDenied", err)
}
}
func TestApproveJoinRequestReturnsBootstrapContract(t *testing.T) {
store := &fakeRepository{platformRole: PlatformRoleAdmin}
service := NewService(store)
approved, err := service.ApproveJoinRequest(context.Background(), ApproveJoinRequestInput{
ActorUserID: "admin-1",
ClusterID: "cluster-1",
JoinRequestID: "join-request-1",
NodeKey: "node-key-1",
})
if err != nil {
t.Fatalf("approve join request: %v", err)
}
if approved.Bootstrap.ClusterID != "cluster-1" || approved.Bootstrap.IdentityStatus == "" {
t.Fatalf("unexpected bootstrap contract: %+v", approved.Bootstrap)
}
if approved.Bootstrap.ClusterAuthority == nil || approved.Bootstrap.AuthoritySignature == nil || len(approved.Bootstrap.AuthorityPayload) == 0 {
t.Fatalf("bootstrap missing authority contract: %+v", approved.Bootstrap)
}
if err := clusterauth.VerifyRaw(store.clusterAuthority.PublicKey, approved.Bootstrap.AuthorityPayload, *approved.Bootstrap.AuthoritySignature); err != nil {
t.Fatalf("verify approval authority signature: %v", err)
}
}
func TestGetJoinRequestBootstrapReturnsSignedApproval(t *testing.T) {
nodeID := "node-1"
store := &fakeRepository{
platformRole: PlatformRoleAdmin,
bootstrapJoinRequest: NodeJoinRequest{
ID: "join-request-1",
ClusterID: "cluster-1",
NodeFingerprint: "node-fp",
PublicKey: "node-public-key",
Status: JoinRequestStatusApproved,
ApprovedNodeID: &nodeID,
},
}
service := NewService(store)
result, err := service.GetJoinRequestBootstrap(context.Background(), GetJoinRequestBootstrapInput{
ClusterID: "cluster-1",
JoinRequestID: "join-request-1",
NodeFingerprint: "node-fp",
PublicKey: "node-public-key",
})
if err != nil {
t.Fatalf("get join request bootstrap: %v", err)
}
if result.Bootstrap == nil || result.Bootstrap.NodeID != nodeID || result.Bootstrap.ClusterAuthority == nil {
t.Fatalf("unexpected bootstrap result: %+v", result)
}
if result.Bootstrap.AuthoritySignature == nil || len(result.Bootstrap.AuthorityPayload) == 0 {
t.Fatalf("bootstrap missing authority signature: %+v", result.Bootstrap)
}
if err := clusterauth.VerifyRaw(store.clusterAuthority.PublicKey, result.Bootstrap.AuthorityPayload, *result.Bootstrap.AuthoritySignature); err != nil {
t.Fatalf("verify bootstrap authority signature: %v", err)
}
}
func TestSetDesiredWorkloadRequiresPlatformAdmin(t *testing.T) {
store := &fakeRepository{platformRole: "user"}
service := NewService(store)
_, err := service.SetDesiredWorkload(context.Background(), SetDesiredWorkloadInput{
ActorUserID: "user-1",
ClusterID: "cluster-1",
NodeID: "node-1",
ServiceType: "rdp-worker",
})
if !errors.Is(err, ErrAccessDenied) {
t.Fatalf("err = %v, want ErrAccessDenied", err)
}
}
func TestReportWorkloadStatusDefaultsToSafeStubState(t *testing.T) {
store := &fakeRepository{}
service := NewService(store)
status, err := service.ReportWorkloadStatus(context.Background(), ReportWorkloadStatusInput{
ClusterID: "cluster-1",
NodeID: "node-1",
ServiceType: "rdp-worker",
})
if err != nil {
t.Fatalf("report workload status: %v", err)
}
if status.ReportedState != "unknown" || status.RuntimeMode != "container" {
t.Fatalf("unexpected status defaults: %+v", status)
}
}
func TestReportMeshLinkDoesNotRequirePlatformAdmin(t *testing.T) {
store := &fakeRepository{}
service := NewService(store)
link, err := service.ReportMeshLink(context.Background(), ReportMeshLinkInput{
ClusterID: "cluster-1",
SourceNodeID: "node-a",
TargetNodeID: "node-b",
LinkStatus: "reachable",
})
if err != nil {
t.Fatalf("report mesh link: %v", err)
}
if link.LinkStatus != "reachable" {
t.Fatalf("LinkStatus = %q", link.LinkStatus)
}
}
func TestCreateRouteIntentRequiresPlatformAdmin(t *testing.T) {
store := &fakeRepository{platformRole: "user"}
service := NewService(store)
_, err := service.CreateRouteIntent(context.Background(), CreateRouteIntentInput{
ActorUserID: "user-1",
ClusterID: "cluster-1",
ServiceClass: "input",
})
if !errors.Is(err, ErrAccessDenied) {
t.Fatalf("err = %v, want ErrAccessDenied", err)
}
}
func TestGetNodeSyntheticMeshConfigRequiresTestingFlag(t *testing.T) {
service := NewService(&fakeRepository{})
cfg, err := service.GetNodeSyntheticMeshConfig(context.Background(), GetNodeSyntheticMeshConfigInput{
ClusterID: "cluster-1",
NodeID: "node-a",
})
if err != nil {
t.Fatalf("get synthetic config: %v", err)
}
if cfg.Enabled {
t.Fatal("config must be disabled when synthetic testing flag is off")
}
if len(cfg.Routes) != 0 || len(cfg.PeerEndpoints) != 0 {
t.Fatalf("disabled config must not leak topology: %+v", cfg)
}
}
func TestGetNodeSyntheticMeshConfigIsNodeScoped(t *testing.T) {
now := time.Date(2026, 4, 27, 12, 0, 0, 0, time.UTC)
service := NewService(&fakeRepository{
testingFlags: EffectiveNodeTestingFlags{
Enabled: true,
SyntheticLinksEnabled: true,
},
routeIntents: []MeshRouteIntent{
{
ID: "route-a-b",
ClusterID: "cluster-1",
SourceSelector: json.RawMessage(`{"node_id":"node-a"}`),
DestinationSelector: json.RawMessage(`{"node_id":"node-b"}`),
ServiceClass: "synthetic",
Status: "active",
Policy: json.RawMessage(`{
"synthetic_enabled": true,
"hops": ["node-a", "node-r", "node-b"],
"allowed_channels": ["fabric_control", "route_control"],
"peer_endpoints": {
"node-r": "http://node-r:19000",
"node-b": "http://node-b:19000",
"node-y": "http://node-y:19000"
},
"peer_endpoint_candidates": {
"node-r": [
{
"endpoint_id": "node-r-public",
"node_id": "node-r",
"transport": "direct_tcp_tls",
"address": "203.0.113.10:443",
"address_family": "ipv4",
"reachability": "public",
"nat_type": "none",
"connectivity_mode": "direct",
"region": "eu",
"priority": 10,
"policy_tags": ["fast-path"],
"metadata": {"source":"test"}
}
],
"node-b": [
{
"endpoint_id": "node-b-outbound",
"node_id": "node-b",
"transport": "outbound_reverse",
"address": "node-b.reverse.local",
"reachability": "outbound_only",
"nat_type": "symmetric",
"connectivity_mode": "outbound_only",
"priority": 20
}
]
},
"recovery_seeds": [
{
"node_id": "node-r",
"endpoint": "https://node-r.example.test:443",
"transport": "direct_tcp_tls",
"connectivity_mode": "direct",
"region": "eu",
"priority": 10,
"metadata": {"role":"stable-recovery"}
},
{
"node_id": "node-seed",
"endpoint": "wss://seed.example.test/mesh",
"transport": "wss",
"connectivity_mode": "direct",
"priority": 20
}
],
"route_version": "route-v1",
"policy_version": "policy-v1",
"peer_directory_version": "peers-v1"
}`),
UpdatedAt: now,
},
{
ID: "route-x-y",
ClusterID: "cluster-1",
SourceSelector: json.RawMessage(`{"node_id":"node-x"}`),
DestinationSelector: json.RawMessage(`{"node_id":"node-y"}`),
ServiceClass: "synthetic",
Status: "active",
Policy: json.RawMessage(`{
"synthetic_enabled": true,
"hops": ["node-x", "node-y"],
"peer_endpoints": {"node-y": "http://node-y:19000"}
}`),
UpdatedAt: now,
},
},
})
service.now = func() time.Time { return now }
cfg, err := service.GetNodeSyntheticMeshConfig(context.Background(), GetNodeSyntheticMeshConfigInput{
ClusterID: "cluster-1",
NodeID: "node-a",
})
if err != nil {
t.Fatalf("get synthetic config: %v", err)
}
if !cfg.Enabled {
t.Fatal("config should be enabled")
}
if len(cfg.Routes) != 1 || cfg.Routes[0].RouteID != "route-a-b" {
t.Fatalf("routes = %+v", cfg.Routes)
}
if cfg.PeerEndpoints["node-r"] == "" || cfg.PeerEndpoints["node-b"] == "" {
t.Fatalf("peer endpoints missing: %+v", cfg.PeerEndpoints)
}
if _, leaked := cfg.PeerEndpoints["node-y"]; leaked {
t.Fatalf("unrelated topology leaked: %+v", cfg.PeerEndpoints)
}
nodeRCandidates := cfg.PeerEndpointCandidates["node-r"]
if len(nodeRCandidates) != 1 {
t.Fatalf("node-r candidates = %+v", cfg.PeerEndpointCandidates)
}
if got := nodeRCandidates[0]; got.EndpointID != "node-r-public" ||
got.Transport != "direct_tcp_tls" ||
got.Reachability != "public" ||
got.NATType != "none" ||
got.ConnectivityMode != "direct" ||
got.Priority != 10 {
t.Fatalf("unexpected node-r candidate: %+v", got)
}
if _, leaked := cfg.PeerEndpointCandidates["node-y"]; leaked {
t.Fatalf("unrelated candidate topology leaked: %+v", cfg.PeerEndpointCandidates)
}
if len(cfg.RecoverySeeds) != 2 || cfg.RecoverySeeds[0].NodeID != "node-r" || cfg.RecoverySeeds[1].NodeID != "node-seed" {
t.Fatalf("unexpected recovery seeds: %+v", cfg.RecoverySeeds)
}
nodeRDirectory, ok := findPeerDirectoryEntry(cfg.PeerDirectory, "node-r")
if !ok || nodeRDirectory.CandidateCount != 1 || !nodeRDirectory.RecoverySeed {
t.Fatalf("node-r peer directory missing recovery/candidate metadata: %+v", cfg.PeerDirectory)
}
if _, ok := findPeerDirectoryEntry(cfg.PeerDirectory, "node-a"); ok {
t.Fatalf("local node leaked into peer directory: %+v", cfg.PeerDirectory)
}
if _, ok := findPeerDirectoryEntry(cfg.PeerDirectory, "node-y"); ok {
t.Fatalf("unrelated node leaked into peer directory: %+v", cfg.PeerDirectory)
}
if cfg.ProductionForwarding {
t.Fatal("production forwarding must remain false")
}
}
func TestGetNodeSyntheticMeshConfigUsesReportedMeshEndpoint(t *testing.T) {
now := time.Date(2026, 4, 28, 12, 0, 0, 0, time.UTC)
service := NewService(&fakeRepository{
testingFlags: EffectiveNodeTestingFlags{
Enabled: true,
SyntheticLinksEnabled: true,
},
routeIntents: []MeshRouteIntent{
{
ID: "route-a-b",
ClusterID: "cluster-1",
SourceSelector: json.RawMessage(`{"node_id":"node-a"}`),
DestinationSelector: json.RawMessage(`{"node_id":"node-b"}`),
ServiceClass: "synthetic",
Status: "active",
Policy: json.RawMessage(`{
"synthetic_enabled": true,
"hops": ["node-a", "node-b"]
}`),
UpdatedAt: now,
},
},
heartbeats: map[string][]NodeHeartbeat{
"node-b": {
{
ClusterID: "cluster-1",
NodeID: "node-b",
Metadata: json.RawMessage(`{
"mesh_endpoint_report": {
"schema_version": "c17z6.mesh_endpoint_report.v1",
"cluster_id": "cluster-1",
"node_id": "node-b",
"peer_endpoint": "https://node-b.dynamic.example.test:443",
"transport": "direct_tcp_tls",
"connectivity_mode": "direct",
"nat_type": "none",
"endpoint_candidates": [
{
"endpoint_id": "node-b-dynamic",
"node_id": "node-b",
"transport": "direct_tcp_tls",
"address": "https://node-b.dynamic.example.test:443",
"reachability": "public",
"connectivity_mode": "direct",
"nat_type": "none",
"priority": 1,
"metadata": {"source":"heartbeat"}
}
]
}
}`),
ObservedAt: now,
},
},
},
})
service.now = func() time.Time { return now }
cfg, err := service.GetNodeSyntheticMeshConfig(context.Background(), GetNodeSyntheticMeshConfigInput{
ClusterID: "cluster-1",
NodeID: "node-a",
})
if err != nil {
t.Fatalf("get synthetic config: %v", err)
}
if cfg.PeerEndpoints["node-b"] != "https://node-b.dynamic.example.test:443" {
t.Fatalf("reported endpoint not projected: %+v", cfg.PeerEndpoints)
}
if got := cfg.PeerEndpointCandidates["node-b"]; len(got) != 1 || got[0].EndpointID != "node-b-dynamic" {
t.Fatalf("reported candidates not projected: %+v", cfg.PeerEndpointCandidates)
}
entry, ok := findPeerDirectoryEntry(cfg.PeerDirectory, "node-b")
if !ok || entry.EndpointCount != 1 || entry.CandidateCount != 1 {
t.Fatalf("peer directory did not include reported endpoint/candidate: %+v", cfg.PeerDirectory)
}
}
func TestGetNodeSyntheticMeshConfigIssuesRendezvousRelayLeases(t *testing.T) {
now := time.Date(2026, 4, 28, 12, 0, 0, 0, time.UTC)
service := NewService(&fakeRepository{
testingFlags: EffectiveNodeTestingFlags{
Enabled: true,
SyntheticLinksEnabled: true,
},
routeIntents: []MeshRouteIntent{
{
ID: "route-a-b",
ClusterID: "cluster-1",
SourceSelector: json.RawMessage(`{"node_id":"node-a"}`),
DestinationSelector: json.RawMessage(`{"node_id":"node-b"}`),
ServiceClass: "synthetic",
Status: "active",
Policy: json.RawMessage(`{
"synthetic_enabled": true,
"hops": ["node-a", "node-r", "node-b"],
"allowed_channels": ["fabric_control", "route_control", "service_payload"],
"peer_endpoints": {
"node-r": "http://node-r:19000"
},
"peer_endpoint_candidates": {
"node-b": [
{
"endpoint_id": "node-b-outbound",
"node_id": "node-b",
"transport": "outbound_reverse",
"address": "node-b.reverse.local",
"reachability": "outbound_only",
"nat_type": "symmetric",
"connectivity_mode": "outbound_only",
"priority": 20
}
]
},
"rendezvous_leases": [
{
"peer_node_id": "node-b",
"relay_node_id": "node-r",
"relay_endpoint": "http://node-r:19000",
"priority": 5
}
]
}`),
UpdatedAt: now,
},
{
ID: "route-x-y",
ClusterID: "cluster-1",
SourceSelector: json.RawMessage(`{"node_id":"node-x"}`),
DestinationSelector: json.RawMessage(`{"node_id":"node-y"}`),
ServiceClass: "synthetic",
Status: "active",
Policy: json.RawMessage(`{
"synthetic_enabled": true,
"hops": ["node-x", "node-y"],
"peer_endpoints": {"node-x": "http://node-x:19000"},
"rendezvous_leases": [
{
"peer_node_id": "node-y",
"relay_node_id": "node-x",
"relay_endpoint": "http://node-x:19000"
}
]
}`),
UpdatedAt: now,
},
},
})
service.now = func() time.Time { return now }
cfg, err := service.GetNodeSyntheticMeshConfig(context.Background(), GetNodeSyntheticMeshConfigInput{
ClusterID: "cluster-1",
NodeID: "node-a",
})
if err != nil {
t.Fatalf("get synthetic config: %v", err)
}
if cfg.SchemaVersion != "c17z18.synthetic.v1" {
t.Fatalf("schema version = %s, want c17z18.synthetic.v1", cfg.SchemaVersion)
}
if len(cfg.RendezvousLeases) != 1 {
t.Fatalf("unexpected rendezvous leases: %+v", cfg.RendezvousLeases)
}
lease := cfg.RendezvousLeases[0]
if lease.LeaseID != "route-a-b-rv-node-b-via-node-r" ||
lease.PeerNodeID != "node-b" ||
lease.RelayNodeID != "node-r" ||
lease.RelayEndpoint != "http://node-r:19000" ||
lease.Transport != "relay_control" ||
lease.Priority != 5 ||
!lease.ControlPlaneOnly ||
!containsString(lease.AllowedChannels, "fabric_control") ||
containsString(lease.AllowedChannels, "service_payload") {
t.Fatalf("unexpected rendezvous lease contract: %+v", lease)
}
if _, ok := findPeerDirectoryEntry(cfg.PeerDirectory, "node-y"); ok {
t.Fatalf("unrelated rendezvous lease leaked into peer directory: %+v", cfg.PeerDirectory)
}
nodeB, ok := findPeerDirectoryEntry(cfg.PeerDirectory, "node-b")
if !ok || !containsString(nodeB.ConnectivityModes, "relay_required") {
t.Fatalf("peer directory missing rendezvous peer mode: %+v", cfg.PeerDirectory)
}
nodeR, ok := findPeerDirectoryEntry(cfg.PeerDirectory, "node-r")
if !ok || !containsString(nodeR.ConnectivityModes, "relay_control") {
t.Fatalf("peer directory missing relay control mode: %+v", cfg.PeerDirectory)
}
}
func TestGetNodeSyntheticMeshConfigReplacesStaleRendezvousRelay(t *testing.T) {
now := time.Date(2026, 4, 28, 12, 30, 0, 0, time.UTC)
staleHeartbeatMetadata, err := json.Marshal(map[string]any{
"mesh_rendezvous_lease_report": map[string]any{
"schema_version": "c17z18.mesh_rendezvous_lease_report.v1",
"cluster_id": "cluster-1",
"node_id": "node-a",
"observed_at": now.Format(time.RFC3339Nano),
"leases": []map[string]any{
{
"lease_id": "route-a-b-rv-node-b-via-node-r-old",
"peer_node_id": "node-b",
"relay_node_id": "node-r-old",
"route_ids": []string{"route-a-b"},
"stale_relay": true,
"reselection_needed": true,
"connection_state": "degraded",
"reason": "auto_outbound_only",
},
},
},
})
if err != nil {
t.Fatalf("marshal heartbeat metadata: %v", err)
}
service := NewService(&fakeRepository{
testingFlags: EffectiveNodeTestingFlags{
Enabled: true,
SyntheticLinksEnabled: true,
},
heartbeats: map[string][]NodeHeartbeat{
"node-a": {
{
ClusterID: "cluster-1",
NodeID: "node-a",
Metadata: staleHeartbeatMetadata,
ObservedAt: now.Add(-10 * time.Second),
},
},
},
routeIntents: []MeshRouteIntent{
{
ID: "route-a-b",
ClusterID: "cluster-1",
SourceSelector: json.RawMessage(`{"node_id":"node-a"}`),
DestinationSelector: json.RawMessage(`{"node_id":"node-b"}`),
ServiceClass: "synthetic",
Status: "active",
Policy: json.RawMessage(`{
"synthetic_enabled": true,
"hops": ["node-a", "node-r-old", "node-r-new", "node-b"],
"allowed_channels": ["fabric_control", "route_control"],
"peer_endpoints": {
"node-r-old": "http://node-r-old:19000",
"node-r-new": "http://node-r-new:19000"
},
"peer_endpoint_candidates": {
"node-b": [
{
"endpoint_id": "node-b-outbound",
"node_id": "node-b",
"transport": "outbound_reverse",
"address": "node-b.reverse.local",
"reachability": "outbound_only",
"nat_type": "symmetric",
"connectivity_mode": "outbound_only",
"priority": 5
}
]
},
"rendezvous_leases": [
{
"lease_id": "route-a-b-rv-node-b-via-node-r-old",
"peer_node_id": "node-b",
"relay_node_id": "node-r-old",
"relay_endpoint": "http://node-r-old:19000",
"priority": 4
}
]
}`),
UpdatedAt: now,
},
},
})
service.now = func() time.Time { return now }
cfg, err := service.GetNodeSyntheticMeshConfig(context.Background(), GetNodeSyntheticMeshConfigInput{
ClusterID: "cluster-1",
NodeID: "node-a",
})
if err != nil {
t.Fatalf("get synthetic config: %v", err)
}
if len(cfg.RendezvousLeases) != 1 {
t.Fatalf("unexpected rendezvous leases: %+v", cfg.RendezvousLeases)
}
lease := cfg.RendezvousLeases[0]
if lease.RelayNodeID != "node-r-new" ||
lease.LeaseID != "route-a-b-rv-node-b-via-node-r-new" ||
lease.Reason != "stale_relay_replacement" {
t.Fatalf("stale relay was not replaced: %+v", lease)
}
var metadata map[string]any
if err := json.Unmarshal(lease.Metadata, &metadata); err != nil {
t.Fatalf("unmarshal lease metadata: %v", err)
}
if metadata["replacement_for_stale_relay"] != true ||
metadata["relay_replacement_contract"] != "stale_relay_feedback_policy" {
t.Fatalf("replacement metadata missing: %+v", metadata)
}
if cfg.RendezvousRelayPolicy == nil ||
cfg.RendezvousRelayPolicy.StaleRelayCount != 1 ||
cfg.RendezvousRelayPolicy.WithdrawnLeaseCount != 1 ||
cfg.RendezvousRelayPolicy.ReplacementLeaseCount != 1 {
t.Fatalf("unexpected relay policy report: %+v", cfg.RendezvousRelayPolicy)
}
var decision RendezvousRelayPolicyDecision
for _, item := range cfg.RendezvousRelayPolicy.Decisions {
if item.Reason == "stale_relay_replacement" {
decision = item
break
}
}
if decision.SelectedRelayID != "node-r-new" || decision.StaleRelayNodeID != "node-r-old" {
t.Fatalf("unexpected relay replacement decision: %+v", cfg.RendezvousRelayPolicy.Decisions)
}
if cfg.RoutePathDecisions == nil ||
cfg.RoutePathDecisions.SchemaVersion != "c17z18.route_path_decisions.v1" ||
cfg.RoutePathDecisions.DecisionCount != 1 ||
cfg.RoutePathDecisions.ReplacementDecisionCount != 1 {
t.Fatalf("unexpected route path decisions: %+v", cfg.RoutePathDecisions)
}
pathDecision := cfg.RoutePathDecisions.Decisions[0]
if pathDecision.DecisionSource != "stale_relay_replacement" ||
pathDecision.SelectedRelayID != "node-r-new" ||
pathDecision.StaleRelayNodeID != "node-r-old" ||
pathDecision.RendezvousPeerNodeID != "node-b" ||
pathDecision.RendezvousLeaseID != "route-a-b-rv-node-b-via-node-r-new" ||
pathDecision.NextHopID != "node-r-new" ||
pathDecision.ProductionForwarding ||
!pathDecision.ControlPlaneOnly ||
strings.Join(pathDecision.EffectiveHops, ",") != "node-a,node-r-new,node-b" {
t.Fatalf("unexpected route path decision: %+v", pathDecision)
}
}
func TestGetNodeSyntheticMeshConfigAppliesReplacementPathHintForExit(t *testing.T) {
now := time.Date(2026, 4, 28, 12, 30, 0, 0, time.UTC)
hintMetadata, err := json.Marshal(map[string]any{
"mesh_route_path_decision_report": map[string]any{
"cluster_id": "cluster-1",
"node_id": "node-a",
"decisions": []map[string]any{
{
"decision_id": "route-a-b-path-node-a-via-node-r-new",
"route_id": "route-a-b",
"cluster_id": "cluster-1",
"local_node_id": "node-a",
"source_node_id": "node-a",
"destination_node_id": "node-b",
"original_hops": []string{"node-a", "node-r-old", "node-r-new", "node-b"},
"effective_hops": []string{"node-a", "node-r-new", "node-b"},
"next_hop_id": "node-r-new",
"local_role": "entry",
"selected_relay_id": "node-r-new",
"selected_relay_endpoint": "http://node-r-new:19000",
"stale_relay_node_id": "node-r-old",
"rendezvous_peer_node_id": "node-b",
"rendezvous_lease_id": "route-a-b-rv-node-b-via-node-r-new",
"rendezvous_lease_reason": "stale_relay_replacement",
"decision_source": "stale_relay_replacement",
"generation": "hint-generation",
"path_score": 900,
"score_reasons": []string{"route_path_decision_hint"},
"control_plane_only": true,
"production_forwarding": false,
"expires_at": now.Add(time.Hour).UTC().Format(time.RFC3339Nano),
},
},
},
})
if err != nil {
t.Fatalf("marshal hint metadata: %v", err)
}
service := NewService(&fakeRepository{
testingFlags: EffectiveNodeTestingFlags{
Enabled: true,
SyntheticLinksEnabled: true,
},
heartbeats: map[string][]NodeHeartbeat{
"node-a": {
{
ClusterID: "cluster-1",
NodeID: "node-a",
Metadata: hintMetadata,
ObservedAt: now.Add(-10 * time.Second),
},
},
},
routeIntents: []MeshRouteIntent{
{
ID: "route-a-b",
ClusterID: "cluster-1",
SourceSelector: json.RawMessage(`{"node_id":"node-a"}`),
DestinationSelector: json.RawMessage(`{"node_id":"node-b"}`),
ServiceClass: "synthetic",
Status: "active",
Policy: json.RawMessage(`{
"synthetic_enabled": true,
"hops": ["node-a", "node-r-old", "node-r-new", "node-b"],
"allowed_channels": ["fabric_control", "route_control"],
"peer_endpoints": {
"node-r-old": "http://node-r-old:19000",
"node-r-new": "http://node-r-new:19000"
},
"peer_endpoint_candidates": {
"node-b": [
{
"endpoint_id": "node-b-outbound",
"node_id": "node-b",
"transport": "outbound_reverse",
"address": "node-b.reverse.local",
"reachability": "outbound_only",
"nat_type": "symmetric",
"connectivity_mode": "outbound_only",
"priority": 5
}
]
},
"rendezvous_leases": [
{
"lease_id": "route-a-b-rv-node-b-via-node-r-old",
"peer_node_id": "node-b",
"relay_node_id": "node-r-old",
"relay_endpoint": "http://node-r-old:19000",
"priority": 4
}
]
}`),
UpdatedAt: now,
},
},
})
service.now = func() time.Time { return now }
cfg, err := service.GetNodeSyntheticMeshConfig(context.Background(), GetNodeSyntheticMeshConfigInput{
ClusterID: "cluster-1",
NodeID: "node-b",
})
if err != nil {
t.Fatalf("get synthetic config: %v", err)
}
if len(cfg.RendezvousLeases) != 1 ||
cfg.RendezvousLeases[0].RelayNodeID != "node-r-new" ||
cfg.RendezvousLeases[0].Reason != "stale_relay_replacement" {
t.Fatalf("replacement hint did not withdraw stale relay lease: %+v", cfg.RendezvousLeases)
}
if cfg.RoutePathDecisions == nil ||
cfg.RoutePathDecisions.ReplacementDecisionCount != 1 ||
len(cfg.RoutePathDecisions.Decisions) != 1 {
t.Fatalf("unexpected route path decisions: %+v", cfg.RoutePathDecisions)
}
decision := cfg.RoutePathDecisions.Decisions[0]
if decision.DecisionSource != "stale_relay_replacement" ||
decision.LocalRole != "exit" ||
decision.PreviousHopID != "node-r-new" ||
decision.SelectedRelayID != "node-r-new" ||
decision.StaleRelayNodeID != "node-r-old" ||
decision.RendezvousPeerNodeID != "node-b" ||
strings.Join(decision.EffectiveHops, ",") != "node-a,node-r-new,node-b" {
t.Fatalf("unexpected hinted route path decision: %+v", decision)
}
}
func TestGetNodeSyntheticMeshConfigUsesRouteHealthDriftToReselectRelay(t *testing.T) {
now := time.Date(2026, 4, 28, 12, 30, 0, 0, time.UTC)
routeHealthMetadata, err := json.Marshal(map[string]any{
"observation_type": "synthetic_route_health",
"route_id": "route-a-b",
"route_path_decision_applied": true,
"route_path_decision_selected_relay_id": "node-s",
"route_path_decision_rendezvous_peer_node_id": "node-b",
"route_path_decision_rendezvous_lease_id": "route-a-b-rv-node-b-via-node-s",
"route_path_decision_rendezvous_lease_reason": "auto_rendezvous_required",
"expected_effective_hops": []string{"node-a", "node-s", "node-b"},
"observed_ack_path": []string{"node-a", "node-t", "node-b"},
"route_path_drift_detected": true,
"control_plane_only": true,
"production_forwarding": false,
"production_payload_forwarding": false,
"route_health_production_payload_forwarding": false,
"route_health_service_payload_forwarding": false,
"synthetic_route_health_route_path_runtime": true,
"production_route_path_forwarding_runtime": false,
"route_health_route_config_contract": "control_plane_route_path_decisions_to_synthetic_route_health",
})
if err != nil {
t.Fatalf("marshal route health metadata: %v", err)
}
service := NewService(&fakeRepository{
testingFlags: EffectiveNodeTestingFlags{
Enabled: true,
SyntheticLinksEnabled: true,
},
meshLinks: []MeshLinkObservation{
{
ClusterID: "cluster-1",
SourceNodeID: "node-a",
TargetNodeID: "node-b",
LinkStatus: "reachable",
Metadata: routeHealthMetadata,
ObservedAt: now.Add(-10 * time.Second),
},
},
routeIntents: []MeshRouteIntent{
{
ID: "route-a-b",
ClusterID: "cluster-1",
SourceSelector: json.RawMessage(`{"node_id":"node-a"}`),
DestinationSelector: json.RawMessage(`{"node_id":"node-b"}`),
ServiceClass: "synthetic",
Status: "active",
Policy: json.RawMessage(`{
"synthetic_enabled": true,
"hops": ["node-a", "node-s", "node-t", "node-b"],
"allowed_channels": ["fabric_control", "route_control"],
"peer_endpoint_candidates": {
"node-b": [
{
"endpoint_id": "node-b-outbound",
"node_id": "node-b",
"transport": "outbound_reverse",
"address": "node-b.reverse.local",
"reachability": "outbound_only",
"nat_type": "symmetric",
"connectivity_mode": "outbound_only",
"priority": 5
}
],
"node-s": [
{
"endpoint_id": "node-s-public",
"node_id": "node-s",
"transport": "direct_tcp_tls",
"address": "http://node-s:19000",
"reachability": "public",
"nat_type": "none",
"connectivity_mode": "direct",
"priority": 1,
"policy_tags": ["fast-path"]
}
],
"node-t": [
{
"endpoint_id": "node-t-public",
"node_id": "node-t",
"transport": "direct_tcp_tls",
"address": "http://node-t:19000",
"reachability": "public",
"nat_type": "none",
"connectivity_mode": "direct",
"priority": 50
}
]
}
}`),
UpdatedAt: now,
},
},
})
service.now = func() time.Time { return now }
cfg, err := service.GetNodeSyntheticMeshConfig(context.Background(), GetNodeSyntheticMeshConfigInput{
ClusterID: "cluster-1",
NodeID: "node-a",
})
if err != nil {
t.Fatalf("get synthetic config: %v", err)
}
if len(cfg.RendezvousLeases) != 1 {
t.Fatalf("unexpected rendezvous leases: %+v", cfg.RendezvousLeases)
}
lease := cfg.RendezvousLeases[0]
if lease.RelayNodeID != "node-t" || lease.Reason != "stale_relay_replacement" {
t.Fatalf("route health drift did not reselect relay: %+v", lease)
}
if cfg.RendezvousRelayPolicy == nil ||
cfg.RendezvousRelayPolicy.StaleRelayCount != 1 ||
cfg.RendezvousRelayPolicy.ReplacementLeaseCount != 1 ||
cfg.RendezvousRelayPolicy.ScoringMode != "route_adjacency_endpoint_priority_mesh_link_health_synthetic_route_health_feedback" {
t.Fatalf("unexpected relay policy report: %+v", cfg.RendezvousRelayPolicy)
}
var policyDecision RendezvousRelayPolicyDecision
for _, item := range cfg.RendezvousRelayPolicy.Decisions {
if item.Reason == "stale_relay_replacement" {
policyDecision = item
break
}
}
if policyDecision.StaleRelayNodeID != "node-s" || policyDecision.SelectedRelayID != "node-t" || policyDecision.PeerNodeID != "node-b" {
t.Fatalf("unexpected route health replacement decision: %+v", cfg.RendezvousRelayPolicy.Decisions)
}
if cfg.RoutePathDecisions == nil || cfg.RoutePathDecisions.ReplacementDecisionCount != 1 {
t.Fatalf("expected replacement route path decision: %+v", cfg.RoutePathDecisions)
}
decision := cfg.RoutePathDecisions.Decisions[0]
if decision.SelectedRelayID != "node-t" ||
decision.StaleRelayNodeID != "node-s" ||
decision.RendezvousPeerNodeID != "node-b" ||
strings.Join(decision.EffectiveHops, ",") != "node-a,node-t,node-b" ||
decision.ProductionForwarding ||
!decision.ControlPlaneOnly {
t.Fatalf("unexpected route path decision from route health feedback: %+v", decision)
}
}
func TestGetNodeSyntheticMeshConfigUsesRouteHealthLatencyForRelayScore(t *testing.T) {
now := time.Date(2026, 4, 28, 12, 30, 0, 0, time.UTC)
routeHealthMetadata, err := json.Marshal(map[string]any{
"observation_type": "synthetic_route_health",
"route_id": "route-a-b",
"route_path_decision_applied": true,
"route_path_decision_selected_relay_id": "node-t",
"route_path_decision_rendezvous_peer_node_id": "node-b",
"expected_effective_hops": []string{"node-a", "node-t", "node-b"},
"observed_ack_path": []string{"node-a", "node-t", "node-b"},
"route_path_drift_detected": false,
"control_plane_only": true,
"production_forwarding": false,
"production_payload_forwarding": false,
"route_health_production_payload_forwarding": false,
"route_health_service_payload_forwarding": false,
})
if err != nil {
t.Fatalf("marshal route health metadata: %v", err)
}
latency := 5
quality := 99
service := NewService(&fakeRepository{
testingFlags: EffectiveNodeTestingFlags{
Enabled: true,
SyntheticLinksEnabled: true,
},
meshLinks: []MeshLinkObservation{
{
ClusterID: "cluster-1",
SourceNodeID: "node-a",
TargetNodeID: "node-b",
LinkStatus: "reachable",
LatencyMs: &latency,
QualityScore: &quality,
Metadata: routeHealthMetadata,
ObservedAt: now.Add(-10 * time.Second),
},
},
routeIntents: []MeshRouteIntent{
{
ID: "route-a-b",
ClusterID: "cluster-1",
SourceSelector: json.RawMessage(`{"node_id":"node-a"}`),
DestinationSelector: json.RawMessage(`{"node_id":"node-b"}`),
ServiceClass: "synthetic",
Status: "active",
Policy: json.RawMessage(`{
"synthetic_enabled": true,
"hops": ["node-a", "node-s", "node-t", "node-b"],
"allowed_channels": ["fabric_control", "route_control"],
"peer_endpoint_candidates": {
"node-b": [
{
"endpoint_id": "node-b-outbound",
"node_id": "node-b",
"transport": "outbound_reverse",
"address": "node-b.reverse.local",
"reachability": "outbound_only",
"nat_type": "symmetric",
"connectivity_mode": "outbound_only",
"priority": 5
}
],
"node-s": [
{
"endpoint_id": "node-s-public",
"node_id": "node-s",
"transport": "direct_tcp_tls",
"address": "http://node-s:19000",
"reachability": "public",
"nat_type": "none",
"connectivity_mode": "direct",
"priority": 1,
"policy_tags": ["fast-path"]
}
],
"node-t": [
{
"endpoint_id": "node-t-public",
"node_id": "node-t",
"transport": "direct_tcp_tls",
"address": "http://node-t:19000",
"reachability": "public",
"nat_type": "none",
"connectivity_mode": "direct",
"priority": 50
}
]
}
}`),
UpdatedAt: now,
},
},
})
service.now = func() time.Time { return now }
cfg, err := service.GetNodeSyntheticMeshConfig(context.Background(), GetNodeSyntheticMeshConfigInput{
ClusterID: "cluster-1",
NodeID: "node-a",
})
if err != nil {
t.Fatalf("get synthetic config: %v", err)
}
if len(cfg.RendezvousLeases) != 1 {
t.Fatalf("unexpected rendezvous leases: %+v", cfg.RendezvousLeases)
}
lease := cfg.RendezvousLeases[0]
if lease.RelayNodeID != "node-t" || lease.Reason == "stale_relay_replacement" {
t.Fatalf("route health latency did not influence relay score: %+v", lease)
}
var metadata map[string]any
if err := json.Unmarshal(lease.Metadata, &metadata); err != nil {
t.Fatalf("unmarshal lease metadata: %v", err)
}
reasons, _ := metadata["relay_selection_score_reasons"].([]any)
if !anyString(reasons, "route_health_reachable") ||
!anyString(reasons, "route_health_no_drift") ||
!anyString(reasons, "route_health_latency") {
t.Fatalf("route health score reasons missing: %+v", metadata)
}
}
func anyString(values []any, want string) bool {
for _, value := range values {
if text, ok := value.(string); ok && text == want {
return true
}
}
return false
}
func findPeerDirectoryEntry(entries []PeerDirectoryEntry, nodeID string) (PeerDirectoryEntry, bool) {
for _, entry := range entries {
if entry.NodeID == nodeID {
return entry, true
}
}
return PeerDirectoryEntry{}, false
}
func TestValidatePeerEndpointCandidates(t *testing.T) {
valid := map[string][]PeerEndpointCandidate{
"node-b": {
{
EndpointID: "node-b-public",
NodeID: "node-b",
Transport: "direct_tcp_tls",
Address: "203.0.113.20:443",
AddressFamily: "ipv4",
Reachability: "public",
NATType: "restricted",
ConnectivityMode: "direct",
Priority: 10,
Metadata: json.RawMessage(`{"source":"test"}`),
},
},
}
if err := validatePeerEndpointCandidates(valid, []string{"node-a", "node-b"}); err != nil {
t.Fatalf("validate valid candidates: %v", err)
}
tests := []struct {
name string
candidates map[string][]PeerEndpointCandidate
}{
{
name: "unknown transport",
candidates: map[string][]PeerEndpointCandidate{"node-b": {{
EndpointID: "node-b-public",
NodeID: "node-b",
Transport: "udp-hole-punch",
Address: "203.0.113.20:443",
Reachability: "public",
ConnectivityMode: "direct",
}}},
},
{
name: "unknown nat",
candidates: map[string][]PeerEndpointCandidate{"node-b": {{
EndpointID: "node-b-public",
NodeID: "node-b",
Transport: "direct_tcp_tls",
Address: "203.0.113.20:443",
Reachability: "public",
NATType: "mystery_nat",
ConnectivityMode: "direct",
}}},
},
{
name: "node outside route path",
candidates: map[string][]PeerEndpointCandidate{"node-y": {{
EndpointID: "node-y-public",
NodeID: "node-y",
Transport: "direct_tcp_tls",
Address: "203.0.113.30:443",
Reachability: "public",
ConnectivityMode: "direct",
}}},
},
{
name: "node mismatch",
candidates: map[string][]PeerEndpointCandidate{"node-b": {{
EndpointID: "node-b-public",
NodeID: "node-c",
Transport: "direct_tcp_tls",
Address: "203.0.113.20:443",
Reachability: "public",
ConnectivityMode: "direct",
}}},
},
{
name: "invalid metadata",
candidates: map[string][]PeerEndpointCandidate{"node-b": {{
EndpointID: "node-b-public",
NodeID: "node-b",
Transport: "direct_tcp_tls",
Address: "203.0.113.20:443",
Reachability: "public",
ConnectivityMode: "direct",
Metadata: json.RawMessage(`{`),
}}},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := validatePeerEndpointCandidates(tt.candidates, []string{"node-a", "node-b"})
if !errors.Is(err, ErrInvalidPayload) {
t.Fatalf("err = %v, want ErrInvalidPayload", err)
}
})
}
}
func TestMinorityClusterBlocksPolicyMutation(t *testing.T) {
store := &fakeRepository{
platformRole: PlatformRoleAdmin,
authorityState: ClusterAuthorityState{
ClusterID: "cluster-1",
AuthorityState: "minority",
MutationMode: "read_only",
},
}
service := NewService(store)
_, err := service.AssignNodeRole(context.Background(), AssignNodeRoleInput{
ActorUserID: "admin-1",
ClusterID: "cluster-1",
NodeID: "node-1",
Role: "rdp-worker",
})
if !errors.Is(err, ErrClusterReadOnly) {
t.Fatalf("err = %v, want ErrClusterReadOnly", err)
}
}
func TestRecoveryAdminCanMutateReadOnlyCluster(t *testing.T) {
store := &fakeRepository{
platformRole: PlatformRoleRecoveryAdmin,
authorityState: ClusterAuthorityState{
ClusterID: "cluster-1",
AuthorityState: "isolated",
MutationMode: "read_only",
},
}
service := NewService(store)
_, err := service.AssignNodeRole(context.Background(), AssignNodeRoleInput{
ActorUserID: "recovery-1",
ClusterID: "cluster-1",
NodeID: "node-1",
Role: "rdp-worker",
})
if err != nil {
t.Fatalf("recovery admin mutate: %v", err)
}
}
func TestCreateVPNConnectionRequiresPlatformAdmin(t *testing.T) {
store := &fakeRepository{platformRole: "user"}
service := NewService(store)
_, err := service.CreateVPNConnection(context.Background(), CreateVPNConnectionInput{
ActorUserID: "user-1",
ClusterID: "cluster-1",
OrganizationID: "org-1",
Name: "office-a",
})
if !errors.Is(err, ErrAccessDenied) {
t.Fatalf("err = %v, want ErrAccessDenied", err)
}
}
func TestCreateVPNConnectionDefaultsToDisabledSingleActive(t *testing.T) {
store := &fakeRepository{platformRole: PlatformRoleAdmin}
service := NewService(store)
item, err := service.CreateVPNConnection(context.Background(), CreateVPNConnectionInput{
ActorUserID: "admin-1",
ClusterID: "cluster-1",
OrganizationID: "org-1",
Name: "office-a",
})
if err != nil {
t.Fatalf("create vpn connection: %v", err)
}
if item.Mode != VPNConnectionModeSingleActive || item.DesiredState != VPNConnectionDesiredDisabled {
t.Fatalf("unexpected defaults: %+v", item)
}
if string(store.lastVPNConnectionInput.AllowedNodePolicy) == "" || string(store.lastVPNConnectionInput.RoutingUsage) == "" {
t.Fatalf("expected default json policies, got %+v", store.lastVPNConnectionInput)
}
}
func TestCreateVPNConnectionRequiresClusterAndOrganizationScope(t *testing.T) {
store := &fakeRepository{platformRole: PlatformRoleAdmin}
service := NewService(store)
_, err := service.CreateVPNConnection(context.Background(), CreateVPNConnectionInput{
ActorUserID: "admin-1",
ClusterID: "cluster-1",
Name: "office-a",
})
if !errors.Is(err, ErrInvalidPayload) {
t.Fatalf("err = %v, want ErrInvalidPayload", err)
}
}
func TestCreateVPNConnectionBlockedInReadOnlyCluster(t *testing.T) {
store := &fakeRepository{
platformRole: PlatformRoleAdmin,
authorityState: ClusterAuthorityState{
ClusterID: "cluster-1",
AuthorityState: "minority",
MutationMode: "read_only",
},
}
service := NewService(store)
_, err := service.CreateVPNConnection(context.Background(), CreateVPNConnectionInput{
ActorUserID: "admin-1",
ClusterID: "cluster-1",
OrganizationID: "org-1",
Name: "office-a",
})
if !errors.Is(err, ErrClusterReadOnly) {
t.Fatalf("err = %v, want ErrClusterReadOnly", err)
}
}
func TestAcquireVPNLeaseRequiresEnabledConnection(t *testing.T) {
store := &fakeRepository{
platformRole: PlatformRoleAdmin,
vpnConnection: VPNConnection{
ID: "vpn-1",
ClusterID: "cluster-1",
Mode: VPNConnectionModeSingleActive,
DesiredState: VPNConnectionDesiredDisabled,
},
}
service := NewService(store)
_, err := service.AcquireVPNConnectionLease(context.Background(), AcquireVPNConnectionLeaseInput{
ActorUserID: "admin-1",
ClusterID: "cluster-1",
VPNConnectionID: "vpn-1",
OwnerNodeID: "node-1",
})
if err == nil || !strings.Contains(err.Error(), "enabled single_active") {
t.Fatalf("err = %v, want enabled single_active validation", err)
}
}
func TestAcquireVPNLeaseRejectsSecondActiveOwner(t *testing.T) {
store := &fakeRepository{
platformRole: PlatformRoleAdmin,
vpnConnection: VPNConnection{
ID: "vpn-1",
ClusterID: "cluster-1",
Mode: VPNConnectionModeSingleActive,
DesiredState: VPNConnectionDesiredEnabled,
},
acquireVPNLeaseErr: ErrVPNLeaseAlreadyActive,
}
service := NewService(store)
_, err := service.AcquireVPNConnectionLease(context.Background(), AcquireVPNConnectionLeaseInput{
ActorUserID: "admin-1",
ClusterID: "cluster-1",
VPNConnectionID: "vpn-1",
OwnerNodeID: "node-2",
})
if !errors.Is(err, ErrVPNLeaseAlreadyActive) {
t.Fatalf("err = %v, want ErrVPNLeaseAlreadyActive", err)
}
}
func TestAcquireVPNLeaseRejectsOwnerOutsideAllowedPolicy(t *testing.T) {
store := &fakeRepository{
platformRole: PlatformRoleAdmin,
vpnConnection: VPNConnection{
ID: "vpn-1",
ClusterID: "cluster-1",
Mode: VPNConnectionModeSingleActive,
DesiredState: VPNConnectionDesiredEnabled,
},
ownerEligibility: VPNLeaseOwnerEligibility{
VPNConnectionID: "vpn-1",
ClusterID: "cluster-1",
OwnerNodeID: "node-1",
MembershipStatus: "active",
NodeRegistrationStatus: NodeRegistrationActive,
AllowedByPolicy: false,
HasAuthorizedRole: true,
},
}
service := NewService(store)
_, err := service.AcquireVPNConnectionLease(context.Background(), AcquireVPNConnectionLeaseInput{
ActorUserID: "admin-1",
ClusterID: "cluster-1",
VPNConnectionID: "vpn-1",
OwnerNodeID: "node-1",
})
if !errors.Is(err, ErrVPNLeaseOwnerNotAllowed) {
t.Fatalf("err = %v, want ErrVPNLeaseOwnerNotAllowed", err)
}
}
func TestAcquireVPNLeaseRejectsOwnerWithoutVPNRole(t *testing.T) {
store := &fakeRepository{
platformRole: PlatformRoleAdmin,
vpnConnection: VPNConnection{
ID: "vpn-1",
ClusterID: "cluster-1",
Mode: VPNConnectionModeSingleActive,
DesiredState: VPNConnectionDesiredEnabled,
},
ownerEligibility: VPNLeaseOwnerEligibility{
VPNConnectionID: "vpn-1",
ClusterID: "cluster-1",
OwnerNodeID: "node-1",
MembershipStatus: "active",
NodeRegistrationStatus: NodeRegistrationActive,
AllowedByPolicy: true,
HasAuthorizedRole: false,
},
}
service := NewService(store)
_, err := service.AcquireVPNConnectionLease(context.Background(), AcquireVPNConnectionLeaseInput{
ActorUserID: "admin-1",
ClusterID: "cluster-1",
VPNConnectionID: "vpn-1",
OwnerNodeID: "node-1",
})
if !errors.Is(err, ErrVPNLeaseOwnerRoleRequired) {
t.Fatalf("err = %v, want ErrVPNLeaseOwnerRoleRequired", err)
}
}
func TestAcquireVPNLeaseRejectsWrongCluster(t *testing.T) {
store := &fakeRepository{
platformRole: PlatformRoleAdmin,
vpnConnection: VPNConnection{
ID: "vpn-1",
ClusterID: "cluster-1",
Mode: VPNConnectionModeSingleActive,
DesiredState: VPNConnectionDesiredEnabled,
},
ownerEligibilityErr: pgx.ErrNoRows,
}
service := NewService(store)
_, err := service.AcquireVPNConnectionLease(context.Background(), AcquireVPNConnectionLeaseInput{
ActorUserID: "admin-1",
ClusterID: "cluster-other",
VPNConnectionID: "vpn-1",
OwnerNodeID: "node-1",
})
if !errors.Is(err, ErrInvalidVPNConnection) {
t.Fatalf("err = %v, want ErrInvalidVPNConnection", err)
}
}
func TestRenewVPNLeaseRejectsExpiredLease(t *testing.T) {
store := &fakeRepository{
platformRole: PlatformRoleAdmin,
ownerEligibility: VPNLeaseOwnerEligibility{
VPNConnectionID: "vpn-1",
ClusterID: "cluster-1",
OwnerNodeID: "node-1",
MembershipStatus: "active",
NodeRegistrationStatus: NodeRegistrationActive,
AllowedByPolicy: true,
HasAuthorizedRole: true,
},
renewVPNLeaseErr: pgx.ErrNoRows,
}
service := NewService(store)
_, err := service.RenewVPNConnectionLease(context.Background(), RenewVPNConnectionLeaseInput{
ActorUserID: "admin-1",
ClusterID: "cluster-1",
VPNConnectionID: "vpn-1",
LeaseID: "lease-1",
OwnerNodeID: "node-1",
FencingToken: "token-1",
})
if !errors.Is(err, ErrInvalidVPNLease) {
t.Fatalf("err = %v, want ErrInvalidVPNLease", err)
}
}
func TestFenceVPNLeaseRequiresRecoveryAdmin(t *testing.T) {
store := &fakeRepository{platformRole: PlatformRoleAdmin}
service := NewService(store)
_, err := service.FenceVPNConnectionLease(context.Background(), FenceVPNConnectionLeaseInput{
ActorUserID: "admin-1",
ClusterID: "cluster-1",
VPNConnectionID: "vpn-1",
LeaseID: "lease-1",
})
if !errors.Is(err, ErrAccessDenied) {
t.Fatalf("err = %v, want ErrAccessDenied", err)
}
}
func TestExpireStaleVPNConnectionLeasesAuditsEachExpiredLease(t *testing.T) {
store := &fakeRepository{
platformRole: PlatformRoleAdmin,
expiredVPNLeases: []VPNConnectionLease{
{ID: "lease-1", ClusterID: "cluster-1", VPNConnectionID: "vpn-1", Status: VPNLeaseStatusExpired},
{ID: "lease-2", ClusterID: "cluster-1", VPNConnectionID: "vpn-2", Status: VPNLeaseStatusExpired},
},
}
service := NewService(store)
items, err := service.ExpireStaleVPNConnectionLeases(context.Background(), ExpireStaleVPNConnectionLeasesInput{
ActorUserID: "admin-1",
ClusterID: "cluster-1",
})
if err != nil {
t.Fatalf("expire stale vpn leases: %v", err)
}
if got, want := len(items), 2; got != want {
t.Fatalf("expired leases = %d, want %d", got, want)
}
var auditCount int
for _, event := range store.auditEvents {
if event.EventType == "vpn_connection.lease_expired" {
auditCount++
}
}
if got, want := auditCount, 2; got != want {
t.Fatalf("lease_expired audit count = %d, want %d", got, want)
}
}
func TestSetVPNConnectionAllowedNodesDeduplicatesScope(t *testing.T) {
store := &fakeRepository{platformRole: PlatformRoleAdmin}
service := NewService(store)
items, err := service.SetVPNConnectionAllowedNodes(context.Background(), SetVPNConnectionAllowedNodesInput{
ActorUserID: "admin-1",
ClusterID: "cluster-1",
VPNConnectionID: "vpn-1",
NodeIDs: []string{"node-1", "node-1", " ", "node-2"},
})
if err != nil {
t.Fatalf("set allowed nodes: %v", err)
}
if got, want := len(store.lastAllowedNodesInput.NodeIDs), 2; got != want {
t.Fatalf("deduped nodes = %d, want %d", got, want)
}
if got, want := len(items), 2; got != want {
t.Fatalf("allowed nodes returned = %d, want %d", got, want)
}
}
func TestUpsertVPNRoutePolicyRejectsInvalidType(t *testing.T) {
store := &fakeRepository{platformRole: PlatformRoleAdmin}
service := NewService(store)
_, err := service.UpsertVPNConnectionRoutePolicy(context.Background(), UpsertVPNConnectionRoutePolicyInput{
ActorUserID: "admin-1",
ClusterID: "cluster-1",
VPNConnectionID: "vpn-1",
RouteType: "submarine",
Destination: "10.0.0.0/24",
})
if !errors.Is(err, ErrInvalidPayload) {
t.Fatalf("err = %v, want ErrInvalidPayload", err)
}
}
func TestListNodeVPNAssignmentsDoesNotRequirePlatformAdmin(t *testing.T) {
store := &fakeRepository{
platformRole: "user",
nodeVPNAssignments: []NodeVPNAssignment{
{VPNConnectionID: "vpn-1", ClusterID: "cluster-1", OrganizationID: "org-1", AssignmentReason: "eligible_candidate"},
},
}
service := NewService(store)
items, err := service.ListNodeVPNAssignments(context.Background(), "cluster-1", "node-1")
if err != nil {
t.Fatalf("list node vpn assignments: %v", err)
}
if got, want := len(items), 1; got != want {
t.Fatalf("assignments = %d, want %d", got, want)
}
}
func TestReportNodeVPNAssignmentStatusRejectsInvisibleAssignment(t *testing.T) {
store := &fakeRepository{}
service := NewService(store)
_, err := service.ReportNodeVPNAssignmentStatus(context.Background(), ReportNodeVPNAssignmentStatusInput{
ClusterID: "cluster-1",
NodeID: "node-1",
VPNConnectionID: "vpn-foreign",
ObservedStatus: VPNAssignmentStatusAssigned,
})
if !errors.Is(err, ErrVPNLeaseOwnerNotAllowed) {
t.Fatalf("err = %v, want ErrVPNLeaseOwnerNotAllowed", err)
}
}
func TestReportNodeVPNAssignmentStatusAcceptsExplicitStates(t *testing.T) {
store := &fakeRepository{
nodeVPNAssignments: []NodeVPNAssignment{
{VPNConnectionID: "vpn-1", ClusterID: "cluster-1", OrganizationID: "org-1"},
},
}
service := NewService(store)
status, err := service.ReportNodeVPNAssignmentStatus(context.Background(), ReportNodeVPNAssignmentStatusInput{
ClusterID: "cluster-1",
NodeID: "node-1",
VPNConnectionID: "vpn-1",
ObservedStatus: VPNAssignmentStatusLeaseRequired,
StatusPayload: json.RawMessage(`{"reason":"no_lease"}`),
})
if err != nil {
t.Fatalf("report node vpn assignment status: %v", err)
}
if status.ObservedStatus != VPNAssignmentStatusLeaseRequired {
t.Fatalf("ObservedStatus = %q, want %q", status.ObservedStatus, VPNAssignmentStatusLeaseRequired)
}
}
func TestReportNodeVPNAssignmentStatusRejectsInvalidStatus(t *testing.T) {
store := &fakeRepository{
nodeVPNAssignments: []NodeVPNAssignment{
{VPNConnectionID: "vpn-1", ClusterID: "cluster-1", OrganizationID: "org-1"},
},
}
service := NewService(store)
_, err := service.ReportNodeVPNAssignmentStatus(context.Background(), ReportNodeVPNAssignmentStatusInput{
ClusterID: "cluster-1",
NodeID: "node-1",
VPNConnectionID: "vpn-1",
ObservedStatus: "running_tunnel",
})
if !errors.Is(err, ErrInvalidPayload) {
t.Fatalf("err = %v, want ErrInvalidPayload", err)
}
}
type fakeRepository struct {
platformRole string
lastTokenHash string
validTokenErr error
createJoinRequestID string
bootstrapJoinRequest NodeJoinRequest
clusterAuthority ClusterAuthorityKey
lastTokenAuthority json.RawMessage
lastApprovalAuthority json.RawMessage
authorityState ClusterAuthorityState
vpnConnection VPNConnection
lastVPNConnectionInput CreateVPNConnectionInput
lastAllowedNodesInput SetVPNConnectionAllowedNodesInput
lastAttachInput AttachExistingNodeInput
lastNodeGroupInput CreateNodeGroupInput
lastAssignGroupInput AssignNodeGroupInput
lastEntryPointInput CreateFabricEntryPointInput
lastEgressPoolInput CreateFabricEgressPoolInput
acquireVPNLeaseErr error
ownerEligibility VPNLeaseOwnerEligibility
ownerEligibilityErr error
renewVPNLeaseErr error
expiredVPNLeases []VPNConnectionLease
nodeVPNAssignments []NodeVPNAssignment
testingFlags EffectiveNodeTestingFlags
routeIntents []MeshRouteIntent
meshLinks []MeshLinkObservation
heartbeats map[string][]NodeHeartbeat
auditEvents []ClusterAuditEvent
}
func (f *fakeRepository) GetPlatformRole(context.Context, string) (string, error) {
return f.platformRole, nil
}
func (f *fakeRepository) ListClusters(context.Context) ([]Cluster, error) {
return nil, nil
}
func (f *fakeRepository) GetCluster(context.Context, string) (Cluster, error) {
return Cluster{}, nil
}
func (f *fakeRepository) CreateCluster(context.Context, CreateClusterInput) (Cluster, error) {
return Cluster{}, nil
}
func (f *fakeRepository) UpdateCluster(_ context.Context, input UpdateClusterInput) (Cluster, error) {
return Cluster{
ID: input.ClusterID,
Slug: "cluster-1",
Name: input.Name,
Status: input.Status,
Region: input.Region,
Metadata: input.Metadata,
}, nil
}
func (f *fakeRepository) GetClusterAuthority(_ context.Context, clusterID string) (ClusterAuthorityKey, error) {
if f.clusterAuthority.PrivateKey == "" {
keys, err := clusterauth.GenerateKeyPair()
if err != nil {
return ClusterAuthorityKey{}, err
}
f.clusterAuthority = ClusterAuthorityKey{
ClusterAuthorityDescriptor: ClusterAuthorityDescriptor{
SchemaVersion: clusterauth.AuthoritySchemaVersion,
ClusterID: clusterID,
AuthorityState: "active",
KeyAlgorithm: clusterauth.AlgorithmEd25519,
PublicKey: keys.PublicKeyB64,
PublicKeyFingerprint: keys.Fingerprint,
CreatedAt: time.Now().UTC(),
UpdatedAt: time.Now().UTC(),
},
PrivateKey: keys.PrivateKeyB64,
}
}
if f.clusterAuthority.ClusterID == "" {
f.clusterAuthority.ClusterID = clusterID
}
return f.clusterAuthority, nil
}
func (f *fakeRepository) EnsureClusterAuthority(ctx context.Context, clusterID string, _ *string) (ClusterAuthorityKey, error) {
return f.GetClusterAuthority(ctx, clusterID)
}
func (f *fakeRepository) ListClusterNodes(context.Context, string) ([]ClusterNode, error) {
return nil, nil
}
func (f *fakeRepository) ListNodeGroups(context.Context, string) ([]ClusterNodeGroup, error) {
return nil, nil
}
func (f *fakeRepository) CreateNodeGroup(_ context.Context, input CreateNodeGroupInput) (ClusterNodeGroup, error) {
f.lastNodeGroupInput = input
return ClusterNodeGroup{
ID: "group-1",
ClusterID: input.ClusterID,
ParentGroupID: input.ParentGroupID,
Name: input.Name,
Description: input.Description,
SortOrder: input.SortOrder,
Metadata: input.Metadata,
}, nil
}
func (f *fakeRepository) AssignNodeToGroup(_ context.Context, input AssignNodeGroupInput) (ClusterNode, error) {
f.lastAssignGroupInput = input
return ClusterNode{
ID: input.NodeID,
NodeKey: "node-key-1",
Name: "Node One",
RegistrationStatus: NodeRegistrationActive,
MembershipStatus: "active",
NodeGroupID: input.GroupID,
}, nil
}
func (f *fakeRepository) CreateJoinToken(_ context.Context, input CreateJoinTokenInput, tokenHash string) (NodeJoinToken, error) {
f.lastTokenHash = tokenHash
return NodeJoinToken{
ID: "token-1",
ClusterID: input.ClusterID,
Scope: input.Scope,
ExpiresAt: input.ExpiresAt,
MaxUses: input.MaxUses,
Status: "active",
CreatedByUserID: &input.ActorUserID,
CreatedAt: time.Now().UTC(),
}, nil
}
func (f *fakeRepository) SetJoinTokenAuthority(_ context.Context, clusterID, tokenID string, payload json.RawMessage, signature ClusterSignature) (NodeJoinToken, error) {
f.lastTokenAuthority = payload
return NodeJoinToken{
ID: tokenID,
ClusterID: clusterID,
Scope: json.RawMessage(`{"roles":["rdp-worker"]}`),
ExpiresAt: time.Now().UTC().Add(time.Hour),
MaxUses: 1,
Status: "active",
AuthorityPayload: payload,
AuthoritySignature: &signature,
}, nil
}
func (f *fakeRepository) GetValidJoinTokenByHash(context.Context, string, string) (NodeJoinToken, error) {
if f.validTokenErr != nil {
return NodeJoinToken{}, f.validTokenErr
}
return NodeJoinToken{ID: "token-1", Status: "active", ExpiresAt: time.Now().Add(time.Hour), MaxUses: 1}, nil
}
func (f *fakeRepository) RevokeJoinToken(context.Context, RevokeJoinTokenInput) (NodeJoinToken, error) {
return NodeJoinToken{ID: "token-1", Status: "revoked"}, nil
}
func (f *fakeRepository) ExpireJoinTokens(context.Context, string) error {
return nil
}
func (f *fakeRepository) CreateJoinRequest(_ context.Context, input CreateJoinRequestInput, joinTokenID string) (NodeJoinRequest, error) {
id := f.createJoinRequestID
if id == "" {
id = "join-request-1"
}
return NodeJoinRequest{
ID: id,
ClusterID: input.ClusterID,
JoinTokenID: &joinTokenID,
NodeName: input.NodeName,
NodeFingerprint: input.NodeFingerprint,
PublicKey: input.PublicKey,
ReportedCapabilities: input.ReportedCapabilities,
ReportedFacts: input.ReportedFacts,
RequestedRoles: input.RequestedRoles,
Status: JoinRequestStatusPending,
}, nil
}
func (f *fakeRepository) GetJoinRequestForBootstrap(context.Context, GetJoinRequestBootstrapInput) (NodeJoinRequest, error) {
if f.bootstrapJoinRequest.ID != "" {
return f.bootstrapJoinRequest, nil
}
return NodeJoinRequest{ID: "join-request-1", ClusterID: "cluster-1", Status: JoinRequestStatusPending}, nil
}
func (f *fakeRepository) ListJoinRequests(context.Context, string) ([]NodeJoinRequest, error) {
return nil, nil
}
func (f *fakeRepository) ApproveJoinRequest(_ context.Context, input ApproveJoinRequestInput) (ApprovedJoinRequest, error) {
return ApprovedJoinRequest{
JoinRequest: NodeJoinRequest{ID: input.JoinRequestID, ClusterID: input.ClusterID, Status: JoinRequestStatusApproved, ApprovedNodeID: &input.NodeKey},
Bootstrap: NodeBootstrap{NodeID: input.NodeKey, ClusterID: input.ClusterID, IdentityStatus: "active"},
}, nil
}
func (f *fakeRepository) SetJoinRequestApprovalAuthority(_ context.Context, clusterID, joinRequestID string, payload json.RawMessage, signature ClusterSignature) (NodeJoinRequest, error) {
f.lastApprovalAuthority = payload
signatureRaw, _ := json.Marshal(signature)
nodeID := "node-1"
return NodeJoinRequest{
ID: joinRequestID,
ClusterID: clusterID,
Status: JoinRequestStatusApproved,
ApprovedNodeID: &nodeID,
ApprovalPayload: payload,
ApprovalSignature: signatureRaw,
}, nil
}
func (f *fakeRepository) RejectJoinRequest(context.Context, RejectJoinRequestInput) (NodeJoinRequest, error) {
return NodeJoinRequest{}, nil
}
func (f *fakeRepository) AssignNodeRole(_ context.Context, input AssignNodeRoleInput) (NodeRoleAssignment, error) {
return NodeRoleAssignment{ClusterID: input.ClusterID, NodeID: input.NodeID, Role: input.Role}, nil
}
func (f *fakeRepository) ListNodeRoleAssignments(context.Context, string, string) ([]NodeRoleAssignment, error) {
return nil, nil
}
func (f *fakeRepository) AttachExistingNodeToCluster(_ context.Context, input AttachExistingNodeInput) (ClusterNode, error) {
f.lastAttachInput = input
return ClusterNode{
ID: input.NodeID,
NodeKey: "node-key-1",
Name: "Node One",
RegistrationStatus: NodeRegistrationActive,
MembershipStatus: "active",
}, nil
}
func (f *fakeRepository) RecordHeartbeat(context.Context, RecordHeartbeatInput) (NodeHeartbeat, error) {
return NodeHeartbeat{}, nil
}
func (f *fakeRepository) ListNodeHeartbeats(_ context.Context, _ string, nodeID string, _ int) ([]NodeHeartbeat, error) {
return f.heartbeats[nodeID], nil
}
func (f *fakeRepository) RevokeNodeIdentity(context.Context, RevokeNodeIdentityInput) error {
return nil
}
func (f *fakeRepository) DisableClusterMembership(context.Context, DisableMembershipInput) error {
return nil
}
func (f *fakeRepository) UpsertFabricTestingFlag(_ context.Context, input UpsertFabricTestingFlagInput) (FabricTestingFlag, error) {
return FabricTestingFlag{
ScopeType: input.ScopeType,
ScopeID: input.ScopeID,
ClusterID: input.ClusterID,
Enabled: input.Enabled,
TelemetryEnabled: input.TelemetryEnabled,
SyntheticLinksEnabled: input.SyntheticLinksEnabled,
HistoryRetentionHours: input.HistoryRetentionHours,
Metadata: input.Metadata,
}, nil
}
func (f *fakeRepository) ListFabricTestingFlags(context.Context) ([]FabricTestingFlag, error) {
return nil, nil
}
func (f *fakeRepository) GetEffectiveNodeTestingFlags(context.Context, string, string) (EffectiveNodeTestingFlags, error) {
return f.testingFlags, nil
}
func (f *fakeRepository) RecordNodeTelemetry(_ context.Context, input RecordNodeTelemetryInput) (NodeTelemetryObservation, error) {
return NodeTelemetryObservation{
ClusterID: input.ClusterID,
NodeID: input.NodeID,
Payload: input.Payload,
}, nil
}
func (f *fakeRepository) ListNodeTelemetry(context.Context, string, string, int) ([]NodeTelemetryObservation, error) {
return nil, nil
}
func (f *fakeRepository) SetDesiredWorkload(_ context.Context, input SetDesiredWorkloadInput) (NodeWorkloadDesiredState, error) {
return NodeWorkloadDesiredState{
ClusterID: input.ClusterID,
NodeID: input.NodeID,
ServiceType: input.ServiceType,
DesiredState: input.DesiredState,
RuntimeMode: input.RuntimeMode,
Config: input.Config,
Environment: input.Environment,
}, nil
}
func (f *fakeRepository) ListDesiredWorkloads(context.Context, string, string) ([]NodeWorkloadDesiredState, error) {
return nil, nil
}
func (f *fakeRepository) ReportWorkloadStatus(_ context.Context, input ReportWorkloadStatusInput) (NodeWorkloadStatus, error) {
return NodeWorkloadStatus{
ClusterID: input.ClusterID,
NodeID: input.NodeID,
ServiceType: input.ServiceType,
ReportedState: input.ReportedState,
RuntimeMode: input.RuntimeMode,
StatusPayload: input.StatusPayload,
}, nil
}
func (f *fakeRepository) ListLatestWorkloadStatuses(context.Context, string, string) ([]NodeWorkloadStatus, error) {
return nil, nil
}
func (f *fakeRepository) ReportMeshLink(_ context.Context, input ReportMeshLinkInput) (MeshLinkObservation, error) {
return MeshLinkObservation{
ClusterID: input.ClusterID,
SourceNodeID: input.SourceNodeID,
TargetNodeID: input.TargetNodeID,
LinkStatus: input.LinkStatus,
Metadata: input.Metadata,
}, nil
}
func (f *fakeRepository) ListMeshLinks(context.Context, string) ([]MeshLinkObservation, error) {
return f.meshLinks, nil
}
func (f *fakeRepository) CreateRouteIntent(_ context.Context, input CreateRouteIntentInput) (MeshRouteIntent, error) {
return MeshRouteIntent{
ClusterID: input.ClusterID,
SourceSelector: input.SourceSelector,
DestinationSelector: input.DestinationSelector,
ServiceClass: input.ServiceClass,
Priority: input.Priority,
Policy: input.Policy,
}, nil
}
func (f *fakeRepository) ListRouteIntents(context.Context, string) ([]MeshRouteIntent, error) {
return f.routeIntents, nil
}
func (f *fakeRepository) ListQoSPolicies(context.Context, string) ([]MeshQoSPolicy, error) {
return nil, nil
}
func (f *fakeRepository) ListFabricEntryPoints(context.Context, string) ([]FabricEntryPoint, error) {
return nil, nil
}
func (f *fakeRepository) CreateFabricEntryPoint(_ context.Context, input CreateFabricEntryPointInput) (FabricEntryPoint, error) {
f.lastEntryPointInput = input
return FabricEntryPoint{
ID: "entry-1",
ClusterID: input.ClusterID,
Name: input.Name,
Status: input.Status,
EndpointType: input.EndpointType,
PublicEndpoint: input.PublicEndpoint,
Policy: input.Policy,
Metadata: input.Metadata,
}, nil
}
func (f *fakeRepository) SetFabricEntryPointNode(_ context.Context, input SetFabricEntryPointNodeInput) (FabricEntryPointNode, error) {
return FabricEntryPointNode{
EntryPointID: input.EntryPointID,
ClusterID: input.ClusterID,
NodeID: input.NodeID,
Status: input.Status,
Priority: input.Priority,
Metadata: input.Metadata,
}, nil
}
func (f *fakeRepository) ListFabricEntryPointNodes(context.Context, string, string) ([]FabricEntryPointNode, error) {
return []FabricEntryPointNode{}, nil
}
func (f *fakeRepository) ListFabricEgressPools(context.Context, string) ([]FabricEgressPool, error) {
return nil, nil
}
func (f *fakeRepository) CreateFabricEgressPool(_ context.Context, input CreateFabricEgressPoolInput) (FabricEgressPool, error) {
f.lastEgressPoolInput = input
return FabricEgressPool{
ID: "egress-1",
ClusterID: input.ClusterID,
Name: input.Name,
Status: input.Status,
Description: input.Description,
RouteScope: input.RouteScope,
Policy: input.Policy,
Metadata: input.Metadata,
}, nil
}
func (f *fakeRepository) SetFabricEgressPoolNode(_ context.Context, input SetFabricEgressPoolNodeInput) (FabricEgressPoolNode, error) {
return FabricEgressPoolNode{
EgressPoolID: input.EgressPoolID,
ClusterID: input.ClusterID,
NodeID: input.NodeID,
Status: input.Status,
Priority: input.Priority,
Metadata: input.Metadata,
}, nil
}
func (f *fakeRepository) ListFabricEgressPoolNodes(context.Context, string, string) ([]FabricEgressPoolNode, error) {
return []FabricEgressPoolNode{}, nil
}
func (f *fakeRepository) GetClusterAuthorityState(context.Context, string) (ClusterAuthorityState, error) {
if f.authorityState.ClusterID == "" {
return ClusterAuthorityState{ClusterID: "cluster-1", AuthorityState: "authoritative", MutationMode: "normal"}, nil
}
return f.authorityState, nil
}
func (f *fakeRepository) UpdateClusterAuthorityState(_ context.Context, input UpdateClusterAuthorityInput) (ClusterAuthorityState, error) {
return ClusterAuthorityState{
ClusterID: input.ClusterID,
AuthorityState: input.AuthorityState,
MutationMode: input.MutationMode,
Notes: input.Notes,
}, nil
}
func (f *fakeRepository) ListClusterAdminSummaries(context.Context) ([]ClusterAdminSummary, error) {
return nil, nil
}
func (f *fakeRepository) CreateVPNConnection(_ context.Context, input CreateVPNConnectionInput) (VPNConnection, error) {
f.lastVPNConnectionInput = input
return VPNConnection{
ID: "vpn-1",
ClusterID: input.ClusterID,
OrganizationID: input.OrganizationID,
Name: input.Name,
TargetEndpoint: input.TargetEndpoint,
ProtocolFamily: input.ProtocolFamily,
CredentialRef: input.CredentialRef,
Mode: input.Mode,
DesiredState: input.DesiredState,
AllowedNodePolicy: input.AllowedNodePolicy,
RoutingUsage: input.RoutingUsage,
RoutePolicy: input.RoutePolicy,
QoSPolicy: input.QoSPolicy,
PlacementPolicy: input.PlacementPolicy,
Status: VPNConnectionStatusDisabled,
Metadata: input.Metadata,
}, nil
}
func (f *fakeRepository) ListVPNConnections(context.Context, string) ([]VPNConnection, error) {
return nil, nil
}
func (f *fakeRepository) GetVPNConnection(context.Context, string, string) (VPNConnection, error) {
if f.vpnConnection.ID != "" {
return f.vpnConnection, nil
}
return VPNConnection{
ID: "vpn-1",
ClusterID: "cluster-1",
Mode: VPNConnectionModeSingleActive,
DesiredState: VPNConnectionDesiredEnabled,
}, nil
}
func (f *fakeRepository) UpdateVPNConnectionDesiredState(_ context.Context, input UpdateVPNConnectionDesiredStateInput) (VPNConnection, error) {
return VPNConnection{ID: input.VPNConnectionID, ClusterID: input.ClusterID, DesiredState: input.DesiredState}, nil
}
func (f *fakeRepository) UpsertVPNConnectionRoutePolicy(_ context.Context, input UpsertVPNConnectionRoutePolicyInput) (VPNConnectionRoutePolicy, error) {
return VPNConnectionRoutePolicy{
ID: "route-policy-1",
VPNConnectionID: input.VPNConnectionID,
ClusterID: input.ClusterID,
RouteType: input.RouteType,
Destination: input.Destination,
Action: input.Action,
ServiceType: input.ServiceType,
Priority: input.Priority,
Policy: input.Policy,
Status: input.Status,
}, nil
}
func (f *fakeRepository) ListVPNConnectionRoutePolicies(context.Context, string, string) ([]VPNConnectionRoutePolicy, error) {
return nil, nil
}
func (f *fakeRepository) SetVPNConnectionAllowedNodes(_ context.Context, input SetVPNConnectionAllowedNodesInput) ([]VPNConnectionAllowedNode, error) {
f.lastAllowedNodesInput = input
items := make([]VPNConnectionAllowedNode, 0, len(input.NodeIDs))
for _, nodeID := range input.NodeIDs {
items = append(items, VPNConnectionAllowedNode{
VPNConnectionID: input.VPNConnectionID,
ClusterID: input.ClusterID,
NodeID: nodeID,
RolePreference: input.RolePreference,
Status: "active",
Metadata: input.Metadata,
})
}
return items, nil
}
func (f *fakeRepository) ListVPNConnectionAllowedNodes(context.Context, string, string) ([]VPNConnectionAllowedNode, error) {
return nil, nil
}
func (f *fakeRepository) AcquireVPNConnectionLease(_ context.Context, input AcquireVPNConnectionLeaseInput, expiresAt time.Time, fencingToken string) (VPNConnectionLease, error) {
if f.acquireVPNLeaseErr != nil {
return VPNConnectionLease{}, f.acquireVPNLeaseErr
}
return VPNConnectionLease{
ID: "lease-1",
VPNConnectionID: input.VPNConnectionID,
ClusterID: input.ClusterID,
OwnerNodeID: input.OwnerNodeID,
LeaseGeneration: 1,
FencingToken: fencingToken,
Status: VPNLeaseStatusActive,
ExpiresAt: expiresAt,
Metadata: input.Metadata,
}, nil
}
func (f *fakeRepository) RenewVPNConnectionLease(_ context.Context, input RenewVPNConnectionLeaseInput, expiresAt time.Time) (VPNConnectionLease, error) {
if f.renewVPNLeaseErr != nil {
return VPNConnectionLease{}, f.renewVPNLeaseErr
}
return VPNConnectionLease{ID: input.LeaseID, VPNConnectionID: input.VPNConnectionID, ClusterID: input.ClusterID, OwnerNodeID: input.OwnerNodeID, FencingToken: input.FencingToken, Status: VPNLeaseStatusActive, ExpiresAt: expiresAt}, nil
}
func (f *fakeRepository) ReleaseVPNConnectionLease(_ context.Context, input ReleaseVPNConnectionLeaseInput) (VPNConnectionLease, error) {
return VPNConnectionLease{ID: input.LeaseID, VPNConnectionID: input.VPNConnectionID, ClusterID: input.ClusterID, OwnerNodeID: input.OwnerNodeID, FencingToken: input.FencingToken, Status: VPNLeaseStatusReleased}, nil
}
func (f *fakeRepository) FenceVPNConnectionLease(_ context.Context, input FenceVPNConnectionLeaseInput) (VPNConnectionLease, error) {
return VPNConnectionLease{ID: input.LeaseID, VPNConnectionID: input.VPNConnectionID, ClusterID: input.ClusterID, Status: VPNLeaseStatusFenced}, nil
}
func (f *fakeRepository) GetActiveVPNConnectionLease(context.Context, string, string) (VPNConnectionLease, error) {
return VPNConnectionLease{ID: "lease-1", Status: VPNLeaseStatusActive}, nil
}
func (f *fakeRepository) CheckVPNLeaseOwnerEligibility(context.Context, string, string, string) (VPNLeaseOwnerEligibility, error) {
if f.ownerEligibilityErr != nil {
return VPNLeaseOwnerEligibility{}, f.ownerEligibilityErr
}
if f.ownerEligibility.VPNConnectionID != "" {
return f.ownerEligibility, nil
}
return VPNLeaseOwnerEligibility{
VPNConnectionID: "vpn-1",
ClusterID: "cluster-1",
OrganizationID: "org-1",
OwnerNodeID: "node-1",
MembershipStatus: "active",
NodeRegistrationStatus: NodeRegistrationActive,
AllowedByPolicy: true,
HasAuthorizedRole: true,
}, nil
}
func (f *fakeRepository) ExpireStaleVPNConnectionLeases(context.Context, string, time.Time) ([]VPNConnectionLease, error) {
return f.expiredVPNLeases, nil
}
func (f *fakeRepository) ListNodeVPNAssignments(context.Context, string, string) ([]NodeVPNAssignment, error) {
return f.nodeVPNAssignments, nil
}
func (f *fakeRepository) ReportNodeVPNAssignmentStatus(_ context.Context, input ReportNodeVPNAssignmentStatusInput) (NodeVPNAssignmentStatus, error) {
return NodeVPNAssignmentStatus{
ID: "status-1",
VPNConnectionID: input.VPNConnectionID,
ClusterID: input.ClusterID,
NodeID: input.NodeID,
ObservedStatus: input.ObservedStatus,
StatusPayload: input.StatusPayload,
ObservedAt: input.ObservedAt,
}, nil
}
func (f *fakeRepository) RecordAudit(_ context.Context, event ClusterAuditEvent) error {
f.auditEvents = append(f.auditEvents, event)
return nil
}
func (f *fakeRepository) ListAuditEvents(context.Context, string, int) ([]ClusterAuditEvent, error) {
return nil, nil
}