Mask secret input in the CLI credentials prompt - #5889
Merged
Merged
Conversation
`credentials set` read the password with `Console.ReadKey(true)` and echoed nothing, so a paste was invisible: there was no way to tell whether anything had been entered before pressing Enter, or whether it had been entered twice. The key loop moves to `SecretConsoleReader`, which echoes `*` per accepted character. Backspace erases one; Escape and Ctrl+U clear the whole entry and re-prompt on a fresh line rather than backspacing over the mask characters, since a long entry wraps and `\b` does not cross a line boundary. Masking is suppressed when stderr is redirected, so no mask bytes reach a file. Extracting the loop also makes it testable: `SecretConsoleReaderTests` drives it with a scripted key queue over a `StringWriter` and asserts the exact echo. Disabling the mask write turns 8 of the 11 tests red. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
sdanyliv
approved these changes
Sep 8, 2026
MaceWindu
marked this pull request as ready for review
September 8, 2026 11:43
MaceWindu
requested review from
Shane32,
igor-tkachev,
jods4 and
viceroypenguin
as code owners
September 8, 2026 11:43
Contributor
Author
📝 Release-notes draft🤖 Auto-generated user-facing summary for this PR. Toggle the boxes to control how it ships; the text is regenerated when new commits land (the maintainer confirms every change).
Full release notes (wiki)
GitHub release highlight (brief)(none) Generated from commit |
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.
Problem
dotnet linq2db credentials set— the interactive step that stores the passwordquery/execute/schema/mcplater resolve through--credentials— read the password withConsole.ReadKey(true)and echoed nothing at all.A paste was therefore invisible. There was no way to tell whether the clipboard had content, whether it landed once or twice, or whether anything had been entered before pressing Enter; the only feedback was
Passwords do not match.after the confirm prompt, or a silently-stored empty password.SystemCliEnvironment.TryReadSecretwas the only interactive secret reader in the product (oneConsole.ReadKeyin all ofSource/), andTestCliEnvironmentsupplies its own implementation, so no test exercised the key loop.Change
The key loop moves to
SecretConsoleReader, which echoes*per accepted character:Backspaceremoves one character and erases one mask character.Escape/Ctrl+Uclear the whole entry, then re-prompt on a fresh line (Password: *** (cleared)) rather than backspacing over the mask characters — a long entry wraps, and\bdoes not cross a line boundary on any common terminal, so an erase run would strand mask characters on the previous row. Clearing a bad long paste is exactly the case this key exists for.\b/*bytes reach a file. The prompt still goes there, as it did before.Both spellings of the clear keys are matched: Windows and the Unix terminfo path populate different
ConsoleKeyInfofields. A plainukeypress is covered by a test so it cannot be swallowed asCtrl+U.Extracting the loop is what makes it testable — the reader takes a
Func<ConsoleKeyInfo>and aTextWriterinstead of talking toConsoledirectly.Trade-off
Masking with one character per keystroke reveals the password's length to anyone watching the screen. That is the standard behaviour of
cmdkey,azandgh, and it is what makes a paste verifiable; no opt-out switch was added.Tests
Tests/LinqToDB.CLI/SecretConsoleReaderTests.cs— 11 tests driving the reader with a scripted key queue over aStringWriter, asserting the exact echo (newline pinned to\nso expectations hold on every platform): per-character masking, a paste-shaped burst, backspace with and without content, both clear-key spellings, clear on an empty entry, control keys, a plainu, and the unmasked path.Disabling the mask write turns 8 of the 11 red; the 3 survivors are precisely the ones asserting the absence of a mask.
Verification
Testing).HasFlag.-3,Interactive secret input requires a console.Docs
Source/LinqToDB.CLI/readme.mdandSKILL.mdboth asserted the prompt had no echo; corrected, along with theICliEnvironment.TryReadSecretdoc comment.