Skip to content

Run the helper's and the extension's checks on every pull request - #9

Merged
agkloop merged 1 commit into
mainfrom
chore/ci
Sep 20, 2026
Merged

agkloop merged 1 commit into
mainfrom
chore/ci

Conversation

@agkloop

@agkloop agkloop commented Sep 20, 2026

Copy link
Copy Markdown
Owner

What

New files only, plus one line in .gitignore. No runtime code changes.

.github/workflows/ci.yml runs on every pull request and on main:

  • Helper (macOS, the only system it ships for): go vet, go test -race, staticcheck, govulncheck. Both linters are clean today, so both block.
  • Extension (Ubuntu): node --check on every script, the manifest parses, node --test on extension/test/.
  • permissions: contents: read; a newer push cancels the run it supersedes.

host/fuzz_test.go: native Go fuzz targets for everything that parses bytes someone else chose. Each asserts only that the parser returns, does not panic, and keeps to its documented limits.

Target Exercises Input comes from
FuzzRewriteHLS, FuzzScanHLS playlist rewriter and scan any web server
FuzzParseCastRecords mDNS parser any machine on the LAN
FuzzDecodeMsg, FuzzCastReadLoop Cast message decoder and frame reader the TV, or whoever answers as one
FuzzVerifyAuthReply auth reply and protobuf fields the TV, before its identity is checked
FuzzNativeFraming native-messaging reader the browser

20 s of fuzzing each found no crash and no hang. The seeds run with go test and add under a second. FuzzNativeFraming holds every handler slot while it runs, so a well-formed request is answered BUSY and never acted on: a fuzzer must not be able to start a real scan or cast.

The DASH rewriter's fuzz target is not here: #7 replaces that rewriter and carries its own target, so the two can merge in either order.

extension/test/sw.test.mjs: the service worker's first test, node:test plus node:vm with a stub chrome, no dependencies (still no package.json). Six cases: media reports are dated; the duration is carried forward; duration: 0 is a value, not a gap; a disconnect clears it; a final IDLE ends the cast; senders other than our own pages get no answer. Breaking sw.js seven different ways made the tests fail each time.

.gitignore: host/host, the binary a bare go build leaves behind.

Testing

  • go vet, go test -race, staticcheck, govulncheck locally (the last two with GOTOOLCHAIN=go1.27.1, which is what host/go.mod pins and what CI installs)
  • Extension job's steps dry-run locally; workflow YAML parses
  • The workflow itself has not run on GitHub yet: this pull request is its first run

Found along the way

GOOS=linux go build and go vet pass. GOOS=windows go build fails in main.go (syscall.Setrlimit) and mdns.go (SetsockoptInet4Addr takes a Handle), so a Windows port needs code changes, not just an installer.

🤖 Generated with Claude Code

Nothing checked a change before it was merged: vet, the Go tests and
the rest ran when someone remembered to. A workflow now runs them on
every pull request and on main. The helper job runs on macOS, the only
system the helper ships for (it builds for Linux as well, not for
Windows): go vet, the tests under the race detector, staticcheck and
govulncheck. Both linters are clean today, so both block. The extension
job syntax-checks every script, parses the manifest and runs the new
test. The workflow may read the repository and nothing else, and a
newer push cancels the run it supersedes.

The parsers that read bytes chosen by someone else get native fuzz
targets: the HLS rewriter and the playlist scan (any web server; the
DASH rewriter's target comes with its rewrite in the relay security
change), the mDNS parser, the Cast frame reader, its message decoder
and the check of the auth reply (any machine on the LAN), and the
native-messaging reader (the browser). Each asserts only that the
parser returns, without panicking, and keeps to the limits it
documents. Their seeds run with go test; 20 s of fuzzing each found
nothing. The native-messaging target holds every handler slot while it
runs, so a well-formed request is answered BUSY and never acted on: a
fuzzer must not be able to start a real scan or cast.

sw.js gets its first test. node:test runs it in a vm context with a
stub chrome object, plays the helper and checks what the popup is told:
media reports are dated, the duration is carried forward (and 0 is a
value, not a gap), a disconnect clears it, a final IDLE ends the cast,
and senders other than our own pages get no answer. No dependencies,
so there is still no package.json.

.gitignore now covers host/host, the binary a bare `go build` leaves
behind.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@agkloop
agkloop merged commit 5e70549 into main Sep 20, 2026
3 checks passed
@agkloop agkloop mentioned this pull request Sep 20, 2026
1 task
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