Repository navigation
fix: analytics only after consent; release anchors; CI hardening; tidy - #87
Merged
Bryan Fawcett (bryanfawcett) merged 5 commits intoOct 13, 2026
Merged
Conversation
Google's tag is no longer requested behind Consent Mode set to denied. Analytics.astro queues the denied defaults and holds the only loader, which runs on a stored yes from the current banner version or when the banner records one. Older versions, the legacy key and malformed records count as no answer, in the banner and the support widget alike. The privacy and cookie policies now say Google Analytics contacts Google only after you agree. Tests run the built script against each case; the consent probe fails on any Google Analytics request before consent. Closes #83 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CoDNYz27iJ7o8PPztCzTpq
The extension has tagged v0.9.6, v0.9.7 and v0.9.8 since the 0.10.0 entry was written, and their menus link to anchors the Releases page did not have. They join 0.9.1 to 0.9.5 under 0.10.0, which stays "coming". taggedTestBuilds lists every tagged test build, and a test fails the build if one has no anchor or more than one. Part of #85 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CoDNYz27iJ7o8PPztCzTpq
…ials Workflows grant nothing at the top level and each job asks for its own permissions: contents read for build and audit, write only for tagging. The build workflow's checkouts no longer persist the token, since nothing there pushes. actions/checkout and actions/setup-node are pinned to full commit SHAs with the version in a comment, and Dependabot now keeps the github-actions pins current. The nyuchi/.github reusable workflows were already pinned to a commit. Closes #84 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CoDNYz27iJ7o8PPztCzTpq
README, CONTRIBUTING and docs/toolchain.md now describe the Astro site's pages, the staging to main release flow, Vite+ as adopted, the inline scripts the CSP hashes and the current audit; the dead Lint badge, the vitest pin, master and "two pages" are gone. react and react-dom are removed: nothing imports them and @bundu/ui declares no peers. Prettier and vp fmt both stay, since a required org gate runs each, and a test fails if their settings differ. Closes #86 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CoDNYz27iJ7o8PPztCzTpq
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
…or-parser at 7.1.6+ npm audit fix brings http-cache-semantics past GHSA-ch52-4w7c-c8xp, so its dated exception in scripts/audit.mjs goes. @tailwindcss/typography pins postcss-selector-parser 6.0.10 (GHSA-rj75-hqrm-r3gf, moderate); an npm overrides entry takes 7.1.6, and the built CSS is byte-for-byte unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CoDNYz27iJ7o8PPztCzTpq
Bryan Fawcett (bryanfawcett)
marked this pull request as ready for review
October 13, 2026 01:01
This was referenced Oct 13, 2026
Merged
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
One commit per issue, against
staging.#83: Google Analytics loads only after consent
Analytics.astrono longer puts Google's tag on the page. One inline script queues the Consent Mode defaults (all denied),jsandconfig, and defineswindow.nyuchiAnalytics.load(), which is now the only way the tag is requested. It is idempotent. The script calls it on page load only whennyuchi-consentparses, hasv === CONSENT_VERSION, and hasanalytics === true.CookieBanner.astrocalls the loader fromapply()only when analytics is granted, so it runs on Accept, on Save with Analytics ticked, or on boot with a stored yes. The legacyanalytics-consentkey is no longer migrated: it is ignored as an answer (the banner asks again) and is still removed on save.parseConsent()insrc/data/consent.ts, used by the banner and bySupportWidget.astro. Older versions, unversioned records, non-objects and JSON that doesn't parse all count as no answer.csp:fixleaves 4 hashes instead of 5.script-src,connect-srcandimg-srchosts are unchanged and already cover the dynamically added tag.src/pages/legal/privacy.astroandcookies.astro, not inlegal.ts. Both now say the analytics tag isn't fetched and Google Analytics gets nothing until you agree. They also cover withdrawal: the current page keeps the tag it already loaded, with cookies off, and later pages don't load it. Google Fonts is still named as a separate contact with Google.legal.updatedand llms.txt are now dated 13 October 2026.tests/consent.test.tschecks that no built page has agoogletagmanagerscript tag or preload. It also runs the built inline script in avmsandbox: no load on a first visit, a stored no, an old version, an unversioned record, the legacy key or malformed values; exactly one load for a current yes or after the banner calls the loader. It also unit-testsparseConsent.tests/security.test.tsswaps the old "defaults before loader tag" ordering test for the new design: defaults before the loader, the banner calling the loader only undergranted("analytics"), and the legacy key never read.scripts/probe-consent.mjsnow fails on any GA request before a choice or after Reject (across a reload). It plants an old-version record plus the legacy key and expects no request and the banner shown, and it expects the gtag request after Accept.#85 (first part): anchors for test builds
alsoIdsnow include 0.9.6, 0.9.7 and 0.9.8. The extension tagged v0.9.8 on 13 Oct, after the issue was filed, so I added it too. 0.10.0 stayscoming.taggedTestBuildsinsrc/data/releases.tslists every tagged test build. A test intests/seo.test.tsfails if any listed version has no anchor, or more than one. It's data-driven and makes no GitHub call. I checked that it fails when 0.9.8 is removed fromalsoIds.#84: CI hardening
permissions: {}at the top. Jobs set their own:contents: readfor check and audit, andcontents: writeonly for the two tagging jobs, unchanged.persist-credentials: false(neither job pushes).actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0andactions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0. Both are lightweight tags with no annotated tag to dereference, and each is whatv4currently points at.nyuchi/.githubreusable workflows were already pinned to commit924e5b4, so I left them as they were..github/dependabot.ymlwith agithub-actionsentry: weekly, grouped,cooldown.default-days: 7(the org Semgrep rule requires it). There was no npm entry to keep.#86: tidy
master, "two pages" and "LICENSE if present". The stale vitest comment in build.yml is gone too.reactandreact-domremoved. Nothing imports them,@bundu/ui@0.5.0declares no peer dependencies, and the build and all checks pass. I regenerated the lockfile with the pinned npm 11.12.1 so the lockfile only loses the react entries, and checked thatnpm ci(npm 10.9.7) installs from it.vp fmt: kept both. Each is run by a required org gate (the lint gate runs Prettier;vite-plus / checkrunsvp fmt --check). Removing either would break a gate this repo doesn't control. Their settings are already identical, and the newtests/toolchain.test.tsfails if.prettierrcandvite.config.ts'sfmtblock ever drift. The reasoning is written up in docs/toolchain.md.Closes #83
Closes #84
Closes #86
Part of #85 (0.10.0 store status follows the release)
Checks run
npm test: build OK, 112 tests passed (6 files), CSP covers 4 inline scripts across 14 pagesnpm run format:check: clean.vp fmt --check: cleannpx vp lint: 5 warnings, the same 5 as onstaging; none newnpx astro check: 0 errors, 0 warnings, 0 hints.github/: clean.@action-validator/clion all three workflows: clean. dependabot.yml validated against the SchemaStore schema. actionlint isn't installed here, so it didn't runnpm run consent:probe(Chromium): all 23 checks passed. That includes no GA request before a choice or after Reject, and none for an old-version or legacy consent. The gtag request is made after Accept. Not verified here: whether the GA cookie appears after Accept, because Google's bundle can't load in this sandbox (TLS proxy). Re-run against the deployed preview to close that.vercel.jsonheaders.🤖 Generated with Claude Code
https://claude.ai/code/session_01CoDNYz27iJ7o8PPztCzTpq
Generated by Claude Code