Define the build contract
A production build needs to answer four questions: which revision entered, which dependencies were used, which checks ran, and which artifact emerged. In a fictional positions API, the release branch advanced between two identically named runs. The team can compare results only after recording the resolved revision and each execution identifier. For supported Git sources, CODEBUILD_RESOLVED_SOURCE_VERSION identifies the commit after DOWNLOAD_SOURCE; do not assume the variable exists for every source type. Add build configuration, relevant inputs, and artifact reference to the record. A build number identifies one execution but does not demonstrate that two runs produced identical content.
Treat cache as recoverable acceleration
The build must remain correct when cache is empty. Local cache belongs to its host and is unsupported for VPC-connected projects; changing Docker privileges does not remove that limitation. Avoid naming custom-cache directories after versioned source directories because links to restored content can override source material. With S3 caching, a lockfile-derived key helps separate incompatible dependencies; sharing also requires checking namespace, paths, bucket, and prefix. Run an uncached exercise and compare expected outcomes. If a version builds only with leftovers from a previous run, an input is undeclared or the process depends improperly on state. Record the discrepancy before accepting the result.
Design a path to each dependency
Before moving CodeBuild into a VPC, inventory DNS, registries, Git origins, AWS services, and integration targets. Reaching private RDS does not prove egress to a public registry. A direct internet-gateway route does not assign a public address to build ENIs. Define authorized egress through NAT or a proxy, or provide an appropriate internal source. Private endpoints reach their respective services; a CodeBuild endpoint is not a general GitHub proxy. Diagnose by layer: resolution, route, filtering, TLS, authentication, and authorization. EC2 UnauthorizedOperation during network preparation calls for reviewing service-role VPC permissions rather than changing tests that have not executed.
Bound package access
For CodeArtifact, separate token retrieval, read authorization, and client configuration. The principal needs appropriate issuance permissions, including STS; placing sts:GetServiceBearerToken only in the domain resource policy does not solve that part. Across accounts, confirm domain-owner instead of relying on a name that may exist in several accounts. If the requirement is to end the token with the assumed session, use the duration option representing remaining time rather than trusting the default. Avoid keeping tokens in shared caches, logs, or artifacts. Troubleshooting should preserve identifiers and context without exposing the authentication secret. Test access with the identity the build actually uses.
Accept demonstrated coverage
A required suite should not be configured as an ignorable batch failure. Compare the required check set with completed candidate-revision outcomes. INCOMPLETE, a missing report, and SKIPPED tests do not demonstrate successful execution. Distinguish functional failure from collection failure; both may block promotion but require different actions. For later review, export raw results and manage retention because the CodeBuild report expires. Define who may read, change, and delete evidence. At production handover, ask whether the agreed criteria were demonstrated rather than whether at least one dashboard appears green. Keep the association between evidence, build identity, and the exact candidate under review.
Exercise: locate missing evidence
The local model below takes a candidate revision, an inventory of required suites, and synthetic results. It returns reasons to hold acceptance when a suite is missing, a revision differs, or an outcome has not completed successfully. It does not query CodeBuild, parse XML, or replace an operational gate. In the exercise, change authorization to SKIPPED, remove reconciliation, and change the contract-suite revision. Explain the missing evidence in each case and which team should produce it. Finally connect the decision to the release window: deferring may be correct when entry conditions cannot be met. Any authorized exception needs separate, explicit treatment.
# Original local coverage exercise; not a CodeBuild integration.
def missing_evidence(revision, required, results):
reasons = []
for suite in sorted(required):
row = results.get(suite)
if row is None:
reasons.append((suite, "missing"))
elif row["revision"]!= revision:
reasons.append((suite, "wrong revision"))
elif row["status"]!= "SUCCEEDED":
reasons.append((suite, "not successful"))
return reasons
required = {"contracts", "reconciliation", "authorization"}
good = {s: {"revision": "candidate-42", "status": "SUCCEEDED"} for s in required}
assert missing_evidence("candidate-42", required, good) == []
assert missing_evidence("candidate-42", required, {}) == [(s, "missing") for s in sorted(required)]
bad = {**good, "authorization": {"revision": "candidate-42", "status": "SKIPPED"}}
assert missing_evidence("candidate-42", required, bad) == [("authorization", "not successful")]
old = {**good, "contracts": {"revision": "candidate-41", "status": "SUCCEEDED"}}
assert missing_evidence("candidate-42", required, old) == [("contracts", "wrong revision")]
A green batch hides failed reconciliation and missing authorization results; the gate compares all three required suites with the candidate revision.
Common pitfalls
Treat cache as source; confuse endpoint and proxy; accept INCOMPLETE; retain only a report URL; ignore a mandatory child.
Related topics: Release validation and progressive exposure
Promotion needs complete candidate-revision evidence and a build that works without accidental state.
Reference: CodeBuild environment variables · DOP-C02