Skip to content

ci: guard PRs against boot-script byte drift and deploy-dep breakage#7562

Draft
santicomp2014 wants to merge 1 commit into
mainfrom
ci/prod-build-boot-hash-guard
Draft

ci: guard PRs against boot-script byte drift and deploy-dep breakage#7562
santicomp2014 wants to merge 1 commit into
mainfrom
ci/prod-build-boot-hash-guard

Conversation

@santicomp2014

Copy link
Copy Markdown
Contributor

Why

The 2026-07-01 incident (#7557 → hotfix #7560, rollback #7561) had two failure modes that were invisible to PR CI, because the production build and the deploy script's dependency chain run for the first time post-merge in the Release workflow:

  1. CSP break: a build-tooling transitive (serialize-javascript v6→v7, pulled in via resolutions) changed the boot script's bytes, so the CSP script-src sha256 gating the client's inline bootstrap no longer matched → browsers blocked the client in prod (~37 min partial outage).
  2. Deploy break: a fast-xml-parser: 5.7.0 pin made @aws-sdk's S3 response parsing reject the 
 entity S3 returns → every deploy blocked.

Several currently-open Dependabot PRs (#7546 rollup/terser majors, #7544 babel group) touch the same toolchain and are green for the same vacuous reason. This PR is the guard that makes them safely mergeable.

What this adds

A prod-build-guard job in PR CI that:

  • builds the production bundles (yarn build) for both the PR and its base branch;
  • fails if the boot script's code bytes drift (build/boot-template.js / build/boot.js). Asset cache-buster fingerprints (?abc123) are normalized away first, so routine asset changes don't trip it — only drift in the boot code (the incident class) fails. Intentional changes are acknowledged with the boot-bytes-approved label, which downgrades the failure to a warning;
  • smoke-checks the deploy-time dependency chain on every PR: scripts/check-deploy-deps.js (constructs the S3 client and regression-tests the XML parser against an S3-style 
 response — the exact 2026-07-01 deploy bug) plus deploy-to-s3.js --help to exercise the deploy script's full import chain.

A determinism fix the guard surfaced: generateManifest (from @hypothesis/frontend-build) fills the manifest object in file-read-completion order, which varies run to run, and the boot bundle inlines that JSON — so two builds of identical source produced different boot bytes. The gulpfile now rewrites build/manifest.json with sorted keys before the boot bundle is built. (Proper long-term fix belongs upstream in frontend-build; follow-up worth opening there.)

Verification (local)

  • Before the manifest sort: two consecutive yarn build runs produced different boot-template.js hashes (manifest key order raced). After: identical hashes across rebuilds.
  • node scripts/check-deploy-deps.js passes; node scripts/deploy-to-s3.js --help exits 0.
  • prettier / eslint / tsc clean on the changed files.

Notes for review

🤖 Generated with Claude Code

Two failure classes from the 2026-07-01 incident (#7557 -> #7560/#7561)
were invisible to PR CI because the production build and the deploy
script's dependency chain only run post-merge in the Release workflow:

- a build-tooling transitive (serialize-javascript v6->v7) changed the
  boot script's bytes, invalidating the CSP script-src sha256 where the
  client is embedded inline -> browsers blocked the client in prod;
- a fast-xml-parser pin broke @aws-sdk's parsing of S3 responses,
  blocking every deploy.

This adds a `prod-build-guard` PR job that:

1. builds the production bundles for the PR and its base branch and
   fails if the boot script's code bytes drift (asset cache-buster
   fingerprints are normalized away; the `boot-bytes-approved` label
   acknowledges intentional changes);
2. smoke-checks the deploy-time dependency chain on every PR
   (deploy-to-s3.js import chain + the AWS SDK XML parser accepting
   the `
` entity S3 returns).

It also makes the boot build deterministic: generateManifest fills the
manifest in file-read-completion order, which varies per run, and the
boot bundle inlines that JSON -- the manifest is now rewritten with
sorted keys so identical inputs produce identical boot bytes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@santicomp2014 santicomp2014 added the boot-bytes-approved Intentional boot-script byte change: prod-build-guard drift becomes a warning; refresh CSP hash. label Jul 2, 2026
@codecov

codecov Bot commented Jul 2, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.62%. Comparing base (9d28950) to head (4f24637).

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #7562   +/-   ##
=======================================
  Coverage   99.62%   99.62%           
=======================================
  Files         285      285           
  Lines       11971    11971           
  Branches     2920     2920           
=======================================
  Hits        11926    11926           
  Misses         45       45           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

boot-bytes-approved Intentional boot-script byte change: prod-build-guard drift becomes a warning; refresh CSP hash.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant