Bazel External Fetch Authority
GloriousFlywheel currently proves shared Bazel remote-cache acceleration for action outputs. That is not the same thing as external repository/archive fetch authority.
Bazel can need external archives during repository resolution and analysis
before a target can benefit from action-cache hits. If those downloads hit
upstream release hosts directly, a transient upstream 502 can fail a
cache-backed proof before the build reaches the shared remote cache.
Current Truth
The source repo has retry mitigation:
.bazelrcsets--experimental_repository_downloader_retries=5.bazelrcsets--http_timeout_scaling=2.0scripts/bazel-cache-backed.shpasses--remote_cacheexplicitly after the strict cache contract check
That means ordinary wrapper use is upstream-with-retries for external
repository archives unless an operator also configures a repository cache or
distdir. Source Bazel Proof now stages the Linux x64 Node 22.13.1 toolchain
archive plus the critical Bzlmod archives that recently blocked GF proof/TTFCH
analysis into an ephemeral verified distdir before Bazel starts, so those
repository fetch paths are no longer raw upstream fetches during Bazel
analysis. A checked coverage contract accounts for that required set and the
remaining generated Node/hermetic launcher candidates that remain deliberately
deferred. This is still not durable mirror authority.
Supported Wrapper Inputs
The repo-managed Bazel wrapper honors these optional inputs:
BAZEL_REPOSITORY_CACHE: passed as--repository_cache=<value>BAZEL_DISTDIR: colon-separated paths passed as repeated--distdir=<value>
These settings are intentionally separate from BAZEL_REMOTE_CACHE.
BAZEL_REMOTE_CACHE covers action outputs. BAZEL_REPOSITORY_CACHE and
BAZEL_DISTDIR cover external repository/archive fetches.
The copied consumer wrapper in examples/bazel/gloriousflywheel-bazel.sh
honors the same repository-cache and distdir inputs. It also accepts
GF_BAZEL_INJECT_REPOSITORIES, a colon-separated list of
repo=/absolute/path entries passed as repeated
--inject_repository=<repo=/absolute/path> flags. That path is for generated
local Bazel repositories whose contents are already materialized, verified, and
present on the runner before Bazel starts.
For public pinned source inputs such as WAS-110 community archives, the intended flow is:
- mirror the public archives into an approved durable artifact store
- materialize the generated vendor repository offline from that mirror
- verify the generated repository and manifest
- inject it into the consuming workspace with
GF_BAZEL_INJECT_REPOSITORIES=was110_vendor_blobs=/absolute/vendor/repo
This keeps mutable upstream URLs out of the build-time path without claiming that GloriousFlywheel owns the consumer repo’s pin files or release policy.
The current honey Attic stack declares was110-public-inputs as the dedicated
RustFS bucket for that public WAS-110 mirror. Keep it separate from attic,
bazel-cache, and tofu-state: those buckets are cache/state authority
surfaces, not pinned-source mirror publication paths.
The live bucket contains these root objects:
| object | size | sha256 |
|---|---|---|
WAS-110_8311_firmware_mod_2.4.0_bfw.7z |
16637511 | b0b03bc28c540239beffb3a9e64f653c4a403d2e7e97a291b2ed785a05079031 |
WAS-110_8311_firmware_mod_v2.8.3_basic.7z |
10435192 | 5d72e7552e396127b59a548c6163113d088d545708aecb0fed38097b862288f8 |
public-source-lock.json |
4058 | source lock copied from 8311-was-110-firmware-builder/pins/public-source-lock.json |
SHA256SUMS |
213 | sidecar for the two archive objects |
The 2026-05-06 proof downloaded the two archive objects from
was110-public-inputs through a bounded direct RustFS pod port-forward,
validated SHA256SUMS, materialized a temporary WAS-110 vendor repository with
pins/fetch-public-inputs.sh --offline --archive-dir <downloaded-mirror>, and
then passed pins/verify-vendor-repo.sh against that generated repo.
Audit Command
Run:
just bazel-external-fetch-authority
Strict mode fails until a repository cache or distdir authority is configured:
just bazel-external-fetch-authority --strict
When a proof needs to show pre-Bazel staging rather than only an environment variable, require a materialization manifest:
just bazel-external-fetch-authority --strict --require-distdir-manifest
The Source Bazel Proof workflow runs the strict audit with
--require-distdir-manifest after validating the materialization manifest
against docs/contracts/bazel-distdir-source-proof-coverage.json.
The offline fixture proof is:
just bazel-external-fetch-authority-self-test
It verifies the status classifier for missing .bazelrc, upstream retry
mitigation, .bazelrc repository-cache/distdir authority, wrapper environment
inputs, strict-mode failure without fetch authority, and the exact
scripts/bazel-cache-backed.sh CLI flags for BAZEL_REPOSITORY_CACHE plus a
colon-separated BAZEL_DISTDIR.
The lockfile input inventory is:
just bazel-external-input-manifest
It parses MODULE.bazel.lock and reports Bzlmod registry files, generated
repository archive inputs, and generated toolchain template URLs. The current
repo manifest is intentionally not an offline-authority claim: the BCR registry
files and http_archive inputs are hash-recorded in the lockfile, but the
generated Node.js toolchain repositories expose version/template URLs without a
lockfile hash in MODULE.bazel.lock. That means the source-repo proof still
needs a repository-cache, distdir, or approved mirror policy before we call
external input resolution durable.
The repo-owned candidate integrity contract is
docs/contracts/bazel-external-input-mirror-candidates.json. It records the
eight generated Node.js 22.13.1 toolchain archives selected by rules_nodejs,
including concrete archive filenames and sha256 values cross-checked against
Node’s upstream SHASUMS256.txt. The manifest guard reports those as
candidate hashes, not lockfile hashes. This is a useful source-integrity step
toward a distdir or approved mirror, but the contract is explicitly
candidate-integrity-only: all entries have materialized: false, so it is
not proof that a durable mirror, distdir, or repository cache is populated.
The repo-owned distdir materializer is:
just bazel-external-input-distdir --output /tmp/gf-bazel-distdir --name nodejs_linux_amd64:22.13.1:linux_amd64
It downloads the selected candidate archive, verifies the recorded sha256,
writes SHA256SUMS, and writes bazel-distdir-manifest.json into the output
directory. Source Bazel Proof uses this for the Linux x64 Node toolchain and
critical Bzlmod archive paths before Bazel starts, validates the runtime
materialization manifest with:
just bazel-distdir-coverage \
--materialization-manifest /tmp/gf-bazel-distdir/bazel-distdir-manifest.json \
--exact-materialization
It then exports BAZEL_DISTDIR and runs
just bazel-external-fetch-authority --strict --require-distdir-manifest
through the workflow command path. That proves pre-Bazel local distdir staging
for the source proof’s selected Node archive. It still does not prove durable
mirror retention or broad external-input authority for every generated platform
archive.
The coverage contract is
docs/contracts/bazel-distdir-source-proof-coverage.json. It must classify
every Node candidate from
docs/contracts/bazel-external-input-mirror-candidates.json as either
required_inputs or deferred_inputs, and its authority class remains
source-proof-ephemeral-only. The contract check is:
just bazel-distdir-coverage-contract-check
The provider-neutral mirror package and restore primitives are:
just bazel-distdir-mirror-package \
--distdir-manifest /tmp/gf-bazel-distdir/bazel-distdir-manifest.json \
--mirror-root /tmp/gf-distdir-mirror
just bazel-distdir-mirror-verify \
--mirror-root /tmp/gf-distdir-mirror \
--required-input nodejs_linux_amd64:22.13.1:linux_amd64
just bazel-distdir-mirror-restore \
--mirror-root /tmp/gf-distdir-mirror \
--output /tmp/gf-restored-distdir \
--required-input nodejs_linux_amd64:22.13.1:linux_amd64
restore reconstructs a local Bazel --distdir directory from the verified
mirror package and writes a normal bazel-distdir-manifest.json, so the same
coverage validator can prove the restored bytes satisfy the current source
proof input set. This is still a local restore mechanics proof, not live
durable storage authority, not consumer exposure, and not broad/default RBE.
It writes MANIFEST.json, distdir/<sha256> object files,
distdir-meta/<sha256>.json provenance sidecars, and
bazel-distdir/<filename> aliases that can become a local BAZEL_DISTDIR after
sync/restore. This validates the package shape and bytes. It still does not
prove the package has been synced to durable storage, restored by CI, or exposed
to consumers through a read-only credential.
The non-secret live authority package gate is:
just bazel-external-input-authority-package-gate --package <package.json>
That package must name a dedicated external-input mirror endpoint, bucket,
mirror_prefix, network audience, scoped GF_EXTERNAL_INPUT_MIRROR_*
credential injection, mirror layout, restore proof, read-only consumer exposure
policy, retention, maintenance/failure-domain behavior, quota policy,
observability, and authority separation. The gate rejects Civo, RustFS, current
Attic/cache/state buckets, protected prefixes, inline secrets, and template
placeholders. It also requires the durable authority contract to remain
no-live-durable-authority until the live proof updates covered_inputs.
The endpoint field is carried by GF_EXTERNAL_INPUT_MIRROR_ENDPOINT; region
and credentials use the matching GF_EXTERNAL_INPUT_MIRROR_REGION,
GF_EXTERNAL_INPUT_MIRROR_ACCESS_KEY_ID, and
GF_EXTERNAL_INPUT_MIRROR_SECRET_ACCESS_KEY names.
After a package exists and the scoped credentials are installed, the live proof harness is:
just bazel-distdir-mirror-live-readiness \
--package <package.json>
just bazel-distdir-mirror-live-proof \
--package <package.json> \
--mirror-root <verified-mirror-root> \
--all-candidates
The readiness guard fails closed before the expensive proof if the non-secret
package is missing, has not reached posture=proof_ready, or the scoped
GF_EXTERNAL_INPUT_MIRROR_* environment is absent or mismatched. It writes
redacted bazel-distdir-mirror-live-readiness-evidence.json so operators can
separate missing authority setup from runner or Bazel failures. The proof
harness then uploads the verified package under mirror_prefix, downloads it
back to a fresh mirror root, verifies the package again, restores a local
BAZEL_DISTDIR, and writes
bazel-distdir-mirror-live-proof-evidence.json. The manual
Bazel Distdir Mirror Live Proof workflow first reruns the full package proof
on tinyland-nix-heavy, runs readiness, then runs this harness. It does not
run on pull requests and does not depend on GitHub artifact upload quota.
Generate the intentionally non-live template with:
just bazel-external-input-authority-package-template /tmp/external-input-authority-package.json
The package, restore, and authority-package fixture proofs are:
just bazel-distdir-mirror-package-contract-check
just bazel-distdir-mirror-restore-contract-check
just bazel-external-input-authority-package-contract-check
just bazel-distdir-mirror-live-proof-contract-check
The durable authority gate is
docs/contracts/bazel-external-input-durable-authority.json. It is currently
no-live-durable-authority: the source-proof Linux x64 archive plus critical
Bzlmod archives are listed as ephemeral source-proof inputs, all 23 candidate
inputs remain pending for durable coverage, and covered_inputs is
intentionally empty. The validator requires any future durable claim to provide
auth, retention, restore, provenance, and consumer exposure evidence instead of
treating the source-proof distdir as a product mirror.
Run:
just bazel-external-input-authority-contract-check
This is the promotion gate for a repository cache, durable distdir, or approved
mirror. It is not satisfied by BAZEL_REMOTE_CACHE, RustFS cache/state buckets,
future RBE CAS/action-cache, or private local-only generated repositories.
The consumer wrapper proof is:
just consumer-bazel-wrapper-contract-check
It verifies the copied wrapper passes --remote_cache, read-only upload mode,
repository-cache, distdir, and injected-repository flags, and rejects relative
or missing injected repository paths.
Boundary
This is not Bazel remote execution. It also does not make an upstream archive mirror public or durable by itself. A future managed authority still needs an explicit policy for repository-cache location, distdir population, retention, and consumer exposure.
Public pinned blobs may be staged into an approved mirror or future approved CAS path when their provenance and retention policy are recorded. Private or license-restricted blobs remain private/local-only and must not be promoted into public cache, public mirror, or shared CAS surfaces by this wrapper.