@@ -533,66 +533,71 @@ jobs:
533533
534534 # ── Wait for ALL VirusTotal engines to complete, then check ──
535535 # The action outputs comma-separated "file=URL" pairs.
536- # We wait until every engine has reported (not just the first few),
537- # then check for any malicious or suspicious detection.
538- # Minimum 60 engines required — below that we consider the scan incomplete.
536+ # URLs are /gui/file-analysis/<base64_id>/detection — we extract the
537+ # base64 analysis ID and poll /api/v3/analyses/<id> until completed.
539538 - name : Check VirusTotal scan results (wait for 100% completion)
540539 env :
541540 VT_API_KEY : ${{ secrets.VIRUS_TOTAL_SCANNER_API_KEY }}
542541 VT_ANALYSIS : ${{ steps.virustotal.outputs.analysis }}
543542 run : |
544543 echo "=== Waiting for VirusTotal scans to fully complete ==="
545544 MIN_ENGINES=60
545+ rm -f /tmp/vt_gate_fail
546546
547547 echo "$VT_ANALYSIS" | tr ',' '\n' | while IFS= read -r entry; do
548548 [ -z "$entry" ] && continue
549549 FILE=$(echo "$entry" | cut -d'=' -f1)
550550 URL=$(echo "$entry" | cut -d'=' -f2-)
551551 BASENAME=$(basename "$FILE")
552552
553- SHA256=$(echo "$URL" | grep -oE '[a-f0-9]{64}')
554- if [ -z "$SHA256" ]; then
555- echo "WARNING: Could not extract SHA256 from $URL — skipping"
556- continue
553+ # Extract base64 analysis ID from URL: /gui/file-analysis/<ID>/detection
554+ ANALYSIS_ID=$(echo "$URL" | sed -n 's|.*/file-analysis/\([^/]*\)/.*|\1|p')
555+ if [ -z "$ANALYSIS_ID" ]; then
556+ echo "WARNING: Could not extract analysis ID from $URL"
557+ # Try SHA256 fallback (older action versions use /gui/file/<sha256>)
558+ ANALYSIS_ID=$(echo "$URL" | grep -oE '[a-f0-9]{64}')
559+ if [ -z "$ANALYSIS_ID" ]; then
560+ echo "BLOCKED: Cannot parse VirusTotal URL: $URL"
561+ echo "FAIL" >> /tmp/vt_gate_fail
562+ continue
563+ fi
557564 fi
558565
559- # Poll until ALL engines have completed (max 20 minutes per binary )
566+ # Poll /api/v3/analyses/<id> until status= completed (max 20 min )
560567 SCAN_COMPLETE=false
561568 for attempt in $(seq 1 120); do
562569 RESULT=$(curl -sf --max-time 10 \
563570 -H "x-apikey: $VT_API_KEY" \
564- "https://www.virustotal.com/api/v3/files/$SHA256 " 2>/dev/null || echo "")
571+ "https://www.virustotal.com/api/v3/analyses/$ANALYSIS_ID " 2>/dev/null || echo "")
565572
566573 if [ -z "$RESULT" ]; then
567- echo " $BASENAME: waiting for file to be processed (attempt $attempt)..."
574+ echo " $BASENAME: waiting (attempt $attempt)..."
568575 sleep 10
569576 continue
570577 fi
571578
572- # Parse all stats in one python call
573579 STATS=$(echo "$RESULT" | python3 -c "
574580 import json, sys
575581 d = json.loads(sys.stdin.read())
576- stats = d.get('data', {}).get('attributes', {}).get('last_analysis_stats', {})
582+ attrs = d.get('data', {}).get('attributes', {})
583+ status = attrs.get('status', 'queued')
584+ stats = attrs.get('stats', {})
577585 malicious = stats.get('malicious', 0)
578586 suspicious = stats.get('suspicious', 0)
579587 undetected = stats.get('undetected', 0)
580588 harmless = stats.get('harmless', 0)
581- failure = stats.get('failure', 0)
582- timeout = stats.get('timeout', 0)
583- unsupported = stats.get('type-unsupported', 0)
584589 total = sum(stats.values())
585- # 'confirmed-timeout' may also exist
586590 completed = malicious + suspicious + undetected + harmless
587- print(f'{malicious},{suspicious},{completed},{total}')
588- " 2>/dev/null || echo "0,0,0,0")
591+ print(f'{status},{ malicious},{suspicious},{completed},{total}')
592+ " 2>/dev/null || echo "queued, 0,0,0,0")
589593
590- MALICIOUS=$(echo "$STATS" | cut -d',' -f1)
591- SUSPICIOUS=$(echo "$STATS" | cut -d',' -f2)
592- COMPLETED=$(echo "$STATS" | cut -d',' -f3)
593- TOTAL=$(echo "$STATS" | cut -d',' -f4)
594+ STATUS=$(echo "$STATS" | cut -d',' -f1)
595+ MALICIOUS=$(echo "$STATS" | cut -d',' -f2)
596+ SUSPICIOUS=$(echo "$STATS" | cut -d',' -f3)
597+ COMPLETED=$(echo "$STATS" | cut -d',' -f4)
598+ TOTAL=$(echo "$STATS" | cut -d',' -f5)
594599
595- if [ "$TOTAL" -ge "$MIN_ENGINES" ] && [ "$COMPLETED" -ge "$MIN_ENGINES " ]; then
600+ if [ "$STATUS" = "completed " ]; then
596601 echo "$BASENAME: $MALICIOUS malicious, $SUSPICIOUS suspicious ($COMPLETED completed, $TOTAL total engines)"
597602
598603 if [ "$MALICIOUS" -gt 0 ] || [ "$SUSPICIOUS" -gt 0 ]; then
@@ -603,7 +608,7 @@ jobs:
603608 break
604609 fi
605610
606- echo " $BASENAME: $COMPLETED/$TOTAL engines completed (attempt $attempt, need $MIN_ENGINES )..."
611+ echo " $BASENAME: $STATUS (attempt $attempt)..."
607612 sleep 10
608613 done
609614
0 commit comments