Skip to content

fix(desktop): improve AppImage icons and remote environment#2538

Open
mwolson wants to merge 24 commits into
pingdotgg:mainfrom
mwolson:fix/linux-secret-store-backend
Open

fix(desktop): improve AppImage icons and remote environment#2538
mwolson wants to merge 24 commits into
pingdotgg:mainfrom
mwolson:fix/linux-secret-store-backend

Conversation

@mwolson
Copy link
Copy Markdown
Contributor

@mwolson mwolson commented May 6, 2026

Summary

  • Generates standard hicolor Linux icon sizes for AppImage builds so AppImageLauncher and desktop shells can resolve the installed app icon.
  • Fixes Linux AppImage/Niri remote environment pairing by configuring Electron's Linux startup options before ready, including --password-store, Wayland/X11 app class, and desktop scheme privileges.
  • Hydrates Linux desktop session environment values, including DBUS_SESSION_BUS_ADDRESS, so GNOME Keyring/libsecret is reachable when launching outside GNOME.
  • Hardens SSH remote environment auth by accepting JSON date strings from remote auth APIs and preserving/rolling back saved environment metadata consistently when bearer-token persistence fails.
  • Fixes saved SSH environment removal so deleting an environment cannot resurrect it on restart. Desktop now removes the saved environment record and embedded encrypted token in one atomic persistence operation before the UI clears local state or starts SSH cleanup.

Closes #2331.
Fixes #2539.

Diagnosis

The icon issue came from Linux AppImage builds staging only a single large icon.png. This PR stages a directory of standard icon sizes (16, 22, 24, 32, 48, 64, 128, 256, and 512) and points electron-builder at that directory. CI installs ImageMagick for Linux release builds so those sizes can be generated reliably.

The credential-store failure came from Electron selecting a non-encrypting Linux safeStorage backend when running under desktop environments it does not recognize, such as Niri. The app was also relying on shell/session environment values that may not be present when launched from an AppImage or desktop entry.

This PR moves the Linux Electron setup into the synchronous process bootstrap path so it happens before Electron emits ready, which is required for --password-store and privileged protocol registration to take effect. It also imports enough login/session environment to reach the user's DBus session bus and falls back to /run/user/$UID/bus when appropriate.

While testing the remote flow, two separate persistence issues showed up:

  • Auth responses returned JSON ISO date strings over the SSH HTTP bridge, while the contract expected already-materialized DateTime.Utc values.
  • Removing a saved SSH environment used two separate persistence writes: one fire-and-forget registry rewrite and one secret removal. Those writes could race, letting secret removal read the old record and write it back, so the environment reappeared after restart.

Scope

This is intentionally focused on Linux desktop/AppImage remote environment reliability. It does not change remote server behavior, and SSH process cleanup after removal remains fire-and-forget so the Settings UI does not hang if disconnect stalls.

Test plan

  • bun fmt
  • bun lint
  • bun typecheck
  • bun run test
  • bun run --filter @t3tools/desktop test -- DesktopEarlyElectronStartup DesktopEnvironment ElectronProtocol DesktopShellEnvironment linuxSecretStorage
  • bun run --filter @t3tools/desktop test -- DesktopSavedEnvironments
  • bun run --filter @t3tools/web test -- localApi service.addSavedEnvironment catalog
  • bun run dist:desktop:linux
  • Extracted AppImages and confirmed hicolor icon entries for 16, 22, 24, 32, 48, 64, 128, 256, and 512.
  • Built a local AppImage and launched it under Niri with T3CODE_HOME isolated.
  • Confirmed packaged logs report passwordStore: gnome-libsecret, backend: gnome_libsecret, and encryptionAvailable: true.
  • Installed with Shelly, added remote-game, and ran a trivial task on it.
  • Deleted remote-game, reinstalled/restarted, and confirmed the saved environment did not come back.

Note

Medium Risk
Touches Electron pre-ready bootstrap behavior, secret-storage/persistence flows, and shared auth date schemas, so regressions could affect Linux startup or remote environment pairing/removal.

Overview
Improves Linux desktop/AppImage packaging by generating a standard multi-size icons/ set during artifact builds (via ImageMagick) and updating release CI to install ImageMagick on Linux.

Reworks Linux desktop startup to apply Electron switches before ready (DBus session bus fallback, --password-store, WM_CLASS, and synchronous protocol privilege registration), adds a persisted linuxPasswordStore setting plus secret-storage backend diagnostics/remediation, and hydrates additional session env vars (notably DBUS_SESSION_BUS_ADDRESS).

Hardens saved environment and remote pairing flows: contracts now decode auth expiresAt from ISO strings, desktop/web add a removeSavedEnvironment IPC/API for atomic registry+secret removal, and web rollback logic preserves original credential-persistence errors when registry rollback fails.

Reviewed by Cursor Bugbot for commit d2d658c. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Generate multi-size AppImage icons and improve Linux remote environment handling

  • Linux builds now generate sized PNGs (16–512px) via ImageMagick into an icons/ directory (build-desktop-artifact.ts), replacing the single icon.png; the release workflow installs ImageMagick on Linux CI runners
  • Adds removeSavedEnvironment end-to-end: new IPC channel, desktop bridge method, persistence layer handler, and web-side LocalApi method with browser fallback
  • removeSavedEnvironment in service.ts now deletes the persisted record and updates in-memory state before non-blocking SSH cleanup; SSH cleanup failures are logged rather than surfaced
  • Introduces configurable Linux password-store preference persisted in desktop settings, applied via Electron command-line switches before app ready, with contextual error messages when secret storage is unavailable
  • On Linux, DBUS_SESSION_BUS_ADDRESS is now hydrated from the default unix socket path when unset, and additional XDG/desktop variables are propagated from the login shell
  • Auth*Result.expiresAt schemas changed from DateTimeUtc to DateTimeUtcFromString to correctly parse ISO string responses
  • Risk: The expiresAt schema change is a breaking behavioral change for any consumers expecting a pre-parsed Date object rather than parsing from a string

Macroscope summarized d2d658c.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 6, 2026

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: d24497c3-39e2-4692-8b5b-66717f4b6c56

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels May 6, 2026
@mwolson mwolson changed the title fix(desktop): improve Niri AppImage integration fix(desktop): improve Niri AppImage and remote environment May 6, 2026
@macroscopeapp
Copy link
Copy Markdown
Contributor

macroscopeapp Bot commented May 6, 2026

Approvability

Verdict: Needs human review

This PR introduces substantial new capabilities including Linux secret storage handling, a new IPC method for removing saved environments, and schema changes to auth contracts. An unresolved review comment questions whether layer restructuring affects Electron initialization order, which needs verification.

You can customize Macroscope's approvability policy. Learn more.

@mwolson mwolson force-pushed the fix/linux-secret-store-backend branch from dba46b4 to bfc4a7c Compare May 6, 2026 02:10
@mwolson
Copy link
Copy Markdown
Contributor Author

mwolson commented May 6, 2026

Before (missing icon)

Missing icon (works in shelly, doesn't work when appimage is launched directly, or with AppImageLauncher):

image

Before (secret manager)

Error when trying to add environment:

image

@mwolson
Copy link
Copy Markdown
Contributor Author

mwolson commented May 6, 2026

After (icons fix)

Launched appimage directly after chmod +x on it:

image

After (secrets-manager fix)

Screenshot from 2026-05-06 14-07-50-blur

Comment thread apps/web/src/environments/runtime/service.ts
@juliusmarminge
Copy link
Copy Markdown
Member

can you resolve conflcits here?

mwolson added 2 commits May 8, 2026 15:02
…ore-backend

# Conflicts:
#	apps/desktop/src/desktopSettings.test.ts
#	apps/desktop/src/desktopSettings.ts
#	apps/desktop/src/main.ts
@juliusmarminge
Copy link
Copy Markdown
Member

icon looks like this for me on ubuntu?
IMG_5075

@mwolson mwolson changed the title fix(desktop): improve Niri AppImage and remote environment fix(desktop): improve AppImage icons and remote environment May 9, 2026
@mwolson mwolson changed the title fix(desktop): improve AppImage icons and remote environment fix(desktop): harden Linux remote environments May 9, 2026
@github-actions github-actions Bot added size:XL 500-999 changed lines (additions + deletions). and removed size:L 100-499 changed lines (additions + deletions). labels May 9, 2026
@mwolson mwolson changed the title fix(desktop): harden Linux remote environments fix(desktop): improve AppImage icons and remote environment May 9, 2026
Comment thread apps/desktop/src/app/DesktopEarlyElectronStartup.ts
Comment thread apps/desktop/src/app/DesktopEarlyElectronStartup.ts Outdated
Copy link
Copy Markdown
Member

@juliusmarminge juliusmarminge left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tested on ubuntu and it works.

desktop app could use some cleanup to follow effect best practices more. i just cleaned it up a bunch so don't wanna move away directly

Comment thread apps/desktop/src/app/DesktopEnvironment.ts Outdated
registerDesktopSchemePrivilegesSync,
).pipe(Effect.withSpan("desktop.electron.protocol.registerSchemePrivileges"));

export const layerSchemePrivileges = Layer.effectDiscard(registerDesktopSchemePrivileges);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the way the layers were setup this ran before electron setup. not sure if you changed some layer structure so that's no longer the case?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, that ordering is still preserved. main.ts now calls configureElectronBeforeReady() synchronously at module startup, before building the Effect runtime/layers and before NodeRuntime.runMain.

I kept only the pre-ready Electron requirements there: registerSchemesAsPrivileged plus the Linux command-line switches. The file protocol handler still registers later after whenReady.

@mwolson mwolson requested a review from juliusmarminge May 9, 2026 20:57
@mwolson
Copy link
Copy Markdown
Contributor Author

mwolson commented May 9, 2026

@juliusmarminge fixed the issues you mentioned and re-smoked it on my end. If you don't want the AGENTS.md changes around Effect (or want different content there) let me know.

@juliusmarminge
Copy link
Copy Markdown
Member

I can look at it in a bit, but there's nothing that says that just cause it should run before electron it must run synchronously at module scope? The layer graph before was setup so that the protocol was the first thing that executed before the main effect program? Was there an issue with that? We create the electron app inside the effect program ye?

Comment thread apps/desktop/src/shell/DesktopShellEnvironment.ts
@mwolson
Copy link
Copy Markdown
Contributor Author

mwolson commented May 9, 2026

I can look at it in a bit, but there's nothing that says that just cause it should run before electron it must run synchronously at module scope? The layer graph before was setup so that the protocol was the first thing that executed before the main effect program? Was there an issue with that? We create the electron app inside the effect program ye?

Good points; I moved this back into the Effect startup graph as an explicit first layer with Layer.flatMap, and isolated the synchronous process/fs reads in a small pre-ready platform adapter. That keeps the Electron pre-ready ordering intact without doing the setup at module scope. (Also updated AGENTS.md guidance to match.)

Comment thread apps/desktop/src/app/DesktopEarlyElectronStartup.ts Outdated
Comment thread apps/web/src/environments/runtime/service.ts
Comment thread apps/web/src/environments/runtime/service.ts
Copy link
Copy Markdown
Contributor

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 8863f9e. Configure here.

Comment thread apps/desktop/src/app/DesktopApp.ts
@mwolson
Copy link
Copy Markdown
Contributor Author

mwolson commented May 12, 2026

@juliusmarminge I've addressed the earlier feedback, merged latest main, and went through several rounds of bugbot feedback, so it's ready for another look as time allows.

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

Labels

size:XL 500-999 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Niri AppImage cannot save remote environment credentials [Bug]: AppImage installed by AppImageLauncher lacks usable Linux desktop icon

2 participants