Skip to content

Release: Java 1.0.0, Node 1.0.0, Python 1.1.0 - #24

Merged
mwaisaida-13 merged 49 commits into
mainfrom
release-2
Oct 22, 2026
Merged

mwaisaida-13 merged 49 commits into
mainfrom
release-2

Conversation

@mwaisaida-13

Copy link
Copy Markdown
Collaborator

What

Brings release-2 onto main for today's releases. Every change here was reviewed in its own PR against release-2; this PR only moves them to the default branch so the release tags can be cut from main.

Java 1.0.0 (first release)

Node 1.0.0 (first release)

Python 1.1.0

Release prep (#23): version bumps, dated CHANGELOGs, Node private guard removed, Dependabot duplicate pip entry dropped.

After merge

Create the GitHub releases java-v1.0.0, node-v1.0.0 and python-v1.1.0 from main, in that order. Each release workflow waits for approval on its environment (maven, npm, pypi) before publishing.

edlng and others added 30 commits September 11, 2026 13:01
Signed-off-by: Edward Liang <liawedwa@amazon.com>
…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)
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.
mwaisaida-13 and others added 19 commits September 24, 2026 23:47
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.
The /python entry already scans python/requirements/dev.txt, so the second entry
opened a duplicate PR for every tooling bump (for example #21 and #22).
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
@mwaisaida-13
mwaisaida-13 requested a review from a team as a code owner October 22, 2026 08:49
@mwaisaida-13
mwaisaida-13 requested a review from ogasarah October 22, 2026 08:51
Comment thread java/README.md
@mwaisaida-13
mwaisaida-13 merged commit b66900d into main Oct 22, 2026
49 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants