6.7.4 From Build to Release Candidate
recommendedA successful Bazel invocation produces outputs. It does not, by itself, produce a release candidate. A release candidate exists only when an immutable set of outputs is joined to complete evidence that says exactly what source, build scope, and builder produced it. That distinction lets later systems approve, sign, or publish one stable subject without asking the build to perform those side effects.
Define a technical eligibility contract
Treat release candidacy as a predicate over a record, not as a directory copied from
bazel-bin. A useful record identifies at least:
- an immutable source revision;
- the Bazel version and the configuration and platform scope;
- the intended build and test work;
- the builder or invocation identities that performed that work;
- every candidate output by cryptographic digest;
- the build, test, event-delivery, and artifact-availability evidence required by the release workflow.
The digest is the identity of an output. A filename such as server.tar, a release
number, or an image tag is a convenient lookup name, but it can be reassigned. The
handoff must therefore say, in effect, “these bytes under these digests,” even when
the user-facing workflow also attaches names. Provenance systems use the same shape:
the artifact is represented as a subject with a checksum, while source, materials,
and builder information describe how that subject came to exist.1
The predicate should return more than a Boolean. Three states are a practical minimum:
| State | Meaning |
|---|---|
eligible | The immutable subject and all required evidence are present, mutually consistent, and reachable. |
ineligible | Complete evidence proves that required build or test work failed. |
unknown | Required work, events, identity, or artifacts are missing, conflicting, stale, or unreachable. |
unknown must block promotion just as ineligible does, but the distinction preserves
the correct diagnosis. A failed test is evidence of a bad candidate. A missing test
result is failure to establish whether a candidate exists at all.
Assemble with Bazel; promote outside the action graph
Keep artifact assembly inside Bazel actions with declared inputs, tools, and outputs. That declaration gives Bazel the graph needed to schedule work and form action cache keys; it is not proof that the action actually uses only that boundary. Enforce an execution policy that isolates undeclared host files and network services, and qualify the action's deterministic behavior with appropriate negative and repeatability tests. Only after those properties are established may the release contract treat reuse of an assembled result as safe.2
Make that qualification part of eligibility evidence. A demonstrated isolation or
determinism violation makes the candidate ineligible; missing or unreachable evidence
leaves it unknown. Merely seeing declared inputs and outputs in the action graph cannot
promote either case to eligible.
Publication has the opposite shape. It changes an external mutable system, normally
requires credentials, and may not be safe to repeat. Therefore a rule may build a
release archive, image layout, manifest, or bundle, but an explicit workflow step
should publish the already identified output. The rules_oci project demonstrates
this boundary concretely: image construction is separated from runnable load and
push operations, and pushing is an explicit side effect rather than an ordinary
cached build action.3 The same design applies beyond OCI images.
This separation answers an important retry question. Rebuilding a candidate may
re-execute or cache-hit assembly actions, but it must not create a release, overwrite
a tag, or upload bytes merely because bazel build ran again. Publication belongs to
6.7.10 Publishing Artifacts Reliably, after approval and any required signing. Keep
publisher credentials there as well; placing them in an action's environment,
arguments, or inputs risks exposing them through execution requests, logs, caches, or
build evidence. 6.7.5 Build Identities and Secrets develops that credential boundary.
Reconcile the build before declaring a candidate
6.5.8 Complete CI Results with BEP/BES provides the evidence handoff. Start with its immutable
intended-work ledger and require every expected partition, invocation, configuration,
test shard, run, and attempt to be accounted for. Then require the BEP event graph to
be complete enough for the release contract. Among the announcements the collector
actually received, an unresolved child identifier exposes a protocol hole after a
crash or partial delivery. It cannot expose an announcement or entire invocation that
never reached the collector, so the intended-work ledger and required terminal record
remain necessary. A successful BuildFinished still describes one command and does
not prove that every distributed CI partition ran.4
Event completeness is still not output availability. BEP can refer to output files
through NamedSetOfFiles; a consumer must traverse those references, and a remote
BES server may be unable to read files that exist only on the Bazel machine.4
For each required release output, establish separately that:
- the expected output is named by the completed build evidence;
- its digest agrees with the candidate manifest;
- an authorized downstream consumer can retrieve the bytes;
- retention lasts through approval, signing, and publication.
Do not substitute “the dashboard is green” for this reconciliation. A dashboard may
have a successful terminal event while one partition never started, or it may show an
artifact link whose bytes have expired. The candidate record should retain these as
specific unknown reasons rather than flattening them into a generic release failure.
Keep lifecycle states independent
A reliable pipeline records transitions rather than treating “release” as one large job:
built -> evidence complete -> technically eligible
-> policy approved -> signed -> published
Each arrow has different authority and failure semantics. Bazel establishes outputs and build evidence. The eligibility service reconciles them. 6.7.9 Bazel Policy and Compliance Checks can contribute technical policy evidence, but approval policy remains a separate decision. 6.7.6 Build Provenance and Attestations binds claims about source, materials, invocation, and builder to the immutable subject. 6.7.8 Signing and Verifying Artifacts binds a signing identity to that subject. Publication finally changes the destination.
Preserve the last successful state when a later transition fails. If signing is unavailable, the candidate remains technically eligible but unsigned; it did not become a build failure. If publication rejects credentials, the signed candidate remains unpublished; it did not become published merely because every Bazel target succeeded. This model makes retries narrow and prevents one subsystem from asserting a state owned by another.
Classify: All required builds and tests completed, and the candidate manifest names an archive by digest. The BEP references that archive, but the artifact store returns “not found.” Is the candidate eligible, ineligible, or unknown?
Reveal
It is unknown. The available evidence does not prove a build or test failure, so
ineligible would be misleading. But the immutable subject is not reachable, so the
technical handoff is incomplete and cannot be promoted. Restore or reproduce the
artifact under the expected digest, then evaluate the same contract again.
Test the boundary with negative cases
Build one known candidate in a clean environment and capture its subject manifest and complete-result record. Then mutate one dimension at a time:
- omit one required CI partition or test attempt;
- attach evidence from a different source revision or configuration;
- remove one referenced artifact from storage;
- replace an output while retaining its mutable filename or tag;
- deny access to the artifact for the eligibility consumer;
- fail signing or publication after eligibility succeeds;
- rerun the Bazel build after the candidate has been recorded.
The first five cases must not produce eligible. The signing and publication failures
must not rewrite the build result or falsely advance the lifecycle. The final rebuild
must have no publication side effect. These tests prove both halves of the design: the
predicate fails closed when the subject or evidence is incomplete, and the build stays
safe to repeat because release authority remains outside cacheable actions.
The runnable release eligibility contract turns that test plan into a small, read-only verifier. Its contract states the expected subject, work, source, builder, configuration, and technical-policy evidence. The negative cases then vary completeness, failure, identity, digest, reachability, authorization, and downstream state one dimension at a time. This is deliberately a release-contract model—not a simulation of BES, an artifact backend, signing, or publication.
A release candidate is not whatever happens to be under bazel-bin after a green
command. It is an immutable set of digest-identified outputs joined to complete,
consistent, and reachable evidence for a stated source, builder, configuration, and
work scope. Failed work makes the candidate ineligible; missing or conflicting
evidence leaves eligibility unknown.
Use Bazel actions for hermetic, cacheable assembly. Keep approval, signing credentials, and publication side effects in explicit later stages that consume the immutable handoff. Then a rebuild can safely reproduce or reuse outputs without publishing them, and a failure after the build cannot masquerade as either a build failure or a successful release.
Check your understanding · 4 questions
1.Which evidence is still required when every received BEP announcement has a corresponding event?
Select all that apply
2.Match each evidence outcome to its release-candidate state:
Drag each answer onto the matching prompt, or click an answer and then click a prompt
3.Which cases must block technical eligibility even though the output keeps the expected filename?
Select all that apply
4.Classify the boundary between Bazel assembly and later release stages:
Choose True or False for each sentence
Footnotes
-
SLSA Artifact Security with Bazel — artifact subject digests and the separation of source, materials, and builder claims ↩
-
Artifact-Based Build Systems — declared actions, hermetic inputs, and safe output reuse ↩
-
rules_oci — daemonless OCI image rules for Bazel — separation of image construction from explicit runnable load and push operations ↩
-
Build Event Protocol — event-graph completeness,
BuildFinished, BES transport, and referenced-file availability ↩1 ↩2