Repository navigation
feat(ui): copy a Secret's value without showing it - #78
Merged
Merged
Conversation
…outlined The owner's alpha walk of 2026-10-22 on v0.38.0 (G16): - AW3, AW19: the window's Escape knew the palette, the notifications, a settings page and the drawer only, so over a dialog it closed the drawer behind it or did nothing. Every overlay now registers what Escape does over it as it shows (escape.go: onEscape, onShown); the window's escape runs the top one's, an overlay without one takes the key. Every Fyne dialog is shown through sh.showDialog (Escape is its Dismiss), a framed dialog hides (its SetOnClosed answers no), the pop-ups, the palette, the notifications, the MCP details and the top bar's menus close. - Fyne hands a key to the focused widget only: the fields of Cogpit's dialogs are types that pass an Escape on (fieldEntry, fieldSelectEntry, fieldCheck, fieldSlider, secretEntry), so Escape cancels a dialog whatever field has the keyboard. - AW4: a list's search is cleared and the table gets the keys; the find bar closes from its fields and from the editor (yamlview's OnEscape). D-57's "any other search" had been the navigator's only. - AW2: Escape on an open dropdown's list takes the keyboard off the field, and a dropdown with the keyboard passes Escape on. - AW1: a closed dropdown draws an entry's outline; the field outline token is raised to 2:1 on every surface in both themes, the wells' and cards' edges keep the old value as colorHairline. TestEveryDialogTakesEscape reads the sources for a dialog or pop-up shown past the mechanism. D-116 and D-104 record the lead's decisions; G16, ui-parity, usage, architecture, conventions and the design language say so.
The owner's alpha walk (AW12): a click below a list's rows closed the drawer about a second later, × and Escape at once. Fyne's driver holds every tap on a fyne.DoubleTappable for the double-click interval before it calls Tapped (internal/driver/glfw/window.go, mouseClickedHandleTapDoubleTap; NSEvent.doubleClickInterval on macOS, 0.5 s by default), and the list's table was one for its header separators' double click, which fits a column. The table now counts that double click itself, as the tab bar and the navigator do (doubleClickTime and the tab bar's clock), and is no DoubleTappable: every click on it acts at its release. Rows and headers were not held: their cells take their own taps. TestListClicksAreNotHeld clicks a row, a header, a header separator and the area below the rows as the driver finds the object under the pointer and fails on a DoubleTappable target; it and the reworked TestDoubleClickSeparatorFitsColumn fail before the change. D-106's GW1 table records the cause and the lead's choice; G16, ui-parity and architecture follow.
The welcome page's cluster rows were a fyne.DoubleTappable, their double click doing what a click does, so Fyne's driver held every click on them for the double-click interval (AW12's cause, found on the table first). The row takes clicks only now. Without the hold, a double click's second click reaches the row again, which the page has rebuilt by then for the cluster connecting: a second cluster.connect would join the run under way but end the first one's wait with errConnectInBackground, an error toast naming another cluster, and a login program not allowed yet would be reviewed twice. The page therefore does nothing for a cluster whose connect it began and that has not returned (pending, from before the review or the dispatch to the engine's answer) or that the window shows connecting. TestWelcomeRowConnectsOnce fails on the old row (held) and on a row without the page's guard (connected twice). D-106 records the choice and the clicks left held (the sync picker's rows, the log tab's head row) with why; G16's AW12 entry follows.
…114) The owner's AW17, AW13 and AW18 of the alpha walk (2026-10-22, D-114). A chosen cluster's failed connect, the restore's or a click's, now shows that cluster's error page over the workspace whether or not a tab is open; the welcome page shows only without a chosen cluster. The page is the welcome page's look: the logo, that it is an error page, the cause in a sentence under the stage it failed in, the connect stage by stage, Connect Again and Show Connection Updates. The cluster layer measures every connect in stages: the kubeconfig, a credential plugin's login, DNS with its addresses, TCP to the address and port (or the proxy's), TLS and the API server's answer. DNS, TCP and TLS come from client-go's own first request through net/http/httptrace, so Cogpit opens no connection of its own. The stages reach the connection log (an attempt's stages, a record each in its file), UIState.ConnectFailure and the ConnectError; the connection's error is the failed stage's sentence, the chain stays in the log. Connection Updates shows each connect's stages. The welcome page lists the hotbar and Recent only, the kubeconfigs' clusters as "Your clusters" on a first start alone (AW13). The view's placeholder no longer says the failure and fits the view with an ellipsis: its long line drew a clipped "Could not" over the navigator (AW18). The window tests' fake engine derives the welcome page where the connection changes, as the engine does.
TestWelcomeRowConnectsOnce failed on the stacked tree for two reasons of D-114's commit, not of the guard. The window tests' fake engine now derives the welcome page as the engine does, which hides it while the shown cluster connects, so the row it waited to see rebuilt never was. And the page has no "Other clusters" any more (AW13): once a cluster is recent, the others' rows went, and the later steps found none. The scene puts every cluster on the hotbar, so each keeps its row, and keeps the page up after each connect the test shows, so that a click on the connecting cluster's row is still checked; a last step checks that the page hides while the shown cluster connects. The error page's test checks that Connect Again, which goes through the welcome page's connect, connects once for a double press.
…o failures
The owner's alpha walk of 2026-10-22 (AW15, AW16): his own Cancel
Connecting raised the error toast "connect <context>: connecting
cancelled", and a click on another cluster while a login waited raised
"connect <context>: another cluster was shown; the connect goes on in the
background". cluster.connect answered the background case with
{state: connecting}, but hotbar.openCluster, ui.tab.select and
ui.setNavigatorScope passed the Go error on, and the window toasted every
error but a declined confirmation. A cancel that ended the run at the
moment the window's connect saw it said "superseded by a newer connect".
The engine now types the outcomes (ErrConnectCancelled,
ErrConnectSuperseded beside ErrConnectInBackground, ConnectNotFailed),
awaitRun answers cancelled or in the background on every race instead
of "superseded", every connecting command answers a background connect
without an error, and the window's showError and the --context answer
skip the three. MCP and the built-in agent read a cancel as cancelled,
not failed. A second connect of the cluster the window's connect waits
for joins that wait instead of ending it, so the first no longer says
another cluster was shown. A failed connect keeps its toast.
D-97 records the lead's decisions; D-66, G16, ui-parity and usage follow.
The owner's decision of 2026-10-22 reverses D-25's "copyable only once revealed": a masked value in the drawer has the copy icon on hover, its tooltip "Copy the value without showing it". A tap runs the GUI-only secret.reveal with whole and puts the whole value on the clipboard for Secret values (concealed, this Mac only, cleared after 60 seconds); the value enters no widget and not the drawer's revealed map, and the toast names the key only. An answer for a drawer that moved on copies nothing. In a Secret's editable drawer (D-59) a masked value copies the same way and opens no editor; an edited or added value hidden again copies what was typed. Empty and cut answers copy nothing; binary values have no such icon. No command copies. D-25, H-25 and the Secrets pages record the decision verbatim and the lead's details.
The lead's decision (D-25, open to revision): a revealed value that Show cut at 4 KiB or 40 lines copies the whole value through its copy icon, by the masked value's path (secret.reveal with whole, the clipboard for Secret values, the toast naming the key), its tooltip "Copy the whole value"; the drawer keeps the cut text. A value Show did not cut copies what it shows, and a selection with Cmd+C exactly the selection, as before. The fetch hook is shared (fetchCopyFor, copyWhole, wholeRead).
hans-fischer
force-pushed
the
feat/copy-masked-secret
branch
from
October 22, 2026 16:04
0ca71e8 to
6025bd2
Compare
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.
Copy a Secret's value straight to the clipboard without showing it first, as the owner asked on 2026-10-22.
Why
"Ich stelle gerade fest, dass man nur Passwörter aus Secrets kopieren kann, bei den man vorher auf 'Show' klickt. Das ist so nicht gewünscht. Ich will natürlich auch Passwörter direkt in den Zwischenspeicher packen können und dann direkt irgendwo in ein Passwortfeld ohne es vorher anzuzeigen."
This reverses D-25's rule that a Secret's value is copyable only once revealed.
What changes
secret.revealwithwholeand copies the whole value.Security
TestCopyHasNoCommand), andsecret.revealstays refused to agents and the CLI (TestRevealIsGUIOnly).Tests
TestSecretMaskedValueCopiedWithoutShowing(a value over 4 KiB copied whole, the drawer still masked, cleared after the TTL),TestSecretMaskedCopyRefusals,TestSecretEditorMaskedValueCopiedWithoutShowing,TestSecretCutRevealedValueCopiedWhole. Each failed before its change.TestSecretRevealedValueCopiedkeeps the revealed path.make test-ui(1175 tests), lint (0 issues),make cycloandgo run ./hack/paritypass. No render changed, since the icon shows on hover only.