Release Go SDK v1.9.0 - #71
Open
stas-schaller wants to merge 9 commits into
Open
Conversation
Detect HTTP 403 {"error":"throttled"} inside PostQuery and retry up to
maxThrottleRetries (5) with exponential backoff (baseThrottleDelaySec = 11s,
doubling: 11/22/44/88/176s) plus +/-25% jitter, honoring retry_after from the
response body when present. Returns the new sentinel ErrThrottled (checkable
via errors.Is) once retries are exhausted.
The throttle check sits before HandleHttpError in the PostQuery loop, so the
existing key-rotation retry path is unaffected. No new public config; the sleep
is injectable in tests via a new optional Context.Sleep field (mirrors the
existing Context.Transport seam).
No version bump; CHANGELOG entry added under Unreleased. Adds core/throttle_test.go
(unit) and test/throttle_test.go (end-to-end); TestHTTPErrorErrorsAs switched to a
non-throttle code since "throttled" is now retried. go test ./... green in both modules.
Mirrors the Python SDK fix (PR #1033, per @stas-schaller review): parseThrottle only inspected the response body, so a non-403 response (e.g. 500/502) carrying {"error":"throttled"} would be retried 5x before failing. Gate the throttle parse/retry on ksmRs.StatusCode == 403 so non-403 responses fall straight through to HandleHttpError. Adds a regression test (TestThrottleBodyNon403NotRetried).
Symmetric ±25% jitter could fire a retry before the backend's 10s memcached window expires (floor - 25% = 8.25s). Switch to 0 to +25% so the delay is always >= the floor. Also add maxThrottleDelaySec = 176 constant and apply it as a cap in throttleDelay so a server-supplied retry_after above 176s is clamped rather than honored blindly.
The test and publish matrices topped out at Go 1.22, which upstream no longer supports. Only 1.25 and 1.26 receive security fixes, so nothing in CI exercised a toolchain a consumer would actually compile with. govulncheck against core with go1.22.12 reports 24 reachable standard library vulnerabilities, including request smuggling in net/http/internal reached from KeeperFile.GetFileData and proxy bypass reached from SecretsManager.PostQuery. The same scan on go1.25.12 reports none. The SDK ships source rather than a binary, so a consumer on a current toolchain was never exposed; the gap was that CI could not have told us either way. 1.25.x and 1.26.x appended to all three matrices. The 1.16 floor in core/go.mod is deliberately unchanged, since raising it would break consumers on older Go. The v1.7.0 changelog already claimed testing against 1.25.0, which was not true of any matrix until now. Verified locally: core unit tests and the test module both pass on go1.25.12 and go1.26.5. actionlint and zizmor clean.
govulncheck ran in no workflow in any KSM Go repo, despite being the only Go scanner that filters by reachability. It reports a vulnerability solely when the code can actually reach the affected symbol, so its output arrives triaged rather than needing a manual pass like a Dependabot manifest diff. Runs on pull requests touching core or test, plus weekly on a schedule. The schedule matters more than the PR trigger: advisories are published against unchanged code, so a scan wired only to PRs goes quiet exactly when a new CVE lands. Scans on the newest supported Go rather than the 1.16 floor. Standard library findings depend on the toolchain doing the building, so a scan on an end-of-life toolchain reports every stdlib defect fixed since and says nothing about this SDK's own code. Results upload as SARIF to code scanning instead of failing the job. Dismissing an alert there records who accepted a risk and why, which is the audit trail a release review needs and which a red build does not produce. Making it blocking is a branch protection setting rather than a change to this file. Verified: govulncheck -format sarif on core reports 0 error-level results, and the jq summary expressions were checked against that output and against the vault plugin's, which has 2. actionlint, zizmor and act -l clean.
… by key size (KSM-1064) Drive (NSF) folders require AES-GCM for the folder key wrap and folder data in CreateFolder/UpdateFolder; the previous CBC encryption caused "invalid sharedFolderKey" errors against NSF-enabled endpoints. fetchAndDecryptFolders now dispatches decrypt mode by subfolder key byte length (60 = GCM, 64 = CBC legacy) - mirrors the read-path fix already on the other KSM SDKs. KeeperFolder gains a UseGcm field; NewKeeperFolder dispatches its own internal folder-data decrypt on it and takes UseGcm as a new required parameter (updated its one existing caller in record_test.go, KSM-917's test, with useGcm=false since that test explicitly encrypts with CBC - assertion and behavior unchanged). Also fixes keeperSecretsManagerClientId, which was hardcoded to a stale "mg17.1.0" unrelated to any real SDK version, to "mg18.0.0" so the NSF gate on the backend recognizes this client. The Go module's own package version intentionally stays in the v1.x line (v1.9.0) rather than following the v18 convention literally - Go modules require an import-path change for any major version 2+, a real migration cost the other six ecosystems don't have. See secrets-manager-go/main/CLAUDE.md for the full reasoning. Verified end-to-end on dev CA: all folders decrypt via GetFolders (previously GCM-created folders failed with padding errors); CreateFolder, read-back, UpdateFolder, and DeleteFolder all round-trip correctly for a fresh GCM subfolder.
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.
Summary
Release branch for v1.9.0 of the Go SDK. Bundles a GetFolders binding fix, throttle retry with exponential backoff, a new PAM field, and CI improvements.
Changes
Bug Fixes
GetFolders()failed with "app key is missing from the storage" when called as the first method on a freshly bound application. It now processesencryptedAppKeyfrom the server binding response the same wayGetSecrets()does.retry_afterat 176s and gates retry on HTTP 403 status.New Features
{"error":"throttled"},PostQuerynow retries up to 5 times with exponentially increasing delays (11s, 22s, 44s, 88s, 176s) plus one-sided jitter, honoringretry_afterfrom the response. ReturnsErrThrottled(checkable viaerrors.Is) once retries are exhausted.dbConnectionMethodtoPamSettingsConnection.Maintenance
govulncheckscan with SARIF output to GitHub code scanning.Breaking Changes
None.
Security Impact
KSM-1048 touches the initial key derivation path:
fetchAndDecryptFoldersnow decryptsencryptedAppKeyusing the client key and stores the result as the app master key, matching the behavior already infetchAndDecryptSecrets. No new cryptographic operations introduced.Testing
go test ./...Related Issues