Read tokens as empty when the secret store's type initializer failed - #302
Merged
Merged
Conversation
…iled [patch] On Linux the credential store first reaches libsecret from a static constructor, so a missing libsecret-1.so.0 arrives as a TypeInitializationException wrapping the DllNotFoundException. IsUnavailable only matched the bare exception types, so the wrapped form escaped every TokenStorage read and write, and the runtime rethrows it on each later access. Unwrap TypeInitializationException in IsUnavailable, and cover the wrapped form with a test double. Fixes #296 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T3Dc4pH8DW9RqEzV5znBXQ
… in-memory store
GitHubRequestOutcomeTests built owners with `new Owner { ... }`, so BuildProvider
was null. Since tokens moved into the secret store (#285), reading or writing an
owner's token derives its persona from BuildProvider.Name, so the four workflow
action tests threw NullReferenceException on every platform.
Build owners with provider.CreateOwner(...), and inject an in-memory credential
store for every test so an authorization failure clearing the provider token
never reaches the developer's real OS secret store.
Fixes #300
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T3Dc4pH8DW9RqEzV5znBXQ
(cherry picked from commit ecf9023)
Contributor
Author
|
I've ported the fix from #301 into this branch as Generated by Claude Code |
|
This was referenced Sep 26, 2026
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.



Fixes #296
What was wrong
On Linux, the credential store first reaches libsecret from a static constructor. So when
libsecret-1.so.0is missing,TokenStoragereceives aTypeInitializationExceptionthat wraps theDllNotFoundException.IsUnavailableonly matched the bare exception types, so the wrapped form escaped everyReadandWrite, and the runtime rethrows it on every later access. On a headless Linux host everyTokengetter threw, when the documented behaviour is "reads as empty, logged once".Change
TokenStorage.IsUnavailablenow unwraps aTypeInitializationExceptionand classifies its inner exception.TypeInitializerFailureCredentialStorethrows the wrapped form. A new test asserts that provider and owner tokens read as empty and thatWritereturnsfalse.Verification (Linux container without libsecret, .NET 10)
I ran every test class except
GitHubRequestOutcomeTests, which is broken onmainindependently (#300, fixed in #301):AzureDevOpsSessionTests.AProviderWithNoCredentialsHasNoSessionandRepeatedLookupsOnAnUnconfiguredProviderStayNull, which hit the real, missing libsecret in this container.AzureDevOpsSessionTests.The "logged once" part isn't asserted, because the suite has no log-capture seam.
ReportUnavailableis unchanged and still gates on itsInterlockedflag.🤖 Generated with Claude Code
https://claude.ai/code/session_01T3Dc4pH8DW9RqEzV5znBXQ
Generated by Claude Code