fix(secrets): stop JSON-encoding secret values#162
Merged
Conversation
chrishagglund-ship-it
force-pushed
the
fix/secrets-shouldnt-force-json
branch
from
July 20, 2026 17:26
88b3d10 to
e42e688
Compare
Codecov Report✅ All modified and coverable lines are covered by tests.
Flags with carried forward coverage won't be shown. Click here to find out more.
... and 3 files with indirect coverage changes 🚀 New features to boost your workflow:
|
v1r3n
approved these changes
Jul 20, 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.
Fix for #152 : stop JSON-encoding secret values in PutSecret/GetSecret
Summary
PutSecretwas running the secret value (an already-plain string) through JSON serialization, which wrapped it in quotes before sending it to the server (secret_value->"secret_value"). The server stores the body verbatim, so the extra quotes became part of the stored secret.GetSecretthen JSON-decoded on read, which stripped the quotes again and made the SDK's own get-after-put round trip look correct while the value was actually corrupted at rest.This PR sends the raw string on write and returns the raw response body on read, matching the Java/Go/Python/Rust SDKs.
Changes
PutSecretWithHttpInfo: send the string body as-is instead ofSerialize(body).GetSecretnow returnsstring(wasobject).GetSecretAsyncnow returnsTask<string>(wasTask<object>).GetSecretWithHttpInfonow returnsApiResponse<string>with the raw response body in.Data(no JSON deserialization).PutSecret_CanBeRetrievedintegration test to assert an exact round-trip match (previously it only asserted non-null, so it could not catch this bug).Why this is a bugfix, not a major version bump
Technically this changes public signatures (
GetSecret:object->string,GetSecretWithHttpInfo:ApiResponse<object>->ApiResponse<string>), which is API-breaking in the strict semver sense. In practice:stringis assignable toobject, so the vast majority of callers keep compiling.Given that, a full major version release seems disproportionate. Proposing this ship as a patch/minor with a clear changelog note rather than a major bump.
Server-side follow-up required
This fixes the client going forward, but secrets written by the previous (buggy) client are still stored with the extra quotes and will not be corrected automatically. Any affected secrets need to be re-saved (re-
PutSecret) after this change so the stored value no longer contains wrapping quotes. Consumers that read the raw stored value (e.g. auth headers, HTTP tasks using${workflow.secrets.x}) are the ones impacted by the corrupted values.Possibly affected in other SDKs (unconfirmed)
While comparing implementations, the JavaScript and Ruby SDKs appear to do the same JSON-encoding of the string body (
JSON.stringify/JSON.generaterespectively), so they may exhibit the same corruption. This has not been empirically confirmed against a live server, and both also strip quotes on read, which can mask it in their own round trip. Worth verifying separately (raw GET / curl) and fixing if reproduced.Test plan
dotnet buildsucceeds.dotnet test --filter "FullyQualifiedName~SecretTests.PutSecret_CanBeRetrieved"passes against a live server (exact round-trip match).