#!/usr/bin/env bash
# Run after loading all five archives. Containers have no external networking.
set -euo pipefail
root="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)"
engine="${CONTAINER_ENGINE:-podman}"
work="$(mktemp -d /tmp/devsecops-per-tool-test.XXXXXXXX)"
trap 'echo "Test evidence: $work"' EXIT
mkdir -p "$work"/{source,clean,reports,missing-db,zap,history}
printf 'requests==2.19.1\n' > "$work/source/requirements.txt"
python3 - "$work" <<'PY'
from pathlib import Path
import hashlib,io,json,random,string,sys,tarfile
p=Path(sys.argv[1]); r=random.Random(1729)
token='ghp_'+''.join(r.choices(string.ascii_letters+string.digits,k=36))
(p/'history/secret.txt').write_text('github_token = "'+token+'"\n')
# Small Docker archive containing installed Python package metadata.
layer=io.BytesIO()
with tarfile.open(fileobj=layer,mode='w') as t:
    data=b'Metadata-Version: 2.1\nName: requests\nVersion: 2.19.1\n'
    m=tarfile.TarInfo('usr/local/lib/python3.11/site-packages/requests-2.19.1.dist-info/METADATA'); m.size=len(data)
    t.addfile(m,io.BytesIO(data))
blob=layer.getvalue(); digest=hashlib.sha256(blob).hexdigest()
cfg=json.dumps({'architecture':'amd64','os':'linux','config':{},'rootfs':{'type':'layers','diff_ids':['sha256:'+digest]}}).encode()
name=hashlib.sha256(cfg).hexdigest()+'.json'
with tarfile.open(p/'app.tar','w') as t:
    for path,data in [('layer.tar',blob),(name,cfg),('manifest.json',json.dumps([{'Config':name,'RepoTags':['fixture:local'],'Layers':['layer.tar']}]).encode())]:
        m=tarfile.TarInfo(path); m.size=len(data); t.addfile(m,io.BytesIO(data))
PY
git -C "$work/history" init -q
git -C "$work/history" -c user.name=Test -c user.email=test@example.invalid add secret.txt
git -C "$work/history" -c user.name=Test -c user.email=test@example.invalid commit -qm 'Synthetic history fixture'
git -C "$work/history" rm -q secret.txt
git -C "$work/history" -c user.name=Test -c user.email=test@example.invalid commit -qm 'Remove fixture at tip'
run() {
  local image="$1"; shift
  "$engine" run --rm --pull=never --network=none --user 0 \
    -v "$work:/test:Z" "localhost/devsecops/$image" "$@"
}
expect() {
  local expected="$1"; shift
  local status=0
  "$@" || status=$?
  [[ "$status" == "$expected" ]] || { echo "Expected $expected; got $status" >&2; exit 1; }
}
for spec in gitleaks:8.30.1 syft:1.51.1 grype:0.118.0 trivy:0.74.0; do
  tool="${spec%:*}"
  run "$spec" bash -c 'set -e; for t in gitleaks syft grype trivy; do if [ "$t" = "$DEVSECOPS_TOOL" ]; then command -v "$t"; elif command -v "$t"; then exit 1; fi; done; if command -v cosign || command -v zap.sh; then exit 1; fi; test ! -e /zap/zap.sh'
  if [[ "$tool" == trivy ]]; then run "$spec" trivy --version; else run "$spec" "$tool" version; fi
done
expect 1 run gitleaks:8.30.1 tool-security source /test/history /test/reports/secrets
run gitleaks:8.30.1 tool-security source /test/clean /test/reports/secrets-clean
git clone -q --depth 1 "file://$work/history" "$work/shallow"
expect 2 run gitleaks:8.30.1 tool-security source /test/shallow /test/reports/shallow
expect 1 run trivy:0.74.0 tool-security source /test/source /test/reports/trivy-source
run trivy:0.74.0 tool-security source /test/clean /test/reports/trivy-clean
expect 1 run trivy:0.74.0 tool-security image /test/app.tar /test/reports/trivy-image
run syft:1.51.1 tool-security source /test/source /test/reports/source-sbom
expect 2 run grype:0.118.0 tool-security sbom /test/reports/source-sbom/sbom.syft.json /test/reports/grype-source
run syft:1.51.1 tool-security image /test/app.tar /test/reports/image-sbom
expect 2 run grype:0.118.0 tool-security sbom /test/reports/image-sbom/sbom.syft.json /test/reports/grype-image
run syft:1.51.1 tool-security source /test/clean /test/reports/clean-sbom
run grype:0.118.0 tool-security sbom /test/reports/clean-sbom/sbom.syft.json /test/reports/grype-clean
expect 1 run grype:0.118.0 env GRYPE_DB_CACHE_DIR=/test/missing-db tool-security sbom /test/reports/source-sbom/sbom.syft.json /test/reports/grype-missing
run gitleaks:8.30.1 evidence-tools package /test/app.tar /test/reports/image-sbom/sbom.cdx.json /test/release
run gitleaks:8.30.1 evidence-tools verify /test/release
printf 'tampered\n' >> "$work/release/app.tar"
expect 1 run gitleaks:8.30.1 evidence-tools verify /test/release
run gitleaks:8.30.1 evidence-tools archive /test/reports /test/evidence.tar.gz
python3 - "$work" <<'PY'
from pathlib import Path
import json,sys
p=Path(sys.argv[1])/'reports'
assert json.loads((p/'secrets/gitleaks-history.json').read_text())
for scope in ['source','image']:
    assert any(c['name']=='requests' for c in json.loads((p/f'{scope}-sbom/sbom.cdx.json').read_text())['components'])
    assert any(m['vulnerability']['severity'] in ['High','Critical'] for m in json.loads((p/f'grype-{scope}/grype.json').read_text())['matches'])
    report=json.loads((p/f'trivy-{scope}/trivy-{scope}.json').read_text())
    assert any(v['Severity'] in ['HIGH','CRITICAL'] for r in report.get('Results',[]) for v in r.get('Vulnerabilities',[]))
PY
cp "$root/containers/test-zap-standalone.sh" "$work/test-zap.sh"
"$engine" run --rm --pull=never --network=none --user 0 \
  -v "$work:/test:Z" -v "$work/zap:/zap/wrk:Z" localhost/devsecops/zap:20260909 bash /test/test-zap.sh
echo 'PASS: five separate tools, scanner isolation, history/shallow gates, source/image SBOM handoff, vulnerability gates, clean fixtures, missing DB, release integrity, ZAP loopback'
