package main import ( "context" "net" "testing" "time" "github.com/oracle/oci-go-sdk/v65/common" "github.com/oracle/oci-go-sdk/v65/core" ) type recordingNSGClient struct { request core.UpdateNetworkSecurityGroupSecurityRulesRequest calls int rules []core.SecurityRule } func (c *recordingNSGClient) UpdateNetworkSecurityGroupSecurityRules(_ context.Context, request core.UpdateNetworkSecurityGroupSecurityRulesRequest) (core.UpdateNetworkSecurityGroupSecurityRulesResponse, error) { c.request = request c.calls++ return core.UpdateNetworkSecurityGroupSecurityRulesResponse{ UpdatedNetworkSecurityGroupSecurityRules: core.UpdatedNetworkSecurityGroupSecurityRules{SecurityRules: c.rules}, }, nil } func returnedRule(id, source string, port int) core.SecurityRule { return core.SecurityRule{ Direction: core.SecurityRuleDirectionIngress, Id: common.String(id), Protocol: common.String("17"), Source: common.String(source), SourceType: core.SecurityRuleSourceTypeCidrBlock, IsStateless: common.Bool(false), UdpOptions: &core.UdpOptions{DestinationPortRange: &core.PortRange{Min: common.Int(port), Max: common.Int(port)}}, } } func TestOCIReconcilerUpdatesOnlyConfiguredWireGuardRule(t *testing.T) { client := &recordingNSGClient{rules: []core.SecurityRule{returnedRule("rule", "203.0.113.7/32", 51820)}} probed := false reconciler := &ociReconciler{ client: client, networkSecurityGroup: "nsg", securityRule: "rule", wireguardDestinationPort: 51820, wireguardURL: "http://relay.test:19100/metrics", recoveryTimeout: time.Minute, probeWireGuard: func(_ context.Context, address string, timeout time.Duration) error { probed = address == "http://relay.test:19100/metrics" && timeout == time.Minute return nil }, } if err := reconciler.Reconcile(context.Background(), net.ParseIP("203.0.113.7")); err != nil { t.Fatal(err) } rules := client.request.SecurityRules if len(rules) != 1 { t.Fatalf("rule count = %d", len(rules)) } rule := rules[0] if *rule.Id != "rule" || *rule.Source != "203.0.113.7/32" || *rule.Protocol != "17" { t.Fatalf("unexpected rule: %#v", rule) } if rule.UdpOptions == nil || *rule.UdpOptions.DestinationPortRange.Min != 51820 || *rule.UdpOptions.DestinationPortRange.Max != 51820 { t.Fatalf("unexpected UDP options: %#v", rule.UdpOptions) } if !probed { t.Fatal("WireGuard connectivity was not probed") } } func TestOCIReconcilerRejectsUnexpectedUpdatedRule(t *testing.T) { client := &recordingNSGClient{rules: []core.SecurityRule{returnedRule("other", "203.0.113.7/32", 51820)}} reconciler := &ociReconciler{ client: client, networkSecurityGroup: "nsg", securityRule: "rule", wireguardDestinationPort: 51820, probeWireGuard: func(context.Context, string, time.Duration) error { return nil }, } if err := reconciler.Reconcile(context.Background(), net.ParseIP("203.0.113.7")); err == nil { t.Fatal("expected returned rule rejection") } } func TestOCIReconcilerRejectsPrivateSource(t *testing.T) { reconciler := &ociReconciler{client: &recordingNSGClient{}, networkSecurityGroup: "nsg", securityRule: "rule", wireguardDestinationPort: 51820} if err := reconciler.Reconcile(context.Background(), net.ParseIP("10.180.186.43")); err == nil { t.Fatal("expected private source rejection") } }