5.11.0 — 2026-10-13¶
← 5.12.0 | 5.10.0 → | ↑ 5.x series
Added¶
Configs - Auth¶
AUTH.JWT_LEEWAY- Clock-skew tolerance in seconds applied toexp,nbfandiatwhen verifying tokens (default0).
Configs - Keycloak¶
KEYCLOAK.REMOTE_CACHE_TTL_SECONDS- Opt-in cache forUserInfoand UMA permission lookups inKeycloakUtils(default0, off). A revoked token stays accepted for up to this long when enabled.
Helpers - Utils¶
verify_totpreplay guard -verify_totptakes an optionalreplay_guard(step)callable that is called with the matched time step for a valid code. ReturningFalserejects the code.keep_zwnjoption -clean_spacingandnormalize_persian_textcan keep the zero-width non-joiner instead of turning it into a space.
Helpers - Interceptors¶
request_validation()- Context manager exported fromarchipy.helpers.interceptors.grpc.exception; a PydanticValidationErrorraised inside it is reported asINVALID_ARGUMENT.trusted_proxy_hosts- The rate-limit interceptors readx-forwarded-foronly when the direct peer is a trusted proxy, so callers behind a load balancer no longer share one bucket.
Changed¶
Helpers - Utils¶
- BREAKING: HMAC signing keys have a minimum length -
JWTUtilsraisesInvalidArgumentErrorwhenSECRET_KEYis shorter than RFC 7518 requires: 32 bytes for HS256, 48 for HS384 and 64 for HS512. It checks on both create and decode, and refuses thenonealgorithm. - Password hash format - Hashes are stored as
pbkdf2_sha256$iterations$salt$hash, and the defaultAUTH.HASH_ITERATIONSis now600000.- Hashes in the old format still verify, using the configured iterations and then
100000 PASSWORD_HISTORY_SIZE=0disables the history check, and negative values are rejected
- Hashes in the old format still verify, using the configured iterations and then
- TOTP expiry and secrets -
generate_totpreports an expiry no later than the end of the verification window. Secrets that are valid base32 are decoded, so authenticator apps produce matching codes. - BREAKING:
additional_claimscannot redefine registered claims -JWTUtils.create_tokenand the token helpers raiseInvalidArgumentErrorwhenadditional_claimscontainsiss,aud,jtior any key already set by the token data (for examplesub,typeandtoken_version). Time claims such asexpcan still be overridden. - Persian punctuation -
normalize_punctuationconverts ASCII,,?,;,%and_only next to Persian text, so numbers (1,000), URLs, e-mails and identifiers are left intact.remove_punctuationstill strips them.
Helpers - Interceptors¶
- BREAKING: handler
ValidationErrormaps toINTERNAL- A PydanticValidationErrorraised by handler code is a server fault, so it is no longer reported asINVALID_ARGUMENT.- Wrap request parsing in
request_validation()to keepINVALID_ARGUMENT - Pass
validation_errors_as_invalid_argument=Trueto the exception interceptors to restore the old mapping
- Wrap request parsing in
- Interceptor order -
customized_interceptorsaccepts a sequence and keeps its order; a set still works but has no guaranteed order. - Rate-limit startup - A failed rate-limit setup raises when
GRPC_RATE_LIMIT.FAIL_CLOSEDis set instead of starting an unprotected server.
Fixed¶
Helpers - Interceptors¶
- Deliberate aborts are kept - The sync exception interceptor no longer rewrites
context.abort()(for exampleRESOURCE_EXHAUSTEDfrom the rate limiter) toINTERNAL, and the async one no longer aborts a second time afterAbortError. - Internal details stay server-side - Unexpected errors send a bare
InternalError; the error text, type and method names are no longer put in trailing metadata. Validation errors no longer echo the submitted input, and trailing metadata is capped at 4096 bytes and serialized withdefault=str. - Rate limits behind other interceptors - The base interceptor closures use
functools.wraps, so decorated RPCs are still limited when a custom interceptor follows the rate limiter. - Rate-limit edge cases - A handler that returns
Noneno longer runs twice when failing open, a rejected call refunds the quota of earlier windows, a failingidentifier_fnskips limiting instead of pooling callers, and JWT verification runs off the event loop. Window metadata and the auth config are cached. - Metrics statuses - Cancelled RPCs and closed streams are recorded as
cancelled, the final gRPC status code is recorded asrpc.grpc.status_code, and handled client errors count asok. generic_exception_handler- Records the real exception instead of a bareUnknownError.- Rate-limit windows - Negative time components are rejected.
Helpers - Utils¶
- TOTP - The code length comes from
TOTP_LENGTH, so a one-digit code can no longer match, and non-ASCII digits are rejected instead of raisingTypeError. - Keycloak auth -
grpc_authandasync_grpc_authsupport streaming handlers and keep the auth context through the stream, aborts pass through, token parsing is case-insensitive on the scheme and rejects repeated or emptyauthorizationvalues, and failure causes are logged instead of sent to the client. - OTel - A failed initialization retries only after a 30 second back-off, shut-down providers are tracked in a
WeakSet, the Pushgateway loop sends a final push on shutdown, and the shared instrument cache is locked. - Datetime - A
%zoffset parsed from a string is kept, the holiday cache is locked and bounded,daterangecounts calendar dates, and a non-JSON holiday response raisesUnknownError. - Strings - Noon and Zal tables no longer corrupt text,
snake_to_camel_casekeeps inner capitals,replace_numbers_with_maskworks in one pass, the currency mask no longer matches backslashes, and punctuation spacing no longer splitsfile.txt. - Files and national codes - Allowed extensions match case-insensitively and with a leading dot; the national-code validator rejects non-ASCII digits and repeated-digit codes.
Singleton- Uses a reentrant lock, so a singleton can build another singleton.
Tests¶
- BDD coverage - Added scenarios to the existing TOTP, password, JWT, datetime, string, file, base utils, singleton, error handling, app utils, gRPC helpers, rate-limit, OTel and Keycloak features, including real in-process sync and async gRPC servers for the abort, metrics and rate-limit behavior.