A small CLI that fetches authenticated content from issuetracker.google.com (Buganizer) and clusterfuzz.com, using a persistent headless Chromium session driven by Playwright.
Built because there is no usable external API for either service and pasting issue contents into another tool gets old fast.
git clone <this repo> ~/repos/bnz
cd ~/repos/bnz
npm install
npx playwright install chromiumAdd ~/repos/bnz to your PATH so bnz is on it (the repo ships a bnz
symlink to bnz.js).
Each service is a one-time headed-browser login. The session is stored in a
persistent Playwright profile at ~/.config/bnz/profile.
bnz login # log into issuetracker.google.com
bnz cf login # log into clusterfuzz.comBoth services use Google SSO, so logging into one usually carries the other — but running both is harmless and ensures cookies are warm.
bnz 505610970 # markdown, compact
bnz 505610970 -v # markdown, verbose (metadata-only comments + Changes lists)
bnz 505610970 --format=json # structured JSON
bnz https://issuetracker.google.com/issues/505610970Compact markdown shows: title, status/type/priority/severity summary, sidebar metadata, hotlists, description, and numbered comments. Verbose adds metadata-only entries (component changes, hotlist toggles) and per-comment field-change lists.
bnz cf 5009280990216192 # by testcase key
bnz cf 505610970 # by Buganizer issue id (resolves the testcase link in the issue body)
bnz cf b/505610970
bnz cf https://clusterfuzz.com/testcase?key=5009280990216192
bnz cf 505610970 -v # verbose
bnz cf 505610970 --format=jsonNumeric input is disambiguated by length: 14+ digits is treated as a testcase
key; otherwise it's a Buganizer issue id and the issue's description and
comments are scanned for a clusterfuzz.com/testcase?key=... link.
Compact testcase output is the three things you usually want:
## Flags— d8 flags parsed from the[Command line]in the crash stacktrace## GN config (args.gn)— the build configuration verbatim## Minimized testcase— the reproducer JavaScript, downloaded via the authenticated session
Verbose adds the page URL, crash header, Job/Sanitizer summary, binary and testcase paths, ASAN environment options, and the full crash stacktrace.
| Flag | Effect |
|---|---|
--format=markdown |
Default. Pretty-printed with ANSI color when stdout is a TTY. |
--format=json |
Structured output. Always full content (verbosity is ignored). |
--format=text |
Raw page text from the DOM walker. Useful for debugging the parser. |
-v, --verbose |
Markdown only: include the omitted-by-default sections. |
--debug |
Adds rawText to JSON. |
--debug-screenshot=path |
Writes a ClusterFuzz page screenshot to the explicit path. |
--no-color |
Disable ANSI color (also respects NO_COLOR). |
-h, --help |
Show usage. |
Both sites are JavaScript SPAs (Polymer with shadow DOM), so we don't try to hit any backend API. Instead:
- Playwright launches Chromium against a persistent user-data dir, reusing
the cookies you established with
bnz login/bnz cf login. - We navigate, wait for the SPA to settle (
networkidle), and walk the document — descending into open shadow roots — to produce a flat text representation. - The text is parsed with anchored regexes for the fields we care about (issue sidebar, description, comments; testcase command line, GN config, stacktrace).
- The clusterfuzz reproducer is downloaded as a separate authenticated request via Playwright's request context (avoids CORS).
Issue URLs are accepted only for Buganizer / Chromium issue hosts and are
normalized by extracting the numeric issue id before navigation. ClusterFuzz
URLs are accepted only for clusterfuzz.com. Human-readable output has
terminal control sequences stripped before printing.
- The persistent profile at
~/.config/bnz/profilecontains authenticated Google session state. Treat it like a browser profile and do not share it. --debugincludes raw page text in JSON output. That can contain sensitive issue or testcase content.- Screenshots are written only when
--debug-screenshot=pathis provided. Choose a private path when capturing sensitive ClusterFuzz pages.
- Parsing is heuristic. The pages don't expose stable selectors, so when
Google changes the UI the regexes will drift.
--format=textand--debugare the escape hatches. - Some sidebar fields on the issue page contain truncated lists (e.g.
OSshowing only the first three values, hidden behind a "Show all" disclosure). The full list is recoverable from the comment-change history. - Buganizer fields rendered as radio groups (Crash Type alternates, Reliably Reproduces, Security selector, etc.) on the clusterfuzz page concatenate all options in DOM order. Those fields are intentionally omitted from the parsed output rather than presented misleadingly.
bnz login/bnz cf loginrequire manual interaction. Cookie rotation may eventually invalidate the session; re-run the login if requests start redirecting toaccounts.google.com.
bnz.js— the entire CLI.bnz— symlink tobnz.js(so the unsuffixed name is onPATH).package.json— declares the Playwright dependency.