#!/bin/bash
#
# Perform vulnerability scan of a container image built by OBS using NeuVector.

# Strict mode
set -euo pipefail

TOPDIR="/usr/src/packages"
OUTPUTDIR="$TOPDIR/DOCKER"

# Helper functions
log() {
    echo "$@" >&2
}
check_required_environment_variables() {
    local required_environment_variable
    for required_environment_variable in "$@"; do
        if [[ -z ${!required_environment_variable:-} ]]; then
            log "Missing environment variable '$required_environment_variable'"
            return 1
        fi
    done
}
containerinfos() {
    find "$OUTPUTDIR" -type f -name '*.containerinfo'
}

check_required_environment_variables BUILD_DIR BUILD_ROOT

# Obtain versions
NV_VERSION="$(rpm -qa | grep -E '^neuvector-scanner-[a-f0-9]+-' |
    sed -E 's/.*-([a-f0-9]+)-.*/\1/g')"
NV_DB_VERSION="$(scanner -d /etc/neuvector/db/ -v | grep -Eo '[0-9.]+')"
log "Using NeuVector version $NV_VERSION (db version: $NV_DB_VERSION)"

log "Retrieving container image metadata"
CONTAINERINFO="$(find "$OUTPUTDIR" -name '*.containerinfo' -print -quit)"
CONTAINER_NAME="$(basename "$CONTAINERINFO" | sed 's/\.containerinfo$//')"
CONTAINER_TAG="$(python3 -c \
    'import json, sys; print(json.load(sys.stdin)["tags"][0])' \
    <"$CONTAINERINFO")"
log "Container image tag to check: $CONTAINER_TAG"

log "Starting Docker"
"$BUILD_DIR/startdockerd" \
    --root "$BUILD_ROOT" \
    --webserver "$TOPDIR/SOURCES/repos" \
    --webserver-upload "$TOPDIR/SOURCES/repos/UPLOAD"

log "Scanning image with NeuVector"
export SCANNER_ON_DEMAND=true
export SCANNER_REPOSITORY="${CONTAINER_TAG%%:*}"
export SCANNER_TAG="${CONTAINER_TAG#*:}"
monitor

log "Stopping Docker"
"$BUILD_DIR/startdockerd" \
    --root "$BUILD_ROOT" \
    --kill

# Convert file to the Cosign Vulnerability Scan Record Attestation Spec format
# https://github.com/sigstore/cosign/blob/main/specs/COSIGN_VULN_ATTESTATION_SPEC.md
# NOTE: The subject will be filled by OBS during publishing
# This command merges the files, avoid --argjson due to error using large files
NV_SCAN_RESULT="/var/neuvector/scan_result.json"
OUTPUT_FILE="$OUTPUTDIR/$CONTAINER_NAME.neuvector_vuln.intoto.json"
SCAN_TIMESTAMP="$(date '+%Y-%m-%dT%H:%M:%S.%N%:z')"
jq -s '.[1].predicate.scanner.result = .[0] | .[1]' "$NV_SCAN_RESULT" - \
    >"$OUTPUT_FILE" <<EOF
{
  "_type": "https://in-toto.io/Statement/v0.1",
  "predicateType": "https://cosign.sigstore.dev/attestation/vuln/v1",
  "subject": [
    {
      "name": "",
      "digest": {
        "sha256": ""
      }
    }
  ],
  "predicate": {
    "invocation": {
      "parameters": null,
      "uri": "",
      "event_id": "",
      "builder.id": ""
    },
    "scanner": {
      "uri": "pkg:github.com/neuvector/scanner@$NV_VERSION",
      "version": "$NV_VERSION",
      "db": {
        "uri": "pkg:github.com/neuvector/vul-dbgen@$NV_DB_VERSION",
        "version": "$NV_DB_VERSION"
      },
      "result": {}
    },
    "metadata": {
      "scanStartedOn": "$SCAN_TIMESTAMP",
      "scanFinishedOn": "$SCAN_TIMESTAMP"
    }
  }
}
EOF

log "Cleaning up"
rm "$NV_SCAN_RESULT"
