What’s new in v0.16.0
- A custom
loggerwhose method raises no longer fails an SDK operation. Every internal log call is contained, so a logging sink that raises - a full disk, a down syslog target - is dropped and the read, refresh, orcreate()(sync and async) that logged continues. The stream observer already had this guarantee; it now covers the logger too. The WIF credential source is deliberately not contained - it is on the auth path and still surfaces its error.
What’s new in v0.15.0
- The async client has the write API.
AsyncNexusClientgainsset_secret,delete_secretanddelete_secret_version, mirroringNexusClient; both route every write status through one shared path so they cannot drift. - The public-key guard reads the backend’s
key_type, not just the key prefix - a key the server reports as public is refused secrets even without thewxp_prefix, because either signal is enough. follow_redirectsis off on every HTTP client and the SSE line reader is bounded, so a credential-bearing request never follows a server-chosen redirect and a server that never emits a newline cannot make the client buffer without limit.- The async client keeps blocking file I/O off the event loop - file-secret writes and cleanup run in a worker thread.
- Thread safety and the free-threaded (no-GIL) position are documented.
- Changed: minimum
httpxis now>=0.26(0.25 does not import on Python 3.14).
What’s new in v0.14.0
- The WIF provider set is a type.
WIFProvideris aStrEnumunioned with the equivalentLiteral, so the enum member and the plain string both type-check and a value outside the set does not. Members are strings, so nothing changes at runtime; an invalid one raisesValueErroratWIFConfig(...). exchange_payloadbuilds the whole token-exchange body from anExchangeContext, so a credential that is not an OIDC token can be expressed - and theaws_iamshape is reachable withoutbotocoreif you sign the request yourself.- A
developerprovider. Afterwestyx dev setup,WIFConfig(enabled=True)authenticates a developer machine against a WIF-enforced service with the session the CLI already obtained - no token exchange, nothing to install. It is the last providerautoconsiders. - The API key and the session token stay out of
__repr__, which is what a traceback rendered with frame locals prints. - Breaking:
WIFConfigis keyword-only, andprovider="aws_iam"withtoken_sourceis refused.
What’s new in v0.13.0
- File-type secrets live in a per-client private directory, created
0700lazily on the first file-type secret; every file inside is created0600withO_EXCL, so the mode is a guarantee regardless of what already occupies the path. A process-levelatexithook removes the files even when the process exits withoutclose(). See File-type secret security. - A 402 Payment Required throttles the background refresh to one attempt every five minutes instead of ending it, and any successful sync - a
304 Not Modifiedincluded - clearsbilling_overdue. Settling the invoice restores service without a restart. - The SSE stream has an idle deadline - new
stream_idle_timeoutoption, default 90 s, sized against the server’s 30 s keepalives. A connection reaped by a load balancer surfaces as a transport error and reconnects instead of blocking forever. See SSE live updates. - Breaking:
ttl_seconds(andstream_idle_timeout) are validated atcreate()- zero, negatives andboolraiseValueErrornaming the option instead of silently becoming the default.
What’s new in v0.12.0
- Per-user flag targeting through the OpenFeature provider. With a targeting key in the evaluation context, a boolean flag is resolved through the AB Testing add-on, so its rollout percentage and cohort rules apply to that identity. One request serves every flag the snapshot knows for that identity, results are memoised, and concurrent evaluations for one identity coalesce into a single request. Without a targeting key nothing changes.
find_flag(key)on both clients returns the flag’sis_activestate orNonewhen the flag is not in the cache at all - the distinctionget_flagcannot express, and the one an OpenFeature provider needs in order to answerFLAG_NOT_FOUND.NexusProviderOptionstunes the targeting TTL, the memoised-identity cap and the add-on suppression window; a value that cannot work is rejected at construction, naming the option.- Breaking:
evaluate_abrefuses a non-string attribute value withTypeErrornaming the attribute, the provider no longer coerces numbers, and an unknown flag resolves asFLAG_NOT_FOUND.
What’s new in v0.11.0
A correctness and type-safety release. Nothing in the public API breaks.- Ships
py.typed(PEP 561) for both packages. Without the marker, type checkers ignore an installed package’s annotations entirely - every SDK call resolved toAnyin your project, however well annotated the SDK was. The SDK is now clean under bothmypy --strictandpyright. See Type checking. - SSE reconnect fixes. A misconfigured
sse_reconnect_cooldownused to kill the stream worker: the handler meant to fall back to the default schedule called a logger method that does not exist, and raised. The value is validated atcreate()now and rejected with a message naming the bad input. Separately,AsyncNexusClientignoredsse_reconnect_cooldownentirely and ended its stream permanently after three transient transport errors - it now reconnects on the configured schedule, matchingNexusClient. See SSE live updates. - The SSE client now has a connect timeout. Lifting the read deadline on a long-lived stream is right; lifting the connect deadline with it was not, and a connect to a black-holed endpoint hung indefinitely with no error and no reconnect.
- File-type secrets are written
0600, applied at creation rather than by a chmod afterwards, and opened withO_NOFOLLOW. Each client materialises to its own paths, so two clients holding the same secret never share a file. See File-type secret security. - A faulting stream observer is reported. Your observer still cannot break the SDK, but a callback that raises is logged with the hook name and the original exception instead of vanishing.
- No
assertin shipped code -python -Ostrips them, and the session-refresh precondition guard went with them. - CI gates on
ruff,mypy,pyrightandbandit, and the suite runs on Python 3.11 through 3.14 - every version this package advertises.
What’s new in v0.10.0
- Version alignment across the Westyx Nexus SDK suite.
What’s new in v0.9.0
aws_iamWIF provider (AWS IAM Caller Identity) - authenticates non-EKS AWS compute (ECS/Fargate, Lambda, plain EC2) that has IAM credentials but no OIDC token. The SDK SigV4-signs an STSGetCallerIdentityrequest (never sent to AWS) and posts it to/v1/auth/token-exchange; Nexus replays it against a pinned STS endpoint to prove your IAM role. The signedX-Nexus-Server-IDis your service’s own base-URL host - a captured request is valid for that one service only, and there is nothing to configure. Requires the optionalbotocoredependency (pip install 'westyx-nexus-sdk[aws-iam]'). See Workload identity.- Azure Workload Identity (AKS) - the
azureprovider now prefers the projected federated token file ($AZURE_FEDERATED_TOKEN_FILE) before falling back to IMDS; auto-detection probes the file too. - Probe-based auto-detection - auto-detect now stats the Kubernetes / AWS-IRSA / Azure token files and live-probes the GCP and Azure metadata servers (~1 s timeout), instead of keying on environment variables absent on real cloud nodes.
- Security hardening - both clients reject plain-http
base_urls (loopback excepted); the Azure IMDS path refuses the generic default audience (must beapi://<client-id>); the async client no longer blocks the event loop on metadata calls; thehttpx.Clientleak is fixed; metadata/exchange reads are bounded.
What’s new in v0.8.0
- OpenFeature provider - new
westyx-nexus-openfeaturesub-package shipsNexusProvider, anAbstractProviderfor the OpenFeature Python SDK. Wraps an existingNexusClient; booleans viaget_flag, string/integer/float/object viaget_config. See OpenFeature provider.
What’s new in v0.5.1
- Requires Python 3.11+ - Python 3.10 is EOL; minimum is now 3.11.
- Security improvements - exception messages contain only status codes; file-type secret paths are fully hashed; WIF tokens stripped of whitespace on all providers.
- WIF reliability - session refreshes before each SSE reconnect; expired sessions no longer cause permanent TTL-polling fallback.
- CI - tests run on merge requests; publish restricted to
main-branch tags.
What’s new in v0.5.0
- Write API -
set_secret,delete_secret,delete_secret_versionfor programmatic secret management. secret keys only; public keys raiseNexusPublicKeyErrorimmediately without a network call. NexusRateLimitedError- new error for HTTP 429 on write endpoints.
What’s new in v0.4.0
- Path prefix change - all API paths are now
/v1/(previously/api/v1/). Updatebase_urlto use<slug>.westyx.dev. NexusQuarantinedError- new typed error raised on429with quarantine body. Both sync and stream paths detect this.on_quarantined(reason, expires_at)observer callback -StreamObservergains a sixth callback; fires on quarantine events from both the stream and sync paths.- Quarantine backoff - stream sleeps until
expires_atbefore reconnecting; background sync is paused during the quarantine window. - Removed
ConfigEntry.is_public- the field is no longer populated.
Highlights
- Python 3.11+ - single runtime dependency (
httpx); the optionalaws_iamWIF provider addsbotocorevia the[aws-iam]extra - Both sync and async APIs -
NexusClientandAsyncNexusClientshare the same cache + SSE protocol; only the I/O model differs - Optional framework adapters - Django, FastAPI, Flask integrations via extras (
pip install "westyx-nexus-sdk[django]") - Thread-safe TTL cache with atomic snapshot replacement and ETag/304 support
- SSE live updates - propagates remote changes within milliseconds; falls back to TTL polling after 3 transport errors
- Typed error hierarchy -
NexusErrorbase + 13 subclasses forisinstance/exceptmatching - Workload Identity Federation (v0.2.0) - Kubernetes / AWS IRSA / GCP / Azure auto-detection; bearer JWT auth; AWS IAM (
aws_iam) for ECS/Fargate/Lambda/plain-EC2 (v0.9.0) - Stream observer hooks (v0.2.0) - structured callbacks for SSE lifecycle events
- AB Testing (v0.3.0) -
evaluate_abfor batch per-user flag evaluation - File-type secrets (v0.3.0) -
get_secret_file_pathmaterialisestype: "file"secrets to temp files - OpenFeature provider (v0.8.0) -
NexusProvidersub-package (westyx-nexus-openfeature) for the OpenFeature Python SDK - Fully typed (v0.11.0) - ships
py.typed; clean undermypy --strictandpyright
