Chapter 22

Source Code and Build Architecture

Scope. This chapter owns everything that happens to code before a build runs: where the repository lives and how Google Cloud connects to it, the branching and review model, commit signing, and the four pre-build scanning classes. Cloud Build is Chapter 23, Artifact Registry is Chapter 24, deployment is Chapter 25, and attestation authoring and the SLSA framework are Chapter 37. Prerequisites. Chapter 3 (§3.9 roles), Chapter 4 (§4.13 Workload Identity Federation), Chapter 13 (§13.14 eliminating secrets from Git), Chapter 15 (Sensitive Data Protection). Verified against. Google Cloud console and API surface as of 2026-09, Cloud SDK 583.0.0, hashicorp/google provider 8.x; see sources at end.

The supply chain starts here, and so does most supply chain compromise. An attacker who can merge a commit does not need to break your build, your registry, or your deployment gate — every one of those will faithfully build, store, and ship what the repository says. The controls in Chapters 23 through 25 all inherit their trustworthiness from whether the source they consume is trustworthy, and nothing downstream can recover it.

That gives this chapter one organizing question: what does it take for a change to reach the default branch? In a well-run estate the answer is a chain of independent facts — the author is an authenticated member of a named group, the commit is signed, at least one other person reviewed it, the branch protection prevented a direct push, and four scanners found nothing. In a badly run one it is "someone had write access", and that is a single credential away from a compromise nobody will detect until the artifact is running.

Google Cloud's part in this is smaller than the problem, which is worth saying plainly. The repository is usually not in Google Cloud. Most estates host on GitHub or GitLab, and the platform's contribution is a connection, a set of scanning services, and a build system that trusts what it clones. This chapter covers Google's own hosting where it is the right choice, the connection mechanisms in every case, and the scanning that Google does supply — while being explicit about the two categories where it supplies nothing and your SCM vendor does.

22.1 Git-Based Development §

Every delivery pipeline in this book starts with a Git repository and a connection from Google Cloud to it. Three hosting options exist and the historical default is closed.

Cloud Source Repositories is no longer an option for new estates. Google's statement is unambiguous: "Effective June 17, 2024, Cloud Source Repositories isn't available to new customers." Existing repositories continue to function; nothing new should be built on it.

OptionWhat it isChoose it when
Secure Source Manager"a regionally deployed, single tenant, managed source code repository hosted on Google Cloud"Source must stay in your Google Cloud tenancy and region
GitHub / GitLab / Bitbucket, connectedExternal hosting with a Google Cloud connectionThe default — the team already lives there
Cloud Source RepositoriesLegacyNever, for anything new

Secure Source Manager is a real, current, regional service. Repositories "support all Git SCM client commands and have built-in pull requests and issue tracking", instances are created with gcloud source-manager instances create and take --kms-key for CMEK, --is-private for a Private Service Connect deployment, and --enable-workforce-identity-federation for workforce identity.

gcloud source-manager instances create ssm-rc-saas \
  --region=us-central1 \
  --project=rc-saas-shared-cicd-01 \
  --kms-key=projects/rc-saas-shared-sec-01/locations/us-central1/keyRings/\
kr-us-central1-cicd/cryptoKeys/k-ssm-source

gcloud source-manager repos create billing \
  --instance=ssm-rc-saas \
  --region=us-central1 \
  --project=rc-saas-shared-cicd-01 \
  --description="Billing service source and its Terraform."

Judgment. Choose Secure Source Manager when residency, single tenancy, or perimeter membership (Chapter 20) is a requirement you must satisfy. Choose external hosting otherwise — the review tooling, the ecosystem, and the developers' habits are all there, and fighting that costs more than it returns.

Pitfall. Whichever you choose, the repository's own access control is now a tier-zero security boundary equal to your Google Cloud IAM. An organization that carefully denies basic roles in GCP and hands out repository admin freely has moved the problem, not solved it.

22.2 Repository Structure §

Repository layout is a security decision because it determines what a single write grant can change.

The dimension that matters is not monorepo versus polyrepo — it is whether application code and infrastructure code share a review population. Terraform that can grant IAM roles (Chapter 26) is more dangerous than application code, and it should not be mergeable by whoever can fix a CSS bug.

Three layouts, with their consequences:

LayoutBlast radius of one write grantWorks when
Monorepo, one review policyEverythingSmall team, uniform trust
Monorepo, path-scoped review rulesScoped by directoryMost estates — the recommended default
Separate infrastructure repositoryInfrastructure isolated by repository IAMInfrastructure is managed by a distinct team

Path-scoped review is the mechanism. A code-owners file that requires the platform team's approval for anything under infra/ gives you a separate trust boundary without a separate repository, and it is enforced by the same branch protection as everything else (§22.6).

Keep the Terraform for a project alongside the project's code, and the Terraform for the organization — folders, org policies, perimeters — in its own repository with its own reviewers. The bootstrap state that can modify the organization is the highest-value target in the estate (§2.21).

Pitfall. A code-owners rule protects paths that exist. A new top-level directory matches no rule and is reviewable by anyone, which is how an attacker adds deploy/ next to a protected infra/. Include a catch-all rule as the last line.

22.3 Trunk-Based Development §

Trunk-based development means every change lands on one long-lived branch quickly, behind feature flags rather than behind long-lived branches.

Its security argument is unfashionable but real: short-lived branches make review effective. A two-day branch produces a diff a reviewer can actually read. A three-week branch produces a diff nobody reads, and unread review is a control that reports success while doing nothing.

Three properties follow from short-lived branches:

  • Scanning is current. Secret and dependency scanners run against something close to what will ship, rather than against a snapshot from a month ago.
  • The deployed artifact matches the reviewed source. With long branches, the merge itself introduces code no reviewer saw.
  • Rollback is meaningful. Reverting one small commit is a real option; reverting a three-week merge is a project.

Feature flags carry a cost you must budget for. A flag is a runtime authorization decision, and a flag that gates a security-relevant behavior — a new authorization path, a permission check — needs the same review as the code behind it, plus a removal date. Estates accumulate flags that nobody dares delete, and each one is a code path that is never exercised in the reviewed configuration.

Judgment. Trunk-based development with mandatory review and a one-day merge expectation is this book's default. It is not the only workable model, but it is the one where the review control actually functions.

Pitfall. Trunk-based development with no review is not trunk-based development; it is direct commit with extra vocabulary. The model depends on branch protection (§22.6) being enforced, not on convention.

22.4 Feature Branching §

A feature branch is a short-lived branch created for one change and deleted at merge. Its security properties come entirely from what happens between creation and merge.

Branch naming is an access-control input, not decoration. Protection rules and CI triggers match on patterns, so a convention of feat/, fix/, and release/ prefixes lets you apply different rules to each — for instance, requiring two approvals on release/ and one elsewhere.

Forks change the trust model completely. A pull request from a fork is code from outside your organization, and a CI system that runs it with production credentials has just executed an attacker's code with your permissions. This is the single most exploited weakness in open CI configurations.

The rule for fork-originated builds: they run with no credentials, in an isolated pool, against no protected resource, and their results gate nothing. Cloud Build's approval requirement (§23.2) is what enforces the "a human looked at this before it ran" step.

Delete branches at merge, automatically. A repository with four hundred stale branches has four hundred snapshots of unpatched dependencies, and any of them can be built by a trigger whose pattern was written loosely.

Pitfall. Long-lived release branches accumulate divergent security fixes. A patch applied to main and forgotten on release/2.4 ships a known vulnerability to the customers most likely to be on a long support contract. If release branches exist, patching them must be part of the same change, not a follow-up ticket.

22.5 Pull Requests §

A pull request is the unit of review and the enforcement point for everything in this chapter. It is where the automated checks report and where a human decides.

Six things should gate a merge, and each should be an independently failing check:

  1. Secret scanning found nothing new (§22.9).
  2. Static analysis found no new high-severity issue (§22.10).
  3. Dependency scanning found no new known-vulnerable direct dependency (§22.11).
  4. Infrastructure code scanning passed policy (§22.12).
  5. Tests passed.
  6. A human with the right ownership approved.

Merge queues matter more than they look. Two pull requests that each pass on their own can fail together, and in a security context "fail together" can mean a policy check that passed against a stale base. Requiring branches to be current before merge closes that gap.

Automate what a reviewer should not have to notice. A human is good at judging whether a change is a good idea and bad at spotting a base64-encoded credential in a 900-line diff. Every check above exists because a reviewer will miss it.

Judgment. One approval is the working minimum, from someone who did not write the change. Two approvals for infrastructure and for anything touching authentication or authorization. Beyond that, additional required approvals mostly buy latency.

Pitfall. Approvals that persist across new commits are an approval of code nobody read. Secure Source Manager can "Block merging a pull request if new commits are added after approvals are granted", and the equivalent setting exists in every major host. Turn it on; without it, "approve then push" is a documented bypass.

22.6 Protected Branches §

Branch protection is what converts the review model from a convention into a control. Everything in §22.3 through §22.5 is advisory until the platform refuses a direct push.

Secure Source Manager's protection controls, in Google's own words:

  • "Require pull requests before merging into protected branches"
  • "Set the required number of reviewers and approvers before a pull request can be merged"
  • "Block merging a pull request if new commits are added after approvals are granted"

The minimum protection set for a default branch:

RulePrevents
No direct pushThe whole review model being optional
Required pull request with N approvalsAn author approving their own change
Dismiss approvals on new commitsApprove-then-push
Required status checks, all of §22.5Merging past a failed scanner
No force push, no deletionRewriting history to hide a commit
Rules apply to administratorsThe bypass everyone forgets

"Include administrators" is the setting that decides whether this is a control. Protection that a repository administrator can bypass protects against mistakes, not against a compromised administrator account — and the compromised administrator account is the threat model.

Break-glass must exist and must be loud. There will be an incident where a fix has to land without review. Provide a documented path — a second, audited approval group, or a temporary rule suspension that alerts (§18.15) — rather than leaving people to discover the administrator bypass under pressure.

Pitfall. Branch protection defends the default branch. A build trigger that fires on any branch, or a deployment pipeline pointed at a tag, routes around it entirely. Protect tags too, and make sure the deploy pipeline's source is a protected reference (§25.14).

22.7 Code Review §

Code review is the only control in this chapter that evaluates intent. Everything else matches patterns.

Reviewers should be asked for three judgments, and a checklist that asks for more gets none of them:

  • Is this change what it claims to be? A commit titled "fix typo" that adds a network call is the signature of a supply chain attack and of a rushed developer, and both need catching.
  • Does it change who can do what? New IAM bindings, new authorization paths, new external calls, new dependencies.
  • Would a failure here be recoverable? Data migrations, deletions, and credential changes deserve a second reader.

Code owners scale review without scaling reviewers. A rule that routes infra/ to the platform team and auth/ to whoever owns identity means the right person sees the dangerous change without every person seeing every change.

Review the dependency change with the same weight as the code change. A one-line lockfile bump introduces someone else's code into your build with no diff to read. §22.11 covers the scanning; the review question is whether the dependency was intended at all.

Judgment. Measure review by whether reviewers ask questions, not by approval counts. A team whose approvals arrive within ninety seconds is not reviewing, and no configuration will fix that.

Pitfall. Automated dependency-update pull requests train reviewers to approve without reading, because ninety-nine of them are fine. Route bot pull requests to a separate check that verifies the update is from the expected source and only escalates to a human on a major version or a new transitive dependency.

22.8 Commit Signing §

A signed commit binds the commit's content to a key its author controls, so that authorship survives an attacker with repository write access.

Git supports signing with GPG, S/MIME, and SSH keys, and hosts can require and display verification status. The security property is narrow and worth stating exactly: a signature proves the commit was created by someone holding that key, not that the change is good and not that the account was not compromised.

Where it actually helps:

  • After an incident, distinguishing commits made by a stolen session from commits made with a key that never left a hardware token.
  • Against history rewriting, because a rewritten commit loses its signature.
  • For release tags, where a signed tag is the anchor a build can verify against.

Enforcement is a branch protection rule, not a hope. Requiring signed commits on the default branch is the only version of this control that does anything; optional signing produces a repository where the important commits are the unsigned ones.

Key management is the whole cost. Developer keys must be enrolled, rotated, revoked on offboarding, and ideally held in hardware. An estate that cannot run that process will end up with shared keys, which is worse than no signing because it looks like a control.

Judgment. Require signing on repositories that build production artifacts, and require signed release tags everywhere. Skip it on internal tooling repositories where the key management cost exceeds the benefit — and say so in writing rather than leaving it inconsistent by accident.

Pitfall. Web-based edits and merge commits created by the host are signed by the host's key, not the author's. A policy of "every commit must be signed by a developer key" is broken by the merge button, and teams resolve it by disabling the rule rather than by using rebase merges.

22.9 Secret Scanning §

Secret scanning detects credentials committed to source. It is a detection control with a hard limitation: by the time it fires, the secret is in the history and must be treated as compromised.

Google Cloud's contribution is Sensitive Data Protection (Chapter 15), whose infoType detectors cover credentials, keys, and tokens and can be run over repository content or over an export of it. Secure Source Manager repositories expose a scan configuration that accepts Sensitive Data Protection templates.

Repository-native scanning is your SCM host's job. GitHub and GitLab both run secret scanning at push time with provider partnerships that revoke leaked cloud credentials automatically. If your source is hosted there, that is your primary control and Google's is the supplement.

The response is always the same three steps, in this order:

  1. Revoke the credential. Before anything else, and regardless of whether the commit reached the default branch.
  2. Rotate whatever it protected.
  3. Then decide about history. Rewriting history is optional and expensive; revocation is neither.

Prevention beats detection here, and §13.14 owns it: secrets come from Secret Manager at runtime, Terraform uses write-only arguments so they never enter state, and a pre-commit hook catches the obvious cases before they leave a laptop.

Pitfall. Scanning the default branch only misses the case that matters most — a secret committed to a feature branch, detected, and "fixed" by force-pushing over it. The object is still in the repository and still fetchable by anyone with read access until garbage collection, which the host controls and you do not.

22.10 Static Analysis §

Static analysis reads source code for defects without running it. Google Cloud does not provide a first-party static application security testing product, and this section says so rather than inventing one.

The practical composition is a build step. Your language's analyzer — the same tool the developers run locally — executes in a Cloud Build step (§23.12), fails the build on a new high-severity finding, and reports as a required check on the pull request (§22.5).

Three properties separate a useful gate from an ignored one:

PropertyWhy
Fails only on new findingsA baseline of 4,000 existing warnings makes the gate meaningless
Runs on the diff where possibleFull-repository analysis on every pull request is too slow to be a gate
Produces one artifact the reviewer can openA log the reviewer must scroll is not a finding

Where a finding lands matters. Emit results in a machine-readable format and either post them as pull request annotations through your SCM host, or convert them into Security Command Center findings via a custom source (§16.1) so that source-level issues sit next to infrastructure ones.

Judgment. Static analysis is the pre-build control with the worst signal-to-noise ratio and the highest configuration cost. Start with a single high-confidence rule set, enforced, and grow it — rather than the full rule set in advisory mode, which is where these tools go to be ignored.

Pitfall. Analyzers that require full dependency resolution to run will fail closed in a hermetic build (§23.7) and fail open in a permissive one. Decide which failure you want before you add the step, because the default is usually "the step errored and the build passed".

22.11 Dependency Scanning §

Dependency scanning identifies known vulnerabilities in the third-party code your build pulls in — which, for most applications, is the overwhelming majority of the shipped bytes.

Artifact Analysis is Google's service for this. It "Provides vulnerability scanning and metadata storage for containers on Google Cloud", and it scans container images, Go packages, and Java packages. Chapter 24 owns the registry-side behavior; the pre-build angle is that you can invoke the same scanner on demand:

gcloud artifacts docker images scan \
  us-central1-docker.pkg.dev/rc-saas-shared-art-01/dev-docker/billing:candidate \
  --location=us

Distinguish direct from transitive findings. A vulnerable direct dependency is yours to upgrade. A vulnerable transitive dependency may not be reachable from your code at all, and a gate that treats them identically produces a backlog nobody can clear. Gate on direct dependencies, report on transitive ones.

Assured Open Source Software is the upstream-side option. Google describes it as a service "that enables enterprise users of open source software to incorporate the same trusted OSS packages which Google uses into their own developer workflows" — packages Google has already built, scanned, and signed. Consumed through a remote repository (§24.1), it moves the problem from scanning to sourcing.

Pin everything and commit the lockfile. A build that resolves version ranges at build time produces a different artifact every run and makes every scan result a statement about a build nobody can reproduce. This is the same requirement that provenance (§23.13) depends on.

Pitfall. Scanning at build time and never again means your view of a running image is as old as its build. Artifact Analysis continues to evaluate stored images against new vulnerability data (§24.6), and that continuous view — not the build-time scan — is what tells you a running service became vulnerable last Tuesday.

22.12 Infrastructure Code Scanning §

Infrastructure code scanning evaluates a proposed infrastructure change against policy before it is applied. It is the highest-value pre-build check in this chapter, because infrastructure code changes the controls that everything else depends on.

Google's first-party mechanism validates a Terraform plan and is generally available. gcloud scc iac-validation-reports create takes "the parent of the IaC defined in the plan file" followed by "path of the terraform plan file in JSON format", returning a long-running operation whose report lists policy violations:

terraform plan -out=tfplan.binary
terraform show -json tfplan.binary > tfplan.json

gcloud scc iac-validation-reports create \
  organizations/123456789012/locations/global \
  --tf-plan-file=tfplan.json

This closes a real gap. Organization policy (§2.30) rejects a non-compliant resource at apply time, which surfaces as a failed pipeline and a confused engineer. Validating the plan reports the same violation on the pull request, before anyone has waited for an apply to fail.

terraform vet is the other Google tool and it is beta-only. It evaluates a plan against Cloud Foundation Toolkit policy library constraints, and it exists only as gcloud beta terraform vet — there is no GA form. Preview surfaces must not be a production dependency, so this book describes it in prose and gates on the generally available check above; if you adopt it, treat the beta labeling as a reason not to make it the only gate.

Compose three checks, not one: terraform fmt -check and terraform validate for syntax and shape, a policy check for organizational rules, and the SCC plan validation above for Google's own security posture rules. Each catches a different class and all three are fast enough to be required checks.

Pitfall. A plan is only as trustworthy as the state it was generated against. Validating a plan produced from a stale state, and then applying from a fresh one, validates a change that is not the change that runs. Generate the plan and apply the same plan artifact (§26.x), or the check describes something hypothetical.

Chapter Summary §

  • Cloud Source Repositories has not been available to new customers since 2024-06-17; new estates use Secure Source Manager or external hosting with a connection.
  • Secure Source Manager is a regional, single-tenant managed Git service with built-in pull requests, branch protection, CMEK, and a private deployment option.
  • The repository's own access control is a tier-zero boundary equal to Google Cloud IAM.
  • Separate the review population for infrastructure code from application code, by path-scoped ownership rules or by repository.
  • Short-lived branches are a security control because they make review effective; long branches produce diffs nobody reads.
  • Fork-originated builds must run with no credentials, in isolation, gating nothing.
  • Approvals that survive new commits approve code nobody read — dismiss them on push.
  • Branch protection that administrators can bypass protects against mistakes, not against a compromised administrator.
  • Protect tags as well as branches, or a tag-triggered deploy routes around the whole model.
  • Commit signing proves who held a key, not that a change is good; enforce it as a protection rule or it is decoration.
  • Google's first-party secret scanning contribution is Sensitive Data Protection; repository-native push scanning is your SCM host's.
  • On a leaked secret, revoke first, rotate second, and decide about history last.
  • No first-party Google SAST product could be confirmed; static analysis is a build step that fails on new findings only.
  • Artifact Analysis scans container images, Go packages, and Java packages; Assured Open Source Software moves the problem from scanning to sourcing.
  • Gate on direct dependency findings and report on transitive ones, or the backlog is uncleanable.
  • gcloud scc iac-validation-reports create validates a Terraform plan JSON against Security Command Center policy and is generally available; terraform vet is beta-only.
  • Validate and apply the same plan artifact, or the policy check described a change that never ran.

Security Checklist §

ControlWhy it mattersHow to verify (CLI + Console)
Default branch requires a pull request and blocks direct pushEvery other control here is advisory without itBranch protection settings; attempt a direct push
Protection rules include administratorsThe bypass is the threat modelProtection rule "include administrators" setting
Approvals dismissed when new commits are pushedApprove-then-push is a documented bypassTry pushing after approval; approval must clear
Tags protected and deploy sources are protected referencesA tag-triggered deploy routes around branch protectionTag protection rules; pipeline source configuration
Path-scoped ownership for infrastructure directories, with a catch-allA new top-level directory otherwise matches no ruleCode owners file; last line is a catch-all
Fork pull requests build without credentialsOtherwise a stranger's code runs with your permissionsTrigger configuration; --require-approval (§23.2)
Signed commits required where production artifacts are builtAuthorship survives repository account compromiseHost verification status on recent commits
Secret scanning covers all branches, not just the defaultForce-pushing over a secret does not remove the objectScanner configuration; §13.14 prevention controls
Dependency lockfiles committed and pinnedAn unpinned build makes every scan result unreproducibleLockfile present and enforced by the build
Terraform plan validated before applyOrganization policy otherwise fails at apply timegcloud scc iac-validation-reports list shows recent reports
terraform fmt -check and validate are required checksCheapest possible gate on the highest-risk codePipeline definition

Sources §