From 43da9709fa14a6f73a2e87bf921fb4fd8a69eba4 Mon Sep 17 00:00:00 2001 From: rldyourmnd Date: Wed, 26 Aug 2026 02:53:23 +0500 Subject: [PATCH] fix(download): enforce three total attempts Signed-off-by: rldyourmnd --- .github/workflows/actionlint.yml | 4 ++-- .github/workflows/dart-flutter-ci.yml | 2 +- .github/workflows/hadolint-ci.yml | 2 +- .github/workflows/osv-scan.yml | 2 +- .github/workflows/qt-ci.yml | 2 +- .github/workflows/secret-scan.yml | 2 +- CHANGELOG.md | 4 ++++ scripts/check_workflow_contracts.py | 19 +++++++++++++++++++ scripts/run_private_security_bundle.sh | 2 +- 9 files changed, 31 insertions(+), 8 deletions(-) diff --git a/.github/workflows/actionlint.yml b/.github/workflows/actionlint.yml index f0eabe3..88d7905 100644 --- a/.github/workflows/actionlint.yml +++ b/.github/workflows/actionlint.yml @@ -108,7 +108,7 @@ jobs: # six seconds, which a Releases outage outlasts easily. Left unset, curl backs # off 1s, 2s, 4s, 8s..., and --retry-max-time bounds the whole thing so a # genuinely dead endpoint still fails the job rather than hanging it. - curl -fsSL --retry 5 --retry-max-time 120 -o /tmp/actionlint.tar.gz \ + curl -fsSL --retry 2 --retry-max-time 120 -o /tmp/actionlint.tar.gz \ "https://github.com/rhysd/actionlint/releases/download/v${ACTIONLINT_VERSION}/actionlint_${ACTIONLINT_VERSION}_linux_amd64.tar.gz" echo "${ACTIONLINT_SHA256} /tmp/actionlint.tar.gz" | sha256sum -c - tar -xzf /tmp/actionlint.tar.gz -C /tmp actionlint @@ -134,7 +134,7 @@ jobs: echo "enable_shellcheck is true but shellcheck_sha256 is empty; a SHA256 of shellcheck-v${SHELLCHECK_VERSION}.linux.x86_64.tar.xz is required" >&2 exit 1 fi - curl -fsSL --retry 5 --retry-max-time 120 -o /tmp/shellcheck.tar.xz \ + curl -fsSL --retry 2 --retry-max-time 120 -o /tmp/shellcheck.tar.xz \ "https://github.com/koalaman/shellcheck/releases/download/v${SHELLCHECK_VERSION}/shellcheck-v${SHELLCHECK_VERSION}.linux.x86_64.tar.xz" echo "${SHELLCHECK_SHA256} /tmp/shellcheck.tar.xz" | sha256sum -c - tar -xJf /tmp/shellcheck.tar.xz -C /tmp "shellcheck-v${SHELLCHECK_VERSION}/shellcheck" diff --git a/.github/workflows/dart-flutter-ci.yml b/.github/workflows/dart-flutter-ci.yml index 834b5f7..9a58f53 100644 --- a/.github/workflows/dart-flutter-ci.yml +++ b/.github/workflows/dart-flutter-ci.yml @@ -165,7 +165,7 @@ jobs: # --retry covers the transient case only; a 404 or a digest mismatch # must fail rather than be retried into success. curl --fail --silent --show-error --location \ - --retry 3 --retry-connrefused --max-time 900 \ + --retry 2 --retry-connrefused --max-time 900 \ --output "$archive" "$ARCHIVE_URL" printf '%s %s\n' "$ARCHIVE_SHA256" "$archive" > "${RUNNER_TEMP}/flutter.sha256" shasum -a 256 -c "${RUNNER_TEMP}/flutter.sha256" diff --git a/.github/workflows/hadolint-ci.yml b/.github/workflows/hadolint-ci.yml index bbb0f0a..e24fce8 100644 --- a/.github/workflows/hadolint-ci.yml +++ b/.github/workflows/hadolint-ci.yml @@ -119,7 +119,7 @@ jobs: # six seconds, which a Releases outage outlasts easily. Left unset, curl backs # off 1s, 2s, 4s, 8s..., and --retry-max-time bounds the whole thing so a # genuinely dead endpoint still fails the job rather than hanging it. - curl -fsSL --retry 5 --retry-max-time 120 -o "${RUNNER_TEMP}/hadolint" \ + curl -fsSL --retry 2 --retry-max-time 120 -o "${RUNNER_TEMP}/hadolint" \ "https://github.com/hadolint/hadolint/releases/download/v${HADOLINT_VERSION}/hadolint-linux-x86_64" echo "${HADOLINT_SHA256} ${RUNNER_TEMP}/hadolint" | sha256sum -c - # Install into a runner-writable directory rather than /usr/local/bin: diff --git a/.github/workflows/osv-scan.yml b/.github/workflows/osv-scan.yml index 7e884a0..3c4b45b 100644 --- a/.github/workflows/osv-scan.yml +++ b/.github/workflows/osv-scan.yml @@ -73,7 +73,7 @@ jobs: # six seconds, which a Releases outage outlasts easily. Left unset, curl backs # off 1s, 2s, 4s, 8s..., and --retry-max-time bounds the whole thing so a # genuinely dead endpoint still fails the job rather than hanging it. - curl -fsSL --retry 5 --retry-max-time 120 -o /tmp/osv-scanner \ + curl -fsSL --retry 2 --retry-max-time 120 -o /tmp/osv-scanner \ "https://github.com/google/osv-scanner/releases/download/v${OSV_VERSION}/osv-scanner_linux_amd64" echo "${OSV_SHA256} /tmp/osv-scanner" | sha256sum -c - # Install into a runner-writable directory rather than /usr/local/bin: diff --git a/.github/workflows/qt-ci.yml b/.github/workflows/qt-ci.yml index d854008..2f0e649 100644 --- a/.github/workflows/qt-ci.yml +++ b/.github/workflows/qt-ci.yml @@ -135,7 +135,7 @@ jobs: run: | set -euo pipefail lock="$RUNNER_TEMP/requirements-qt.txt" - curl --fail --silent --show-error --location --retry 3 \ + curl --fail --silent --show-error --location --retry 2 \ --output "$lock" \ "https://raw.githubusercontent.com/$CALLEE_REPOSITORY/$CALLEE_SHA/requirements-qt.txt" printf '%s %s\n' "$LOCK_SHA256" "$lock" | sha256sum --check --status || { diff --git a/.github/workflows/secret-scan.yml b/.github/workflows/secret-scan.yml index 74cda52..01321f0 100644 --- a/.github/workflows/secret-scan.yml +++ b/.github/workflows/secret-scan.yml @@ -226,7 +226,7 @@ jobs: binary_root="$(mktemp -d "${RUNNER_TEMP}/nddev-gitleaks.XXXXXX")" archive="${binary_root}/${GITLEAKS_BINARY_ASSET}" printf 'GITLEAKS_BINARY_ROOT=%s\n' "$binary_root" >> "$GITHUB_ENV" - curl -fsSL --retry 5 --retry-max-time 120 \ + curl -fsSL --retry 2 --retry-max-time 120 \ --output "$archive" "$GITLEAKS_BINARY_URL" actual_size="$(wc -c < "$archive" | tr -d '[:space:]')" if [ "$actual_size" != "$GITLEAKS_BINARY_SIZE" ]; then diff --git a/CHANGELOG.md b/CHANGELOG.md index 0dcf100..dd347c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ The project follows Semantic Versioning. ## [Unreleased] +- Standardized reviewed network downloads on two retries after the initial + request: exactly three total attempts, with checksum and permanent-failure + handling unchanged. + ## [0.1.10] - 2026-08-25 - Updated the immutable tool-cache action to signed `v1.0.1`, retaining each diff --git a/scripts/check_workflow_contracts.py b/scripts/check_workflow_contracts.py index 991ef35..595bec7 100644 --- a/scripts/check_workflow_contracts.py +++ b/scripts/check_workflow_contracts.py @@ -334,12 +334,31 @@ def check() -> list[str]: problems += _runner_selftest() problems += _job_defaults_pin_the_shell() problems += _started_runs_are_preserved() + problems += _download_attempts_are_bounded() return problems BARE_BASH_C = re.compile(r'\bbash -c "(\$\{?[A-Za-z_][A-Za-z0-9_]*\}?)"') # Inputs whose value is handed to a shell by the reusable that receives it. COMMAND_INPUT = re.compile(r"(^|_)commands?$") +DOWNLOAD_RETRY = re.compile(r"--retry[ =]([0-9]+)") + + +def _download_attempts_are_bounded() -> list[str]: + """curl's retry count excludes the initial request; two means three attempts.""" + problems: list[str] = [] + paths = [*workflow_files(), *(Path("scripts").glob("*.sh"))] + for path in paths: + for lineno, line in enumerate(path.read_text(encoding="utf-8").splitlines(), start=1): + if line.lstrip().startswith("#"): + continue + for match in DOWNLOAD_RETRY.finditer(line): + if int(match.group(1)) > 2: + problems.append( + f"{path}:{lineno}: download retry count {match.group(1)} " + "exceeds two retries / three total attempts" + ) + return problems def _started_runs_are_preserved() -> list[str]: diff --git a/scripts/run_private_security_bundle.sh b/scripts/run_private_security_bundle.sh index 52b84dc..622fd58 100755 --- a/scripts/run_private_security_bundle.sh +++ b/scripts/run_private_security_bundle.sh @@ -52,7 +52,7 @@ use_or_download() { install -m 0600 "$supplied" "$output" return fi - curl -fsSL --retry 5 --retry-max-time 120 -o "$output" "$url" + curl -fsSL --retry 2 --retry-max-time 120 -o "$output" "$url" } use_or_download "${ACTIONLINT_ARCHIVE_PATH:-}" "$tool_root/actionlint.tar.gz" \