feat(1password): read host passwords from 1Password, use its SSH agent - #12
Merged
Merged
Conversation
- A host can carry a 1Password secret reference (op://vault/item/field, new "1Password reference" field in the host form, `password_ref` in hosts.toml) instead of a stored password. The app reads it with the 1Password CLI (`op read`) right before connecting — before, not during, the handshake, since a Windows Hello / Touch ID prompt can outlast the connect timeout — keeps it in memory for 10 minutes, and never writes it to disk. If it can't be read, the keys still get their turn and the failure message says what 1Password reported. - SSH keys: on macOS and Linux the app now falls back to 1Password's agent socket when SSH_AUTH_SOCK isn't set (GUI apps on macOS usually don't get it). On Windows 1Password's agent already serves the pipe the app uses. - Key setup that turns password login off drops the reference too, so no pointless 1Password prompt follows every connect. - README: a "Using 1Password" section. Tested against the SSH test container with a stand-in `op` (no 1Password in CI): login through a reference works, an unreadable reference fails with 1Password's reason. Unit tests cover the reference format, the CLI call and its error cases, hosts.toml and the host form. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ject]"
IPC handlers threw a plain { message } object. Electron hands a rejected
invoke only the thrown value's toString(), so in the real app every error
from the main process — a terminal or SFTP that couldn't open, a remote
desktop that couldn't connect, 1Password's reason — reached the UI as
"Error invoking remote method 'x': [object Object]". The e2e stubs pass the
object through untouched, which is why the tests never saw it.
Handlers now throw a real Error, and the renderer unwraps Electron's
"Error invoking remote method" prefix, so the message itself shows. Checked
in the real app: "unknown host: no-such-host" instead of "[object Object]".
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A remote desktop connection gets the same "1Password reference" field as a host (op://vault/item/field): its password is read from 1Password when connecting — for the in-app tab and for mstsc / FreeRDP alike — instead of being stored. A reference wins over a stored password; a password typed in the tab wins over both. Tiles show a 1Password badge. SSH and remote desktop share one 10-minute cache of what 1Password answered, so one reference asks once however it's used. The reference check is shared by both forms. Tested in the real app with a stand-in `op` on PATH: the right reference is read and used to connect; a wrong one shows 1Password's own message. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t it Once a 1Password reference is entered in a host or a remote desktop connection, the form checks for the CLI the reference needs. Missing, it shows the install command for this OS (winget / brew; the setup guide on Linux) with a Copy button, the one setting to turn on in the 1Password app, and "Check again"; installed, it shows the CLI's version. `op` is also looked for where winget, Homebrew and the installers put it when it isn't on the app's PATH — a CLI just installed with winget is found without restarting the app, and on macOS an app started from the Finder finds Homebrew's. Tested in the real app: without op the hint and command show and Copy copies it; with op in WinGet's Links folder but not on PATH, it is found. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…p screen Closing the active tab always fell back to the SSH dashboard, even with the sidebar in Remote Desktop mode. It now goes to the current mode's home screen. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…assword Instead of a separate "1Password reference" field for the password, every credential field in the host and remote desktop editors has its own 1Password switch next to its label: hostname, user and password can each be typed or read from 1Password when connecting. Hostname and user keep their reference in the field itself (an address never starts with op://); the password's still goes in passwordRef, since the stored password never travels back to the form. Existing profiles open with the password switch on, so nothing needs migrating. Resolved in one place per protocol, right before dialling: resolveConnection for RDP (launch and embedded), resolveHostAddress per SSH hop and for the TCP port check. Certificates stay keyed by the saved address. Tiles, cards and the palette show a reference as its item, ‹web-1›, and the badge says what comes from 1Password. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The port (hosts and remote desktop) and the domain (remote desktop) get the same 1Password switch as address, user and password. The domain keeps its reference in the field; the port, a number on disk, gets portRef / port_ref beside it and keeps the default, so older builds still read the file. resolvePort reads and checks it (1-65535) without echoing what 1Password returned. The TCP port check probes the resolved port unless it has one of its own. Tiles and cards leave out parts from the same item as the address, so a profile kept in one item shows as just ‹item›. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rd copies them with "Copy Secret Reference" wraps a reference whose vault, item or field name has a space in quotes: "op://IT/e-HPV one/Benutzername". The form refused both the quotes and the spaces. Names may now hold spaces (not at either end), and a reference pasted in quotes is saved without them. The backend accepts and strips them too, so op gets the bare reference. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The default path gets the same 1Password switch, the reference kept in the field. The backend reads it before starting the shell there; the terminal tab no longer types a cd for a reference; the SFTP browser asks the backend (sftp_default_path) for the path to open, falling back to / and saying why. "Set as default path" in SFTP saves a plain path. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
new "1Password reference" field in the host form,
password_refinhosts.toml) instead of a stored password. The app reads it with the
1Password CLI (
op read) right before connecting — before, not during, thehandshake, since a Windows Hello / Touch ID prompt can outlast the connect
timeout — keeps it in memory for 10 minutes, and never writes it to disk.
If it can't be read, the keys still get their turn and the failure message
says what 1Password reported.
socket when SSH_AUTH_SOCK isn't set (GUI apps on macOS usually don't get
it). On Windows 1Password's agent already serves the pipe the app uses.
pointless 1Password prompt follows every connect.
Tested against the SSH test container with a stand-in
op(no 1Password inCI): login through a reference works, an unreadable reference fails with
1Password's reason. Unit tests cover the reference format, the CLI call and
its error cases, hosts.toml and the host form.
Co-Authored-By: Claude Opus 5.5 noreply@anthropic.com
What and why
How it was tested
Checklist
npm run checkandnpm testpass