Secure Software Delivery for Federal Environments Module 5 · Across the Boundary

The Transfer

Last reviewed

Advanced

What you'll learn

~20 min
  • Run the git-bundle transfer lifecycle: high-water marks, verification, strict ordering, fast-forward-only
  • Operate the blob-ZIP variant through a cross-domain gate with its control-point checklist
  • Harden a transfer pipeline by finding the gaps - hash checks and ingest scanning included

The boundary rule, called in

Lesson 3.2 ended with a promise: the moment an artifact crosses a trust boundary, the receiver shares none of your platform’s guarantees, and integrity must travel with the artifact — independently verifiable, structurally enforced. This lesson is that rule operating at the hardest boundary there is: a guarded gate between classification domains, where the sender cannot log in to explain, the receiver cannot reach back to ask, and a black-box inspection system sits in the middle. The reference material provides two production variants. Learn both — the second is what larger programs run, and the pair teaches more than either alone.

Variant A: the git-bundle lifecycle

For moving repositories across the gap, the reference lifecycle uses git’s native offline transport — bundles — wrapped in ceremony that is the actual lesson:

SEND (low side): RECEIVE (high side):
1. read HIGH-WATER-MARK tag 1. poll landing zone, sort by
(last-sent commit per repo) build-id - STRICT ORDER, no
2. bundle ONLY commits since skipping ahead
the mark 2. verify EACH bundle: git bundle
3. git bundle verify locally verify + re-computed hash vs
manifest, before it touches
a repo
4. write JSON manifest: repo, 3. apply: already-applied -> no-op
ranges, build-id, hashes (idempotent); clean descendant
5. per-repo prefix in the -> FAST-FORWARD; anything else
landing zone -> DIVERGENCE protocol
6. advance the mark ONLY on
confirmed receipt

The load-bearing rule is the last receive state: fast-forward-only, and divergence is never merged. If the high-side repo has commits the low side doesn’t know about — someone patched in the enclave — the transfer does not reconcile. It opens a PR whose only permitted resolution is abandonment: the high-side divergence is exported as a change request, applied on the low side through normal review, and flows back through the gate in the next transfer. One direction of truth, structurally enforced. And never forget what that export IS: a high-to-low movement of information across a classification boundary. Even a change description leaves the enclave only through an authorized release path — classification review, sanitization, an approved transfer mechanism — and where no such path exists, cleared staff re-create the change on the low side from memory and intent, not from exported artifacts. The abandon-only rule protects the repo’s one-way flow; the release review protects the other one-way flow, and it comes first. Notice what this design does not rely on: trusted couriers or anyone’s good intentions. Be precise about what each check buys, because they are not interchangeable: git bundle verify proves well-formedness and prerequisite fit — never origin — so the manifest’s content hashes, re-computed at receive, are what tie each bundle to its manifest (skip that re-computation and Variant A quietly inherits the same ingest gap called out in Variant B below). Be honest about the residual, as the lesson is for Variant B: an unsigned manifest that rode the same channel proves bundle-matches-manifest, not manifest-came-from-sender — sender origin rests on the gate’s own channel controls plus, where you can arrange it, an independently protected expected digest on the high side. Integrity comes from that hash verification plus strict ordering plus the fast-forward constraint — approval is structural: the system is arranged so the unauthorized state cannot be reached through any permitted operation. That’s the boundary rule’s deepest form.

Variant B: the blob-ZIP pipeline through a CDS

For programs moving releases (not repo history) at scale, the second production variant automates the pattern through a cross-domain solution:

merge to main (low side)
-> pipeline ZIPs the release (minus .git) + JSON manifest -> container
-> CDS product moves it low->high (black box - not yours)
-> manifest-triggered function on the high side: validates manifest,
extracts, computes per-file delta (blob-hash add/edit/delete),
syncs into a BRANCH of the high-side repo
-> human opens/reviews the PR -> merge IS the release

Same skeleton as Variant A — one-way flow, manifest-driven, verification before application, a human structural gate at the end — implemented event-driven. The reference deployment’s control-point checklist is the transferable artifact; run any transfer pipeline you meet against it: trigger gate (main branch only — no feature-branch ride-alongs), .git stripped (history is Variant A’s cargo, never B’s), manifest validation with a dead-letter path (malformed does not mean discarded silently), container-to-repo allowlist (a package cannot route itself somewhere new), Zip-Slip path sanitization on extract, size caps, path exclusions, idempotency guards (same package twice is a no-op, not a double-apply), human PR as the final gate.

And now the honest part, straight from the reference system’s own operators: the deployed pipeline has gaps. Two worth naming because they’re the hardening exercise: the manifest carries hashes, but nothing re-computes the ZIP’s hash against the manifest at ingest (the integrity chain has an unverified hop across the one segment nobody controls — the CDS itself is trusted implicitly); and no anti-virus/content scan runs at the ingest point (trust is delegated wholly to the CDS’s inspection plus the human reviewer). The program knows, and runs mature/naive sibling copies of this pipeline as its own before/after teaching pair. Your exercise below closes both.

Prompt first: the hardening pass

Here is our transfer pipeline (function code + pipeline YAML attached).
1) run the control-point checklist against it - table: control point,
present/absent, where enforced (code line or config key);
2) close the ingest-verification gap: add ZIP-hash-vs-manifest
verification BEFORE extraction, failing to the dead-letter path
with the mismatch logged - show the diff;
3) close the scan gap: insert a content-scan step post-download,
pre-extraction; quarantine path on findings; note what scanning
can and cannot establish here (Lesson 3.2 honesty - name the
residual trust in the CDS);
4) idempotency proof: demonstrate that replaying the last three
manifests produces zero repo changes - as a TEST the pipeline
runs on itself.
💬Why abandon-only feels wrong and is right

Every engineer’s instinct at the divergence PR is to merge it - the fix is RIGHT THERE, it works, the enclave needs it. The instinct is how one-way flow dies: merge once and the high side becomes a second source of truth, the next transfer conflicts, and every future package requires archaeology to apply. Abandon-only is not process for its own sake - it is the price of the property that makes everything else work: the low side is always, provably, the whole story. Pay it every time, including the time it is genuinely painful.

KNOWLEDGE CHECK

During an urgent fix window, a high-side operator hand-patches a config file and commits it in the enclave repo. The next transfer arrives; the receive tooling detects non-fast-forward and opens the divergence PR. The team lead argues: 'merge it this once - the patch is correct, abandoning it loses a working fix.' What does the protocol require, and what actually happens to the fix?

Key takeaway

Across the gate, integrity is structural: bundles verified at both ends, manifests as the contract, strict ordering, idempotent application, fast-forward-only with abandon-only divergence — one direction of truth no good intention can bend. The automated variant adds the control-point checklist and, in its reference deployment, two honest gaps (ingest hash verification, ingest scanning) that your hardening pass closes. Signatures where receivers can check them, structure everywhere else — Lesson 3.2’s rule, fully spent. Next: deployment on a side you’ll never see.

Search lessons