#!/bin/bash

# Copyright 2023 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# This script executes a run of the NVD CVE to OSV conversion code.
# It operates over the latest available NVD dump and only the subset of years
# specified.
# It assumes it is running in a Docker container

function __error_handing__() {
     local last_status_code=$1;
     local error_line_number=$2;
     echo 1>&2 "Error - exited with status $last_status_code at line $error_line_number";
}

trap  '__error_handing__ $? $LINENO' ERR

set -e
set -u

echo "Commencing conversion run"

# Download NVD CVE dumps.
echo "Downloading NVD CVE dumps"
mkdir -p "${WORK_DIR}/nvd"
gcloud --no-user-output-enabled storage -q cp "${NVD_GCS_PATH}/*-????.json" "${WORK_DIR}/nvd"

# Download latest CPE repo map.
echo "Downloading latest CPE Git repository map"
gcloud --no-user-output-enabled storage -q cp "${CPEREPO_GCS_PATH}" "${WORK_DIR}"

mkdir -p "${WORK_DIR}/nvd2osv/gcs_stage"

# Convert NVD CVE records to OSV.

for (( YEAR = $(date +%Y) ; YEAR >= ${FIRST_INSCOPE_YEAR} ; YEAR-- )); do
  # Run OSV record generation.
  echo "Converting NVD CVE records from ${YEAR} to OSV"
  /usr/local/bin/nvd-cve-osv \
    --cpe_repos "${WORK_DIR}/cpe_product_to_repo.json" \
    --nvd_json "${WORK_DIR}/nvd/nvdcve-2.0-${YEAR}.json" \
    --out_dir "${WORK_DIR}/nvd2osv/${YEAR}" \
    --out_format OSV

  # Copy results to staging area.
  echo "Copying NVD CVE records from ${YEAR} successfully converted to OSV to aggregated staging"
  find "${WORK_DIR}/nvd2osv/${YEAR}" -type f -name \*.json \
    -exec cp '{}' "${WORK_DIR}/nvd2osv/gcs_stage/" \;

  # Copy conversion summary staging area.
  DURABLE_OUTCOMES_CSV="nvd-conversion-outcomes-${YEAR}-$(date -Iminutes).csv"
  cp "${WORK_DIR}/nvd2osv/${YEAR}/outcomes.csv" "${WORK_DIR}/nvd2osv/gcs_stage/${DURABLE_OUTCOMES_CSV}"

  echo "Results summary will be available in ${OSV_OUTPUT_GCS_PATH}/${DURABLE_OUTCOMES_CSV}"
done

# Copy (and remove any missing) results to GCS bucket, with some sanity
# checking.
objs_present=$(gsutil ls "${OSV_OUTPUT_GCS_PATH}" | wc -l)
objs_deleted=$(gsutil -m rsync -c -n -d "${WORK_DIR}/nvd2osv/gcs_stage" "${OSV_OUTPUT_GCS_PATH}" 2>&1 | grep "Would remove" | wc -l)

threshold=$(echo "scale=2; ${objs_present} * (${SAFETY_THRESHOLD_PCT:-2} / 100)" | bc)

# Bash can't deal with floats
if (( $(echo "${objs_deleted} > ${threshold}" | bc -l) )); then
  echo "Warning. Unexpectedly high (${objs_deleted}) number of CVE records would be deleted!" >> /dev/stderr
  gsutil -m rsync -c -n -d "${WORK_DIR}/nvd2osv/gcs_stage" "${OSV_OUTPUT_GCS_PATH}" 2>&1 | grep "Would remove" >> /dev/stderr
  # TODO: add back in once nvd-mirror issue fixed: exit 1
fi

echo "Copying NVD CVE records successfully converted to GCS bucket"
gsutil -q -m rsync -c "${WORK_DIR}/nvd2osv/gcs_stage" "${OSV_OUTPUT_GCS_PATH}"

echo "Conversion run complete"
