Repository: Checkmarx/kics (language: python)

Issue:
Dockerfile: better handling of corrupted dockerfiles
when running a scan on a corrupted file such as:

```
FROM alpine:latest

COPY {{ file_path }} /blabla

RUN echo "failure"
```

which should be failing due to:

```
 => ERROR [2/3] COPY {{ file_path }} /blabla                                                                                                                                                         0.0s
------
 > [2/3] COPY {{ file_path }} /blabla:
------
failed to compute cache key: "/{{" not found: not found
```

we are getting the following panic:

>                    .0MO.
>                    OMMMx
>                    ;NMX;
>                     ...           ...              ....
> WMMMd     cWMMM0.  KMMMO      ;xKWMMMMNOc.     ,xXMMMMMWXkc.
> WMMMd   .0MMMN:    KMMMO    :XMMMMMMMMMMMWl   xMMMMMWMMMMMMl
> WMMMd  lWMMMO.     KMMMO   xMMMMKc...'lXMk   ,MMMMx   .;dXx
> WMMMd.0MMMX;       KMMMO  cMMMMd        '    'MMMMNl'
> WMMMNWMMMMl        KMMMO  0MMMN               oMMMMMMMXkl.
> WMMMMMMMMMMo       KMMMO  0MMMX                .ckKWMMMMMM0.
> WMMMMWokMMMMk      KMMMO  oMMMMc              .     .:OMMMM0
> WMMMK.  dMMMM0.    KMMMO   KMMMMx'    ,kNc   :WOc.    .NMMMX
> WMMMd    cWMMMX.   KMMMO    kMMMMMWXNMMMMMd .WMMMMWKO0NMMMMl
> WMMMd     ,NMMMN,  KMMMO     'xNMMMMMMMNx,   .l0WMMMMMMMWk,
> xkkk:      ,kkkkx  okkkl        ;xKXKx;          ;dOKKkc
> 
> 
> Scanning with Keeping Infrastructure as Code Secure v1.7.10
> 
> 
> Preparing Scan Assets: Done
> panic: runtime error: slice bounds out of range [:1] with length 0
> 
> goroutine 52 [running]:
> github.com/Checkmarx/kics/pkg/detector.GetBracketValues({0x4000c71e4f, 0x2}, {0x4001308a38, 0x1, 0x1}, {0x4000c71e47, 0x0})
> 	/app/pkg/detector/helper.go:68 +0x62c
> github.com/Checkmarx/kics/pkg/detector.GetBracketValues({0x4000c71e47, 0xc}, {0x4001308a38, 0x1, 0x1}, {0x0, 0x0})
> 	/app/pkg/detector/helper.go:58 +0x374
> github.com/Checkmarx/kics/pkg/detector.GetBracketValues({0x4000c71e37, 0xe}, {0x0, 0x0, 0x0}, {0x4000c71e47, 0xc})
> 	/app/pkg/detector/helper.go:60 +0x39c
> github.com/Checkmarx/kics/pkg/detector.GetBracketValues({0x4000c71e30, 0x23}, {0x0, 0x0, 0x0}, {0x0, 0x0})
> 	/app/pkg/detector/helper.go:58 +0x374
> github.com/Checkmarx/kics/pkg/detector/docker.DetectKindLine.DetectLine({}, 0x4000cb80c0, {0x4000c71e30, 0x23}, 0x1f108?, 0x400136ea58?)
> 	/app/pkg/detector/docker/docker_detect.go:39 +0xbc
> github.com/Checkmarx/kics/pkg/detector.(*DetectLine).DetectLine(0x4000cb2660, 0x4000cb80c0, {0x4000c71e30, 0x23}, 0x4001303cc0?)
> 	/app/pkg/detector/detector.go:45 +0x8c
> github.com/Checkmarx/kics/pkg/engine.glob..func1(0x400130e0f0, {0x27f81c8, 0x400079c000}, {0x1d67700?, 0x4001370360}, 0x4000cb2660)
> 	/app/pkg/engine/vulnerability_builder.go:117 +0x7ec
> github.com/Checkmarx/kics/pkg/engine.(*Inspector).DecodeQueryResults(0x4000612000, 0x400130e0f0, {0x4001303c80?, 0x400136f9a0?, 0x4001071958?})
> 	/app/pkg/engine/inspector.go:362 +0x190
> github.com/Checkmarx/kics/pkg/engine.(*Inspector).doRun(0x4000612000, 0x400130e0f0)
> 	/app/pkg/engine/inspector.go:338 +0x478
> github.com/Checkmarx/kics/pkg/engine.(*Inspector).Inspect(0x4000612000, {0x27ecfd0?, 0x3d09420}, {0x20f6e38, 0x7}, {0x4000cb8240?, 0x1, 0x1}, {0x4000d05250, 0x1, ...}, ...)
> 	/app/pkg/engine/inspector.go:239 +0x508
> github.com/Checkmarx/kics/pkg/kics.(*Service).StartScan(0x400001fc70, {0x27ecfd0, 0x3d09420}, {0x20f6e38, 0x7}, 0x0?, 0x4000d7b070, 0x0?)
> 	/app/pkg/kics/service.go:102 +0x19c
> created by github.com/Checkmarx/kics/pkg/scanner.StartScan in goroutine 1
> 	/app/pkg/scanner/scanner.go:67 +0x138


Discussion / hints:
Please, follow the guideline for an issue title: 

For **bug**:

`bug(<scope>): <title starting with lowercase letter>`

For **query**:

`query(<platform>): <title starting with lowercase letter>`

For **feature request**:

`feat(<scope>): <title starting with lowercase letter>`

Thank you!
*KICS Team*
<!-- thollander/actions-comment-pull-request "title_check" -->

Fix patch:
diff --git a/pkg/engine/inspector.go b/pkg/engine/inspector.go
index 8a729191c17..d47e989b7a7 100644
--- a/pkg/engine/inspector.go
+++ b/pkg/engine/inspector.go
@@ -300,9 +300,16 @@ func (c *Inspector) GetFailedQueries() map[string]error {
 	return c.failedQueries
 }
 
-func (c *Inspector) doRun(ctx *QueryContext) ([]model.Vulnerability, error) {
+func (c *Inspector) doRun(ctx *QueryContext) (vulns []model.Vulnerability, err error) {
 	timeoutCtx, cancel := context.WithTimeout(ctx.Ctx, c.queryExecTimeout)
 	defer cancel()
+	defer func() {
+		if r := recover(); r != nil {
+			errMessage := fmt.Sprintf("Recovered from panic during query '%s' run. ", ctx.Query.Metadata.Query)
+			err = fmt.Errorf("panic: %v", r)
+			log.Err(err).Msg(errMessage)
+		}
+	}()
 	options := []rego.EvalOption{rego.EvalParsedInput(*ctx.payload)}
 
 	var cov *cover.Cover


Test patch:
diff --git a/e2e/fixtures/E2E_CLI_068_RESULT.json b/e2e/fixtures/E2E_CLI_068_RESULT.json
new file mode 100644
index 00000000000..00f5353502a
--- /dev/null
+++ b/e2e/fixtures/E2E_CLI_068_RESULT.json
@@ -0,0 +1,98 @@
+{
+  "kics_version": "development",
+  "files_scanned": 1,
+  "lines_scanned": 6,
+  "files_parsed": 1,
+  "lines_parsed": 6,
+  "lines_ignored": 0,
+  "files_failed_to_scan": 0,
+  "queries_total": 49,
+  "queries_failed_to_execute": 1,
+  "queries_failed_to_compute_similarity_id": 0,
+  "scan_id": "console",
+  "severity_counters": {
+    "HIGH": 1,
+    "INFO": 0,
+    "LOW": 1,
+    "MEDIUM": 1,
+    "TRACE": 0
+  },
+  "total_counter": 3,
+  "total_bom_resources": 0,
+  "start": "2023-10-15T09:20:54.322549843Z",
+  "end": "2023-10-15T09:20:57.878486637Z",
+  "paths": [
+    "/path/test/fixtures/dockerfile/corrupted_dockerfile"
+  ],
+  "queries": [
+    {
+      "query_name": "Missing User Instruction",
+      "query_id": "fd54f200-402c-4333-a5a4-36ef6709af2f",
+      "query_url": "https://docs.docker.com/engine/reference/builder/#user",
+      "severity": "HIGH",
+      "platform": "Dockerfile",
+      "category": "Build Process",
+      "description": "A user should be specified in the dockerfile, otherwise the image will run as root",
+      "description_id": "eb49caf6",
+      "files": [
+        {
+          "file_name": "../../path/test/fixtures/dockerfile/corrupted_dockerfile",
+          "similarity_id": "821b0a105dd9ebb6b14489251615d94813a578feb68624113a52ba9c1668ecb7",
+          "line": 1,
+          "issue_type": "MissingAttribute",
+          "search_key": "FROM={{alpine:latest}}",
+          "search_line": -1,
+          "search_value": "",
+          "expected_value": "The 'Dockerfile' should contain the 'USER' instruction",
+          "actual_value": "The 'Dockerfile' does not contain any 'USER' instruction"
+        }
+      ]
+    },
+    {
+      "query_name": "Image Version Using 'latest'",
+      "query_id": "f45ea400-6bbe-4501-9fc7-1c3d75c32067",
+      "query_url": "https://docs.docker.com/develop/dev-best-practices/",
+      "severity": "MEDIUM",
+      "platform": "Dockerfile",
+      "category": "Supply-Chain",
+      "description": "When building images, always tag them with useful tags which codify version information, intended destination (prod or test, for instance), stability, or other information that is useful when deploying the application in different environments. Do not rely on the automatically-created latest tag",
+      "description_id": "22f535ec",
+      "files": [
+        {
+          "file_name": "../../path/test/fixtures/dockerfile/corrupted_dockerfile",
+          "similarity_id": "a32938ae4d056569e5cfda73594f6cb276d4f9ee14a848fb6b642b14defee892",
+          "line": 1,
+          "issue_type": "IncorrectValue",
+          "search_key": "FROM={{alpine:latest}}",
+          "search_line": -1,
+          "search_value": "",
+          "expected_value": "FROM alpine:latest:'version' where version should not be 'latest'",
+          "actual_value": "FROM alpine:latest'"
+        }
+      ]
+    },
+    {
+      "query_name": "Healthcheck Instruction Missing",
+      "query_id": "b03a748a-542d-44f4-bb86-9199ab4fd2d5",
+      "query_url": "https://docs.docker.com/engine/reference/builder/#healthcheck",
+      "severity": "LOW",
+      "platform": "Dockerfile",
+      "category": "Insecure Configurations",
+      "description": "Ensure that HEALTHCHECK is being used. The HEALTHCHECK instruction tells Docker how to test a container to check that it is still working",
+      "description_id": "426121ee",
+      "files": [
+        {
+          "file_name": "../../path/test/fixtures/dockerfile/corrupted_dockerfile",
+          "similarity_id": "ec1a1e998229f963313752def87ce5027e89997cfb4180c9b356414566f5a029",
+          "line": 1,
+          "issue_type": "MissingAttribute",
+          "search_key": "FROM={{alpine:latest}}",
+          "search_line": -1,
+          "search_value": "",
+          "expected_value": "Dockerfile should contain instruction 'HEALTHCHECK'",
+          "actual_value": "Dockerfile doesn't contain instruction 'HEALTHCHECK'"
+        }
+      ]
+    }
+  ]
+}
diff --git a/e2e/testcases/e2e-cli-068_corrupted_dockerfile.go b/e2e/testcases/e2e-cli-068_corrupted_dockerfile.go
new file mode 100644
index 00000000000..a454068801c
--- /dev/null
+++ b/e2e/testcases/e2e-cli-068_corrupted_dockerfile.go
@@ -0,0 +1,26 @@
+// Package testcases provides end-to-end (E2E) testing functionality for the application.
+package testcases
+
+// E2E-CLI-068 - KICS  scan but recover from corrupted dockerfile
+// should perform the scan successfully and return exit code 50
+func init() { //nolint
+	testSample := TestCase{
+		Name: "should perform a valid scan and recover from a corrupted dockerfile [E2E-CLI-068]",
+		Args: args{
+			Args: []cmdArgs{
+				[]string{"scan", "-o", "/path/e2e/output", "--output-name", "E2E_CLI_068_RESULT",
+					"-p", "/path/test/fixtures/dockerfile/corrupted_dockerfile",
+				},
+			},
+			ExpectedResult: []ResultsValidation{
+				{
+					ResultsFile:    "E2E_CLI_068_RESULT",
+					ResultsFormats: []string{"json"},
+				},
+			},
+		},
+		WantStatus: []int{50},
+	}
+
+	Tests = append(Tests, testSample)
+}
diff --git a/test/fixtures/dockerfile/corrupted_dockerfile b/test/fixtures/dockerfile/corrupted_dockerfile
new file mode 100644
index 00000000000..fdc2b63f8f8
--- /dev/null
+++ b/test/fixtures/dockerfile/corrupted_dockerfile
@@ -0,0 +1,5 @@
+FROM alpine:latest
+
+COPY {{ file_path }} /test
+
+RUN echo "failure"