Merge origin/main into claude/spelunk-api-key-tenant-6373cf

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
laurensandClaude Opus 5.5 committed 2026-10-20 16:26:32 +02:00
commit 6f6e92f315
25 files changed
+2667 -417

No files matched your search

+1 -1
View File
@@ -510,7 +510,7 @@ field cannot be removed and stays as a permanently refused member; `SyncEndpoint
| Org chip `dodotech / platform` | contracts + server | An *organisation* above teams, which does not exist — `VaultSummary.TeamId` is no longer always null since M3, but a team is not an org and there is exactly one tenant per deployment. | The vault's own name, and the account this machine is enrolled as. Team names are on the VAULTS screen, where they are about something. |
| `SYNCED` dot, always green | client-app | Nothing — the design's claim is simply unconditional. | Green **only** when a connection is held, the last sync pass actually reached the server, and the outbox is empty; otherwise `UNREACHABLE`, the count of changes still waiting, or `OFFLINE`. Holding an `IVaultServer` proves a sign-in once succeeded and nothing more, so a laptop whose lid has been shut all afternoon still has one — reachability comes from the outcome of the last pass. A permanently green light is the same as no light. |
| `VAULT SYNCED 11:02` | client-session | `StoredSyncState.LastPulledAt`/`LastPushedAt` are persisted, but `VaultSession` exposes the store as `internal`. A property away. | Omitted. The one honest sync fact — the outbox depth — is in the titlebar and the status bar. |
| `⌘K` command palette running commands | client-domain | A snippet or saved-command item type (`SyncEntityType.Snippet = 8` is reserved). | Ctrl+K opens a real host search that connects on Enter. The box says "search hosts", not "search hosts · run command". |
| `⌘K` command palette running commands | client-domain | A snippet or saved-command item type (`SyncEntityType.Snippet = 8` is reserved). | Ctrl+K opens a real host search that connects on Enter, and reads a typed `user@host[:port]` as a machine to connect to with a password, without saving it. The box says "search hosts, or type user@host", not "search hosts · run command". |
| Status bar `· via bastion-eu` | client-ssh | Jump-host execution. See below. | Omitted. |
| Status bar port forwards | client-ssh | — | **Shipped** on the session status bar as a count of listening forwards; the ports themselves are in the session sidebar. |
| Status bar `sftp · 2 transfers` | client-app | Nothing now — file transfer is built. What is missing is the count reaching the status bar, which is a screen away from where the queue lives. | Omitted from the status bar. The queue itself is on the FILES screen, with a row per transfer. |
+77 -8
View File
@@ -1388,6 +1388,39 @@ Ctrl+K, then click a result with the mouse rather than pressing Enter.
**Pass:** the palette closes and the connection starts.
### 7.10a Connecting to a machine that is not saved
Ctrl+K, type `user@host` for a reachable machine that is **not** on HOSTS, press Enter, type its password and
press Enter again. Do it once against a machine whose host key this vault has never seen.
**Pass:** the palette asks for the password in place, with the caret already in the box. On the second Enter
it closes, a tab named `user@host` opens, and the fingerprint card asks about the key; approving it connects.
Afterwards HOSTS has nothing new on it, and the connection log has an entry for `user@host:22`. Escape from
the password box goes back to the address with what was typed still in it.
**Failure means:** a new row on HOSTS is the palette saving what it promised not to. A tab that fails with
"authentication failed" for a password known to be right is worth comparing against the phone's CONNECT TO A
MACHINE box, which takes the same path — `VaultViewModel.ConnectToEndpointAsync` — so a difference between
the two is in how the palette hands the password over, not in the connection. The headless half of this is
`QuickConnectTests`; what it cannot do is dial.
### 7.10b Pressing Terminal with nothing open asks what to connect to
Close every terminal tab, then press **Terminal** on the rail.
**Pass:** the terminal's frame holds a prompt — `connect to:` with the caret already on it, so typing works
without a click. Type part of a saved host's name: the matching hosts appear under the line, Tab completes to
the first, and Enter connects to it — asking `user@host:port's password:` first only if that host has no key
or saved password. Type `user@host` for a machine that is not saved instead: Enter asks for its password, and
the second Enter opens a tab for it. Escape steps back from the password to the name. Afterwards HOSTS has
nothing new on it, and no credential was saved — even with "remember" ticked in a host's drawer earlier.
**Failure means:** a prompt that needs a click before it takes typing is the terminal's WebView still holding
the native keyboard focus — see `NativeKeyboardFocus`, which `ConnectPrompt.TakeKeyboard` calls. Anything drawn
*under* a blank rectangle is the occlusion rule broken: the prompt may only show while no tab exists. A new
credential in KEYS after connecting is the prompt's attempt acting on the drawer's tick, which
`ShellFlowTests.ThePrompt_NeverSavesAPassword_EvenWithTheDrawersTickLeftOn` exists to stop.
### 7.11 A host or a bucket made now can be picked on FILES now
With the files screen's picker open on an empty or short list, go to HOSTS and add a host — or to KEYS and
@@ -1421,7 +1454,7 @@ time)" — is the worse failure of the two: it rebinds a host as a side effect o
## Phase 8 — Adding and removing on the phone's host list
Twenty-one checks, and the reason there are twenty-one rather than none is worth stating: **the layout suite
Twenty-two checks, and the reason there are twenty-two rather than none is worth stating: **the layout suite
cannot see any of this and structurally never will.** `DodoSSH.Client.App.Layout.Tests` targets `net10.0` and
`DodoSSH.Client.Android` targets `net10.0-android`, so a project reference is impossible; Avalonia's
application, dispatcher and platform are one-shot process globals, so a second head cannot share the
@@ -1794,6 +1827,23 @@ follow, and try disconnecting and reconnecting instead.
---
### 8.20 Connecting from the search box to a machine that is not saved
With a terminal already open on some other machine, go back to HOSTS and type `user@host` for a reachable
machine that is **not** in the list into the search box at the top. Type its password into the card that
appears, and press CONNECT.
**Pass:** the card appears only once there is an `@` in the box, names the address with `:22` on the end, and
says NOT SAVED. CONNECT opens a second tab for `user@host` — the first is still there — and the fingerprint
card asks about an unknown key over the terminal. Back on HOSTS the search box is empty, the list is the whole
list again, and there is no new host in it. A port the parser refuses (`root@box:70000`) gives a sentence in
amber under the box rather than a card.
**Failure means:** the card sitting *over* the list rather than pushing it down is the panels' arrangement
having been lost — see the remark above `IsSendingChosenHostsToAVault` in `HostsScreen.axaml`. A password that
shows in the keyboard's suggestion strip is `Classes="secret"` missing from the box. Everything behind the
card is `ShellFlowTests`' hosts-search cases; this is the rectangles, and the software keyboard.
## Phase 9 — Tag chips and the picker
The desktop half is measured by the layout suite, which now seeds three tags and puts all of them on one
@@ -2049,14 +2099,16 @@ that dialled it taken away. See `MainWindowViewModel.OnVaultConnectionFailed`.
With at least one keychain host and one machine connected to by hand in the log, open Connections with
nothing running.
**Pass:** tapping the keychain one lands on HOSTS with that host **ticked and the action bar up**, ready
for CONNECT out of the ⋯. Tapping the hand-typed one puts its address back in the box on this screen and
leaves the password box **empty**. Neither one dials anything on its own.
**Pass:** tapping the keychain one puts **its name** on the `connect to:` line and carries on as typing that
name would — its password line, or straight into a terminal for a host with a key or a saved password.
Tapping the hand-typed one puts its `user@host:port` on the line and asks for its password with the password
line **empty**. Neither one leaves this screen, and the hand-typed one dials nothing until a password is
given.
**Failure means:** if the hand-typed one navigates to HOSTS, the log entry is carrying a host id it should
not have. If the password came back, something is storing it — it never was. And if the keychain one arrives
at a list with nothing marked, `ConnectToRecent` is setting the selection rather than going through
`AskAboutHost`: nothing on that list means "selected" any more, so that is a screen with nothing to press.
**Failure means:** if the hand-typed one shows a host's name rather than its address, the log entry is
carrying a host id it should not have. If the password came back, something is storing it — it never was.
And if the keychain one shows the logged address rather than the host's name, the host id is not being
matched against the keychain — see `MainWindowViewModel.ChoosePromptRecentAsync`.
### 11.9 The keychain and snippets are the vault's, and back walks out of them
@@ -2285,6 +2337,23 @@ Android is not delivering the click as a `contextmenu` event, and the gesture ne
`WebView` instead of a page one. Neither costs this head anything it has today: a phone without a pointer
has no right button to miss.
### 11.14 Connections with nothing open asks what to connect to
Close every shell, then press **Connections**. Type part of a saved host's name into the `connect to:` line.
**Pass:** the matching hosts appear under the line as buttons a thumb can hit; tapping one asks for that
host's password on a line of its own under ssh's wording — or connects at once, for a host with a key or a
saved password. Then type `user@host` for a machine that is not saved and press CONNECT: the password line
appears with the keyboard already on it, and BACK — or the system back gesture — steps off it onto the
address rather than leaving the screen. A tap on a RECENT row lands on the prompt and asks whatever it needs
to before anything is dialled. Nothing new appears on HOSTS or in the keychain afterwards.
**Failure means:** a password line that appears with the keyboard still on the first line is the posted focus
in `ConnectPrompt.axaml.cs` arriving before the box has bounds. Back that leaves Connections from the password
line is `PhoneShell.OnBackRequested`'s prompt step having been reordered below the surface check. The
decisions themselves — which name matches, what is refused, what is saved — are `ShellFlowTests`' prompt
cases, shared with the desktop; this is the rectangles and the keyboard.
---
## Phase 12 — Shared vaults: the operations that span two accounts