feat(ssh): auto-provision a harness-server dev backend over SSH - #149
feat(ssh): auto-provision a harness-server dev backend over SSH#149big-guy wants to merge 1 commit into
Conversation
Consolidated branch work (collapsed onto base 22d025a). Headline is the SSH auto-provisioning flow; also folds in the merged headless-docker-scripts helpers, the welcome backend-identity feature, and the slice of main the merge carried in. SSH provisioning (Harness ships the installer, push-or-pull the server): - The bootstrap no longer curls install-headless.sh from a GitHub raw URL. Harness ships the installer (extraResources) and pipes it to the remote via `env <prefix> sh -s`, so the installer matches the version doing the bootstrap. Resolved via app.getAppPath() (chunk-safe), not __dirname. - Server bytes are auto-selected: upload mode probes the remote platform (uname) and, if a matching local tarball exists, putFiles it to /tmp and runs the installer in HARNESS_SERVER_TARBALL mode (no GitHub round-trip, coarse upload % streamed into the progress log); else download mode pulls a published release. HARNESS_PROVISION_RELEASE_ONLY / *_LOCAL_TARBALL / *_TARBALL_DIR override. - install-headless.sh gains a HARNESS_SERVER_TARBALL branch (skip download + version resolution, verify sibling .sha256 if present) and locates the extracted top-level dir generically. Opt-in cross-platform bundling for packaged builds: - resolveBundledServerDir() (dev release/headless, packaged resourcesPath/headless) + a gitignored resources/headless staging dir wired into extraResources with a tar.gz filter. - scripts/stage-server-tarballs.mjs + npm bundle:servers / pack:servers. Default builds stay lean; pack:servers ships the tarballs. Headless docker helpers: - pack-headless-linux.sh (Docker-based linux arm64/amd64 tarball build), run-headless-container.sh (clean bare remote — no tarball copied in; provisioned by the app), reset-headless-container.sh (SSH in, stop + uninstall harness-server), plus the VNC UI container helper. Welcome screen: - system:getBackendInfo surfaces the connected backend's host/uname/version; re-fetched per active backend so a remote shows the SERVER's identity, not the viewer's. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
@frenchie4111 I wasn't sure what was possible, so I had to prototype it. I played around with something like this trying to get #107 working locally without a lot of fuss. This builds on the other PR, but it adds two things:
I think this could be simplified by moving the download entirely into the app and have it push that over. Then install-headless just always unpacks a local tarball, regardless of how it got there. OTOH, there's some advantage to have the server download it directly. There are some build side changes to support building a bundled version of Harness, but the regular install doesn't change. My idea was that this would be a dev-only change because it makes testing easier. WDYT? To try this: Then try connecting to a backend with root@localhost:2223 This should connect, copy the tarball from Harness, install and start harness-server. You might need to make changes to .ssh/config to make this work, but |
Draft / spike stacked on
feat/ssh-bootstrap-remote(PR #107's SSH bootstrap).Extends the SSH bootstrap so Harness provisions a remote
harness-serveritself instead of relying on a fixed GitHub raw URL, and adds the Docker-based Linux build/run tooling to exercise it end-to-end.SSH provisioning — Harness ships the installer, push-or-pull the server
curlsinstall-headless.shfrom a hardcoded GitHub raw URL. Harness ships the installer (viaextraResources) and pipes it to the remote over the existing ssh2 connection (env <prefix> sh -s), so the installer always matches the version doing the bootstrap. Resolved viaapp.getAppPath()(chunk-safe), not__dirname.uname); if a matching locally-built tarball exists,putFileit to a/tmpstaging dir and run the installer inHARNESS_SERVER_TARBALLmode (no GitHub round-trip; coarse upload % streamed into the progress log).HARNESS_SERVER_BASE_URL/VERSIONhonored).HARNESS_PROVISION_RELEASE_ONLY,HARNESS_SERVER_LOCAL_TARBALL,HARNESS_SERVER_TARBALL_DIR.install-headless.shgains aHARNESS_SERVER_TARBALLbranch (skip download + version resolution, verify a sibling.sha256if present) and locates the extracted top-level dir generically.Opt-in cross-platform bundling for packaged builds
resolveBundledServerDir()(dev →release/headless/, packaged →process.resourcesPath/headless/) + a gitignoredresources/headless/staging dir wired intoextraResourceswith a tar.gz filter, so default builds carry no extra payload.scripts/stage-server-tarballs.mjs+ npmbundle:servers/pack:servers.Headless Docker tooling
pack-headless-linux.sh(Docker-based linux arm64/amd64 tarball build),run-headless-container.sh(a clean bare remote — no tarball copied in; provisioned by the app),reset-headless-container.sh(SSH in; stop + uninstallharness-serverand wipe~/.harness,~/.claude,~/.codex), and the VNC UI container helper.Welcome screen
system:getBackendInfosurfaces the connected backend's host/uname/version; re-fetched per active backend so a remote shows the server's identity, not the viewer's.Validated end-to-end: built linux arm64 + amd64 tarballs, spun up clean Ubuntu containers, and provisioned
harness-serverover SSH via upload mode (server installed + running + tunneled).🤖 Generated with Claude Code