Skip to content

Commit 07839bb

Browse files
authored
Merge pull request #113 from leaseweb/claude_code_audit
Claude code audit
2 parents b080868 + 897122b commit 07839bb

File tree

5 files changed

+72
-20
lines changed

5 files changed

+72
-20
lines changed

.golangci.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ linters:
1414
disable:
1515
- goheader
1616
- depguard
17-
- wrapcheck
1817
- mnd
1918
- varnamelen
2019
- testpackage
@@ -30,7 +29,6 @@ linters:
3029
- interfacebloat
3130
- exhaustruct
3231
- lll
33-
- gosec
3432
- gomoddirectives
3533
- godox
3634
- gochecknoinits

cloudstack/cloudstack.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ func newCSCloud(cfg *CSConfig) (*CSCloud, error) {
9898
}
9999

100100
if cs.client == nil {
101-
return nil, errors.New("no cloud provider config given")
101+
return nil, errors.New("cloud provider configuration incomplete: api-url, api-key, and secret-key are all required")
102102
}
103103

104104
return cs, nil

cloudstack/cloudstack_instances.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ import (
3131
)
3232

3333
func (cs *CSCloud) nodeAddresses(instance *cloudstack.VirtualMachine) ([]corev1.NodeAddress, error) {
34+
if instance == nil {
35+
return nil, errors.New("instance is nil")
36+
}
37+
3438
if len(instance.Nic) == 0 {
3539
return nil, errors.New("instance does not have an internal IP")
3640
}

cloudstack/cloudstack_loadbalancer.go

Lines changed: 59 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -142,14 +142,26 @@ func (cs *CSCloud) EnsureLoadBalancer(ctx context.Context, clusterName string, s
142142
cs.eventRecorder.Event(service, corev1.EventTypeNormal, "CreatedLoadBalancer", msg)
143143
klog.Info(msg)
144144
} else if service.Spec.LoadBalancerIP != "" && service.Spec.LoadBalancerIP != lb.ipAddr {
145-
// LoadBalancerIP was specified and it's different from the current IP
145+
// LoadBalancerIP was specified and it's different from the current IP.
146+
// Validate the target IP exists before tearing down the old config to avoid
147+
// leaving the service in a broken state if the new IP is invalid.
148+
if err := lb.validatePublicIPAvailable(service.Spec.LoadBalancerIP); err != nil {
149+
return nil, fmt.Errorf("cannot switch load balancer to IP %s: %w", service.Spec.LoadBalancerIP, err)
150+
}
151+
146152
// Release the old IP first
147153
klog.V(4).Infof("Deleting firewall rules for old ip and releasing old load balancer IP %v, switching to specified IP %v", lb.ipAddr, service.Spec.LoadBalancerIP)
148154

149155
// Best-effort cleanup of existing rules bound to the current IP to avoid stale deletes / name conflicts.
150156
for _, oldRule := range lb.rules {
151157
proto := ProtocolFromLoadBalancer(oldRule.Protocol)
158+
if proto == LoadBalancerProtocolInvalid {
159+
klog.Warningf("Skipping firewall cleanup for rule %s: unrecognized protocol %q", oldRule.Name, oldRule.Protocol)
160+
}
152161
port64, pErr := strconv.ParseInt(oldRule.Publicport, 10, 32)
162+
if pErr != nil {
163+
klog.Warningf("Skipping firewall cleanup for rule %s: cannot parse port %q: %v", oldRule.Name, oldRule.Publicport, pErr)
164+
}
153165
if proto != LoadBalancerProtocolInvalid && pErr == nil {
154166
if _, fwErr := lb.deleteFirewallRule(oldRule.Publicipid, int(port64), proto); fwErr != nil {
155167
klog.V(4).Infof("Ignoring firewall rule delete error for %s: %v", oldRule.Name, fwErr)
@@ -240,10 +252,10 @@ func (cs *CSCloud) EnsureLoadBalancer(ctx context.Context, clusterName string, s
240252
network, count, err := lb.Network.GetNetworkByID(lb.networkID, cloudstack.WithProject(lb.projectID))
241253
if err != nil {
242254
if count == 0 {
243-
return nil, err
255+
return nil, fmt.Errorf("could not find network with ID %s: %w", lb.networkID, err)
244256
}
245257

246-
return nil, err
258+
return nil, fmt.Errorf("failed to get network with ID %s: %w", lb.networkID, err)
247259
}
248260

249261
lbSourceRanges, err := getLoadBalancerSourceRanges(service)
@@ -636,7 +648,7 @@ func (cs *CSCloud) listAllVirtualMachines() ([]*cloudstack.VirtualMachine, error
636648

637649
l, err := cs.client.VirtualMachine.ListVirtualMachines(p)
638650
if err != nil {
639-
return nil, err
651+
return nil, fmt.Errorf("failed to list virtual machines: %w", err)
640652
}
641653

642654
allVMs = append(allVMs, l.VirtualMachines...)
@@ -665,6 +677,31 @@ func (lb *loadBalancer) getLoadBalancerIP(loadBalancerIP string) error {
665677
return lb.associatePublicIPAddress()
666678
}
667679

680+
// validatePublicIPAvailable checks that the given IP address exists in CloudStack
681+
// without modifying any load balancer state. Used as a pre-flight check before
682+
// tearing down an existing configuration.
683+
func (lb *loadBalancer) validatePublicIPAvailable(ip string) error {
684+
p := lb.Address.NewListPublicIpAddressesParams()
685+
p.SetIpaddress(ip)
686+
p.SetAllocatedonly(false)
687+
p.SetListall(true)
688+
689+
if lb.projectID != "" {
690+
p.SetProjectid(lb.projectID)
691+
}
692+
693+
l, err := lb.Address.ListPublicIpAddresses(p)
694+
if err != nil {
695+
return fmt.Errorf("error looking up IP address %v: %w", ip, err)
696+
}
697+
698+
if l.Count != 1 {
699+
return fmt.Errorf("IP address %v not found (got %d results)", ip, l.Count)
700+
}
701+
702+
return nil
703+
}
704+
668705
// getPublicIPAddressID retrieves the ID of the given IP, and sets the address and its ID.
669706
func (lb *loadBalancer) getPublicIPAddress(loadBalancerIP string) error {
670707
klog.V(4).Infof("Retrieve load balancer IP details: %v", loadBalancerIP)
@@ -784,8 +821,11 @@ func (lb *loadBalancer) updateLoadBalancerRule(lbRuleName string, protocol LoadB
784821
p.SetProtocol(protocol.CSProtocol())
785822

786823
_, err := lb.LoadBalancer.UpdateLoadBalancerRule(p)
824+
if err != nil {
825+
return fmt.Errorf("failed to update loadbalancer rule with ID %s: %w", lbRule.Id, err)
826+
}
787827

788-
return err
828+
return nil
789829
}
790830

791831
// createLoadBalancerRule creates a new load balancer rule and returns its ID.
@@ -933,6 +973,10 @@ func symmetricDifference(hostIDs []string, lbInstances []*cloudstack.VirtualMach
933973

934974
var remove []string //nolint:prealloc
935975
for _, instance := range lbInstances {
976+
if instance == nil {
977+
continue
978+
}
979+
936980
if newIDs[instance.Id] {
937981
delete(newIDs, instance.Id)
938982

@@ -1088,12 +1132,13 @@ func (lb *loadBalancer) updateFirewallRule(publicIPID string, publicPort int, pr
10881132
// delete all other rules that didn't match the CIDR list
10891133
// do this first to prevent CS rule conflict errors
10901134
klog.V(4).Infof("Firewall rules to be deleted for %v: %v", lb.ipAddr, rulesMapToString(filtered))
1135+
var deleteErr error
10911136
for rule := range filtered {
10921137
p := lb.Firewall.NewDeleteFirewallRuleParams(rule.Id)
1093-
_, err = lb.Firewall.DeleteFirewallRule(p)
1094-
if err != nil {
1138+
if _, err = lb.Firewall.DeleteFirewallRule(p); err != nil {
10951139
// report the error, but keep on deleting the other rules
10961140
klog.Errorf("Error deleting old firewall rule %v: %v", rule.Id, err)
1141+
deleteErr = err
10971142
}
10981143
}
10991144

@@ -1104,15 +1149,15 @@ func (lb *loadBalancer) updateFirewallRule(publicIPID string, publicPort int, pr
11041149
p.SetCidrlist(allowedCIDRs)
11051150
p.SetStartport(publicPort)
11061151
p.SetEndport(publicPort)
1107-
_, err = lb.Firewall.CreateFirewallRule(p)
1108-
if err != nil {
1152+
if _, err = lb.Firewall.CreateFirewallRule(p); err != nil {
11091153
// return immediately if we can't create the new rule
11101154
return false, fmt.Errorf("error creating new firewall rule for public IP %v, proto %v, port %v, allowed %v: %w", publicIPID, protocol, publicPort, allowedCIDRs, err)
11111155
}
11121156
}
11131157

1114-
// return true (because we changed something), but also the last error if deleting one old rule failed
1115-
return true, err
1158+
changed := match == nil || len(filtered) > 0
1159+
1160+
return changed, deleteErr
11161161
}
11171162

11181163
// deleteFirewallRule deletes the firewall rule associated with the ip:port:protocol combo
@@ -1139,18 +1184,20 @@ func (lb *loadBalancer) deleteFirewallRule(publicIPID string, publicPort int, pr
11391184
}
11401185

11411186
// delete all rules
1187+
var errs error
11421188
deleted := false
11431189
for _, rule := range filtered {
11441190
p := lb.Firewall.NewDeleteFirewallRuleParams(rule.Id)
11451191
_, err = lb.Firewall.DeleteFirewallRule(p)
11461192
if err != nil {
11471193
klog.Errorf("Error deleting old firewall rule %v: %v", rule.Id, err)
1194+
errs = errors.Join(errs, fmt.Errorf("error deleting old firewall rule %v: %w", rule.Id, err))
11481195
} else {
11491196
deleted = true
11501197
}
11511198
}
11521199

1153-
return deleted, err
1200+
return deleted, errs
11541201
}
11551202

11561203
// getLoadBalancerSourceRanges first tries to parse and verify loadBalancerSourceRanges field from a Service object.

cloudstack/cloudstack_loadbalancer_test.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1952,8 +1952,8 @@ func TestUpdateFirewallRule(t *testing.T) {
19521952
if err != nil {
19531953
t.Fatalf("unexpected error: %v", err)
19541954
}
1955-
if !updated {
1956-
t.Errorf("updated = false, want true")
1955+
if updated {
1956+
t.Errorf("updated = true, want false (nothing changed)")
19571957
}
19581958
})
19591959

@@ -2159,9 +2159,12 @@ func TestUpdateFirewallRule(t *testing.T) {
21592159
}
21602160

21612161
updated, err := lb.updateFirewallRule("ip-123", 80, LoadBalancerProtocolTCP, []string{"10.0.0.0/8"})
2162-
// Should still return true even if delete failed
2163-
if err != nil && !strings.Contains(err.Error(), "error creating") {
2164-
t.Fatalf("unexpected error: %v", err)
2162+
// Should still return true even if delete failed, but the deletion error should be surfaced
2163+
if err == nil {
2164+
t.Fatalf("expected deletion error to be returned, got nil")
2165+
}
2166+
if !strings.Contains(err.Error(), "delete API error") {
2167+
t.Fatalf("expected deletion error, got: %v", err)
21652168
}
21662169
if !updated {
21672170
t.Errorf("updated = false, want true")

0 commit comments

Comments
 (0)