Repository: Checkmarx/kics (language: python)

Issue:
bug(ansible): not detecting yaml inventory since v1.7.11
Since Version 1.7.11 the yaml inventory files are not detected anymore and therefor not scanned.

### Expected Behavior
With v1.7.10 I get the expanded behavior
docker run -t -v /path/to/inventory:/path checkmarx/kics:v1.7.10 scan -p /path

`Scanning with Keeping Infrastructure as Code Secure v1.7.10


Preparing Scan Assets: Done
Executing queries: [---------------------------------------------------] 100.00%

Files scanned: 332
Parsed files: 329
Queries loaded: 292
Queries failed to execute: 0`

and e.g., secrets in them are correct detected
### Actual Behavior
With v1.7.11 no files are detected
docker run -t -v /path/to/inventory:/path checkmarx/kics:latest scan -p /path
`Scanning with Keeping Infrastructure as Code Secure v1.7.11


Files scanned: 0
Parsed files: 0
Queries loaded: 0
Queries failed to execute: 0`

### Steps to Reproduce the Problem
The inventory folder contains multiple yaml files with hosts:
group1.yml
```
---
# group1
group1:
  hosts:
    host1.tld
    host2.tld

# sub group
sub_group:
  hosts:
    host2.tld

groups:
  children:
    sub_group:
    group1:
```
and sub folders group_vars and host_vars with yaml files for vars
group_vars/sub_group.yml
```
---
mysql_innodb_large_prefix: 0
mysql_skip_name_resolve: true
mysql_root_password: 'insecure'
```
### Specifications
-   Version: v1.7.11
-   Platform: host Debian 12



Discussion / hints:
Hi @timo-fc ,

Thank you for your input!
We are checking the situation and we will provide a fix for it asap.

Fix patch:
diff --git a/pkg/analyzer/analyzer.go b/pkg/analyzer/analyzer.go
index 5326c782681..e983e63435b 100644
--- a/pkg/analyzer/analyzer.go
+++ b/pkg/analyzer/analyzer.go
@@ -104,7 +104,9 @@ var (
 	listKeywordsAnsible = []string{"name", "gather_facts",
 		"hosts", "tasks", "become", "with_items", "with_dict",
 		"when", "become_pass", "become_exe", "become_flags"}
-	playBooks = "playbooks"
+	playBooks               = "playbooks"
+	ansibleHost             = "all"
+	listKeywordsAnsibleHots = []string{"hosts", "children"}
 )
 
 const (
@@ -552,6 +554,10 @@ func checkYamlPlatform(content []byte, path string) string {
 	if checkForAnsible(yamlContent) {
 		return ansible
 	}
+	// check if the file contains some keywords related with Ansible Host
+	if checkForAnsibleHost(yamlContent) {
+		return ansible
+	}
 	return ""
 }
 
@@ -574,6 +580,20 @@ func checkForAnsible(yamlContent model.Document) bool {
 	return isAnsible
 }
 
+func checkForAnsibleHost(yamlContent model.Document) bool {
+	isAnsible := false
+	if hosts := yamlContent[ansibleHost]; hosts != nil {
+		if listHosts, ok := hosts.(map[string]interface{}); ok {
+			for _, value := range listKeywordsAnsibleHots {
+				if host := listHosts[value]; host != nil {
+					isAnsible = true
+				}
+			}
+		}
+	}
+	return isAnsible
+}
+
 // computeValues computes expected Lines of Code to be scanned from locCount channel
 // and creates the types and unwanted slices from the channels removing any duplicates
 func computeValues(types, unwanted chan string, locCount chan int, done chan bool) (typesS, unwantedS []string, locTotal int) {


Test patch:
diff --git a/e2e/fixtures/E2E_CLI_075_RESULT.json b/e2e/fixtures/E2E_CLI_075_RESULT.json
new file mode 100644
index 00000000000..b466515b650
--- /dev/null
+++ b/e2e/fixtures/E2E_CLI_075_RESULT.json
@@ -0,0 +1,69 @@
+{
+	"kics_version": "development",
+	"files_scanned": 2,
+	"lines_scanned": 48,
+	"files_parsed": 2,
+	"lines_parsed": 48,
+	"lines_ignored": 0,
+	"files_failed_to_scan": 0,
+	"queries_total": 1,
+	"queries_failed_to_execute": 0,
+	"queries_failed_to_compute_similarity_id": 0,
+	"scan_id": "console",
+	"severity_counters": {
+		"HIGH": 0,
+		"INFO": 0,
+		"LOW": 0,
+		"MEDIUM": 2,
+		"TRACE": 0
+	},
+	"total_counter": 2,
+	"total_bom_resources": 0,
+	"start": "2023-11-23T15:54:44.1211396Z",
+	"end": "2023-11-23T15:54:45.914525Z",
+	"paths": [
+    "/path/test/fixtures/analyzer_test_ansible_host/e2e"
+	],
+	"queries": [
+		{
+			"query_name": "Ansible Tower Exposed To Internet",
+			"query_id": "1b2bf3ff-31e9-460e-bbfb-45e48f4f20cc",
+			"query_url": "https://docs.ansible.com/ansible-tower/latest/html/administration/security_best_practices.html#understand-the-architecture-of-ansible-and-tower",
+			"severity": "MEDIUM",
+			"platform": "Ansible",
+			"cloud_provider": "COMMON",
+			"category": "Best Practices",
+			"experimental": false,
+			"description": "Avoid exposing Ansible Tower to the public internet, effectively reducing the potential attack surface of your deployment",
+			"description_id": "657a8b1d",
+			"files": [
+				{
+					"file_name": "path\\test\\fixtures\\analyzer_test_ansible_host\\e2e\\positive2.yaml",
+					"similarity_id": "7b9574422b2f0a1a2eb467c930f7d52fb727d0b8839703d668531c1362d09c4b",
+					"line": 24,
+					"resource_type": "n/a",
+					"resource_name": "children",
+					"issue_type": "IncorrectValue",
+					"search_key": "all.children.tower.hosts",
+					"search_line": -1,
+					"search_value": "",
+					"expected_value": "Ansible Tower IP should be private",
+					"actual_value": "Ansible Tower IP is public"
+				},
+				{
+					"file_name": "path\\test\\fixtures\\analyzer_test_ansible_host\\e2e\\positive1.ini",
+					"similarity_id": "9cb04742c227f8da30d5e3f0ed823fd05334179f79dbe2435ba146af79317c45",
+					"line": 1,
+					"resource_type": "n/a",
+					"resource_name": "children",
+					"issue_type": "IncorrectValue",
+					"search_key": "[tower]",
+					"search_line": -1,
+					"search_value": "",
+					"expected_value": "Ansible Tower IP should be private",
+					"actual_value": "Ansible Tower IP is public"
+				}
+			]
+		}
+	]
+}
diff --git a/e2e/testcases/e2e-cli-075_ansible_host_detected.go b/e2e/testcases/e2e-cli-075_ansible_host_detected.go
new file mode 100644
index 00000000000..241bf3a7d21
--- /dev/null
+++ b/e2e/testcases/e2e-cli-075_ansible_host_detected.go
@@ -0,0 +1,27 @@
+package testcases
+
+// E2E-CLI-075 - KICS  scan
+// should perform the scan successfully detect ansible and return result 40
+func init() { //nolint
+	testSample := TestCase{
+		Name: "should perform a valid scan and and detect ansible [E2E-CLI-075]",
+		Args: args{
+			Args: []cmdArgs{
+				[]string{"scan", "-o", "/path/e2e/output",
+					"--output-name", "E2E_CLI_075_RESULT",
+					"-p", "\"/path/test/fixtures/analyzer_test_ansible_host/e2e\"",
+					"-i", "1b2bf3ff-31e9-460e-bbfb-45e48f4f20cc",
+				},
+			},
+			ExpectedResult: []ResultsValidation{
+				{
+					ResultsFile:    "E2E_CLI_075_RESULT",
+					ResultsFormats: []string{"json"},
+				},
+			},
+		},
+		WantStatus: []int{40},
+	}
+
+	Tests = append(Tests, testSample)
+}
diff --git a/pkg/analyzer/analyzer_test.go b/pkg/analyzer/analyzer_test.go
index 62ad13a89bf..e352b5b57c7 100644
--- a/pkg/analyzer/analyzer_test.go
+++ b/pkg/analyzer/analyzer_test.go
@@ -53,7 +53,8 @@ func TestAnalyzer_Analyze(t *testing.T) {
 			name: "analyze_test_multiple_path",
 			paths: []string{
 				filepath.FromSlash("../../test/fixtures/analyzer_test/Dockerfile"),
-				filepath.FromSlash("../../test/fixtures/analyzer_test/terraform.tf")},
+				filepath.FromSlash("../../test/fixtures/analyzer_test/terraform.tf"),
+			},
 			wantTypes:            []string{"dockerfile", "terraform"},
 			wantExclude:          []string{},
 			typesFromFlag:        []string{""},
@@ -66,7 +67,8 @@ func TestAnalyzer_Analyze(t *testing.T) {
 		{
 			name: "analyze_test_multi_checks_path",
 			paths: []string{
-				filepath.FromSlash("../../test/fixtures/analyzer_test/openAPI_test")},
+				filepath.FromSlash("../../test/fixtures/analyzer_test/openAPI_test"),
+			},
 			wantTypes:            []string{"openapi"},
 			wantExclude:          []string{},
 			typesFromFlag:        []string{""},
@@ -79,7 +81,8 @@ func TestAnalyzer_Analyze(t *testing.T) {
 		{
 			name: "analyze_test_not_openapi",
 			paths: []string{
-				filepath.FromSlash("../../test/fixtures/analyzer_test/not_openapi.json")},
+				filepath.FromSlash("../../test/fixtures/analyzer_test/not_openapi.json"),
+			},
 			wantTypes:            []string{},
 			wantExclude:          []string{filepath.FromSlash("../../test/fixtures/analyzer_test/not_openapi.json")},
 			typesFromFlag:        []string{""},
@@ -139,7 +142,8 @@ func TestAnalyzer_Analyze(t *testing.T) {
 			wantTypes: []string{"kubernetes"},
 			wantExclude: []string{filepath.FromSlash("../../test/fixtures/gitignore/positive.dockerfile"),
 				filepath.FromSlash("../../test/fixtures/gitignore/secrets.tf"),
-				filepath.FromSlash("../../test/fixtures/gitignore/gitignore")},
+				filepath.FromSlash("../../test/fixtures/gitignore/gitignore"),
+			},
 			typesFromFlag:        []string{""},
 			excludeTypesFromFlag: []string{""},
 			wantLOC:              13,
@@ -225,7 +229,8 @@ func TestAnalyzer_Analyze(t *testing.T) {
 				filepath.FromSlash("../../test/fixtures/analyzer_test/openAPI_test/openAPI.yaml"),
 				filepath.FromSlash("../../test/fixtures/analyzer_test/pnpm-lock.yaml"),
 				filepath.FromSlash("../../test/fixtures/analyzer_test/undetected.yaml"),
-				filepath.FromSlash("../../test/fixtures/analyzer_test/github.yaml")},
+				filepath.FromSlash("../../test/fixtures/analyzer_test/github.yaml"),
+			},
 			typesFromFlag:        []string{"ansible", "pulumi"},
 			excludeTypesFromFlag: []string{""},
 			wantLOC:              374,
@@ -242,7 +247,8 @@ func TestAnalyzer_Analyze(t *testing.T) {
 				filepath.FromSlash("../../test/fixtures/analyzer_test/not_openapi.json"),
 				filepath.FromSlash("../../test/fixtures/analyzer_test/undetected.yaml"),
 				filepath.FromSlash("../../test/fixtures/analyzer_test/pnpm-lock.yaml"),
-				filepath.FromSlash("../../test/fixtures/analyzer_test/dead_symlink")},
+				filepath.FromSlash("../../test/fixtures/analyzer_test/dead_symlink"),
+			},
 			typesFromFlag:        []string{""},
 			excludeTypesFromFlag: []string{"ansible", "pulumi"},
 			wantLOC:              576,
@@ -258,7 +264,8 @@ func TestAnalyzer_Analyze(t *testing.T) {
 				filepath.FromSlash("../../test/fixtures/analyzer_test/pnpm-lock.yaml"),
 				filepath.FromSlash("../../test/fixtures/analyzer_test/not_openapi.json"),
 				filepath.FromSlash("../../test/fixtures/analyzer_test/dead_symlink"),
-				filepath.FromSlash("../../test/fixtures/analyzer_test/undetected.yaml")},
+				filepath.FromSlash("../../test/fixtures/analyzer_test/undetected.yaml"),
+			},
 			typesFromFlag:        []string{""},
 			excludeTypesFromFlag: []string{""},
 			wantLOC:              834,
@@ -331,6 +338,42 @@ func TestAnalyzer_Analyze(t *testing.T) {
 			gitIgnoreFileName:    "",
 			excludeGitIgnore:     false,
 		},
+		{
+			name:                 "ansible_host",
+			paths:                []string{filepath.FromSlash("../../test/fixtures/analyzer_test_ansible_host/ansiblehost.yaml")},
+			wantTypes:            []string{"ansible"},
+			wantExclude:          []string{},
+			typesFromFlag:        []string{""},
+			excludeTypesFromFlag: []string{""},
+			wantLOC:              33,
+			wantErr:              false,
+			gitIgnoreFileName:    "",
+			excludeGitIgnore:     false,
+		},
+		{
+			name:                 "ansible_by_children",
+			paths:                []string{filepath.FromSlash("../../test/fixtures/analyzer_test_ansible_host/ansiblehost2.yaml")},
+			wantTypes:            []string{"ansible"},
+			wantExclude:          []string{},
+			typesFromFlag:        []string{""},
+			excludeTypesFromFlag: []string{""},
+			wantLOC:              22,
+			wantErr:              false,
+			gitIgnoreFileName:    "",
+			excludeGitIgnore:     false,
+		},
+		{
+			name:                 "ansible_by_host",
+			paths:                []string{filepath.FromSlash("../../test/fixtures/analyzer_test_ansible_host/ansiblehost3.yaml")},
+			wantTypes:            []string{"ansible"},
+			wantExclude:          []string{},
+			typesFromFlag:        []string{""},
+			excludeTypesFromFlag: []string{""},
+			wantLOC:              9,
+			wantErr:              false,
+			gitIgnoreFileName:    "",
+			excludeGitIgnore:     false,
+		},
 	}
 
 	for _, tt := range tests {
diff --git a/test/fixtures/analyzer_test_ansible_host/ansiblehost.yaml b/test/fixtures/analyzer_test_ansible_host/ansiblehost.yaml
new file mode 100644
index 00000000000..27ed6335a8b
--- /dev/null
+++ b/test/fixtures/analyzer_test_ansible_host/ansiblehost.yaml
@@ -0,0 +1,33 @@
+all:
+  children:
+    automationhub:
+      hosts:
+        automationhub.acme.org:
+          admin_password: <password>
+          pg_database: awx
+          pg_host: database-01.acme.org
+          pg_password: <password>
+          pg_port: '5432'
+          pg_sslmode: prefer
+          pg_username: awx
+    database:
+      hosts:
+        database-01.acme.org:
+          admin_password: <password>
+          pg_database: awx
+          pg_host: database-01.acme.org
+          pg_password: <password>
+          pg_port: '5432'
+          pg_sslmode: prefer
+          pg_username: awx
+    tower:
+      hosts:
+        172.27.0.5:
+          admin_password: <password>
+          pg_database: awx
+          pg_host: database-01.acme.org
+          pg_password: <password>
+          pg_port: '5432'
+          pg_sslmode: prefer
+          pg_username: awx
+    ungrouped: {}
diff --git a/test/fixtures/analyzer_test_ansible_host/ansiblehost2.yaml b/test/fixtures/analyzer_test_ansible_host/ansiblehost2.yaml
new file mode 100644
index 00000000000..6fd920e5a22
--- /dev/null
+++ b/test/fixtures/analyzer_test_ansible_host/ansiblehost2.yaml
@@ -0,0 +1,22 @@
+---
+all:
+  children:
+    webservers:
+      hosts:
+        webserver1: null
+        webserver2: null
+      databases:
+        hosts:
+          dbserver1:
+            ansible_host: 192.168.1.103
+            ansible_user: postgres
+          dbserver2:
+            ansible_host: 192.168.1.104
+            ansible_user: mysql
+  hosts:
+    webserver1:
+      ansible_host: 192.168.1.101
+      ansible_user: ubuntu
+    webserver2:
+      ansible_host: 192.168.1.102
+      ansible_user: centos
diff --git a/test/fixtures/analyzer_test_ansible_host/ansiblehost3.yaml b/test/fixtures/analyzer_test_ansible_host/ansiblehost3.yaml
new file mode 100644
index 00000000000..373d1d62c4a
--- /dev/null
+++ b/test/fixtures/analyzer_test_ansible_host/ansiblehost3.yaml
@@ -0,0 +1,9 @@
+---
+all:
+  hosts:
+    webserver1:
+      ansible_host: 192.168.1.101
+      ansible_user: ubuntu
+    webserver2:
+      ansible_host: 192.168.1.102
+      ansible_user: centos
diff --git a/test/fixtures/analyzer_test_ansible_host/e2e/positive1.ini b/test/fixtures/analyzer_test_ansible_host/e2e/positive1.ini
new file mode 100644
index 00000000000..e113b9e51b8
--- /dev/null
+++ b/test/fixtures/analyzer_test_ansible_host/e2e/positive1.ini
@@ -0,0 +1,14 @@
+[tower]
+150.50.1.1
+[automationhub]
+automationhub.acme.org
+[database]
+database-01.acme.org
+[all:vars]
+admin_password='<password>'
+pg_host='database-01.acme.org'
+pg_port='5432'
+pg_database='awx'
+pg_username='awx'
+pg_password='<password>'
+pg_sslmode='prefer'
\ No newline at end of file
diff --git a/test/fixtures/analyzer_test_ansible_host/e2e/positive2.yaml b/test/fixtures/analyzer_test_ansible_host/e2e/positive2.yaml
new file mode 100644
index 00000000000..051721f224c
--- /dev/null
+++ b/test/fixtures/analyzer_test_ansible_host/e2e/positive2.yaml
@@ -0,0 +1,33 @@
+all:
+  children:
+    automationhub:
+      hosts:
+        automationhub.acme.org:
+          admin_password: <password>
+          pg_database: awx
+          pg_host: database-01.acme.org
+          pg_password: <password>
+          pg_port: '5432'
+          pg_sslmode: prefer
+          pg_username: awx
+    database:
+      hosts:
+        database-01.acme.org:
+          admin_password: <password>
+          pg_database: awx
+          pg_host: database-01.acme.org
+          pg_password: <password>
+          pg_port: '5432'
+          pg_sslmode: prefer
+          pg_username: awx
+    tower:
+      hosts:
+        139.50.1.1:
+          admin_password: <password>
+          pg_database: awx
+          pg_host: database-01.acme.org
+          pg_password: <password>
+          pg_port: '5432'
+          pg_sslmode: prefer
+          pg_username: awx
+    ungrouped: {}