Gate the built site in a browser, and its scripts in the markup - #11
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
bd73877 to
0313f2e
Compare
Review 1P2 — Accessibility gate accepts empty or unresolved accessible names
The SVG check only tests for the presence of Residual risksReviewed only the pinned diff Verdict: NEEDS ATTENTION |
0313f2e to
3705611
Compare
Review 1 replyFixed in All prior sabotage classes were re-run and remain reachable; the emptied-text case now fails through the computed-name assertion. Browser checks still use 1280x800 and 390x844 viewports with a 10000ms link timeout. Head CI and Vercel are green. |
Review 2No findings. Review 1 is correctly dispositioned: Reviewed exact range Verdict: APPROVE |
Review 2 replyNo findings require changes. The network dependency and Chromium scope are accepted and documented with exact parameters: one attempt per critical external link, 10000ms timeout, redirects followed, and Chrome at 1280x800 plus 390x844. This is a Chromium smoke/accessibility gate rather than a cross-browser conformance claim. Head CI/Vercel are green. Disposition: Review 2 is approving. |
3705611 to
344384a
Compare
The no-JavaScript gate only looked for *.js files, so an inline <script> shipped past it. check_scripts.py walks the built HTML and rejects any <script src> and any inline <script> whose type is not application/ld+json -- the one script this page ships, and data rather than code. The site also had no browser verification at all. browser-check.mjs serves dist/ locally and loads it in headless Chrome at 1280x800 and 390x844, failing on console errors, uncaught exceptions, failed or >=400 requests, missing landmarks (one h1, header/main/footer, lang, title, description), links or SVGs without text alternatives, horizontal overflow (page-level, and any top-level section past the viewport edge), and broken internal or external links (200 expected, 10s timeout, redirects followed). Every assertion was proven reachable by sabotaging a build copy; one that was not -- aria-labels on the frames' role-less div wrappers -- was removed rather than kept as theatre. Proven to fail end to end: an is:inline script in the page source builds to 'dist/index.html:97: inline executable script <script type=None>', exit 1. Fixes aviorstudio/termcade-be#35
Review 1, finding 3. The link and SVG name checks matched raw attributes and text, which waves through an empty aria-label, an aria-labelledby pointing at nothing, and text hidden with display:none. The check now reads each node's computed accessible name from Chrome's accessibility tree (CDP Accessibility.getFullAXTree) at both viewports and fails on any link or unhidden svg/image whose computed name is empty, naming the offending element. Proven reachable against a sabotaged build copy: empty aria-label, unresolved aria-labelledby, and display:none-only link text each fail with 'link with an empty computed accessible name: <a ...>'; an unhidden unlabelled svg fails with 'unhidden svg or image with an empty computed accessible name: <svg ...>'. The previously emptied-link-text sabotage is now caught by the same computed-name assertion with a better message.
344384a to
92fdd3c
Compare
Fixes aviorstudio/termcade-be#35
Stacked on #10 (aviorstudio/termcade-be#29); this diff is only the second layer.
What
Script gate —
tools/check_scripts.pywalks every HTML file indist/and rejects any<script src=...>and any inline<script>whose type is notapplication/ld+json. The old gate only searched for*.jsfiles, which an inline script sails straight past. The JSON-LD structured-data block is data, not code, and stays allowed. The existingfind dist -name '*.js'check is kept — it catches a script file nothing references, which the markup scan cannot see.Browser gate —
tools/browser-check.mjsservesdist/over a throwaway local HTTP server and loads the page in headless Chrome (preinstalled onubuntu-latest, so no browser download;playwright-coreis the only new dependency, with node pinned in.mise.tomlbecause playwright-core does not run on bun). It fails on:<h1>, no<header>/<main>/<footer>, missinghtml[lang],<title>, or meta descriptionaria-hiddennor labelled.page-shell'soverflow-x: hiddenmasks the scrollbar for in-shell content)Documented parameters (in the script header, the CI step comment, and the README): viewports 1280×800 desktop and 390×844 mobile (touch + isMobile), external link timeout 10000ms, one attempt, redirects followed, accessibility threshold = the landmark/alternative-text assertions above (no raster images exist, so no alt rule binds).
Proof the gates fail
Inline script through the real build (required by the issue): added
<script is:inline>alert("deliberate")</script>tosrc/pages/index.astro, rebuilt:Restored, rebuilt, green. The external-
srcandtype="module"rejection branches were also exercised against synthetic files and fail with their own messages.Every browser assertion proven reachable by sabotaging a copy of
dist(never the committed sources):console error: saboteur,uncaught exception: Error: boom<h1>, unwrapped<footer>expected exactly one <h1>, found 0,no <footer> landmark1 section(s) extend past the viewportoverflow-x:visibleon the shellpage has a horizontal scrollbar(proves the scrollbar backstop is reachable)link /nope: HTTP 404,link https://wazero.io/definitely-not-a-page: HTTP 404,1 link(s) with no link textrequest failed: ... (net::ERR_UNSAFE_PORT)aria-hiddenfrom an SVG1 svg(s) neither hidden nor labelledOne proposed assertion failed this audit and was removed:
aria-labelon the frames' plain<div>wrappers is not exposed by assistive technology (no role), and the frames contain text so the "no text" fallback never fired — dead code. The frames are text by design; the honest alternative-text rules are the SVG and link-text assertions. This is recorded in the script header.Verification
python3 tools/check_scripts.py dist— pass, 1 page, ld+json allowed.node tools/browser-check.mjs dist— pass at both viewports; all 8 page links (2 internal/, 6 external) returned 200.bun run buildclean;bun.lockupdated viabun add -d playwright-core(frozen-lockfile safe).