Repository navigation
ci(dry-run): scan the archive artifacts with VirusTotal as the final step - #1489
Merged
Merged
Conversation
…step
Preparation for the next dry-run cycle. The release gate scans every shipped
artifact with VirusTotal and blocks on any detection; the dry run did not, so
the one question most likely to stop a release was the one a dry run could not
answer. v0.9.1-rc found that out the expensive way.
The scan mirrors the release job. The only difference is where the archives come
from: the release pulls them off a published release, a dry run has none, so
they come from the build job's artifacts — the same files, produced by the same
canonical package-release.sh, extracted the same way and scanned as the same
bytes a user would download and run. Same zero-tolerance gate
(scripts/ci/check-virustotal.sh), so a dry run now fails where the release would.
It runs LAST, after smoke and soak. It is the slowest job — polling can take two
hours — and its verdict does not depend on our code at all: the same unchanged
bytes can come back clean one day and flagged the next. That must not delay the
feedback that IS about our code.
Two independent skips, because they answer different questions:
skip_builds no artifacts at all "do lint and tests pass?"
skip_virustotal build + smoke + soak, no scan "do the archives pass CI?"
The second is the one asked for: during a debug cycle, when the question is
whether the archives survive smoke and soak, a two-hour scan burning API quota
is pure noise. skip_builds implies no scan, since there is nothing to scan.
Extraction lives in scripts/ci/extract-release-archives.sh rather than inline in
the YAML because the venue-parity contract requires it — a venue may provision,
plumb artifacts, or call a canonical leg script, and this is leg logic. The
contract caught the inline version.
Two defects found by testing the script instead of trusting it:
* The empty-input guard did not guard. It counted files in the output
directory, but the install scripts are copied in unconditionally, so the
count was never zero and an input with no archives reported success — a
clean VirusTotal run over nothing, the exact false green the check exists to
prevent. It now counts binaries recovered from archives, and exits 1 on
zero.
* The script was committed 100644 while the workflow invokes it directly as a
command, which is the "Permission denied" failure
test_script_exec_bit_contract.sh was written for. That contract scans
scripts/ but not .github/workflows/, so it did not catch it here.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Preparation for the next dry-run cycle.
Why
The release gate scans every shipped artifact with VirusTotal and blocks on any detection. The dry run did not — so the single question most likely to stop a release was the one a dry run couldn't answer. v0.9.1-rc found that out the expensive way.
What
The scan mirrors the release job. The only difference is provenance: the release pulls archives off a published release, a dry run has none, so they come from the build job's artifacts — the same files, produced by the same canonical
package-release.sh, extracted the same way, scanned as the same bytes a user downloads and runs. Same zero-tolerance gate (scripts/ci/check-virustotal.sh), so a dry run now fails where the release would.It runs last, after smoke and soak. It's the slowest job (polling can take two hours) and its verdict doesn't depend on our code at all — the same unchanged bytes can come back clean one day and flagged the next. That must not delay the feedback that is about our code.
Two independent skips
skip_buildsskip_virustotalThe second is the one requested: during a debug cycle, when the question is whether the archives survive smoke and soak, a two-hour scan burning API quota is pure noise.
skip_buildsimplies no scan — there's nothing to scan.Extraction moved to a script
scripts/ci/extract-release-archives.sh, not inline YAML, because the venue-parity contract requires it — a venue may provision, plumb artifacts, or call a canonical leg script, and this is leg logic. The contract caught the inline version and was right to.Two defects found by testing the script rather than trusting it
100644while the workflow invokes it directly as a command — the "Permission denied" failuretest_script_exec_bit_contract.shwas written for. That contract scansscripts/but not.github/workflows/, so it didn't catch it here. Now100755, matching its siblings.Scope notes
dry-run.ymlisworkflow_dispatch-only, so nothing here runs on PRs or pushes.Contracts pass: venue-parity, release-gate-chain, exec-bit.