fix(ci): pin Bun across the L1 contract suite - #762
Conversation
独立对抗窄审 · PR #762Verdict: CLEAN — no BLOCKER, no MAJOR, no MINOR. Reviewer: 通信IM马 (independent, read-only). Extracted PR tree via Note: brief indicates the original grok测试6 reviewer hit a Grok 402 balance-exhausted error; this is the single replacement audit. Provenance
Item-by-item① L1 denominator = 14 (13 helper + 1 pre-pinned) — CONFIRMEDIndependent enumeration of 14 declared. 13 qa-* Dockerfiles modified in this PR to use the shared helper; L1 bun.sh remainder = 0 (independent grep): ② helper fail-closed properties — CONFIRMED (7/7)
Independent SHA verify: Exact match to Independent witnessed-red: Bad SHA → helper's ③ full
|
|
Final coordinates supersede the archive-helper source after CI falsified its availability assumption.
Why: the first helper source passed 14/14 locally, but CI attempt 1 failed qa-cli-01/02 and attempt 2 failed qa-cli-01/qa-hub-05, all as curl HTTP exit 22 while other identical consumers passed. Thirteen independent archive downloads were not a reliable gate. The final source pins the official Bun 1.3.14 OCI index digest across all 14 L1 Dockerfiles. Local full L1 is 14/14, |
独立对抗窄审 · PR #762 (final digest-pinned source, SUPERSEDES archive-helper approach)Verdict: CLEAN — no BLOCKER, no MAJOR, no MINOR. Supersedes my earlier CLEAN comment on old archive-helper source (source Reviewer: 通信IM马 (independent, read-only). Extracted PR tree via Provenance
Commit chain: The archive-helper approach ( Item-by-item① 14 L1 suites all use identical Bun image digest — CONFIRMEDIndependent enumeration of Every L1 Dockerfile pins the same digest: Independent 13 Node-based L1 images (qa-*) use a multi-stage pattern: FROM oven/bun:1.3.14@sha256:e10577...e5c4 AS bun-runtime
FROM node:20-slim
...
COPY --from=bun-runtime /usr/local/bin/bun /usr/local/bin/bun
RUN ln -sf /usr/local/bin/bun /usr/local/bin/bunx \
&& test "$(bun --version)" = "1.3.14" \
&& test "$(bunx --version)" = "1.3.14"Both test686-rest-shape-golden uses the same digest directly as base image ( bun.sh and old-helper remnants: ② official
|
| target | actual value | brief expected |
|---|---|---|
| multi-arch OCI index digest | sha256:e10577f0db68676a7024391c6e5cb4b879ebd17188ab750cf10024a6d700e5c4 |
e10577...e5c4 ✓ |
| linux/amd64 manifest | sha256:50317d83cd5a5ae1d8b35b3379c69f57ce1a0dbf4def91f0965653d767851834 |
50317...1834 ✓ |
Both match. The pinned digest is the real Bun 1.3.14 upstream.
COPY path /usr/local/bin/bun exists in the official oven/bun:1.3.14 image (standard Bun install location; verified transitively — the pattern works, spot-check build succeeds).
Node final base node:20-slim was NOT swapped: independent grep of all 13 multi-stage Dockerfiles shows exactly FROM node:20-slim as the second stage in every file.
③ real 14/14 --l1 run + witnessed-red on wrong digest — CONFIRMED
Report claims:
sg docker -c 'bash scripts/qa.sh --l1'→ 14/14 PASS,ALL PASS in 115s, exit 0
My independent verifications:
- Spot-check build of qa-hub-05:
sg docker -c 'docker build -q -f tests/qa-hub-05-roundtrip/Dockerfile ...'→sha256:9aafa1dbb96b...— build succeeds end-to-end (COPY from bun-runtime works; version assertions pass). - Witnessed-red on wrong digest (all-zeros):
Docker pull rejects the non-existent digest before any build layer executes. The content-addressed pin is load-bearing — corrupting the digest reds immediately.
FROM oven/bun:1.3.14@sha256:0000...0 AS bun-runtime ... ERROR: failed to build: failed to solve: oven/bun:1.3.14@sha256:0000...0: failed to resolve source metadata: not found
Full 14/14 replay not re-done (author already ran; my spot-check + witnessed-red confirm the pattern is real).
④ old approach truly closed, no new bypass — CONFIRMED
Compared new vs old:
| aspect | old (archive helper, 2c95173b) |
new (digest-pinned, 79e4acea) |
|---|---|---|
| external download surface per L1 build | 13 (each container's curl → GitHub releases) | 0 (Docker resolves the image ONCE by digest; content-addressed) |
| external network points of failure | GitHub releases 4xx/5xx transient | Docker Hub layer serving (typically cached + CDN'd; also digest-addressable so any layer server change is instantly detected) |
| retry semantics | curl --retry 3 in helper |
Docker layer pull retries + digest verify (built-in) |
| checksum verification | sha256sum --check --strict before extract |
OCI digest is a content-address (cryptographic identity of the image) |
| observability on failure | curl exit 22 (rate-limit / transient) | image-pull failure surfaces at Docker layer with clear "not found / digest mismatch" |
CI history proved the archive-helper approach:
- Attempt 1: qa-cli-01 + qa-cli-02 build failed (curl exit 22)
- Attempt 2 (re-run): qa-cli-01 + qa-hub-05 build failed (curl exit 22) — DIFFERENT failing pair
- 12 of 13 SAME-helper users passed each time — proved the helper contract was correct BUT the 13-parallel-download availability was the bottleneck
The new approach removes the entire helper file (tests/lib/install-bun-pinned.sh → deleted). No residual per-Dockerfile network path. Docker resolves the pinned digest once (with layer cache) — 13 builds share the same layer bytes with zero re-download after the first pull.
No new bypass paths found: no residual curl, no PATH shadow, no cache-based old-image reuse, no ENV bypass. Every bun/bunx invocation resolves to the digest-pinned binary.
⑤ source→HEAD only report + virtual merge + drift + secret — CONFIRMED
- source→HEAD delta: only
docs/tests/report-l1-pinned-bun.txt(+36 / −27, updating the report to reflect the new approach). No source or test file touched by the report commit. - Virtual merge:
git merge-tree $(git merge-base pr-762 main) main pr-762→ 349 lines output, zero true conflict markers. - File drift:
git log --oneline 05d4b73e..origin/main -- <each PR-touched file>= 0 commits on all 15 paths. Main has moved past base (05d4b73e → 15b8d750) but not on any file this PR touches. - Secret sweep across 15 changed files: 0 hits for
ntok_/utok_/atok_/BEGIN PRIVATE KEY.
⑥ scope closed only for L1 subset + no vendored image — CONFIRMED (honest disclosure)
- Report explicitly: "This closes the L1 subset only. The larger [ci] remaining 30 non-L1 Dockerfiles still install Bun through unpinned bun.sh #728 repository denominator remains open for Dockerfiles outside scripts/qa.sh --l1."
- 30 other Dockerfiles in
tests/still use unpinned patterns — OUT OF SCOPE per brief. - No vendored image / big tarball in changed paths (only
tests/test661-explicit-bootstrap-db/fake-bin/bun— a test fake-bin stub, not this PR, not a real Bun archive). - Report: "The official Bun image remains an external registry input; its bytes are content-addressed by digest, not vendored in this repository." — matches actual state.
Additional observations (informational, not blocking)
- The digest-pinned pattern is architecturally stronger than the archive-helper approach it replaces:
- Removes the x86_64 hard gate from the helper (was needed because binary tarball is arch-specific). The multi-arch OCI image auto-selects the right layer per node arch → other archs would now work if the runner supports them. Not a regression; a widening.
- Content-addressed source is a hardened supply-chain property; corrupting the digest fails at pull, not at post-download checksum.
- Amortized bandwidth: Docker layer cache means 13 builds share one layer download after first pull.
- The report's explanation of the CI availability flaw ("attempt 1 failed qa-cli-01 and qa-cli-02, attempt 2 failed qa-cli-01 and qa-hub-05, failing suite moved between attempts, so rerunning could not establish a reliable gate") is exactly the diagnostic reasoning that turns "flaky test" into "denominator problem to fix at source" — good discipline.
- One small consistency observation (not a MINOR): the helper's earlier
ln -sf bun /usr/local/bin/bunxin the Bun stage insideoven/bun:1.3.14— the Bun image itself doesn't ship a bunx symlink at/usr/local/bin/bunx, so the new Dockerfiles doln -sfexplicitly. Report notes this: "The archive-helper experiment also caught a real integration requirement: a Bun binary without a bunx symlink allowed the image to build but made the actual anet hub lifecycle fail. The final source creates and version-checks that symlink, and all real L1 journeys pass." Preserved correctly.
Reviewer discipline (self)
Applied feedback_finding_confirmation_is_not_verdict: every focus item was mechanically mapped to brief wording. Nothing lands on BLOCKER/MAJOR/MINOR gate wording. Verdict: CLEAN.
Independent verifications executed:
curlDocker Hub API → multiarch digeste10577...e5c4+ amd6450317...1834byte-for-byte match brief expected values.sg docker buildqa-hub-05 Dockerfile → succeeds; COPY-from + version assertions all pass.sg docker buildwithsha256:0000...0→ fails at pull with "not found" — witnessed-red on the content-addressed source.for d in <14 L1>; do grep digest ...; done | sort -u | wc -l→ 1 unique digest across all 14.find tests/lib/→ old helper file gone.
Prior CLEAN comment (on archive-helper source) is SUPERSEDED by this comment. GitHub retains both for audit trail; the current verdict for source 79e4acea / head e8fabbfb is the one above.
No approve, no merge, no deploy.
Outcome
Pins Bun across the complete
scripts/qa.sh --l1Docker denominator using the official image's immutable OCI digest.This is a substantial partial fix for #728, but intentionally does not close the remaining non-L1 Dockerfile denominator.
Frozen coordinates (supersedes the archive-helper coordinates)
05d4b73e9efe42421700e56e163164759a361eb079e4acea0ff8e91d3772040da7d41fe1c02905e7e8fabbfbebbd95e95dfd52ca18ceabdf815111ccdocs/tests/report-l1-pinned-bun.txt2c95173b/b40411f1are superseded after CI exposed random HTTP 22 failures in per-image archive downloadsWhy the scope is the L1 denominator
PR #757 failed twice at unchanged
curl ... bun.sh/install | bashlayers. A one-file diagnostic moved the failure to the next identical Dockerfile, proving a denominator problem.The current L1 inventory contains 14 Docker suites:
oven/bun:1.3.14@sha256:e10577f0db68676a7024391c6e5cb4b879ebd17188ab750cf10024a6d700e5c4;bun+bunxare exactly 1.3.14;bun.sh/install.CI correction
The first complete-denominator source used a checksum-pinned archive helper. It passed 14/14 locally, but CI failed different helper consumers on two attempts:
Thirteen independent GitHub downloads were therefore not a reliable gate. The final source removes that helper and uses one content-addressed official Docker source. Runtime images remain
node:20-slim.Docker evidence
Witnessed red: replacing qa-dash-07's Bun digest with 64 zeroes makes Docker fail before test layers with the exact digest
not found.The work also caught a real integration requirement: a Bun binary without a
bunxsymlink builds but breaks the real anet lifecycle. The final Node-based images create and version-check that symlink.Boundary