Skip to content

Instantly share code, notes, and snippets.

@arsdragonfly
Created September 12, 2025 19:58
Show Gist options
  • Select an option

  • Save arsdragonfly/e375f5d74c9828a04eeac35d0935e3be to your computer and use it in GitHub Desktop.

Select an option

Save arsdragonfly/e375f5d74c9828a04eeac35d0935e3be to your computer and use it in GitHub Desktop.
Download Trivy on Windows
#!/usr/bin/env python3
"""
Download and extract Trivy Windows binary (trivy.exe) into a "trivy" folder.
Usage:
python download_trivy_windows.py [--version X.Y.Z]
If --version is omitted the script queries the GitHub API for the latest release.
"""
import argparse
import io
import json
import os
import shutil
import sys
import tempfile
import time
import zipfile
from urllib.request import Request, urlopen
from urllib.error import URLError, HTTPError
GITHUB_API_LATEST = "https://api.github.com/repos/aquasecurity/trivy/releases/latest"
def get_latest_version():
req = Request(GITHUB_API_LATEST, headers={
"Accept": "application/vnd.github+json",
"X-GitHub-Api-Version": "2022-11-28",
"User-Agent": "azhpc-download-script"
})
with urlopen(req, timeout=30) as resp:
data = json.load(resp)
name = data.get("name")
if not name:
raise RuntimeError("failed to get release name from GitHub API")
return name.lstrip("v")
def download(url, dest_path, retries=3, backoff=3):
for attempt in range(1, retries + 1):
try:
req = Request(url, headers={"User-Agent": "azhpc-download-script"})
with urlopen(req, timeout=60) as resp:
total = resp.getheader("Content-Length")
total = int(total) if total and total.isdigit() else None
with open(dest_path, "wb") as out:
downloaded = 0
chunk_size = 8192
while True:
chunk = resp.read(chunk_size)
if not chunk:
break
out.write(chunk)
downloaded += len(chunk)
return
except (HTTPError, URLError) as e:
if attempt == retries:
raise
time.sleep(backoff * attempt)
def extract_all(zip_path, dest_dir):
"""Extract entire ZIP into dest_dir (creates dest_dir)."""
with zipfile.ZipFile(zip_path, "r") as zf:
os.makedirs(dest_dir, exist_ok=True)
zf.extractall(path=dest_dir)
return os.path.abspath(dest_dir)
def main():
p = argparse.ArgumentParser()
p.add_argument("--version", help="trivy version (e.g. 0.45.0). If omitted, uses latest release from GitHub")
p.add_argument("--out-dir", default="trivy", help="output directory to place trivy.exe")
args = p.parse_args()
version = args.version
if not version:
print("Querying GitHub for latest Trivy release...")
version = get_latest_version()
print(f"Latest Trivy version: {version}")
zip_name = f"trivy_{version}_windows-64bit.zip"
url = f"https://github.com/aquasecurity/trivy/releases/download/v{version}/{zip_name}"
td = tempfile.mkdtemp(prefix="trivy-download-")
try:
zip_path = os.path.join(td, zip_name)
print(f"Downloading {url} -> {zip_path}")
download(url, zip_path)
print("Download complete; extracting archive to trivy folder...")
dest = extract_all(zip_path, args.out_dir)
print(f"Extracted archive contents to: {dest}")
finally:
shutil.rmtree(td, ignore_errors=True)
if __name__ == "__main__":
try:
main()
except Exception as e:
print("ERROR:", str(e), file=sys.stderr)
sys.exit(2)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment