Skip to content

Publish a live demo report to GitHub Pages on every merge - #458

Merged
tylervick merged 1 commit into
mainfrom
ci/pages-demo
Aug 13, 2026
Merged

tylervick merged 1 commit into
mainfrom
ci/pages-demo

Conversation

@tylervick

Copy link
Copy Markdown
Member

Why

Pages is already enabled on this repo — build_type: workflow, public, https://xctesthtmlreport.github.io/XCTestHTMLReport/ — with zero builds ever pushed to it. Meanwhile the README's only pictures of this tool's output are two imgur uploads (README.md:8, :14) that predate 4.0 and that nobody here controls or can update.

Rendering the sample report from the current tree on every merge replaces both with one artifact that can't go stale and can't be taken down by a third party.

What

New pages.yml: build on macOS → deploy on ubuntu.

  • Reuses ./.github/actions/fixture-cache-key with the same key and the same paths as test.yml, so a merge normally finds the cache warm and publishes without booting a simulator.
  • Deploy is split out so the macOS runner is released early, and so pages: write / id-token: write live only on the job that needs them. Top level stays contents: read.
  • concurrency: pages with cancel-in-progress: false — Pages has one live deployment, and a merge landing mid-run should still publish rather than be dropped.

README gets one line linking the live report. The stale imgur images are left alone deliberately — replacing them needs a committed screenshot, which is the headless-renderer work, not this.

Verification

Ran the exact workflow command locally against the release binary:

mkdir -p _site && .build/release/xchtmlreport -i -o _site …/TestResults.xcresult

→ one self-contained 8.6 MB _site/index.html. Served it over HTTP and opened it in a browser: renders correctly (16 tests, 9 passed / 1 skipped / 6 failed, device sidebar populated), and an inlined attachment previews fine from the standalone file. Payloads emitted as data: URIs:

type count
image/png 11
video/mp4 4
text/plain 9
text/html 2

Zero external or relative refs. Linking mode would have emitted 460 KB whose src attributes point back into the .xcresult, 404ing every screenshot and video on the published site.

zizmor --min-severity low and actionlint both clean.

Note

The demo will show failing tests. TestResults.xcresult deliberately contains failures, retries, and attachment filenames full of quotes and angle brackets. That's the point — the failure UI is what people come to this tool to look at — but it's public and permanent, so flagging it explicitly.

🤖 Generated with Claude Code

Pages has been enabled on this repository for some time -- build_type
"workflow", public, https://xctesthtmlreport.github.io/XCTestHTMLReport/
-- with zero builds ever pushed to it. Meanwhile the README's only
pictures of this tool's output are two imgur uploads that predate 4.0
and that nobody here controls or can update.

Rendering the sample report from the current tree on every merge to main
replaces both problems with one artifact that cannot go stale and cannot
be taken down by a third party.

The build job reuses .github/actions/fixture-cache-key with the same key
and the same paths as test.yml, so a merge normally finds the cache
already warm and publishes without booting a simulator at all. Deploy is
split onto ubuntu so the macOS runner is released early and so the
pages/id-token scopes live only on the job that needs them.

Rendered with -i. Verified locally against the release binary: one
self-contained 8.6 MB index.html carrying 11 PNGs, 4 mp4s, 9 text
attachments and 2 HTML attachments as data: URIs, with no external or
relative references at all. The default linking mode emits 460 KB whose
src attributes point back into the .xcresult bundle, which would 404
every screenshot and video on the published site.

TestResults is the fixture rendered because it is the richest one --
failures, retries, screen recordings, and attachment filenames full of
quotes and angle brackets. The demo showing red tests is deliberate: the
failure UI is what people come to this tool to look at.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
@coderabbitai

coderabbitai Bot commented Aug 13, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@tylervick, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 50 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: e7b3bc40-2457-405f-a3ee-095844368d61

📥 Commits

Reviewing files that changed from the base of the PR and between fdbe78b and d90919e.

📒 Files selected for processing (3)
  • .github/workflows/pages.yml
  • .gitignore
  • README.md

Comment @coderabbitai help to get the list of available commands.

@tylervick
tylervick merged commit f3f960f into main Aug 13, 2026
8 checks passed
@tylervick
tylervick deleted the ci/pages-demo branch August 13, 2026 09:27
tylervick added a commit that referenced this pull request Aug 14, 2026
…#463)

An attachment filename containing `"` terminated the `data="…"` attribute it
was written into, so `<GreaterThan>` from the fixture's hostile filename was
parsed as a start tag and entered the DOM. The report is published to a public
GitHub Pages URL on every merge (#458), which makes this a stored-injection
surface rather than a local-file curiosity.

Two halves, because escaping alone is not enough:

`stringByEscapingXMLChars` now runs over every leaf value the `HTML` seam
substitutes — not just `Attachment`'s, but the titles, log source, device
fields and screenshot-flow sources that `Test`, `Iteration`, `Run`,
`RunDestination` and `TestScreenshotFlow` contribute. Values that are already
rendered markup keep passing through untouched; `HTML.swift` now documents
which case a new placeholder falls into, since nothing can enforce it.

Escaping cannot fix `onclick="showText('[[SOURCE]]')"`, though: a browser
resolves `&apos;` back to `'` before compiling the attribute as JavaScript, so
an escaped filename is still a live breakout. The five attachment handlers now
read the `data` attribute they already carry instead of interpolating anything
— `showText(this.getAttribute('data'))`. `toggle` and `selectDevice` keep
interpolating, deliberately: what they pass is an `IdentifierPath.identifier`,
a hex digest by construction, and a test pins that shape.

The escaping also repairs the feature the injection broke. A truncated `data`
attribute meant the preview opened a prefix of the filename; it now opens the
file it names.

`SummarySeamTests.testHostileAttachmentFilenameDoesNotBreakOutOfAttribute`
loses its `XCTExpectFailure` here — an unexpected pass would otherwise fail
the suite on a correct fix.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant