#!/usr/bin/env bash
set -euo pipefail
export PATH="/opt/devsecops/bin:/zap:$PATH"
root=/opt/devsecops
mode="${1:?Use versions, smoke, source, image, zap, host, package, verify, archive, or upload}"
shift
# Avoid automatic scanner configuration discovery in the project working directory.
cd /tmp
case "$mode" in
  versions)
    gitleaks version; trivy --version; syft version; grype version; zap.sh -version
    ;;
  smoke)
    bash "$root/scripts/test-offline.sh"
    ;;
  source)
    status=0
    bash "$root/scripts/scan-source.sh" "${1:?source directory}" "${2:?report directory}" || status=1
    bash "$root/scripts/scan-supply-chain.sh" dir "$1" "$2/supply-chain" || status=1
    exit "$status"
    ;;
  image)
    status=0
    bash "$root/scripts/scan-image.sh" "${1:?image archive}" "${2:?report directory}" || status=1
    bash "$root/scripts/scan-supply-chain.sh" docker-archive "$1" "$2/supply-chain" || status=1
    exit "$status"
    ;;
  zap)
    target="${1:?staging URL}"; reports="${2:?report directory}"
    [[ "$reports" == /zap/wrk ]] || { echo 'Mount the report volume at /zap/wrk' >&2; exit 2; }
    [[ "$target" == http://* || "$target" == https://* ]] || exit 2
    mkdir -p "$reports"
    # Baseline returns nonzero on alerts or execution errors. Preserve that status.
    exec zap-baseline.py -t "$target" -r zap.html -J zap.json \
      -z '-dir /tmp/zap-ci -config autoupdate.checkOnStart=false -config autoupdate.checkAddonUpdates=false'
    ;;
  host)
    host="${1:?SSH user@RHEL-test-host}"; reports="${2:?report directory}"
    [[ "$host" =~ ^[a-zA-Z0-9][a-zA-Z0-9_.@-]*$ ]] || exit 2
    : "${OPENSCAP_SSH_KEY:?Set the test-host SSH key as a Drone secret}"
    : "${OPENSCAP_KNOWN_HOSTS:?Set independently verified SSH host keys}"
    mkdir -p "$reports"
    umask 077
    sshdir="$(mktemp -d /tmp/devsecops-ssh.XXXXXXXX)"
    trap 'rm -f -- "$sshdir/key" "$sshdir/known_hosts"; rmdir -- "$sshdir"' EXIT
    printf '%s\n' "$OPENSCAP_SSH_KEY" > "$sshdir/key"
    printf '%s\n' "$OPENSCAP_KNOWN_HOSTS" > "$sshdir/known_hosts"
    # The fixed, administrator-installed host command evaluates the real RHEL host.
    exec_status=0
    ssh -T -i "$sshdir/key" -o BatchMode=yes -o IdentitiesOnly=yes \
      -o ConnectTimeout=15 -o ServerAliveInterval=30 -o ServerAliveCountMax=3 \
      -o StrictHostKeyChecking=yes -o "UserKnownHostsFile=$sshdir/known_hosts" \
      "$host" 'sudo -n /usr/local/sbin/devsecops-openscap-host' \
      > "$reports/host-compliance.tar.gz" || exec_status=$?
    exit "$exec_status"
    ;;
  package)
    artifact="${1:?image archive}"; sbom="${2:?SBOM}"; output="${3:?new release directory}"
    test -s "$artifact"; test -s "$sbom"
    mkdir "$output"
    cp "$artifact" "$output/app.tar"
    cp "$sbom" "$output/image.cdx.json"
    cd "$output"
    sha256sum app.tar image.cdx.json > release.sha256
    ;;
  verify)
    cd "${1:?release directory}"
    # Integrity only: this does not authenticate the producer or manifest.
    test -s app.tar; test -s image.cdx.json
    sha256sum app.tar image.cdx.json > /tmp/release-check.$$
    trap 'rm -f /tmp/release-check.$$' EXIT
    cmp release.sha256 /tmp/release-check.$$
    ;;
  archive)
    reports="${1:?report directory}"; output="${2:?output .tar.gz}"
    # The output must be outside the input directory.
    case "$(realpath -m "$output")" in "$(realpath "$reports")"/*) exit 2;; esac
    tar -C "$reports" -czf "$output" .
    ;;
  upload)
    # Generic HTTPS PUT endpoint (for example an internal generic artifact repository).
    # Do not send credentials to redirects or unverified TLS endpoints.
    : "${EVIDENCE_URL:?Set the full HTTPS destination URL}"
    : "${EVIDENCE_TOKEN:?Set an upload-only bearer token}"
    [[ "$EVIDENCE_URL" == https://* ]] || { echo 'HTTPS required' >&2; exit 2; }
    bash "$root/scripts/upload-evidence.sh" "${1:?archive file}"
    ;;
  *) echo "Unknown mode: $mode" >&2; exit 2;;
esac
