Skip to content

fix: retry transient pinned tool downloads - #1140

Draft
doublewhy wants to merge 4 commits into
devfrom
fix/ci-download-retries
Draft

fix: retry transient pinned tool downloads#1140
doublewhy wants to merge 4 commits into
devfrom
fix/ci-download-retries

Conversation

@doublewhy

@doublewhy doublewhy commented Aug 12, 2026

Copy link
Copy Markdown

Plain-language summary

  • Context: OpenRAE downloads checksum-pinned copies of Conftest, Vale, Gitleaks, and OSV Scanner before several required verification lanes. A recently merged helper already retries some failures up to five attempts.
  • Problem: That coarse helper automatically follows redirects, retries a broad transport-error class, has no single wall-clock deadline across response parsing and reads, and does not bound every response. The original version of this PR also left that helper beside a second implementation after rebasing.
  • Fix: Consolidate acquisition behind one governed downloader with explicit approved redirects, three bounded attempts, a true total read deadline, strict response framing and size checks, and sanitized failures. The earlier API is now only a compatibility facade and cannot raise those limits; every tool keeps its existing pin, checksum, cache, archive, and fail-closed validation.

Closes #1137.

Integration status

#1113 and #1121 have merged. This branch is rebased onto dev at 96b20ae8422fae9936bae928bbd8a1c14d2001da and includes both changes.

  • The shared tools/http_download.py added by feat: add source-neutral SDL candidate synthesis #1113 no longer contains a second retry implementation. It delegates to the governed release downloader and caps legacy attempt, timeout, and size options at the new policy.
  • Conftest, Vale, and Gitleaks retain their pinned version, checksum source, archive, cache, and install behavior; only release acquisition uses the governed downloader.
  • OSV Scanner retains fix(supply-chain): gate vulnerable dependencies and scanner cache #1121's repository-pinned digest table, cache type and identity checks, bounded hashing, safe cache path, executable validation, and durable atomic install. It makes one asset request through the governed downloader.
  • The obsolete OSV parameter in the two-stage checksum-metadata test is absent because OSV no longer downloads checksum metadata. Its one-request failure path remains covered by the shared installer diagnostic test.
  • A superseded Docs run reached the governed downloader and exhausted all three attempts on a Vale remote disconnect; that was an upstream availability failure, not a docs or style finding.

No #1113 or #1121 supply-chain control is duplicated, bypassed, or relaxed. No integration dependency on those merged changes remains. This PR stays draft and intentionally last in the current merge order while lower-layer CI and tooling PRs advance; all exact-head required checks are green.

What changed

  • Added one approved-origin release downloader shared by Conftest, Vale, Gitleaks, and OSV Scanner.
  • Replaced the earlier coarse retry implementation with a compatibility facade that delegates to the sole governed boundary.
  • Bounded production acquisition to three attempts, three redirect hops per attempt, a caller-capped 60-second per-hop/read socket timeout, a 190-second total deadline, capped deterministic backoff, capped Retry-After, and 256 MiB per response.
  • Prevented direct callers from raising the governed per-operation timeout; callers may only lower it.
  • Removed five obsolete inline network-rule suppressions after the adapters stopped calling the standard-library opener directly.
  • Retried only timeouts, remote disconnects, incomplete responses, connection failures, HTTP 408/429, and HTTP 5xx.
  • Replaced automatic redirects with an explicit HTTPS transition allowlist for the exact Vale repository relocation and GitHub's current release-assets.githubusercontent.com production-asset path. Signed final-asset queries are never logged, redirect bodies are never drained, and the asset host cannot redirect onward.
  • Made redirect validation total over malformed authorities: parser failures and Unicode-normalization traps now become one sanitized, non-retryable diagnostic without reflecting attacker-controlled Location text.
  • Added a deadline-aware raw socket reader so status lines, headers, proxy tunnel headers, chunk framing/trailers, and bodies all reapply the remaining wall deadline instead of relying on an idle timeout.
  • Streamed bodies under the shared deadline, validated declared lengths and transfer framing, retried early EOFs, and rejected oversized, malformed, conflicting, or over-reading responses without retry.
  • Normalized malformed HTTP/protocol exceptions to a stable non-retryable diagnostic without reflecting upstream status text or response bytes.
  • Rejected unapproved or ambiguous URLs before network access; no mirror, credential, or version fallback was added.
  • Kept checksum, signature, archive/type, identity, origin, and other owning validations outside the retry loop; the shared response-size bound also fails immediately without retry.
  • Updated the decision record and GOV-913 traceability for the single boundary, compatibility facade, and all four adapters.

Verification

On exact rebased head 4a107f7a05f9304ad7a51e22db2904b4cfd5d1ae:

  • 282 passed, 1 deselected across the feat: add source-neutral SDL candidate synthesis #1113 compatibility, retry, wrapper, and repository-tool test files.
  • All 505 changed executable lines and all 158 changed branch exits are covered in exact-base branch-aware analysis.
  • tools/release_download.py: 452/452 statements and 150/150 branch exits covered (100%).
  • tools/http_download.py: 26/26 statements and 10/10 branch exits covered (100%).
  • Canonical Ruff checks and formatting pass for all changed project tests and repository tooling.
  • The complete policy session passes, including Conftest self-verification, repository policy, requirement traceability, and ADR checks.
  • Ground Control-backed requirement governance reported its documented availability skip because the configured service hostname was not resolvable locally; this PR does not weaken that gate.
  • The live osv_scan Nox session passes against the current frozen lockfile.
  • Exact-head hosted verification is green: CI run 31664978450 passed verify, fuzz, Docker integration, supply-chain, and Sonar; Docs run 31664978515 and CodeQL run 31664975690 passed; title guard and GitGuardian passed. The PR-only deploy job was intentionally skipped.

The unchanged governed retry core previously passed its focused suite under Python 3.11, 3.12, 3.13, and 3.14. A dependency-isolated Python 3.15.0a8 run also passed it; full Python 3.15 project qualification remains separate in #1134.

Security and compatibility

No tool version, digest, checksum source, initial GitHub repository, cache path, archive rule, command line, or CI gate is weakened or changed. The legacy download_bytes API remains available but delegates to the sole governed implementation and cannot exceed its three-attempt, 60-second per-read, or 256 MiB limits. Exhausted transient failures remain hard failures.

@doublewhy
doublewhy force-pushed the fix/ci-download-retries branch 2 times, most recently from 8ae3d5b to 5532cbf Compare August 13, 2026 03:32
@doublewhy
doublewhy force-pushed the fix/ci-download-retries branch from 5532cbf to 4a107f7 Compare August 13, 2026 03:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant