Skip to content

feat(f11): add native macOS fleet desktop - #167

Merged
gnanirahulnutakki merged 3 commits into
devfrom
gnanirahulnutakki/feat/f11-native-desktop-shell
Jul 15, 2026
Merged

feat(f11): add native macOS fleet desktop#167
gnanirahulnutakki merged 3 commits into
devfrom
gnanirahulnutakki/feat/f11-native-desktop-shell

Conversation

@gnanirahulnutakki

@gnanirahulnutakki gnanirahulnutakki commented Jul 15, 2026

Copy link
Copy Markdown
Member

What changed

  • Adds sith desktop, a native macOS Wails v2 shell around the existing local fleet IDE.
  • Adds a native Import folder picker that uses the bounded kubeconfig-directory importer; paths and kubeconfig content do not cross the WebView bridge.
  • Reuses the hardened in-process UI handler at wails://wails with no TCP listener, no telemetry, and no second Kubernetes client.
  • Adds ADR 0010, packaging target, path-private error handling, and atomic session replacement.

Review and safety

  • CodeRabbit identified a close/import race; this PR fixes it with terminal host state and a deterministic regression test.
  • Native dialog and importer errors are deliberately redacted because underlying errors can expose local filesystem paths.
  • Development bundle is ARM64 with stable com.ardurai.sith identifier and ad-hoc signature. Developer ID signing, notarization, stapling, and public-release provenance remain E9 follow-up work.

Validation

  • make ci
  • make e2e-isolation (PostgreSQL RLS plus 50,000-case selector fuzz)
  • make release-check
  • KIND=/Volumes/EXTENDED/MacData/tools/bin/kind make e2e-kind (PASS, 158.742s)
  • make desktop-build WAILS=/Volumes/EXTENDED/MacData/go/bin/wails
  • Security queues immediately before publication: Dependabot 0, code scanning 0, secret scanning 0.

Closes #166.

Summary by CodeRabbit

  • New Features
    • Added the sith desktop command for running the local fleet IDE in a native macOS window.
    • Added an “Import folder” picker to load kubeconfigs from a selected directory.
    • Added Apple Silicon desktop build support via make desktop-build, including bundle preparation and signing for local verification.
  • Documentation
    • Updated README with desktop usage, build steps, and current limitations.
    • Added an ADR describing the native desktop shell approach.
  • Bug Fixes
    • Improved desktop session replacement and failure handling to keep the active session stable.
    • Added safeguards to avoid exposing local paths or kubeconfig contents in the UI.

Package the existing local fleet IDE in a Wails v2 macOS shell with a native, path-private kubeconfig-folder import flow. Preserve the hardened in-process UI boundary and atomic session handoff.

GSTACK-Checkpoint: 2026-07-14/f11-native-desktop-shell#1
Signed-off-by: Gnani Rahul <gnani.nutakki@gmail.com>
@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown

Review Change Stack

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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: e9755ed3-c04a-4d06-81fc-7f366ecb9113

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
📝 Walkthrough

Walkthrough

Adds a native macOS Wails desktop shell for the existing local fleet IDE, with in-process web UI serving, native kubeconfig directory import, atomic session replacement, macOS arm64 build/signing automation, CLI wiring, tests, and architecture documentation.

Changes

Native desktop shell

Layer / File(s) Summary
In-process web UI and desktop bridge contract
internal/webui/desktop.go, internal/webui/server.go, internal/webui/assets/*, internal/webui/*_test.go, internal/privacy/boundary_test.go
Adds Wails-origin validation, in-process handler replacement, opt-in folder import controls, and security/regression tests.
Desktop session and folder import lifecycle
internal/cli/desktop.go, internal/cli/desktop_test.go
Creates desktop sessions from bounded kubeconfig sources, atomically replaces active sessions, preserves failed imports, and closes safely during races.
Darwin entrypoint and Wails integration
internal/cli/desktop_darwin.go, internal/cli/desktop_execute.go, internal/cli/desktop_other.go, internal/cli/root.go, cmd/sith-desktop/*
Adds the macOS native bridge, Wails runner, desktop CLI entrypoint, command registration, application metadata, and non-macOS rejection behavior.
Desktop build and module configuration
Makefile, go.mod, .gitignore
Adds Wails requirements, generated frontend ignores, and macOS arm64 bundle, identifier, signing, and verification steps.
Architecture and implementation records
README.md, docs/adr/*, sessions/*
Documents desktop usage, accepted architecture, release limitations, and recorded validation evidence.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant Wails
  participant DesktopBridge
  participant desktopHost
  participant WebUI
  User->>Wails: Open native desktop application
  Wails->>WebUI: Serve wails://wails through in-process middleware
  WebUI->>DesktopBridge: Choose kubeconfig directory
  DesktopBridge->>desktopHost: Import selected directory
  desktopHost->>desktopHost: Create and atomically swap session
  desktopHost-->>WebUI: Return import success
  WebUI->>WebUI: Reload application
Loading

Possibly related PRs

  • ArdurAI/sith#142: Updates the same privacy import allowlist area for additional web UI modules.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 14.81% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly names the main change: a native macOS desktop shell for Sith.
Linked Issues check ✅ Passed The PR delivers the native macOS Wails desktop shell, in-process UI, bounded import flow, and tests aligned with #166.
Out of Scope Changes check ✅ Passed The changes stay focused on the desktop shell, packaging, docs, and tests, with no unrelated feature work.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch gnanirahulnutakki/feat/f11-native-desktop-shell

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

@gnanirahulnutakki

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (4)
Makefile (1)

47-53: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Verify the produced executable is actually ARM64.

The target requests darwin/arm64, but the post-build checks only the bundle path, identifier, and signature. Add an architecture assertion so an incorrectly produced artifact cannot pass the packaging gate. Wails lists darwin/arm64 as a supported target. (wails.io)

Proposed validation
 		app='cmd/sith-desktop/build/bin/Sith.app'; \
 		test -d "$$app"; \
+		test "$$(lipo -archs "$$app/Contents/MacOS/Sith")" = arm64; \
 		"$(PLISTBUDDY)" -c 'Set :CFBundleIdentifier com.ardurai.sith' "$$app/Contents/Info.plist"; \
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Makefile` around lines 47 - 53, Update the post-build validation in the
Makefile target to assert that the generated Sith.app executable is ARM64, in
addition to the existing bundle, identifier, and signature checks. Inspect the
executable inside the app bundle using the available architecture inspection
command and fail the target unless it reports arm64.
internal/webui/desktop.go (1)

29-45: 🩺 Stability & Availability | 🔵 Trivial | ⚖️ Poor tradeoff

Unbounded blocking: a hung in-flight request stalls Replace and, transitively, all new requests.

ServeHTTP holds the read lock for the full duration of the downstream ServeHTTP call. Go's sync.RWMutex gives waiting writers priority, so once Replace starts waiting on Lock(), every subsequent RLock() (i.e. every new incoming request) also blocks until the stuck request finishes. There's no timeout anywhere in this path, so a single hung fleet-engine call can freeze the whole desktop session until the process is restarted.

Consider bounding the in-flight request (e.g. request context deadline) or documenting that downstream handlers must guarantee bounded execution time.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/webui/desktop.go` around lines 29 - 45, Update
InProcessHandler.ServeHTTP and Replace so a hung downstream
LocalHandler.ServeHTTP cannot hold the RWMutex indefinitely; bound in-flight
request execution with an appropriate request-context deadline or timeout while
preserving atomic handler replacement and fail-closed behavior for a nil current
handler.
internal/cli/desktop.go (1)

50-71: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Hydrator failures are silently discarded.

_ = hydrator.Run(ctx) swallows any error from the hydration loop with no logging path. Since no logger is threaded through desktopSession/desktopHost, a persistent hydration failure (e.g., repeated cluster read errors) would leave the desktop UI silently stale with zero way to diagnose it.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/cli/desktop.go` around lines 50 - 71, The goroutine in
newDesktopSession discards errors from hydrator.Run, leaving persistent
hydration failures undiagnosed. Add an error-reporting path through the
desktopSession/desktopHost lifecycle and use it when the hydration goroutine
returns an error, preserving cancellation and cleanup behavior while ensuring
failures are logged or surfaced.
internal/cli/desktop_darwin.go (1)

50-85: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Signal-derived ctx from ExecuteDesktop is never wired to app shutdown.

ExecuteDesktop (desktop_execute.go) builds ctx via signal.NotifyContext(..., os.Interrupt) and passes it here, but runDesktop only uses it to construct desktopHost/sessions — it never watches ctx.Done() to call runtime.Quit or otherwise stop wails.Run. On SIGINT (relevant for go run, dev builds, or any CI/E2E harness that terminates the process), the session's hydrator/context is cancelled while the window keeps running and wails.Run keeps blocking, leaving a stale, half-torn-down UI instead of a clean exit.

♻️ Suggested fix: watch ctx and quit gracefully
 	bridge := &DesktopBridge{host: host}
+	go func() {
+		<-ctx.Done()
+		if bridge.ctx != nil {
+			runtime.Quit(bridge.ctx)
+		}
+	}()
 	err = wails.Run(&options.App{
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/cli/desktop_darwin.go` around lines 50 - 85, Update runDesktop to
watch ctx.Done() while wails.Run is active and request a graceful Wails
application shutdown via the appropriate runtime quit mechanism. Ensure the
watcher is stopped or exits when the app shuts down, and preserve the existing
host.Close cleanup and wails.Run error handling.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cmd/sith-desktop/wails.json`:
- Around line 5-6: Update the Wails configuration in wails.json so
frontend:build no longer runs against a missing default frontend directory:
either add the required frontend directory under cmd/sith-desktop or set
frontend:dir to the actual existing frontend location, while preserving the
intended build command.

In `@internal/cli/desktop.go`:
- Around line 25-40: Update the RunE validation in newDesktopCommand so a nil
reader or local client is allowed when options.kubeconfigDir is set, letting
runDesktop apply the supplied kubeconfig override. Retain the existing error for
invocations lacking both default dependencies and a kubeconfig directory, and
continue passing the resolved options to runDesktop.

In `@Makefile`:
- Around line 44-46: Update the Wails validation in desktop-build to require the
pinned v2.12.0 CLI version, and add the -nomodsync flag to the Wails build
invocation so it does not rewrite go.mod. Keep the existing command availability
check and build options unchanged.

In `@README.md`:
- Around line 364-369: Update the native import bridge documentation to
consistently describe all three outcomes: success, cancellation, and
sanitized/redacted errors, while preserving the guarantee that no absolute path
or kubeconfig content is exposed. Apply this wording in README.md lines 364-369,
docs/adr/0010-native-local-desktop-shell.md lines 22-24, and
sessions/2026-07-14-f11-native-desktop-shell.md lines 21-23.

---

Nitpick comments:
In `@internal/cli/desktop_darwin.go`:
- Around line 50-85: Update runDesktop to watch ctx.Done() while wails.Run is
active and request a graceful Wails application shutdown via the appropriate
runtime quit mechanism. Ensure the watcher is stopped or exits when the app
shuts down, and preserve the existing host.Close cleanup and wails.Run error
handling.

In `@internal/cli/desktop.go`:
- Around line 50-71: The goroutine in newDesktopSession discards errors from
hydrator.Run, leaving persistent hydration failures undiagnosed. Add an
error-reporting path through the desktopSession/desktopHost lifecycle and use it
when the hydration goroutine returns an error, preserving cancellation and
cleanup behavior while ensuring failures are logged or surfaced.

In `@internal/webui/desktop.go`:
- Around line 29-45: Update InProcessHandler.ServeHTTP and Replace so a hung
downstream LocalHandler.ServeHTTP cannot hold the RWMutex indefinitely; bound
in-flight request execution with an appropriate request-context deadline or
timeout while preserving atomic handler replacement and fail-closed behavior for
a nil current handler.

In `@Makefile`:
- Around line 47-53: Update the post-build validation in the Makefile target to
assert that the generated Sith.app executable is ARM64, in addition to the
existing bundle, identifier, and signature checks. Inspect the executable inside
the app bundle using the available architecture inspection command and fail the
target unless it reports arm64.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 602180f1-8170-4c27-b7aa-030676bb3531

📥 Commits

Reviewing files that changed from the base of the PR and between c6fa47b and 78af530.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (22)
  • .gitignore
  • Makefile
  • README.md
  • cmd/sith-desktop/main.go
  • cmd/sith-desktop/wails.json
  • docs/adr/0010-native-local-desktop-shell.md
  • docs/adr/README.md
  • go.mod
  • internal/cli/desktop.go
  • internal/cli/desktop_darwin.go
  • internal/cli/desktop_execute.go
  • internal/cli/desktop_other.go
  • internal/cli/desktop_test.go
  • internal/cli/root.go
  • internal/privacy/boundary_test.go
  • internal/webui/assets/app.js
  • internal/webui/assets/index.html
  • internal/webui/desktop.go
  • internal/webui/desktop_test.go
  • internal/webui/server.go
  • internal/webui/server_test.go
  • sessions/2026-07-14-f11-native-desktop-shell.md

Comment thread cmd/sith-desktop/wails.json
Comment thread internal/cli/desktop.go
Comment thread Makefile Outdated
Comment thread README.md
Use non-blocking session leases, a sanitized hydration-stop state, directory-only startup, graceful signal shutdown, and reproducible pinned Wails packaging with ARM64 verification.

GSTACK-Checkpoint: 2026-07-14/f11-native-desktop-shell#2
Signed-off-by: Gnani Rahul <gnani.nutakki@gmail.com>
@gnanirahulnutakki

Copy link
Copy Markdown
Member Author

Addressed the CodeRabbit review in b99820e:

  • Replaced lock-held request routing with draining session leases, so slow old requests cannot stall the new session.
  • Added sanitized desktop hydration-stop state, explicit directory-only source validation, and graceful SIGINT-to-Wails shutdown.
  • Pinned/verified Wails v2.12.0, disabled Wails module mutation with -nosyncgomod, asserted ARM64, and committed the frontend directory marker.
  • Added the requested bridge-outcome documentation and bounded the close/import regression test.

make ci, make e2e-isolation, make release-check, real make e2e-kind, and make desktop-build all pass on the correction source.

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown

@gnanirahulnutakki Thanks for the detailed rundown of the fixes. I'll kick off a fresh review of the changes in b99820e.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Signed-off-by: Gnani Rahul <gnani.nutakki@gmail.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
internal/cli/desktop.go (1)

177-189: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Wait for the drained channel before closing the session Close() drops the channel returned by host.handler.Replace(nil) and calls session.close() immediately; that can tear down webui.Application while a request leased to the old session is still in flight.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/cli/desktop.go` around lines 177 - 189, Update desktopHost.Close to
retain the channel returned by host.handler.Replace(nil) and wait for it to
drain before calling session.close(). Preserve the existing mutex, closed-state
guard, session detachment, and nil-handler replacement behavior, ensuring the
webui.Application session is closed only after in-flight requests complete.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@internal/cli/desktop.go`:
- Around line 177-189: Update desktopHost.Close to retain the channel returned
by host.handler.Replace(nil) and wait for it to drain before calling
session.close(). Preserve the existing mutex, closed-state guard, session
detachment, and nil-handler replacement behavior, ensuring the webui.Application
session is closed only after in-flight requests complete.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: d237e84e-c85c-4265-bef3-860a25ef10cb

📥 Commits

Reviewing files that changed from the base of the PR and between 78af530 and b99820e.

📒 Files selected for processing (13)
  • Makefile
  • README.md
  • cmd/sith-desktop/frontend/.gitkeep
  • cmd/sith-desktop/wails.json
  • docs/adr/0010-native-local-desktop-shell.md
  • internal/cli/desktop.go
  • internal/cli/desktop_darwin.go
  • internal/cli/desktop_test.go
  • internal/webui/assets/app.js
  • internal/webui/desktop.go
  • internal/webui/desktop_test.go
  • internal/webui/server_test.go
  • sessions/2026-07-14-f11-native-desktop-shell.md
🚧 Files skipped from review as they are similar to previous changes (7)
  • cmd/sith-desktop/wails.json
  • docs/adr/0010-native-local-desktop-shell.md
  • internal/webui/assets/app.js
  • internal/cli/desktop_darwin.go
  • Makefile
  • README.md
  • internal/webui/server_test.go

@gnanirahulnutakki
gnanirahulnutakki merged commit 7f9302d into dev Jul 15, 2026
7 checks passed
@gnanirahulnutakki
gnanirahulnutakki deleted the gnanirahulnutakki/feat/f11-native-desktop-shell branch July 15, 2026 01:23
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