Cache Exposure And Package Canaries
This page defines the current enterprise/package onboarding contract for Bazel cache use. It is deliberately narrower than Bazel remote execution.
Supported Exposure Model
Current supported Bazel cache exposure is:
- self-hosted CI runners receive
BAZEL_REMOTE_CACHEthrough the runner bootstrap environment - internal developer machines attach through a product-owned consumer profile
that carries an operator-provided real endpoint, then
just cache-contract-strictmust pass - pull requests use read-only remote-cache behavior
- trusted default-branch pushes may upload action results when the repo owner explicitly opts in
Current unsupported exposure:
- no stable public Bazel cache hostname is promised
- no arbitrary internet consumer cache endpoint is promised
- no default Bazel remote execution or consumer-facing
--remote_executorpath is selected
This is enough for enterprise package canaries that run on enrolled capability-class lanes. It is not enough to advertise public Bazel cache service access. The explicit GF REAPI proof lane is separate from this cache exposure model.
Developer-Machine Policy
Policy decision: product-owned profile, operator-owned endpoint authority.
The current supported developer-machine Bazel path is a consumer profile
rendered by GloriousFlywheel tooling from a real endpoint supplied by an
operator. Use just flywheel-consumer-env shared-cache-backed --cache-endpoint "$BAZEL_REMOTE_CACHE" --write .env.flywheel.local to materialize a
non-secret local profile after endpoint authority is available, then source
that profile or load it through direnv before running the strict contract.
The current proven local route is still a bounded Honey svc/bazel-cache
port-forward. That route is only a proof lane: it must use the
port-forward-cache profile or set GF_BAZEL_LOCAL_PROOF=port-forward.
A future tailnet-routable endpoint or authenticated public hostname must be
tracked as a separate infrastructure and auth decision before it is advertised
as default product behavior.
Developer-machine attachment rules:
just inforeportscompatibility-local-onlyuntilBAZEL_REMOTE_CACHEis explicitly setjust cache-contract-strictmust pass before cache-backed local Bazel work counts as substrate-attached- localhost Bazel endpoints fail unless
GF_BAZEL_LOCAL_PROOF=port-forward just developer-cache-attachment-proof //:deployment_bundle falseis the bounded proof command- read-only remote-cache behavior is the safe baseline
- cache writes require an explicit trusted-operator opt-in
The guard for this policy is:
just bazel-cache-exposure-policy-check
Package Canary Workflow
Use the public example:
examples/github/package-cache-canary.yml
Required properties:
runs-onuses a shared capability class such asyour-org-nix- the workflow fails early when
BAZEL_REMOTE_CACHEis absent - the workflow verifies
GF_BAZEL_SUBSTRATE_MODE=shared-cache-backed - the workflow prints only attachment state, not private endpoint values
- pull requests leave
GF_BAZEL_REMOTE_UPLOAD=false - trusted default-branch pushes may set
GF_BAZEL_REMOTE_UPLOAD=true
The copied consumer wrapper is:
examples/bazel/gloriousflywheel-bazel.sh
It passes --remote_cache="$BAZEL_REMOTE_CACHE" explicitly and defaults to
--remote_upload_local_results=false unless GF_BAZEL_REMOTE_UPLOAD is true.
That makes package pull requests safe to run against a shared cache without
turning untrusted PRs into cache writers.
The same wrapper can pass external input authority into consumer repositories:
BAZEL_REPOSITORY_CACHE becomes --repository_cache, BAZEL_DISTDIR becomes
repeated --distdir, GF_BAZEL_REPOSITORY_DISABLE_DOWNLOAD=true becomes
--repository_disable_download, and GF_BAZEL_INJECT_REPOSITORIES becomes
repeated --inject_repository for verified local generated repositories.
Use GF_BAZEL_REPOSITORY_DISABLE_DOWNLOAD=true only in an explicit
repository-cache/distdir proof lane after the expected inputs are already
pre-populated. It is a completeness check for the external-input authority
path, not a default developer setting.
Nix Cache Boundary
ATTIC_PUBLIC_KEY is public trust material for Nix substituter attachment.
ATTIC_TOKEN is credential material for private reads or trusted writes.
Package canaries should pass ATTIC_PUBLIC_KEY when available. They should
only pass ATTIC_TOKEN when private reads or explicitly trusted writes are
required. Pull requests should remain read-only. Default-branch publication must be token-gated,
and broad repo proof workflow writes remain behind the RustFS/backend
publication guardrail rather than becoming ordinary canary behavior.
External Repository Fetches
Bazel remote cache covers action outputs. It does not make external repository archives cache-authoritative.
Run:
just bazel-external-fetch-authority
Current source-truth may still be upstream-with-retries unless an operator
provides BAZEL_REPOSITORY_CACHE or BAZEL_DISTDIR. Treat that as separate
from remote action-cache attachment and separate from remote execution.
The repeatable offline guard is:
just bazel-external-fetch-authority-self-test
Use non-strict authority reporting for ordinary package canaries until a repository-cache or distdir authority is configured. Use strict mode only when the canary is meant to prove external archive fetch authority in addition to remote action-cache attachment.
For pinned public source inputs, such as a generated WAS-110 public-community vendor repository, materialize and verify the local repository before invoking Bazel, then pass it with an absolute-path entry such as:
GF_BAZEL_INJECT_REPOSITORIES=was110_vendor_blobs=/absolute/vendor/repo
This is a consumer wiring contract. It does not publish the mirror, bless a mutable upstream URL, or make private blobs eligible for public cache/CAS. The explicit RBE proof wrapper accepts the same handoff when a canary is meant to prove both input authority and remote action execution.
Promotion Criteria
Count a package canary as attached when:
- the workflow runs on an enrolled self-hosted capability lane
BAZEL_REMOTE_CACHEis presentGF_BAZEL_SUBSTRATE_MODEisshared-cache-backed- the Bazel wrapper builds or tests a small package target
- logs show cache attachment and upload mode without printing the endpoint
Do not count it as RBE. The current capability is shared cache acceleration with local Bazel execution on the runner.