Releases: StuartMeeks/NextIteration.SpectreConsole.Auth
v0.6.1
Fixed
- Markup injection in
accountscommand output — provider names, account names, environments, summaryDisplayFields, exception messages, and the--providerflag echoed in the "Unknown provider" error now flow throughMarkup.Escapebefore reachingMarkupLine/Table.AddRow/ Spectre selection prompts. A credential whose name happened to contain[or]previously corrupted theaccounts listtable rendering, and exception messages with markup-looking content (common onJsonException/ IO errors) garbled the error line inCommandErrorReporter. accounts delete <short-id>crash —accounts delete abc(or any non-GUID id shorter than 8 chars) previously threwArgumentOutOfRangeExceptionon theaccountId[..8]slice in the confirm prompt before reaching "not found". A newCommandFormatting.ShortIdhelper safely abbreviates, andDeleteCredentialAsync/SelectCredentialAsync/GetCredentialByIdAsyncnow validate thataccountIdis a GUID before any filesystem call. Non-GUIDs resolve to deterministicfalseon the mutating APIs andArgumentExceptionon the strictGetCredentialByIdAsync. Closes a path-traversal/glob-injection vector where*or..\..\foocould have flowed intoPath.CombineandDirectory.GetFilespatterns.- Concurrent
accounts selectlost updates —selections.jsonwas read-modify-written without serialization, so two CLI invocations modifying different providers could lose one provider's update. Reads/writes now happen under a cross-process advisory lock backed byselections.json.lock(FileShare.None+FileOptions.DeleteOnClose+ exponential backoff up to ~5s). Atomic rename was already preventing torn files; this closes the lost-update window. The Keychain and libsecret backends are unaffected — both OS stores serialise their own writes. - Unbalanced parenthesis in
accounts selectandaccounts deletechoice prompts — drive-by fix while replacing the unsafe[..8]slices.
Changed
PackageOutputPath— was hard-coded asC:\nuget-local\, which on Linux produced surprisingsrc/NextIteration.SpectreConsole.Auth/C:/nuget-local/…repo churn. Now repo-relative ($(MSBuildThisFileDirectory)..\..\artifacts\packages) and already gitignored.GeneratePackageOnBuild— now scoped toReleasebuilds via MSBuild condition.dotnet testand Debug builds no longer pack, materially shortening the local test loop.
Tests
18 new tests; suite now at 145.
CommandFormatting.ShortIdacross full GUIDs, short strings, exact-8 boundary, null/empty.- Non-GUID
accountIdresolves to deterministic not-found on file-backendDelete/Select; throws onGetCredentialByIdAsync. - Concurrent
SelectCredentialAsyncon different providers both persist (regression test for theselections.jsonrace). SelectionsLockuncontended/contended/post-release semantics.
Migration notes
No source changes required on consumer code. Public API surface is unchanged — this is additive hardening on top of 0.6.0.
Install
dotnet add package NextIteration.SpectreConsole.Auth --version 0.6.1See CHANGELOG.md for the full history.
v0.6.0
Added
ICredentialManager.GetCredentialByIdAsync(providerName, accountId)— returns the decrypted JSON payload of a specific credential without mutating which credential is currently selected. The non-mutating counterpart toGetSelectedCredentialAsync. Implemented natively in all three built-in backends (FileCredentialManager,KeychainCredentialManager,LibsecretCredentialManager) via a single direct lookup — no select-then-read dance, no shared-state side effects.
Breaking changes
ICredentialManagergains a required member —GetCredentialByIdAsync. Consumers who have rolled their ownICredentialManagerimplementation need to add this method. (There are no default interface implementations; a no-op fallback was explicitly rejected to keep the contract honest.)
Motivation
Consumers needed a way to read a specific stored credential's secret at runtime based on some lookup key — e.g. resolving a credential by externalId, or enumerating credentials when a command needs ops+vendor pairs or source+dest pairs. Before 0.6.0 this required a "select credential X → read its decrypted JSON → restore the originally-selected credential" dance, which (a) leaked mutation into global state, (b) wasn't concurrency-safe, and (c) left an orphaned selection when there was no original active credential to restore. The new method makes all of that go away.
Tests
14 new tests (6 File-backend, 4 Keychain, 4 Libsecret), all exercising: happy-path round-trip, unknown-id returns null, cross-provider isolation, and the core regression — does not mutate the selected-credential state. Suite at 127 tests.
Install
dotnet add package NextIteration.SpectreConsole.Auth --version 0.6.0See CHANGELOG.md for the full history.
v0.5.0
Changed
- Upgraded to Spectre.Console 0.55.2 and Spectre.Console.Cli 0.55.0 (from 0.54.0 / 0.53.1).
- Spectre.Console.Cli 0.55 tightened
AsyncCommand<T>.ExecuteAsyncfrompublictoprotected. The four built-in command overrides (AddCredentialCommand,ListCredentialsCommand,SelectCredentialCommand,DeleteCredentialCommand) now match. - Spectre.Console 0.55 split
Spectre.Console.Ansiinto its own assembly. Consumers still pinned to Spectre.Console 0.54.x will hitTypeLoadExceptiononSpectre.Console.Styleat runtime; upgrade to 0.55.x when taking this release.
- Spectre.Console.Cli 0.55 tightened
Migration notes
No source changes required on consumer code for this release — API surface is unchanged. The break is purely in the Spectre.Console dependency boundary.
Install
dotnet add package NextIteration.SpectreConsole.Auth --version 0.5.0See CHANGELOG.md for the full history.
v0.4.2
Changed
- Refreshed package icon to establish a unified visual family with the three provider packages (shield-in-circle mark, shared across all four NuGet packages).
Install
dotnet add package NextIteration.SpectreConsole.Auth --version 0.4.2See CHANGELOG.md for the full history.
v0.4.1
Added
- macOS Keychain backend (experimental). New
KeychainCredentialManager; opt in viaCredentialStoreOptions.UseKeychain = true+KeychainAppIdentifier. Each credential becomes a generic-password keychain item scoped by the consumer's app identifier. - Linux libsecret backend (experimental). New
LibsecretCredentialManager; opt in viaCredentialStoreOptions.UseKeyring = true+KeyringAppIdentifier. Items are stored in the user's default Secret Service collection. CredentialStoreOptions.AdditionalEntropy— caller-supplied bytes mixed into PBKDF2 alongside machine identity. When set, the KEK depends on both the machine AND the entropy, so a stolen keystore file alone is not enough to decrypt. Opt-in; default behaviour is bit-identical to earlier versions.CredentialStoreOptions.KeyringCollection(Linux libsecret). Defaults to"default"(user's login keyring). Set to"session"for the in-memory collection that always exists on a running Secret Service daemon — useful for CI, headless environments, or ephemeral use.- CI matrix expanded:
ubuntu-latest(libsecret via gnome-keyring-daemon) +macos-latest(Keychain via Security.framework) in parallel.
Fixed
- macOS
SecItemCopyMatchingresults:DecodeArraynow dispatches on CF type ID rather than probing withCFDictionaryGetValue. Probing a CFArray with a dictionary function toll-free-bridges to[NSArray objectForKey:]and crashes the test host on first run withNSInvalidArgumentException. - macOS
errSecParam (-50)when requestingkSecReturnAttributes + kSecReturnData + kSecMatchLimitAllin a single query.QueryItemsandQueryAllItemsForAppnow fetch attributes only and follow up per-item withkSecMatchLimitOneto load data — a supported combination. - Linux libsecret tests failing against CI's fresh
gnome-keyring-daemon(thelogincollection doesn't exist until provisioned). The library's availability probe now performs a real store + clear round-trip in"session"rather than a bare search.
Changed
DpapiCredentialEncryptionandCredentialEncryptionFactory.CreateDpapicarry[SupportedOSPlatform("windows")]so the analyzer enforces Windows-only usage at compile time.
Install
dotnet add package NextIteration.SpectreConsole.Auth --version 0.4.1See CHANGELOG.md for the full history.
Initial public release.
- AES-GCM authenticated credential encryption with tamper detection
accounts add|list|select|deletecommand branch- Hardened filesystem permissions (Unix 0600, Windows ACL)
- Atomic writes; crash-safe keystore and credential files
- Provider model with
ICredentialCollector+ICredentialSummaryProvider - Companion packages: Adobe, Airtable, SoftwareOne