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

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

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

Conversation

@mwolson

@mwolsonmwolson commented May 6, 2026

Copy link
Copy Markdown
Contributor

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 Linux Electron startup, encrypted credential persistence, and shared auth schema decoding; saved-environment removal ordering changed but covered by tests.

Overview
Improves Linux AppImage packaging and remote saved-environment reliability on non-GNOME desktops (e.g. Niri).

Linux desktop bootstrap now applies Electron options before ready: persisted linuxPasswordStore, --password-store heuristics for unrecognized sessions, WM class, synchronous t3 scheme privileges, and optional DBUS_SESSION_BUS_ADDRESS from /run/user/$UID/bus. Login-shell hydration also pulls more XDG/desktop vars. Secret save failures return Keyring/KWallet guidance via selectedStorageBackend.

Saved environments: new removeSavedEnvironment IPC/persistence removes registry + encrypted token in one write; the web layer deletes persisted state first and runs SSH disconnect in the background. Bearer-token persistence uses clearer rollback (preserves primary errors) and replaces stale SSH records via atomic remove.

Remote auth over SSH HTTP decodes expiresAt from ISO strings (DateTimeUtcFromString in contracts).

Release/build: Linux CI installs ImageMagick; desktop Linux artifacts stage hicolor-sized icons (icons/ dir) instead of a single PNG.

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

Note

Improve Linux AppImage icons and remote environment credential management

  • Linux AppImage builds now generate multi-size icons (16–512px) via ImageMagick into a resources/icons directory; electron-builder is updated to point at this directory instead of a single icon.png
  • Adds a removeSavedEnvironment method end-to-end: IPC channel, preload bridge, DesktopSavedEnvironments service, LocalApi persistence, and web-side catalog/store update
  • Introduces linuxSecretStorage.ts with helpers to normalize password-store preferences, resolve the Electron --password-store switch, and generate platform-appropriate remediation messages when secret storage is unavailable
  • Pre-ready Linux Electron startup now resolves DBUS session bus address, WM class, and password-store switch from a settings file before app.ready, and logs the safe storage backend after ready
  • DesktopShellEnvironment hydrates additional XDG/Wayland/DBus environment variables from the login shell and auto-discovers DBUS_SESSION_BUS_ADDRESS via the XDG runtime dir socket
  • expiresAt fields in auth contract schemas (AuthBootstrapResult, AuthBearerBootstrapResult, AuthWebSocketTokenResult, AuthSessionState) are changed from DateTimeUtc to DateTimeUtcFromString for correct JSON decoding
  • Risk: removing a saved environment no longer explicitly removes the bearer token; SSH cleanup is non-blocking and failures are only logged

Macroscope summarized 2273d3e.

@coderabbitai

coderabbitaiBot commented May 6, 2026

Copy link
Copy Markdown

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: 25c2c134-e105-40a1-a107-735b64a8e3f5

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

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-actionsgithub-actionsBot 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
@mwolsonmwolson changed the title fix(desktop): improve Niri AppImage integrationfix(desktop): improve Niri AppImage and remote environmentMay 6, 2026
@macroscopeapp

macroscopeappBot commented May 6, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR introduces significant new Linux platform behavior including password store detection, DBus session bus address resolution, new IPC methods, and schema changes affecting DateTime serialization. An unresolved comment also questions whether Electron scheme privilege registration timing was affected by the layer restructuring.

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

@mwolson
mwolsonforce-pushed the fix/linux-secret-store-backend branch from dba46b4 to bfc4a7cCompareMay 6, 2026 02:10
@mwolson

Copy link
Copy Markdown
ContributorAuthor

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
ContributorAuthor

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 threadapps/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

@mwolsonmwolson changed the title fix(desktop): improve Niri AppImage and remote environmentfix(desktop): improve AppImage icons and remote environmentMay 9, 2026
@mwolsonmwolson changed the title fix(desktop): improve AppImage icons and remote environmentfix(desktop): harden Linux remote environmentsMay 9, 2026
@github-actionsgithub-actionsBot added size:XL 500-999 changed lines (additions + deletions). and removed size:L 100-499 changed lines (additions + deletions). labels May 9, 2026
@mwolsonmwolson changed the title fix(desktop): harden Linux remote environmentsfix(desktop): improve AppImage icons and remote environmentMay 9, 2026
Comment threadapps/desktop/src/app/DesktopEarlyElectronStartup.ts
Comment threadapps/desktop/src/app/DesktopEarlyElectronStartup.ts Outdated

@juliusmarmingejuliusmarminge left a comment

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.

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 threadapps/desktop/src/app/DesktopEnvironment.ts Outdated
Comment threadapps/desktop/src/electron/ElectronProtocol.ts Outdated
@mwolson

Copy link
Copy Markdown
ContributorAuthor

@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 threadapps/desktop/src/shell/DesktopShellEnvironment.ts
@mwolson

Copy link
Copy Markdown
ContributorAuthor

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 threadapps/desktop/src/app/DesktopEarlyElectronStartup.ts Outdated
Comment threadapps/web/src/environments/runtime/service.ts
Comment threadapps/web/src/environments/runtime/service.ts

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

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 threadapps/desktop/src/app/DesktopApp.ts
@mwolson

Copy link
Copy Markdown
ContributorAuthor

@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.

@mwolson

Copy link
Copy Markdown
ContributorAuthor

@juliusmarminge I've merged main again to update the branch; if you'd rather have me split out the appimage work (which from our conversation ~1 month ago seemed to be tested on Ubuntu and went well), let me know, either way.

@mwolson

Copy link
Copy Markdown
ContributorAuthor

Thanks for taking a look at this larger branch. I split it into focused follow-up PRs so each fix can be reviewed independently:

I am closing this original combined PR in favor of those smaller PRs.

@mwolsonmwolson closed this Jun 2, 2026
@mwolson
mwolson deleted the fix/linux-secret-store-backend branch June 3, 2026 12:43
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL500-999 changed lines (additions + deletions).vouch:unvouchedPR 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

@mwolson@juliusmarminge
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

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

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

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

Conversation

@mwolson

@mwolsonmwolson commented May 6, 2026

Copy link
Copy Markdown
Contributor

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 Linux Electron startup, encrypted credential persistence, and shared auth schema decoding; saved-environment removal ordering changed but covered by tests.

Overview
Improves Linux AppImage packaging and remote saved-environment reliability on non-GNOME desktops (e.g. Niri).

Linux desktop bootstrap now applies Electron options before ready: persisted linuxPasswordStore, --password-store heuristics for unrecognized sessions, WM class, synchronous t3 scheme privileges, and optional DBUS_SESSION_BUS_ADDRESS from /run/user/$UID/bus. Login-shell hydration also pulls more XDG/desktop vars. Secret save failures return Keyring/KWallet guidance via selectedStorageBackend.

Saved environments: new removeSavedEnvironment IPC/persistence removes registry + encrypted token in one write; the web layer deletes persisted state first and runs SSH disconnect in the background. Bearer-token persistence uses clearer rollback (preserves primary errors) and replaces stale SSH records via atomic remove.

Remote auth over SSH HTTP decodes expiresAt from ISO strings (DateTimeUtcFromString in contracts).

Release/build: Linux CI installs ImageMagick; desktop Linux artifacts stage hicolor-sized icons (icons/ dir) instead of a single PNG.

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

Note

Improve Linux AppImage icons and remote environment credential management

  • Linux AppImage builds now generate multi-size icons (16–512px) via ImageMagick into a resources/icons directory; electron-builder is updated to point at this directory instead of a single icon.png
  • Adds a removeSavedEnvironment method end-to-end: IPC channel, preload bridge, DesktopSavedEnvironments service, LocalApi persistence, and web-side catalog/store update
  • Introduces linuxSecretStorage.ts with helpers to normalize password-store preferences, resolve the Electron --password-store switch, and generate platform-appropriate remediation messages when secret storage is unavailable
  • Pre-ready Linux Electron startup now resolves DBUS session bus address, WM class, and password-store switch from a settings file before app.ready, and logs the safe storage backend after ready
  • DesktopShellEnvironment hydrates additional XDG/Wayland/DBus environment variables from the login shell and auto-discovers DBUS_SESSION_BUS_ADDRESS via the XDG runtime dir socket
  • expiresAt fields in auth contract schemas (AuthBootstrapResult, AuthBearerBootstrapResult, AuthWebSocketTokenResult, AuthSessionState) are changed from DateTimeUtc to DateTimeUtcFromString for correct JSON decoding
  • Risk: removing a saved environment no longer explicitly removes the bearer token; SSH cleanup is non-blocking and failures are only logged

Macroscope summarized 2273d3e.

@coderabbitai

coderabbitaiBot commented May 6, 2026

Copy link
Copy Markdown

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: 25c2c134-e105-40a1-a107-735b64a8e3f5

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

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-actionsgithub-actionsBot 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
@mwolsonmwolson changed the title fix(desktop): improve Niri AppImage integrationfix(desktop): improve Niri AppImage and remote environmentMay 6, 2026
@macroscopeapp

macroscopeappBot commented May 6, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR introduces significant new Linux platform behavior including password store detection, DBus session bus address resolution, new IPC methods, and schema changes affecting DateTime serialization. An unresolved comment also questions whether Electron scheme privilege registration timing was affected by the layer restructuring.

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

@mwolson
mwolsonforce-pushed the fix/linux-secret-store-backend branch from dba46b4 to bfc4a7cCompareMay 6, 2026 02:10
@mwolson

Copy link
Copy Markdown
ContributorAuthor

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
ContributorAuthor

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 threadapps/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

@mwolsonmwolson changed the title fix(desktop): improve Niri AppImage and remote environmentfix(desktop): improve AppImage icons and remote environmentMay 9, 2026
@mwolsonmwolson changed the title fix(desktop): improve AppImage icons and remote environmentfix(desktop): harden Linux remote environmentsMay 9, 2026
@github-actionsgithub-actionsBot added size:XL 500-999 changed lines (additions + deletions). and removed size:L 100-499 changed lines (additions + deletions). labels May 9, 2026
@mwolsonmwolson changed the title fix(desktop): harden Linux remote environmentsfix(desktop): improve AppImage icons and remote environmentMay 9, 2026
Comment threadapps/desktop/src/app/DesktopEarlyElectronStartup.ts
Comment threadapps/desktop/src/app/DesktopEarlyElectronStartup.ts Outdated

@juliusmarmingejuliusmarminge left a comment

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.

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 threadapps/desktop/src/app/DesktopEnvironment.ts Outdated
Comment threadapps/desktop/src/electron/ElectronProtocol.ts Outdated
@mwolson

Copy link
Copy Markdown
ContributorAuthor

@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 threadapps/desktop/src/shell/DesktopShellEnvironment.ts
@mwolson

Copy link
Copy Markdown
ContributorAuthor

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 threadapps/desktop/src/app/DesktopEarlyElectronStartup.ts Outdated
Comment threadapps/web/src/environments/runtime/service.ts
Comment threadapps/web/src/environments/runtime/service.ts

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

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 threadapps/desktop/src/app/DesktopApp.ts
@mwolson

Copy link
Copy Markdown
ContributorAuthor

@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.

@mwolson

Copy link
Copy Markdown
ContributorAuthor

@juliusmarminge I've merged main again to update the branch; if you'd rather have me split out the appimage work (which from our conversation ~1 month ago seemed to be tested on Ubuntu and went well), let me know, either way.

@mwolson

Copy link
Copy Markdown
ContributorAuthor

Thanks for taking a look at this larger branch. I split it into focused follow-up PRs so each fix can be reviewed independently:

I am closing this original combined PR in favor of those smaller PRs.

@mwolsonmwolson closed this Jun 2, 2026
@mwolson
mwolson deleted the fix/linux-secret-store-backend branch June 3, 2026 12:43
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL500-999 changed lines (additions + deletions).vouch:unvouchedPR 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

@mwolson@juliusmarminge
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

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

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

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

Conversation

@mwolson

@mwolsonmwolson commented May 6, 2026

Copy link
Copy Markdown
Contributor

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 Linux Electron startup, encrypted credential persistence, and shared auth schema decoding; saved-environment removal ordering changed but covered by tests.

Overview
Improves Linux AppImage packaging and remote saved-environment reliability on non-GNOME desktops (e.g. Niri).

Linux desktop bootstrap now applies Electron options before ready: persisted linuxPasswordStore, --password-store heuristics for unrecognized sessions, WM class, synchronous t3 scheme privileges, and optional DBUS_SESSION_BUS_ADDRESS from /run/user/$UID/bus. Login-shell hydration also pulls more XDG/desktop vars. Secret save failures return Keyring/KWallet guidance via selectedStorageBackend.

Saved environments: new removeSavedEnvironment IPC/persistence removes registry + encrypted token in one write; the web layer deletes persisted state first and runs SSH disconnect in the background. Bearer-token persistence uses clearer rollback (preserves primary errors) and replaces stale SSH records via atomic remove.

Remote auth over SSH HTTP decodes expiresAt from ISO strings (DateTimeUtcFromString in contracts).

Release/build: Linux CI installs ImageMagick; desktop Linux artifacts stage hicolor-sized icons (icons/ dir) instead of a single PNG.

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

Note

Improve Linux AppImage icons and remote environment credential management

  • Linux AppImage builds now generate multi-size icons (16–512px) via ImageMagick into a resources/icons directory; electron-builder is updated to point at this directory instead of a single icon.png
  • Adds a removeSavedEnvironment method end-to-end: IPC channel, preload bridge, DesktopSavedEnvironments service, LocalApi persistence, and web-side catalog/store update
  • Introduces linuxSecretStorage.ts with helpers to normalize password-store preferences, resolve the Electron --password-store switch, and generate platform-appropriate remediation messages when secret storage is unavailable
  • Pre-ready Linux Electron startup now resolves DBUS session bus address, WM class, and password-store switch from a settings file before app.ready, and logs the safe storage backend after ready
  • DesktopShellEnvironment hydrates additional XDG/Wayland/DBus environment variables from the login shell and auto-discovers DBUS_SESSION_BUS_ADDRESS via the XDG runtime dir socket
  • expiresAt fields in auth contract schemas (AuthBootstrapResult, AuthBearerBootstrapResult, AuthWebSocketTokenResult, AuthSessionState) are changed from DateTimeUtc to DateTimeUtcFromString for correct JSON decoding
  • Risk: removing a saved environment no longer explicitly removes the bearer token; SSH cleanup is non-blocking and failures are only logged

Macroscope summarized 2273d3e.

@coderabbitai

coderabbitaiBot commented May 6, 2026

Copy link
Copy Markdown

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: 25c2c134-e105-40a1-a107-735b64a8e3f5

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

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-actionsgithub-actionsBot 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
@mwolsonmwolson changed the title fix(desktop): improve Niri AppImage integrationfix(desktop): improve Niri AppImage and remote environmentMay 6, 2026
@macroscopeapp

macroscopeappBot commented May 6, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR introduces significant new Linux platform behavior including password store detection, DBus session bus address resolution, new IPC methods, and schema changes affecting DateTime serialization. An unresolved comment also questions whether Electron scheme privilege registration timing was affected by the layer restructuring.

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

@mwolson
mwolsonforce-pushed the fix/linux-secret-store-backend branch from dba46b4 to bfc4a7cCompareMay 6, 2026 02:10
@mwolson

Copy link
Copy Markdown
ContributorAuthor

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
ContributorAuthor

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 threadapps/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

@mwolsonmwolson changed the title fix(desktop): improve Niri AppImage and remote environmentfix(desktop): improve AppImage icons and remote environmentMay 9, 2026
@mwolsonmwolson changed the title fix(desktop): improve AppImage icons and remote environmentfix(desktop): harden Linux remote environmentsMay 9, 2026
@github-actionsgithub-actionsBot added size:XL 500-999 changed lines (additions + deletions). and removed size:L 100-499 changed lines (additions + deletions). labels May 9, 2026
@mwolsonmwolson changed the title fix(desktop): harden Linux remote environmentsfix(desktop): improve AppImage icons and remote environmentMay 9, 2026
Comment threadapps/desktop/src/app/DesktopEarlyElectronStartup.ts
Comment threadapps/desktop/src/app/DesktopEarlyElectronStartup.ts Outdated

@juliusmarmingejuliusmarminge left a comment

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.

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 threadapps/desktop/src/app/DesktopEnvironment.ts Outdated
Comment threadapps/desktop/src/electron/ElectronProtocol.ts Outdated
@mwolson

Copy link
Copy Markdown
ContributorAuthor

@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 threadapps/desktop/src/shell/DesktopShellEnvironment.ts
@mwolson

Copy link
Copy Markdown
ContributorAuthor

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 threadapps/desktop/src/app/DesktopEarlyElectronStartup.ts Outdated
Comment threadapps/web/src/environments/runtime/service.ts
Comment threadapps/web/src/environments/runtime/service.ts

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

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 threadapps/desktop/src/app/DesktopApp.ts
@mwolson

Copy link
Copy Markdown
ContributorAuthor

@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.

@mwolson

Copy link
Copy Markdown
ContributorAuthor

@juliusmarminge I've merged main again to update the branch; if you'd rather have me split out the appimage work (which from our conversation ~1 month ago seemed to be tested on Ubuntu and went well), let me know, either way.

@mwolson

Copy link
Copy Markdown
ContributorAuthor

Thanks for taking a look at this larger branch. I split it into focused follow-up PRs so each fix can be reviewed independently:

I am closing this original combined PR in favor of those smaller PRs.

@mwolsonmwolson closed this Jun 2, 2026
@mwolson
mwolson deleted the fix/linux-secret-store-backend branch June 3, 2026 12:43
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL500-999 changed lines (additions + deletions).vouch:unvouchedPR 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

@mwolson@juliusmarminge
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

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

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

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

Conversation

@mwolson

@mwolsonmwolson commented May 6, 2026

Copy link
Copy Markdown
Contributor

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 Linux Electron startup, encrypted credential persistence, and shared auth schema decoding; saved-environment removal ordering changed but covered by tests.

Overview
Improves Linux AppImage packaging and remote saved-environment reliability on non-GNOME desktops (e.g. Niri).

Linux desktop bootstrap now applies Electron options before ready: persisted linuxPasswordStore, --password-store heuristics for unrecognized sessions, WM class, synchronous t3 scheme privileges, and optional DBUS_SESSION_BUS_ADDRESS from /run/user/$UID/bus. Login-shell hydration also pulls more XDG/desktop vars. Secret save failures return Keyring/KWallet guidance via selectedStorageBackend.

Saved environments: new removeSavedEnvironment IPC/persistence removes registry + encrypted token in one write; the web layer deletes persisted state first and runs SSH disconnect in the background. Bearer-token persistence uses clearer rollback (preserves primary errors) and replaces stale SSH records via atomic remove.

Remote auth over SSH HTTP decodes expiresAt from ISO strings (DateTimeUtcFromString in contracts).

Release/build: Linux CI installs ImageMagick; desktop Linux artifacts stage hicolor-sized icons (icons/ dir) instead of a single PNG.

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

Note

Improve Linux AppImage icons and remote environment credential management

  • Linux AppImage builds now generate multi-size icons (16–512px) via ImageMagick into a resources/icons directory; electron-builder is updated to point at this directory instead of a single icon.png
  • Adds a removeSavedEnvironment method end-to-end: IPC channel, preload bridge, DesktopSavedEnvironments service, LocalApi persistence, and web-side catalog/store update
  • Introduces linuxSecretStorage.ts with helpers to normalize password-store preferences, resolve the Electron --password-store switch, and generate platform-appropriate remediation messages when secret storage is unavailable
  • Pre-ready Linux Electron startup now resolves DBUS session bus address, WM class, and password-store switch from a settings file before app.ready, and logs the safe storage backend after ready
  • DesktopShellEnvironment hydrates additional XDG/Wayland/DBus environment variables from the login shell and auto-discovers DBUS_SESSION_BUS_ADDRESS via the XDG runtime dir socket
  • expiresAt fields in auth contract schemas (AuthBootstrapResult, AuthBearerBootstrapResult, AuthWebSocketTokenResult, AuthSessionState) are changed from DateTimeUtc to DateTimeUtcFromString for correct JSON decoding
  • Risk: removing a saved environment no longer explicitly removes the bearer token; SSH cleanup is non-blocking and failures are only logged

Macroscope summarized 2273d3e.

@coderabbitai

coderabbitaiBot commented May 6, 2026

Copy link
Copy Markdown

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: 25c2c134-e105-40a1-a107-735b64a8e3f5

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

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-actionsgithub-actionsBot 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
@mwolsonmwolson changed the title fix(desktop): improve Niri AppImage integrationfix(desktop): improve Niri AppImage and remote environmentMay 6, 2026
@macroscopeapp

macroscopeappBot commented May 6, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR introduces significant new Linux platform behavior including password store detection, DBus session bus address resolution, new IPC methods, and schema changes affecting DateTime serialization. An unresolved comment also questions whether Electron scheme privilege registration timing was affected by the layer restructuring.

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

@mwolson
mwolsonforce-pushed the fix/linux-secret-store-backend branch from dba46b4 to bfc4a7cCompareMay 6, 2026 02:10
@mwolson

Copy link
Copy Markdown
ContributorAuthor

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
ContributorAuthor

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 threadapps/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

@mwolsonmwolson changed the title fix(desktop): improve Niri AppImage and remote environmentfix(desktop): improve AppImage icons and remote environmentMay 9, 2026
@mwolsonmwolson changed the title fix(desktop): improve AppImage icons and remote environmentfix(desktop): harden Linux remote environmentsMay 9, 2026
@github-actionsgithub-actionsBot added size:XL 500-999 changed lines (additions + deletions). and removed size:L 100-499 changed lines (additions + deletions). labels May 9, 2026
@mwolsonmwolson changed the title fix(desktop): harden Linux remote environmentsfix(desktop): improve AppImage icons and remote environmentMay 9, 2026
Comment threadapps/desktop/src/app/DesktopEarlyElectronStartup.ts
Comment threadapps/desktop/src/app/DesktopEarlyElectronStartup.ts Outdated

@juliusmarmingejuliusmarminge left a comment

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.

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 threadapps/desktop/src/app/DesktopEnvironment.ts Outdated
Comment threadapps/desktop/src/electron/ElectronProtocol.ts Outdated
@mwolson

Copy link
Copy Markdown
ContributorAuthor

@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 threadapps/desktop/src/shell/DesktopShellEnvironment.ts
@mwolson

Copy link
Copy Markdown
ContributorAuthor

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 threadapps/desktop/src/app/DesktopEarlyElectronStartup.ts Outdated
Comment threadapps/web/src/environments/runtime/service.ts
Comment threadapps/web/src/environments/runtime/service.ts

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

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 threadapps/desktop/src/app/DesktopApp.ts
@mwolson

Copy link
Copy Markdown
ContributorAuthor

@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.

@mwolson

Copy link
Copy Markdown
ContributorAuthor

@juliusmarminge I've merged main again to update the branch; if you'd rather have me split out the appimage work (which from our conversation ~1 month ago seemed to be tested on Ubuntu and went well), let me know, either way.

@mwolson

Copy link
Copy Markdown
ContributorAuthor

Thanks for taking a look at this larger branch. I split it into focused follow-up PRs so each fix can be reviewed independently:

I am closing this original combined PR in favor of those smaller PRs.

@mwolsonmwolson closed this Jun 2, 2026
@mwolson
mwolson deleted the fix/linux-secret-store-backend branch June 3, 2026 12:43
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL500-999 changed lines (additions + deletions).vouch:unvouchedPR 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

@mwolson@juliusmarminge
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

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

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

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

Conversation

@mwolson

@mwolsonmwolson commented May 6, 2026

Copy link
Copy Markdown
Contributor

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 Linux Electron startup, encrypted credential persistence, and shared auth schema decoding; saved-environment removal ordering changed but covered by tests.

Overview
Improves Linux AppImage packaging and remote saved-environment reliability on non-GNOME desktops (e.g. Niri).

Linux desktop bootstrap now applies Electron options before ready: persisted linuxPasswordStore, --password-store heuristics for unrecognized sessions, WM class, synchronous t3 scheme privileges, and optional DBUS_SESSION_BUS_ADDRESS from /run/user/$UID/bus. Login-shell hydration also pulls more XDG/desktop vars. Secret save failures return Keyring/KWallet guidance via selectedStorageBackend.

Saved environments: new removeSavedEnvironment IPC/persistence removes registry + encrypted token in one write; the web layer deletes persisted state first and runs SSH disconnect in the background. Bearer-token persistence uses clearer rollback (preserves primary errors) and replaces stale SSH records via atomic remove.

Remote auth over SSH HTTP decodes expiresAt from ISO strings (DateTimeUtcFromString in contracts).

Release/build: Linux CI installs ImageMagick; desktop Linux artifacts stage hicolor-sized icons (icons/ dir) instead of a single PNG.

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

Note

Improve Linux AppImage icons and remote environment credential management

  • Linux AppImage builds now generate multi-size icons (16–512px) via ImageMagick into a resources/icons directory; electron-builder is updated to point at this directory instead of a single icon.png
  • Adds a removeSavedEnvironment method end-to-end: IPC channel, preload bridge, DesktopSavedEnvironments service, LocalApi persistence, and web-side catalog/store update
  • Introduces linuxSecretStorage.ts with helpers to normalize password-store preferences, resolve the Electron --password-store switch, and generate platform-appropriate remediation messages when secret storage is unavailable
  • Pre-ready Linux Electron startup now resolves DBUS session bus address, WM class, and password-store switch from a settings file before app.ready, and logs the safe storage backend after ready
  • DesktopShellEnvironment hydrates additional XDG/Wayland/DBus environment variables from the login shell and auto-discovers DBUS_SESSION_BUS_ADDRESS via the XDG runtime dir socket
  • expiresAt fields in auth contract schemas (AuthBootstrapResult, AuthBearerBootstrapResult, AuthWebSocketTokenResult, AuthSessionState) are changed from DateTimeUtc to DateTimeUtcFromString for correct JSON decoding
  • Risk: removing a saved environment no longer explicitly removes the bearer token; SSH cleanup is non-blocking and failures are only logged

Macroscope summarized 2273d3e.

@coderabbitai

coderabbitaiBot commented May 6, 2026

Copy link
Copy Markdown

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: 25c2c134-e105-40a1-a107-735b64a8e3f5

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

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-actionsgithub-actionsBot 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
@mwolsonmwolson changed the title fix(desktop): improve Niri AppImage integrationfix(desktop): improve Niri AppImage and remote environmentMay 6, 2026
@macroscopeapp

macroscopeappBot commented May 6, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR introduces significant new Linux platform behavior including password store detection, DBus session bus address resolution, new IPC methods, and schema changes affecting DateTime serialization. An unresolved comment also questions whether Electron scheme privilege registration timing was affected by the layer restructuring.

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

@mwolson
mwolsonforce-pushed the fix/linux-secret-store-backend branch from dba46b4 to bfc4a7cCompareMay 6, 2026 02:10
@mwolson

Copy link
Copy Markdown
ContributorAuthor

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
ContributorAuthor

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 threadapps/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

@mwolsonmwolson changed the title fix(desktop): improve Niri AppImage and remote environmentfix(desktop): improve AppImage icons and remote environmentMay 9, 2026
@mwolsonmwolson changed the title fix(desktop): improve AppImage icons and remote environmentfix(desktop): harden Linux remote environmentsMay 9, 2026
@github-actionsgithub-actionsBot added size:XL 500-999 changed lines (additions + deletions). and removed size:L 100-499 changed lines (additions + deletions). labels May 9, 2026
@mwolsonmwolson changed the title fix(desktop): harden Linux remote environmentsfix(desktop): improve AppImage icons and remote environmentMay 9, 2026
Comment threadapps/desktop/src/app/DesktopEarlyElectronStartup.ts
Comment threadapps/desktop/src/app/DesktopEarlyElectronStartup.ts Outdated

@juliusmarmingejuliusmarminge left a comment

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.

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 threadapps/desktop/src/app/DesktopEnvironment.ts Outdated
Comment threadapps/desktop/src/electron/ElectronProtocol.ts Outdated
@mwolson

Copy link
Copy Markdown
ContributorAuthor

@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 threadapps/desktop/src/shell/DesktopShellEnvironment.ts
@mwolson

Copy link
Copy Markdown
ContributorAuthor

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 threadapps/desktop/src/app/DesktopEarlyElectronStartup.ts Outdated
Comment threadapps/web/src/environments/runtime/service.ts
Comment threadapps/web/src/environments/runtime/service.ts

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

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 threadapps/desktop/src/app/DesktopApp.ts
@mwolson

Copy link
Copy Markdown
ContributorAuthor

@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.

@mwolson

Copy link
Copy Markdown
ContributorAuthor

@juliusmarminge I've merged main again to update the branch; if you'd rather have me split out the appimage work (which from our conversation ~1 month ago seemed to be tested on Ubuntu and went well), let me know, either way.

@mwolson

Copy link
Copy Markdown
ContributorAuthor

Thanks for taking a look at this larger branch. I split it into focused follow-up PRs so each fix can be reviewed independently:

I am closing this original combined PR in favor of those smaller PRs.

@mwolsonmwolson closed this Jun 2, 2026
@mwolson
mwolson deleted the fix/linux-secret-store-backend branch June 3, 2026 12:43
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL500-999 changed lines (additions + deletions).vouch:unvouchedPR 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

@mwolson@juliusmarminge
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

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

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

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

Conversation

@mwolson

@mwolsonmwolson commented May 6, 2026

Copy link
Copy Markdown
Contributor

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 Linux Electron startup, encrypted credential persistence, and shared auth schema decoding; saved-environment removal ordering changed but covered by tests.

Overview
Improves Linux AppImage packaging and remote saved-environment reliability on non-GNOME desktops (e.g. Niri).

Linux desktop bootstrap now applies Electron options before ready: persisted linuxPasswordStore, --password-store heuristics for unrecognized sessions, WM class, synchronous t3 scheme privileges, and optional DBUS_SESSION_BUS_ADDRESS from /run/user/$UID/bus. Login-shell hydration also pulls more XDG/desktop vars. Secret save failures return Keyring/KWallet guidance via selectedStorageBackend.

Saved environments: new removeSavedEnvironment IPC/persistence removes registry + encrypted token in one write; the web layer deletes persisted state first and runs SSH disconnect in the background. Bearer-token persistence uses clearer rollback (preserves primary errors) and replaces stale SSH records via atomic remove.

Remote auth over SSH HTTP decodes expiresAt from ISO strings (DateTimeUtcFromString in contracts).

Release/build: Linux CI installs ImageMagick; desktop Linux artifacts stage hicolor-sized icons (icons/ dir) instead of a single PNG.

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

Note

Improve Linux AppImage icons and remote environment credential management

  • Linux AppImage builds now generate multi-size icons (16–512px) via ImageMagick into a resources/icons directory; electron-builder is updated to point at this directory instead of a single icon.png
  • Adds a removeSavedEnvironment method end-to-end: IPC channel, preload bridge, DesktopSavedEnvironments service, LocalApi persistence, and web-side catalog/store update
  • Introduces linuxSecretStorage.ts with helpers to normalize password-store preferences, resolve the Electron --password-store switch, and generate platform-appropriate remediation messages when secret storage is unavailable
  • Pre-ready Linux Electron startup now resolves DBUS session bus address, WM class, and password-store switch from a settings file before app.ready, and logs the safe storage backend after ready
  • DesktopShellEnvironment hydrates additional XDG/Wayland/DBus environment variables from the login shell and auto-discovers DBUS_SESSION_BUS_ADDRESS via the XDG runtime dir socket
  • expiresAt fields in auth contract schemas (AuthBootstrapResult, AuthBearerBootstrapResult, AuthWebSocketTokenResult, AuthSessionState) are changed from DateTimeUtc to DateTimeUtcFromString for correct JSON decoding
  • Risk: removing a saved environment no longer explicitly removes the bearer token; SSH cleanup is non-blocking and failures are only logged

Macroscope summarized 2273d3e.

@coderabbitai

coderabbitaiBot commented May 6, 2026

Copy link
Copy Markdown

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: 25c2c134-e105-40a1-a107-735b64a8e3f5

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

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-actionsgithub-actionsBot 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
@mwolsonmwolson changed the title fix(desktop): improve Niri AppImage integrationfix(desktop): improve Niri AppImage and remote environmentMay 6, 2026
@macroscopeapp

macroscopeappBot commented May 6, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR introduces significant new Linux platform behavior including password store detection, DBus session bus address resolution, new IPC methods, and schema changes affecting DateTime serialization. An unresolved comment also questions whether Electron scheme privilege registration timing was affected by the layer restructuring.

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

@mwolson
mwolsonforce-pushed the fix/linux-secret-store-backend branch from dba46b4 to bfc4a7cCompareMay 6, 2026 02:10
@mwolson

Copy link
Copy Markdown
ContributorAuthor

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
ContributorAuthor

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 threadapps/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

@mwolsonmwolson changed the title fix(desktop): improve Niri AppImage and remote environmentfix(desktop): improve AppImage icons and remote environmentMay 9, 2026
@mwolsonmwolson changed the title fix(desktop): improve AppImage icons and remote environmentfix(desktop): harden Linux remote environmentsMay 9, 2026
@github-actionsgithub-actionsBot added size:XL 500-999 changed lines (additions + deletions). and removed size:L 100-499 changed lines (additions + deletions). labels May 9, 2026
@mwolsonmwolson changed the title fix(desktop): harden Linux remote environmentsfix(desktop): improve AppImage icons and remote environmentMay 9, 2026
Comment threadapps/desktop/src/app/DesktopEarlyElectronStartup.ts
Comment threadapps/desktop/src/app/DesktopEarlyElectronStartup.ts Outdated

@juliusmarmingejuliusmarminge left a comment

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.

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 threadapps/desktop/src/app/DesktopEnvironment.ts Outdated
Comment threadapps/desktop/src/electron/ElectronProtocol.ts Outdated
@mwolson

Copy link
Copy Markdown
ContributorAuthor

@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 threadapps/desktop/src/shell/DesktopShellEnvironment.ts
@mwolson

Copy link
Copy Markdown
ContributorAuthor

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 threadapps/desktop/src/app/DesktopEarlyElectronStartup.ts Outdated
Comment threadapps/web/src/environments/runtime/service.ts
Comment threadapps/web/src/environments/runtime/service.ts

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

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 threadapps/desktop/src/app/DesktopApp.ts
@mwolson

Copy link
Copy Markdown
ContributorAuthor

@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.

@mwolson

Copy link
Copy Markdown
ContributorAuthor

@juliusmarminge I've merged main again to update the branch; if you'd rather have me split out the appimage work (which from our conversation ~1 month ago seemed to be tested on Ubuntu and went well), let me know, either way.

@mwolson

Copy link
Copy Markdown
ContributorAuthor

Thanks for taking a look at this larger branch. I split it into focused follow-up PRs so each fix can be reviewed independently:

I am closing this original combined PR in favor of those smaller PRs.

@mwolsonmwolson closed this Jun 2, 2026
@mwolson
mwolson deleted the fix/linux-secret-store-backend branch June 3, 2026 12:43
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL500-999 changed lines (additions + deletions).vouch:unvouchedPR 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

@mwolson@juliusmarminge
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

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

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

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

Conversation

@mwolson

@mwolsonmwolson commented May 6, 2026

Copy link
Copy Markdown
Contributor

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 Linux Electron startup, encrypted credential persistence, and shared auth schema decoding; saved-environment removal ordering changed but covered by tests.

Overview
Improves Linux AppImage packaging and remote saved-environment reliability on non-GNOME desktops (e.g. Niri).

Linux desktop bootstrap now applies Electron options before ready: persisted linuxPasswordStore, --password-store heuristics for unrecognized sessions, WM class, synchronous t3 scheme privileges, and optional DBUS_SESSION_BUS_ADDRESS from /run/user/$UID/bus. Login-shell hydration also pulls more XDG/desktop vars. Secret save failures return Keyring/KWallet guidance via selectedStorageBackend.

Saved environments: new removeSavedEnvironment IPC/persistence removes registry + encrypted token in one write; the web layer deletes persisted state first and runs SSH disconnect in the background. Bearer-token persistence uses clearer rollback (preserves primary errors) and replaces stale SSH records via atomic remove.

Remote auth over SSH HTTP decodes expiresAt from ISO strings (DateTimeUtcFromString in contracts).

Release/build: Linux CI installs ImageMagick; desktop Linux artifacts stage hicolor-sized icons (icons/ dir) instead of a single PNG.

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

Note

Improve Linux AppImage icons and remote environment credential management

  • Linux AppImage builds now generate multi-size icons (16–512px) via ImageMagick into a resources/icons directory; electron-builder is updated to point at this directory instead of a single icon.png
  • Adds a removeSavedEnvironment method end-to-end: IPC channel, preload bridge, DesktopSavedEnvironments service, LocalApi persistence, and web-side catalog/store update
  • Introduces linuxSecretStorage.ts with helpers to normalize password-store preferences, resolve the Electron --password-store switch, and generate platform-appropriate remediation messages when secret storage is unavailable
  • Pre-ready Linux Electron startup now resolves DBUS session bus address, WM class, and password-store switch from a settings file before app.ready, and logs the safe storage backend after ready
  • DesktopShellEnvironment hydrates additional XDG/Wayland/DBus environment variables from the login shell and auto-discovers DBUS_SESSION_BUS_ADDRESS via the XDG runtime dir socket
  • expiresAt fields in auth contract schemas (AuthBootstrapResult, AuthBearerBootstrapResult, AuthWebSocketTokenResult, AuthSessionState) are changed from DateTimeUtc to DateTimeUtcFromString for correct JSON decoding
  • Risk: removing a saved environment no longer explicitly removes the bearer token; SSH cleanup is non-blocking and failures are only logged

Macroscope summarized 2273d3e.

@coderabbitai

coderabbitaiBot commented May 6, 2026

Copy link
Copy Markdown

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: 25c2c134-e105-40a1-a107-735b64a8e3f5

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

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-actionsgithub-actionsBot 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
@mwolsonmwolson changed the title fix(desktop): improve Niri AppImage integrationfix(desktop): improve Niri AppImage and remote environmentMay 6, 2026
@macroscopeapp

macroscopeappBot commented May 6, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR introduces significant new Linux platform behavior including password store detection, DBus session bus address resolution, new IPC methods, and schema changes affecting DateTime serialization. An unresolved comment also questions whether Electron scheme privilege registration timing was affected by the layer restructuring.

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

@mwolson
mwolsonforce-pushed the fix/linux-secret-store-backend branch from dba46b4 to bfc4a7cCompareMay 6, 2026 02:10
@mwolson

Copy link
Copy Markdown
ContributorAuthor

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
ContributorAuthor

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 threadapps/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

@mwolsonmwolson changed the title fix(desktop): improve Niri AppImage and remote environmentfix(desktop): improve AppImage icons and remote environmentMay 9, 2026
@mwolsonmwolson changed the title fix(desktop): improve AppImage icons and remote environmentfix(desktop): harden Linux remote environmentsMay 9, 2026
@github-actionsgithub-actionsBot added size:XL 500-999 changed lines (additions + deletions). and removed size:L 100-499 changed lines (additions + deletions). labels May 9, 2026
@mwolsonmwolson changed the title fix(desktop): harden Linux remote environmentsfix(desktop): improve AppImage icons and remote environmentMay 9, 2026
Comment threadapps/desktop/src/app/DesktopEarlyElectronStartup.ts
Comment threadapps/desktop/src/app/DesktopEarlyElectronStartup.ts Outdated

@juliusmarmingejuliusmarminge left a comment

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.

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 threadapps/desktop/src/app/DesktopEnvironment.ts Outdated
Comment threadapps/desktop/src/electron/ElectronProtocol.ts Outdated
@mwolson

Copy link
Copy Markdown
ContributorAuthor

@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 threadapps/desktop/src/shell/DesktopShellEnvironment.ts
@mwolson

Copy link
Copy Markdown
ContributorAuthor

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 threadapps/desktop/src/app/DesktopEarlyElectronStartup.ts Outdated
Comment threadapps/web/src/environments/runtime/service.ts
Comment threadapps/web/src/environments/runtime/service.ts

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

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 threadapps/desktop/src/app/DesktopApp.ts
@mwolson

Copy link
Copy Markdown
ContributorAuthor

@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.

@mwolson

Copy link
Copy Markdown
ContributorAuthor

@juliusmarminge I've merged main again to update the branch; if you'd rather have me split out the appimage work (which from our conversation ~1 month ago seemed to be tested on Ubuntu and went well), let me know, either way.

@mwolson

Copy link
Copy Markdown
ContributorAuthor

Thanks for taking a look at this larger branch. I split it into focused follow-up PRs so each fix can be reviewed independently:

I am closing this original combined PR in favor of those smaller PRs.

@mwolsonmwolson closed this Jun 2, 2026
@mwolson
mwolson deleted the fix/linux-secret-store-backend branch June 3, 2026 12:43
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL500-999 changed lines (additions + deletions).vouch:unvouchedPR 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

@mwolson@juliusmarminge
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

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

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

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

Conversation

@mwolson

@mwolsonmwolson commented May 6, 2026

Copy link
Copy Markdown
Contributor

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 Linux Electron startup, encrypted credential persistence, and shared auth schema decoding; saved-environment removal ordering changed but covered by tests.

Overview
Improves Linux AppImage packaging and remote saved-environment reliability on non-GNOME desktops (e.g. Niri).

Linux desktop bootstrap now applies Electron options before ready: persisted linuxPasswordStore, --password-store heuristics for unrecognized sessions, WM class, synchronous t3 scheme privileges, and optional DBUS_SESSION_BUS_ADDRESS from /run/user/$UID/bus. Login-shell hydration also pulls more XDG/desktop vars. Secret save failures return Keyring/KWallet guidance via selectedStorageBackend.

Saved environments: new removeSavedEnvironment IPC/persistence removes registry + encrypted token in one write; the web layer deletes persisted state first and runs SSH disconnect in the background. Bearer-token persistence uses clearer rollback (preserves primary errors) and replaces stale SSH records via atomic remove.

Remote auth over SSH HTTP decodes expiresAt from ISO strings (DateTimeUtcFromString in contracts).

Release/build: Linux CI installs ImageMagick; desktop Linux artifacts stage hicolor-sized icons (icons/ dir) instead of a single PNG.

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

Note

Improve Linux AppImage icons and remote environment credential management

  • Linux AppImage builds now generate multi-size icons (16–512px) via ImageMagick into a resources/icons directory; electron-builder is updated to point at this directory instead of a single icon.png
  • Adds a removeSavedEnvironment method end-to-end: IPC channel, preload bridge, DesktopSavedEnvironments service, LocalApi persistence, and web-side catalog/store update
  • Introduces linuxSecretStorage.ts with helpers to normalize password-store preferences, resolve the Electron --password-store switch, and generate platform-appropriate remediation messages when secret storage is unavailable
  • Pre-ready Linux Electron startup now resolves DBUS session bus address, WM class, and password-store switch from a settings file before app.ready, and logs the safe storage backend after ready
  • DesktopShellEnvironment hydrates additional XDG/Wayland/DBus environment variables from the login shell and auto-discovers DBUS_SESSION_BUS_ADDRESS via the XDG runtime dir socket
  • expiresAt fields in auth contract schemas (AuthBootstrapResult, AuthBearerBootstrapResult, AuthWebSocketTokenResult, AuthSessionState) are changed from DateTimeUtc to DateTimeUtcFromString for correct JSON decoding
  • Risk: removing a saved environment no longer explicitly removes the bearer token; SSH cleanup is non-blocking and failures are only logged

Macroscope summarized 2273d3e.

@coderabbitai

coderabbitaiBot commented May 6, 2026

Copy link
Copy Markdown

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: 25c2c134-e105-40a1-a107-735b64a8e3f5

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

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-actionsgithub-actionsBot 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
@mwolsonmwolson changed the title fix(desktop): improve Niri AppImage integrationfix(desktop): improve Niri AppImage and remote environmentMay 6, 2026
@macroscopeapp

macroscopeappBot commented May 6, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR introduces significant new Linux platform behavior including password store detection, DBus session bus address resolution, new IPC methods, and schema changes affecting DateTime serialization. An unresolved comment also questions whether Electron scheme privilege registration timing was affected by the layer restructuring.

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

@mwolson
mwolsonforce-pushed the fix/linux-secret-store-backend branch from dba46b4 to bfc4a7cCompareMay 6, 2026 02:10
@mwolson

Copy link
Copy Markdown
ContributorAuthor

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
ContributorAuthor

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 threadapps/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

@mwolsonmwolson changed the title fix(desktop): improve Niri AppImage and remote environmentfix(desktop): improve AppImage icons and remote environmentMay 9, 2026
@mwolsonmwolson changed the title fix(desktop): improve AppImage icons and remote environmentfix(desktop): harden Linux remote environmentsMay 9, 2026
@github-actionsgithub-actionsBot added size:XL 500-999 changed lines (additions + deletions). and removed size:L 100-499 changed lines (additions + deletions). labels May 9, 2026
@mwolsonmwolson changed the title fix(desktop): harden Linux remote environmentsfix(desktop): improve AppImage icons and remote environmentMay 9, 2026
Comment threadapps/desktop/src/app/DesktopEarlyElectronStartup.ts
Comment threadapps/desktop/src/app/DesktopEarlyElectronStartup.ts Outdated

@juliusmarmingejuliusmarminge left a comment

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.

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 threadapps/desktop/src/app/DesktopEnvironment.ts Outdated
Comment threadapps/desktop/src/electron/ElectronProtocol.ts Outdated
@mwolson

Copy link
Copy Markdown
ContributorAuthor

@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 threadapps/desktop/src/shell/DesktopShellEnvironment.ts
@mwolson

Copy link
Copy Markdown
ContributorAuthor

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 threadapps/desktop/src/app/DesktopEarlyElectronStartup.ts Outdated
Comment threadapps/web/src/environments/runtime/service.ts
Comment threadapps/web/src/environments/runtime/service.ts

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

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 threadapps/desktop/src/app/DesktopApp.ts
@mwolson

Copy link
Copy Markdown
ContributorAuthor

@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.

@mwolson

Copy link
Copy Markdown
ContributorAuthor

@juliusmarminge I've merged main again to update the branch; if you'd rather have me split out the appimage work (which from our conversation ~1 month ago seemed to be tested on Ubuntu and went well), let me know, either way.

@mwolson

Copy link
Copy Markdown
ContributorAuthor

Thanks for taking a look at this larger branch. I split it into focused follow-up PRs so each fix can be reviewed independently:

I am closing this original combined PR in favor of those smaller PRs.

@mwolsonmwolson closed this Jun 2, 2026
@mwolson
mwolson deleted the fix/linux-secret-store-backend branch June 3, 2026 12:43
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL500-999 changed lines (additions + deletions).vouch:unvouchedPR 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

@mwolson@juliusmarminge