fix(welcome): stop a shared connection row from acting on the local connection - #2313
Merged
Conversation
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
…ateral # Conflicts: # CHANGELOG.md # TableProTests/ViewModels/WelcomeViewModelTests.swift
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.
Four defects in the welcome-window connection list, found while reviewing #2310 and each verified against the code before being fixed. They are grouped because they all live in the same list and the same view model. None of them are caused by #2310; the swipe actions just made me read this code closely.
A Team Library row could delete your local connection
The worst of the four, because it destroys Keychain data.
Publishing a connection to the Team Library sends
sourceConnectionId: connection.id.uuidString, the pull echoes it back, and the row was built with that value as its identity. The row is tagged with it in the sameList(selection:)that tags local connection rows withconnection.id, so your own published connection appeared under both Connections and Team Library carrying one identity. The context menu resolves its ids against local storage only, so Edit and Delete on the Team Library copy resolved to the local connection. Confirming that delete removed the local connection along with its password, SSH password, key passphrase, SSL passphrase and TOTP secret, while the shared entry stayed on screen untouched.Shared rows now derive their identity from the payload, using the same SHA-256 derivation linked-folder rows already use, so a shared row can never collide with a local one.
primaryActionhad the same collision: it iterates local connections and team library connections for the same id, so one Return could start two connects.Opening a linked or Team Library connection did nothing at all
connectToLinkedConnectionbuilt a complete connection from the shared payload and then forwarded only its id, which was resolved against local storage. A linked-folder id is a derived UUID and a colleague's Team Library id is their local UUID, so neither is ever in storage. The lookup threw, and the error handler returns early when no window is open for that id, which is always true here because no window ever opened. The result was a double-click that produced no window, no spinner, no alert, and oneinfolog line.TabRouteralready had the pattern for this:openTableaccepts atransientConnectionand callsregisterPendingSessionfor a connection that is not in storage.openConnectionnow does the same, and the linked path routes through it.A connection that could not be deleted vanished anyway
ConnectionStorage.deleteConnectionsbails out when the write fails, logging an error, but returnedVoid. The view model removed the rows regardless, so a failed delete looked like a successful one and the connection came back on the next launch. Both delete methods now report success, matching the@discardableResult -> Boolconvention the rest of that file already uses, and the view model reloads from storage instead of trimming the list when the write fails.Select All and Ctrl+J skipped favorited connections
When there are favorites and no active search, a favorited ungrouped connection is deliberately removed from the tree because it renders in the Favorites section instead. But
flatVisibleConnectionswas derived only from the tree, and that is whatCmd+Aand theCtrl+J/Ctrl+Knavigation walk. So starring an ungrouped connection quietly removed it from Select All and made it unreachable by keyboard.It now includes the Favorites section in display order, deduplicated so a favorited connection inside a group, which is rendered in both places by design, is still visited once.
Verification
verify.sh build: PASSverify.sh test WelcomeViewModelTests ConnectionStorageSyncDeleteTests: PASS, 15 casesswiftlint --stricton all five changed files: cleanFour new unit tests cover the keyboard reachability of favorites, the no-duplicates guarantee, the failed-delete path using a read-only directory to force the write to fail, and the stability and distinctness of derived shared-row ids.
The Team Library collision itself is not directly unit tested, because building one requires a Team-tier license and the live sync coordinator, neither of which is injectable here. The test covers the derivation the fix depends on instead. Worth a manual pass by someone with Team access: publish a connection, then Delete the Team Library copy and confirm the local one survives.