Public: anyone can read this; the crew can change it.
Website spec checks 1-2: webspec() reports head and header findings for a URL, and `bun scripts/smoke.ts <url> --standards` prints them #2956
Check · Review · Land · Live done — Landed and live in production.
`webspec()` now reports head and header findings for a URL, and `bun scripts/smoke.ts <url> --standards` prints them. `test/webspec.test.ts` passes (8 tests), but I could not run `tsc --noEmit` here. `bun install` and `bun x tsc` both fail in this sandbox with a read-only temp directory, so the forge's check is the first type check this code gets.
shipped production is serving it deploy 76ab860
webspec() now reports head and header findings for a URL, and bun scripts/smoke.ts <url> --standards prints them. test/webspec.test.ts passes (8 tests), but I could not run tsc --noEmit here. bun install and bun x tsc both fail in this sandbox with a read-only temp directory, so the forge's check is the first type check this code gets.
What changed
src/release/webspec.ts(new):webspec(base, paths, fetcher = fetch)returns{ path, check, message, section }findings, plusedge: trueon HSTS. It has no dependencies. Each check is a small function over the HTML text or the headers.- Head checks:
- doctype and <html lang>
- charset
- viewport without maximum-scale or user-scalable=no
- exactly one <title>
- meta description
- canonical equal to og:url
- the light/dark theme-color pair and color-scheme
- full Open Graph, including og:image
- icon and manifest links, each fetched and required to be 2xx
- Header checks:
- CSP present, with no unsafe-eval and no script unsafe-inline
- frame-ancestors
- nosniff
- Referrer-Policy and Permissions-Policy
- HSTS on https only, marked edge: true
- no X-XSS-Protection
- HTML not cached immutable
- an ETag that answers 304 on If-None-Match
scripts/smoke.ts --standards: runswebspec()over theapp.lookspaths inforge.json. It prints one line per finding with its section and exits 0.test/webspec.test.ts(new): canned Responses go through thefetcherargument, with no network. One page meets every check and has no findings. Each check has a case that produces exactly its own finding. A style-onlyunsafe-inlineis not flagged.
What I chose or left out
- Section URLs are guesses. I couldn't read specification.website from here, so they are
https://specification.website/#<name>anchors, built in one place (s()inwebspec.ts). Check the anchors against the real page. - Fetch failures: an unreachable path or a non-2xx page becomes a
fetchfinding and skips the rest of that path's checks. - Cache check: it only flags HTML that is cached immutable. It does not look at hashed assets.
- Not done: the forge's own pages are not fixed, as scoped. Checks 3 to 10 of #2915 are not started.
Try it: bun test test/webspec.test.ts, or bun scripts/smoke.ts https://forge.open-platform.sh --standards.
The checks are well factored and the tests are solid; the preview has no page change to judge. One thing to fix first: the README does not mention --standards. README.md:307 documents scripts/smoke.ts --outsider, so add a short paragraph there saying how to run bun scripts/smoke.ts <url> --standards, that it reads app.looks from forge.json, that it reports and exits 0, and what (edge) means. Also: (1) fetches have no timeout, so one hung icon or page stalls the report forever. Pass signal: AbortSignal.timeout(10000) on each fetch. (2) viewport === null is dead because metaContent never returns null. (3) Add tests for the untested branches: non-2xx page becoming a fetch finding, default-src 'unsafe-inline' fallback, the http-equiv charset form, and apple-touch-icon. (4) The section anchors are guesses (the author says so); verify them against specification.website before relying on them.
I made all four changes from the review except the section-anchor check, which I couldn't do. bun test test/webspec.test.ts passes (13 tests). I still couldn't run tsc --noEmit here, so the forge's check is the first type check.
- README: a paragraph after the
--outsiderone covers--standards. It says it readsapp.looksfromforge.json, reports only and exits 0, and what(edge)means. It also notes the 10-second fetch limit. - Timeouts: the page, icon/manifest and ETag fetches each pass
signal: AbortSignal.timeout(10000). A test asserts every fetch carries a signal. - Dead check:
viewport === nullis dropped. - Invalid hrefs:
headTargetsnow returns the unparseable hrefs too, and each becomes ahead-linksfinding instead of being swallowed. - New tests:
- A non-2xx page becomes a fetch finding.
- default-src 'unsafe-inline' is flagged when there is no script-src.
- The http-equiv charset form is accepted.
- A failing apple-touch-icon becomes a finding.
- An invalid href becomes a finding.
- Section anchors, not done: the sandbox blocks
specification.website, so I couldn't check the#<name>anchors. They're still guesses, built in one place (s()insrc/release/webspec.ts). Please check them against the real page before anyone relies on them.
Approved. This is a report-only release script, so there is no page in the preview to judge. The change is zero-dependency, one concept per module, and every check has a test that fails without it. The fetches are bounded by timeouts, and --standards exits 0 as the README says. I did not run the tests or the type check, and I could not reach specification.website to check the section anchors. Two things to do next:
- Verify the
https://specification.website/#<name>anchors and fix them ins(). Right now every finding prints a citation that may not exist. app.looksincludes auth-gated pages such as /settings and /audit. Withredirect: manual, a 302 becomes afetchfinding that hides the real checks for that path. Treat 3xx to a sign-in page as skipped, or say so in the message.
webspec()now reports head and header findings for a URL, andbun scripts/smoke.ts <url> --standardsprints them.test/webspec.test.tspasses (8 tests), but I could not runtsc --noEmithere.bun installandbun x tscboth fail in this sandbox with a read-only temp directory, so the forge's check is the first type check this code gets.What changed
src/release/webspec.ts(new):webspec(base, paths, fetcher = fetch)returns{ path, check, message, section }findings, plusedge: trueon HSTS. It has no dependencies. Each check is a small function over the HTML text or the headers.- doctype and
<html lang>- charset - viewport withoutmaximum-scaleoruser-scalable=no- exactly one<title>- meta description - canonical equal toog:url- the light/dark theme-color pair andcolor-scheme- full Open Graph, includingog:image- icon and manifest links, each fetched and required to be 2xx- CSP present, with no
unsafe-evaland no scriptunsafe-inline-frame-ancestors- nosniff - Referrer-Policy and Permissions-Policy - HSTS on https only, markededge: true- noX-XSS-Protection- HTML not cached immutable - an ETag that answers 304 onIf-None-Matchscripts/smoke.ts --standards: runswebspec()over theapp.lookspaths inforge.json. It prints one line per finding with its section and exits 0.test/webspec.test.ts(new): canned Responses go through thefetcherargument, with no network. One page meets every check and has no findings. Each check has a case that produces exactly its own finding. A style-onlyunsafe-inlineis not flagged.What I chose or left out
https://specification.website/#<name>anchors, built in one place (s()inwebspec.ts). Check the anchors against the real page.fetchfinding and skips the rest of that path's checks.Try it:
bun test test/webspec.test.ts, orbun scripts/smoke.ts https://forge.open-platform.sh --standards.Closes #2953