Skip to content

fix(qsys-mac-installer): fail fast on headless-SSH .NET installs - #13

Merged
reowens merged 1 commit into
mainfrom
fix/headless-ssh-preflight
Jul 11, 2026
Merged

reowens merged 1 commit into
mainfrom
fix/headless-ssh-preflight

Conversation

@reowens

@reowens reowens commented Jul 11, 2026

Copy link
Copy Markdown
Owner

Problem

The .NET runtime installer needs a macOS GUI (Aqua) session to create its window. Over a headless SSH-only login, Wine's winemac.drv can't reach one (nodrv_CreateWindow), so the runtime installs nothing. install_dotnet's landing assertion already catches this — but only after a ~250 MB download and two install attempts.

Change

Add a high-precision preflight probe is_headless_ssh() to preflight() that refuses up front, and only when we're confident it's headless:

  • reached over SSH (SSH_CONNECTION/SSH_TTY set), and
  • no user owns the GUI console (/dev/console owned by root).

So a local Terminal (no SSH_CONNECTION), a screen-sharing/VNC session (owns the console), and the GUI app path (Provisioner → provision.sh, SSH unset) all read as NOT headless — a working setup is never false-blocked. QSYS_ASSUME_GUI=1 overrides. The install_dotnet landing assertion stays as the correctness backstop.

launchctl managername == Aqua was rejected during verification: it returns Background in a plain local Terminal too, which would hard-block valid local runs — a regression worse than the status quo.

Tests

Adds a hermetic test in scripts/test.sh (mocks the console owner via a PATH stat shim, varies SSH_CONNECTION) asserting the probe fires on SSH + unowned console, stays silent on local and screen-sharing sessions, and honors the override. Full test.sh suite green locally including the Xcode build legs.

Verification

Context Result
Local (console owned by user, no SSH) not headless → preflight passes
Headless SSH (console=root) detected → preflight dies with guidance
Same + QSYS_ASSUME_GUI=1 override → proceeds

🤖 Generated with Claude Code

The .NET runtime installer needs a macOS GUI (Aqua) session for its
window; over a headless SSH login Wine's winemac.drv can't create one
(nodrv_CreateWindow) and the runtime installs nothing. install_dotnet's
landing assertion already catches this, but only after a ~250 MB
download and two install attempts.

Add a high-precision preflight probe (is_headless_ssh) that refuses up
front only when we're confident it's headless: reached over SSH AND no
user owns the GUI console (/dev/console == root). A local Terminal, a
screen-sharing/VNC session, and the GUI app path all read as NOT
headless, so a working setup is never false-blocked. QSYS_ASSUME_GUI=1
overrides. `launchctl managername` was rejected because it returns
"Background" in a plain local Terminal too. The install_dotnet assertion
stays as the correctness backstop.

Adds a hermetic test (mocks console owner via a PATH stat shim, varies
SSH_CONNECTION) covering all three paths.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@reowens
reowens merged commit 85d3950 into main Jul 11, 2026
3 checks passed
@reowens
reowens deleted the fix/headless-ssh-preflight branch July 11, 2026 17:57
reowens added a commit that referenced this pull request Jul 28, 2026
Ships the installer fixes that landed after 0.1.6:

- fail-fast pre-flight for headless-SSH .NET installs (#13, 85d3950)
- MSI path containment, allowlisted provisioning env, launcher
  WINEDLLOVERRIDES parity (7a20a2c — audit QTA-01/06/11)

Bumps both bundle plists, the generated launcher plist in lib/recipe.sh,
and the README release link to 0.1.7.

DMG sha256 5968ff8d7a58cee2d247773069b347a885305aa7a3cbfd2f729730564e481998

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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