feat(cli): mir doctor --share + beta checklist — measured beta, no telemetry (B2) - #80
Conversation
…thout telemetry (B2) --share runs doctor's checks and prints a report built for a public issue: version, platform, tmux, and check results — with identities, machine names, state paths, and custom relay URLs withheld at the source, every line additionally scrubbed of the home directory, and a test that seeds recognizable secrets and asserts none survive. The bug template and BETA.md now ask for --share, and docs/beta-checklist.md walks a tester through the release gates so the north-star is measurable from reports alone. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KeiotDVE94wEzvc7wcvm1y
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b11ffaf8dc
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if !d.share || rawURL == defaults.SignalURL() { | ||
| return s |
There was a problem hiding this comment.
Redact relays configured through MIR_SIGNAL
When a self-hosted user configures the relay via the documented MIR_SIGNAL override and the health check fails, rawURL == defaults.SignalURL() is true, so this branch returns the HTTP error unchanged. Go's HTTP errors include the requested URL, causing mir doctor --share to expose the private relay hostname in the public bug report the new template requests; the comparison needs to use the baked-in public relay or redact every relay URL in share mode.
Useful? React with 👍 / 👎.
| d.w = func(format string, values ...any) { | ||
| fmt.Fprint(a.out, scrubHome(fmt.Sprintf(format, values...))) |
There was a problem hiding this comment.
Redact keychain references from shared errors
When the OS keychain is locked or its entry is unavailable, client.InspectIdentityStorage propagates the commandSecretStore.Get error, which embeds the unique SecretRef as owner secret %q. The share-mode writer only scrubs the home directory, so the supposedly paste-safe report publishes this owner-correlated keychain identifier; known identity-storage errors should be sanitized before being written.
Useful? React with 👍 / 👎.
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit b11ffaf. Configure here.
| return "custom" | ||
| } | ||
| return raw | ||
| } |
There was a problem hiding this comment.
Custom MIR_SIGNAL URL not redacted
Medium Severity
shareURL and scrubValue treat a relay as public when it equals defaults.SignalURL(), which returns MIR_SIGNAL when set. That is the documented self-host override, so mir doctor --share can print a home-server URL in health failures and unsafe-URL lines.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit b11ffaf. Configure here.
| s = strings.ReplaceAll(s, u.Host, "custom") | ||
| } | ||
| return s | ||
| } |
There was a problem hiding this comment.
Health errors leak resolved relay IPs
Medium Severity
scrubValue only substitutes the raw URL and u.Host. Go dial errors for a hostname custom relay include the resolved IP and port, which those replacements do not match, so a failed --share health check can still expose a private relay address.
Reviewed by Cursor Bugbot for commit b11ffaf. Configure here.
| // the default relay is shown, anything else becomes "custom" (a private URL | ||
| // can identify a home server). | ||
| func (d *doctorReport) shareURL(raw string) string { | ||
| if d.share && raw != defaults.SignalURL() { |
There was a problem hiding this comment.
🔒 Agentic Security Review
Severity: MEDIUM
shareURL and scrubValue treat a relay as public when it equals defaults.SignalURL(). That helper returns MIR_SIGNAL when set, which is the documented self-host override, and --signal defaults to the same value.
A tester who only exported MIR_SIGNAL (no extra flag) will paste the private relay URL into the public issue the new bug template requires. Invalid/non-HTTPS failures print it via shareURL; failed health checks skip scrubbing entirely because rawURL == defaults.SignalURL().
Impact: Home-lab or internal relay hostnames (and the URLs in Go HTTP errors) can be published as if they were the hosted default.
Reviewed by Cursor Security Reviewer for commit b11ffaf. Configure here.
| s = strings.ReplaceAll(s, base, "custom") | ||
| } | ||
| if u, err := url.Parse(rawURL); err == nil && u.Host != "" { | ||
| s = strings.ReplaceAll(s, u.Host, "custom") |
There was a problem hiding this comment.
🔒 Agentic Security Review
Severity: MEDIUM
Even when custom-URL scrubbing runs, it only ReplaceAlls the configured URL string and u.Host. Go net/http dial errors separately embed the resolved address (dial tcp 10.0.0.5:443). After hostname replacement that IP:port remains.
The new test uses http://127.0.0.1:1, where u.Host already matches the dial target, so it does not catch hostname → IP leakage. Testers are asked to paste --share into public issues.
Impact: A failed health check of a hostname custom relay can still publish a private or RFC1918 relay address.
Reviewed by Cursor Security Reviewer for commit b11ffaf. Configure here.




Closes #79.
What --share includes
What --share withholds (test-enforced)
(redacted)custom, including inside HTTP error strings (which embed both the dialed URL and the resolved host:port)TestDoctorShareRedactsPrivateMaterialseeds recognizable fake secrets and asserts none survive; plainmir doctorstays verbatim for local use.Decisions
reconnected in …line themselves instead.Wired into the report flow
mir doctor --shareTests
go test ./...green,gofmt -lclean, web 152/152.🤖 Generated with Claude Code
https://claude.ai/code/session_01KeiotDVE94wEzvc7wcvm1y
Note
Low Risk
Changes are additive CLI output redaction and documentation; default
mir doctorbehavior is preserved and sensitive leakage is test-guarded.Overview
Adds
mir doctor --share, which runs the same local checks asmir doctorbut prints a report safe to paste into public issues. Identities become(redacted), state paths collapse to basenames with home-dir scrubbing on every line, and non-default relay URLs (including in HTTP error text) show ascustom. Plainmir doctoroutput is unchanged.Beta feedback flow: the bug report template and
BETA.mdnow ask for--shareinstead of full doctor output. Newdocs/beta-checklist.mdis a ~10-minute walk-through (install timing, reconnect, warm switching, rename, retire/re-pair, environment notes) tied to release gates, linked fromBETA.mdbecause the product has no telemetry.Redaction is covered by
doctor_share_test.go(seeded secrets must not appear in--shareoutput).Reviewed by Cursor Bugbot for commit b11ffaf. Bugbot is set up for automated code reviews on this repo. Configure here.