Files
codebase-memory-mcp/scripts/ci/append-vt-notes.sh
T
Martin Vogel 48fc942418 ci(release): double-verify ML antivirus false positives instead of re-rolling builds
Release run 30464288732 was blocked by the VirusTotal gate: three linux-amd64
binaries flagged 1/62 by Microsoft's Wacatac.B!ml -- fully stripped binaries
(0 symbols, verified on the exact artifacts), the state that scanned clean in
the two previous cycles. Meanwhile a real Defender endpoint (engine
1.1.26060.3008, signatures 1.455.410.0 updated the same day, RTP on) scans
the identical bytes clean. Four cycles of evidence now say the same thing:
this verdict is an unstable ML decision boundary, not a property of the code,
and no build-side lever moves it durably -- stripping, downloader removal and
metadata changes each "worked" only until a later build flipped it back.

So stop treating the flag as buildable-away and verify it honestly instead:

  check-virustotal.sh may downgrade BLOCKED to TOLERATED only when ALL hold:
    - pre-release version (-rc./-pre/-alpha/-beta); stable releases never
    - every failing file flagged by exactly ONE engine
    - that engine is Microsoft and the verdict ends in "!ml" (never a
      signature name)
    - hash-pinned Defender ENDPOINT evidence is attached to the draft release
      (defender-endpoint-verification.txt) proving Microsoft's shipping
      product, signature-updated at scan time, reports the exact bytes clean

  av-endpoint-verify.sh (new) produces that evidence: downloads the draft
  assets, scans them on the local Windows VM endpoint, refuses to attest if
  RTP is off or Defender itself detects, uploads the hash-pinned result.
  The gate prints the exact command when evidence is missing; re-running the
  failed verify job does not rebuild, so the bytes stay fixed.

  append-vt-notes.sh (new, extracted from inline YAML per venue-parity) then
  renders the release-notes table honestly: a tolerated file reads "1/62 ML
  false positive, endpoint-verified clean", never "0 detections".

tests/test_vt_gate_tolerance_contract.sh pins all nine decision directions
against a stubbed VT API and release store -- clean pass, stable-never,
missing/stale/DETECTED evidence, signature-named verdict, non-Microsoft
engine, multi-engine -- so the tolerance provably fails closed.

Also: release.yml gains skip_tests for re-releases of an already test-green
tree (build/smoke/soak/verify always run; lint failures still gate via
!cancelled() && !failure()).

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-07-29 20:45:13 +02:00

51 lines
2.4 KiB
Bash

#!/usr/bin/env bash
# Append the Security Verification section to the release notes: per-binary
# sha256 + VirusTotal links, and — when the pre-release ML false-positive
# tolerance fired (scripts/ci/check-virustotal.sh wrote /tmp/vt_tolerated.tsv)
# — an honest annotation instead of a blanket "0 detections" claim.
# Expects: GH_TOKEN, VERSION; run from the verify job workspace (binaries/).
set -euo pipefail
TOL=/tmp/vt_tolerated.tsv
TABLE="\n\n## Security Verification\n\n"
if [ -s "$TOL" ]; then
N=$(wc -l < "$TOL" | tr -d ' ')
TABLE+="All release binaries were scanned with 70+ antivirus engines. "
TABLE+="**${N} of them currently show a single machine-learning heuristic detection** "
TABLE+="(Microsoft \`Wacatac!ml\`) that we have verified to be a false positive: "
TABLE+="an up-to-date Microsoft Defender endpoint — signatures updated at scan time, "
TABLE+="real-time protection on — scans the identical bytes clean. The hash-pinned "
TABLE+="evidence is attached to this release as \`defender-endpoint-verification.txt\`, "
TABLE+="and a false-positive report for these exact hashes has been submitted to "
TABLE+="Microsoft. See **Antivirus false positives on release binaries** in the notes "
TABLE+="above for the full story and what we are doing about it.\n\n"
else
TABLE+="All release binaries scanned with 70+ antivirus engines — **0 detections**.\n\n"
fi
TABLE+="| Binary | SHA-256 | VirusTotal |\n"
TABLE+="|--------|---------|------------|\n"
for bin in binaries/codebase-memory-mcp-*; do
[ -f "$bin" ] || continue
name=$(basename "$bin")
sha256=$(sha256sum "$bin" 2>/dev/null | awk '{print $1}' \
|| shasum -a 256 "$bin" | awk '{print $1}')
label=$(echo "$name" | sed 's/^codebase-memory-mcp-//' | sed 's/\.exe$//')
short="${sha256:0:20}..."
vt_url="https://www.virustotal.com/gui/file/${sha256}/detection"
if [ -s "$TOL" ] && grep -q "^${name} " "$TOL"; then
completed=$(grep "^${name} " "$TOL" | cut -f6)
cell="[1/${completed} ⚠️ ML false positive, endpoint-verified clean](${vt_url})"
else
cell="[0 detections ✅](${vt_url})"
fi
TABLE+="| \`${label}\` | \`${short}\` | ${cell} |\n"
done
CURRENT=$(gh release view "$VERSION" \
--json body --jq '.body // ""' --repo "$GITHUB_REPOSITORY")
printf '%s%b' "$CURRENT" "$TABLE" > /tmp/release_notes.md
gh release edit "$VERSION" \
--notes-file /tmp/release_notes.md --repo "$GITHUB_REPOSITORY"