Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
67d6b53
test(coverage): define bounded trusted uv download retries
seonghobae Aug 5, 2026
8e28523
docs(coverage): define trusted uv transient retry boundary
seonghobae Aug 5, 2026
b3fb370
ci: verify trusted uv retry repair once
seonghobae Aug 5, 2026
6cc1c40
ci: repair trusted uv retry workflow syntax
seonghobae Aug 5, 2026
a893955
ci: add one-shot trusted uv retry patch helper
seonghobae Aug 5, 2026
03499b1
ci: run trusted uv retry repair with a standalone helper
seonghobae Aug 5, 2026
581cf5c
ci: exclude one-shot helper from final coverage gate
seonghobae Aug 5, 2026
e053a9a
fix(coverage): retry transient trusted uv downloads
github-actions[bot] Aug 5, 2026
5b7f42c
ci(pr790): repair transient transport classification
seonghobae Aug 5, 2026
390c52b
test(coverage): narrow trusted uv retries to transient failures
seonghobae Aug 5, 2026
d4db09b
ci(pr790): trigger bounded transport repair
seonghobae Aug 5, 2026
5b0766a
ci(pr790): align repair with reviewed RED contracts
seonghobae Aug 5, 2026
b4196bd
ci: export exact PR 790 repair source for verified publication
seonghobae Aug 5, 2026
26a7873
ci: expose exact PR 790 source artifact to pull-request verification
seonghobae Aug 5, 2026
492dd41
chore: remove temporary PR 790 export workflow
seonghobae Aug 5, 2026
f191b1e
chore: remove temporary PR 790 repair workflow
seonghobae Aug 5, 2026
0c1002f
ci(pr790): add deterministic transport finalizer
seonghobae Aug 5, 2026
d62c5a1
ci: apply test-first PR 790 classifier repair
seonghobae Aug 5, 2026
5582e9b
ci(pr790): finalize reviewed transport repair
seonghobae Aug 5, 2026
182d8a6
fix(pr790): cover explicit timeout classification
seonghobae Aug 5, 2026
d78c922
ci(pr790): remove temporary sources before coverage
seonghobae Aug 5, 2026
379b3ec
fix(coverage): classify transient uv transport failures
github-actions[bot] Aug 5, 2026
84d8aa9
test(coverage): lock retry documentation to closed policy
seonghobae Aug 5, 2026
8a51b4f
docs(coverage): reconcile closed trusted uv retry policy
seonghobae Aug 5, 2026
c95a122
docs(changelog): remove overbroad retry claim
seonghobae Aug 5, 2026
24b7f1f
test(coverage): normalize retry policy Markdown
seonghobae Aug 5, 2026
b30303b
test(coverage): align retry policy wording
seonghobae Aug 5, 2026
8516ecb
test(security): prove Git PATH injection fails closed
seonghobae Aug 5, 2026
95816a5
ci(repair): add bounded trusted Git exact-trigger repair
seonghobae Aug 5, 2026
e8d6b2a
ci(repair): bind trusted Git repair to PR exact head
seonghobae Aug 5, 2026
7f426f3
ci(repair): correct exact-head trusted Git commit path
seonghobae Aug 5, 2026
945a6c5
ci(repair): reconcile workflow-permission boundary
seonghobae Aug 5, 2026
075299d
fix(security): resolve Git outside ambient PATH
github-actions[bot] Aug 5, 2026
09744fc
ci(coverage): gate trusted Git executable regression
seonghobae Aug 5, 2026
409fd96
ci(repair): remove bounded trusted Git repair workflow
seonghobae Aug 5, 2026
a306e7c
test(ci): require trusted Git contract trigger coverage
seonghobae Aug 5, 2026
5570d5a
fix(ci): trigger trusted Git contract quality gate
seonghobae Aug 5, 2026
c2fffa1
test(coverage): reject malformed URL reasons without retry
seonghobae Aug 6, 2026
c09313e
ci(pr790): add malformed URL error regression
seonghobae Aug 6, 2026
614002d
test(coverage): pin malformed URL error failure
github-actions[bot] Aug 6, 2026
d11085b
test(coverage): reject malformed URL error reasons
seonghobae Aug 6, 2026
e9fb719
test(coverage): consolidate malformed URL error regression
seonghobae Aug 6, 2026
6f6354b
test(coverage): remove duplicate malformed URL regression
seonghobae Aug 6, 2026
f190f28
test(security): reproduce materializer output path races
seonghobae Aug 6, 2026
e84990c
fix(security): pin materializer output descriptors
seonghobae Aug 6, 2026
b20de65
ci(security): gate descriptor-pinned output regressions
seonghobae Aug 6, 2026
ee90706
docs(security): record descriptor-pinned output contract
seonghobae Aug 6, 2026
b27a1c0
chore(changelog): record output race remediation
seonghobae Aug 6, 2026
1bad6f8
test(coverage): exercise output descriptor failure edges
seonghobae Aug 6, 2026
9211a66
test(coverage): lock malformed URLError reason fail-closed
seonghobae Aug 6, 2026
b90461f
test(coverage): remove duplicate malformed reason contract
seonghobae Aug 6, 2026
5b3a692
test(strix): define semantic non-finding classification
seonghobae Aug 6, 2026
85a122e
fix(strix): classify contradictory semantic non-findings
seonghobae Aug 6, 2026
1d17661
test(strix): require classifier before severity handling
seonghobae Aug 6, 2026
f976605
ci(repair): apply exact-head Strix classifier integration
seonghobae Aug 6, 2026
9502bd4
chore(ci): stop unsafe Strix gate rewrite
seonghobae Aug 6, 2026
9a22722
revert(security): keep contradictory Strix findings blocking
seonghobae Aug 6, 2026
1cae779
revert(test): remove Strix gate-bypass contract
seonghobae Aug 6, 2026
dc78b91
test(coverage): reject hard links added during pinned writes
seonghobae Aug 7, 2026
9e6b720
fix(coverage): revalidate output link count after writes
seonghobae Aug 7, 2026
1bee5b0
docs(coverage): record post-write hard-link validation
seonghobae Aug 7, 2026
c70b954
docs(coverage): define post-write link-count boundary
seonghobae Aug 7, 2026
80b54da
docs(uv): pin Python 3.14 urllib reference
seonghobae Aug 7, 2026
b4c82b2
test(uv): isolate trusted Git executable cache
seonghobae Aug 7, 2026
62f9cde
ci(uv): register retry doctoring regression consistently
seonghobae Aug 7, 2026
d69c073
test(uv): require retry doctoring in focused quality lists
seonghobae Aug 7, 2026
969c1c6
chore(stack): reconcile trusted uv hardening with main
seonghobae Aug 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .github/workflows/trusted-uv-materializer-quality-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ on:
- "scripts/ci/materialize_base_python_requirements.py"
- "tests/conftest.py"
- "tests/test_materialize*.py"
- "tests/test_trusted_git_executable.py"
- "tests/test_trusted_uv*.py"
- "tests/test_uv*.py"
- "tests/test_repository_branch_coverage_*.py"
Expand All @@ -20,6 +21,7 @@ on:
- "scripts/ci/materialize_base_python_requirements.py"
- "tests/conftest.py"
- "tests/test_materialize*.py"
- "tests/test_trusted_git_executable.py"
- "tests/test_trusted_uv*.py"
- "tests/test_uv*.py"
- "tests/test_repository_branch_coverage_*.py"
Expand Down Expand Up @@ -125,9 +127,12 @@ jobs:
python -m coverage erase
python -m coverage run -m pytest \
tests/test_materialize_base_python_requirements.py \
tests/test_materialize_output_directory_security.py \
tests/test_materialize_uv_export_hash_contract.py \
tests/test_trusted_git_executable.py \
tests/test_trusted_uv_download_contract.py \
tests/test_trusted_uv_portability_and_streaming.py \
tests/test_trusted_uv_retry_documentation.py \
tests/test_uv_export_isolation_contract.py \
tests/test_uv_redirect_and_coverage_contract.py \
tests/test_uv_redirect_boundary.py \
Expand All @@ -151,9 +156,12 @@ jobs:
python -m compileall -q \
scripts/ci/materialize_base_python_requirements.py \
tests/test_materialize_base_python_requirements.py \
tests/test_materialize_output_directory_security.py \
tests/test_materialize_uv_export_hash_contract.py \
tests/test_trusted_git_executable.py \
tests/test_trusted_uv_download_contract.py \
tests/test_trusted_uv_portability_and_streaming.py \
tests/test_trusted_uv_retry_documentation.py \
tests/test_uv_export_isolation_contract.py \
tests/test_uv_redirect_and_coverage_contract.py \
tests/test_uv_redirect_boundary.py \
Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ Semantic Versioning where the repository publishes a release.

### Fixed

- Pinned generated Python lock output to no-follow directory and file descriptors, rejected symbolic and multiply linked destinations before mutation, revalidated inode and single-link bindings after synchronized writes, and added deterministic regressions for output-path races, hard links introduced during writes, file swaps, and stalled writes.
- Resolved Git only through the operating system default executable path and rejected missing or relative results before trusted base-lock materialization, preventing pull-request-controlled `PATH` selection.
- Restricted trusted uv retries to HTTP 408/425/429/500/502/503/504 and explicitly classified temporary DNS, timeout, connection, host, or network failures; every retry reuses the immutable request contract and discards failed-attempt bytes, while TLS, permanent DNS, malformed, and unclassified local errors fail after one attempt.
- Bound each review-agent invocation key to the wrapper's complete canonical payload, including the base branch and requesting actor; altered fields with a valid-format key now fail before durable-leader election or forwarding, and wrapper write permission is job-scoped.
- Bound both trusted-uv quality jobs to `github.event.pull_request.head.sha` and added a permanent two-checkout regression contract so exact-head compatibility, coverage, docstring, and compilation claims cannot silently measure GitHub's generated pull-request merge revision.
- Made Strix treat only a single LiteLLM provider-error line containing NVIDIA NIM context and model-catalog 404 evidence as cross-model fallback evidence, rejecting cross-line signal assembly and provider-like target source literals; moved the public default to Nemotron 3 Super 120B and added a second NVIDIA hosted candidate before GitHub Models without neutralizing reported vulnerabilities.
94 changes: 94 additions & 0 deletions docs/doctoring/trusted-uv-transient-download-retry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# Trusted uv transient download retry boundary

## Decision

The central coverage materializer downloads one checksum-pinned uv archive from one literal Astral HTTPS URL. It performs at most **three total attempts**, separated by deterministic delays of one and two seconds, only for this closed availability set:

- HTTP `408`, `425`, `429`, `500`, `502`, `503`, and `504`;
- temporary DNS resolution reported as `EAI_AGAIN`;
- `TimeoutError`; and
- connection aborted, refused, or reset, plus explicit host or network down, reset, unreachable, or timed-out operating-system errors.

The fixed `GET` is safe and idempotent, so a bounded retry does not mutate remote or repository state. Each attempt repeats the same literal URL and exact timeout. The retry loop does not follow redirects, enable proxies, change the release URL, use repository-controlled headers, or accept an unverified payload.

## Fail-closed exclusions

The following conditions are never retried:

- every HTTP response outside the exact closed set, including authorization, not-found, and unsupported-method failures;
- certificate verification or any other TLS failure;
- permanent DNS failure;
- a malformed or non-exception `URLError.reason`;
- local permission failures and every unclassified `OSError`;
- redirect attempts or a final origin or port outside the fixed Astral HTTPS origin;
- an oversized archive;
- SHA-256 mismatch;
- malformed archive members, incorrect executable size or type, unsupported runner architecture, or unexpected uv version; and
- offline export, exact-pin grammar, Git-tree, TOML, or workspace-boundary failures.

A response body belongs to one attempt only. Partial bytes read before a transient failure are discarded before the next attempt. Retry exhaustion reports only a bounded HTTP status, transport errno, or exception class and the attempt count. It never includes exception text, URLs, response bodies, headers, credentials, or URL-derived user information.

The base-commit reader resolves `git` with `shutil.which("git", path=os.defpath)` and accepts only an absolute result. The ambient process `PATH` cannot select the executable; missing or relative resolution fails before any repository command runs.

## Descriptor-pinned output boundary

The generated-lock output path is treated as an untrusted namespace rather than as a stable object. Every directory component is created or opened relative to an already-open parent descriptor with `O_DIRECTORY`, `O_NOFOLLOW`, and `O_CLOEXEC`. The materializer compares the path entry's device and inode to the pinned descriptor immediately after open and again before reporting success. Removing, replacing, or redirecting the output pathname therefore fails closed; subsequent writes never re-resolve that mutable pathname.

Generated requirements and manifests are opened relative to the pinned output directory. A new file requires `O_CREAT | O_EXCL | O_NOFOLLOW`; a rerun may reopen only an existing singly linked regular file. Symbolic links, hard links, directories, FIFOs, and other special files are rejected before truncation. Each write is bounded by forward-progress checks and synchronized with `fsync`. After synchronization, both the published path and the pinned file descriptor must still identify the same singly linked regular inode; a hard link introduced during the write window therefore fails closed before success. The directory is then synchronized and revalidated.

This contract intentionally uses the POSIX descriptor-relative interface represented by `openat()` and Python's `dir_fd` operations. It prevents the check-then-use gap reported against the earlier `Path.exists()`/`Path.is_symlink()` followed by `Path.mkdir()` sequence. The central GitHub runner is Linux; a platform that does not provide the required no-follow descriptor flags fails at import or execution rather than silently falling back to pathname-based writes.

## Incident evidence

Central OpenCode coverage run `31002427460` for `ContextualWisdomLab/newsdom-api#524` reached the exact trusted-uv materialization stage and failed with `trusted uv archive download failed: HTTPError`. The source PR changed only `AGENTS.md`; all repository-local checks were successful. A later workflow in the same operating window downloaded the pinned uv release successfully, supporting a bounded transient-retry response rather than weakening the immutable bootstrap or bypassing coverage.

The same failure class later blocked exact-head OpenCode coverage for `ContextualWisdomLab/pg-llm-batch#53` in central workflow run `31022108085`. Repository-local CI, security, and SAST checks passed on that exact product head, while trusted uv archive materialization failed before PR-controlled tests ran.

Exact-head Strix run `31076540331` for organization control-plane PR `ContextualWisdomLab/.github#790` identified a medium-severity time-of-check/time-of-use race between output-directory symlink inspection and directory creation. The finding was valid rather than stale or infrastructure-only. Test-first commit `a1dcc679c1767f7e806793d7c0225a1342a9a875` captured intermediate symlink, pathname removal and replacement, generated-file symlink and hard-link, post-open swap, zero-progress write, and root-output regressions before descriptor-pinned production remediation.

A later exact-head independent review found a second valid race: a concurrent writer could add a hard link after the initial `st_nlink == 1` check while the descriptor remained bound to the same inode. RED commit `dc78b919e36011fa0f56e3ce9e334d3b1cb2261e` proved the existing implementation accepted that condition. The production fix revalidates regular-file type, device/inode identity, and single-link state after `fsync`, so the same race now fails closed.

## Verification contract

Permanent tests require:

- every HTTP status in the exact closed set receives one bounded retry;
- representative permanent HTTP responses fail after one attempt and no sleep;
- temporary DNS, timeout, and connection-reset failures retry;
- certificate verification, permanent DNS, malformed transport reasons, and unclassified local errors fail after one attempt and no sleep;
- persistent transient failures stop after exactly three attempts and delays of one and two seconds;
- every attempt reuses the literal trusted URL and exact timeout;
- partial bytes from a failed response are absent from the next attempt;
- every output path component is opened without following symlinks and remains bound to the pinned descriptor;
- output-path removal or inode replacement fails closed after descriptor-relative writes;
- generated-file symlinks and multiply linked files are rejected before mutation;
- a hard link introduced after the initial file check but before final validation fails closed after the synchronized write;
- a singly linked regular generated file can be safely refreshed on a rerun;
- a post-open generated-file path swap and a zero-progress descriptor write fail closed; and
- the no-proxy opener, redirect rejection, final-origin validation, repeated bounded reads, maximum size, checksum, archive member, executable version, Python compatibility, offline export, full SHA-256 grammar, 100% statement and branch coverage, and production docstrings remain unchanged.

A permanent documentation contract rejects broader legacy wording such as all `URLError` or `OSError` failures and generic `5xx` retries.

## MSA and operational boundary

This retry and output hardening belong to the organization-owned coverage control plane because every leaf repository consumes the same trusted bootstrap. Leaf repositories such as pg-llm-batch, NewsDOM, and naruon must not duplicate a downloader, pathname race workaround, or weakened review gate. If all three attempts fail or any output binding changes, the current-head review remains fail-closed and publishes bounded evidence; no approval or merge is synthesized.

## Rollback

Rollback of the transport slice removes the retry constants and loop while retaining every immutable-source, no-proxy, no-redirect, bounded-read, checksum, archive, executable-version, and offline-export control. Operators may also set the delay tuple to empty in a reviewed change to restore one attempt. Increasing attempts, delays, or the closed classifier requires a separate availability, security, and runner-budget review.

The output-binding remediation must not be rolled back to pathname prechecks. A safe rollback may stop materialization entirely or replace the implementation with an independently reviewed descriptor-relative or private-directory publication design that preserves no-follow opening, inode validation, regular-file validation, single-link validation before and after writes, and fail-closed behavior.

## References

Fielding, R. T., Nottingham, M., & Reschke, J. (2022). *HTTP semantics* (RFC 9110). RFC Editor. https://doi.org/10.17487/RFC9110

Nottingham, M., & Fielding, R. (2012). *Additional HTTP status codes* (RFC 6585). RFC Editor. https://doi.org/10.17487/RFC6585

Python Software Foundation. (2026). *os—Miscellaneous operating system interfaces*. Python 3.14 documentation. https://docs.python.org/3.14/library/os.html

Python Software Foundation. (2026). *urllib.error—Exception classes raised by urllib.request*. Python 3.14 documentation. https://docs.python.org/3.14/library/urllib.error.html

The Open Group. (2024). *open, openat—Open file relative to directory file descriptor*. In *The Open Group Base Specifications Issue 8, IEEE Std 1003.1-2024*. https://pubs.opengroup.org/onlinepubs/9799919799/functions/open.html

Thomson, M., Nottingham, M., & Tarreau, W. (2018). *Using early data in HTTP* (RFC 8470). RFC Editor. https://doi.org/10.17487/RFC8470
Loading
Loading