diff --git a/checks/docker/update_instruction_alone.rego b/checks/docker/update_instruction_alone.rego index 1a322e56..3aea6057 100644 --- a/checks/docker/update_instruction_alone.rego +++ b/checks/docker/update_instruction_alone.rego @@ -47,29 +47,31 @@ deny[res] { run_cmd := concat(" ", run.Value) cmds := regex.split(`\s*&&\s*`, run_cmd) - update_res = has_update(cmds) - not update_followed_by_install(cmds, update_res) + some package_manager + update_indexes := has_update(cmds, package_managers[package_manager]) + not update_followed_by_install(cmds, package_manager, update_indexes) msg := "The instruction 'RUN update' should always be followed by ' install' in the same RUN statement." res := result.new(msg, run) } -has_update(cmds) = { - "package_manager": package_manager, - "cmd_index": index, -} { - index := contains_cmd_with_package_manager(cmds, update_cmds, package_managers[package_manager]) +has_update(cmds, package_manager) = indexes { + indexes := contains_cmd_with_package_manager(cmds, update_cmds, package_manager) } -update_followed_by_install(cmds, update_res) { - install_index := contains_cmd_with_package_manager(cmds, install_cmds, update_res.package_manager) - update_res.cmd_index < install_index +update_followed_by_install(cmds, package_manager, update_indexes) { + install_index := contains_cmd_with_package_manager(cmds, install_cmds, package_manager) + update_indexes[_] < install_index[_] } -contains_cmd_with_package_manager(cmds, cmds_to_check, package_manager) = cmd_index { - cmd_parts := split(cmds[cmd_index], " ") - some i, j - cmd_parts[i] == package_manager[_] - cmd_parts[j] == cmds_to_check[_] - i < j +contains_cmd_with_package_manager(cmds, cmds_to_check, package_manager) = cmd_indexes { + cmd_indexes = [idx | + cmd_parts := split(cmds[idx], " ") + some i, j + i != j + cmd_parts[i] == package_manager[_] + cmd_parts[j] == cmds_to_check[_] + i < j + ] + count(cmd_indexes) != 0 } diff --git a/checks/docker/update_instruction_alone_test.rego b/checks/docker/update_instruction_alone_test.rego index 614f1a59..21d52355 100644 --- a/checks/docker/update_instruction_alone_test.rego +++ b/checks/docker/update_instruction_alone_test.rego @@ -68,6 +68,28 @@ test_chained_denied { r[_].msg == "The instruction 'RUN update' should always be followed by ' install' in the same RUN statement." } +test_multiple_package_managers { + r := deny with input as {"Stages": [{ + "Name": "ubuntu:18.04", + "Commands": [ + { + "Cmd": "from", + "Value": ["ubuntu:18.04"], + }, + { + "Cmd": "run", + "Value": ["apt-get update -y && apt-get upgrade -y && apt-get install -y curl && apk-update"], + }, + { + "Cmd": "entrypoint", + "Value": ["mysql"], + }, + ], + }]} + + count(r) == 0 +} + test_allowed { r := deny with input as {"Stages": [{"Name": "ubuntu:18.04", "Commands": [ { @@ -103,6 +125,25 @@ test_allowed { count(r) == 0 } +test_allowed_multiple_install_cmds { + r := deny with input as {"Stages": [{"Name": "ubuntu:18.04", "Commands": [ + { + "Cmd": "from", + "Value": ["ubuntu:18.04"], + }, + { + "Cmd": "run", + "Value": ["apt-get update -y && apt-get upgrade -y && apt-get install -y curl"], + }, + { + "Cmd": "entrypoint", + "Value": ["mysql"], + }, + ]}]} + + count(r) == 0 +} + test_allow_upgrade { r := deny with input as {"Stages": [{"Name": "ubuntu:18.04", "Commands": [ {