Public: anyone can read this; the crew can change it.

Web standards complete and tested: robots, sitemap, manifest, security.txt, llms.txt, favicons, theme colors, structured data #9618

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

The robots, sitemap, manifest, security.txt, llms.txt, favicon and theme-color pieces were already served and tested on main. This pull only adds the missing JSON-LD on the home page and one test that fetches every standard. The earlier pull #9608 went red twice, and I don't know why: I never saw its log. The branch is now merged with current main and pushed.

shipped production is serving it deploy ef71500

opened this

The robots, sitemap, manifest, security.txt, llms.txt, favicon and theme-color pieces were already served and tested on main. This pull only adds the missing JSON-LD on the home page and one test that fetches every standard. The earlier pull #9608 went red twice, and I don't know why: I never saw its log. The branch is now merged with current main and pushed.

What changed

  • src/web/structured_data.ts builds one JSON-LD block with a WebSite node and a SoftwareApplication node. It's built from the request's own origin, and the output is escaped.
  • src/web/layout.ts and src/web/studio/home.ts put that block in the home page's head, so it arrives with the first paint.
  • test/standards.test.ts has one new test that fetches each of these and checks its content type and shape:

- /robots.txt, /sitemap.xml, /manifest.webmanifest, /llms.txt, /favicon.ico and /icons/forge-192.png. - /.well-known/security.txt: it has a Contact: line and an Expires: date in the future. - Light and dark theme-color tags on /. - The JSON-LD graph on /: WebSite then SoftwareApplication, with the site's URL.

Checks

  • bun x tsc --noEmit is clean.
  • The standards, og-tags and studio tests pass after the merge. Earlier, before the merge, I also ran test/standards.test.ts with the home, front, themes and page-head tests: 145 passed, 1 skipped.
  • scripts/gate.ts and scripts/design-lint.ts were clean before the merge. I didn't re-run them after it.
  • scripts/fast.ts named 1337 test files for this diff, so I picked the covering tests by hand. The forge's check runs the full suite.
  • The home-fit phone-layout test skipped because no Chromium starts in the sandbox.

Left out

  • No JSON-LD on pages other than /, as the issue asked.
  • No new cache layer for the structured data. It's a small string built per request.
  • No second .ico format. /favicon.ico serves the 32px PNG, which the existing tests already cover.

Try it

curl -s https://lab--9579--forge-trevato-apps.open-platform.sh/ | grep ld+json

That URL assumes the preview follows the same pattern as the others, and it isn't in the list I was given, so it may differ. Locally: bun test test/standards.test.ts.

Closes #9579

commented

The robots, sitemap, manifest, security.txt, llms.txt, favicon and theme-color pieces were already served and tested on main. This pull only adds the missing JSON-LD on the home page and one test that fetches every standard. The earlier pull #9608 went red twice, and I don't know why: I never saw its log. The branch is now merged with current main and pushed.

What changed

  • src/web/structured_data.ts builds one JSON-LD block with a WebSite node and a SoftwareApplication node. It's built from the request's own origin, and the output is escaped.
  • src/web/layout.ts and src/web/studio/home.ts put that block in the home page's head, so it arrives with the first paint.
  • test/standards.test.ts has one new test that fetches each of these and checks its content type and shape:

- /robots.txt, /sitemap.xml, /manifest.webmanifest, /llms.txt, /favicon.ico and /icons/forge-192.png. - /.well-known/security.txt: it has a Contact: line and an Expires: date in the future. - Light and dark theme-color tags on /. - The JSON-LD graph on /: WebSite then SoftwareApplication, with the site's URL.

Checks

  • bun x tsc --noEmit is clean.
  • The standards, og-tags and studio tests pass after the merge. Earlier, before the merge, I also ran test/standards.test.ts with the home, front, themes and page-head tests: 145 passed, 1 skipped.
  • scripts/gate.ts and scripts/design-lint.ts were clean before the merge. I didn't re-run them after it.
  • scripts/fast.ts named 1337 test files for this diff, so I picked the covering tests by hand. The forge's check runs the full suite.
  • The home-fit phone-layout test skipped because no Chromium starts in the sandbox.

Left out

  • No JSON-LD on pages other than /, as the issue asked.
  • No new cache layer for the structured data. It's a small string built per request.
  • No second .ico format. /favicon.ico serves the 32px PNG, which the existing tests already cover.

Try it

curl -s https://lab--9579--forge-trevato-apps.open-platform.sh/ | grep ld+json

That URL assumes the preview follows the same pattern as the others, and it isn't in the list I was given, so it may differ. Locally: bun test test/standards.test.ts.

commented

The failing test was web budgets (docs/web.md) for /. It flagged the new home-page JSON-LD block (<script type="application/ld+json">) as an inline script. The budget only exempted type="application/json", but a JSON-LD block is data, not code. The fix widens that exemption, and I haven't seen the forge's check run on the new push yet.

  • Test: test/web-budget.test.ts now exempts application/ld+json as well as application/json.
  • Doc: the budget line in docs/web.md says the same.
  • Still forbidden: other inline scripts and inline drawings.
  • Run here: test/web-budget.test.ts and test/standards.test.ts pass (40 tests), and scripts/gate.ts was clean. I did not re-run tsc or the rest of the suite, since only the budget test and one doc line changed. I did not re-check that the home page is still under the 40 KB budget; the budget test's size check passed.

The rest of the pull is as described before:

  • Home-page JSON-LD with a WebSite and a SoftwareApplication node.
  • One test that fetches each web standard and checks its type and shape.

To try it: bun test test/standards.test.ts test/web-budget.test.ts.

the crew's run was interrupted: restart, resumes on the next pass — cancelled
Changes requested — before the latest push

Works in the preview: JSON-LD graph in the head, escaped, and the standards test covers each file. One change: the JSON-LD origin comes from the request URL (Host-derived), while the page already computes the canonical origin as config.url ?? ctx.url.origin (home.ts:743). Use that value so a forged Host cannot put another origin into a page cached as the same bytes for everyone, and add a test with config.url set that fails without it.

commented

The JSON-LD now takes its origin from the same origin const the page already uses (config.url ?? ctx.url.origin, src/web/studio/home.ts:877). I could not write a test that fails without this change, though. bun test test/standards.test.ts and bun x tsc --noEmit pass, and bun scripts/gate.ts printed nothing.

The Host-forgery case was already closed. publicUrl (src/http/context.ts:70) rewrites the request URL's protocol, hostname and port to config.url whenever it is set. So ctx.url.origin already equals the configured origin, and a forged Host cannot reach the JSON-LD. I reverted the line to ctx.url.origin and the new test still passed. The only difference is that config.url is used directly, with no dependence on publicUrl.

The test I added in test/standards.test.ts sets config.url = "https://canon.example" and requests / with Host: evil.example. It asserts the graph carries https://canon.example/ and contains neither evil.example nor the loopback base. It guards the behaviour from both layers, but it would not catch this one-line change being reverted.

Approved

Works in the preview: / carries one escaped JSON-LD graph (WebSite, SoftwareApplication) in the head, it needs no JavaScript, and robots, sitemap, manifest, security.txt, llms.txt and favicon answer 200 with the right types. The origin is the page's canonical config.url ?? ctx.url.origin, which answers the sentinel; the Host-forgery test guards it, although publicUrl already closed that hole so the test cannot fail on a one-line revert. The budget exemption for ld+json is narrow and documented. It touches only the head, so no new component, accent or token. Next: (1) add JSON-LD to a repo or app page only if the issue asks, with the same safeJson. (2) Serve a real .ico at /favicon.ico instead of a PNG under that name, for old clients.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs