diff --git a/scripts/ci/check-virustotal.sh b/scripts/ci/check-virustotal.sh index 37859471..427d398d 100755 --- a/scripts/ci/check-virustotal.sh +++ b/scripts/ci/check-virustotal.sh @@ -425,8 +425,8 @@ def parse_completed(document: object, submission: Submission) -> Tuple[str, Opti if data.get("type") != "analysis": raise GateError(f"VirusTotal response is not an analysis for {submission.expected.scan_path}") response_id = data.get("id") - if response_id != submission.analysis_id: - raise GateError(f"VirusTotal response id mismatch for {submission.expected.scan_path}") + if not isinstance(response_id, str) or ANALYSIS_ID_RE.fullmatch(response_id) is None: + raise GateError(f"VirusTotal response has an invalid analysis id: {submission.expected.scan_path}") attributes = data.get("attributes") if not isinstance(attributes, dict): raise GateError("VirusTotal response has no analysis attributes") diff --git a/tests/test_vt_gate_zero_tolerance_contract.sh b/tests/test_vt_gate_zero_tolerance_contract.sh index e89d837c..4e7f9d6f 100644 --- a/tests/test_vt_gate_zero_tolerance_contract.sh +++ b/tests/test_vt_gate_zero_tolerance_contract.sh @@ -93,6 +93,15 @@ write_response low-engines 0 0 49 "$PROBE_SHA" "$PROBE_SIZE" write_response wrong-hash 0 0 60 "$PROBE2_SHA" "$PROBE_SIZE" write_response wrong-size 0 0 60 "$PROBE_SHA" "$((PROBE_SIZE + 1))" +cat > "$FIX/responses/upload-alias.json" < "$FIX/responses/named-engine.json" < prints rc clean_output="binaries/objects/probe=$(url_for clean-analysis)" [ "$(run_gate "$clean_output")" = "0" ] || fail "clean exact scan must pass: $(cat "$FIX/last.log")" +alias_output="binaries/objects/probe=$(url_for upload-alias)" +[ "$(run_gate "$alias_output")" = "0" ] || \ + fail "a content-bound canonical response alias must pass: $(cat "$FIX/last.log")" RESULTS="$FIX/work/binaries/vt-results.tsv" [ -f "$RESULTS" ] || fail "clean gate did not atomically publish its results manifest" grep -q '^# cbm-virustotal-results-v1$' "$RESULTS" || fail "results marker missing" grep -q "objects/probe.*$PROBE_SHA.*$PROBE_SIZE.*60" "$RESULTS" || \ fail "results do not bind path/hash/size/actual engine count" +grep -Fq 'upload-alias' "$RESULTS" || \ + fail "results must retain the action's submitted analysis ID" for id in one-malicious one-suspicious; do [ "$(run_gate "binaries/objects/probe=$(url_for "$id")")" != "0" ] || \