Repository navigation
feat(console): the console on the website - #82
Open
ExposureGuard wants to merge 1 commit into
Open
ExposureGuard wants to merge 1 commit into
ExposureGuard wants to merge 1 commit into
Conversation
`haldir console` is a desktop window; this is the same thing at `/console`,
where a person who has not installed anything can see it.
The honest split: **a website cannot read your filesystem.** The half that
scans a machine stays local (`haldir discover --json`), so the page takes that
report as a paste and renders it beside the register — with the same next
steps, the same on-ramp snippet, and the same one-line summary. Run against a
self-hosted instance and your machine's inventory never leaves your network;
the page says so next to the box rather than implying it.
**Shaping happens server-side, in the function that already owns it.** The
endpoint calls `haldir_console.build_rows` — so the CLI, the desktop window and
the web page are one definition of what a row is, not three that drift. The
page's JavaScript only renders what comes back, and a test parses the served
page for `row.<field>` reads and asserts each one is a field the endpoint
returns (the same contract the dashboard pages are held to).
**The paste is untrusted input**, so it is sanitized before it is rendered:
lists coerced to the documented shape, non-dict entries skipped, strings
capped, unknown keys dropped — a list where a dict belongs used to raise three
frames down inside `build_rows`. Bodies over 256 KB are refused with a 413
before they are parsed.
Two bugs found by rendering it rather than reading it:
* the summary said "0 clients" beside a rendered list of them, because
`summarize()` read a `summary` block the sanitizer drops. It now computes
from the lists it is describing, which is also why it can show the number
that matters: "1 ungoverned".
* "1 sessions" — the register detail is customer-facing text, and it reads
like a template that was not finished.
`?example=1` loads a sample report, so the empty state has something to show
and the page can be linked from docs. The palette moved into one constant that
both cloud pages interpolate — they are one product seen from two angles.
Screenshots: `docs/console-web.png` (and the desktop one in `docs/console.png`),
both rendered on this machine — headless Chrome for this page, a real window
for the other.
Verified: 1164 tests, flake8 clean, mypy clean over 33 files, `openapi.json`
regenerated for the new endpoint (91 paths).
Co-Authored-By: Claude Code <noreply@anthropic.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #81 (the desktop console + discovery). Merge #81 first, then retarget to
main.haldir consoleis a desktop window. This is the same thing at/console— where someone who has installed nothing can see it.The honest split
A website cannot read your filesystem. The half that scans a machine stays local (
haldir discover --json), so the page takes that report as a paste and renders it beside the register — same rows, same next steps, same on-ramp snippet, same summary line. Against a self-hosted instance your machine's inventory never leaves your network, and the page says so next to the box rather than implying it.One definition of a row
Shaping happens server-side by calling
haldir_console.build_rows— the function the CLI and the desktop window already render. The page's JavaScript only draws what comes back, and a test parses the served page forrow.<field>reads and asserts each is a field/v1/console/rowsreturns. That's the same contract the dashboard pages are held to, for the same reason.The paste is untrusted input, sanitized before it is rendered: lists coerced to the documented shape, non-dict entries skipped, strings capped, unknown keys dropped (a list where a dict belongs raised three frames down inside
build_rows). Bodies over 256 KB get a 413 before they are parsed.Two bugs found by rendering it rather than reading it
summarize()read asummaryblock that the sanitizer drops. It now computes from the lists it is describing — which is also why it can report the number that matters: "1 ungoverned".Both were invisible in the tests that existed; the screenshot found them.
?example=1loads a sample so the empty state has something to show and the page can be linked from docs.Also: the palette moved into one constant both cloud pages interpolate (they're one product from two angles), and the dashboard nav gained a
Console ↗link.Verification
1164 tests, flake8 clean, mypy clean over 33 files,
openapi.jsonregenerated (91 paths). The screenshot above is this page rendered in headless Chrome against a real local instance — not a mockup.Still yours
The desktop half (
#81) and this page both end at the same place: the snippet gets a server under governance. Nothing here publishes, enrolls, or starts anything.🤖 Generated with Claude Code