Skip to content

Ship a glibc 2.28 headless Linux binary for RHEL 8 and WSL hosts - #200

Open
jmcshane wants to merge 1 commit into
agentdesktop-dev:mainfrom
jmcshane:headless-linux-glibc-2-28
Open

jmcshane wants to merge 1 commit into
agentdesktop-dev:mainfrom
jmcshane:headless-linux-glibc-2-28

Conversation

@jmcshane

Copy link
Copy Markdown
Contributor

Problem

The agentdesktop-linux-* release binary does not start on RHEL 8 (and RHEL 8 under WSL2, as used on many virtual desktops), even for daemon and CLI commands:

./agentdesktop: error while loading shared libraries: libgdk-3.so.0: cannot open shared object file
./agentdesktop: error while loading shared libraries: libwebkit2gtk-4.1.so.0: cannot open shared object file

The binary contains the Tauri UI, so the loader needs GTK and WebKitGTK 4.1 before main() runs. It is also built on Ubuntu 22.04, so it needs GLIBC_2.34. RHEL 8 has glibc 2.28 and no WebKitGTK 4.1 (that arrived in RHEL 9), so installing packages cannot fix it.

Change

The daemon and CLI already exist without Tauri as the agentdesktop-headless bin in agentdesktop-agent, but it was never released. This PR ships it:

  • Release: new build-linux-headless-binaries job builds agentdesktop-headless inside manylinux_2_28 (glibc 2.28, pinned by digest) for amd64 and arm64. The binaries are attested with the existing Linux binaries and attached to the release as agentdesktop-headless-linux-{amd64,arm64}.
  • Portability check: .github/scripts/verify-linux-portability.sh fails when a binary needs glibc newer than a given version or links a library outside the base system set (libc, libm, libdl, libpthread, librt, libgcc_s, the loader). It runs in the release job and in a new CI job, so a glibc regression fails on the PR instead of at a customer.
  • Socket lookup: the desktop binary found a --user daemon through AGENTDESKTOP_SOCKET, then the system socket, then $XDG_RUNTIME_DIR / ~/.local/state. The headless binary only tried the system socket, so its CLI could not reach a user-mode daemon. The lookup moves to agentdesktop_core::client_socket_path() and both binaries use it.
  • Docs: README section for Linux without a desktop (RHEL 8, WSL, VDI): download, systemd user unit (with the WSL systemd=true note), and how sign-in works without a local browser.

No new dependencies. The headless binary has no GTK, WebKit, D-Bus, or OpenSSL dependency on Linux (TLS is rustls with aws-lc-rs).

Testing

Build and portability

  • Built agentdesktop-headless in manylinux_2_28 for aarch64 (locally) and x86_64 (on a cloud VM, using the same image digest as CI). In both builds the newest required symbol is GLIBC_2.28 and the only NEEDED entries are libc, libm, libdl, libpthread, libgcc_s and the loader. --version and daemon --help run.
  • cargo fmt --check, cargo clippy -D warnings (core and agent) and the agentdesktop-core tests pass. The agentdesktop desktop crate change is a rename to the shared function; CI covers its build because it needs WebKitGTK.

End to end on a RHEL 8-class WSL desktop behind an LLM gateway

To reproduce the reported environment, we built a short-lived Azure lab and deleted it after the test:

  • Desktop VM: Windows Server 2025 (D4ds_v5, nested virtualization) with WSL 3.0.3 and the official AlmaLinux 8.10 WSL image (RHEL 8 ABI, glibc 2.28, no WebKitGTK 4.1). systemd was left off, which is the WSL default, as on the reporting user's machine.
  • Gateway VM: Ubuntu 24.04 with agentgateway v1.6.0 on a private address. A /v1 route to OpenAI with jwtAuth in strict mode accepts only Microsoft Entra ID access tokens for the Agentdesktop app registration (v2.0 issuer, app audience, remote JWKS), and the gateway injects the OpenAI key upstream.
  • Agentdesktop config (in WSL): llmGateway.url points to the gateway, with authentication.type: oidc against Entra and programs.codex.useLlmGateway: true. Agentdesktop wrote Codex's provider (base_url = <gateway>/v1) with itself as the credential helper. No provider block was written by hand.

Steps and results:

  1. The released v0.3.0 agentdesktop-linux-amd64 fails in the WSL distro with the missing-library errors above. This reproduces the report.

  2. The headless binary from this branch, installed as ~/.local/bin/agentdesktop, starts on the same distro with no missing libraries.

  3. agentdesktop daemon --user ran in the foreground (no systemd). WSL has no browser, so the daemon printed the Entra sign-in URL. Opening it in Edge on the Windows host completed the OIDC flow through WSL's localhost forwarding to the daemon's 127.0.0.1 callback.

  4. Codex 0.164.0 (static musl build) in WSL sent requests through the gateway using the Agentdesktop-issued Entra token. Gateway access log, abbreviated:

    Source Request Status User (from JWT) Model
    desktop VM GET /v1/models?client_version=0.164.0 (×6) 200 the signed-in Entra user
    desktop VM POST /v1/responses (×2) 200 the signed-in Entra user gpt-5.6-terra
    gateway host, no token POST /v1/responses 401

    Requests with no token or a malformed token got 401.

Not covered here

  • The release workflow changes only run on a release. A workflow_dispatch run of Release with skip_github_release: true would exercise them before the next tag.
  • The new CI job runs on a Blacksmith runner with container:. If the runner does not support container jobs, move that job to ubuntu-24.04.
  • The manylinux digests are not updated by the current Dependabot config (it watches only the Dockerfile), so they need manual updates.
  • Corporate TLS-inspecting proxies: the LLM proxy's upstream client and the controller gRPC channel do not use HTTPS_PROXY, and the controller channel trusts only controller.caCertificatePath. That is a separate change.

🤖 Generated with Claude Code

The Linux release binary links GTK and WebKitGTK 4.1 through Tauri and is
built against glibc 2.35, so it fails to load on RHEL 8 (glibc 2.28, no
WebKitGTK 4.1) even for daemon and CLI commands.

- Build agentdesktop-headless (daemon + CLI, no Tauri) in a manylinux_2_28
  container (pinned by digest) for amd64 and arm64, attest it, and attach it to releases.
- Add verify-linux-portability.sh to fail when the binary needs a glibc newer
  than 2.28 or links a library outside the base system set; run it in CI and
  release.
- Move client socket resolution (AGENTDESKTOP_SOCKET, system socket, then the
  per-user socket) into agentdesktop-core so the headless CLI finds a user-mode
  daemon the same way the desktop binary does.
- Document the headless binary and a systemd user unit for RHEL 8, WSL and VDI.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

This branch has not been deployed

No deployments
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