Files
fleet/tools/hangar/scripts/dev.sh
T
Andrey KizimenkoandGeorge Karr 0f9af89a93 Add Hangar: Go/Wails desktop control panel for the Fleet dev environment (#46406)
## Summary

Adds `tools/hangar` — a macOS desktop control panel for working on Fleet
locally: branch management, `fleet serve` orchestration, log tail, dev
MySQL backup/restore, `fleetctl`, GitOps, and `osquery-perf`, all in one
window.

Built with **Go + [Wails 3](https://v3alpha.wails.io)** — the backend is
plain Go (`os/exec`, `syscall`, goroutines) so Fleet engineers can
contribute to it; only the desktop shell is Wails. The `internal/`
packages are pure and unit-tested.

### History note
Hangar started as a Rust/Tauri app. It was ported to Go, and **the Go
port is now the canonical `tools/hangar`**. The original Rust/Tauri
implementation has been removed from the monorepo (preserved in a
standalone repo) — so although this branch's earlier commits add and
then replace the Rust app, the net diff is just the Go app at
`tools/hangar`. The bundle identifier is `com.fleetdm.fleet-hangar`,
matching the original app so existing settings carry over.

# Checklist for submitter

- [x] Input data is properly validated, `SELECT *` is avoided, SQL
injection is prevented (using placeholders for values in statements), JS
inline code is prevented especially for url redirects, and untrusted
data interpolated into shell scripts/commands is validated against shell
metacharacters.
- [x] Timeouts are implemented and retries are limited to avoid infinite
loops

> No `changes/` file: `tools/` is contributor tooling, not a
user-visible Fleet change. No DB migrations, no Fleet config settings,
no fleetd/orbit changes.

## Testing

- [x] Added/updated automated tests (Go unit tests across `internal/`,
including a path-traversal regression for backup deletion)
- [x] QA'd all new/changed functionality manually

## Test plan
- [x] `cd tools/hangar && task dev` launches the app (live-reload)
- [x] `task build` produces `bin/fleet-hangar`; `go test ./...` is green
- [x] First-run gate discovers a local Fleet clone and runs dep checks
- [x] Server tab can run the build chain and start `fleet serve`
- [x] Git tab branch search finds an older branch (e.g. a stale `qa-*`)
by name


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Introduced Fleet Hangar, a comprehensive desktop application for Fleet
development workflows, providing unified controls for server/database
management, git operations, configuration, logging, and troubleshooting.
  * Added database backup management with metadata tracking.
* Integrated process orchestration for development services (Docker,
ngrok, Python).
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: George Karr <georgekarrv@users.noreply.github.com>
2026-06-23 15:45:23 -05:00

43 lines
1.7 KiB
Bash
Executable File

#!/usr/bin/env bash
# Dev wrapper for `wails3 dev` with reliable Ctrl+C teardown.
#
# wails3 dev launches the Vite dev server as a *detached* child (its own
# process group), so a plain Ctrl+C — delivered only to the foreground group —
# leaves Vite orphaned on the port ("address already in use" next run).
#
# We run wails3 as a *background job under job control* (`set -m`, so it gets
# its own process group) and `wait` on it. That keeps this shell free to run
# its trap the instant a signal arrives (running wails3 in the foreground
# would block the trap until wails3 exits — which it doesn't, hence the hang).
# On signal we tear down explicitly: wails3 + the app (its process group),
# then Vite (by port, since it's in a separate group).
set -uo pipefail
set -m
PORT="${1:-9245}"
cleanup() {
trap '' INT TERM # ignore repeat signals while we tear down
# Stop wails3 dev + the app (its process group). wails3 dev ignores SIGINT,
# so TERM it, then escalate to KILL if it lingers.
if [ -n "${WAILS:-}" ]; then
kill -TERM -"${WAILS}" 2>/dev/null || kill -TERM "${WAILS}" 2>/dev/null || true
sleep 0.3
if kill -0 -"${WAILS}" 2>/dev/null || kill -0 "${WAILS}" 2>/dev/null; then
kill -KILL -"${WAILS}" 2>/dev/null || kill -KILL "${WAILS}" 2>/dev/null || true
fi
fi
# Vite is detached into its own group by wails3 — free it by port.
local pids
pids="$(lsof -ti "tcp:${PORT}" 2>/dev/null || true)"
if [ -n "${pids}" ]; then
# shellcheck disable=SC2086 # intentional word-split: kill may take several PIDs
kill -KILL ${pids} 2>/dev/null || true
fi
}
trap cleanup INT TERM EXIT
wails3 dev -config ./build/config.yml -port "${PORT}" &
WAILS=$!
wait "${WAILS}"