diff --git a/RELEASE.md b/RELEASE.md index 506e494..e8a0305 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -104,7 +104,9 @@ A real publish is the same sequence, run deliberately by hand: the fix: export `VERCEL_AUTOMATION_BYPASS_SECRET` with the value from the project's Protection Bypass for Automation setting and rerun. The secret travels only as a request header; never commit it or print it. The public - aliases in step 9 are not protected and need no secret. + aliases in step 9 are not protected and need no secret. The check also asks + Vercel to skip the preview toolbar injection, so a preview's root document + hashes the same as its rewritten routes. 9. **Read back both live aliases.** With the Vercel CLI authenticated, run: diff --git a/scripts/check-live-parity.test.ts b/scripts/check-live-parity.test.ts index 6ac5cf1..bee2d89 100644 --- a/scripts/check-live-parity.test.ts +++ b/scripts/check-live-parity.test.ts @@ -122,6 +122,9 @@ describe("live parity contract", () => { expect(seen[0]).not.toHaveProperty("x-vercel-protection-bypass"); expect(seen[1]["x-vercel-protection-bypass"]).toBe("secret-value"); expect(seen[1]["user-agent"]).toBe("operator-os-explainer-live-parity/1"); + for (const headers of seen) { + expect(headers["x-vercel-skip-toolbar"]).toBe("1"); + } }); it("names the bypass variable when a deployment redirects to Vercel SSO", async () => { diff --git a/scripts/check-live-parity.ts b/scripts/check-live-parity.ts index 789919f..a19628e 100644 --- a/scripts/check-live-parity.ts +++ b/scripts/check-live-parity.ts @@ -230,6 +230,10 @@ export async function fetchBytes( redirect: "manual", headers: { "user-agent": "operator-os-explainer-live-parity/1", + // Preview deployments append the Vercel Toolbar script after + // on the root document only, which breaks the one-shell comparison. + // Vercel skips the injection when this header is present. + "x-vercel-skip-toolbar": "1", ...protectionBypassHeaders(environment), }, });