Skip to content

[Wails] M5.5: desktop binary binds no TCP listener#146

Merged
josh-padnick merged 2 commits intofeat/wails-rewritefrom
josh-padnick/m5.5-no-tcp-listener
Apr 27, 2026
Merged

[Wails] M5.5: desktop binary binds no TCP listener#146
josh-padnick merged 2 commits intofeat/wails-rewritefrom
josh-padnick/m5.5-no-tcp-listener

Conversation

@josh-padnick
Copy link
Copy Markdown
Collaborator

@josh-padnick josh-padnick commented Apr 27, 2026

Summary

Removes the lazy embedded Gin server from the desktop binary so a running Gruntbooks process listens on no network sockets. The threat-model goal of M5.5 — eliminating the localhost API that any sibling process running as the same user could discover and abuse — is delivered: lsof -a -p $PID -iTCP -sTCP:LISTEN after opening a gruntbook returns nothing.

What changed

  • services/serverManager.Start no longer calls api.StartServerWithShutdown. It still creates the SessionManager and ExecutableRegistry that every IPC service depends on; it just doesn't bind a port.
  • desktop/app.go drops the /api/* reverse-proxy block and the newAPIProxy helper. The asset handler now only serves the embedded React build with SPA fallback. OpenResult.port and DesktopStatus.serverPort are gone — the frontend never used the number anyway.
  • TS bindings regenerated.

What did not change (deferred from the original M5.5 plan)

The original M5.5 plan was: migrate Playwright onto Wails's -tags server build mode (real bindings over HTTP at /wails/runtime), then delete cmd/serve.go, api/server.go, every if (!isDesktop()) fetch('/api/...') branch in the frontend, and gin-gonic/gin from go.mod.

That plan is blocked on a Wails alpha.78 bug: go build -tags server fails to compile because BrowserWindow (in pkg/application/browser_window.go) is missing Window.SetScreen, a regression introduced when the Window interface gained screen-management methods (PR wailsapp/wails#5067) without a matching update on BrowserWindow. The bug is also present on the upstream v3-alpha branch tip — there is no later alpha to bump to. Filed upstream as wailsapp/wails#5262.

Until either (a) a future alpha ships the fix or (b) we adopt a custom HTTP transport on top of application.MessageProcessor, Playwright stays on the legacy gruntbooks serve harness. The dual-pathed fetch('/api/...') branches in frontend hooks remain in place for that path. None of that code runs in the shipped desktop binary — that's the headline guarantee this PR delivers.

Test plan

  • go build ./... clean
  • go test ./services/... ./desktop/... clean (full suite green)
  • bun x tsc --noEmit clean
  • bun run lint clean (one pre-existing warning unrelated)
  • Playwright e2e: 17/17 passing on Chromium
  • lsof -a -p $PID -iTCP -sTCP:LISTEN empty for the desktop binary with a gruntbook open
  • gruntbooks serve still works for Playwright (verified via /api/health probe)

🤖 Generated with Claude Code

Removes the lazy embedded Gin server from the desktop binary so a
running Gruntbooks process listens on no network sockets. The
threat-model goal of M5.5 — eliminating the localhost API that any
sibling process running as the same user could discover and abuse —
is delivered: a `lsof -i -P -p $(pidof Gruntbooks)` after opening a
gruntbook returns nothing.

What changed
- `services/serverManager.Start` no longer calls
  `api.StartServerWithShutdown`. It still creates the SessionManager
  and ExecutableRegistry that every IPC service depends on; it just
  doesn't bind a port.
- `desktop/app.go` drops the `/api/*` reverse-proxy block and the
  `newAPIProxy` helper. The asset handler now only serves the embedded
  React build with SPA fallback. `OpenResult.port` and
  `DesktopStatus.serverPort` are gone — the frontend never used the
  number anyway.
- TS bindings regenerated.

What did not change (deferred from the original M5.5 plan)
- `cmd/serve.go`, `api/server.go`, and the dual-pathed
  `if (!isDesktop()) fetch('/api/...')` branches in every legacy
  frontend hook are kept. Playwright still drives `gruntbooks serve`
  for now.
- The full Gin deletion + Playwright-on-bindings migration was meant
  to land here. It is blocked on Wails v3 alpha.78's `-tags server`
  build mode failing to compile (`BrowserWindow` is missing
  `Window.SetScreen`, a regression introduced in PR #5067 and not yet
  fixed upstream). Until either alpha.79 ships a fix or we adopt a
  custom HTTP transport on top of `application.MessageProcessor`,
  Playwright stays on the legacy harness. See HANDOFF_PROMPT.md for
  the prompt that picks this work up.

Verification
- `go build ./...` clean
- `go test ./services/... ./desktop/...` clean
- `bun x tsc --noEmit` clean
- `bun run lint` clean (one pre-existing warning unrelated)
- Playwright e2e suite: 17/17 passing (Chromium)
- `lsof -a -p $PID -iTCP -sTCP:LISTEN` empty for the desktop binary
  with a gruntbook open
- `gruntbooks serve` still works for Playwright (verified via
  /api/health probe)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 27, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
runbooks Ready Ready Preview, Comment Apr 27, 2026 7:49pm

Request Review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 27, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b5919190-6d40-49c7-9816-9bb88e95ec74

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch josh-padnick/m5.5-no-tcp-listener

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Demo3's <TemplateInline> component was hitting POST /api/boilerplate/render-inline
unconditionally via useApi, which surfaced as "Failed to connect to gruntbook
server at wails://localhost/api/boilerplate/render-inline" once #146 removed
the desktop binary's /api/* asset proxy. The earlier audit looked for raw
fetch('/api/...') calls and missed this one because TemplateInline used the
useApi hook indirectly — useApi has no isDesktop() gating of its own.

Fix follows the dual-path pattern used by useApiBoilerplateRender / Template
and useScriptExecution: keep the useApi call for browser mode (gated by
isDesktop() so the endpoint is empty in desktop), and add a parallel
BoilerplateService.RenderInline IPC invoker with local 300ms debounce,
monotonic seq guard for stale-response discard, and matching state shape so
the rest of TemplateInline doesn't change.

Verified against testdata/sample-gruntbooks/demo3:
- Backend logs show RenderBoilerplateTemplate firing on input change
- No TCP listener bound (lsof empty)
- Build, lint, and tsc all green

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@josh-padnick josh-padnick merged commit d6cfa13 into feat/wails-rewrite Apr 27, 2026
14 of 15 checks passed
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