From 4ce0a87815774879b80d8851774e577122c40878 Mon Sep 17 00:00:00 2001 From: Tamir Date: Wed, 12 Aug 2026 11:45:07 +0300 Subject: [PATCH] v1.24.1 --- CHANGELOG.md | 10 +++++----- pyproject.toml | 2 +- uv.lock | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cdd1a2f..392eea5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,13 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [1.24.1] - 2026-08-12 + ### Security - Fixed a path traversal issue where a resource name or id containing `../` was resolved while the request was prepared, retargeting the call at a different API endpoint under the SDK's own credentials (for example `containers.delete_deployment('../../v1/instances')` issued `DELETE /v1/instances`). This also prevents a name from injecting query parameters, such as overriding the `force` flag of `containers.delete_secret`. Caller-supplied path values are no longer interpolated into the request path. `HTTPClient.get/post/put/patch/delete` now accept a keyword-only `path_params` mapping whose values are validated as a single path segment before substitution, and all service modules pass names and ids that way. This covers `instances.is_available()` and `clusters.is_available()`, where the affected value was the `instance_type`/`cluster_type`. As a backstop, `HTTPClient` refuses to send a request whose path would escape the API base path. - `InferenceClient` paths are validated too: `path` may still span several segments, but it can no longer walk out of the deployment's base url. + A path value must be a `str`, `int` or `UUID` and match `[A-Za-z0-9._~-]+` (the RFC 3986 unreserved set); anything else — a separator, `.`/`..`, an empty value, `None`, or an unsupported type — now raises `ValueError` instead of being percent-encoded and sent. Every id and name the API actually accepts in a path position already falls within this set (ids are UUIDs; deployment, job and secret names are validated server-side against RFC 1123 or Kubernetes secret-name rules), so this closes off attack input without affecting documented usage. If you have a name that was already URL-encoded, pass the raw name instead: `get_deployment_by_name('my%20deployment')` now raises rather than looking up a deployment literally named `my%20deployment`. + + `InferenceClient` paths are validated too: `path` may still span several segments, but it can no longer walk out of the deployment's base url. `InferenceClient` also now requires `endpoint_base_url` to include the deployment path — `InferenceClient(key, 'https://containers.example.com')` previously produced a `base_domain` of `https:/`, sending async status and result requests to a host named `status`/`result` while still carrying the inference key. The API never returns a bare host, so this only catches a hand-typed URL that dropped the deployment name. ### Added @@ -24,10 +28,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed -- **Breaking:** a resource name or id used in a request path must now match `[A-Za-z0-9._~-]+` (the RFC 3986 unreserved set). Anything else raises `ValueError` instead of being percent-encoded and sent — including `/`, `\`, `%`, spaces, `?`, `#` and non-ASCII characters. Every name the API takes in a path position is a slug, an id or a machine type (`my-deployment`, `1A100.22V`, a UUID), so ordinary calls are unaffected. If you have a name that was already URL-encoded, pass the raw name: `get_deployment_by_name('my%20deployment')` now raises rather than looking up a deployment literally named `my%20deployment`. -- **Breaking:** a relative path segment (`.` or `..`), an empty value, or `None` raises `ValueError`. Encoding is not sufficient for these: `%2E` is decoded back to `.` before the request is sent. -- **Breaking:** a path value that is not a `str`, `int` or `UUID` now raises `ValueError` rather than being coerced with `str()` into a nonsense path segment. -- **Breaking:** `InferenceClient` now requires `endpoint_base_url` to include the deployment path. `InferenceClient(key, 'https://containers.example.com')` previously produced a `base_domain` of `https:/`, sending async status and result requests to a host named `status`/`result` while still carrying the inference key. - Refactored `Image` model to use `@dataclass` and `@dataclass_json` for consistency with `Instance` and `Volume` - License changed from MIT to Apache 2.0 diff --git a/pyproject.toml b/pyproject.toml index 4005857..18cd099 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "verda" -version = "1.24.0" +version = "1.24.1" description = "Official Python SDK for Verda (formerly DataCrunch) Public API" readme = "README.md" requires-python = ">=3.10" diff --git a/uv.lock b/uv.lock index dc6869a..1970f1f 100644 --- a/uv.lock +++ b/uv.lock @@ -509,7 +509,7 @@ wheels = [ [[package]] name = "verda" -version = "1.24.0" +version = "1.24.1" source = { editable = "." } dependencies = [ { name = "dataclasses-json" },