Repository: FairwindsOps/polaris (go)

Issue:
Exception in Polaris 9.2.0 when PDB uses spec.maxUnavailable instead of spec.minAvailable
### What happened?

After upgrading to Polaris 9.2.0, we get the attached exception in our pipelines:
[pipeline-output.txt](https://github.com/user-attachments/files/16285206/pipeline-output.txt)

Some of our PodDisruptionBudgets are configured to use `spec.maxUnavailable` rather than `spec.minAvailable`, which is valid according to the `PodDisruptionBudget` spec, and which is even included in [Kubernetes documentation examples](https://kubernetes.io/docs/tasks/run-application/configure-pdb/#specifying-a-poddisruptionbudget).

I believe the root problem is in the `pdbMinAvailableGreaterThanHPAMinReplicas` function, which does not check to see if `attachedPDB.Spec.MinAvailable` has a value before passing it to `getIntOrPercentValueSafely`, in [this section of the function](https://github.com/FairwindsOps/polaris/commit/952b6aed65ed971bf64a64c2698c3df3905248cc#diff-8cf7e477f7fe55b5d41511f169b90a87607ea711e4fd7c894d77049aa020fde9R50-R54)


### What did you expect to happen?

I expect Polaris to not throw an exception for PDBs that adhere to the PodDisruptionBudget spec.

### How can we reproduce this?

1. Save the following as `app.yaml`
    ```yaml
    apiVersion: policy/v1
    kind: PodDisruptionBudget
    metadata:  
      name: "app-pdb"
      labels:
        app.kubernetes.io/name: "app"
    spec:
      maxUnavailable: 25%
      selector:
        matchLabels:
          app.kubernetes.io/name: "app"
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:  
      name: "app-deployment"
      labels:
        app.kubernetes.io/name: "app"
    spec:  
      selector:
        matchLabels:
          app.kubernetes.io/name: "app"
      revisionHistoryLimit: 3
      template:
        metadata:
          labels:
            app.kubernetes.io/name: "app"
        spec:
          containers:
            - name: container
              image: "alpine"
              resources: {}
    ---
    apiVersion: autoscaling/v2
    kind: HorizontalPodAutoscaler
    metadata: 
      name: "app-hpa"
      labels:
        app.kubernetes.io/name: "app"
    spec:
      scaleTargetRef:
        apiVersion: apps/v1
        kind: Deployment
        name: app-deployment
      minReplicas: 2
      maxReplicas: 4
      metrics:
      - type: Resource
        resource:
          name: cpu
          target:
            type: Utilization
            averageUtilization: 70
    ```
 1. using Polaris version 9.2.0, run `polaris audit --audit-path app.yaml`

### Version

9.2.0

### Search

- [X] I did search for other open and closed issues before opening this.

### Code of Conduct

- [X] I agree to follow this project's Code of Conduct

### Additional context

_No response_

Pull request description:
pdbMinAvailableGreaterThanHPAMinReplicas should support optional minAvailable
By spec, `minAvailable` is optional, and we should accommodate for that

This PR fixes #1061

## Checklist
* [X] I have signed the CLA
* [X] I have updated/added any relevant documentation

## Description
### What's the goal of this PR?

### What changes did you make?

### What alternative solution should we consider, if any?



Patch:
diff --git a/pkg/validator/pdb_hpa_validator.go b/pkg/validator/pdb_hpa_validator.go
index e613df00..4f1ecb3a 100644
--- a/pkg/validator/pdb_hpa_validator.go
+++ b/pkg/validator/pdb_hpa_validator.go
@@ -21,7 +21,6 @@ func init() {
 
 func pdbMinAvailableGreaterThanHPAMinReplicas(test schemaTestCase) (bool, []jsonschema.ValError, error) {
 	if test.ResourceProvider == nil {
-		logrus.Debug("ResourceProvider is nil")
 		return true, nil, nil
 	}
 
@@ -47,6 +46,10 @@ func pdbMinAvailableGreaterThanHPAMinReplicas(test schemaTestCase) (bool, []json
 	if attachedPDB != nil && attachedHPA != nil {
 		logrus.Debugf("both PDB and HPA are attached to deployment %s", deployment.Name)
 
+		if attachedPDB.Spec.MinAvailable == nil {
+			return true, nil, nil
+		}
+
 		pdbMinAvailable, isPercent, err := getIntOrPercentValueSafely(attachedPDB.Spec.MinAvailable)
 		if err != nil {
 			logrus.Warnf("error getting getIntOrPercentValueSafely: %v", err)
@@ -56,7 +59,6 @@ func pdbMinAvailableGreaterThanHPAMinReplicas(test schemaTestCase) (bool, []json
 		if isPercent {
 			// if the value is a percentage, we need to calculate the actual value
 			if attachedHPA.Spec.MinReplicas == nil {
-				logrus.Debug("attachedHPA.Spec.MinReplicas is nil")
 				return true, nil, nil
 			}
 
@@ -90,7 +92,6 @@ func hasPDBAttached(deployment appsv1.Deployment, pdbs []kube.GenericResource) (
 		}
 
 		if pdb.Spec.Selector == nil {
-			logrus.Debug("pdb.Spec.Selector is nil")
 			continue
 		}
 


Test patch:
diff --git a/test/checks/pdbMinAvailableGreaterThanHPAMinReplicas/success-maxUnavailable.yaml b/test/checks/pdbMinAvailableGreaterThanHPAMinReplicas/success-maxUnavailable.yaml
new file mode 100644
index 00000000..be80d90a
--- /dev/null
+++ b/test/checks/pdbMinAvailableGreaterThanHPAMinReplicas/success-maxUnavailable.yaml
@@ -0,0 +1,43 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: zookeeper
+spec:
+  template:
+    metadata:
+      labels:
+        app.kubernetes.io/name: zookeeper
+        foo: bar
+    spec:
+      containers:
+        - name: zookeeper
+          image: zookeeper
+---
+apiVersion: policy/v1
+kind: PodDisruptionBudget
+metadata:
+  name: zookeeper-pdb
+spec:
+  maxUnavailable: 5
+  selector:
+    matchLabels:
+      app.kubernetes.io/name: zookeeper
+---
+apiVersion: autoscaling/v2
+kind: HorizontalPodAutoscaler
+metadata:
+  name: zookeeper-hpa
+spec:
+  scaleTargetRef:
+    apiVersion: apps/v1
+    kind: Deployment
+    name: zookeeper
+  minReplicas: 5
+  maxReplicas: 7
+  metrics:
+    - type: Resource
+      resource:
+        name: cpu
+        target:
+          type: Utilization
+          averageUtilization: 50