Skip to content

Release Python SDK v17.3.0 - #1032

Merged
maksimu merged 1 commit into
masterfrom
release/sdk/python/core/v17.3.0
Jul 22, 2026
Merged

maksimu merged 1 commit into
masterfrom
release/sdk/python/core/v17.3.0

Conversation

@stas-schaller

@stas-schaller stas-schaller commented Jun 8, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Python Core SDK v17.3.0 and Python Helper v1.1.2. The release adds typed KeeperRecordLink linked-credential accessors (KSM-992), IL5 custom server public key support (KSM-932), automatic throttle retry with exponential backoff (KSM-877), and fixes four bugs: cryptic TypeError on None-valued config keys (KSM-808), partial config files left behind after failed OTT binding (KSM-807), incomplete Windows ACL cleanup (KSM-813), and RecordCreate.to_dict() silently dropping "custom": [] from the payload (KSM-819). Default behaviour is unchanged for all standard Keeper deployments.

Changes

New Features

  • Typed KeeperRecordLink linked-credential accessors (KSM-992): record.get_links() returns typed link objects with Java-parity accessors (user/permission booleans, encryption detection, AES-256-GCM get_decrypted_data, get_link_data, and ai_settings/jit_settings/generic settings access) plus accessors for the current backend payload shape verified against a live PAM app (meta links with an allowedSettings fallback for the permission booleans, is_iam_user/belongs_to/rotation_settings, get_allowed_settings()/get_meta_data()). Purely additive — the raw record.links list is unchanged and each typed link keeps the untouched original dict in .raw. get_pam_users()-style type filters are not buildable (link payloads carry no record type — same conclusion as Rust KSM-997). Review-hardened: get_link_data() now falls through to decryption when a plain-JSON parse fails, so encrypted ai_settings/jit_settings links whose ciphertext coincidentally begins with { or [ (~2/256) decrypt correctly instead of returning None.
  • Throttle retry with exponential backoff (KSM-877): on HTTP 403 {"error":"throttled"}, _post_query retries transparently up to 5 times with delays of 11s, 22s, 44s, 88s, 176s (±25% jitter), honoring retry_after from the response body when present. A typed KeeperThrottleError (subclass of KeeperError) is raised once retries are exhausted. All SecretsManager operations gain throttle resilience with no caller changes. Key-rotation retry behavior is unchanged.
  • Custom server public key support (KSM-932): three provisioning paths for injecting a non-default EC P-256 server public key at runtime, with explicit precedence (programmatic > one-time token > pre-existing config). Provisioning surfaces: a serverPublicKey field in storage, a 4-segment one-time-token extension (REGION:clientKey:keyId:serverPublicKeyBase64), and new server_public_key / server_public_key_id parameters on SecretsManager. Also fixes a long-standing missing raise in generate_transmission_key and prevents __init__ from silently resetting a non-standard key_id back to the default when a custom key is configured.

Bug Fixes

  • Cryptic TypeError on None-valued config keys (KSM-808): config-decoding utilities (base64_to_bytes, url_safe_str_to_bytes, base64_to_string, CryptoUtils.url_safe_str_to_bytes) now raise KeeperError with actionable messages instead of TypeError when passed None. Per-call-site guards in core.py name the specific missing ConfigKey (appKey, clientKey) and direct the user to reinitialize with a fresh One-Time Token. Customer-reported.
  • Partial config left behind after failed binding (KSM-807): SDK now deletes the incomplete client-config.json when OTT binding fails (expired or already-consumed token) so users are not silently trapped in a retry loop. The error message names the deleted file and instructs the user to generate a fresh token.
  • Windows icacls Everyone ACE not fully removed (KSM-813): set_config_mode() now removes all Everyone ACEs from the config file, not only Full Control. A read-only Everyone ACE could persist after the previous sequence.
  • RecordCreate.to_dict() drops "custom": [] from payload (KSM-819): falsy check (if self.custom:) silently dropped an empty custom-fields list before serialization, making the KSM-702 CLI fix ineffective at the SDK level. Changed to if self.custom is not None:.
  • Populate empty LICENSE files across 4 packages (core, helper, CLI, storage). All four shipped as 0-byte files declaring MIT in setup.py — legal/compliance gap that would publish to PyPI as a license-claim-without-text.
  • Runtime Python version guard mismatch: core.py runtime check raised on < 3.6 while setup.py python_requires and classifiers required >= 3.9 (announced in v17.2.0). Updated guard to match.
  • 4-segment one-time-token parser hardening: malformed tokens (wrong segment count, empty keyId or serverPublicKey segments, invalid base64) now raise ValueError at construction. Previously these silently degraded to default-key behavior.

Maintenance

  • Python Helper at 1.1.2; core dependency tightened to >=17.3.0. Helper version pairs 1:1 with core.
  • Hardcoded fallback version updated (17.2.1 → 17.3.0) in keeper_globals.py and smoke test assertions.
  • Docstrings added to new public API surface: SecretsManager.__init__'s new constructor params and generate_transmission_key's new arg, including precedence documentation.
  • README section documenting the three provisioning paths in generic terms.
  • CHANGELOG.md removed: README is the single source of truth for the PyPI changelog.
  • Lazy KSM_CACHE_DIR resolution (KSM-1004): KSMCache now reads the cache directory at call time instead of once at import, so the env var is honored whenever it is set (not only pre-import). kms_cache_file_name is kept for backward compatibility; default CWD-relative behavior is unchanged.

Breaking Changes

None. The new field, parameter, and 4-segment token format are opt-in. The new parser errors only fire on inputs that previously silently degraded — no caller relying on documented v17.2.1 behavior is affected.

Related Issues

@stas-schaller
stas-schaller marked this pull request as ready for review June 8, 2026 19:49
idimov-keeper
idimov-keeper previously approved these changes Jun 9, 2026
idimov-keeper
idimov-keeper previously approved these changes Jun 13, 2026
@stas-schaller
stas-schaller force-pushed the release/sdk/python/core/v17.3.0 branch from c05fd59 to b0c41a8 Compare June 15, 2026 21:58
KSM-992: typed KeeperRecordLink accessor layer and Record.get_links()
KSM-877: automatic throttle retry with exponential backoff
KSM-932: IL5 custom server public key support
KSM-808: KeeperError with actionable messages on missing config keys
KSM-807: delete partial config on failed OTT initialization
KSM-813: Windows set_config_mode() removes all Everyone ACEs
KSM-819: RecordCreate.to_dict() no longer drops empty custom list
KSM-1004: KSMCache resolves KSM_CACHE_DIR at call time

Co-authored-by: Mateo Gallego <mgallego@keepersecurity.com>
@maksimu
maksimu merged commit b4c821d into master Jul 22, 2026
37 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.

3 participants