Skip to content

Support desktop Remote SSH discovery and guest keyring authentication #480

Description

@hbrodin

Feature

Support the ChatGPT/Codex desktop app as a UI for Codex running inside a coop VM over Remote SSH. Users should be able to keep the desktop interface, including features such as speech input, while builds, shell commands, and project files stay in the guest. Speech input is a motivation for this workflow, not a capability independently verified in this investigation.

coop already generates an SSH alias with coop ssh-config. The desktop app can connect through that alias. The integration needs reliable guest authentication and a convenient way to discover or register the VM in the app.

Reproduced limitation

On a fresh macOS/Lima VM built from a rebuilt default image, with guest Codex CLI 0.154.0 installed through the native installer:

  1. Configure coop with [codex] auth = "chatgpt".
  2. Start a VM and generate its SSH configuration.
  3. Add the generated SSH host in the desktop app and select a guest project directory.
  4. Initiate the remote connection's Codex login flow and complete browser sign-in.

The Remote SSH connection succeeds, but browser sign-in reports:

Sign-in completed but credentials could not be saved locally.
Error code: persist_failed
failed to write OAuth tokens to keyring: Couldn't access platform secure storage: SS error: result not returned from SS API

The guest selects cli_auth_credentials_store = "keyring". The failure is saving the OAuth credentials in the guest, after SSH authentication and browser account sign-in succeed.

Evidence and diagnosis

In ChatGPT authentication mode, coop codex uses the codex-account wrapper to establish a D-Bus session, prompt for a guest keyring password, unlock GNOME Keyring, and launch Codex in that session.

The desktop app starts codex app-server directly through the remote login shell. That path bypasses the wrapper and does not inherit its unlocked keyring session.

On a VM with an existing encrypted keyring, remote server startup also stalled before its control socket became available. A bounded comparison probe showed that the server became ready with an existing unlocked keyring session, while the ordinary SSH environment did not become ready within the probe interval. On the fresh VM, server startup succeeded, but credential persistence failed. These are distinct failure states and should remain distinguishable in diagnostics.

Older coop images also use a Codex installation layout rejected by the native daemon-management command. Rebuilding the image resolved that separate prerequisite; merely creating another instance from an older image did not.

Research and implementation scope

Guest authentication and server lifecycle

  • Design a managed D-Bus/keyring session and app-server lifecycle that supports non-interactive desktop launches without borrowing another process's environment.
  • Define an explicit unlock flow when needed. Missing, locked, and unavailable keyrings should produce bounded, actionable failures.
  • Support reconnects without requiring an unrelated terminal session to remain open.
  • Cover VM restart, server crash, token refresh, logout, simultaneous CLI/desktop use, and cleanup after failed startup or destroy.
  • Prevent repeated connection attempts from leaving duplicate servers or conflicting socket owners.
  • Document native-install prerequisites and migration for existing images.
  • Assess compatibility with OpenAI credential-proxy mode separately from ChatGPT account authentication.

Preserve existing credential-storage guarantees. Do not silently fall back to plaintext credentials, copy host account credentials, or persist the keyring password to bypass unlocking. Any intentional authentication-policy change needs an explicit design decision.

Desktop host discovery and registration

Investigate whether coop can make a VM available in the desktop app automatically, analogous to coop ssh-config:

  • Verify the app's documented discovery of concrete SSH aliases and whether writing the alias is sufficient for it to appear without manual hostname entry.
  • Distinguish host discovery from enabling a connection, selecting a project, and authenticating. Do not assume discovery completes those steps.
  • Look for a supported CLI, deep link, or API for registering/opening an SSH host and guest project. If available, evaluate a coop command or extension to the editor integration that uses it.
  • Prefer supported interfaces; do not depend on editing undocumented application databases or private settings formats.
  • Define idempotent behavior for repeated setup, app-not-installed cases, VM restarts and changed SSH ports, VM recreation, and cleanup without deleting unrelated user connections.
  • If discovery is the only supported mechanism, document the remaining app steps and make the generated SSH alias easy to find.

Acceptance criteria

  • A fresh supported VM can be discovered or registered through the documented coop workflow.
  • The desktop app connects, guest credentials are saved to the intended store, and a real remote task completes.
  • Locked/missing keyrings, reconnects, restart, refresh/logout, and concurrent CLI/desktop use behave as documented.
  • Failed starts and VM teardown leave no unmanaged server processes or stale registration owned by the integration.
  • Documentation clearly separates desktop login, guest authentication, and execution location.
  • Validate desktop-to-Lima end to end and backend-shared authentication/lifecycle behavior on Firecracker where applicable; state untested combinations.

References

Additional reproduction: both authentication methods fail

The same fresh-VM workflow was subsequently tried with both browser-based ChatGPT sign-in and device-code sign-in. Browser sign-in repeated the persist_failed credential-storage failure. Device-code sign-in reported:

failed to write OAuth tokens to keyring: Platform secure storage failure: zbus error: org.freedesktop.DBus.Error.UnknownMethod: Object does not exist at path "/org/freedesktop/secrets/collection/login"

This error identifies a missing Secret Service login-collection object at the time of credential persistence. It does not by itself establish why the collection is absent, whether it was never initialized, or whether the server is using a different session/service instance. Changing the OAuth sign-in method does not resolve the shared credential-storage failure.

The investigation should cover collection creation and default-collection selection in addition to session-bus reachability and unlocking. Verify which Secret Service instance the app server uses, whether that instance exposes the intended collection, and how a fresh headless guest initializes it without relying on a graphical prompt. Test both browser and device-code sign-in against fresh, locked, and already-unlocked guest keyrings.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions