Repository: derailed/popeye (Go)

Issue:
Configmaps and Secrets in a projected volume not detected as used
<img src="https://raw.githubusercontent.com/derailed/popeye/master/assets/popeye_bug.png" align="right" width="100" height="auto"/>

<br/>
<br/>
<br/>


**Describe the bug**
Projected volumes are not checked for config maps and secrets so they get reported as potentially unused.

**To Reproduce**
Steps to reproduce the behavior:
1. Have a pod/deployment with a projected volume that is comprised of multiple items (configmaps and/or secrets)
2. Run popeye

**Expected behavior**
Since the configmaps/secrets are mapped to the pod/deployment via the projected volume, I would expect they get reported as used.

**Versions (please complete the following information):**
 - OS: OSX
 - Popeye 0.21.5
 - K8s 1.27.11




Discussion:
Am seeing the same behavior.



Patch:
diff --git a/internal/cache/pod.go b/internal/cache/pod.go
index c77a78e4..c1f9bc6b 100644
--- a/internal/cache/pod.go
+++ b/internal/cache/pod.go
@@ -80,6 +80,21 @@ func (*Pod) volumeRefs(ns string, vv []v1.Volume, refs *sync.Map) {
 		if cmv != nil {
 			addKeys(ConfigMapKey, FQN(ns, cmv.LocalObjectReference.Name), cmv.Items, refs)
 		}
+
+		if v.VolumeSource.Projected != nil {
+			vp := v.VolumeSource.Projected.Sources
+			for _, projection := range vp {
+				ps := projection.Secret
+				if ps != nil {
+					addKeys(SecretKey, FQN(ns, ps.Name), ps.Items, refs)
+				}
+
+				pcm := projection.ConfigMap
+				if pcm != nil {
+					addKeys(ConfigMapKey, FQN(ns, pcm.Name), pcm.Items, refs)
+				}
+			}
+		}
 	}
 }
 


Test patch:
diff --git a/internal/lint/cm_test.go b/internal/lint/cm_test.go
index 986e86f8..8dd67cee 100644
--- a/internal/lint/cm_test.go
+++ b/internal/lint/cm_test.go
@@ -33,9 +33,7 @@ func TestConfigMapLint(t *testing.T) {
 	assert.Equal(t, rules.InfoLevel, ii[0].Level)
 
 	ii = cm.Outcome()["default/cm2"]
-	assert.Equal(t, 1, len(ii))
-	assert.Equal(t, "[POP-400] Used? Unable to locate resource reference", ii[0].Message)
-	assert.Equal(t, rules.InfoLevel, ii[0].Level)
+	assert.Equal(t, 0, len(ii))
 
 	ii = cm.Outcome()["default/cm3"]
 	assert.Equal(t, 0, len(ii))
diff --git a/internal/lint/sec_test.go b/internal/lint/sec_test.go
index 9c0556c9..e02642ce 100644
--- a/internal/lint/sec_test.go
+++ b/internal/lint/sec_test.go
@@ -36,9 +36,7 @@ func TestSecretLint(t *testing.T) {
 	assert.Equal(t, rules.InfoLevel, ii[0].Level)
 
 	ii = sec.Outcome()["default/sec2"]
-	assert.Equal(t, 1, len(ii))
-	assert.Equal(t, `[POP-400] Used? Unable to locate resource reference`, ii[0].Message)
-	assert.Equal(t, rules.InfoLevel, ii[0].Level)
+	assert.Equal(t, 0, len(ii))
 
 	ii = sec.Outcome()["default/sec3"]
 	assert.Equal(t, 1, len(ii))
diff --git a/internal/lint/testdata/core/pod/1.yaml b/internal/lint/testdata/core/pod/1.yaml
index fe35bd0a..d0565aa7 100644
--- a/internal/lint/testdata/core/pod/1.yaml
+++ b/internal/lint/testdata/core/pod/1.yaml
@@ -65,6 +65,23 @@ items:
           path: "game.properties"
         - key: namespace
           path: "user-interface.properties"
+    - name: projected
+      projected:
+        sources:
+          - secret:
+              name: sec2
+              items:
+                - key: admin-user
+                  path: "user"
+                - key: admin-password
+                  path: "password"
+          - configMap:
+              name: cm2
+              items:
+                - key: k1
+                  path: "k1"
+                - key: k2
+                  path: "k2"
   status:
     podIPs:
     - ip: 172.1.0.3