Repository navigation
Release: Java 1.0.0, Node 1.0.0, Python 1.1.0 - #24
Merged
Merged
Conversation
Signed-off-by: Edward Liang <liawedwa@amazon.com>
Port IAM authentication to Java
…auth tokens The stateless ElastiCacheIAMAuthTokenProvider signs on every call. The manager wraps it with a thread-safe cache and refreshes the token on a background daemon thread `refresh_after` seconds after signing (default 300), so clients that reconnect often or run connection pools always get a valid token without signing per call. Behaviour - Config validated and region resolved eagerly at construction; first token signed lazily on the first get_token()/get_credentials(). - A token is served for 880s after signing: the 900s lifetime minus a 20s margin for clock skew and the AUTH round trip. refresh_after must be below 880. Expiry is tracked on the wall clock, since the server judges X-Amz-Date against its own wall clock and a monotonic clock stands still through a host suspend. - get_token() returns the cached token while it is valid. A token found past its refresh due time (missed timer, suspended process) is returned immediately and refreshed in the background; callers holding a valid token never wait. - Single flight: concurrent callers with no valid token share one signing cycle and receive the same result or the same failure (concurrent.futures.Future). - Retry: up to 8 attempts, exponential backoff from 100ms with a nominal 5s cap, +/-20% jitter. Every error is retried, including ConfigurationError: on an instance role a transient IMDS failure surfaces as "no credentials". - Failure semantics: while the cached token is valid a failed cycle is invisible to callers, logs a warning, and schedules another cycle after the maximum backoff (get_token() does not restart it early); with no token the last error is raised; with an expired token TokenRefreshError is raised with the last error as __cause__. - on_token_changed(token) is called synchronously outside the lock for each newly installed token; a callback failure is logged and the token kept. - close() (or the context manager) cancels the timer, wakes a sleeping retry, drops the cached secret, and makes later calls raise TokenRefreshError. Idempotent. A scheduling failure never loses a signed token. Also - TokenRefreshError (not a ToolkitInputError) added to errors and exported with the manager and DEFAULT_REFRESH_AFTER_SECONDS. - _CachedToken keeps the bearer token out of its repr. - Tests: shared session fake and fixtures moved to tests/helpers.py and tests/conftest.py; 53 manager tests with injected clock, scheduler, sleep and jitter so no real timers run, plus real-thread single-flight tests. - README "Caching and background refresh" section and CHANGELOG entry.
Signed-off-by: Edward Liang <liawedwa@amazon.com>
- Callback failures are logged by exception type only: the callback received the token, so its message or traceback might contain it. - Re-check expiry under the lock before serving the still-valid token at the end of a failed cycle; a waiter that joined because its token expired must not get it back if the clock crossed expires_at while the lock was released. - Complete and clear the signing flight before calling on_token_changed, so a timer that fires during a slow callback starts its own cycle instead of joining the old one and skipping the reschedule. Reuse decisions now compare token identity rather than issued_at. - Add refresh_token(): sign a replacement immediately for a client whose AUTH was rejected with a token the manager still considers valid; raises TokenRefreshError if none could be signed. - Tests: daemon workers with liveness asserts; shared-flight tests hold the owner open until every waiter has joined (join-counting Future); re-entrant callback test runs bounded; real _wait interrupted while blocked; real-timer end-to-end test with a callback slower than refresh_after; regression tests for the two races above.
Mirrors python-release.yml: on a published node-v* GitHub Release, run the supported-version test matrix, verify and pack, then publish from the `npm` environment with OIDC trusted publishing and provenance, and smoke-test the published package. Release logic lives in scripts, not YAML: - scripts/verify.mjs: tag matches package.json's version, `private` is off, CHANGELOG.md has an entry for the version, repository.url is set (provenance requires it), and optionally npm is new enough for trusted publishing. The publish job asserts the npm version instead of installing npm from the registry at publish time. - scripts/smoke.mjs: install the published version into a temporary project with retries, import it, check the public exports and the installed version. package.json gains repository/homepage/bugs (provenance verifies repository.url against the publishing repository) and publishConfig.access=public, which a scoped package needs on first publish. Nothing publishes until a node-v* release is created, the `npm` GitHub environment exists with required reviewers, and the npm trusted publisher is configured for the package.
Node refuses to spawn .cmd shims directly (spawnSync npm.cmd EINVAL), which failed the --require-npm check on the Windows CI runners.
feat(python): add ElastiCacheIAMAuthTokenManager (auto-refresh)
feat(java): Add Auto Refresh
Same shape as scripts/java_dev.py: a small stdlib-only Python script for the step npm has no command for. The release gate stays in node/scripts/verify.mjs (npm run verify, with its tests); everything else is plain npm in the workflow. - smoke VERSION installs the exact published version into a temporary project and checks the public exports. It retries 20 times, 40s apart (about 13 minutes), with a fresh npm cache and --prefer-online each time, logging 'install attempt X/20 failed (registry may lag the upload)': the registry has taken around 8 minutes to serve a newly published tarball. - Replaces node/scripts/smoke.mjs. - The publish job gains a repository_owner guard, so a fork can never publish, and the build job packs into node/pack/ for the publish job.
python.yml watched scripts/**, so a change to another language's runner (scripts/node_dev.py) also ran the Python matrix. Watch scripts/python_dev.py, like java.yml watches scripts/java_dev.py.
verify.mjs: - Accept X.Y.Z and X.Y.Z-rc.N only. Release candidates publish under the `next` dist-tag (verify writes dist_tag to GITHUB_OUTPUT and the publish step passes it), so `latest` keeps pointing at the last full release. Any other prerelease suffix is rejected in the gate; npm itself refuses a prerelease without an explicit --tag, which would only fail at the upload. - Reject --require-npm without a value; it silently skipped the npm check. - Reject non-numeric version parts instead of comparing NaN, which passed silently. Tests: runVerify takes an env parameter; cases for each of the above.
verify accepts X.Y.Z and X.Y.ZrcN (PEP 440) and rejects any other suffix (.devN, aN, bN). pip skips pre-releases unless one is requested explicitly, so an RC on PyPI never reaches a plain pip install and needs no separate channel.
npm refuses to publish a prerelease version without an explicit dist-tag, so verify.mjs now fails on any version with a prerelease suffix and the publish step no longer needs a computed --tag. The Python gate applies the same rule (X.Y.Z only). Prereleases are never required before a release.
- pom.xml: add the developer and scm metadata Maven Central requires, and a release profile that signs every artifact and publishes through the Central Portal. Normal builds never sign. - java_dev.py: add verify (tag matches a non-SNAPSHOT pom version with a CHANGELOG entry) and smoke (polls Maven Central for the published files). - java-release.yml: on a java-v* release, test every supported Java version, then sign and publish from the maven environment and smoke-test Maven Central.
verify now also requires java/examples/pom.xml and java/integration-tests/pom.xml to depend on the release version, since the examples are not built by the release workflow. The developers block uses the same fields as other AWS libraries on Maven Central.
…he-ja-e7facdbe Add forced IAM token refresh API to the Java toolkit
- setup-java's gpg-passphrase names MAVEN_GPG_PASSPHRASE explicitly, so the settings.xml it writes and maven-gpg-plugin read the same variable. - The smoke test requires the signature of every artifact, not just the jar.
ci(node): add the npm release workflow
ci(java): add the Maven Central release workflow
Lets a caller sign with a credentials object it already holds — the one behind an existing boto3 client, for instance — instead of a session. Credentials take precedence over the session and are still re-read per token, so rotation is preserved.
feat(python): accept a credentials object for token signing
Brings the Python 1.0.0 release commit (publish guard removed, CHANGELOG dated), CODEOWNERS, the Python CI token restriction and the dependabot bump onto release-2.
Set the version to 1.0.0 in the library, integration-tests and examples poms and the README, and date the CHANGELOG entry.
Set the version to 1.0.0, remove the private publish guard, and date the CHANGELOG entry.
Set the version to 1.1.0 and date the CHANGELOG entry for the token manager and the credentials parameter.
Release prep: Java 1.0.0, Node 1.0.0, Python 1.1.0
ogasarah
reviewed
Oct 22, 2026
dianadc13
approved these changes
Oct 22, 2026
ogasarah
approved these changes
Oct 22, 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.
What
Brings
release-2ontomainfor today's releases. Every change here was reviewed in its own PR againstrelease-2; this PR only moves them to the default branch so the release tags can be cut frommain.Java 1.0.0 (first release)
ElastiCacheIamAuthTokenManagerwith background refresh andrefreshToken()(feat(node): add node implementation #9, feat(java): Add Auto Refresh #13, Add forced IAM token refresh API to the Java toolkit #17).Node 1.0.0 (first release)
generateIamAuthToken(),ElastiCacheIAMAuthTokenProviderandElastiCacheIAMAuthTokenManager(Port IAM authentication to Java #10, feat(node): add auto-refresh #12).Python 1.1.0
ElastiCacheIAMAuthTokenManagerwith background refresh (feat(python): add ElastiCacheIAMAuthTokenManager (auto-refresh) #15).credentialsparameter for signing with a credentials object the caller already holds (feat(python): accept a credentials object for token signing #19).Release prep (#23): version bumps, dated CHANGELOGs, Node
privateguard removed, Dependabot duplicate pip entry dropped.After merge
Create the GitHub releases
java-v1.0.0,node-v1.0.0andpython-v1.1.0frommain, in that order. Each release workflow waits for approval on its environment (maven,npm,pypi) before publishing.