Repository: crossplane/provider-aws (go)

Issue:
ec2.sg: panic when sorting ingress/egress rules without port (ipProtocol -1)
### What happened?
panic when sorting ingress/egress rules
```
crossplane-provider-aws-c2ea9b021877-7795f8c8d9-c72tw provider-aws panic: runtime error: invalid memory address or nil pointer dereference [recovered]
crossplane-provider-aws-c2ea9b021877-7795f8c8d9-c72tw provider-aws 	panic: runtime error: invalid memory address or nil pointer dereference
crossplane-provider-aws-c2ea9b021877-7795f8c8d9-c72tw provider-aws [signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x1dc6042]
crossplane-provider-aws-c2ea9b021877-7795f8c8d9-c72tw provider-aws 
crossplane-provider-aws-c2ea9b021877-7795f8c8d9-c72tw provider-aws goroutine 1589 [running]:
crossplane-provider-aws-c2ea9b021877-7795f8c8d9-c72tw provider-aws k8s.io/apimachinery/pkg/util/runtime.HandleCrash(0x0, 0x0, 0x0)
crossplane-provider-aws-c2ea9b021877-7795f8c8d9-c72tw provider-aws 	/home/.../src/provider-aws/.work/pkg/pkg/mod/k8s.io/apimachinery@v0.20.1/pkg/util/runtime/runtime.go:55 +0x109
crossplane-provider-aws-c2ea9b021877-7795f8c8d9-c72tw provider-aws panic(0x272c760, 0x47ec060)
crossplane-provider-aws-c2ea9b021877-7795f8c8d9-c72tw provider-aws 	/home/.../opt/go/src/runtime/panic.go:965 +0x1b9
crossplane-provider-aws-c2ea9b021877-7795f8c8d9-c72tw provider-aws github.com/crossplane/provider-aws/pkg/clients/ec2.CreateSGPatch.func1(0x6, 0x0, 0x2646d60)
crossplane-provider-aws-c2ea9b021877-7795f8c8d9-c72tw provider-aws 	/home/.../src/provider-aws/pkg/clients/ec2/securitygroup.go:308 +0x42
crossplane-provider-aws-c2ea9b021877-7795f8c8d9-c72tw provider-aws sort.quickSort_func(0xc0017d89f0, 0xc00123f950, 0x0, 0x8, 0x8)
crossplane-provider-aws-c2ea9b021877-7795f8c8d9-c72tw provider-aws 	/home/.../opt/go/src/sort/zfuncversion.go:154 +0x1b8
crossplane-provider-aws-c2ea9b021877-7795f8c8d9-c72tw provider-aws sort.Slice(0x2554260, 0xc001c2a228, 0xc0017d89f0)
crossplane-provider-aws-c2ea9b021877-7795f8c8d9-c72tw provider-aws 	/home/.../opt/go/src/sort/slice.go:20 +0xe8
crossplane-provider-aws-c2ea9b021877-7795f8c8d9-c72tw provider-aws github.com/crossplane/provider-aws/pkg/clients/ec2.CreateSGPatch(0xc0011b4e40, 0xc0011b4e70, 0xc0011b4ea0, 0xc001173980, 0x1, 0x1, 0xc0008e4e00, 0x7, 0x7, 0xc0011b55d0, ...)
crossplane-provider-aws-c2ea9b021877-7795f8c8d9-c72tw provider-aws 	/home/.../src/provider-aws/pkg/clients/ec2/securitygroup.go:307 +0x50d
```


### How can we reproduce it?
```
apiVersion: ec2.aws.crossplane.io/v1beta1
kind: SecurityGroup
metadata:
  name: test
spec:
  forProvider:
    description: test
    groupName: test
    ingress:
    - ipProtocol: "-1"
      ipRanges:
      - cidrIp: 10.0.1.0/24
    - ipProtocol: "-1"
      ipRanges:
      - cidrIp: 10.0.4.0/24
    region: eu-north-1
    vpcId: ...
  providerConfigRef:
    name: default
```

### What environment did it happen in?
Crossplane version: 0.17

<!--
Include at least the version or commit of Crossplane you were running. Consider
also including your:

* Cloud provider or hardware configuration
* Kubernetes version (use `kubectl version`)
* Kubernetes distribution (e.g. Tectonic, GKE, OpenShift)
* OS (e.g. from /etc/os-release)
* Kernel (e.g. `uname -a`)
-->


Pull request description:
ec2.securitygroup: Handle nil fromPort/toPort (ipProtocol -1)
### Description of your changes

When ipProtocol is -1, fromPort/toPort will be nil. This causes a panic
when sorting ingress/egress rules. We just need a stable sort so we can
use an aws helper to get 0 for the value in that case.

Also add a normal test for the sort functions (have more than one item so we will sort something).

Fixes #616

I have:

- [x] Read and followed Crossplane's [contribution process].
- [x] Run `make reviewable test` to ensure this PR is ready for review.

### How has this code been tested

* Unit test
* YAML from #616

[contribution process]: https://git.io/fj2m9


Patch:
diff --git a/pkg/clients/ec2/securitygroup.go b/pkg/clients/ec2/securitygroup.go
index 9f86bdace..77a808e7c 100644
--- a/pkg/clients/ec2/securitygroup.go
+++ b/pkg/clients/ec2/securitygroup.go
@@ -150,7 +150,7 @@ func GenerateIPPermissions(objectPerms []ec2.IpPermission) []v1beta1.IPPermissio
 		permissions[i] = ipPerm
 	}
 	sort.Slice(permissions, func(i, j int) bool {
-		return *permissions[i].FromPort < *permissions[j].FromPort
+		return aws.Int64Value(permissions[i].FromPort) < aws.Int64Value(permissions[j].FromPort)
 	})
 	return permissions
 }
@@ -304,10 +304,10 @@ func CreateSGPatch(in ec2.SecurityGroup, target v1beta1.SecurityGroupParameters)
 	}
 
 	sort.Slice(target.Egress, func(i, j int) bool {
-		return *target.Egress[i].FromPort < *target.Egress[j].FromPort
+		return aws.Int64Value(target.Egress[i].FromPort) < aws.Int64Value(target.Egress[j].FromPort)
 	})
 	sort.Slice(target.Ingress, func(i, j int) bool {
-		return *target.Ingress[i].FromPort < *target.Ingress[j].FromPort
+		return aws.Int64Value(target.Ingress[i].FromPort) < aws.Int64Value(target.Ingress[j].FromPort)
 	})
 
 	jsonPatch, err := awsclients.CreateJSONPatch(*currentParams, target)


Test patch:
diff --git a/pkg/clients/ec2/securitygroup_test.go b/pkg/clients/ec2/securitygroup_test.go
index a68401192..16eece793 100644
--- a/pkg/clients/ec2/securitygroup_test.go
+++ b/pkg/clients/ec2/securitygroup_test.go
@@ -20,9 +20,9 @@ var (
 	sgOwner    = "some owner"
 )
 
-func specIPPermsision(port int) []v1beta1.IPPermission {
-	return []v1beta1.IPPermission{
-		{
+func specIPPermsision(ports ...int) (ret []v1beta1.IPPermission) {
+	for _, port := range ports {
+		ret = append(ret, v1beta1.IPPermission{
 			FromPort:   aws.Int64(int64(port)),
 			ToPort:     aws.Int64(int64(port)),
 			IPProtocol: "tcp",
@@ -31,13 +31,14 @@ func specIPPermsision(port int) []v1beta1.IPPermission {
 					CIDRIP: sgCidr,
 				},
 			},
-		},
+		})
 	}
+	return ret
 }
 
-func sgIPPermission(port int) []ec2.IpPermission {
-	return []ec2.IpPermission{
-		{
+func sgIPPermission(ports ...int) (ret []ec2.IpPermission) {
+	for _, port := range ports {
+		ret = append(ret, ec2.IpPermission{
 			FromPort:   aws.Int64(int64(port)),
 			ToPort:     aws.Int64(int64(port)),
 			IpProtocol: aws.String(sgProtocol),
@@ -46,8 +47,9 @@ func sgIPPermission(port int) []ec2.IpPermission {
 					CidrIp: aws.String(sgCidr),
 				},
 			},
-		},
+		})
 	}
+	return ret
 }
 
 func TestIsSGUpToDate(t *testing.T) {
@@ -77,6 +79,23 @@ func TestIsSGUpToDate(t *testing.T) {
 			},
 			want: true,
 		},
+		"SameFieldsUnsorted": {
+			args: args{
+				sg: ec2.SecurityGroup{
+					Description:   aws.String(sgDesc),
+					GroupName:     aws.String(sgName),
+					VpcId:         aws.String(sgVpc),
+					IpPermissions: sgIPPermission(80, 100, 90),
+				},
+				p: v1beta1.SecurityGroupParameters{
+					Description: sgDesc,
+					GroupName:   sgName,
+					VPCID:       aws.String(sgVpc),
+					Ingress:     specIPPermsision(100, 90, 80),
+				},
+			},
+			want: true,
+		},
 		"DifferentFields": {
 			args: args{
 				sg: ec2.SecurityGroup{
@@ -176,6 +195,27 @@ func TestCreateSGPatch(t *testing.T) {
 				patch: &v1beta1.SecurityGroupParameters{},
 			},
 		},
+		"SameFieldsNilPort": {
+			args: args{
+				sg: ec2.SecurityGroup{
+					Description:         aws.String(sgDesc),
+					GroupName:           aws.String(sgName),
+					IpPermissions:       nil,
+					IpPermissionsEgress: append(sgIPPermission(80), ec2.IpPermission{IpProtocol: aws.String("-1")}),
+					VpcId:               aws.String(sgVpc),
+				},
+				p: &v1beta1.SecurityGroupParameters{
+					Description: sgDesc,
+					GroupName:   sgName,
+					Egress:      append(specIPPermsision(80), v1beta1.IPPermission{IPProtocol: "-1"}),
+					Ingress:     nil,
+					VPCID:       aws.String(sgVpc),
+				},
+			},
+			want: want{
+				patch: &v1beta1.SecurityGroupParameters{},
+			},
+		},
 		"DifferentFields": {
 			args: args{
 				sg: ec2.SecurityGroup{