diff --git a/docs/platforms.md b/docs/platforms.md index bc4a6c7de7d..302faa278de 100644 --- a/docs/platforms.md +++ b/docs/platforms.md @@ -86,7 +86,9 @@ Note that KICS recognizes this technology as Azure Resource Manager (for queries ## Docker -KICS supports scanning Docker files with any name (but with no extension) and files with `.dockerfile` extension. +KICS supports scanning Dockerfile configurations with any name (but with no extension) and files matched by either name (`Dockerfile`, `Dockerfile.`), extension (`.dockerfile`,`.ubi8`,`.debian`), or by location inside directories named `docker`, `dockerfile`, or `dockerfiles`, where all text files are verified for a valid configuration regardless of extension. + +Note that every check is matched case-insensitively with the exception of the `.ubi8` and `.debian` extensions. ## Docker Compose diff --git a/e2e/fixtures/E2E_CLI_105_RESULT.json b/e2e/fixtures/E2E_CLI_105_RESULT.json new file mode 100644 index 00000000000..5c4c55498d8 --- /dev/null +++ b/e2e/fixtures/E2E_CLI_105_RESULT.json @@ -0,0 +1,415 @@ +{ + "kics_version": "development", + "files_scanned": 26, + "lines_scanned": 212, + "files_parsed": 26, + "lines_parsed": 204, + "lines_ignored": 8, + "files_failed_to_scan": 0, + "queries_total": 48, + "queries_failed_to_execute": 1, + "queries_failed_to_compute_similarity_id": 0, + "scan_id": "console", + "severity_counters": { + "CRITICAL": 0, + "HIGH": 23, + "INFO": 0, + "LOW": 3, + "MEDIUM": 2, + "TRACE": 0 + }, + "total_counter": 28, + "total_bom_resources": 0, + "start": "2026-03-13T16:37:29.4562916Z", + "end": "2026-03-13T16:37:30.3687083Z", + "paths": [ + "/path/test/fixtures/dockerfile", + "/path/test/fixtures/negative_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", + "cwe": "250", + "risk_score": "7.7", + "cloud_provider": "COMMON", + "category": "Build Process", + "experimental": false, + "description": "Always set a user in the runtime stage of your Dockerfile. Without it, the container defaults to root, even if earlier build stages define a user.", + "description_id": "eb49caf6", + "files": [ + { + "file_name": "path/test/fixtures/dockerfile/any_name/file.Dockerfile", + "similarity_id": "1d972910b640dfb968ab630847182b4a19f44b78aeeaa0ef93c96c7e27aa8b6a", + "line": 6, + "issue_type": "MissingAttribute", + "search_key": "FROM={{alpine:3.19 AS builder}}", + "search_line": -1, + "search_value": "", + "expected_value": "The 'Dockerfile' should contain the 'USER' instruction", + "actual_value": "The 'Dockerfile' does not contain any 'USER' instruction" + }, + { + "file_name": "path/test/fixtures/dockerfile/test_folder_names_case/Docker/any_file.txt", + "similarity_id": "6da391b0e3e24d85f72b3ace5db0569be32ef11e6f9a433b138ae4e0b004df58", + "line": 1, + "issue_type": "MissingAttribute", + "search_key": "FROM={{alpine:3.19 AS builder}}", + "search_line": -1, + "search_value": "", + "expected_value": "The 'Dockerfile' should contain the 'USER' instruction", + "actual_value": "The 'Dockerfile' does not contain any 'USER' instruction" + }, + { + "file_name": "path/test/fixtures/dockerfile/corrupted_dockerfile", + "similarity_id": "558c83370b9fc9e230035e00ff7b5302cd64c16f700e73c830579947e250a381", + "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" + }, + { + "file_name": "path/test/fixtures/dockerfile/case_insensitive_tests/random_name", + "similarity_id": "4df62f3dddaa0fe84e53c387514ff1ffb2405fb47a80011271dfc6742078a0e8", + "line": 1, + "issue_type": "MissingAttribute", + "search_key": "FROM={{alpine:3.19 as builder}}", + "search_line": -1, + "search_value": "", + "expected_value": "The 'Dockerfile' should contain the 'USER' instruction", + "actual_value": "The 'Dockerfile' does not contain any 'USER' instruction" + }, + { + "file_name": "path/test/fixtures/dockerfile/test_folder_names/dockerfiles/any_file.txt", + "similarity_id": "e150676345e87674484ea970ca810125007b743069646ac448feaba242b7211f", + "line": 1, + "issue_type": "MissingAttribute", + "search_key": "FROM={{alpine:3.19 AS builder}}", + "search_line": -1, + "search_value": "", + "expected_value": "The 'Dockerfile' should contain the 'USER' instruction", + "actual_value": "The 'Dockerfile' does not contain any 'USER' instruction" + }, + { + "file_name": "path/test/fixtures/dockerfile/case_insensitive_tests/DOCKERfile.txt", + "similarity_id": "f9caf5d57d5872073bc7b7a555a3283708f72c9990689c8d4e6b3ce1957b496a", + "line": 1, + "issue_type": "MissingAttribute", + "search_key": "FROM={{alpine:3.19 as builder}}", + "search_line": -1, + "search_value": "", + "expected_value": "The 'Dockerfile' should contain the 'USER' instruction", + "actual_value": "The 'Dockerfile' does not contain any 'USER' instruction" + }, + { + "file_name": "path/test/fixtures/dockerfile/test_folder_names/dockerfile/any_file.txt", + "similarity_id": "c2e7f0c0c566a723ff253f4a95e837749faba964ec008551c1f87a7faa476110", + "line": 1, + "issue_type": "MissingAttribute", + "search_key": "FROM={{alpine:3.19 AS builder}}", + "search_line": -1, + "search_value": "", + "expected_value": "The 'Dockerfile' should contain the 'USER' instruction", + "actual_value": "The 'Dockerfile' does not contain any 'USER' instruction" + }, + { + "file_name": "path/test/fixtures/dockerfile/any_name/random_name", + "similarity_id": "ee3531797486eec98e3dd28ec8cc5f7f6f00743d1cf79cd47f6859df87026f59", + "line": 3, + "issue_type": "MissingAttribute", + "search_key": "FROM={{alpine:3.19 AS builder}}", + "search_line": -1, + "search_value": "", + "expected_value": "The 'Dockerfile' should contain the 'USER' instruction", + "actual_value": "The 'Dockerfile' does not contain any 'USER' instruction" + }, + { + "file_name": "path/test/fixtures/dockerfile/test_folder_names_case/Dockerfile/any_file.txt", + "similarity_id": "47d6f707c904f56fe3ca1cc7bce1d2e0ae41d421da983110a5c15fc7e48105df", + "line": 1, + "issue_type": "MissingAttribute", + "search_key": "FROM={{alpine:3.19 AS builder}}", + "search_line": -1, + "search_value": "", + "expected_value": "The 'Dockerfile' should contain the 'USER' instruction", + "actual_value": "The 'Dockerfile' does not contain any 'USER' instruction" + }, + { + "file_name": "path/test/fixtures/dockerfile/case_insensitive_tests/any_name.ubi8", + "similarity_id": "ce95928798897e3f22c2677202d38812030cc2dfb5cf0470d397d7baaf8c1de1", + "line": 1, + "issue_type": "MissingAttribute", + "search_key": "FROM={{alpine:3.19 as builder}}", + "search_line": -1, + "search_value": "", + "expected_value": "The 'Dockerfile' should contain the 'USER' instruction", + "actual_value": "The 'Dockerfile' does not contain any 'USER' instruction" + }, + { + "file_name": "path/test/fixtures/dockerfile/case_insensitive_tests/dockerFILE", + "similarity_id": "9977ed3614740afd406ca0a86f0df4da5e8680efbb6e9e66ff71ae1dc2d9025f", + "line": 1, + "issue_type": "MissingAttribute", + "search_key": "FROM={{alpine:3.19 as builder}}", + "search_line": -1, + "search_value": "", + "expected_value": "The 'Dockerfile' should contain the 'USER' instruction", + "actual_value": "The 'Dockerfile' does not contain any 'USER' instruction" + }, + { + "file_name": "path/test/fixtures/dockerfile/case_insensitive_tests/any_name.debian", + "similarity_id": "c949a1c23fe7c61dea7daac22ce6a13ffb8dec65b4bcbeacc76bf295518e72ef", + "line": 1, + "issue_type": "MissingAttribute", + "search_key": "FROM={{alpine:3.19 as builder}}", + "search_line": -1, + "search_value": "", + "expected_value": "The 'Dockerfile' should contain the 'USER' instruction", + "actual_value": "The 'Dockerfile' does not contain any 'USER' instruction" + }, + { + "file_name": "path/test/fixtures/dockerfile/any_name/file_2.DOCKERfile", + "similarity_id": "29858cfa69a98973cc1ae10f84e66267240bd630126eba2ba15e58a7aa2dd54d", + "line": 4, + "issue_type": "MissingAttribute", + "search_key": "FROM={{alpine:3.19 AS builder}}", + "search_line": -1, + "search_value": "", + "expected_value": "The 'Dockerfile' should contain the 'USER' instruction", + "actual_value": "The 'Dockerfile' does not contain any 'USER' instruction" + }, + { + "file_name": "path/test/fixtures/dockerfile/case_insensitive_tests/Dockerfile.something", + "similarity_id": "2b1d191f474528c93b66c1f5f891efd3763834725ed4008cbd216702f576ef20", + "line": 1, + "issue_type": "MissingAttribute", + "search_key": "FROM={{alpine:3.19 as builder}}", + "search_line": -1, + "search_value": "", + "expected_value": "The 'Dockerfile' should contain the 'USER' instruction", + "actual_value": "The 'Dockerfile' does not contain any 'USER' instruction" + }, + { + "file_name": "path/test/fixtures/dockerfile/any_name/any_name.debian", + "similarity_id": "ef335c394fbaebc802c99ba59b1b3ec830043ac020b711efc7cf497752b73429", + "line": 4, + "issue_type": "MissingAttribute", + "search_key": "FROM={{alpine:3.19 AS builder}}", + "search_line": -1, + "search_value": "", + "expected_value": "The 'Dockerfile' should contain the 'USER' instruction", + "actual_value": "The 'Dockerfile' does not contain any 'USER' instruction" + }, + { + "file_name": "path/test/fixtures/dockerfile/Dockerfile-example", + "similarity_id": "aeaf42752011d846797cea09ce1a0eb5457673c67b0fb16914a0c639a253e5c7", + "line": 1, + "issue_type": "MissingAttribute", + "search_key": "FROM={{openjdk:10-jdk}}", + "search_line": -1, + "search_value": "", + "expected_value": "The 'Dockerfile' should contain the 'USER' instruction", + "actual_value": "The 'Dockerfile' does not contain any 'USER' instruction" + }, + { + "file_name": "path/test/fixtures/dockerfile/case_insensitive_tests/file_2.DOCKERfile", + "similarity_id": "b0694a2913d293ea034d0fe62bd549aed2dd316a81fb82b611a7ab901e32b1b6", + "line": 1, + "issue_type": "MissingAttribute", + "search_key": "FROM={{alpine:3.19 AS builder}}", + "search_line": -1, + "search_value": "", + "expected_value": "The 'Dockerfile' should contain the 'USER' instruction", + "actual_value": "The 'Dockerfile' does not contain any 'USER' instruction" + }, + { + "file_name": "path/test/fixtures/dockerfile/any_name/Dockerfile.something", + "similarity_id": "b41a39fe06c21fc69fbd6e8f7b3e2c44e8d0d7a8e2b0e0c251f5d6a174e031ee", + "line": 4, + "issue_type": "MissingAttribute", + "search_key": "FROM={{alpine:3.19 AS builder}}", + "search_line": -1, + "search_value": "", + "expected_value": "The 'Dockerfile' should contain the 'USER' instruction", + "actual_value": "The 'Dockerfile' does not contain any 'USER' instruction" + }, + { + "file_name": "path/test/fixtures/dockerfile/any_name/dockerFILE", + "similarity_id": "e97a5ec241eb063c5757aed13a666c8126e4375ac9aed300cdc72d4ae883dfdc", + "line": 6, + "issue_type": "MissingAttribute", + "search_key": "FROM={{alpine:3.19 AS builder}}", + "search_line": -1, + "search_value": "", + "expected_value": "The 'Dockerfile' should contain the 'USER' instruction", + "actual_value": "The 'Dockerfile' does not contain any 'USER' instruction" + }, + { + "file_name": "path/test/fixtures/dockerfile/test_folder_names/docker/any_file.txt", + "similarity_id": "9d78b93c92fe63c29dec006a12993b74dc6c6fbf29ae295ff7c6e19136657e2d", + "line": 1, + "issue_type": "MissingAttribute", + "search_key": "FROM={{alpine:3.19 AS builder}}", + "search_line": -1, + "search_value": "", + "expected_value": "The 'Dockerfile' should contain the 'USER' instruction", + "actual_value": "The 'Dockerfile' does not contain any 'USER' instruction" + }, + { + "file_name": "path/test/fixtures/dockerfile/test_folder_names_case/Dockerfiles/any_file.txt", + "similarity_id": "b58c4c4ed6c88b82fdf62608154342a31a2de95eaae39716ff4f6ccf1a5bcdda", + "line": 1, + "issue_type": "MissingAttribute", + "search_key": "FROM={{alpine:3.19 AS builder}}", + "search_line": -1, + "search_value": "", + "expected_value": "The 'Dockerfile' should contain the 'USER' instruction", + "actual_value": "The 'Dockerfile' does not contain any 'USER' instruction" + }, + { + "file_name": "path/test/fixtures/dockerfile/any_name/DOCKERfile.txt", + "similarity_id": "5663f110b46dbc0378ff0540fc4a54700c80197a1ced862564f987d4f2e7116d", + "line": 13, + "issue_type": "MissingAttribute", + "search_key": "FROM={{alpine:3.19 AS builder}}", + "search_line": -1, + "search_value": "", + "expected_value": "The 'Dockerfile' should contain the 'USER' instruction", + "actual_value": "The 'Dockerfile' does not contain any 'USER' instruction" + }, + { + "file_name": "path/test/fixtures/dockerfile/any_name/any_name.ubi8", + "similarity_id": "4d64348b27180d867de9cf04a51db582786ea6622adb94fb54fdbac03b284769", + "line": 4, + "issue_type": "MissingAttribute", + "search_key": "FROM={{alpine:3.19 AS builder}}", + "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": "Add Instead of Copy", + "query_id": "9513a694-aa0d-41d8-be61-3271e056f36b", + "query_url": "https://docs.docker.com/engine/reference/builder/#add", + "severity": "MEDIUM", + "platform": "Dockerfile", + "cwe": "610", + "risk_score": "5.2", + "category": "Supply-Chain", + "experimental": false, + "description": "Using ADD to load external installation scripts could lead to an evil web server leveraging this and loading a malicious script.", + "description_id": "0aedd324", + "files": [ + { + "file_name": "path/test/fixtures/dockerfile/Dockerfile-example", + "similarity_id": "9d6bb1f4ca1093d79890b1b24b00dbb2e8fa60ca0df6b2ba391db348256eec6f", + "line": 6, + "issue_type": "IncorrectValue", + "search_key": "FROM={{openjdk:10-jdk}}.{{ADD ${JAR_FILE} app.jar}}", + "search_line": -1, + "search_value": "", + "expected_value": "'COPY' ${JAR_FILE}", + "actual_value": "'ADD' ${JAR_FILE}" + } + ] + }, + { + "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", + "cwe": "1357", + "risk_score": "5.1", + "category": "Best Practices", + "experimental": false, + "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": "b8c6f58c6b52c4155b70475008be34bcf7ca39a15378ca1828e657a75ba907f3", + "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": "Curl or Wget Instead of Add", + "query_id": "4b410d24-1cbe-4430-a632-62c9a931cf1c", + "query_url": "https://docs.docker.com/develop/develop-images/dockerfile_best-practices/", + "severity": "LOW", + "platform": "Dockerfile", + "cwe": "610", + "risk_score": "2.8", + "category": "Best Practices", + "experimental": false, + "description": "Use of Curl or Wget should be done instead of Add to fetch packages from remote URLs due to the use of Add being strongly discouraged", + "description_id": "29e8216b", + "files": [ + { + "file_name": "path/test/fixtures/dockerfile/Dockerfile-example", + "similarity_id": "37ebb20d72a17217823809f4bbf670db1167d627157c42c0b4dd9b063e30b5bd", + "line": 3, + "issue_type": "IncorrectValue", + "search_key": "FROM={{openjdk:10-jdk}}.{{ADD http://source.file/package.file.tar.gz /temp}}", + "search_line": -1, + "search_value": "", + "expected_value": "Should use 'curl' or 'wget' to download http://source.file/package.file.tar.gz", + "actual_value": "'ADD' http://source.file/package.file.tar.gz" + } + ] + }, + { + "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", + "cwe": "710", + "risk_score": "3.6", + "category": "Insecure Configurations", + "experimental": false, + "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/Dockerfile-example", + "similarity_id": "4d0420e48f4c7d991ed6694980266d5b7313da8abb2e29b2dd777ce7c6f6251d", + "line": 1, + "issue_type": "MissingAttribute", + "search_key": "FROM={{openjdk:10-jdk}}", + "search_line": -1, + "search_value": "", + "expected_value": "Dockerfile should contain instruction 'HEALTHCHECK'", + "actual_value": "Dockerfile doesn't contain instruction 'HEALTHCHECK'" + }, + { + "file_name": "path/test/fixtures/dockerfile/corrupted_dockerfile", + "similarity_id": "ae470ca681b82da606c6080acf7ea93906066db785bf47e2372ef7b342f43f7e", + "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/fixtures/E2E_CLI_106_PAYLOAD.json b/e2e/fixtures/E2E_CLI_106_PAYLOAD.json new file mode 100644 index 00000000000..9587df8b5a4 --- /dev/null +++ b/e2e/fixtures/E2E_CLI_106_PAYLOAD.json @@ -0,0 +1,1750 @@ +{ + "document": [ + { + "args": [], + "command": { + "openjdk:10-jdk": [ + { + "Cmd": "from", + "EndLine": 1, + "Flags": [], + "JSON": false, + "Original": "FROM openjdk:10-jdk", + "SubCmd": "", + "Value": [ + "openjdk:10-jdk" + ], + "_kics_line": 1 + }, + { + "Cmd": "volume", + "EndLine": 2, + "Flags": [], + "JSON": false, + "Original": "VOLUME /tmp", + "SubCmd": "", + "Value": [ + "/tmp" + ], + "_kics_line": 2 + }, + { + "Cmd": "add", + "EndLine": 3, + "Flags": [], + "JSON": false, + "Original": "ADD http://source.file/package.file.tar.gz /temp", + "SubCmd": "", + "Value": [ + "http://source.file/package.file.tar.gz", + "/temp" + ], + "_kics_line": 3 + }, + { + "Cmd": "run", + "EndLine": 4, + "Flags": [], + "JSON": false, + "Original": "RUN tar -xjf /temp/package.file.tar.gz", + "SubCmd": "", + "Value": [ + "tar -xjf /temp/package.file.tar.gz" + ], + "_kics_line": 4 + }, + { + "Cmd": "arg", + "EndLine": 5, + "Flags": [], + "JSON": false, + "Original": "ARG JAR_FILE", + "SubCmd": "", + "Value": [ + "JAR_FILE" + ], + "_kics_line": 5 + }, + { + "Cmd": "add", + "EndLine": 6, + "Flags": [], + "JSON": false, + "Original": "ADD ${JAR_FILE} app.jar", + "SubCmd": "", + "Value": [ + "${JAR_FILE}", + "app.jar" + ], + "_kics_line": 6 + }, + { + "Cmd": "entrypoint", + "EndLine": 7, + "Flags": [], + "JSON": true, + "Original": "ENTRYPOINT [\"java\",\"-Djava.security.egd=file:/dev/./urandom\",\"-jar\",\"/app.jar\"]", + "SubCmd": "", + "Value": [ + "java", + "-Djava.security.egd=file:/dev/./urandom", + "-jar", + "/app.jar" + ], + "_kics_line": 7 + } + ] + }, + "file": "file", + "id": "0" + }, + { + "args": [], + "command": { + "alpine:3.19 AS builder": [ + { + "Cmd": "from", + "EndLine": 13, + "Flags": [], + "JSON": false, + "Original": "FROM alpine:3.19 AS builder", + "SubCmd": "", + "Value": [ + "alpine:3.19", + "AS", + "builder" + ], + "_kics_line": 13 + }, + { + "Cmd": "copy", + "EndLine": 15, + "Flags": [], + "JSON": false, + "Original": "COPY . .", + "SubCmd": "", + "Value": [ + ".", + "." + ], + "_kics_line": 15 + }, + { + "Cmd": "healthcheck", + "EndLine": 17, + "Flags": [ + "--interval=30s", + "--timeout=30s", + "--start-period=5s", + "--retries=3" + ], + "JSON": true, + "Original": "HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 CMD [ \"executable\" ]", + "SubCmd": "", + "Value": [ + "CMD", + "executable" + ], + "_kics_line": 17 + } + ] + }, + "file": "file", + "id": "0" + }, + { + "args": [ + { + "Cmd": "arg", + "EndLine": 1, + "Flags": [], + "JSON": false, + "Original": "ARG VERSION=1.0", + "SubCmd": "", + "Value": [ + "VERSION=1.0" + ], + "_kics_line": 1 + }, + { + "Cmd": "arg", + "EndLine": 2, + "Flags": [], + "JSON": false, + "Original": "ARG BASE_IMAGE=ubuntu:22.04", + "SubCmd": "", + "Value": [ + "BASE_IMAGE=ubuntu:22.04" + ], + "_kics_line": 2 + } + ], + "command": { + "alpine:3.19 AS builder": [ + { + "Cmd": "from", + "EndLine": 4, + "Flags": [], + "JSON": false, + "Original": "FROM alpine:3.19 AS builder", + "SubCmd": "", + "Value": [ + "alpine:3.19", + "AS", + "builder" + ], + "_kics_line": 4 + }, + { + "Cmd": "copy", + "EndLine": 6, + "Flags": [], + "JSON": false, + "Original": "COPY . .", + "SubCmd": "", + "Value": [ + ".", + "." + ], + "_kics_line": 6 + }, + { + "Cmd": "healthcheck", + "EndLine": 8, + "Flags": [ + "--interval=30s", + "--timeout=30s", + "--start-period=5s", + "--retries=3" + ], + "JSON": true, + "Original": "HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 CMD [ \"executable\" ]", + "SubCmd": "", + "Value": [ + "CMD", + "executable" + ], + "_kics_line": 8 + } + ] + }, + "file": "file", + "id": "0" + }, + { + "args": [ + { + "Cmd": "arg", + "EndLine": 1, + "Flags": [], + "JSON": false, + "Original": "ARG VERSION=1.0", + "SubCmd": "", + "Value": [ + "VERSION=1.0" + ], + "_kics_line": 1 + }, + { + "Cmd": "arg", + "EndLine": 2, + "Flags": [], + "JSON": false, + "Original": "ARG BASE_IMAGE=ubuntu:22.04", + "SubCmd": "", + "Value": [ + "BASE_IMAGE=ubuntu:22.04" + ], + "_kics_line": 2 + } + ], + "command": { + "alpine:3.19 AS builder": [ + { + "Cmd": "from", + "EndLine": 4, + "Flags": [], + "JSON": false, + "Original": "FROM alpine:3.19 AS builder", + "SubCmd": "", + "Value": [ + "alpine:3.19", + "AS", + "builder" + ], + "_kics_line": 4 + }, + { + "Cmd": "copy", + "EndLine": 6, + "Flags": [], + "JSON": false, + "Original": "COPY . .", + "SubCmd": "", + "Value": [ + ".", + "." + ], + "_kics_line": 6 + }, + { + "Cmd": "healthcheck", + "EndLine": 8, + "Flags": [ + "--interval=30s", + "--timeout=30s", + "--start-period=5s", + "--retries=3" + ], + "JSON": true, + "Original": "HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 CMD [ \"executable\" ]", + "SubCmd": "", + "Value": [ + "CMD", + "executable" + ], + "_kics_line": 8 + } + ] + }, + "file": "file", + "id": "0" + }, + { + "args": [ + { + "Cmd": "arg", + "EndLine": 1, + "Flags": [], + "JSON": false, + "Original": "ARG VERSION=1.0", + "SubCmd": "", + "Value": [ + "VERSION=1.0" + ], + "_kics_line": 1 + }, + { + "Cmd": "arg", + "EndLine": 2, + "Flags": [], + "JSON": false, + "Original": "ARG BASE_IMAGE=ubuntu:22.04", + "SubCmd": "", + "Value": [ + "BASE_IMAGE=ubuntu:22.04" + ], + "_kics_line": 2 + } + ], + "command": { + "alpine:3.19 AS builder": [ + { + "Cmd": "from", + "EndLine": 4, + "Flags": [], + "JSON": false, + "Original": "FROM alpine:3.19 AS builder", + "SubCmd": "", + "Value": [ + "alpine:3.19", + "AS", + "builder" + ], + "_kics_line": 4 + }, + { + "Cmd": "copy", + "EndLine": 6, + "Flags": [], + "JSON": false, + "Original": "COPY . .", + "SubCmd": "", + "Value": [ + ".", + "." + ], + "_kics_line": 6 + }, + { + "Cmd": "healthcheck", + "EndLine": 8, + "Flags": [ + "--interval=30s", + "--timeout=30s", + "--start-period=5s", + "--retries=3" + ], + "JSON": true, + "Original": "HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 CMD [ \"executable\" ]", + "SubCmd": "", + "Value": [ + "CMD", + "executable" + ], + "_kics_line": 8 + } + ] + }, + "file": "file", + "id": "0" + }, + { + "args": [ + { + "Cmd": "arg", + "EndLine": 1, + "Flags": [], + "JSON": false, + "Original": "ARG BASE_IMAGE=ubuntu:22.04", + "SubCmd": "", + "Value": [ + "BASE_IMAGE=ubuntu:22.04" + ], + "_kics_line": 1 + }, + { + "Cmd": "arg", + "EndLine": 4, + "Flags": [], + "JSON": false, + "Original": "ARG JAR_FILE", + "SubCmd": "", + "Value": [ + "JAR_FILE" + ], + "_kics_line": 4 + } + ], + "command": { + "alpine:3.19 AS builder": [ + { + "Cmd": "from", + "EndLine": 6, + "Flags": [], + "JSON": false, + "Original": "FROM alpine:3.19 AS builder", + "SubCmd": "", + "Value": [ + "alpine:3.19", + "AS", + "builder" + ], + "_kics_line": 6 + }, + { + "Cmd": "copy", + "EndLine": 8, + "Flags": [], + "JSON": false, + "Original": "COPY . .", + "SubCmd": "", + "Value": [ + ".", + "." + ], + "_kics_line": 8 + }, + { + "Cmd": "healthcheck", + "EndLine": 10, + "Flags": [ + "--interval=30s", + "--timeout=30s", + "--start-period=5s", + "--retries=3" + ], + "JSON": true, + "Original": "HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 CMD [ \"executable\" ]", + "SubCmd": "", + "Value": [ + "CMD", + "executable" + ], + "_kics_line": 10 + } + ] + }, + "file": "file", + "id": "0" + }, + { + "args": [ + { + "Cmd": "arg", + "EndLine": 2, + "Flags": [], + "JSON": false, + "Original": "ARG BASE_IMAGE=ubuntu:22.04", + "SubCmd": "", + "Value": [ + "BASE_IMAGE=ubuntu:22.04" + ], + "_kics_line": 2 + } + ], + "command": { + "alpine:3.19 AS builder": [ + { + "Cmd": "from", + "EndLine": 6, + "Flags": [], + "JSON": false, + "Original": "FROM alpine:3.19 AS builder", + "SubCmd": "", + "Value": [ + "alpine:3.19", + "AS", + "builder" + ], + "_kics_line": 6 + }, + { + "Cmd": "copy", + "EndLine": 8, + "Flags": [], + "JSON": false, + "Original": "COPY . .", + "SubCmd": "", + "Value": [ + ".", + "." + ], + "_kics_line": 8 + }, + { + "Cmd": "healthcheck", + "EndLine": 10, + "Flags": [ + "--interval=30s", + "--timeout=30s", + "--start-period=5s", + "--retries=3" + ], + "JSON": true, + "Original": "HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 CMD [ \"executable\" ]", + "SubCmd": "", + "Value": [ + "CMD", + "executable" + ], + "_kics_line": 10 + } + ] + }, + "file": "file", + "id": "0" + }, + { + "args": [ + { + "Cmd": "arg", + "EndLine": 1, + "Flags": [], + "JSON": false, + "Original": "ARG BASE_IMAGE=ubuntu:22.04", + "SubCmd": "", + "Value": [ + "BASE_IMAGE=ubuntu:22.04" + ], + "_kics_line": 1 + } + ], + "command": { + "alpine:3.19 AS builder": [ + { + "Cmd": "from", + "EndLine": 4, + "Flags": [], + "JSON": false, + "Original": "FROM alpine:3.19 AS builder", + "SubCmd": "", + "Value": [ + "alpine:3.19", + "AS", + "builder" + ], + "_kics_line": 4 + }, + { + "Cmd": "copy", + "EndLine": 6, + "Flags": [], + "JSON": false, + "Original": "COPY .. .", + "SubCmd": "", + "Value": [ + "..", + "." + ], + "_kics_line": 6 + }, + { + "Cmd": "healthcheck", + "EndLine": 8, + "Flags": [ + "--interval=30s", + "--timeout=30s", + "--start-period=5s", + "--retries=3" + ], + "JSON": true, + "Original": "HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 CMD [ \"executable\" ]", + "SubCmd": "", + "Value": [ + "CMD", + "executable" + ], + "_kics_line": 8 + } + ] + }, + "file": "file", + "id": "0" + }, + { + "args": [ + { + "Cmd": "arg", + "EndLine": 1, + "Flags": [], + "JSON": false, + "Original": "ARG BASE_IMAGE=ubuntu:22.04", + "SubCmd": "", + "Value": [ + "BASE_IMAGE=ubuntu:22.04" + ], + "_kics_line": 1 + } + ], + "command": { + "alpine:3.19 AS builder": [ + { + "Cmd": "from", + "EndLine": 3, + "Flags": [], + "JSON": false, + "Original": "FROM alpine:3.19 AS builder", + "SubCmd": "", + "Value": [ + "alpine:3.19", + "AS", + "builder" + ], + "_kics_line": 3 + }, + { + "Cmd": "copy", + "EndLine": 5, + "Flags": [], + "JSON": false, + "Original": "COPY . .", + "SubCmd": "", + "Value": [ + ".", + "." + ], + "_kics_line": 5 + }, + { + "Cmd": "healthcheck", + "EndLine": 7, + "Flags": [ + "--interval=30s", + "--timeout=30s", + "--start-period=5s", + "--retries=3" + ], + "JSON": true, + "Original": "HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 CMD [ \"executable\" ]", + "SubCmd": "", + "Value": [ + "CMD", + "executable" + ], + "_kics_line": 7 + } + ] + }, + "file": "file", + "id": "0" + }, + { + "args": [], + "command": { + "alpine:3.19 as builder": [ + { + "Cmd": "from", + "EndLine": 13, + "Flags": [], + "JSON": false, + "Original": "from alpine:3.19 as builder", + "SubCmd": "", + "Value": [ + "alpine:3.19", + "as", + "builder" + ], + "_kics_line": 13 + }, + { + "Cmd": "copy", + "EndLine": 15, + "Flags": [], + "JSON": false, + "Original": "copy . .", + "SubCmd": "", + "Value": [ + ".", + "." + ], + "_kics_line": 15 + }, + { + "Cmd": "healthcheck", + "EndLine": 17, + "Flags": [ + "--interval=30s", + "--timeout=30s", + "--start-period=5s", + "--retries=3" + ], + "JSON": true, + "Original": "healthcheck --interval=30s --timeout=30s --start-period=5s --retries=3 cmd [ \"executable\" ]", + "SubCmd": "", + "Value": [ + "cmd", + "executable" + ], + "_kics_line": 17 + } + ] + }, + "file": "file", + "id": "0" + }, + { + "args": [ + { + "Cmd": "arg", + "EndLine": 1, + "Flags": [], + "JSON": false, + "Original": "arg VERSION=1.0", + "SubCmd": "", + "Value": [ + "VERSION=1.0" + ], + "_kics_line": 1 + }, + { + "Cmd": "arg", + "EndLine": 2, + "Flags": [], + "JSON": false, + "Original": "arg BASE_IMAGE=ubuntu:22.04", + "SubCmd": "", + "Value": [ + "BASE_IMAGE=ubuntu:22.04" + ], + "_kics_line": 2 + } + ], + "command": { + "alpine:3.19 as builder": [ + { + "Cmd": "from", + "EndLine": 4, + "Flags": [], + "JSON": false, + "Original": "from alpine:3.19 as builder", + "SubCmd": "", + "Value": [ + "alpine:3.19", + "as", + "builder" + ], + "_kics_line": 4 + }, + { + "Cmd": "copy", + "EndLine": 6, + "Flags": [], + "JSON": false, + "Original": "copy . .", + "SubCmd": "", + "Value": [ + ".", + "." + ], + "_kics_line": 6 + }, + { + "Cmd": "healthcheck", + "EndLine": 8, + "Flags": [ + "--interval=30s", + "--timeout=30s", + "--start-period=5s", + "--retries=3" + ], + "JSON": true, + "Original": "healthcheck --interval=30s --timeout=30s --start-period=5s --retries=3 cmd [ \"executable\" ]", + "SubCmd": "", + "Value": [ + "cmd", + "executable" + ], + "_kics_line": 8 + } + ] + }, + "file": "file", + "id": "0" + }, + { + "args": [ + { + "Cmd": "arg", + "EndLine": 1, + "Flags": [], + "JSON": false, + "Original": "arg VERSION=1.0", + "SubCmd": "", + "Value": [ + "VERSION=1.0" + ], + "_kics_line": 1 + }, + { + "Cmd": "arg", + "EndLine": 2, + "Flags": [], + "JSON": false, + "Original": "arg BASE_IMAGE=ubuntu:22.04", + "SubCmd": "", + "Value": [ + "BASE_IMAGE=ubuntu:22.04" + ], + "_kics_line": 2 + } + ], + "command": { + "alpine:3.19 as builder": [ + { + "Cmd": "from", + "EndLine": 4, + "Flags": [], + "JSON": false, + "Original": "from alpine:3.19 as builder", + "SubCmd": "", + "Value": [ + "alpine:3.19", + "as", + "builder" + ], + "_kics_line": 4 + }, + { + "Cmd": "copy", + "EndLine": 6, + "Flags": [], + "JSON": false, + "Original": "copy . .", + "SubCmd": "", + "Value": [ + ".", + "." + ], + "_kics_line": 6 + }, + { + "Cmd": "healthcheck", + "EndLine": 8, + "Flags": [ + "--interval=30s", + "--timeout=30s", + "--start-period=5s", + "--retries=3" + ], + "JSON": true, + "Original": "healthcheck --interval=30s --timeout=30s --start-period=5s --retries=3 cmd [ \"executable\" ]", + "SubCmd": "", + "Value": [ + "cmd", + "executable" + ], + "_kics_line": 8 + } + ] + }, + "file": "file", + "id": "0" + }, + { + "args": [ + { + "Cmd": "arg", + "EndLine": 1, + "Flags": [], + "JSON": false, + "Original": "arg VERSION=1.0", + "SubCmd": "", + "Value": [ + "VERSION=1.0" + ], + "_kics_line": 1 + }, + { + "Cmd": "arg", + "EndLine": 2, + "Flags": [], + "JSON": false, + "Original": "arg BASE_IMAGE=ubuntu:22.04", + "SubCmd": "", + "Value": [ + "BASE_IMAGE=ubuntu:22.04" + ], + "_kics_line": 2 + } + ], + "command": { + "alpine:3.19 as builder": [ + { + "Cmd": "from", + "EndLine": 4, + "Flags": [], + "JSON": false, + "Original": "from alpine:3.19 as builder", + "SubCmd": "", + "Value": [ + "alpine:3.19", + "as", + "builder" + ], + "_kics_line": 4 + }, + { + "Cmd": "copy", + "EndLine": 6, + "Flags": [], + "JSON": false, + "Original": "copy . .", + "SubCmd": "", + "Value": [ + ".", + "." + ], + "_kics_line": 6 + }, + { + "Cmd": "healthcheck", + "EndLine": 8, + "Flags": [ + "--interval=30s", + "--timeout=30s", + "--start-period=5s", + "--retries=3" + ], + "JSON": true, + "Original": "healthcheck --interval=30s --timeout=30s --start-period=5s --retries=3 cmd [ \"executable\" ]", + "SubCmd": "", + "Value": [ + "cmd", + "executable" + ], + "_kics_line": 8 + } + ] + }, + "file": "file", + "id": "0" + }, + { + "args": [ + { + "Cmd": "arg", + "EndLine": 1, + "Flags": [], + "JSON": false, + "Original": "arg BASE_IMAGE=ubuntu:22.04", + "SubCmd": "", + "Value": [ + "BASE_IMAGE=ubuntu:22.04" + ], + "_kics_line": 1 + }, + { + "Cmd": "arg", + "EndLine": 4, + "Flags": [], + "JSON": false, + "Original": "arg JAR_FILE", + "SubCmd": "", + "Value": [ + "JAR_FILE" + ], + "_kics_line": 4 + } + ], + "command": { + "alpine:3.19 as builder": [ + { + "Cmd": "from", + "EndLine": 6, + "Flags": [], + "JSON": false, + "Original": "from alpine:3.19 as builder", + "SubCmd": "", + "Value": [ + "alpine:3.19", + "as", + "builder" + ], + "_kics_line": 6 + }, + { + "Cmd": "copy", + "EndLine": 8, + "Flags": [], + "JSON": false, + "Original": "copy . .", + "SubCmd": "", + "Value": [ + ".", + "." + ], + "_kics_line": 8 + }, + { + "Cmd": "healthcheck", + "EndLine": 10, + "Flags": [ + "--interval=30s", + "--timeout=30s", + "--start-period=5s", + "--retries=3" + ], + "JSON": true, + "Original": "healthcheck --interval=30s --timeout=30s --start-period=5s --retries=3 cmd [ \"executable\" ]", + "SubCmd": "", + "Value": [ + "cmd", + "executable" + ], + "_kics_line": 10 + } + ] + }, + "file": "file", + "id": "0" + }, + { + "args": [ + { + "Cmd": "arg", + "EndLine": 2, + "Flags": [], + "JSON": false, + "Original": "arg BASE_IMAGE=ubuntu:22.04", + "SubCmd": "", + "Value": [ + "BASE_IMAGE=ubuntu:22.04" + ], + "_kics_line": 2 + } + ], + "command": { + "alpine:3.19 as builder": [ + { + "Cmd": "from", + "EndLine": 6, + "Flags": [], + "JSON": false, + "Original": "from alpine:3.19 as builder", + "SubCmd": "", + "Value": [ + "alpine:3.19", + "as", + "builder" + ], + "_kics_line": 6 + }, + { + "Cmd": "copy", + "EndLine": 8, + "Flags": [], + "JSON": false, + "Original": "copy . .", + "SubCmd": "", + "Value": [ + ".", + "." + ], + "_kics_line": 8 + }, + { + "Cmd": "healthcheck", + "EndLine": 10, + "Flags": [ + "--interval=30s", + "--timeout=30s", + "--start-period=5s", + "--retries=3" + ], + "JSON": true, + "Original": "healthcheck --interval=30s --timeout=30s --start-period=5s --retries=3 cmd [ \"executable\" ]", + "SubCmd": "", + "Value": [ + "cmd", + "executable" + ], + "_kics_line": 10 + } + ] + }, + "file": "file", + "id": "0" + }, + { + "args": [ + { + "Cmd": "arg", + "EndLine": 1, + "Flags": [], + "JSON": false, + "Original": "arg BASE_IMAGE=ubuntu:22.04", + "SubCmd": "", + "Value": [ + "BASE_IMAGE=ubuntu:22.04" + ], + "_kics_line": 1 + } + ], + "command": { + "alpine:3.19 AS builder": [ + { + "Cmd": "from", + "EndLine": 4, + "Flags": [], + "JSON": false, + "Original": "from alpine:3.19 AS builder", + "SubCmd": "", + "Value": [ + "alpine:3.19", + "AS", + "builder" + ], + "_kics_line": 4 + }, + { + "Cmd": "copy", + "EndLine": 6, + "Flags": [], + "JSON": false, + "Original": "copy .. .", + "SubCmd": "", + "Value": [ + "..", + "." + ], + "_kics_line": 6 + }, + { + "Cmd": "healthcheck", + "EndLine": 8, + "Flags": [ + "--interval=30s", + "--timeout=30s", + "--start-period=5s", + "--retries=3" + ], + "JSON": true, + "Original": "healthcheck --interval=30s --timeout=30s --start-period=5s --retries=3 cmd [ \"executable\" ]", + "SubCmd": "", + "Value": [ + "cmd", + "executable" + ], + "_kics_line": 8 + } + ] + }, + "file": "file", + "id": "0" + }, + { + "args": [ + { + "Cmd": "arg", + "EndLine": 1, + "Flags": [], + "JSON": false, + "Original": "arg BASE_IMAGE=ubuntu:22.04", + "SubCmd": "", + "Value": [ + "BASE_IMAGE=ubuntu:22.04" + ], + "_kics_line": 1 + } + ], + "command": { + "alpine:3.19 as builder": [ + { + "Cmd": "from", + "EndLine": 3, + "Flags": [], + "JSON": false, + "Original": "from alpine:3.19 as builder", + "SubCmd": "", + "Value": [ + "alpine:3.19", + "as", + "builder" + ], + "_kics_line": 3 + }, + { + "Cmd": "copy", + "EndLine": 5, + "Flags": [], + "JSON": false, + "Original": "copy . .", + "SubCmd": "", + "Value": [ + ".", + "." + ], + "_kics_line": 5 + }, + { + "Cmd": "healthcheck", + "EndLine": 7, + "Flags": [ + "--interval=30s", + "--timeout=30s", + "--start-period=5s", + "--retries=3" + ], + "JSON": true, + "Original": "healthcheck --interval=30s --timeout=30s --start-period=5s --retries=3 cmd [ \"executable\" ]", + "SubCmd": "", + "Value": [ + "cmd", + "executable" + ], + "_kics_line": 7 + } + ] + }, + "file": "file", + "id": "0" + }, + { + "args": [], + "command": { + "alpine:latest": [ + { + "Cmd": "from", + "EndLine": 1, + "Flags": [], + "JSON": false, + "Original": "FROM alpine:latest", + "SubCmd": "", + "Value": [ + "alpine:latest" + ], + "_kics_line": 1 + }, + { + "Cmd": "copy", + "EndLine": 3, + "Flags": [], + "JSON": false, + "Original": "COPY {{ file_path }} /test", + "SubCmd": "", + "Value": [ + "{{", + "file_path", + "}}", + "/test" + ], + "_kics_line": 3 + }, + { + "Cmd": "run", + "EndLine": 5, + "Flags": [], + "JSON": false, + "Original": "RUN echo \"failure\"", + "SubCmd": "", + "Value": [ + "echo \"failure\"" + ], + "_kics_line": 5 + } + ] + }, + "file": "file", + "id": "0" + }, + { + "args": [], + "command": { + "alpine:3.19 AS builder": [ + { + "Cmd": "from", + "EndLine": 1, + "Flags": [], + "JSON": false, + "Original": "FROM alpine:3.19 AS builder", + "SubCmd": "", + "Value": [ + "alpine:3.19", + "AS", + "builder" + ], + "_kics_line": 1 + }, + { + "Cmd": "copy", + "EndLine": 3, + "Flags": [], + "JSON": false, + "Original": "COPY . .", + "SubCmd": "", + "Value": [ + ".", + "." + ], + "_kics_line": 3 + }, + { + "Cmd": "healthcheck", + "EndLine": 5, + "Flags": [ + "--interval=30s", + "--timeout=30s", + "--start-period=5s", + "--retries=3" + ], + "JSON": true, + "Original": "HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 CMD [ \"executable\" ]", + "SubCmd": "", + "Value": [ + "CMD", + "executable" + ], + "_kics_line": 5 + } + ] + }, + "file": "file", + "id": "0" + }, + { + "args": [], + "command": { + "alpine:3.19 AS builder": [ + { + "Cmd": "from", + "EndLine": 1, + "Flags": [], + "JSON": false, + "Original": "FROM alpine:3.19 AS builder", + "SubCmd": "", + "Value": [ + "alpine:3.19", + "AS", + "builder" + ], + "_kics_line": 1 + }, + { + "Cmd": "copy", + "EndLine": 3, + "Flags": [], + "JSON": false, + "Original": "COPY . .", + "SubCmd": "", + "Value": [ + ".", + "." + ], + "_kics_line": 3 + }, + { + "Cmd": "healthcheck", + "EndLine": 5, + "Flags": [ + "--interval=30s", + "--timeout=30s", + "--start-period=5s", + "--retries=3" + ], + "JSON": true, + "Original": "HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 CMD [ \"executable\" ]", + "SubCmd": "", + "Value": [ + "CMD", + "executable" + ], + "_kics_line": 5 + } + ] + }, + "file": "file", + "id": "0" + }, + { + "args": [], + "command": { + "alpine:3.19 AS builder": [ + { + "Cmd": "from", + "EndLine": 1, + "Flags": [], + "JSON": false, + "Original": "FROM alpine:3.19 AS builder", + "SubCmd": "", + "Value": [ + "alpine:3.19", + "AS", + "builder" + ], + "_kics_line": 1 + }, + { + "Cmd": "copy", + "EndLine": 3, + "Flags": [], + "JSON": false, + "Original": "COPY . .", + "SubCmd": "", + "Value": [ + ".", + "." + ], + "_kics_line": 3 + }, + { + "Cmd": "healthcheck", + "EndLine": 5, + "Flags": [ + "--interval=30s", + "--timeout=30s", + "--start-period=5s", + "--retries=3" + ], + "JSON": true, + "Original": "HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 CMD [ \"executable\" ]", + "SubCmd": "", + "Value": [ + "CMD", + "executable" + ], + "_kics_line": 5 + } + ] + }, + "file": "file", + "id": "0" + }, + { + "args": [], + "command": { + "alpine:3.19 AS builder": [ + { + "Cmd": "from", + "EndLine": 1, + "Flags": [], + "JSON": false, + "Original": "FROM alpine:3.19 AS builder", + "SubCmd": "", + "Value": [ + "alpine:3.19", + "AS", + "builder" + ], + "_kics_line": 1 + }, + { + "Cmd": "copy", + "EndLine": 3, + "Flags": [], + "JSON": false, + "Original": "COPY . .", + "SubCmd": "", + "Value": [ + ".", + "." + ], + "_kics_line": 3 + }, + { + "Cmd": "healthcheck", + "EndLine": 5, + "Flags": [ + "--interval=30s", + "--timeout=30s", + "--start-period=5s", + "--retries=3" + ], + "JSON": true, + "Original": "HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 CMD [ \"executable\" ]", + "SubCmd": "", + "Value": [ + "CMD", + "executable" + ], + "_kics_line": 5 + } + ] + }, + "file": "file", + "id": "0" + }, + { + "args": [], + "command": { + "alpine:3.19 AS builder": [ + { + "Cmd": "from", + "EndLine": 1, + "Flags": [], + "JSON": false, + "Original": "FROM alpine:3.19 AS builder", + "SubCmd": "", + "Value": [ + "alpine:3.19", + "AS", + "builder" + ], + "_kics_line": 1 + }, + { + "Cmd": "copy", + "EndLine": 3, + "Flags": [], + "JSON": false, + "Original": "COPY . .", + "SubCmd": "", + "Value": [ + ".", + "." + ], + "_kics_line": 3 + }, + { + "Cmd": "healthcheck", + "EndLine": 5, + "Flags": [ + "--interval=30s", + "--timeout=30s", + "--start-period=5s", + "--retries=3" + ], + "JSON": true, + "Original": "HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 CMD [ \"executable\" ]", + "SubCmd": "", + "Value": [ + "CMD", + "executable" + ], + "_kics_line": 5 + } + ] + }, + "file": "file", + "id": "0" + }, + { + "args": [], + "command": { + "alpine:3.19 AS builder": [ + { + "Cmd": "from", + "EndLine": 1, + "Flags": [], + "JSON": false, + "Original": "FROM alpine:3.19 AS builder", + "SubCmd": "", + "Value": [ + "alpine:3.19", + "AS", + "builder" + ], + "_kics_line": 1 + }, + { + "Cmd": "copy", + "EndLine": 3, + "Flags": [], + "JSON": false, + "Original": "COPY . .", + "SubCmd": "", + "Value": [ + ".", + "." + ], + "_kics_line": 3 + }, + { + "Cmd": "healthcheck", + "EndLine": 5, + "Flags": [ + "--interval=30s", + "--timeout=30s", + "--start-period=5s", + "--retries=3" + ], + "JSON": true, + "Original": "HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 CMD [ \"executable\" ]", + "SubCmd": "", + "Value": [ + "CMD", + "executable" + ], + "_kics_line": 5 + } + ] + }, + "file": "file", + "id": "0" + }, + { + "args": [ + { + "Cmd": "package", + "EndLine": 1, + "Flags": [], + "JSON": false, + "Original": "package main", + "SubCmd": "", + "Value": [ + "" + ], + "_kics_line": 1 + }, + { + "Cmd": "import", + "EndLine": 3, + "Flags": [], + "JSON": false, + "Original": "import \"fmt\"", + "SubCmd": "", + "Value": [ + "" + ], + "_kics_line": 3 + }, + { + "Cmd": "func", + "EndLine": 5, + "Flags": [], + "JSON": false, + "Original": "func main() {", + "SubCmd": "", + "Value": [ + "" + ], + "_kics_line": 5 + }, + { + "Cmd": "fmt.println(\"hello,", + "EndLine": 6, + "Flags": [], + "JSON": false, + "Original": "fmt.Println(\"Hello, World!\")", + "SubCmd": "", + "Value": [ + "" + ], + "_kics_line": 6 + }, + { + "Cmd": "}", + "EndLine": 7, + "Flags": null, + "JSON": false, + "Original": "}", + "SubCmd": "", + "Value": [ + "" + ], + "_kics_line": 7 + } + ], + "command": {}, + "file": "file", + "id": "0" + }, + { + "args": [ + { + "Cmd": "public", + "EndLine": 1, + "Flags": [], + "JSON": false, + "Original": "public class HelloWorld {", + "SubCmd": "", + "Value": [ + "" + ], + "_kics_line": 1 + }, + { + "Cmd": "public", + "EndLine": 2, + "Flags": [], + "JSON": false, + "Original": "public static void main(String[] args) {", + "SubCmd": "", + "Value": [ + "" + ], + "_kics_line": 2 + }, + { + "Cmd": "system.out.println(\"hello,", + "EndLine": 3, + "Flags": [], + "JSON": false, + "Original": "System.out.println(\"Hello, World!\");", + "SubCmd": "", + "Value": [ + "" + ], + "_kics_line": 3 + }, + { + "Cmd": "}", + "EndLine": 4, + "Flags": null, + "JSON": false, + "Original": "}", + "SubCmd": "", + "Value": [ + "" + ], + "_kics_line": 4 + }, + { + "Cmd": "}", + "EndLine": 5, + "Flags": null, + "JSON": false, + "Original": "}", + "SubCmd": "", + "Value": [ + "" + ], + "_kics_line": 5 + } + ], + "command": {}, + "file": "file", + "id": "0" + } + ] +} diff --git a/e2e/testcases/e2e-cli-075_ansible_host_detected.go b/e2e/testcases/e2e-cli-075_ansible_host_detected.go index 241bf3a7d21..b261a1d32ea 100644 --- a/e2e/testcases/e2e-cli-075_ansible_host_detected.go +++ b/e2e/testcases/e2e-cli-075_ansible_host_detected.go @@ -4,7 +4,7 @@ package testcases // 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]", + Name: "should perform a valid scan and detect ansible [E2E-CLI-075]", Args: args{ Args: []cmdArgs{ []string{"scan", "-o", "/path/e2e/output", diff --git a/e2e/testcases/e2e-cli-106_valid_dockerfile_detected.go b/e2e/testcases/e2e-cli-106_valid_dockerfile_detected.go new file mode 100644 index 00000000000..a7d46870aaa --- /dev/null +++ b/e2e/testcases/e2e-cli-106_valid_dockerfile_detected.go @@ -0,0 +1,31 @@ +package testcases + +// E2E-CLI-106 - KICS scan +// should perform the scan successfully detect all valid dockerfile documents and return result 50 +func init() { //nolint + testSample := TestCase{ + Name: "should perform a valid scan with all dockerfile documents parsed [E2E-CLI-106]", + Args: args{ + Args: []cmdArgs{ + []string{"scan", "-o", "/path/e2e/output", + "--output-name", "E2E_CLI_106_RESULT", + "-p", "/path/test/fixtures/dockerfile", + "-p", "/path/test/fixtures/negative_dockerfile", + "--payload-path", "/path/e2e/output/E2E_CLI_106_PAYLOAD.json", + }, + }, + ExpectedResult: []ResultsValidation{ + { + ResultsFile: "E2E_CLI_106_RESULT", + ResultsFormats: []string{"json"}, + }, + }, + ExpectedPayload: []string{ + "E2E_CLI_106_PAYLOAD.json", + }, + }, + WantStatus: []int{50}, + } + + Tests = append(Tests, testSample) +} diff --git a/pkg/analyzer/analyzer.go b/pkg/analyzer/analyzer.go index 83ac9f8a359..901c9b00589 100644 --- a/pkg/analyzer/analyzer.go +++ b/pkg/analyzer/analyzer.go @@ -98,22 +98,20 @@ var ( listKeywordsGoogleDeployment = []string{"resources"} armRegexTypes = []string{"blueprint", "templateArtifact", "roleAssignmentArtifact", "policyAssignmentArtifact"} possibleFileTypes = map[string]bool{ - ".yml": true, - ".yaml": true, - ".json": true, - ".dockerfile": true, - "Dockerfile": true, - "possibleDockerfile": true, - ".debian": true, - ".ubi8": true, - ".tf": true, - "tfvars": true, - ".proto": true, - ".sh": true, - ".cfg": true, - ".conf": true, - ".ini": true, - ".bicep": true, + ".yml": true, + ".yaml": true, + ".json": true, + ".dockerfile": true, + ".debian": true, + ".ubi8": true, + ".tf": true, + "tfvars": true, + ".proto": true, + ".sh": true, + ".cfg": true, + ".conf": true, + ".ini": true, + ".bicep": true, } supportedRegexes = map[string][]string{ "azureresourcemanager": append(armRegexTypes, arm), @@ -430,26 +428,18 @@ func (a *analyzerInfo) worker( //nolint: gocyclo }() ext, errExt := utils.GetExtension(a.filePath) + if errExt == nil { linesCount, _ := utils.LineCounter(a.filePath, a.fallbackMinifiedFileLOC) switch ext { - // Dockerfile (direct identification) - case ".dockerfile", "Dockerfile": + // Dockerfile + case ".dockerfile": if a.isAvailableType(dockerfile) { results <- dockerfile locCount <- linesCount fileInfo <- fileTypeInfo{filePath: a.filePath, fileType: dockerfile, locCount: linesCount} } - // Dockerfile (indirect identification) - case "possibleDockerfile", ".ubi8", ".debian": - if a.isAvailableType(dockerfile) && isDockerfile(a.filePath) { - results <- dockerfile - locCount <- linesCount - fileInfo <- fileTypeInfo{filePath: a.filePath, fileType: dockerfile, locCount: linesCount} - } else { - unwanted <- a.filePath - } // Terraform case ".tf", "tfvars": if a.isAvailableType(terraform) { @@ -487,30 +477,6 @@ func (a *analyzerInfo) worker( //nolint: gocyclo } } -func isDockerfile(path string) bool { - content, err := os.ReadFile(filepath.Clean(path)) - if err != nil { - log.Error().Msgf("failed to analyze file: %s", err) - return false - } - - regexes := []*regexp.Regexp{ - regexp.MustCompile(`\s*FROM\s*`), - regexp.MustCompile(`\s*RUN\s*`), - } - - check := true - - for _, regex := range regexes { - if !regex.Match(content) { - check = false - break - } - } - - return check -} - // overrides k8s match when all regexes pass for azureresourcemanager key and extension is set to json func needsOverride(check bool, returnType, key, ext string) bool { if check && returnType == kubernetes && key == arm && ext == json { diff --git a/pkg/analyzer/analyzer_test.go b/pkg/analyzer/analyzer_test.go index ea7adcf7f69..cce93881918 100644 --- a/pkg/analyzer/analyzer_test.go +++ b/pkg/analyzer/analyzer_test.go @@ -151,7 +151,6 @@ func TestAnalyzer_Analyze(t *testing.T) { wantExclude: []string{ filepath.FromSlash("../../test/fixtures/gitignore/positive.dockerfile"), filepath.FromSlash("../../test/fixtures/gitignore/secrets.tf"), - filepath.FromSlash("../../test/fixtures/gitignore/gitignore"), }, typesFromFlag: []string{""}, excludeTypesFromFlag: []string{""}, @@ -167,7 +166,7 @@ func TestAnalyzer_Analyze(t *testing.T) { filepath.FromSlash("../../test/fixtures/gitignore"), }, wantTypes: []string{"dockerfile", "kubernetes", "terraform"}, - wantExclude: []string{filepath.FromSlash("../../test/fixtures/gitignore/gitignore")}, + wantExclude: []string{}, typesFromFlag: []string{""}, excludeTypesFromFlag: []string{""}, wantLOC: 42, diff --git a/pkg/parser/docker/parser.go b/pkg/parser/docker/parser.go index 7f97835b07e..a676b1cfee7 100644 --- a/pkg/parser/docker/parser.go +++ b/pkg/parser/docker/parser.go @@ -59,7 +59,7 @@ func (p *Parser) Parse(_ string, fileContent []byte) ([]model.Document, []int, e for _, child := range parsed.AST.Children { child.Value = strings.ToLower(child.Value) if child.Value == "from" { - fromValue = strings.TrimPrefix(child.Original, "FROM ") + fromValue = child.Original[5:] } if ignoreStruct.getIgnoreComments(child) { @@ -133,7 +133,7 @@ func (p *Parser) GetKind() model.FileKind { // SupportedExtensions returns Dockerfile extensions func (p *Parser) SupportedExtensions() []string { - return []string{"Dockerfile", ".dockerfile", ".ubi8", ".debian", "possibleDockerfile"} + return []string{".dockerfile", ".ubi8", ".debian"} } // SupportedTypes returns types supported by this parser, which are dockerfile diff --git a/pkg/parser/docker/parser_test.go b/pkg/parser/docker/parser_test.go index 3f6d6076ba9..e5bc4d14783 100644 --- a/pkg/parser/docker/parser_test.go +++ b/pkg/parser/docker/parser_test.go @@ -17,7 +17,7 @@ func TestParser_GetKind(t *testing.T) { // TestParser_SupportedExtensions tests the functions [SupportedExtensions()] and all the methods called by them func TestParser_SupportedExtensions(t *testing.T) { p := &Parser{} - require.Equal(t, []string{"Dockerfile", ".dockerfile", ".ubi8", ".debian", "possibleDockerfile"}, p.SupportedExtensions()) + require.Equal(t, []string{".dockerfile", ".ubi8", ".debian"}, p.SupportedExtensions()) } // TestParser_SupportedExtensions tests the functions [SupportedTypes()] and all the methods called by them @@ -235,3 +235,46 @@ func TestParser_GetResolvedFiles(t *testing.T) { }) } } + +// TestParser_Parse_CaseInsensitive tests that the parser handles Dockerfile commands +// in a case-insensitive manner +func TestParser_Parse_CaseInsensitive(t *testing.T) { + p := &Parser{} + // baseline sample + upper := ` +FROM alpine:3.18 +RUN echo "hello" +` + lower := ` +from alpine:3.18 +run echo "hello" +` + mixed := ` +fRoM alpine:3.18 +rUn echo "hello" +` + + docUpper, _, err := p.Parse("Dockerfile", []byte(upper)) + require.NoError(t, err) + require.Len(t, docUpper, 1) + cmdsUpper := docUpper[0]["command"].(map[string]interface{})["alpine:3.18"].([]interface{}) + + docLower, _, err := p.Parse("Dockerfile", []byte(lower)) + require.NoError(t, err) + require.Len(t, docLower, 1) + cmdsLower := docLower[0]["command"].(map[string]interface{})["alpine:3.18"].([]interface{}) + require.Len(t, cmdsUpper, len(cmdsLower)) + + docMixed, _, err := p.Parse("Dockerfile", []byte(mixed)) + require.NoError(t, err) + require.Len(t, docMixed, 1) + cmdsMixed := docMixed[0]["command"].(map[string]interface{})["alpine:3.18"].([]interface{}) + require.Len(t, cmdsUpper, len(cmdsMixed)) + + for i := range cmdsUpper { + require.Equal(t, cmdsUpper[i].(map[string]interface{})["Cmd"], cmdsMixed[i].(map[string]interface{})["Cmd"]) + require.Equal(t, cmdsUpper[i].(map[string]interface{})["Value"], cmdsMixed[i].(map[string]interface{})["Value"]) + require.Equal(t, cmdsUpper[i].(map[string]interface{})["Cmd"], cmdsLower[i].(map[string]interface{})["Cmd"]) + require.Equal(t, cmdsUpper[i].(map[string]interface{})["Value"], cmdsLower[i].(map[string]interface{})["Value"]) + } +} diff --git a/pkg/parser/parser_test.go b/pkg/parser/parser_test.go index 73d1f4d44b7..0eff1ce94ea 100644 --- a/pkg/parser/parser_test.go +++ b/pkg/parser/parser_test.go @@ -94,7 +94,6 @@ func TestParser_SupportedExtensions(t *testing.T) { require.Contains(t, extensions, ".tf") require.Contains(t, extensions, ".yaml") require.Contains(t, extensions, ".dockerfile") - require.Contains(t, extensions, "Dockerfile") } func initilizeBuilder() []*Parser { diff --git a/pkg/remediation/scan.go b/pkg/remediation/scan.go index e48f5648ee0..b95ebfb65b2 100644 --- a/pkg/remediation/scan.go +++ b/pkg/remediation/scan.go @@ -95,7 +95,7 @@ func getPayload(filePath string, content []byte, openAPIResolveReferences bool, var err error switch ext { - case ".dockerfile", "Dockerfile", "possibleDockerfile", ".ubi8", ".debian": + case ".dockerfile", ".ubi8", ".debian": p, err = parser.NewBuilder().Add(&dockerParser.Parser{}).Build([]string{""}, []string{""}) case terraformExtension: diff --git a/pkg/utils/get_extension.go b/pkg/utils/get_extension.go index cfc9bc48861..ec1f300cb28 100644 --- a/pkg/utils/get_extension.go +++ b/pkg/utils/get_extension.go @@ -14,9 +14,7 @@ import ( // GetExtension gets the extension of a file path func GetExtension(path string) (string, error) { - targets := []string{"Dockerfile", "tfvars"} - - // Get file information + extDockerfile := ".dockerfile" fileInfo, err := os.Stat(path) if err != nil { return "", fmt.Errorf("file %s not found", path) @@ -26,35 +24,54 @@ func GetExtension(path string) (string, error) { return "", fmt.Errorf("the path %s is a directory", path) } + if ext, ok := isDockerfileExtension(path, extDockerfile); ok { + return ext, nil + } + ext := filepath.Ext(path) - if ext == "" { - base := filepath.Base(path) + switch ext { + case ".ubi8", ".debian": + if readPossibleDockerFile(path) { + return extDockerfile, nil + } + case "": + if filepath.Base(path) == "tfvars" { + return ".tfvars", nil + } + isText, err := isTextFile(path) + if err != nil { + return "", err + } + if isText && readPossibleDockerFile(path) { + return extDockerfile, nil + } + } + return ext, nil +} - if Contains(base, targets) { - ext = base - } else { - isText, err := isTextFile(path) +func isDockerfileExtension(path, extDockerfile string) (string, bool) { + base := filepath.Base(path) + d := "dockerfile" - if err != nil { - return "", err - } + lower := strings.ToLower(base) + if lower == d || strings.HasPrefix(lower, "dockerfile.") { + return extDockerfile, true + } - if isText { - if readPossibleDockerFile(path) { - ext = "possibleDockerfile" - } - } - } + if strings.EqualFold(filepath.Ext(path), extDockerfile) { + return extDockerfile, true } - return ext, nil + dir := strings.ToLower(filepath.Base(filepath.Dir(path))) + if (dir == "docker" || dir == d || dir == "dockerfiles") && readPossibleDockerFile(path) { + return extDockerfile, true + } + + return "", false } func readPossibleDockerFile(path string) bool { path = filepath.Clean(path) - if strings.HasSuffix(path, "gitignore") { - return true - } file, err := os.Open(path) if err != nil { return false @@ -68,12 +85,14 @@ func readPossibleDockerFile(path string) bool { scanner := bufio.NewScanner(file) // Read lines from the file for scanner.Scan() { - if strings.HasPrefix(scanner.Text(), "FROM") { - return true - } else if strings.HasPrefix(scanner.Text(), "#") { + if strings.HasPrefix(scanner.Text(), "#") || strings.HasPrefix(strings.ToLower(scanner.Text()), "arg") || scanner.Text() == "" { continue } else { - return false + if strings.HasPrefix(strings.ToLower(scanner.Text()), "from ") { + return true + } else { + return false + } } } return false diff --git a/pkg/utils/get_extension_test.go b/pkg/utils/get_extension_test.go index 73f5955effa..37df89de556 100644 --- a/pkg/utils/get_extension_test.go +++ b/pkg/utils/get_extension_test.go @@ -18,22 +18,106 @@ func TestGetExtension(t *testing.T) { }{ { name: "Get extension from a file named as Dockerfile and without extension defined ('Dockerfile')", - want: "Dockerfile", + want: ".dockerfile", filePath: "../../Dockerfile", toCreate: false, err: nil, }, { - name: "Get extension from a file not named as Dockerfile and without extension defined ('Dockerfile-example')", - want: "possibleDockerfile", - filePath: "../../test/fixtures/dockerfile/Dockerfile-example", + name: "Get extension from a file named as dockerFILE and without extension defined ('dockerFILE')", + want: ".dockerfile", + filePath: "../../test/fixtures/dockerfile/any_name/dockerFILE", toCreate: false, err: nil, }, { - name: "Get extension from a file with extension defined ('positive.tf')", - want: ".tf", - filePath: "../../test/fixtures/all_auth_users_get_read_access/test/positive.tf", + name: "Get extension from a file not named 'dockerfile' with extension defined as Dockerfile ('file.Dockerfile')", + want: ".dockerfile", + filePath: "../../test/fixtures/dockerfile/any_name/file.Dockerfile", + toCreate: false, + err: nil, + }, + { + name: "Get extension from a file not named 'dockerfile' with extension defined as DOCKERfile ('file_2.DOCKERfile')", + want: ".dockerfile", + filePath: "../../test/fixtures/dockerfile/any_name/file_2.DOCKERfile", + toCreate: false, + err: nil, + }, + { + name: "Get extension from a file named 'Dockerfile' with any extension defined ('Dockerfile.something')", + want: ".dockerfile", + filePath: "../../test/fixtures/dockerfile/any_name/Dockerfile.something", + toCreate: false, + err: nil, + }, + { + name: "Get extension from a file named 'DOCKERfile' with any extension defined ('DOCKERfile.txt')", + want: ".dockerfile", + filePath: "../../test/fixtures/dockerfile/any_name/DOCKERfile.txt", + toCreate: false, + err: nil, + }, + { + name: "Get extension from a file not named as Dockerfile and without a relevant extension defined ('any_file.txt'), should detect due to parent folder 'docker'", + want: ".dockerfile", + filePath: "../../test/fixtures/dockerfile/test_folder_names/docker/any_file.txt", + toCreate: false, + err: nil, + }, + { + name: "Get extension from a file not named as Dockerfile and without a relevant extension defined ('any_file.txt'), should detect due to parent folder 'Docker'", + want: ".dockerfile", + filePath: "../../test/fixtures/dockerfile/test_folder_names_case/Docker/any_file.txt", + toCreate: false, + err: nil, + }, + { + name: "Get extension from a file not named as Dockerfile and without a relevant extension defined ('any_file.txt'), should detect due to parent folder 'dockerfile'", + want: ".dockerfile", + filePath: "../../test/fixtures/dockerfile/test_folder_names/dockerfile/any_file.txt", + toCreate: false, + err: nil, + }, + { + name: "Get extension from a file not named as Dockerfile and without a relevant extension defined ('any_file.txt'), should detect due to parent folder 'Dockerfile'", + want: ".dockerfile", + filePath: "../../test/fixtures/dockerfile/test_folder_names_case/Dockerfile/any_file.txt", + toCreate: false, + err: nil, + }, + { + name: "Get extension from a file not named as Dockerfile and without a relevant extension defined ('any_file.txt'), should detect due to parent folder 'dockerfiles'", + want: ".dockerfile", + filePath: "../../test/fixtures/dockerfile/test_folder_names/dockerfiles/any_file.txt", + toCreate: false, + err: nil, + }, + { + name: "Get extension from a file not named as Dockerfile and without a relevant extension defined ('any_file.txt'), should detect due to parent folder 'Dockerfiles'", + want: ".dockerfile", + filePath: "../../test/fixtures/dockerfile/test_folder_names_case/Dockerfiles/any_file.txt", + toCreate: false, + err: nil, + }, + { + name: "Get extension from a file not named as Dockerfile and without extension defined ('random_name'), due to parent folder scan will identify dockerfile syntax regardless", + want: ".dockerfile", + filePath: "../../test/fixtures/dockerfile/any_name/random_name", + toCreate: false, + err: nil, + }, + { + name: "Get extension from a valid text file with dockerfile syntax and '.ubi8' extension ('any_name.ubi8')", + want: ".dockerfile", + filePath: "../../test/fixtures/dockerfile/any_name/any_name.ubi8", + toCreate: false, + err: nil, + }, + { + name: "Get extension from a valid text file with dockerfile syntax and '.debian' extension ('any_name.debian')", + want: ".dockerfile", + filePath: "../../test/fixtures/dockerfile/any_name/any_name.debian", toCreate: false, err: nil, }, @@ -44,6 +128,27 @@ func TestGetExtension(t *testing.T) { toCreate: false, err: nil, }, + { + name: "Get literal extension from a file not named as Dockerfile and with extension that is not .dockerfile,.ubi8 or .debian, regardless of text syntax", + want: ".txt", + filePath: "../../test/fixtures/negative_dockerfile/not_dockerfile.txt", + toCreate: false, + err: nil, + }, + { + name: "Get literal extension from a valid text file with '.ubi8' extension that lacks relevant dockerfile syntax('any_name.ubi8')", + want: ".ubi8", + filePath: "../../test/fixtures/negative_dockerfile/not_dockerfile.ubi8", + toCreate: false, + err: nil, + }, + { + name: "Get literal extension from a valid text file with '.debian' extension that lacks relevant dockerfile syntax('any_name.debian')", + want: ".debian", + filePath: "../../test/fixtures/negative_dockerfile/not_dockerfile.debian", + toCreate: false, + err: nil, + }, { name: "Get error when analyze a folder", want: "", @@ -51,6 +156,69 @@ func TestGetExtension(t *testing.T) { toCreate: true, err: fmt.Errorf("the path %s is a directory", "../../test/fixtures/for_test_folder"), }, + { + name: "Get extension from a file with extension defined ('positive.tf')", + want: ".tf", + filePath: "../../test/fixtures/all_auth_users_get_read_access/test/positive.tf", + toCreate: false, + err: nil, + }, + { + name: "(Case_insensitive_tests) -- Get extension from a file named as dockerFILE and without extension defined ('dockerFILE')", + want: ".dockerfile", + filePath: "../../test/fixtures/dockerfile/case_insensitive_tests/dockerFILE", + toCreate: false, + err: nil, + }, + { + name: "(Case_insensitive_tests) -- Get extension from a file not named 'dockerfile' with extension defined as Dockerfile ('file.Dockerfile')", + want: ".dockerfile", + filePath: "../../test/fixtures/dockerfile/case_insensitive_tests/file.Dockerfile", + toCreate: false, + err: nil, + }, + { + name: "(Case_insensitive_tests) -- Get extension from a file not named 'dockerfile' with extension defined as DOCKERfile ('file_2.DOCKERfile')", + want: ".dockerfile", + filePath: "../../test/fixtures/dockerfile/case_insensitive_tests/file_2.DOCKERfile", + toCreate: false, + err: nil, + }, + { + name: "(Case_insensitive_tests) -- Get extension from a file named 'Dockerfile' with any extension defined ('Dockerfile.something')", + want: ".dockerfile", + filePath: "../../test/fixtures/dockerfile/case_insensitive_tests/Dockerfile.something", + toCreate: false, + err: nil, + }, + { + name: "(Case_insensitive_tests) -- Get extension from a file named 'DOCKERfile' with any extension defined ('DOCKERfile.txt')", + want: ".dockerfile", + filePath: "../../test/fixtures/dockerfile/case_insensitive_tests/DOCKERfile.txt", + toCreate: false, + err: nil, + }, + { + name: "(Case_insensitive_tests) -- Get extension from a file not named as Dockerfile and without extension defined ('random_name'), due to parent folder scan will identify dockerfile syntax regardless", + want: ".dockerfile", + filePath: "../../test/fixtures/dockerfile/case_insensitive_tests/random_name", + toCreate: false, + err: nil, + }, + { + name: "(Case_insensitive_tests) -- Get extension from a valid text file with dockerfile syntax and '.ubi8' extension ('any_name.ubi8')", + want: ".dockerfile", + filePath: "../../test/fixtures/dockerfile/case_insensitive_tests/any_name.ubi8", + toCreate: false, + err: nil, + }, + { + name: "(Case_insensitive_tests) -- Get extension from a valid text file with dockerfile syntax and '.debian' extension ('any_name.debian')", + want: ".dockerfile", + filePath: "../../test/fixtures/dockerfile/case_insensitive_tests/any_name.debian", + toCreate: false, + err: nil, + }, } for _, test := range tests { diff --git a/test/fixtures/dockerfile/Dockerfile-example b/test/fixtures/dockerfile/Dockerfile-example index 4bd67e4f18f..d7d7935b60b 100644 --- a/test/fixtures/dockerfile/Dockerfile-example +++ b/test/fixtures/dockerfile/Dockerfile-example @@ -1,7 +1,7 @@ FROM openjdk:10-jdk VOLUME /tmp ADD http://source.file/package.file.tar.gz /temp -RUN tar -xjf /temp/package.file.tar.gz +RUN tar -xjf /temp/package.file.tar.gz ARG JAR_FILE ADD ${JAR_FILE} app.jar ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"] diff --git a/test/fixtures/dockerfile/any_name/DOCKERfile.txt b/test/fixtures/dockerfile/any_name/DOCKERfile.txt new file mode 100644 index 00000000000..6ff5c5c2694 --- /dev/null +++ b/test/fixtures/dockerfile/any_name/DOCKERfile.txt @@ -0,0 +1,17 @@ + + + + + + + + + + + + +FROM alpine:3.19 AS builder + +COPY . . + +HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 CMD [ "executable" ] \ No newline at end of file diff --git a/test/fixtures/dockerfile/any_name/Dockerfile.something b/test/fixtures/dockerfile/any_name/Dockerfile.something new file mode 100644 index 00000000000..9b120bfb8ab --- /dev/null +++ b/test/fixtures/dockerfile/any_name/Dockerfile.something @@ -0,0 +1,8 @@ +ARG VERSION=1.0 +ARG BASE_IMAGE=ubuntu:22.04 + +FROM alpine:3.19 AS builder + +COPY . . + +HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 CMD [ "executable" ] \ No newline at end of file diff --git a/test/fixtures/dockerfile/any_name/any_name.debian b/test/fixtures/dockerfile/any_name/any_name.debian new file mode 100644 index 00000000000..9b120bfb8ab --- /dev/null +++ b/test/fixtures/dockerfile/any_name/any_name.debian @@ -0,0 +1,8 @@ +ARG VERSION=1.0 +ARG BASE_IMAGE=ubuntu:22.04 + +FROM alpine:3.19 AS builder + +COPY . . + +HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 CMD [ "executable" ] \ No newline at end of file diff --git a/test/fixtures/dockerfile/any_name/any_name.ubi8 b/test/fixtures/dockerfile/any_name/any_name.ubi8 new file mode 100644 index 00000000000..9b120bfb8ab --- /dev/null +++ b/test/fixtures/dockerfile/any_name/any_name.ubi8 @@ -0,0 +1,8 @@ +ARG VERSION=1.0 +ARG BASE_IMAGE=ubuntu:22.04 + +FROM alpine:3.19 AS builder + +COPY . . + +HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 CMD [ "executable" ] \ No newline at end of file diff --git a/test/fixtures/dockerfile/any_name/dockerFILE b/test/fixtures/dockerfile/any_name/dockerFILE new file mode 100644 index 00000000000..151a7d85c3b --- /dev/null +++ b/test/fixtures/dockerfile/any_name/dockerFILE @@ -0,0 +1,10 @@ +ARG BASE_IMAGE=ubuntu:22.04 + +# Comments between arg +ARG JAR_FILE + +FROM alpine:3.19 AS builder + +COPY . . + +HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 CMD [ "executable" ] \ No newline at end of file diff --git a/test/fixtures/dockerfile/any_name/file.Dockerfile b/test/fixtures/dockerfile/any_name/file.Dockerfile new file mode 100644 index 00000000000..991a057479f --- /dev/null +++ b/test/fixtures/dockerfile/any_name/file.Dockerfile @@ -0,0 +1,10 @@ +# Comments before arg +ARG BASE_IMAGE=ubuntu:22.04 + +# Comments after arg + +FROM alpine:3.19 AS builder + +COPY . . + +HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 CMD [ "executable" ] diff --git a/test/fixtures/dockerfile/any_name/file_2.DOCKERfile b/test/fixtures/dockerfile/any_name/file_2.DOCKERfile new file mode 100644 index 00000000000..589ac77f479 --- /dev/null +++ b/test/fixtures/dockerfile/any_name/file_2.DOCKERfile @@ -0,0 +1,8 @@ +ARG BASE_IMAGE=ubuntu:22.04 +# Comments before FROM + +FROM alpine:3.19 AS builder + +COPY .. . + +HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 CMD [ "executable" ] diff --git a/test/fixtures/dockerfile/any_name/random_name b/test/fixtures/dockerfile/any_name/random_name new file mode 100644 index 00000000000..ca2ebdfb132 --- /dev/null +++ b/test/fixtures/dockerfile/any_name/random_name @@ -0,0 +1,7 @@ +ARG BASE_IMAGE=ubuntu:22.04 + +FROM alpine:3.19 AS builder + +COPY . . + +HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 CMD [ "executable" ] \ No newline at end of file diff --git a/test/fixtures/dockerfile/case_insensitive_tests/DOCKERfile.txt b/test/fixtures/dockerfile/case_insensitive_tests/DOCKERfile.txt new file mode 100644 index 00000000000..453f5147d38 --- /dev/null +++ b/test/fixtures/dockerfile/case_insensitive_tests/DOCKERfile.txt @@ -0,0 +1,17 @@ + + + + + + + + + + + + +from alpine:3.19 as builder + +copy . . + +healthcheck --interval=30s --timeout=30s --start-period=5s --retries=3 cmd [ "executable" ] \ No newline at end of file diff --git a/test/fixtures/dockerfile/case_insensitive_tests/Dockerfile.something b/test/fixtures/dockerfile/case_insensitive_tests/Dockerfile.something new file mode 100644 index 00000000000..104b1d85e89 --- /dev/null +++ b/test/fixtures/dockerfile/case_insensitive_tests/Dockerfile.something @@ -0,0 +1,8 @@ +arg VERSION=1.0 +arg BASE_IMAGE=ubuntu:22.04 + +from alpine:3.19 as builder + +copy . . + +healthcheck --interval=30s --timeout=30s --start-period=5s --retries=3 cmd [ "executable" ] \ No newline at end of file diff --git a/test/fixtures/dockerfile/case_insensitive_tests/any_name.debian b/test/fixtures/dockerfile/case_insensitive_tests/any_name.debian new file mode 100644 index 00000000000..104b1d85e89 --- /dev/null +++ b/test/fixtures/dockerfile/case_insensitive_tests/any_name.debian @@ -0,0 +1,8 @@ +arg VERSION=1.0 +arg BASE_IMAGE=ubuntu:22.04 + +from alpine:3.19 as builder + +copy . . + +healthcheck --interval=30s --timeout=30s --start-period=5s --retries=3 cmd [ "executable" ] \ No newline at end of file diff --git a/test/fixtures/dockerfile/case_insensitive_tests/any_name.ubi8 b/test/fixtures/dockerfile/case_insensitive_tests/any_name.ubi8 new file mode 100644 index 00000000000..104b1d85e89 --- /dev/null +++ b/test/fixtures/dockerfile/case_insensitive_tests/any_name.ubi8 @@ -0,0 +1,8 @@ +arg VERSION=1.0 +arg BASE_IMAGE=ubuntu:22.04 + +from alpine:3.19 as builder + +copy . . + +healthcheck --interval=30s --timeout=30s --start-period=5s --retries=3 cmd [ "executable" ] \ No newline at end of file diff --git a/test/fixtures/dockerfile/case_insensitive_tests/dockerFILE b/test/fixtures/dockerfile/case_insensitive_tests/dockerFILE new file mode 100644 index 00000000000..a9b4c423e2c --- /dev/null +++ b/test/fixtures/dockerfile/case_insensitive_tests/dockerFILE @@ -0,0 +1,10 @@ +arg BASE_IMAGE=ubuntu:22.04 + +# Comments between arg +arg JAR_FILE + +from alpine:3.19 as builder + +copy . . + +healthcheck --interval=30s --timeout=30s --start-period=5s --retries=3 cmd [ "executable" ] \ No newline at end of file diff --git a/test/fixtures/dockerfile/case_insensitive_tests/file.Dockerfile b/test/fixtures/dockerfile/case_insensitive_tests/file.Dockerfile new file mode 100644 index 00000000000..66464c06378 --- /dev/null +++ b/test/fixtures/dockerfile/case_insensitive_tests/file.Dockerfile @@ -0,0 +1,10 @@ +# Comments before arg +arg BASE_IMAGE=ubuntu:22.04 + +# Comments after arg + +from alpine:3.19 as builder + +copy . . + +healthcheck --interval=30s --timeout=30s --start-period=5s --retries=3 cmd [ "executable" ] diff --git a/test/fixtures/dockerfile/case_insensitive_tests/file_2.DOCKERfile b/test/fixtures/dockerfile/case_insensitive_tests/file_2.DOCKERfile new file mode 100644 index 00000000000..b09209f5e55 --- /dev/null +++ b/test/fixtures/dockerfile/case_insensitive_tests/file_2.DOCKERfile @@ -0,0 +1,8 @@ +arg BASE_IMAGE=ubuntu:22.04 +# Comments before from + +from alpine:3.19 AS builder + +copy .. . + +healthcheck --interval=30s --timeout=30s --start-period=5s --retries=3 cmd [ "executable" ] diff --git a/test/fixtures/dockerfile/case_insensitive_tests/random_name b/test/fixtures/dockerfile/case_insensitive_tests/random_name new file mode 100644 index 00000000000..424b06c294c --- /dev/null +++ b/test/fixtures/dockerfile/case_insensitive_tests/random_name @@ -0,0 +1,7 @@ +arg BASE_IMAGE=ubuntu:22.04 + +from alpine:3.19 as builder + +copy . . + +healthcheck --interval=30s --timeout=30s --start-period=5s --retries=3 cmd [ "executable" ] \ No newline at end of file diff --git a/test/fixtures/dockerfile/test_folder_names/docker/any_file.txt b/test/fixtures/dockerfile/test_folder_names/docker/any_file.txt new file mode 100644 index 00000000000..83acf398c06 --- /dev/null +++ b/test/fixtures/dockerfile/test_folder_names/docker/any_file.txt @@ -0,0 +1,5 @@ +FROM alpine:3.19 AS builder + +COPY . . + +HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 CMD [ "executable" ] \ No newline at end of file diff --git a/test/fixtures/dockerfile/test_folder_names/dockerfile/any_file.txt b/test/fixtures/dockerfile/test_folder_names/dockerfile/any_file.txt new file mode 100644 index 00000000000..83acf398c06 --- /dev/null +++ b/test/fixtures/dockerfile/test_folder_names/dockerfile/any_file.txt @@ -0,0 +1,5 @@ +FROM alpine:3.19 AS builder + +COPY . . + +HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 CMD [ "executable" ] \ No newline at end of file diff --git a/test/fixtures/dockerfile/test_folder_names/dockerfiles/any_file.txt b/test/fixtures/dockerfile/test_folder_names/dockerfiles/any_file.txt new file mode 100644 index 00000000000..83acf398c06 --- /dev/null +++ b/test/fixtures/dockerfile/test_folder_names/dockerfiles/any_file.txt @@ -0,0 +1,5 @@ +FROM alpine:3.19 AS builder + +COPY . . + +HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 CMD [ "executable" ] \ No newline at end of file diff --git a/test/fixtures/dockerfile/test_folder_names_case/Docker/any_file.txt b/test/fixtures/dockerfile/test_folder_names_case/Docker/any_file.txt new file mode 100644 index 00000000000..83acf398c06 --- /dev/null +++ b/test/fixtures/dockerfile/test_folder_names_case/Docker/any_file.txt @@ -0,0 +1,5 @@ +FROM alpine:3.19 AS builder + +COPY . . + +HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 CMD [ "executable" ] \ No newline at end of file diff --git a/test/fixtures/dockerfile/test_folder_names_case/Dockerfile/any_file.txt b/test/fixtures/dockerfile/test_folder_names_case/Dockerfile/any_file.txt new file mode 100644 index 00000000000..83acf398c06 --- /dev/null +++ b/test/fixtures/dockerfile/test_folder_names_case/Dockerfile/any_file.txt @@ -0,0 +1,5 @@ +FROM alpine:3.19 AS builder + +COPY . . + +HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 CMD [ "executable" ] \ No newline at end of file diff --git a/test/fixtures/dockerfile/test_folder_names_case/Dockerfiles/any_file.txt b/test/fixtures/dockerfile/test_folder_names_case/Dockerfiles/any_file.txt new file mode 100644 index 00000000000..83acf398c06 --- /dev/null +++ b/test/fixtures/dockerfile/test_folder_names_case/Dockerfiles/any_file.txt @@ -0,0 +1,5 @@ +FROM alpine:3.19 AS builder + +COPY . . + +HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 CMD [ "executable" ] \ No newline at end of file diff --git a/test/fixtures/negative_dockerfile/not_dockerfile.debian b/test/fixtures/negative_dockerfile/not_dockerfile.debian new file mode 100644 index 00000000000..d9e8b4e17a4 --- /dev/null +++ b/test/fixtures/negative_dockerfile/not_dockerfile.debian @@ -0,0 +1,7 @@ +package main + +import "fmt" + +func main() { + fmt.Println("Hello, World!") +} \ No newline at end of file diff --git a/test/fixtures/negative_dockerfile/not_dockerfile.txt b/test/fixtures/negative_dockerfile/not_dockerfile.txt new file mode 100644 index 00000000000..847945a42b0 --- /dev/null +++ b/test/fixtures/negative_dockerfile/not_dockerfile.txt @@ -0,0 +1,3 @@ +# should not flag since name is not "dockerfile" and extension is not .dockerfile, .ubi8 or .debian (.txt) + +FROM alpine:3.19 AS builder \ No newline at end of file diff --git a/test/fixtures/negative_dockerfile/not_dockerfile.ubi8 b/test/fixtures/negative_dockerfile/not_dockerfile.ubi8 new file mode 100644 index 00000000000..3d781ec4ba6 --- /dev/null +++ b/test/fixtures/negative_dockerfile/not_dockerfile.ubi8 @@ -0,0 +1,5 @@ +public class HelloWorld { + public static void main(String[] args) { + System.out.println("Hello, World!"); + } +} \ No newline at end of file