hraness

deploy proofs: verifying the published artifact is the reviewed source

binding the served page to the source commit

Drafted by an AI agent at Ben Guo's direct request from the Hraness source repositories, and checked against those sources before publication.

A page that deployed is not necessarily the page that was reviewed. Between the commit that passed CI and the bytes a crawler receives there are at least three places the identity can blur: the deployment the provider promoted, the alias that resolves, and the artifact the edge actually serves. A delivery proof is a small signed claim the deployment makes about itself (“I am deployment dpl_… of project prj_…, built from commit <sha>“) that an independent verifier can recompute from the provider’s own records and compare against what the served response carries. If the header a public request returns does not match the proof the provider says that deployment should carry, the deployment is not what it claims to be.

The public package @hraness/vercel-delivery implements this as a Next.js config wrapper. Wrapping a config with withProductionDeliveryProof causes every production response to carry an X-Hraness-Delivery-Proof header whose value is a deterministic token over the deployment identity, not a signature, but a commitment: the verifier recomputes the same token from Vercel’s own deployment, project, and Git records, and the two must be equal for the delivery to be proven. This page is carrying one right now; the header is on every route of the site, including this lesson, and you can see it with curl -sI https://hraness.com/ | grep -i x-hraness-delivery-proof.

what the proof binds

The token is not a signature over the response body; it is a commitment to the deployment’s identity. The identity has four parts, all of which are environment values Vercel injects at build time: the deployment ID (VERCEL_DEPLOYMENT_ID), the project ID (VERCEL_PROJECT_ID), the Git commit SHA (VERCEL_GIT_COMMIT_SHA), and the registered project name, which the caller supplies so the token is bound to the product, not only the provider’s own identifiers. The proof is v1. followed by a SHA-256 hex digest over a domain-separated concatenation of those four values:

SHA-256( "hraness-production-delivery-proof-v1" || \0 || deploymentId || \0 || projectId || \0 || projectName || \0 || sha )

The versioned \0-separated format matters: the domain separator prevents a digest computed for a different purpose from being replayed as a delivery proof, and the v1. prefix leaves room to change the construction without ambiguity.

fail-closed means exactly that

The wrapper has two modes, and the boundary between them is whether any Vercel identity is present. On a plain local run (VERCEL unset, no deployment, project, or SHA environment) resolveProductionDeliveryProof returns null and the config is passed through unchanged. The moment any of those fields is present, validation activates: a missing deployment ID, project ID, or SHA throws Vercel production delivery proof requires exposed deployment, project, and Git identity and the build fails. The design intent is that a misconfigured deployment cannot ship a half-bound proof; it either proves its full identity or it does not build.

That asymmetry (inert locally, strict on the provider) is deliberate. A local next build should not need provider credentials to succeed, but a deployment that received some of its identity and not the rest is exactly the case a proof exists to catch. Failing the build is the only honest answer, because a deployment that cannot prove itself is not one you want serving traffic.

the exact construction

The token construction, from src/index.ts, is deliberately small enough to audit in one reading:

export function productionDeliveryProofToken(
  identity: ProductionDeliveryProofIdentity,
): string {
  const checked = checkedIdentity(identity);
  const digest = createHash("sha256")
    .update("hraness-production-delivery-proof-v1\0")
    .update(checked.deploymentId)
    .update("\0")
    .update(checked.projectId)
    .update("\0")
    .update(checked.projectName)
    .update("\0")
    .update(checked.sha)
    .digest("hex");
  return `v1.${digest}`;
}

checkedIdentity validates each field before it enters the digest. The deployment ID must match ^dpl_[A-Za-z0-9]+$, the project ID ^prj_[A-Za-z0-9]+$, the project name must be lowercase kebab case, and the SHA must be a full 40- or 64-character lowercase Git object ID. These are not sanity checks; they are what keep a truncated, uppercase, or placeholder value from producing a well-formed-looking token that would pass a shape check but bind nothing.

The header is installed as a catch-all rule in the wrapped config’s headers():

{ key: "X-Hraness-Delivery-Proof", value: proof }

applied to /:path*. Existing headers are awaited and preserved (the wrapper appends its rule rather than replacing the config’s own) and it accepts both object and function NextConfig forms. On this site, next.config.ts applies it as the outermost wrapper, so the proof is added after every other config transform has run.

preview deployments get a different policy

A preview deployment is a proof-bearing deployment that is not production, and the wrapper treats it accordingly. When VERCEL_ENV === "preview", VERCEL_URL must be a bare generated *.vercel.app hostname (anything else throws) and the wrapper adds two things: X-Robots-Tag: noindex, nofollow, noarchive on the same catch-all rule, and a NEXT_PUBLIC_HRANESS_VERCEL_PREVIEW_ORIGIN env value the app can use to show a preview notice. A preview that failed to parse its own hostname fails the build rather than ship an indexable preview.

Two env values are wrapper-owned and reject direct assignment: NEXT_PUBLIC_HRANESS_VERCEL_PREVIEW_ORIGIN (which must come from the validated VERCEL_URL, not from hand-set config) and NEXT_PUBLIC_HRANESS_VERCEL_SURFACE_ORIGIN, which is reserved for a trusted wrapper and refuses nextConfig.env assignment entirely. The package’s own guide is explicit about why: the preview origin is UI evidence only; it must never authorize requests, routing, or data access. A preview is a place to look at the build, not an authority to trust.

the verifier side

The proof is only useful because the verifier is independent. The delivery pipeline’s --verify-delivery path does not ask the deployment what it is; it asks the provider. From the Vercel API it reads the deployment record, the project record, and the commit SHA, recomputes productionDeliveryProofToken over that identity, and then probes the public domains directly (ordinary and pinned-deployment requests) expecting the X-Hraness-Delivery-Proof header on every response to equal the recomputed token. A response with more than one proof header, a missing header, or a mismatched token is a failure, not a warning.

That check sits inside a larger readiness ladder whose rungs are named in the repository: SOURCE ALL-CLEAR means the tested commit merged to main; PROVIDER ALL-CLEAR additionally requires Vercel to report that exact SHA READY on Production with fresh alias lookups binding every registered production alias to it; PUBLIC ALL-CLEAR adds direct TCP, TLS, and HTTP probes across independent resolvers. The delivery proof is what binds the last rung to the first: it is how a public probe can prove the bytes it received came from the deployment the provider promoted for the commit that was reviewed.

The package’s own verification is worth noting because it is the same posture applied to the package itself. Its README pins installation to an immutable tag (github:hraness/vercel-delivery#v0.1.2) and bun run check rebuilds the committed distribution, runs behavior tests, packs the package, imports both exports under genuine Node, and typechecks a consumer next.config.ts through a real production build. The proof mechanism is checked by the same kind of evidence it produces.

what the proof does not prove

A delivery proof is a claim about deployment identity, not about content. It says “the deployment that served this response is the one Vercel built from this commit for this project”; it does not say the bytes are unchanged since build, because it does not need to: the proof’s job is to bind the identity the verifier can cross-check against the provider’s records, not to sign the body. A tampered response would carry a mismatched or absent proof, and that mismatch is what the verifier reads as failure.

It also does not make a preview into a production. A preview deployment carries the same proof construction but is marked noindex, nofollow, noarchive and carries the preview-origin notice exactly so that a *.vercel.app deployment can never be mistaken for the canonical surface. The preview origin is environment evidence for the UI to display; it is not a trust signal, and the package’s rules say so.

And it does not replace the rest of the readiness ladder. PROVIDER ALL-CLEAR still requires Vercel’s own report that the SHA is READY on Production with aliases bound to it; PUBLIC ALL-CLEAR still requires the direct probe matrix. The proof is the piece that binds those probes to the reviewed source. The rungs still have to be climbed. What it removes is the gap where a passing provider status and a passing public response could be two different deployments and nobody would know.

The interesting thing about the whole construction is how small it is. One header, one digest, four validated fields, two wrapper-owned env vars, and a verifier that recomputes rather than trusts. That is the shape of a delivery proof that is worth having: cheap enough to put on every response, specific enough that a mismatch is a finding rather than noise.

sources

  • vercel-delivery: src/index.ts for the token construction, identity validation, preview policy, and withProductionDeliveryProof wrapper; README.md for the pinned install and check commands.
  • The monorepo behind this site (projects): scripts/vercel-production-delivery.ts for the independent verifier and the ALL-CLEAR ladder in AGENTS.md.
  • Vercel system environment variables: the VERCEL_DEPLOYMENT_ID, VERCEL_PROJECT_ID, VERCEL_GIT_COMMIT_SHA, and VERCEL_URL fields the proof reads.

keep reading: free for subscribers

the rest of this lesson is free. add your email once and every subscriber lesson on this site stays unlocked.

already subscribed? enter the same email to unlock.