Skip to content

Commit

Permalink
feat: Add scan functions (#229)
Browse files Browse the repository at this point in the history
  • Loading branch information
JonZeolla authored Jan 4, 2023
1 parent 1e75de0 commit 238ba4f
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 29 deletions.
16 changes: 4 additions & 12 deletions build/Dockerfile.j2
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,14 @@ ARG {{ argument }}
{% endfor %}

{# Skip this if there is no relevant env, such as for the -terraform base tag #}
{% if dockerfile_envs %}
{% for dockerfile in dockerfile_envs %}
{% for dockerfile in dockerfile_envs if dockerfile_envs %}
{{ dockerfile }}
{% endfor %}
{% endif %}

{# Skip this if there is no tool-env combination specific dockerfile/frag #}
{% if dockerfile_tool_envs %}
{% for dockerfile in dockerfile_tool_envs %}
{% for dockerfile in dockerfile_tool_envs if dockerfile_tool_envs %}
{{ dockerfile }}
{% endfor %}
{% endif %}

FROM base as final

Expand All @@ -42,15 +38,11 @@ USER easy_infra
{% endfor %}

{# Skip this if there is no relevant env, such as for the -terraform base tag #}
{% if dockerfrag_envs %}
{% for dockerfrag in dockerfrag_envs %}
{% for dockerfrag in dockerfrag_envs if dockerfrag_envs %}
{{ dockerfrag }}
{% endfor %}
{% endif %}

{# Skip this if there is no tool-env combination specific dockerfile/frag #}
{% if dockerfrag_tool_envs %}
{% for dockerfrag in dockerfrag_tool_envs %}
{% for dockerfrag in dockerfrag_tool_envs if dockerfrag_tool_envs %}
{{ dockerfrag }}
{% endfor %}
{% endif %}
73 changes: 58 additions & 15 deletions build/functions.j2
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,25 @@
source /usr/local/bin/common.sh


function run_command() {
if [[ "$#" -lt 1 ]]; then
echo "Improper use of the easy_infra run_command function; $# arguments provided when at least 1 was expected"
return 230
fi

function_name="${1}"
shift
function_arguments=("${@}")

if [[ "${function_name}" =~ ^scan_.* ]]; then
# Special case to handle our "scan_" functions
return
fi

command "${function_name}" "${function_arguments[@]}"
}


function process_command_exit_status() {
# Store the provided exit status to return it at the end
exit_status="${1}"
Expand All @@ -29,8 +48,15 @@ function process_command_exit_status() {
}

{# Macro to be used by the loops below #}
{% macro function(function, file_extensions, security_tools, allow_filter, version_argument, validations) %}
function {{ function }}() {
{%- macro function(function, package=function, scan=false) %}

{%- set file_extensions = packages[package]["file_extensions"] -%}
{%- set security_tools = packages[package]["security"] -%}
{%- set allow_filter = packages[package]["allow_filter"] -%}
{%- set version_argument = packages[package]["version_argument"] -%}
{%- set validations = packages[package]["validation"] -%}

function {{ "scan_" ~ function if scan else function }}() {
arguments=("${@}")
easy_infra_{{ function | replace("-", "_") }}_security_tools=({% for security_tool in security_tools %}{{ security_tool | replace("-", "_") }}{% if not loop.last %} {% endif %}{% endfor %})

Expand All @@ -49,6 +75,24 @@ function {{ function }}() {
done
done

{% if scan %}
if [[ "${1}" == "version" ]]; then
_feedback INFO "Detected version check, skipping security checks for scan_{{ function }}"
echo "{{ function }} is using the following security tools:"
for security_tool in "${easy_infra_{{ function | replace("-", "_") }}_security_tools[@]}"; do
security_tool_version_variable="${security_tool^^}_VERSION"
echo "${security_tool} version ${!security_tool_version_variable}"
done
return
{%- else %}
if [[ "${1}" == "{{ version_argument }}" ]]; then
_feedback INFO "Detected version check, skipping security checks for {{ function }}"
# Allow piping of the version command into other commands
run_command "${FUNCNAME[0]}" "${arguments[@]}"
return $?
{%- endif %}
fi

{% if allow_filter is defined %}
# Apply the allow filters after easy_infra specific arguments have been removed
for i in "${!arguments[@]}"; do
Expand All @@ -60,7 +104,7 @@ function {{ function }}() {

if [[ "${hit:-false}" == "false" ]]; then
# Run the command and return
command "${FUNCNAME[0]}" "${arguments[@]}"
run_command "${FUNCNAME[0]}" "${arguments[@]}"
return $?
fi
done
Expand Down Expand Up @@ -98,13 +142,6 @@ function {{ function }}() {
dirs+=($(pwd -P))
fi

if [[ "${1}" == "{{ version_argument }}" ]]; then
_feedback INFO "Detected version check, skipping security checks for {{ function }}"
# Allow piping of the version command into other commands
command "${FUNCNAME[0]}" "${arguments[@]}"
return $?
fi

declare -A dir_exit_codes

for dir in "${dirs[@]}"; do
Expand Down Expand Up @@ -139,7 +176,7 @@ function {{ function }}() {
_feedback WARNING "Skipping all security checks for {{ function }} due to the --disable-security argument"
_log "easy_infra.stdouterr" info unknown "{{ function }}" "${dir}" string "All security checks for {{ function }} were skipped due to the --disable-security argument"
unset 'security_skipped'
command "${FUNCNAME[0]}" "${arguments[@]}"
run_command "${FUNCNAME[0]}" "${arguments[@]}"
return=$?
popd > /dev/null
if [[ "${return:-1}" != 0 ]]; then
Expand All @@ -155,7 +192,7 @@ function {{ function }}() {
elif [[ "${DISABLE_SECURITY,,}" == "true" ]]; then
_feedback WARNING "Skipping all security checks for {{ function }} due to the DISABLE_SECURITY environment variable value"
_log "easy_infra.stdouterr" info unknown "{{ function }}" "${dir}" string "All security checks for {{ function }} were skipped due to the DISABLE_SECURITY environment variable value"
command "${FUNCNAME[0]}" "${arguments[@]}"
run_command "${FUNCNAME[0]}" "${arguments[@]}"
return=$?
popd > /dev/null
if [[ "${return:-1}" != 0 ]]; then
Expand Down Expand Up @@ -287,7 +324,7 @@ function {{ function }}() {
{%- endfor %}

# Run the command per a PATH lookup, after any easy_infra specific arguments are removed
command "${FUNCNAME[0]}" "${arguments[@]}"
run_command "${FUNCNAME[0]}" "${arguments[@]}"
return=$?
if [[ "${return:-1}" != 0 ]]; then
popd > /dev/null
Expand Down Expand Up @@ -329,8 +366,14 @@ function {{ function }}() {
{# Loop through each of the provided packages (or aliases, if they are set) to be wrapped and generate a function for each -#}
{% for package in packages if packages[package]["security"] -%}
{% for alias in packages[package]["aliases"] -%}
{{ function(alias, packages[package]["file_extensions"], packages[package]["security"], packages[package]["allow_filter"], packages[package]["version_argument"], packages[package]["validation"]) }}
{# Create the alias function -#}
{{ function(alias, package) }}
{# And then a scan alias function -#}
{{ function(alias, package, scan=true) }}
{% else %}
{{ function(package, packages[package]["file_extensions"], packages[package]["security"], packages[package]["allow_filter"], packages[package]["version_argument"], packages[package]["validation"]) }}
{# Create the package function -#}
{{ function(package) }}
{# And then a scan package function -#}
{{ function(package, scan=true) }}
{% endfor %}
{%- endfor -%}
5 changes: 4 additions & 1 deletion easy_infra/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,10 @@ def opinionated_docker_run(
"Received an unexpected exit when invoking CLIENT.containers.run() with the following arguments: "
+ f"{auto_remove=}, {command=}, {detach=}, {environment=}, {image=}, {network_mode=}, {tty=}, {volumes=}, {working_dir=}"
)
sys.exit(response["StatusCode"])

# This ensures that if it unexpectedly exits 0, it still fails the pipeline
exit_code = response["StatusCode"]
sys.exit(max(exit_code, 1))


def is_status_expected(*, expected: int, response: dict) -> bool:
Expand Down
10 changes: 9 additions & 1 deletion tests/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,8 @@ def run_terraform(*, image: str) -> None:
tests: list[tuple[dict, str, int]] = [ # type: ignore
({}, "terraform init", 0),
({}, "tfenv exec init", 0),
({}, "scan_terraform", 0),
({}, "scan_tfenv", 0),
(
{},
'/bin/bash -c "terraform init && terraform validate && echo no | terraform apply"',
Expand Down Expand Up @@ -613,7 +615,7 @@ def run_terraform(*, image: str) -> None:
"DISABLE_SECURITY": "true",
"TERRAFORM_VERSION": "1.1.8",
},
'/bin/bash -c "terraform init -backend=false && terraform validate"',
'/bin/bash -c "scan_terraform && terraform init -backend=false && terraform validate"',
1,
), # This tests the bring-your-own TERRAFORM_VERSION hook (40-), regardless of the built-in security tools (DISABLE_SECURITY=true)
# It fails because it ignores the 50- terraform due to AUTODETECT=false, and the v_0_14_dir files fail given the version of
Expand Down Expand Up @@ -690,6 +692,7 @@ def run_terraform(*, image: str) -> None:
tests: list[tuple[dict, str, int]] = [ # type: ignore
({"DISABLE_SECURITY": "true"}, "terraform init", 0),
({"DISABLE_SECURITY": "true"}, "tfenv exec init", 0),
({"DISABLE_SECURITY": "true"}, "scan_terraform", 0),
({}, '/usr/bin/env bash -c "DISABLE_SECURITY=true terraform init"', 0),
(
{},
Expand Down Expand Up @@ -734,6 +737,7 @@ def run_terraform(*, image: str) -> None:
tests: list[tuple[dict, str, int]] = [ # type: ignore
({}, "terraform plan", 1),
({}, "tfenv exec plan", 1),
({}, "scan_terraform", 1),
(
{},
'/usr/bin/env bash -c "terraform plan"',
Expand Down Expand Up @@ -941,6 +945,10 @@ def run_ansible(*, image: str) -> None:
# expected exit code
tests: list[tuple[dict, str, int]] = [
({}, "ansible-playbook insecure.yml --check", 50),
({}, "scan_ansible", 50),
({}, "scan_ansible-playbook", 50),
({"DISABLE_SECURITY": "true"}, "scan_ansible-playbook", 0),
({}, "scan_ansible --skip-kics", 0),
(
{},
"ansible-playbook --skip-kics insecure.yml --check",
Expand Down

0 comments on commit 238ba4f

Please sign in to comment.