#!/usr/bin/bash

bdu=""
while getopts ":b" opt; do
    case $opt in
                b)
                        bdu="--using-bdu"
                        ;;
    esac
done

json=$(trivy ${bdu} k8s --scanners vuln,misconfig --report summary --format json --disable-node-collector | jq -r '.Findings.[]')

if [ -z "${json}" ]; then
    echo "Ошибка при попытке сканирования кластера kubernetes"
    exit 1
fi

readarray -t vulnerabilities_all < <(jq -c '.Results.[] | select(.Vulnerabilities != null)' <<< ${json})

misconfig_raw=$(jq -r '. | select(.Kind | IN("Role", "RoleBinding", "ClusterRole", "ClusterRoleBinding") | not)' <<< ${json})
readarray -t misconfigurations_all < <(jq -c '.Results.[] | select(.Misconfigurations != null)' <<< ${misconfig_raw})

uid=$(id -u)

show_message() {
    local message="$1"

    if [ -n "${message}" ]; then
        echo $message
    fi
}

log_message(){
    local message="$1"
    
    if [ -n "${message}" ]; then
        message="Время=$(date +"%Y-%m-%dT%H:%M:%S.%N%:z") ${message}"

        logger -t trivy <<< "${message}"
    fi
}

get_level () {
    local critical=$1
    local high=$2
    local total=$3

    local level="Низкий"

    if [ $critical -gt 0 ]; then
        level="Критический"
    elif [ $high -gt 0 ]; then
        level="Высокий"
    elif [ $total -gt 0 ]; then
        level="Средний"
    fi

    echo "${level}"
}

perform_vuln () {
    local image=
    local vulnerabilities=
    
    local vuln_critical=0
    local vuln_high=0
    local vuln_other=0
    local vuln_count=0

    local level="Низкий"
    local vuln_m="уязвимостей не обнаружено"

    local uuid=$(uuidgen)

    local message_user=
    local message=

    image=$(jq -r ".Target" <<< ${item} | cut -d' ' -f1)

    vulnerabilities=$(jq -r '.Vulnerabilities' <<< ${item})

    vuln_other=0
    
    vuln_critical=$(jq -r '. | map(select(.Severity | test("critical"; "i"))) | length' <<< ${vulnerabilities})
    vuln_high=$(jq -r '. | map(select(.Severity | test("high"; "i"))) | length' <<< ${vulnerabilities})

    vuln_count=$(jq -r '. | length' <<< ${vulnerabilities})

    vuln_other=$(($vuln_count - $vuln_critical - $vuln_high))

    level=$(get_level ${vuln_critical} ${vuln_high} ${vuln_count})

    if [ $vuln_count -gt 0 ]; then
        vuln_m="обнаружено уязвимостей ${vuln_count} (критичных - ${vuln_critical}, высокого уровня - ${vuln_high}, прочих - ${vuln_other})"
    fi

    message_user="В docker-образе ${image} ${vuln_m}"

    message="Тип=\"Сканирование кластера kubernetes\" id=${uuid}, Пользователь=${uid}, Уровень=${level}, Сообщение=\"${message_user}\""
    
    show_message "${message_user}"
    log_message "${message}"
}

perform_mis () {
    local resource=
    local misconfigurations=
    
    local conf_critical=0
    local conf_high=0
    local conf_other=0
    local conf_count=0

    local level="Низкий"
    local conf_m="ошибок конфигурации не обнаружено"

    local uuid=$(uuidgen)

    local message_user=
    local message=

    resource=$(jq -r '.Target' <<< ${item})

    misconfigurations=$(jq -r '.Misconfigurations' <<< ${item})

    conf_critical=$(jq -r '. | map(select(.Severity | test("critical"; "i"))) | length' <<< ${misconfigurations})
    conf_high=$(jq -r '. | map(select(.Severity | test("high"; "i"))) | length' <<< ${misconfigurations})

    conf_count=$(jq -r '. | length' <<< ${misconfigurations})

    conf_other=$(($conf_count - $conf_critical - $conf_high))

    level=$(get_level ${conf_critical} ${conf_high} ${conf_count})

    if [ $conf_count -gt 0 ]; then
        conf_m="обнаружено ошибок конфигурации ${conf_count} (критичных - ${conf_critical}, высокого уровня - ${conf_high}, прочих - ${conf_other})"
    fi

    message_user="В ресурсе ${resource} ${conf_m}"

    message="Тип=\"Сканирование кластера kubernetes\" id=${uuid}, Пользователь=${uid}, Уровень=${level}, Сообщение=\"${message_user}\""

    show_message "${message_user}"
    log_message "${message}"
}

for item in "${vulnerabilities_all[@]}"; do
    perform_vuln ${item}    
done

for item in "${misconfigurations_all[@]}"; do
    perform_mis ${item}
done