From 7dbb9ba18814a4cb8dcbb8f81b34cf5e484e780f Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Mon, 12 Jan 2026 14:46:36 +0000
Subject: [PATCH 01/27] codegen metadata
---
.stats.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.stats.yml b/.stats.yml
index e42a5ca..cf214ce 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 160
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-3935e467f9c15925790aada293124db82bb5d6840eeac52d81fbac6a9b0fd154.yml
-openapi_spec_hash: b417d7f10ea430216e9b70e4468a3212
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-bc2d9ee7f9a0aea1a4305b5487eac32742d6aea1e515616a8a2eda759cbb5b8f.yml
+openapi_spec_hash: 1832681b749df9e2a56e2ca728572575
config_hash: d3267594264bfb76d2ee7e881d5f8a5a
From 03bd1858ec2aefbd4c20a71c206135c441afa99c Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Mon, 12 Jan 2026 15:45:23 +0000
Subject: [PATCH 02/27] feat: Define SCIMConfiguration database schema
---
.stats.yml | 4 ++--
src/gitpod/types/shared/resource_type.py | 1 +
src/gitpod/types/shared_params/resource_type.py | 1 +
3 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/.stats.yml b/.stats.yml
index cf214ce..df7a521 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 160
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-bc2d9ee7f9a0aea1a4305b5487eac32742d6aea1e515616a8a2eda759cbb5b8f.yml
-openapi_spec_hash: 1832681b749df9e2a56e2ca728572575
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-f35d75f04023f8de20cc787ab5202c4853a79ea14fa8e639f598e034b312207f.yml
+openapi_spec_hash: 0b2bf8b46a5bb29402fb9ae08ce6314f
config_hash: d3267594264bfb76d2ee7e881d5f8a5a
diff --git a/src/gitpod/types/shared/resource_type.py b/src/gitpod/types/shared/resource_type.py
index 1a18f4e..7531c05 100644
--- a/src/gitpod/types/shared/resource_type.py
+++ b/src/gitpod/types/shared/resource_type.py
@@ -48,4 +48,5 @@
"RESOURCE_TYPE_ROLE_ASSIGNMENT_CHANGED",
"RESOURCE_TYPE_GROUP_MEMBERSHIP_CHANGED",
"RESOURCE_TYPE_WEBHOOK",
+ "RESOURCE_TYPE_SCIM_CONFIGURATION",
]
diff --git a/src/gitpod/types/shared_params/resource_type.py b/src/gitpod/types/shared_params/resource_type.py
index 793bab2..34d2f8c 100644
--- a/src/gitpod/types/shared_params/resource_type.py
+++ b/src/gitpod/types/shared_params/resource_type.py
@@ -50,4 +50,5 @@
"RESOURCE_TYPE_ROLE_ASSIGNMENT_CHANGED",
"RESOURCE_TYPE_GROUP_MEMBERSHIP_CHANGED",
"RESOURCE_TYPE_WEBHOOK",
+ "RESOURCE_TYPE_SCIM_CONFIGURATION",
]
From 2847a10e6cbb09be83b012e8a6fcabd32f49e019 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Mon, 12 Jan 2026 17:15:56 +0000
Subject: [PATCH 03/27] feat(api): improve SearchRepositories pagination with
next_page and total_count
---
.stats.yml | 4 ++--
.../runner_search_repositories_response.py | 19 ++++++++++++++++---
2 files changed, 18 insertions(+), 5 deletions(-)
diff --git a/.stats.yml b/.stats.yml
index df7a521..7ce5377 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 160
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-f35d75f04023f8de20cc787ab5202c4853a79ea14fa8e639f598e034b312207f.yml
-openapi_spec_hash: 0b2bf8b46a5bb29402fb9ae08ce6314f
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-b40906da1a429be933f59cd9c3b2f7197aef9b302033558e7cbb65579357240a.yml
+openapi_spec_hash: bc0aec8cac7bfb2a69792bb43cfe50d2
config_hash: d3267594264bfb76d2ee7e881d5f8a5a
diff --git a/src/gitpod/types/runner_search_repositories_response.py b/src/gitpod/types/runner_search_repositories_response.py
index 65597de..e4f7350 100644
--- a/src/gitpod/types/runner_search_repositories_response.py
+++ b/src/gitpod/types/runner_search_repositories_response.py
@@ -10,7 +10,12 @@
class Pagination(BaseModel):
- """Pagination information for the response"""
+ """
+ Pagination information for the response.
+ Token format: "NEXT_PAGE/TOTAL_PAGES/TOTAL_COUNT" (e.g., "2/40/1000").
+ Use -1 for unknown values (e.g., "2/-1/-1" when totals unavailable).
+ Empty token means no more pages.
+ """
next_token: Optional[str] = FieldInfo(alias="nextToken", default=None)
"""Token passed for retrieving the next set of results.
@@ -29,10 +34,18 @@ class Repository(BaseModel):
class RunnerSearchRepositoriesResponse(BaseModel):
last_page: Optional[int] = FieldInfo(alias="lastPage", default=None)
- """Last page in the responses"""
+ """Deprecated: Use pagination token instead.
+
+ Total pages can be extracted from token.
+ """
pagination: Optional[Pagination] = None
- """Pagination information for the response"""
+ """
+ Pagination information for the response. Token format:
+ "NEXT_PAGE/TOTAL_PAGES/TOTAL_COUNT" (e.g., "2/40/1000"). Use -1 for unknown
+ values (e.g., "2/-1/-1" when totals unavailable). Empty token means no more
+ pages.
+ """
repositories: Optional[List[Repository]] = None
"""List of repositories matching the search criteria"""
From 1bc205897a717cae24f866eee3db2f91148b9ee7 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Tue, 13 Jan 2026 11:28:32 +0000
Subject: [PATCH 04/27] codegen metadata
---
.stats.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.stats.yml b/.stats.yml
index 7ce5377..d535149 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 160
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-b40906da1a429be933f59cd9c3b2f7197aef9b302033558e7cbb65579357240a.yml
-openapi_spec_hash: bc0aec8cac7bfb2a69792bb43cfe50d2
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-46e0124fe8e07933a6ea784e81b4d02086696c246f519aaa34b087f46410c818.yml
+openapi_spec_hash: fe98c15ea1e320c05593cd57457e4af5
config_hash: d3267594264bfb76d2ee7e881d5f8a5a
From be5a8235224ff1ecf25464e716191fbf3c7c7fb1 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Tue, 13 Jan 2026 18:36:02 +0000
Subject: [PATCH 05/27] feat(client): add support for binary request streaming
---
src/gitpod/_base_client.py | 145 +++++++++++++++++++++++++---
src/gitpod/_models.py | 17 +++-
src/gitpod/_types.py | 9 ++
tests/test_client.py | 187 ++++++++++++++++++++++++++++++++++++-
4 files changed, 344 insertions(+), 14 deletions(-)
diff --git a/src/gitpod/_base_client.py b/src/gitpod/_base_client.py
index 1613979..e6ccedf 100644
--- a/src/gitpod/_base_client.py
+++ b/src/gitpod/_base_client.py
@@ -9,6 +9,7 @@
import inspect
import logging
import platform
+import warnings
import email.utils
from types import TracebackType
from random import random
@@ -51,9 +52,11 @@
ResponseT,
AnyMapping,
PostParser,
+ BinaryTypes,
RequestFiles,
HttpxSendArgs,
RequestOptions,
+ AsyncBinaryTypes,
HttpxRequestFiles,
ModelBuilderProtocol,
not_given,
@@ -477,8 +480,19 @@ def _build_request(
retries_taken: int = 0,
) -> httpx.Request:
if log.isEnabledFor(logging.DEBUG):
- log.debug("Request options: %s", model_dump(options, exclude_unset=True))
-
+ log.debug(
+ "Request options: %s",
+ model_dump(
+ options,
+ exclude_unset=True,
+ # Pydantic v1 can't dump every type we support in content, so we exclude it for now.
+ exclude={
+ "content",
+ }
+ if PYDANTIC_V1
+ else {},
+ ),
+ )
kwargs: dict[str, Any] = {}
json_data = options.json_data
@@ -532,7 +546,13 @@ def _build_request(
is_body_allowed = options.method.lower() != "get"
if is_body_allowed:
- if isinstance(json_data, bytes):
+ if options.content is not None and json_data is not None:
+ raise TypeError("Passing both `content` and `json_data` is not supported")
+ if options.content is not None and files is not None:
+ raise TypeError("Passing both `content` and `files` is not supported")
+ if options.content is not None:
+ kwargs["content"] = options.content
+ elif isinstance(json_data, bytes):
kwargs["content"] = json_data
else:
kwargs["json"] = json_data if is_given(json_data) else None
@@ -1194,6 +1214,7 @@ def post(
*,
cast_to: Type[ResponseT],
body: Body | None = None,
+ content: BinaryTypes | None = None,
options: RequestOptions = {},
files: RequestFiles | None = None,
stream: Literal[False] = False,
@@ -1206,6 +1227,7 @@ def post(
*,
cast_to: Type[ResponseT],
body: Body | None = None,
+ content: BinaryTypes | None = None,
options: RequestOptions = {},
files: RequestFiles | None = None,
stream: Literal[True],
@@ -1219,6 +1241,7 @@ def post(
*,
cast_to: Type[ResponseT],
body: Body | None = None,
+ content: BinaryTypes | None = None,
options: RequestOptions = {},
files: RequestFiles | None = None,
stream: bool,
@@ -1231,13 +1254,25 @@ def post(
*,
cast_to: Type[ResponseT],
body: Body | None = None,
+ content: BinaryTypes | None = None,
options: RequestOptions = {},
files: RequestFiles | None = None,
stream: bool = False,
stream_cls: type[_StreamT] | None = None,
) -> ResponseT | _StreamT:
+ if body is not None and content is not None:
+ raise TypeError("Passing both `body` and `content` is not supported")
+ if files is not None and content is not None:
+ raise TypeError("Passing both `files` and `content` is not supported")
+ if isinstance(body, bytes):
+ warnings.warn(
+ "Passing raw bytes as `body` is deprecated and will be removed in a future version. "
+ "Please pass raw bytes via the `content` parameter instead.",
+ DeprecationWarning,
+ stacklevel=2,
+ )
opts = FinalRequestOptions.construct(
- method="post", url=path, json_data=body, files=to_httpx_files(files), **options
+ method="post", url=path, json_data=body, content=content, files=to_httpx_files(files), **options
)
return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls))
@@ -1247,11 +1282,23 @@ def patch(
*,
cast_to: Type[ResponseT],
body: Body | None = None,
+ content: BinaryTypes | None = None,
files: RequestFiles | None = None,
options: RequestOptions = {},
) -> ResponseT:
+ if body is not None and content is not None:
+ raise TypeError("Passing both `body` and `content` is not supported")
+ if files is not None and content is not None:
+ raise TypeError("Passing both `files` and `content` is not supported")
+ if isinstance(body, bytes):
+ warnings.warn(
+ "Passing raw bytes as `body` is deprecated and will be removed in a future version. "
+ "Please pass raw bytes via the `content` parameter instead.",
+ DeprecationWarning,
+ stacklevel=2,
+ )
opts = FinalRequestOptions.construct(
- method="patch", url=path, json_data=body, files=to_httpx_files(files), **options
+ method="patch", url=path, json_data=body, content=content, files=to_httpx_files(files), **options
)
return self.request(cast_to, opts)
@@ -1261,11 +1308,23 @@ def put(
*,
cast_to: Type[ResponseT],
body: Body | None = None,
+ content: BinaryTypes | None = None,
files: RequestFiles | None = None,
options: RequestOptions = {},
) -> ResponseT:
+ if body is not None and content is not None:
+ raise TypeError("Passing both `body` and `content` is not supported")
+ if files is not None and content is not None:
+ raise TypeError("Passing both `files` and `content` is not supported")
+ if isinstance(body, bytes):
+ warnings.warn(
+ "Passing raw bytes as `body` is deprecated and will be removed in a future version. "
+ "Please pass raw bytes via the `content` parameter instead.",
+ DeprecationWarning,
+ stacklevel=2,
+ )
opts = FinalRequestOptions.construct(
- method="put", url=path, json_data=body, files=to_httpx_files(files), **options
+ method="put", url=path, json_data=body, content=content, files=to_httpx_files(files), **options
)
return self.request(cast_to, opts)
@@ -1275,9 +1334,19 @@ def delete(
*,
cast_to: Type[ResponseT],
body: Body | None = None,
+ content: BinaryTypes | None = None,
options: RequestOptions = {},
) -> ResponseT:
- opts = FinalRequestOptions.construct(method="delete", url=path, json_data=body, **options)
+ if body is not None and content is not None:
+ raise TypeError("Passing both `body` and `content` is not supported")
+ if isinstance(body, bytes):
+ warnings.warn(
+ "Passing raw bytes as `body` is deprecated and will be removed in a future version. "
+ "Please pass raw bytes via the `content` parameter instead.",
+ DeprecationWarning,
+ stacklevel=2,
+ )
+ opts = FinalRequestOptions.construct(method="delete", url=path, json_data=body, content=content, **options)
return self.request(cast_to, opts)
def get_api_list(
@@ -1717,6 +1786,7 @@ async def post(
*,
cast_to: Type[ResponseT],
body: Body | None = None,
+ content: AsyncBinaryTypes | None = None,
files: RequestFiles | None = None,
options: RequestOptions = {},
stream: Literal[False] = False,
@@ -1729,6 +1799,7 @@ async def post(
*,
cast_to: Type[ResponseT],
body: Body | None = None,
+ content: AsyncBinaryTypes | None = None,
files: RequestFiles | None = None,
options: RequestOptions = {},
stream: Literal[True],
@@ -1742,6 +1813,7 @@ async def post(
*,
cast_to: Type[ResponseT],
body: Body | None = None,
+ content: AsyncBinaryTypes | None = None,
files: RequestFiles | None = None,
options: RequestOptions = {},
stream: bool,
@@ -1754,13 +1826,25 @@ async def post(
*,
cast_to: Type[ResponseT],
body: Body | None = None,
+ content: AsyncBinaryTypes | None = None,
files: RequestFiles | None = None,
options: RequestOptions = {},
stream: bool = False,
stream_cls: type[_AsyncStreamT] | None = None,
) -> ResponseT | _AsyncStreamT:
+ if body is not None and content is not None:
+ raise TypeError("Passing both `body` and `content` is not supported")
+ if files is not None and content is not None:
+ raise TypeError("Passing both `files` and `content` is not supported")
+ if isinstance(body, bytes):
+ warnings.warn(
+ "Passing raw bytes as `body` is deprecated and will be removed in a future version. "
+ "Please pass raw bytes via the `content` parameter instead.",
+ DeprecationWarning,
+ stacklevel=2,
+ )
opts = FinalRequestOptions.construct(
- method="post", url=path, json_data=body, files=await async_to_httpx_files(files), **options
+ method="post", url=path, json_data=body, content=content, files=await async_to_httpx_files(files), **options
)
return await self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)
@@ -1770,11 +1854,28 @@ async def patch(
*,
cast_to: Type[ResponseT],
body: Body | None = None,
+ content: AsyncBinaryTypes | None = None,
files: RequestFiles | None = None,
options: RequestOptions = {},
) -> ResponseT:
+ if body is not None and content is not None:
+ raise TypeError("Passing both `body` and `content` is not supported")
+ if files is not None and content is not None:
+ raise TypeError("Passing both `files` and `content` is not supported")
+ if isinstance(body, bytes):
+ warnings.warn(
+ "Passing raw bytes as `body` is deprecated and will be removed in a future version. "
+ "Please pass raw bytes via the `content` parameter instead.",
+ DeprecationWarning,
+ stacklevel=2,
+ )
opts = FinalRequestOptions.construct(
- method="patch", url=path, json_data=body, files=await async_to_httpx_files(files), **options
+ method="patch",
+ url=path,
+ json_data=body,
+ content=content,
+ files=await async_to_httpx_files(files),
+ **options,
)
return await self.request(cast_to, opts)
@@ -1784,11 +1885,23 @@ async def put(
*,
cast_to: Type[ResponseT],
body: Body | None = None,
+ content: AsyncBinaryTypes | None = None,
files: RequestFiles | None = None,
options: RequestOptions = {},
) -> ResponseT:
+ if body is not None and content is not None:
+ raise TypeError("Passing both `body` and `content` is not supported")
+ if files is not None and content is not None:
+ raise TypeError("Passing both `files` and `content` is not supported")
+ if isinstance(body, bytes):
+ warnings.warn(
+ "Passing raw bytes as `body` is deprecated and will be removed in a future version. "
+ "Please pass raw bytes via the `content` parameter instead.",
+ DeprecationWarning,
+ stacklevel=2,
+ )
opts = FinalRequestOptions.construct(
- method="put", url=path, json_data=body, files=await async_to_httpx_files(files), **options
+ method="put", url=path, json_data=body, content=content, files=await async_to_httpx_files(files), **options
)
return await self.request(cast_to, opts)
@@ -1798,9 +1911,19 @@ async def delete(
*,
cast_to: Type[ResponseT],
body: Body | None = None,
+ content: AsyncBinaryTypes | None = None,
options: RequestOptions = {},
) -> ResponseT:
- opts = FinalRequestOptions.construct(method="delete", url=path, json_data=body, **options)
+ if body is not None and content is not None:
+ raise TypeError("Passing both `body` and `content` is not supported")
+ if isinstance(body, bytes):
+ warnings.warn(
+ "Passing raw bytes as `body` is deprecated and will be removed in a future version. "
+ "Please pass raw bytes via the `content` parameter instead.",
+ DeprecationWarning,
+ stacklevel=2,
+ )
+ opts = FinalRequestOptions.construct(method="delete", url=path, json_data=body, content=content, **options)
return await self.request(cast_to, opts)
def get_api_list(
diff --git a/src/gitpod/_models.py b/src/gitpod/_models.py
index ca9500b..29070e0 100644
--- a/src/gitpod/_models.py
+++ b/src/gitpod/_models.py
@@ -3,7 +3,20 @@
import os
import inspect
import weakref
-from typing import TYPE_CHECKING, Any, Type, Union, Generic, TypeVar, Callable, Optional, cast
+from typing import (
+ IO,
+ TYPE_CHECKING,
+ Any,
+ Type,
+ Union,
+ Generic,
+ TypeVar,
+ Callable,
+ Iterable,
+ Optional,
+ AsyncIterable,
+ cast,
+)
from datetime import date, datetime
from typing_extensions import (
List,
@@ -787,6 +800,7 @@ class FinalRequestOptionsInput(TypedDict, total=False):
timeout: float | Timeout | None
files: HttpxRequestFiles | None
idempotency_key: str
+ content: Union[bytes, bytearray, IO[bytes], Iterable[bytes], AsyncIterable[bytes], None]
json_data: Body
extra_json: AnyMapping
follow_redirects: bool
@@ -805,6 +819,7 @@ class FinalRequestOptions(pydantic.BaseModel):
post_parser: Union[Callable[[Any], Any], NotGiven] = NotGiven()
follow_redirects: Union[bool, None] = None
+ content: Union[bytes, bytearray, IO[bytes], Iterable[bytes], AsyncIterable[bytes], None] = None
# It should be noted that we cannot use `json` here as that would override
# a BaseModel method in an incompatible fashion.
json_data: Union[Body, None] = None
diff --git a/src/gitpod/_types.py b/src/gitpod/_types.py
index ab7cbe2..dbebac0 100644
--- a/src/gitpod/_types.py
+++ b/src/gitpod/_types.py
@@ -13,9 +13,11 @@
Mapping,
TypeVar,
Callable,
+ Iterable,
Iterator,
Optional,
Sequence,
+ AsyncIterable,
)
from typing_extensions import (
Set,
@@ -56,6 +58,13 @@
else:
Base64FileInput = Union[IO[bytes], PathLike]
FileContent = Union[IO[bytes], bytes, PathLike] # PathLike is not subscriptable in Python 3.8.
+
+
+# Used for sending raw binary data / streaming data in request bodies
+# e.g. for file uploads without multipart encoding
+BinaryTypes = Union[bytes, bytearray, IO[bytes], Iterable[bytes]]
+AsyncBinaryTypes = Union[bytes, bytearray, IO[bytes], AsyncIterable[bytes]]
+
FileTypes = Union[
# file (or bytes)
FileContent,
diff --git a/tests/test_client.py b/tests/test_client.py
index f948b8a..81db6c8 100644
--- a/tests/test_client.py
+++ b/tests/test_client.py
@@ -8,10 +8,11 @@
import json
import asyncio
import inspect
+import dataclasses
import tracemalloc
-from typing import Any, Union, cast
+from typing import Any, Union, TypeVar, Callable, Iterable, Iterator, Optional, Coroutine, cast
from unittest import mock
-from typing_extensions import Literal
+from typing_extensions import Literal, AsyncIterator, override
import httpx
import pytest
@@ -36,6 +37,7 @@
from .utils import update_env
+T = TypeVar("T")
base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
bearer_token = "My Bearer Token"
@@ -50,6 +52,57 @@ def _low_retry_timeout(*_args: Any, **_kwargs: Any) -> float:
return 0.1
+def mirror_request_content(request: httpx.Request) -> httpx.Response:
+ return httpx.Response(200, content=request.content)
+
+
+# note: we can't use the httpx.MockTransport class as it consumes the request
+# body itself, which means we can't test that the body is read lazily
+class MockTransport(httpx.BaseTransport, httpx.AsyncBaseTransport):
+ def __init__(
+ self,
+ handler: Callable[[httpx.Request], httpx.Response]
+ | Callable[[httpx.Request], Coroutine[Any, Any, httpx.Response]],
+ ) -> None:
+ self.handler = handler
+
+ @override
+ def handle_request(
+ self,
+ request: httpx.Request,
+ ) -> httpx.Response:
+ assert not inspect.iscoroutinefunction(self.handler), "handler must not be a coroutine function"
+ assert inspect.isfunction(self.handler), "handler must be a function"
+ return self.handler(request)
+
+ @override
+ async def handle_async_request(
+ self,
+ request: httpx.Request,
+ ) -> httpx.Response:
+ assert inspect.iscoroutinefunction(self.handler), "handler must be a coroutine function"
+ return await self.handler(request)
+
+
+@dataclasses.dataclass
+class Counter:
+ value: int = 0
+
+
+def _make_sync_iterator(iterable: Iterable[T], counter: Optional[Counter] = None) -> Iterator[T]:
+ for item in iterable:
+ if counter:
+ counter.value += 1
+ yield item
+
+
+async def _make_async_iterator(iterable: Iterable[T], counter: Optional[Counter] = None) -> AsyncIterator[T]:
+ for item in iterable:
+ if counter:
+ counter.value += 1
+ yield item
+
+
def _get_open_connections(client: Gitpod | AsyncGitpod) -> int:
transport = client._client._transport
assert isinstance(transport, httpx.HTTPTransport) or isinstance(transport, httpx.AsyncHTTPTransport)
@@ -511,6 +564,70 @@ def test_multipart_repeating_array(self, client: Gitpod) -> None:
b"",
]
+ @pytest.mark.respx(base_url=base_url)
+ def test_binary_content_upload(self, respx_mock: MockRouter, client: Gitpod) -> None:
+ respx_mock.post("/upload").mock(side_effect=mirror_request_content)
+
+ file_content = b"Hello, this is a test file."
+
+ response = client.post(
+ "/upload",
+ content=file_content,
+ cast_to=httpx.Response,
+ options={"headers": {"Content-Type": "application/octet-stream"}},
+ )
+
+ assert response.status_code == 200
+ assert response.request.headers["Content-Type"] == "application/octet-stream"
+ assert response.content == file_content
+
+ def test_binary_content_upload_with_iterator(self) -> None:
+ file_content = b"Hello, this is a test file."
+ counter = Counter()
+ iterator = _make_sync_iterator([file_content], counter=counter)
+
+ def mock_handler(request: httpx.Request) -> httpx.Response:
+ assert counter.value == 0, "the request body should not have been read"
+ return httpx.Response(200, content=request.read())
+
+ with Gitpod(
+ base_url=base_url,
+ bearer_token=bearer_token,
+ _strict_response_validation=True,
+ http_client=httpx.Client(transport=MockTransport(handler=mock_handler)),
+ ) as client:
+ response = client.post(
+ "/upload",
+ content=iterator,
+ cast_to=httpx.Response,
+ options={"headers": {"Content-Type": "application/octet-stream"}},
+ )
+
+ assert response.status_code == 200
+ assert response.request.headers["Content-Type"] == "application/octet-stream"
+ assert response.content == file_content
+ assert counter.value == 1
+
+ @pytest.mark.respx(base_url=base_url)
+ def test_binary_content_upload_with_body_is_deprecated(self, respx_mock: MockRouter, client: Gitpod) -> None:
+ respx_mock.post("/upload").mock(side_effect=mirror_request_content)
+
+ file_content = b"Hello, this is a test file."
+
+ with pytest.deprecated_call(
+ match="Passing raw bytes as `body` is deprecated and will be removed in a future version. Please pass raw bytes via the `content` parameter instead."
+ ):
+ response = client.post(
+ "/upload",
+ body=file_content,
+ cast_to=httpx.Response,
+ options={"headers": {"Content-Type": "application/octet-stream"}},
+ )
+
+ assert response.status_code == 200
+ assert response.request.headers["Content-Type"] == "application/octet-stream"
+ assert response.content == file_content
+
@pytest.mark.respx(base_url=base_url)
def test_basic_union_response(self, respx_mock: MockRouter, client: Gitpod) -> None:
class Model1(BaseModel):
@@ -1364,6 +1481,72 @@ def test_multipart_repeating_array(self, async_client: AsyncGitpod) -> None:
b"",
]
+ @pytest.mark.respx(base_url=base_url)
+ async def test_binary_content_upload(self, respx_mock: MockRouter, async_client: AsyncGitpod) -> None:
+ respx_mock.post("/upload").mock(side_effect=mirror_request_content)
+
+ file_content = b"Hello, this is a test file."
+
+ response = await async_client.post(
+ "/upload",
+ content=file_content,
+ cast_to=httpx.Response,
+ options={"headers": {"Content-Type": "application/octet-stream"}},
+ )
+
+ assert response.status_code == 200
+ assert response.request.headers["Content-Type"] == "application/octet-stream"
+ assert response.content == file_content
+
+ async def test_binary_content_upload_with_asynciterator(self) -> None:
+ file_content = b"Hello, this is a test file."
+ counter = Counter()
+ iterator = _make_async_iterator([file_content], counter=counter)
+
+ async def mock_handler(request: httpx.Request) -> httpx.Response:
+ assert counter.value == 0, "the request body should not have been read"
+ return httpx.Response(200, content=await request.aread())
+
+ async with AsyncGitpod(
+ base_url=base_url,
+ bearer_token=bearer_token,
+ _strict_response_validation=True,
+ http_client=httpx.AsyncClient(transport=MockTransport(handler=mock_handler)),
+ ) as client:
+ response = await client.post(
+ "/upload",
+ content=iterator,
+ cast_to=httpx.Response,
+ options={"headers": {"Content-Type": "application/octet-stream"}},
+ )
+
+ assert response.status_code == 200
+ assert response.request.headers["Content-Type"] == "application/octet-stream"
+ assert response.content == file_content
+ assert counter.value == 1
+
+ @pytest.mark.respx(base_url=base_url)
+ async def test_binary_content_upload_with_body_is_deprecated(
+ self, respx_mock: MockRouter, async_client: AsyncGitpod
+ ) -> None:
+ respx_mock.post("/upload").mock(side_effect=mirror_request_content)
+
+ file_content = b"Hello, this is a test file."
+
+ with pytest.deprecated_call(
+ match="Passing raw bytes as `body` is deprecated and will be removed in a future version. Please pass raw bytes via the `content` parameter instead."
+ ):
+ response = await async_client.post(
+ "/upload",
+ body=file_content,
+ cast_to=httpx.Response,
+ options={"headers": {"Content-Type": "application/octet-stream"}},
+ )
+
+ assert response.status_code == 200
+ assert response.request.headers["Content-Type"] == "application/octet-stream"
+ assert response.content == file_content
+
@pytest.mark.respx(base_url=base_url)
async def test_basic_union_response(self, respx_mock: MockRouter, async_client: AsyncGitpod) -> None:
class Model1(BaseModel):
From a55115ba054078dcb689222cc150b2b1f56077bf Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Wed, 14 Jan 2026 05:26:53 +0000
Subject: [PATCH 06/27] feat: move agent mode from Spec to Status, add
AgentModeChange signals
---
.stats.yml | 4 ++--
src/gitpod/types/agent_execution.py | 9 ++++++---
src/gitpod/types/agent_mode.py | 4 +++-
3 files changed, 11 insertions(+), 6 deletions(-)
diff --git a/.stats.yml b/.stats.yml
index d535149..a59a947 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 160
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-46e0124fe8e07933a6ea784e81b4d02086696c246f519aaa34b087f46410c818.yml
-openapi_spec_hash: fe98c15ea1e320c05593cd57457e4af5
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-cad9422301ea573f7fdbcf5047e421a0a6e963468a9d8f464e47ed1800a8fc75.yml
+openapi_spec_hash: b2e5072d4659a5c4fb5d2e8916388af9
config_hash: d3267594264bfb76d2ee7e881d5f8a5a
diff --git a/src/gitpod/types/agent_execution.py b/src/gitpod/types/agent_execution.py
index 384da90..ad11938 100644
--- a/src/gitpod/types/agent_execution.py
+++ b/src/gitpod/types/agent_execution.py
@@ -259,9 +259,6 @@ class Spec(BaseModel):
limits: Optional[SpecLimits] = None
- mode: Optional[AgentMode] = None
- """mode is the operational mode for this agent execution"""
-
session: Optional[str] = None
spec_version: Optional[str] = FieldInfo(alias="specVersion", default=None)
@@ -355,6 +352,12 @@ class Status(BaseModel):
judgement: Optional[str] = None
"""judgement is the judgement of the agent run produced by the judgement prompt."""
+ mode: Optional[AgentMode] = None
+ """
+ mode is the current operational mode of the agent execution. This is set by the
+ agent when entering different modes (e.g., Ralph mode via /ona:ralph command).
+ """
+
outputs: Optional[Dict[str, StatusOutputs]] = None
"""
outputs is a map of key-value pairs that can be set by the agent during
diff --git a/src/gitpod/types/agent_mode.py b/src/gitpod/types/agent_mode.py
index de414c7..d7bd23b 100644
--- a/src/gitpod/types/agent_mode.py
+++ b/src/gitpod/types/agent_mode.py
@@ -4,4 +4,6 @@
__all__ = ["AgentMode"]
-AgentMode: TypeAlias = Literal["AGENT_MODE_UNSPECIFIED", "AGENT_MODE_EXECUTION", "AGENT_MODE_PLANNING"]
+AgentMode: TypeAlias = Literal[
+ "AGENT_MODE_UNSPECIFIED", "AGENT_MODE_EXECUTION", "AGENT_MODE_PLANNING", "AGENT_MODE_RALPH"
+]
From e0023da5a30344c2fc87ebce55e26101c4ad40b5 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Wed, 14 Jan 2026 15:02:52 +0000
Subject: [PATCH 07/27] feat(api): add draft and state fields to PullRequest
proto
---
.stats.yml | 6 +++---
api.md | 1 +
src/gitpod/types/__init__.py | 1 +
src/gitpod/types/agent_code_context.py | 7 +++++++
src/gitpod/types/agent_code_context_param.py | 7 +++++++
src/gitpod/types/runner_parse_context_url_response.py | 7 +++++++
src/gitpod/types/shared/__init__.py | 1 +
src/gitpod/types/shared/state.py | 7 +++++++
src/gitpod/types/shared_params/__init__.py | 1 +
src/gitpod/types/shared_params/state.py | 9 +++++++++
tests/api_resources/test_agents.py | 4 ++++
11 files changed, 48 insertions(+), 3 deletions(-)
create mode 100644 src/gitpod/types/shared/state.py
create mode 100644 src/gitpod/types/shared_params/state.py
diff --git a/.stats.yml b/.stats.yml
index a59a947..9004557 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 160
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-cad9422301ea573f7fdbcf5047e421a0a6e963468a9d8f464e47ed1800a8fc75.yml
-openapi_spec_hash: b2e5072d4659a5c4fb5d2e8916388af9
-config_hash: d3267594264bfb76d2ee7e881d5f8a5a
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-47577991d03c0dab9d0f219bd3f6cf8cb3ea386a919a10c949318091aca5b10f.yml
+openapi_spec_hash: ad236fd154210c60d9aca150a3fd51bc
+config_hash: f36d04c8359fe8baec226396a18b309e
diff --git a/api.md b/api.md
index 29f93a4..36e2403 100644
--- a/api.md
+++ b/api.md
@@ -15,6 +15,7 @@ from gitpod.types import (
ResourceType,
RunsOn,
SecretRef,
+ State,
Subject,
Task,
TaskExecution,
diff --git a/src/gitpod/types/__init__.py b/src/gitpod/types/__init__.py
index bd85a24..954f9df 100644
--- a/src/gitpod/types/__init__.py
+++ b/src/gitpod/types/__init__.py
@@ -10,6 +10,7 @@
from .secret import Secret as Secret
from .shared import (
Task as Task,
+ State as State,
RunsOn as RunsOn,
Gateway as Gateway,
Subject as Subject,
diff --git a/src/gitpod/types/agent_code_context.py b/src/gitpod/types/agent_code_context.py
index 05c1832..ece7309 100644
--- a/src/gitpod/types/agent_code_context.py
+++ b/src/gitpod/types/agent_code_context.py
@@ -5,6 +5,7 @@
from pydantic import Field as FieldInfo
from .._models import BaseModel
+from .shared.state import State
__all__ = ["AgentCodeContext", "ContextURL", "PullRequest", "PullRequestRepository"]
@@ -40,12 +41,18 @@ class PullRequest(BaseModel):
author: Optional[str] = None
"""Author name as provided by the SCM system"""
+ draft: Optional[bool] = None
+ """Whether this is a draft pull request"""
+
from_branch: Optional[str] = FieldInfo(alias="fromBranch", default=None)
"""Source branch name (the branch being merged from)"""
repository: Optional[PullRequestRepository] = None
"""Repository information"""
+ state: Optional[State] = None
+ """Current state of the pull request"""
+
title: Optional[str] = None
"""Pull request title"""
diff --git a/src/gitpod/types/agent_code_context_param.py b/src/gitpod/types/agent_code_context_param.py
index 8080145..821f296 100644
--- a/src/gitpod/types/agent_code_context_param.py
+++ b/src/gitpod/types/agent_code_context_param.py
@@ -6,6 +6,7 @@
from typing_extensions import Annotated, TypedDict
from .._utils import PropertyInfo
+from .shared.state import State
__all__ = ["AgentCodeContextParam", "ContextURL", "PullRequest", "PullRequestRepository"]
@@ -41,12 +42,18 @@ class PullRequest(TypedDict, total=False):
author: str
"""Author name as provided by the SCM system"""
+ draft: bool
+ """Whether this is a draft pull request"""
+
from_branch: Annotated[str, PropertyInfo(alias="fromBranch")]
"""Source branch name (the branch being merged from)"""
repository: PullRequestRepository
"""Repository information"""
+ state: State
+ """Current state of the pull request"""
+
title: str
"""Pull request title"""
diff --git a/src/gitpod/types/runner_parse_context_url_response.py b/src/gitpod/types/runner_parse_context_url_response.py
index c712e40..c18fd7d 100644
--- a/src/gitpod/types/runner_parse_context_url_response.py
+++ b/src/gitpod/types/runner_parse_context_url_response.py
@@ -5,6 +5,7 @@
from pydantic import Field as FieldInfo
from .._models import BaseModel
+from .shared.state import State
__all__ = ["RunnerParseContextURLResponse", "Git", "Issue", "Pr", "PullRequest", "PullRequestRepository"]
@@ -71,12 +72,18 @@ class PullRequest(BaseModel):
author: Optional[str] = None
"""Author name as provided by the SCM system"""
+ draft: Optional[bool] = None
+ """Whether this is a draft pull request"""
+
from_branch: Optional[str] = FieldInfo(alias="fromBranch", default=None)
"""Source branch name (the branch being merged from)"""
repository: Optional[PullRequestRepository] = None
"""Repository information"""
+ state: Optional[State] = None
+ """Current state of the pull request"""
+
title: Optional[str] = None
"""Pull request title"""
diff --git a/src/gitpod/types/shared/__init__.py b/src/gitpod/types/shared/__init__.py
index 50c1315..5bfea28 100644
--- a/src/gitpod/types/shared/__init__.py
+++ b/src/gitpod/types/shared/__init__.py
@@ -1,6 +1,7 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from .task import Task as Task
+from .state import State as State
from .gateway import Gateway as Gateway
from .runs_on import RunsOn as RunsOn
from .subject import Subject as Subject
diff --git a/src/gitpod/types/shared/state.py b/src/gitpod/types/shared/state.py
new file mode 100644
index 0000000..92aa0de
--- /dev/null
+++ b/src/gitpod/types/shared/state.py
@@ -0,0 +1,7 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal, TypeAlias
+
+__all__ = ["State"]
+
+State: TypeAlias = Literal["STATE_UNSPECIFIED", "STATE_OPEN", "STATE_CLOSED", "STATE_MERGED"]
diff --git a/src/gitpod/types/shared_params/__init__.py b/src/gitpod/types/shared_params/__init__.py
index 4673c76..e91ec61 100644
--- a/src/gitpod/types/shared_params/__init__.py
+++ b/src/gitpod/types/shared_params/__init__.py
@@ -1,5 +1,6 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+from .state import State as State
from .runs_on import RunsOn as RunsOn
from .subject import Subject as Subject
from .principal import Principal as Principal
diff --git a/src/gitpod/types/shared_params/state.py b/src/gitpod/types/shared_params/state.py
new file mode 100644
index 0000000..1d81f94
--- /dev/null
+++ b/src/gitpod/types/shared_params/state.py
@@ -0,0 +1,9 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal, TypeAlias
+
+__all__ = ["State"]
+
+State: TypeAlias = Literal["STATE_UNSPECIFIED", "STATE_OPEN", "STATE_CLOSED", "STATE_MERGED"]
diff --git a/tests/api_resources/test_agents.py b/tests/api_resources/test_agents.py
index b92173b..f4f2aad 100644
--- a/tests/api_resources/test_agents.py
+++ b/tests/api_resources/test_agents.py
@@ -410,6 +410,7 @@ def test_method_start_execution_with_all_params(self, client: Gitpod) -> None:
"pull_request": {
"id": "id",
"author": "author",
+ "draft": True,
"from_branch": "fromBranch",
"repository": {
"clone_url": "cloneUrl",
@@ -417,6 +418,7 @@ def test_method_start_execution_with_all_params(self, client: Gitpod) -> None:
"name": "name",
"owner": "owner",
},
+ "state": "STATE_UNSPECIFIED",
"title": "title",
"to_branch": "toBranch",
"url": "url",
@@ -921,6 +923,7 @@ async def test_method_start_execution_with_all_params(self, async_client: AsyncG
"pull_request": {
"id": "id",
"author": "author",
+ "draft": True,
"from_branch": "fromBranch",
"repository": {
"clone_url": "cloneUrl",
@@ -928,6 +931,7 @@ async def test_method_start_execution_with_all_params(self, async_client: AsyncG
"name": "name",
"owner": "owner",
},
+ "state": "STATE_UNSPECIFIED",
"title": "title",
"to_branch": "toBranch",
"url": "url",
From 838e74c4da4b57590a6dd0af19bdd20faf7d2805 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Wed, 14 Jan 2026 18:04:27 +0000
Subject: [PATCH 08/27] feat: [api] sorting for `ListMembers`
---
.stats.yml | 4 +--
.../resources/organizations/organizations.py | 14 ++++++++++
.../types/organization_list_members_params.py | 27 +++++++++++++++++--
tests/api_resources/test_organizations.py | 8 ++++++
4 files changed, 49 insertions(+), 4 deletions(-)
diff --git a/.stats.yml b/.stats.yml
index 9004557..3117cef 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 160
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-47577991d03c0dab9d0f219bd3f6cf8cb3ea386a919a10c949318091aca5b10f.yml
-openapi_spec_hash: ad236fd154210c60d9aca150a3fd51bc
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-3a8fb9d6b9645a483a08206e944cc388325e210f0bd54daa9e15ee561a37fabc.yml
+openapi_spec_hash: fe42cbf3b012e4aebf56f64a675c3dd3
config_hash: f36d04c8359fe8baec226396a18b309e
diff --git a/src/gitpod/resources/organizations/organizations.py b/src/gitpod/resources/organizations/organizations.py
index c1ec57e..c9de4ae 100644
--- a/src/gitpod/resources/organizations/organizations.py
+++ b/src/gitpod/resources/organizations/organizations.py
@@ -507,6 +507,7 @@ def list_members(
page_size: int | Omit = omit,
filter: organization_list_members_params.Filter | Omit = omit,
pagination: organization_list_members_params.Pagination | Omit = omit,
+ sort: organization_list_members_params.Sort | Omit = omit,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
@@ -551,6 +552,11 @@ def list_members(
pagination: pagination contains the pagination options for listing members
+ sort: sort specifies the order of results. When unspecified, the authenticated user is
+ returned first, followed by other members sorted by name ascending. When an
+ explicit sort is specified, results are sorted purely by the requested field
+ without any special handling for the authenticated user.
+
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -567,6 +573,7 @@ def list_members(
"organization_id": organization_id,
"filter": filter,
"pagination": pagination,
+ "sort": sort,
},
organization_list_members_params.OrganizationListMembersParams,
),
@@ -1086,6 +1093,7 @@ def list_members(
page_size: int | Omit = omit,
filter: organization_list_members_params.Filter | Omit = omit,
pagination: organization_list_members_params.Pagination | Omit = omit,
+ sort: organization_list_members_params.Sort | Omit = omit,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
@@ -1130,6 +1138,11 @@ def list_members(
pagination: pagination contains the pagination options for listing members
+ sort: sort specifies the order of results. When unspecified, the authenticated user is
+ returned first, followed by other members sorted by name ascending. When an
+ explicit sort is specified, results are sorted purely by the requested field
+ without any special handling for the authenticated user.
+
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -1146,6 +1159,7 @@ def list_members(
"organization_id": organization_id,
"filter": filter,
"pagination": pagination,
+ "sort": sort,
},
organization_list_members_params.OrganizationListMembersParams,
),
diff --git a/src/gitpod/types/organization_list_members_params.py b/src/gitpod/types/organization_list_members_params.py
index 06c529e..16d5cba 100644
--- a/src/gitpod/types/organization_list_members_params.py
+++ b/src/gitpod/types/organization_list_members_params.py
@@ -2,11 +2,11 @@
from __future__ import annotations
-from typing_extensions import Required, Annotated, TypedDict
+from typing_extensions import Literal, Required, Annotated, TypedDict
from .._utils import PropertyInfo
-__all__ = ["OrganizationListMembersParams", "Filter", "Pagination"]
+__all__ = ["OrganizationListMembersParams", "Filter", "Pagination", "Sort"]
class OrganizationListMembersParams(TypedDict, total=False):
@@ -22,6 +22,15 @@ class OrganizationListMembersParams(TypedDict, total=False):
pagination: Pagination
"""pagination contains the pagination options for listing members"""
+ sort: Sort
+ """sort specifies the order of results.
+
+ When unspecified, the authenticated user is returned first, followed by other
+ members sorted by name ascending. When an explicit sort is specified, results
+ are sorted purely by the requested field without any special handling for the
+ authenticated user.
+ """
+
class Filter(TypedDict, total=False):
search: str
@@ -42,3 +51,17 @@ class Pagination(TypedDict, total=False):
Maximum 100.
"""
+
+
+class Sort(TypedDict, total=False):
+ """sort specifies the order of results.
+
+ When unspecified, the authenticated user is
+ returned first, followed by other members sorted by name ascending. When an explicit
+ sort is specified, results are sorted purely by the requested field without any
+ special handling for the authenticated user.
+ """
+
+ field: Literal["SORT_FIELD_UNSPECIFIED", "SORT_FIELD_NAME", "SORT_FIELD_DATE_JOINED"]
+
+ order: Literal["SORT_ORDER_UNSPECIFIED", "SORT_ORDER_ASC", "SORT_ORDER_DESC"]
diff --git a/tests/api_resources/test_organizations.py b/tests/api_resources/test_organizations.py
index 8cda4e7..644ccbb 100644
--- a/tests/api_resources/test_organizations.py
+++ b/tests/api_resources/test_organizations.py
@@ -271,6 +271,10 @@ def test_method_list_members_with_all_params(self, client: Gitpod) -> None:
"token": "token",
"page_size": 20,
},
+ sort={
+ "field": "SORT_FIELD_UNSPECIFIED",
+ "order": "SORT_ORDER_UNSPECIFIED",
+ },
)
assert_matches_type(SyncMembersPage[OrganizationMember], organization, path=["response"])
@@ -600,6 +604,10 @@ async def test_method_list_members_with_all_params(self, async_client: AsyncGitp
"token": "token",
"page_size": 20,
},
+ sort={
+ "field": "SORT_FIELD_UNSPECIFIED",
+ "order": "SORT_ORDER_UNSPECIFIED",
+ },
)
assert_matches_type(AsyncMembersPage[OrganizationMember], organization, path=["response"])
From 34fb372aef655ae57fc99d5b37e152c75d831af5 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Wed, 14 Jan 2026 19:42:10 +0000
Subject: [PATCH 09/27] feat: [backend] Introduce role and member status
filtering for `ListMembers`
---
.stats.yml | 4 ++--
src/gitpod/types/organization_list_members_params.py | 9 +++++++++
src/gitpod/types/shared_params/__init__.py | 1 +
src/gitpod/types/shared_params/user_status.py | 11 +++++++++++
tests/api_resources/test_organizations.py | 12 ++++++++++--
5 files changed, 33 insertions(+), 4 deletions(-)
create mode 100644 src/gitpod/types/shared_params/user_status.py
diff --git a/.stats.yml b/.stats.yml
index 3117cef..f36c8c0 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 160
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-3a8fb9d6b9645a483a08206e944cc388325e210f0bd54daa9e15ee561a37fabc.yml
-openapi_spec_hash: fe42cbf3b012e4aebf56f64a675c3dd3
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-13ed0159480c5c02ed02394764e7c528c1110cdc42d2a0ff5fac228f48403a08.yml
+openapi_spec_hash: e1b4c20a8a5faee0f2dd22b449e7a106
config_hash: f36d04c8359fe8baec226396a18b309e
diff --git a/src/gitpod/types/organization_list_members_params.py b/src/gitpod/types/organization_list_members_params.py
index 16d5cba..2e5f87e 100644
--- a/src/gitpod/types/organization_list_members_params.py
+++ b/src/gitpod/types/organization_list_members_params.py
@@ -2,9 +2,12 @@
from __future__ import annotations
+from typing import List
from typing_extensions import Literal, Required, Annotated, TypedDict
from .._utils import PropertyInfo
+from .shared.user_status import UserStatus
+from .shared.organization_role import OrganizationRole
__all__ = ["OrganizationListMembersParams", "Filter", "Pagination", "Sort"]
@@ -33,9 +36,15 @@ class OrganizationListMembersParams(TypedDict, total=False):
class Filter(TypedDict, total=False):
+ roles: List[OrganizationRole]
+ """roles filters members by their organization role"""
+
search: str
"""search performs case-insensitive search across member name and email"""
+ statuses: List[UserStatus]
+ """status filters members by their user status"""
+
class Pagination(TypedDict, total=False):
"""pagination contains the pagination options for listing members"""
diff --git a/src/gitpod/types/shared_params/__init__.py b/src/gitpod/types/shared_params/__init__.py
index e91ec61..093bf76 100644
--- a/src/gitpod/types/shared_params/__init__.py
+++ b/src/gitpod/types/shared_params/__init__.py
@@ -7,6 +7,7 @@
from .task_spec import TaskSpec as TaskSpec
from .secret_ref import SecretRef as SecretRef
from .field_value import FieldValue as FieldValue
+from .user_status import UserStatus as UserStatus
from .resource_type import ResourceType as ResourceType
from .task_metadata import TaskMetadata as TaskMetadata
from .environment_class import EnvironmentClass as EnvironmentClass
diff --git a/src/gitpod/types/shared_params/user_status.py b/src/gitpod/types/shared_params/user_status.py
new file mode 100644
index 0000000..fd8ac19
--- /dev/null
+++ b/src/gitpod/types/shared_params/user_status.py
@@ -0,0 +1,11 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal, TypeAlias
+
+__all__ = ["UserStatus"]
+
+UserStatus: TypeAlias = Literal[
+ "USER_STATUS_UNSPECIFIED", "USER_STATUS_ACTIVE", "USER_STATUS_SUSPENDED", "USER_STATUS_LEFT"
+]
diff --git a/tests/api_resources/test_organizations.py b/tests/api_resources/test_organizations.py
index 644ccbb..b404eb7 100644
--- a/tests/api_resources/test_organizations.py
+++ b/tests/api_resources/test_organizations.py
@@ -266,7 +266,11 @@ def test_method_list_members_with_all_params(self, client: Gitpod) -> None:
organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047",
token="token",
page_size=0,
- filter={"search": "search"},
+ filter={
+ "roles": ["ORGANIZATION_ROLE_UNSPECIFIED"],
+ "search": "search",
+ "statuses": ["USER_STATUS_UNSPECIFIED"],
+ },
pagination={
"token": "token",
"page_size": 20,
@@ -599,7 +603,11 @@ async def test_method_list_members_with_all_params(self, async_client: AsyncGitp
organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047",
token="token",
page_size=0,
- filter={"search": "search"},
+ filter={
+ "roles": ["ORGANIZATION_ROLE_UNSPECIFIED"],
+ "search": "search",
+ "statuses": ["USER_STATUS_UNSPECIFIED"],
+ },
pagination={
"token": "token",
"page_size": 20,
From 89fd8fef7f9de200e4aecd563c965d4209427052 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Wed, 14 Jan 2026 21:11:51 +0000
Subject: [PATCH 10/27] feat(dashboard): show tier badge in org selector
---
.stats.yml | 6 +++---
api.md | 2 +-
src/gitpod/types/__init__.py | 2 +-
src/gitpod/types/account_membership.py | 8 ++++++--
src/gitpod/types/organization.py | 2 +-
src/gitpod/types/shared/__init__.py | 1 +
src/gitpod/types/{ => shared}/organization_tier.py | 0
7 files changed, 13 insertions(+), 8 deletions(-)
rename src/gitpod/types/{ => shared}/organization_tier.py (100%)
diff --git a/.stats.yml b/.stats.yml
index f36c8c0..5770e67 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 160
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-13ed0159480c5c02ed02394764e7c528c1110cdc42d2a0ff5fac228f48403a08.yml
-openapi_spec_hash: e1b4c20a8a5faee0f2dd22b449e7a106
-config_hash: f36d04c8359fe8baec226396a18b309e
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-504fab16d01ad7f81914542fd0523f4dfefce87813891da391b97b1b0a70f563.yml
+openapi_spec_hash: 84d9d652cac365c646e01111cee89afc
+config_hash: acfe8cf5d6e4b26387e4fefa3bff8409
diff --git a/api.md b/api.md
index 36e2403..9b1a07d 100644
--- a/api.md
+++ b/api.md
@@ -10,6 +10,7 @@ from gitpod.types import (
FieldValue,
Gateway,
OrganizationRole,
+ OrganizationTier,
Principal,
ProjectEnvironmentClass,
ResourceType,
@@ -338,7 +339,6 @@ from gitpod.types import (
InviteDomains,
Organization,
OrganizationMember,
- OrganizationTier,
OrganizationCreateResponse,
OrganizationRetrieveResponse,
OrganizationUpdateResponse,
diff --git a/src/gitpod/types/__init__.py b/src/gitpod/types/__init__.py
index 954f9df..842817b 100644
--- a/src/gitpod/types/__init__.py
+++ b/src/gitpod/types/__init__.py
@@ -25,6 +25,7 @@
TaskExecution as TaskExecution,
EnvironmentClass as EnvironmentClass,
OrganizationRole as OrganizationRole,
+ OrganizationTier as OrganizationTier,
AutomationTrigger as AutomationTrigger,
TaskExecutionSpec as TaskExecutionSpec,
TaskExecutionPhase as TaskExecutionPhase,
@@ -72,7 +73,6 @@
from .error_event_param import ErrorEventParam as ErrorEventParam
from .event_list_params import EventListParams as EventListParams
from .group_list_params import GroupListParams as GroupListParams
-from .organization_tier import OrganizationTier as OrganizationTier
from .prebuild_metadata import PrebuildMetadata as PrebuildMetadata
from .runner_capability import RunnerCapability as RunnerCapability
from .runner_spec_param import RunnerSpecParam as RunnerSpecParam
diff --git a/src/gitpod/types/account_membership.py b/src/gitpod/types/account_membership.py
index 10f2603..6f443a8 100644
--- a/src/gitpod/types/account_membership.py
+++ b/src/gitpod/types/account_membership.py
@@ -6,6 +6,7 @@
from .._models import BaseModel
from .shared.organization_role import OrganizationRole
+from .shared.organization_tier import OrganizationTier
__all__ = ["AccountMembership"]
@@ -25,6 +26,9 @@ class AccountMembership(BaseModel):
organization_member_count: Optional[int] = FieldInfo(alias="organizationMemberCount", default=None)
"""
- organization_name is the member count of the organization the user is a member
- of
+ organization_member_count is the member count of the organization the user is a
+ member of
"""
+
+ organization_tier: Optional[OrganizationTier] = FieldInfo(alias="organizationTier", default=None)
+ """organization_tier is the tier of the organization (Free, Core, Enterprise)"""
diff --git a/src/gitpod/types/organization.py b/src/gitpod/types/organization.py
index edf88f1..e833b09 100644
--- a/src/gitpod/types/organization.py
+++ b/src/gitpod/types/organization.py
@@ -7,7 +7,7 @@
from .._models import BaseModel
from .invite_domains import InviteDomains
-from .organization_tier import OrganizationTier
+from .shared.organization_tier import OrganizationTier
__all__ = ["Organization"]
diff --git a/src/gitpod/types/shared/__init__.py b/src/gitpod/types/shared/__init__.py
index 5bfea28..de9766f 100644
--- a/src/gitpod/types/shared/__init__.py
+++ b/src/gitpod/types/shared/__init__.py
@@ -16,6 +16,7 @@
from .task_execution import TaskExecution as TaskExecution
from .environment_class import EnvironmentClass as EnvironmentClass
from .organization_role import OrganizationRole as OrganizationRole
+from .organization_tier import OrganizationTier as OrganizationTier
from .automation_trigger import AutomationTrigger as AutomationTrigger
from .task_execution_spec import TaskExecutionSpec as TaskExecutionSpec
from .task_execution_phase import TaskExecutionPhase as TaskExecutionPhase
diff --git a/src/gitpod/types/organization_tier.py b/src/gitpod/types/shared/organization_tier.py
similarity index 100%
rename from src/gitpod/types/organization_tier.py
rename to src/gitpod/types/shared/organization_tier.py
From 30e17c55b991286527f64c8857b04dd9b5a2ba7b Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Thu, 15 Jan 2026 11:17:51 +0000
Subject: [PATCH 11/27] feat(secrets): add ServiceAccountSecret entity with
full support
---
.stats.yml | 4 ++--
src/gitpod/types/secret_scope.py | 3 +++
src/gitpod/types/secret_scope_param.py | 3 +++
src/gitpod/types/shared/resource_type.py | 1 +
src/gitpod/types/shared_params/resource_type.py | 1 +
tests/api_resources/test_secrets.py | 4 ++++
6 files changed, 14 insertions(+), 2 deletions(-)
diff --git a/.stats.yml b/.stats.yml
index 5770e67..a1fa096 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 160
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-504fab16d01ad7f81914542fd0523f4dfefce87813891da391b97b1b0a70f563.yml
-openapi_spec_hash: 84d9d652cac365c646e01111cee89afc
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-8a0189eebf423961bd98075dab28db4377c3a939da1dcf237d1b3958724e6dcf.yml
+openapi_spec_hash: 48004e7605cf720584e822ec11a2eb8b
config_hash: acfe8cf5d6e4b26387e4fefa3bff8409
diff --git a/src/gitpod/types/secret_scope.py b/src/gitpod/types/secret_scope.py
index f66b672..1d01cb3 100644
--- a/src/gitpod/types/secret_scope.py
+++ b/src/gitpod/types/secret_scope.py
@@ -16,5 +16,8 @@ class SecretScope(BaseModel):
project_id: Optional[str] = FieldInfo(alias="projectId", default=None)
"""project_id is the Project ID this Secret belongs to"""
+ service_account_id: Optional[str] = FieldInfo(alias="serviceAccountId", default=None)
+ """service_account_id is the Service Account ID this Secret belongs to"""
+
user_id: Optional[str] = FieldInfo(alias="userId", default=None)
"""user_id is the User ID this Secret belongs to"""
diff --git a/src/gitpod/types/secret_scope_param.py b/src/gitpod/types/secret_scope_param.py
index d68e56b..b7cf4f4 100644
--- a/src/gitpod/types/secret_scope_param.py
+++ b/src/gitpod/types/secret_scope_param.py
@@ -16,5 +16,8 @@ class SecretScopeParam(TypedDict, total=False):
project_id: Annotated[str, PropertyInfo(alias="projectId")]
"""project_id is the Project ID this Secret belongs to"""
+ service_account_id: Annotated[str, PropertyInfo(alias="serviceAccountId")]
+ """service_account_id is the Service Account ID this Secret belongs to"""
+
user_id: Annotated[str, PropertyInfo(alias="userId")]
"""user_id is the User ID this Secret belongs to"""
diff --git a/src/gitpod/types/shared/resource_type.py b/src/gitpod/types/shared/resource_type.py
index 7531c05..599108b 100644
--- a/src/gitpod/types/shared/resource_type.py
+++ b/src/gitpod/types/shared/resource_type.py
@@ -49,4 +49,5 @@
"RESOURCE_TYPE_GROUP_MEMBERSHIP_CHANGED",
"RESOURCE_TYPE_WEBHOOK",
"RESOURCE_TYPE_SCIM_CONFIGURATION",
+ "RESOURCE_TYPE_SERVICE_ACCOUNT_SECRET",
]
diff --git a/src/gitpod/types/shared_params/resource_type.py b/src/gitpod/types/shared_params/resource_type.py
index 34d2f8c..9d489e4 100644
--- a/src/gitpod/types/shared_params/resource_type.py
+++ b/src/gitpod/types/shared_params/resource_type.py
@@ -51,4 +51,5 @@
"RESOURCE_TYPE_GROUP_MEMBERSHIP_CHANGED",
"RESOURCE_TYPE_WEBHOOK",
"RESOURCE_TYPE_SCIM_CONFIGURATION",
+ "RESOURCE_TYPE_SERVICE_ACCOUNT_SECRET",
]
diff --git a/tests/api_resources/test_secrets.py b/tests/api_resources/test_secrets.py
index 6a54d36..680a9d7 100644
--- a/tests/api_resources/test_secrets.py
+++ b/tests/api_resources/test_secrets.py
@@ -41,6 +41,7 @@ def test_method_create_with_all_params(self, client: Gitpod) -> None:
scope={
"organization_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
"project_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ "service_account_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
"user_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
},
value="postgresql://user:pass@localhost:5432/db",
@@ -86,6 +87,7 @@ def test_method_list_with_all_params(self, client: Gitpod) -> None:
"scope": {
"organization_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
"project_id": "b0e12f6c-4c67-429d-a4a6-d9838b5da047",
+ "service_account_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
"user_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
},
},
@@ -252,6 +254,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncGitpod) ->
scope={
"organization_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
"project_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ "service_account_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
"user_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
},
value="postgresql://user:pass@localhost:5432/db",
@@ -297,6 +300,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncGitpod) -> N
"scope": {
"organization_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
"project_id": "b0e12f6c-4c67-429d-a4a6-d9838b5da047",
+ "service_account_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
"user_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
},
},
From a4c7479eeb85d549fbe481ab69a8f33e72027e81 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Thu, 15 Jan 2026 15:08:30 +0000
Subject: [PATCH 12/27] codegen metadata
---
.stats.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.stats.yml b/.stats.yml
index a1fa096..6535584 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 160
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-8a0189eebf423961bd98075dab28db4377c3a939da1dcf237d1b3958724e6dcf.yml
-openapi_spec_hash: 48004e7605cf720584e822ec11a2eb8b
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-e5c85c471bd3b69f4237abeba5f04212621408955a347de366cfd294a05b2b80.yml
+openapi_spec_hash: 2a09889ff17121827dad73c3d318a921
config_hash: acfe8cf5d6e4b26387e4fefa3bff8409
From fab0fb5b56ccdaa9fd049e54875854ab6b0caf41 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Thu, 15 Jan 2026 20:42:29 +0000
Subject: [PATCH 13/27] codegen metadata
---
.stats.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.stats.yml b/.stats.yml
index 6535584..2b051f4 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 160
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-e5c85c471bd3b69f4237abeba5f04212621408955a347de366cfd294a05b2b80.yml
-openapi_spec_hash: 2a09889ff17121827dad73c3d318a921
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-978712dd212465a9a1633be0a7981cfad4dd3836827e7d98eeac1a4f14224f94.yml
+openapi_spec_hash: 2f9436918b0af97785377ce80b4b2782
config_hash: acfe8cf5d6e4b26387e4fefa3bff8409
From ddd18c09beb0f24e076818783d2dae09ca9b9f8b Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Fri, 16 Jan 2026 13:20:34 +0000
Subject: [PATCH 14/27] feat(api): add search, creator, and status filters to
ListWorkflows
---
.stats.yml | 4 ++--
src/gitpod/types/groups/resource_role.py | 1 +
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/.stats.yml b/.stats.yml
index 2b051f4..ba16c23 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 160
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-978712dd212465a9a1633be0a7981cfad4dd3836827e7d98eeac1a4f14224f94.yml
-openapi_spec_hash: 2f9436918b0af97785377ce80b4b2782
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-247b6e1af7faefcf2f0ad1f1a012b45fd566be64e313d92648311bac4cda8b8e.yml
+openapi_spec_hash: 5eb6026ee5764b077a65c26e85e4a84a
config_hash: acfe8cf5d6e4b26387e4fefa3bff8409
diff --git a/src/gitpod/types/groups/resource_role.py b/src/gitpod/types/groups/resource_role.py
index cd2e164..33ecbb7 100644
--- a/src/gitpod/types/groups/resource_role.py
+++ b/src/gitpod/types/groups/resource_role.py
@@ -8,6 +8,7 @@
"RESOURCE_ROLE_UNSPECIFIED",
"RESOURCE_ROLE_ORG_ADMIN",
"RESOURCE_ROLE_ORG_MEMBER",
+ "RESOURCE_ROLE_ORG_RUNNERS_ADMIN",
"RESOURCE_ROLE_GROUP_ADMIN",
"RESOURCE_ROLE_GROUP_VIEWER",
"RESOURCE_ROLE_USER_IDENTITY",
From 9c8f7eadd38bc0326ecf1be48706003fa258257c Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Fri, 16 Jan 2026 16:59:40 +0000
Subject: [PATCH 15/27] feat(api): add ListSCMOrganizations endpoint
---
.stats.yml | 8 +-
api.md | 2 +
src/gitpod/resources/runners/runners.py | 152 ++++++++++++++++++
src/gitpod/types/__init__.py | 4 +
.../runner_list_scm_organizations_params.py | 20 +++
.../runner_list_scm_organizations_response.py | 28 ++++
tests/api_resources/test_runners.py | 79 +++++++++
7 files changed, 289 insertions(+), 4 deletions(-)
create mode 100644 src/gitpod/types/runner_list_scm_organizations_params.py
create mode 100644 src/gitpod/types/runner_list_scm_organizations_response.py
diff --git a/.stats.yml b/.stats.yml
index ba16c23..d64cbf2 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
-configured_endpoints: 160
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-247b6e1af7faefcf2f0ad1f1a012b45fd566be64e313d92648311bac4cda8b8e.yml
-openapi_spec_hash: 5eb6026ee5764b077a65c26e85e4a84a
-config_hash: acfe8cf5d6e4b26387e4fefa3bff8409
+configured_endpoints: 161
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-baa13045a9492d958fc06db0dcee2fd99972435f8b9a707831cf4da8d84db194.yml
+openapi_spec_hash: 5e7adb5d5cdf924eb7c0e4ddf1b81260
+config_hash: d930f7e17a525d153b810339251607b7
diff --git a/api.md b/api.md
index 9b1a07d..ed7817a 100644
--- a/api.md
+++ b/api.md
@@ -568,6 +568,7 @@ from gitpod.types import (
RunnerCheckAuthenticationForHostResponse,
RunnerCreateLogsTokenResponse,
RunnerCreateRunnerTokenResponse,
+ RunnerListScmOrganizationsResponse,
RunnerParseContextURLResponse,
RunnerSearchRepositoriesResponse,
)
@@ -583,6 +584,7 @@ Methods:
- client.runners.check_authentication_for_host(\*\*params) -> RunnerCheckAuthenticationForHostResponse
- client.runners.create_logs_token(\*\*params) -> RunnerCreateLogsTokenResponse
- client.runners.create_runner_token(\*\*params) -> RunnerCreateRunnerTokenResponse
+- client.runners.list_scm_organizations(\*\*params) -> RunnerListScmOrganizationsResponse
- client.runners.parse_context_url(\*\*params) -> RunnerParseContextURLResponse
- client.runners.search_repositories(\*\*params) -> RunnerSearchRepositoriesResponse
diff --git a/src/gitpod/resources/runners/runners.py b/src/gitpod/resources/runners/runners.py
index 1c445f8..0ba69c1 100644
--- a/src/gitpod/resources/runners/runners.py
+++ b/src/gitpod/resources/runners/runners.py
@@ -19,6 +19,7 @@
runner_parse_context_url_params,
runner_create_runner_token_params,
runner_search_repositories_params,
+ runner_list_scm_organizations_params,
runner_check_authentication_for_host_params,
)
from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
@@ -60,6 +61,7 @@
from ...types.runner_parse_context_url_response import RunnerParseContextURLResponse
from ...types.runner_create_runner_token_response import RunnerCreateRunnerTokenResponse
from ...types.runner_search_repositories_response import RunnerSearchRepositoriesResponse
+from ...types.runner_list_scm_organizations_response import RunnerListScmOrganizationsResponse
from ...types.runner_check_authentication_for_host_response import RunnerCheckAuthenticationForHostResponse
__all__ = ["RunnersResource", "AsyncRunnersResource"]
@@ -608,6 +610,75 @@ def create_runner_token(
cast_to=RunnerCreateRunnerTokenResponse,
)
+ def list_scm_organizations(
+ self,
+ *,
+ token: str | Omit = omit,
+ page_size: int | Omit = omit,
+ runner_id: str | Omit = omit,
+ scm_host: str | Omit = omit,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> RunnerListScmOrganizationsResponse:
+ """
+ Lists SCM organizations the user belongs to.
+
+ Use this method to:
+
+ - Get all organizations for a user on a specific SCM host
+ - Check organization admin permissions for webhook creation
+
+ ### Examples
+
+ - List GitHub organizations:
+
+ Lists all organizations the user belongs to on GitHub.
+
+ ```yaml
+ runnerId: "d2c94c27-3b76-4a42-b88c-95a85e392c68"
+ scmHost: "github.com"
+ ```
+
+ Args:
+ scm_host: The SCM host to list organizations from (e.g., "github.com", "gitlab.com")
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ return self._post(
+ "/gitpod.v1.RunnerService/ListSCMOrganizations",
+ body=maybe_transform(
+ {
+ "runner_id": runner_id,
+ "scm_host": scm_host,
+ },
+ runner_list_scm_organizations_params.RunnerListScmOrganizationsParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "token": token,
+ "page_size": page_size,
+ },
+ runner_list_scm_organizations_params.RunnerListScmOrganizationsParams,
+ ),
+ ),
+ cast_to=RunnerListScmOrganizationsResponse,
+ )
+
def parse_context_url(
self,
*,
@@ -1304,6 +1375,75 @@ async def create_runner_token(
cast_to=RunnerCreateRunnerTokenResponse,
)
+ async def list_scm_organizations(
+ self,
+ *,
+ token: str | Omit = omit,
+ page_size: int | Omit = omit,
+ runner_id: str | Omit = omit,
+ scm_host: str | Omit = omit,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> RunnerListScmOrganizationsResponse:
+ """
+ Lists SCM organizations the user belongs to.
+
+ Use this method to:
+
+ - Get all organizations for a user on a specific SCM host
+ - Check organization admin permissions for webhook creation
+
+ ### Examples
+
+ - List GitHub organizations:
+
+ Lists all organizations the user belongs to on GitHub.
+
+ ```yaml
+ runnerId: "d2c94c27-3b76-4a42-b88c-95a85e392c68"
+ scmHost: "github.com"
+ ```
+
+ Args:
+ scm_host: The SCM host to list organizations from (e.g., "github.com", "gitlab.com")
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ return await self._post(
+ "/gitpod.v1.RunnerService/ListSCMOrganizations",
+ body=await async_maybe_transform(
+ {
+ "runner_id": runner_id,
+ "scm_host": scm_host,
+ },
+ runner_list_scm_organizations_params.RunnerListScmOrganizationsParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=await async_maybe_transform(
+ {
+ "token": token,
+ "page_size": page_size,
+ },
+ runner_list_scm_organizations_params.RunnerListScmOrganizationsParams,
+ ),
+ ),
+ cast_to=RunnerListScmOrganizationsResponse,
+ )
+
async def parse_context_url(
self,
*,
@@ -1483,6 +1623,9 @@ def __init__(self, runners: RunnersResource) -> None:
self.create_runner_token = to_raw_response_wrapper(
runners.create_runner_token,
)
+ self.list_scm_organizations = to_raw_response_wrapper(
+ runners.list_scm_organizations,
+ )
self.parse_context_url = to_raw_response_wrapper(
runners.parse_context_url,
)
@@ -1527,6 +1670,9 @@ def __init__(self, runners: AsyncRunnersResource) -> None:
self.create_runner_token = async_to_raw_response_wrapper(
runners.create_runner_token,
)
+ self.list_scm_organizations = async_to_raw_response_wrapper(
+ runners.list_scm_organizations,
+ )
self.parse_context_url = async_to_raw_response_wrapper(
runners.parse_context_url,
)
@@ -1571,6 +1717,9 @@ def __init__(self, runners: RunnersResource) -> None:
self.create_runner_token = to_streamed_response_wrapper(
runners.create_runner_token,
)
+ self.list_scm_organizations = to_streamed_response_wrapper(
+ runners.list_scm_organizations,
+ )
self.parse_context_url = to_streamed_response_wrapper(
runners.parse_context_url,
)
@@ -1615,6 +1764,9 @@ def __init__(self, runners: AsyncRunnersResource) -> None:
self.create_runner_token = async_to_streamed_response_wrapper(
runners.create_runner_token,
)
+ self.list_scm_organizations = async_to_streamed_response_wrapper(
+ runners.list_scm_organizations,
+ )
self.parse_context_url = async_to_streamed_response_wrapper(
runners.parse_context_url,
)
diff --git a/src/gitpod/types/__init__.py b/src/gitpod/types/__init__.py
index 842817b..7306513 100644
--- a/src/gitpod/types/__init__.py
+++ b/src/gitpod/types/__init__.py
@@ -221,6 +221,7 @@
from .runner_search_repositories_response import RunnerSearchRepositoriesResponse as RunnerSearchRepositoriesResponse
from .environment_create_logs_token_params import EnvironmentCreateLogsTokenParams as EnvironmentCreateLogsTokenParams
from .project_prebuild_configuration_param import ProjectPrebuildConfigurationParam as ProjectPrebuildConfigurationParam
+from .runner_list_scm_organizations_params import RunnerListScmOrganizationsParams as RunnerListScmOrganizationsParams
from .user_get_authenticated_user_response import UserGetAuthenticatedUserResponse as UserGetAuthenticatedUserResponse
from .environment_create_from_project_params import (
EnvironmentCreateFromProjectParams as EnvironmentCreateFromProjectParams,
@@ -231,6 +232,9 @@
from .project_create_from_environment_params import (
ProjectCreateFromEnvironmentParams as ProjectCreateFromEnvironmentParams,
)
+from .runner_list_scm_organizations_response import (
+ RunnerListScmOrganizationsResponse as RunnerListScmOrganizationsResponse,
+)
from .environment_create_from_project_response import (
EnvironmentCreateFromProjectResponse as EnvironmentCreateFromProjectResponse,
)
diff --git a/src/gitpod/types/runner_list_scm_organizations_params.py b/src/gitpod/types/runner_list_scm_organizations_params.py
new file mode 100644
index 0000000..bd1f788
--- /dev/null
+++ b/src/gitpod/types/runner_list_scm_organizations_params.py
@@ -0,0 +1,20 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Annotated, TypedDict
+
+from .._utils import PropertyInfo
+
+__all__ = ["RunnerListScmOrganizationsParams"]
+
+
+class RunnerListScmOrganizationsParams(TypedDict, total=False):
+ token: str
+
+ page_size: Annotated[int, PropertyInfo(alias="pageSize")]
+
+ runner_id: Annotated[str, PropertyInfo(alias="runnerId")]
+
+ scm_host: Annotated[str, PropertyInfo(alias="scmHost")]
+ """The SCM host to list organizations from (e.g., "github.com", "gitlab.com")"""
diff --git a/src/gitpod/types/runner_list_scm_organizations_response.py b/src/gitpod/types/runner_list_scm_organizations_response.py
new file mode 100644
index 0000000..8e9db07
--- /dev/null
+++ b/src/gitpod/types/runner_list_scm_organizations_response.py
@@ -0,0 +1,28 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+
+from pydantic import Field as FieldInfo
+
+from .._models import BaseModel
+
+__all__ = ["RunnerListScmOrganizationsResponse", "Organization"]
+
+
+class Organization(BaseModel):
+ is_admin: Optional[bool] = FieldInfo(alias="isAdmin", default=None)
+ """
+ Whether the user has admin permissions in this organization. Admin permissions
+ typically allow creating organization-level webhooks.
+ """
+
+ name: Optional[str] = None
+ """Organization name/slug (e.g., "gitpod-io")"""
+
+ url: Optional[str] = None
+ """Organization URL (e.g., "https://github.com/gitpod-io")"""
+
+
+class RunnerListScmOrganizationsResponse(BaseModel):
+ organizations: Optional[List[Organization]] = None
+ """List of organizations the user belongs to"""
diff --git a/tests/api_resources/test_runners.py b/tests/api_resources/test_runners.py
index 9ce4674..5cf72fe 100644
--- a/tests/api_resources/test_runners.py
+++ b/tests/api_resources/test_runners.py
@@ -17,6 +17,7 @@
RunnerParseContextURLResponse,
RunnerCreateRunnerTokenResponse,
RunnerSearchRepositoriesResponse,
+ RunnerListScmOrganizationsResponse,
RunnerCheckAuthenticationForHostResponse,
)
from gitpod.pagination import SyncRunnersPage, AsyncRunnersPage
@@ -363,6 +364,45 @@ def test_streaming_response_create_runner_token(self, client: Gitpod) -> None:
assert cast(Any, response.is_closed) is True
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_list_scm_organizations(self, client: Gitpod) -> None:
+ runner = client.runners.list_scm_organizations()
+ assert_matches_type(RunnerListScmOrganizationsResponse, runner, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_list_scm_organizations_with_all_params(self, client: Gitpod) -> None:
+ runner = client.runners.list_scm_organizations(
+ token="token",
+ page_size=0,
+ runner_id="d2c94c27-3b76-4a42-b88c-95a85e392c68",
+ scm_host="github.com",
+ )
+ assert_matches_type(RunnerListScmOrganizationsResponse, runner, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_raw_response_list_scm_organizations(self, client: Gitpod) -> None:
+ response = client.runners.with_raw_response.list_scm_organizations()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ runner = response.parse()
+ assert_matches_type(RunnerListScmOrganizationsResponse, runner, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_streaming_response_list_scm_organizations(self, client: Gitpod) -> None:
+ with client.runners.with_streaming_response.list_scm_organizations() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ runner = response.parse()
+ assert_matches_type(RunnerListScmOrganizationsResponse, runner, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
@pytest.mark.skip(reason="Prism tests are disabled")
@parametrize
def test_method_parse_context_url(self, client: Gitpod) -> None:
@@ -786,6 +826,45 @@ async def test_streaming_response_create_runner_token(self, async_client: AsyncG
assert cast(Any, response.is_closed) is True
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_list_scm_organizations(self, async_client: AsyncGitpod) -> None:
+ runner = await async_client.runners.list_scm_organizations()
+ assert_matches_type(RunnerListScmOrganizationsResponse, runner, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_list_scm_organizations_with_all_params(self, async_client: AsyncGitpod) -> None:
+ runner = await async_client.runners.list_scm_organizations(
+ token="token",
+ page_size=0,
+ runner_id="d2c94c27-3b76-4a42-b88c-95a85e392c68",
+ scm_host="github.com",
+ )
+ assert_matches_type(RunnerListScmOrganizationsResponse, runner, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_raw_response_list_scm_organizations(self, async_client: AsyncGitpod) -> None:
+ response = await async_client.runners.with_raw_response.list_scm_organizations()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ runner = await response.parse()
+ assert_matches_type(RunnerListScmOrganizationsResponse, runner, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_streaming_response_list_scm_organizations(self, async_client: AsyncGitpod) -> None:
+ async with async_client.runners.with_streaming_response.list_scm_organizations() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ runner = await response.parse()
+ assert_matches_type(RunnerListScmOrganizationsResponse, runner, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
@pytest.mark.skip(reason="Prism tests are disabled")
@parametrize
async def test_method_parse_context_url(self, async_client: AsyncGitpod) -> None:
From 53dcf30cb41a6cbf30ce510b0b2d46cdd5895008 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Wed, 21 Jan 2026 14:28:04 +0000
Subject: [PATCH 16/27] chore(internal): update `actions/checkout` version
---
.github/workflows/ci.yml | 32 +++++++++++++++---------------
.github/workflows/publish-pypi.yml | 6 +++---
2 files changed, 19 insertions(+), 19 deletions(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index a69c2e7..e4988ca 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -2,15 +2,15 @@ name: CI
on:
push:
branches-ignore:
- - 'generated'
- - 'codegen/**'
- - 'integrated/**'
- - 'stl-preview-head/**'
- - 'stl-preview-base/**'
+ - "generated"
+ - "codegen/**"
+ - "integrated/**"
+ - "stl-preview-head/**"
+ - "stl-preview-base/**"
pull_request:
branches-ignore:
- - 'stl-preview-head/**'
- - 'stl-preview-base/**'
+ - "stl-preview-head/**"
+ - "stl-preview-base/**"
jobs:
lint:
@@ -19,15 +19,15 @@ jobs:
runs-on: ${{ github.repository == 'stainless-sdks/gitpod-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
if: github.event_name == 'push' || github.event.pull_request.head.repo.fork
steps:
- - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
- name: Install Rye
run: |
curl -sSf https://rye.astral.sh/get | bash
echo "$HOME/.rye/shims" >> $GITHUB_PATH
env:
- RYE_VERSION: '0.44.0'
- RYE_INSTALL_OPTION: '--yes'
+ RYE_VERSION: "0.44.0"
+ RYE_INSTALL_OPTION: "--yes"
- name: Install dependencies
run: rye sync --all-features
@@ -44,15 +44,15 @@ jobs:
id-token: write
runs-on: ${{ github.repository == 'stainless-sdks/gitpod-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
steps:
- - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
- name: Install Rye
run: |
curl -sSf https://rye.astral.sh/get | bash
echo "$HOME/.rye/shims" >> $GITHUB_PATH
env:
- RYE_VERSION: '0.44.0'
- RYE_INSTALL_OPTION: '--yes'
+ RYE_VERSION: "0.44.0"
+ RYE_INSTALL_OPTION: "--yes"
- name: Install dependencies
run: rye sync --all-features
@@ -81,15 +81,15 @@ jobs:
runs-on: ${{ github.repository == 'stainless-sdks/gitpod-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
if: github.event_name == 'push' || github.event.pull_request.head.repo.fork
steps:
- - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
- name: Install Rye
run: |
curl -sSf https://rye.astral.sh/get | bash
echo "$HOME/.rye/shims" >> $GITHUB_PATH
env:
- RYE_VERSION: '0.44.0'
- RYE_INSTALL_OPTION: '--yes'
+ RYE_VERSION: "0.44.0"
+ RYE_INSTALL_OPTION: "--yes"
- name: Bootstrap
run: ./scripts/bootstrap
diff --git a/.github/workflows/publish-pypi.yml b/.github/workflows/publish-pypi.yml
index 3343ab6..0c20e7d 100644
--- a/.github/workflows/publish-pypi.yml
+++ b/.github/workflows/publish-pypi.yml
@@ -17,19 +17,19 @@ jobs:
id-token: write
steps:
- - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
- name: Install Rye
uses: eifinger/setup-rye@c694239a43768373e87d0103d7f547027a23f3c8 # v4
with:
version: '0.44.0'
-
+
- name: Sync dependencies
run: rye sync
- name: Build package
run: rye build --clean
-
+
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # release/v1
with:
From 70becd4cd142fac4fc839018d52fb4cb93e17834 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Fri, 16 Jan 2026 19:01:09 +0000
Subject: [PATCH 17/27] feat: API for SCIM configuration management
---
.stats.yml | 8 +-
api.md | 23 +
src/gitpod/pagination.py | 53 +
.../resources/organizations/__init__.py | 14 +
.../resources/organizations/organizations.py | 32 +
.../organizations/scim_configurations.py | 909 ++++++++++++++++++
src/gitpod/types/organizations/__init__.py | 15 +
.../types/organizations/scim_configuration.py | 37 +
.../scim_configuration_create_params.py | 27 +
.../scim_configuration_create_response.py | 19 +
.../scim_configuration_delete_params.py | 14 +
.../scim_configuration_list_params.py | 31 +
...m_configuration_regenerate_token_params.py | 17 +
...configuration_regenerate_token_response.py | 13 +
.../scim_configuration_retrieve_params.py | 14 +
.../scim_configuration_retrieve_response.py | 13 +
.../scim_configuration_update_params.py | 24 +
.../scim_configuration_update_response.py | 13 +
.../organizations/test_scim_configurations.py | 501 ++++++++++
19 files changed, 1773 insertions(+), 4 deletions(-)
create mode 100644 src/gitpod/resources/organizations/scim_configurations.py
create mode 100644 src/gitpod/types/organizations/scim_configuration.py
create mode 100644 src/gitpod/types/organizations/scim_configuration_create_params.py
create mode 100644 src/gitpod/types/organizations/scim_configuration_create_response.py
create mode 100644 src/gitpod/types/organizations/scim_configuration_delete_params.py
create mode 100644 src/gitpod/types/organizations/scim_configuration_list_params.py
create mode 100644 src/gitpod/types/organizations/scim_configuration_regenerate_token_params.py
create mode 100644 src/gitpod/types/organizations/scim_configuration_regenerate_token_response.py
create mode 100644 src/gitpod/types/organizations/scim_configuration_retrieve_params.py
create mode 100644 src/gitpod/types/organizations/scim_configuration_retrieve_response.py
create mode 100644 src/gitpod/types/organizations/scim_configuration_update_params.py
create mode 100644 src/gitpod/types/organizations/scim_configuration_update_response.py
create mode 100644 tests/api_resources/organizations/test_scim_configurations.py
diff --git a/.stats.yml b/.stats.yml
index d64cbf2..c7d8a2f 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
-configured_endpoints: 161
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-baa13045a9492d958fc06db0dcee2fd99972435f8b9a707831cf4da8d84db194.yml
-openapi_spec_hash: 5e7adb5d5cdf924eb7c0e4ddf1b81260
-config_hash: d930f7e17a525d153b810339251607b7
+configured_endpoints: 167
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-40c6617e0b944168058135c9325d556b21c2edde19518090aefa542c76afcdb3.yml
+openapi_spec_hash: 235404d99aa56e51b933261d195dc206
+config_hash: cec4ffca97dd72023c573623499bc35b
diff --git a/api.md b/api.md
index ed7817a..8c0b90a 100644
--- a/api.md
+++ b/api.md
@@ -438,6 +438,29 @@ Methods:
- client.organizations.policies.retrieve(\*\*params) -> PolicyRetrieveResponse
- client.organizations.policies.update(\*\*params) -> object
+## ScimConfigurations
+
+Types:
+
+```python
+from gitpod.types.organizations import (
+ ScimConfiguration,
+ ScimConfigurationCreateResponse,
+ ScimConfigurationRetrieveResponse,
+ ScimConfigurationUpdateResponse,
+ ScimConfigurationRegenerateTokenResponse,
+)
+```
+
+Methods:
+
+- client.organizations.scim_configurations.create(\*\*params) -> ScimConfigurationCreateResponse
+- client.organizations.scim_configurations.retrieve(\*\*params) -> ScimConfigurationRetrieveResponse
+- client.organizations.scim_configurations.update(\*\*params) -> ScimConfigurationUpdateResponse
+- client.organizations.scim_configurations.list(\*\*params) -> SyncScimConfigurationsPage[ScimConfiguration]
+- client.organizations.scim_configurations.delete(\*\*params) -> object
+- client.organizations.scim_configurations.regenerate_token(\*\*params) -> ScimConfigurationRegenerateTokenResponse
+
## SSOConfigurations
Types:
diff --git a/src/gitpod/pagination.py b/src/gitpod/pagination.py
index c8d007f..0ffd69d 100644
--- a/src/gitpod/pagination.py
+++ b/src/gitpod/pagination.py
@@ -78,6 +78,9 @@
"RunnersPagePagination",
"SyncRunnersPage",
"AsyncRunnersPage",
+ "ScimConfigurationsPagePagination",
+ "SyncScimConfigurationsPage",
+ "AsyncScimConfigurationsPage",
"SecretsPagePagination",
"SyncSecretsPage",
"AsyncSecretsPage",
@@ -1251,6 +1254,56 @@ def next_page_info(self) -> Optional[PageInfo]:
return PageInfo(params={"token": next_token})
+class ScimConfigurationsPagePagination(BaseModel):
+ next_token: Optional[str] = FieldInfo(alias="nextToken", default=None)
+
+
+class SyncScimConfigurationsPage(BaseSyncPage[_T], BasePage[_T], Generic[_T]):
+ pagination: Optional[ScimConfigurationsPagePagination] = None
+ scim_configurations: List[_T] = FieldInfo(alias="scimConfigurations")
+
+ @override
+ def _get_page_items(self) -> List[_T]:
+ scim_configurations = self.scim_configurations
+ if not scim_configurations:
+ return []
+ return scim_configurations
+
+ @override
+ def next_page_info(self) -> Optional[PageInfo]:
+ next_token = None
+ if self.pagination is not None:
+ if self.pagination.next_token is not None:
+ next_token = self.pagination.next_token
+ if not next_token:
+ return None
+
+ return PageInfo(params={"token": next_token})
+
+
+class AsyncScimConfigurationsPage(BaseAsyncPage[_T], BasePage[_T], Generic[_T]):
+ pagination: Optional[ScimConfigurationsPagePagination] = None
+ scim_configurations: List[_T] = FieldInfo(alias="scimConfigurations")
+
+ @override
+ def _get_page_items(self) -> List[_T]:
+ scim_configurations = self.scim_configurations
+ if not scim_configurations:
+ return []
+ return scim_configurations
+
+ @override
+ def next_page_info(self) -> Optional[PageInfo]:
+ next_token = None
+ if self.pagination is not None:
+ if self.pagination.next_token is not None:
+ next_token = self.pagination.next_token
+ if not next_token:
+ return None
+
+ return PageInfo(params={"token": next_token})
+
+
class SecretsPagePagination(BaseModel):
next_token: Optional[str] = FieldInfo(alias="nextToken", default=None)
diff --git a/src/gitpod/resources/organizations/__init__.py b/src/gitpod/resources/organizations/__init__.py
index 84d6bde..21debec 100644
--- a/src/gitpod/resources/organizations/__init__.py
+++ b/src/gitpod/resources/organizations/__init__.py
@@ -40,6 +40,14 @@
SSOConfigurationsResourceWithStreamingResponse,
AsyncSSOConfigurationsResourceWithStreamingResponse,
)
+from .scim_configurations import (
+ ScimConfigurationsResource,
+ AsyncScimConfigurationsResource,
+ ScimConfigurationsResourceWithRawResponse,
+ AsyncScimConfigurationsResourceWithRawResponse,
+ ScimConfigurationsResourceWithStreamingResponse,
+ AsyncScimConfigurationsResourceWithStreamingResponse,
+)
from .domain_verifications import (
DomainVerificationsResource,
AsyncDomainVerificationsResource,
@@ -74,6 +82,12 @@
"AsyncPoliciesResourceWithRawResponse",
"PoliciesResourceWithStreamingResponse",
"AsyncPoliciesResourceWithStreamingResponse",
+ "ScimConfigurationsResource",
+ "AsyncScimConfigurationsResource",
+ "ScimConfigurationsResourceWithRawResponse",
+ "AsyncScimConfigurationsResourceWithRawResponse",
+ "ScimConfigurationsResourceWithStreamingResponse",
+ "AsyncScimConfigurationsResourceWithStreamingResponse",
"SSOConfigurationsResource",
"AsyncSSOConfigurationsResource",
"SSOConfigurationsResourceWithRawResponse",
diff --git a/src/gitpod/resources/organizations/organizations.py b/src/gitpod/resources/organizations/organizations.py
index c9de4ae..c45b8a5 100644
--- a/src/gitpod/resources/organizations/organizations.py
+++ b/src/gitpod/resources/organizations/organizations.py
@@ -60,6 +60,14 @@
SSOConfigurationsResourceWithStreamingResponse,
AsyncSSOConfigurationsResourceWithStreamingResponse,
)
+from .scim_configurations import (
+ ScimConfigurationsResource,
+ AsyncScimConfigurationsResource,
+ ScimConfigurationsResourceWithRawResponse,
+ AsyncScimConfigurationsResourceWithRawResponse,
+ ScimConfigurationsResourceWithStreamingResponse,
+ AsyncScimConfigurationsResourceWithStreamingResponse,
+)
from .domain_verifications import (
DomainVerificationsResource,
AsyncDomainVerificationsResource,
@@ -96,6 +104,10 @@ def invites(self) -> InvitesResource:
def policies(self) -> PoliciesResource:
return PoliciesResource(self._client)
+ @cached_property
+ def scim_configurations(self) -> ScimConfigurationsResource:
+ return ScimConfigurationsResource(self._client)
+
@cached_property
def sso_configurations(self) -> SSOConfigurationsResource:
return SSOConfigurationsResource(self._client)
@@ -682,6 +694,10 @@ def invites(self) -> AsyncInvitesResource:
def policies(self) -> AsyncPoliciesResource:
return AsyncPoliciesResource(self._client)
+ @cached_property
+ def scim_configurations(self) -> AsyncScimConfigurationsResource:
+ return AsyncScimConfigurationsResource(self._client)
+
@cached_property
def sso_configurations(self) -> AsyncSSOConfigurationsResource:
return AsyncSSOConfigurationsResource(self._client)
@@ -1296,6 +1312,10 @@ def invites(self) -> InvitesResourceWithRawResponse:
def policies(self) -> PoliciesResourceWithRawResponse:
return PoliciesResourceWithRawResponse(self._organizations.policies)
+ @cached_property
+ def scim_configurations(self) -> ScimConfigurationsResourceWithRawResponse:
+ return ScimConfigurationsResourceWithRawResponse(self._organizations.scim_configurations)
+
@cached_property
def sso_configurations(self) -> SSOConfigurationsResourceWithRawResponse:
return SSOConfigurationsResourceWithRawResponse(self._organizations.sso_configurations)
@@ -1346,6 +1366,10 @@ def invites(self) -> AsyncInvitesResourceWithRawResponse:
def policies(self) -> AsyncPoliciesResourceWithRawResponse:
return AsyncPoliciesResourceWithRawResponse(self._organizations.policies)
+ @cached_property
+ def scim_configurations(self) -> AsyncScimConfigurationsResourceWithRawResponse:
+ return AsyncScimConfigurationsResourceWithRawResponse(self._organizations.scim_configurations)
+
@cached_property
def sso_configurations(self) -> AsyncSSOConfigurationsResourceWithRawResponse:
return AsyncSSOConfigurationsResourceWithRawResponse(self._organizations.sso_configurations)
@@ -1396,6 +1420,10 @@ def invites(self) -> InvitesResourceWithStreamingResponse:
def policies(self) -> PoliciesResourceWithStreamingResponse:
return PoliciesResourceWithStreamingResponse(self._organizations.policies)
+ @cached_property
+ def scim_configurations(self) -> ScimConfigurationsResourceWithStreamingResponse:
+ return ScimConfigurationsResourceWithStreamingResponse(self._organizations.scim_configurations)
+
@cached_property
def sso_configurations(self) -> SSOConfigurationsResourceWithStreamingResponse:
return SSOConfigurationsResourceWithStreamingResponse(self._organizations.sso_configurations)
@@ -1446,6 +1474,10 @@ def invites(self) -> AsyncInvitesResourceWithStreamingResponse:
def policies(self) -> AsyncPoliciesResourceWithStreamingResponse:
return AsyncPoliciesResourceWithStreamingResponse(self._organizations.policies)
+ @cached_property
+ def scim_configurations(self) -> AsyncScimConfigurationsResourceWithStreamingResponse:
+ return AsyncScimConfigurationsResourceWithStreamingResponse(self._organizations.scim_configurations)
+
@cached_property
def sso_configurations(self) -> AsyncSSOConfigurationsResourceWithStreamingResponse:
return AsyncSSOConfigurationsResourceWithStreamingResponse(self._organizations.sso_configurations)
diff --git a/src/gitpod/resources/organizations/scim_configurations.py b/src/gitpod/resources/organizations/scim_configurations.py
new file mode 100644
index 0000000..529ae16
--- /dev/null
+++ b/src/gitpod/resources/organizations/scim_configurations.py
@@ -0,0 +1,909 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Optional
+
+import httpx
+
+from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
+from ..._utils import maybe_transform, async_maybe_transform
+from ..._compat import cached_property
+from ..._resource import SyncAPIResource, AsyncAPIResource
+from ..._response import (
+ to_raw_response_wrapper,
+ to_streamed_response_wrapper,
+ async_to_raw_response_wrapper,
+ async_to_streamed_response_wrapper,
+)
+from ...pagination import SyncScimConfigurationsPage, AsyncScimConfigurationsPage
+from ..._base_client import AsyncPaginator, make_request_options
+from ...types.organizations import (
+ scim_configuration_list_params,
+ scim_configuration_create_params,
+ scim_configuration_delete_params,
+ scim_configuration_update_params,
+ scim_configuration_retrieve_params,
+ scim_configuration_regenerate_token_params,
+)
+from ...types.organizations.scim_configuration import ScimConfiguration
+from ...types.organizations.scim_configuration_create_response import ScimConfigurationCreateResponse
+from ...types.organizations.scim_configuration_update_response import ScimConfigurationUpdateResponse
+from ...types.organizations.scim_configuration_retrieve_response import ScimConfigurationRetrieveResponse
+from ...types.organizations.scim_configuration_regenerate_token_response import ScimConfigurationRegenerateTokenResponse
+
+__all__ = ["ScimConfigurationsResource", "AsyncScimConfigurationsResource"]
+
+
+class ScimConfigurationsResource(SyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> ScimConfigurationsResourceWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers
+ """
+ return ScimConfigurationsResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> ScimConfigurationsResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response
+ """
+ return ScimConfigurationsResourceWithStreamingResponse(self)
+
+ def create(
+ self,
+ *,
+ organization_id: str,
+ sso_configuration_id: str,
+ name: Optional[str] | Omit = omit,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> ScimConfigurationCreateResponse:
+ """
+ Creates a new SCIM configuration for automated user provisioning.
+
+ Use this method to:
+
+ - Set up SCIM 2.0 provisioning from an identity provider
+ - Generate a bearer token for SCIM API authentication
+ - Link SCIM provisioning to an existing SSO configuration
+
+ ### Examples
+
+ - Create basic SCIM configuration:
+
+ Creates a SCIM configuration linked to an SSO provider.
+
+ ```yaml
+ organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047"
+ ssoConfigurationId: "d2c94c27-3b76-4a42-b88c-95a85e392c68"
+ ```
+
+ Args:
+ organization_id: organization_id is the ID of the organization to create the SCIM configuration
+ for
+
+ sso_configuration_id: sso_configuration_id is the SSO configuration to link (required for user
+ provisioning)
+
+ name: name is a human-readable name for the SCIM configuration
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ return self._post(
+ "/gitpod.v1.OrganizationService/CreateSCIMConfiguration",
+ body=maybe_transform(
+ {
+ "organization_id": organization_id,
+ "sso_configuration_id": sso_configuration_id,
+ "name": name,
+ },
+ scim_configuration_create_params.ScimConfigurationCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=ScimConfigurationCreateResponse,
+ )
+
+ def retrieve(
+ self,
+ *,
+ scim_configuration_id: str,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> ScimConfigurationRetrieveResponse:
+ """
+ Retrieves a specific SCIM configuration.
+
+ Use this method to:
+
+ - View SCIM configuration details
+ - Check if SCIM is enabled
+ - Verify SSO linkage
+
+ ### Examples
+
+ - Get SCIM configuration:
+
+ Retrieves details of a specific SCIM configuration.
+
+ ```yaml
+ scimConfigurationId: "d2c94c27-3b76-4a42-b88c-95a85e392c68"
+ ```
+
+ Args:
+ scim_configuration_id: scim_configuration_id is the ID of the SCIM configuration to get
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ return self._post(
+ "/gitpod.v1.OrganizationService/GetSCIMConfiguration",
+ body=maybe_transform(
+ {"scim_configuration_id": scim_configuration_id},
+ scim_configuration_retrieve_params.ScimConfigurationRetrieveParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=ScimConfigurationRetrieveResponse,
+ )
+
+ def update(
+ self,
+ *,
+ scim_configuration_id: str,
+ enabled: Optional[bool] | Omit = omit,
+ name: Optional[str] | Omit = omit,
+ sso_configuration_id: Optional[str] | Omit = omit,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> ScimConfigurationUpdateResponse:
+ """
+ Updates a SCIM configuration.
+
+ Use this method to:
+
+ - Enable or disable SCIM provisioning
+ - Link or unlink SSO configuration
+ - Update configuration name
+
+ ### Examples
+
+ - Disable SCIM:
+
+ Disables SCIM provisioning.
+
+ ```yaml
+ scimConfigurationId: "d2c94c27-3b76-4a42-b88c-95a85e392c68"
+ enabled: false
+ ```
+
+ - Link to SSO:
+
+ Links SCIM configuration to an SSO provider.
+
+ ```yaml
+ scimConfigurationId: "d2c94c27-3b76-4a42-b88c-95a85e392c68"
+ ssoConfigurationId: "f53d2330-3795-4c5d-a1f3-453121af9c60"
+ ```
+
+ Args:
+ scim_configuration_id: scim_configuration_id is the ID of the SCIM configuration to update
+
+ enabled: enabled controls whether SCIM provisioning is active
+
+ name: name is a human-readable name for the SCIM configuration
+
+ sso_configuration_id: sso_configuration_id is the SSO configuration to link
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ return self._post(
+ "/gitpod.v1.OrganizationService/UpdateSCIMConfiguration",
+ body=maybe_transform(
+ {
+ "scim_configuration_id": scim_configuration_id,
+ "enabled": enabled,
+ "name": name,
+ "sso_configuration_id": sso_configuration_id,
+ },
+ scim_configuration_update_params.ScimConfigurationUpdateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=ScimConfigurationUpdateResponse,
+ )
+
+ def list(
+ self,
+ *,
+ token: str | Omit = omit,
+ page_size: int | Omit = omit,
+ pagination: scim_configuration_list_params.Pagination | Omit = omit,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> SyncScimConfigurationsPage[ScimConfiguration]:
+ """
+ Lists SCIM configurations for an organization.
+
+ Use this method to:
+
+ - View all SCIM configurations
+ - Monitor provisioning status
+ - Audit SCIM settings
+
+ ### Examples
+
+ - List SCIM configurations:
+
+ Shows all SCIM configurations for an organization.
+
+ ```yaml
+ pagination:
+ pageSize: 20
+ ```
+
+ Args:
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ return self._get_api_list(
+ "/gitpod.v1.OrganizationService/ListSCIMConfigurations",
+ page=SyncScimConfigurationsPage[ScimConfiguration],
+ body=maybe_transform(
+ {"pagination": pagination}, scim_configuration_list_params.ScimConfigurationListParams
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "token": token,
+ "page_size": page_size,
+ },
+ scim_configuration_list_params.ScimConfigurationListParams,
+ ),
+ ),
+ model=ScimConfiguration,
+ method="post",
+ )
+
+ def delete(
+ self,
+ *,
+ scim_configuration_id: str,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> object:
+ """
+ Removes a SCIM configuration from an organization.
+
+ Use this method to:
+
+ - Disable SCIM provisioning completely
+ - Remove unused configurations
+ - Clean up after migration
+
+ ### Examples
+
+ - Delete SCIM configuration:
+
+ Removes a specific SCIM configuration.
+
+ ```yaml
+ scimConfigurationId: "d2c94c27-3b76-4a42-b88c-95a85e392c68"
+ ```
+
+ Args:
+ scim_configuration_id: scim_configuration_id is the ID of the SCIM configuration to delete
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ return self._post(
+ "/gitpod.v1.OrganizationService/DeleteSCIMConfiguration",
+ body=maybe_transform(
+ {"scim_configuration_id": scim_configuration_id},
+ scim_configuration_delete_params.ScimConfigurationDeleteParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=object,
+ )
+
+ def regenerate_token(
+ self,
+ *,
+ scim_configuration_id: str,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> ScimConfigurationRegenerateTokenResponse:
+ """
+ Regenerates the bearer token for a SCIM configuration.
+
+ Use this method to:
+
+ - Rotate SCIM credentials
+ - Recover from token compromise
+ - Update IdP configuration
+
+ ### Examples
+
+ - Regenerate token:
+
+ Creates a new bearer token, invalidating the old one.
+
+ ```yaml
+ scimConfigurationId: "d2c94c27-3b76-4a42-b88c-95a85e392c68"
+ ```
+
+ Args:
+ scim_configuration_id: scim_configuration_id is the ID of the SCIM configuration to regenerate token
+ for
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ return self._post(
+ "/gitpod.v1.OrganizationService/RegenerateSCIMToken",
+ body=maybe_transform(
+ {"scim_configuration_id": scim_configuration_id},
+ scim_configuration_regenerate_token_params.ScimConfigurationRegenerateTokenParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=ScimConfigurationRegenerateTokenResponse,
+ )
+
+
+class AsyncScimConfigurationsResource(AsyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> AsyncScimConfigurationsResourceWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers
+ """
+ return AsyncScimConfigurationsResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncScimConfigurationsResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response
+ """
+ return AsyncScimConfigurationsResourceWithStreamingResponse(self)
+
+ async def create(
+ self,
+ *,
+ organization_id: str,
+ sso_configuration_id: str,
+ name: Optional[str] | Omit = omit,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> ScimConfigurationCreateResponse:
+ """
+ Creates a new SCIM configuration for automated user provisioning.
+
+ Use this method to:
+
+ - Set up SCIM 2.0 provisioning from an identity provider
+ - Generate a bearer token for SCIM API authentication
+ - Link SCIM provisioning to an existing SSO configuration
+
+ ### Examples
+
+ - Create basic SCIM configuration:
+
+ Creates a SCIM configuration linked to an SSO provider.
+
+ ```yaml
+ organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047"
+ ssoConfigurationId: "d2c94c27-3b76-4a42-b88c-95a85e392c68"
+ ```
+
+ Args:
+ organization_id: organization_id is the ID of the organization to create the SCIM configuration
+ for
+
+ sso_configuration_id: sso_configuration_id is the SSO configuration to link (required for user
+ provisioning)
+
+ name: name is a human-readable name for the SCIM configuration
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ return await self._post(
+ "/gitpod.v1.OrganizationService/CreateSCIMConfiguration",
+ body=await async_maybe_transform(
+ {
+ "organization_id": organization_id,
+ "sso_configuration_id": sso_configuration_id,
+ "name": name,
+ },
+ scim_configuration_create_params.ScimConfigurationCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=ScimConfigurationCreateResponse,
+ )
+
+ async def retrieve(
+ self,
+ *,
+ scim_configuration_id: str,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> ScimConfigurationRetrieveResponse:
+ """
+ Retrieves a specific SCIM configuration.
+
+ Use this method to:
+
+ - View SCIM configuration details
+ - Check if SCIM is enabled
+ - Verify SSO linkage
+
+ ### Examples
+
+ - Get SCIM configuration:
+
+ Retrieves details of a specific SCIM configuration.
+
+ ```yaml
+ scimConfigurationId: "d2c94c27-3b76-4a42-b88c-95a85e392c68"
+ ```
+
+ Args:
+ scim_configuration_id: scim_configuration_id is the ID of the SCIM configuration to get
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ return await self._post(
+ "/gitpod.v1.OrganizationService/GetSCIMConfiguration",
+ body=await async_maybe_transform(
+ {"scim_configuration_id": scim_configuration_id},
+ scim_configuration_retrieve_params.ScimConfigurationRetrieveParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=ScimConfigurationRetrieveResponse,
+ )
+
+ async def update(
+ self,
+ *,
+ scim_configuration_id: str,
+ enabled: Optional[bool] | Omit = omit,
+ name: Optional[str] | Omit = omit,
+ sso_configuration_id: Optional[str] | Omit = omit,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> ScimConfigurationUpdateResponse:
+ """
+ Updates a SCIM configuration.
+
+ Use this method to:
+
+ - Enable or disable SCIM provisioning
+ - Link or unlink SSO configuration
+ - Update configuration name
+
+ ### Examples
+
+ - Disable SCIM:
+
+ Disables SCIM provisioning.
+
+ ```yaml
+ scimConfigurationId: "d2c94c27-3b76-4a42-b88c-95a85e392c68"
+ enabled: false
+ ```
+
+ - Link to SSO:
+
+ Links SCIM configuration to an SSO provider.
+
+ ```yaml
+ scimConfigurationId: "d2c94c27-3b76-4a42-b88c-95a85e392c68"
+ ssoConfigurationId: "f53d2330-3795-4c5d-a1f3-453121af9c60"
+ ```
+
+ Args:
+ scim_configuration_id: scim_configuration_id is the ID of the SCIM configuration to update
+
+ enabled: enabled controls whether SCIM provisioning is active
+
+ name: name is a human-readable name for the SCIM configuration
+
+ sso_configuration_id: sso_configuration_id is the SSO configuration to link
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ return await self._post(
+ "/gitpod.v1.OrganizationService/UpdateSCIMConfiguration",
+ body=await async_maybe_transform(
+ {
+ "scim_configuration_id": scim_configuration_id,
+ "enabled": enabled,
+ "name": name,
+ "sso_configuration_id": sso_configuration_id,
+ },
+ scim_configuration_update_params.ScimConfigurationUpdateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=ScimConfigurationUpdateResponse,
+ )
+
+ def list(
+ self,
+ *,
+ token: str | Omit = omit,
+ page_size: int | Omit = omit,
+ pagination: scim_configuration_list_params.Pagination | Omit = omit,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> AsyncPaginator[ScimConfiguration, AsyncScimConfigurationsPage[ScimConfiguration]]:
+ """
+ Lists SCIM configurations for an organization.
+
+ Use this method to:
+
+ - View all SCIM configurations
+ - Monitor provisioning status
+ - Audit SCIM settings
+
+ ### Examples
+
+ - List SCIM configurations:
+
+ Shows all SCIM configurations for an organization.
+
+ ```yaml
+ pagination:
+ pageSize: 20
+ ```
+
+ Args:
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ return self._get_api_list(
+ "/gitpod.v1.OrganizationService/ListSCIMConfigurations",
+ page=AsyncScimConfigurationsPage[ScimConfiguration],
+ body=maybe_transform(
+ {"pagination": pagination}, scim_configuration_list_params.ScimConfigurationListParams
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "token": token,
+ "page_size": page_size,
+ },
+ scim_configuration_list_params.ScimConfigurationListParams,
+ ),
+ ),
+ model=ScimConfiguration,
+ method="post",
+ )
+
+ async def delete(
+ self,
+ *,
+ scim_configuration_id: str,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> object:
+ """
+ Removes a SCIM configuration from an organization.
+
+ Use this method to:
+
+ - Disable SCIM provisioning completely
+ - Remove unused configurations
+ - Clean up after migration
+
+ ### Examples
+
+ - Delete SCIM configuration:
+
+ Removes a specific SCIM configuration.
+
+ ```yaml
+ scimConfigurationId: "d2c94c27-3b76-4a42-b88c-95a85e392c68"
+ ```
+
+ Args:
+ scim_configuration_id: scim_configuration_id is the ID of the SCIM configuration to delete
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ return await self._post(
+ "/gitpod.v1.OrganizationService/DeleteSCIMConfiguration",
+ body=await async_maybe_transform(
+ {"scim_configuration_id": scim_configuration_id},
+ scim_configuration_delete_params.ScimConfigurationDeleteParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=object,
+ )
+
+ async def regenerate_token(
+ self,
+ *,
+ scim_configuration_id: str,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> ScimConfigurationRegenerateTokenResponse:
+ """
+ Regenerates the bearer token for a SCIM configuration.
+
+ Use this method to:
+
+ - Rotate SCIM credentials
+ - Recover from token compromise
+ - Update IdP configuration
+
+ ### Examples
+
+ - Regenerate token:
+
+ Creates a new bearer token, invalidating the old one.
+
+ ```yaml
+ scimConfigurationId: "d2c94c27-3b76-4a42-b88c-95a85e392c68"
+ ```
+
+ Args:
+ scim_configuration_id: scim_configuration_id is the ID of the SCIM configuration to regenerate token
+ for
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ return await self._post(
+ "/gitpod.v1.OrganizationService/RegenerateSCIMToken",
+ body=await async_maybe_transform(
+ {"scim_configuration_id": scim_configuration_id},
+ scim_configuration_regenerate_token_params.ScimConfigurationRegenerateTokenParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=ScimConfigurationRegenerateTokenResponse,
+ )
+
+
+class ScimConfigurationsResourceWithRawResponse:
+ def __init__(self, scim_configurations: ScimConfigurationsResource) -> None:
+ self._scim_configurations = scim_configurations
+
+ self.create = to_raw_response_wrapper(
+ scim_configurations.create,
+ )
+ self.retrieve = to_raw_response_wrapper(
+ scim_configurations.retrieve,
+ )
+ self.update = to_raw_response_wrapper(
+ scim_configurations.update,
+ )
+ self.list = to_raw_response_wrapper(
+ scim_configurations.list,
+ )
+ self.delete = to_raw_response_wrapper(
+ scim_configurations.delete,
+ )
+ self.regenerate_token = to_raw_response_wrapper(
+ scim_configurations.regenerate_token,
+ )
+
+
+class AsyncScimConfigurationsResourceWithRawResponse:
+ def __init__(self, scim_configurations: AsyncScimConfigurationsResource) -> None:
+ self._scim_configurations = scim_configurations
+
+ self.create = async_to_raw_response_wrapper(
+ scim_configurations.create,
+ )
+ self.retrieve = async_to_raw_response_wrapper(
+ scim_configurations.retrieve,
+ )
+ self.update = async_to_raw_response_wrapper(
+ scim_configurations.update,
+ )
+ self.list = async_to_raw_response_wrapper(
+ scim_configurations.list,
+ )
+ self.delete = async_to_raw_response_wrapper(
+ scim_configurations.delete,
+ )
+ self.regenerate_token = async_to_raw_response_wrapper(
+ scim_configurations.regenerate_token,
+ )
+
+
+class ScimConfigurationsResourceWithStreamingResponse:
+ def __init__(self, scim_configurations: ScimConfigurationsResource) -> None:
+ self._scim_configurations = scim_configurations
+
+ self.create = to_streamed_response_wrapper(
+ scim_configurations.create,
+ )
+ self.retrieve = to_streamed_response_wrapper(
+ scim_configurations.retrieve,
+ )
+ self.update = to_streamed_response_wrapper(
+ scim_configurations.update,
+ )
+ self.list = to_streamed_response_wrapper(
+ scim_configurations.list,
+ )
+ self.delete = to_streamed_response_wrapper(
+ scim_configurations.delete,
+ )
+ self.regenerate_token = to_streamed_response_wrapper(
+ scim_configurations.regenerate_token,
+ )
+
+
+class AsyncScimConfigurationsResourceWithStreamingResponse:
+ def __init__(self, scim_configurations: AsyncScimConfigurationsResource) -> None:
+ self._scim_configurations = scim_configurations
+
+ self.create = async_to_streamed_response_wrapper(
+ scim_configurations.create,
+ )
+ self.retrieve = async_to_streamed_response_wrapper(
+ scim_configurations.retrieve,
+ )
+ self.update = async_to_streamed_response_wrapper(
+ scim_configurations.update,
+ )
+ self.list = async_to_streamed_response_wrapper(
+ scim_configurations.list,
+ )
+ self.delete = async_to_streamed_response_wrapper(
+ scim_configurations.delete,
+ )
+ self.regenerate_token = async_to_streamed_response_wrapper(
+ scim_configurations.regenerate_token,
+ )
diff --git a/src/gitpod/types/organizations/__init__.py b/src/gitpod/types/organizations/__init__.py
index ba4b2b5..60c60eb 100644
--- a/src/gitpod/types/organizations/__init__.py
+++ b/src/gitpod/types/organizations/__init__.py
@@ -6,6 +6,7 @@
from .custom_domain import CustomDomain as CustomDomain
from .provider_type import ProviderType as ProviderType
from .sso_configuration import SSOConfiguration as SSOConfiguration
+from .scim_configuration import ScimConfiguration as ScimConfiguration
from .crowd_strike_config import CrowdStrikeConfig as CrowdStrikeConfig
from .domain_verification import DomainVerification as DomainVerification
from .organization_invite import OrganizationInvite as OrganizationInvite
@@ -30,20 +31,34 @@
from .custom_domain_retrieve_params import CustomDomainRetrieveParams as CustomDomainRetrieveParams
from .custom_domain_update_response import CustomDomainUpdateResponse as CustomDomainUpdateResponse
from .sso_configuration_list_params import SSOConfigurationListParams as SSOConfigurationListParams
+from .scim_configuration_list_params import ScimConfigurationListParams as ScimConfigurationListParams
from .custom_domain_retrieve_response import CustomDomainRetrieveResponse as CustomDomainRetrieveResponse
from .domain_verification_list_params import DomainVerificationListParams as DomainVerificationListParams
from .sso_configuration_create_params import SSOConfigurationCreateParams as SSOConfigurationCreateParams
from .sso_configuration_delete_params import SSOConfigurationDeleteParams as SSOConfigurationDeleteParams
from .sso_configuration_update_params import SSOConfigurationUpdateParams as SSOConfigurationUpdateParams
+from .scim_configuration_create_params import ScimConfigurationCreateParams as ScimConfigurationCreateParams
+from .scim_configuration_delete_params import ScimConfigurationDeleteParams as ScimConfigurationDeleteParams
+from .scim_configuration_update_params import ScimConfigurationUpdateParams as ScimConfigurationUpdateParams
from .domain_verification_create_params import DomainVerificationCreateParams as DomainVerificationCreateParams
from .domain_verification_delete_params import DomainVerificationDeleteParams as DomainVerificationDeleteParams
from .domain_verification_verify_params import DomainVerificationVerifyParams as DomainVerificationVerifyParams
from .sso_configuration_create_response import SSOConfigurationCreateResponse as SSOConfigurationCreateResponse
from .sso_configuration_retrieve_params import SSOConfigurationRetrieveParams as SSOConfigurationRetrieveParams
+from .scim_configuration_create_response import ScimConfigurationCreateResponse as ScimConfigurationCreateResponse
+from .scim_configuration_retrieve_params import ScimConfigurationRetrieveParams as ScimConfigurationRetrieveParams
+from .scim_configuration_update_response import ScimConfigurationUpdateResponse as ScimConfigurationUpdateResponse
from .domain_verification_create_response import DomainVerificationCreateResponse as DomainVerificationCreateResponse
from .domain_verification_retrieve_params import DomainVerificationRetrieveParams as DomainVerificationRetrieveParams
from .domain_verification_verify_response import DomainVerificationVerifyResponse as DomainVerificationVerifyResponse
from .sso_configuration_retrieve_response import SSOConfigurationRetrieveResponse as SSOConfigurationRetrieveResponse
+from .scim_configuration_retrieve_response import ScimConfigurationRetrieveResponse as ScimConfigurationRetrieveResponse
from .domain_verification_retrieve_response import (
DomainVerificationRetrieveResponse as DomainVerificationRetrieveResponse,
)
+from .scim_configuration_regenerate_token_params import (
+ ScimConfigurationRegenerateTokenParams as ScimConfigurationRegenerateTokenParams,
+)
+from .scim_configuration_regenerate_token_response import (
+ ScimConfigurationRegenerateTokenResponse as ScimConfigurationRegenerateTokenResponse,
+)
diff --git a/src/gitpod/types/organizations/scim_configuration.py b/src/gitpod/types/organizations/scim_configuration.py
new file mode 100644
index 0000000..289db0f
--- /dev/null
+++ b/src/gitpod/types/organizations/scim_configuration.py
@@ -0,0 +1,37 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Optional
+from datetime import datetime
+
+from pydantic import Field as FieldInfo
+
+from ..._models import BaseModel
+
+__all__ = ["ScimConfiguration"]
+
+
+class ScimConfiguration(BaseModel):
+ """SCIMConfiguration represents a SCIM 2.0 provisioning configuration"""
+
+ id: str
+ """id is the unique identifier of the SCIM configuration"""
+
+ created_at: datetime = FieldInfo(alias="createdAt")
+ """created_at is when the SCIM configuration was created"""
+
+ organization_id: str = FieldInfo(alias="organizationId")
+ """
+ organization_id is the ID of the organization this SCIM configuration belongs to
+ """
+
+ updated_at: datetime = FieldInfo(alias="updatedAt")
+ """updated_at is when the SCIM configuration was last updated"""
+
+ enabled: Optional[bool] = None
+ """enabled indicates if SCIM provisioning is active"""
+
+ name: Optional[str] = None
+ """name is a human-readable name for the SCIM configuration"""
+
+ sso_configuration_id: Optional[str] = FieldInfo(alias="ssoConfigurationId", default=None)
+ """sso_configuration_id is the linked SSO configuration (optional)"""
diff --git a/src/gitpod/types/organizations/scim_configuration_create_params.py b/src/gitpod/types/organizations/scim_configuration_create_params.py
new file mode 100644
index 0000000..fae3380
--- /dev/null
+++ b/src/gitpod/types/organizations/scim_configuration_create_params.py
@@ -0,0 +1,27 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Optional
+from typing_extensions import Required, Annotated, TypedDict
+
+from ..._utils import PropertyInfo
+
+__all__ = ["ScimConfigurationCreateParams"]
+
+
+class ScimConfigurationCreateParams(TypedDict, total=False):
+ organization_id: Required[Annotated[str, PropertyInfo(alias="organizationId")]]
+ """
+ organization_id is the ID of the organization to create the SCIM configuration
+ for
+ """
+
+ sso_configuration_id: Required[Annotated[str, PropertyInfo(alias="ssoConfigurationId")]]
+ """
+ sso_configuration_id is the SSO configuration to link (required for user
+ provisioning)
+ """
+
+ name: Optional[str]
+ """name is a human-readable name for the SCIM configuration"""
diff --git a/src/gitpod/types/organizations/scim_configuration_create_response.py b/src/gitpod/types/organizations/scim_configuration_create_response.py
new file mode 100644
index 0000000..95ba89b
--- /dev/null
+++ b/src/gitpod/types/organizations/scim_configuration_create_response.py
@@ -0,0 +1,19 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from pydantic import Field as FieldInfo
+
+from ..._models import BaseModel
+from .scim_configuration import ScimConfiguration
+
+__all__ = ["ScimConfigurationCreateResponse"]
+
+
+class ScimConfigurationCreateResponse(BaseModel):
+ token: str
+ """
+ token is the bearer token for SCIM API authentication. This is only returned
+ once during creation - store it securely.
+ """
+
+ scim_configuration: ScimConfiguration = FieldInfo(alias="scimConfiguration")
+ """scim_configuration is the created SCIM configuration"""
diff --git a/src/gitpod/types/organizations/scim_configuration_delete_params.py b/src/gitpod/types/organizations/scim_configuration_delete_params.py
new file mode 100644
index 0000000..51972cb
--- /dev/null
+++ b/src/gitpod/types/organizations/scim_configuration_delete_params.py
@@ -0,0 +1,14 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Required, Annotated, TypedDict
+
+from ..._utils import PropertyInfo
+
+__all__ = ["ScimConfigurationDeleteParams"]
+
+
+class ScimConfigurationDeleteParams(TypedDict, total=False):
+ scim_configuration_id: Required[Annotated[str, PropertyInfo(alias="scimConfigurationId")]]
+ """scim_configuration_id is the ID of the SCIM configuration to delete"""
diff --git a/src/gitpod/types/organizations/scim_configuration_list_params.py b/src/gitpod/types/organizations/scim_configuration_list_params.py
new file mode 100644
index 0000000..199d3d3
--- /dev/null
+++ b/src/gitpod/types/organizations/scim_configuration_list_params.py
@@ -0,0 +1,31 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Annotated, TypedDict
+
+from ..._utils import PropertyInfo
+
+__all__ = ["ScimConfigurationListParams", "Pagination"]
+
+
+class ScimConfigurationListParams(TypedDict, total=False):
+ token: str
+
+ page_size: Annotated[int, PropertyInfo(alias="pageSize")]
+
+ pagination: Pagination
+
+
+class Pagination(TypedDict, total=False):
+ token: str
+ """
+ Token for the next set of results that was returned as next_token of a
+ PaginationResponse
+ """
+
+ page_size: Annotated[int, PropertyInfo(alias="pageSize")]
+ """Page size is the maximum number of results to retrieve per page. Defaults to 25.
+
+ Maximum 100.
+ """
diff --git a/src/gitpod/types/organizations/scim_configuration_regenerate_token_params.py b/src/gitpod/types/organizations/scim_configuration_regenerate_token_params.py
new file mode 100644
index 0000000..b6cedad
--- /dev/null
+++ b/src/gitpod/types/organizations/scim_configuration_regenerate_token_params.py
@@ -0,0 +1,17 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Required, Annotated, TypedDict
+
+from ..._utils import PropertyInfo
+
+__all__ = ["ScimConfigurationRegenerateTokenParams"]
+
+
+class ScimConfigurationRegenerateTokenParams(TypedDict, total=False):
+ scim_configuration_id: Required[Annotated[str, PropertyInfo(alias="scimConfigurationId")]]
+ """
+ scim_configuration_id is the ID of the SCIM configuration to regenerate token
+ for
+ """
diff --git a/src/gitpod/types/organizations/scim_configuration_regenerate_token_response.py b/src/gitpod/types/organizations/scim_configuration_regenerate_token_response.py
new file mode 100644
index 0000000..0af03b1
--- /dev/null
+++ b/src/gitpod/types/organizations/scim_configuration_regenerate_token_response.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from ..._models import BaseModel
+
+__all__ = ["ScimConfigurationRegenerateTokenResponse"]
+
+
+class ScimConfigurationRegenerateTokenResponse(BaseModel):
+ token: str
+ """
+ token is the new bearer token for SCIM API authentication. This invalidates the
+ previous token - store it securely.
+ """
diff --git a/src/gitpod/types/organizations/scim_configuration_retrieve_params.py b/src/gitpod/types/organizations/scim_configuration_retrieve_params.py
new file mode 100644
index 0000000..f020f21
--- /dev/null
+++ b/src/gitpod/types/organizations/scim_configuration_retrieve_params.py
@@ -0,0 +1,14 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Required, Annotated, TypedDict
+
+from ..._utils import PropertyInfo
+
+__all__ = ["ScimConfigurationRetrieveParams"]
+
+
+class ScimConfigurationRetrieveParams(TypedDict, total=False):
+ scim_configuration_id: Required[Annotated[str, PropertyInfo(alias="scimConfigurationId")]]
+ """scim_configuration_id is the ID of the SCIM configuration to get"""
diff --git a/src/gitpod/types/organizations/scim_configuration_retrieve_response.py b/src/gitpod/types/organizations/scim_configuration_retrieve_response.py
new file mode 100644
index 0000000..55bb90a
--- /dev/null
+++ b/src/gitpod/types/organizations/scim_configuration_retrieve_response.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from pydantic import Field as FieldInfo
+
+from ..._models import BaseModel
+from .scim_configuration import ScimConfiguration
+
+__all__ = ["ScimConfigurationRetrieveResponse"]
+
+
+class ScimConfigurationRetrieveResponse(BaseModel):
+ scim_configuration: ScimConfiguration = FieldInfo(alias="scimConfiguration")
+ """scim_configuration is the SCIM configuration identified by the ID"""
diff --git a/src/gitpod/types/organizations/scim_configuration_update_params.py b/src/gitpod/types/organizations/scim_configuration_update_params.py
new file mode 100644
index 0000000..da91917
--- /dev/null
+++ b/src/gitpod/types/organizations/scim_configuration_update_params.py
@@ -0,0 +1,24 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Optional
+from typing_extensions import Required, Annotated, TypedDict
+
+from ..._utils import PropertyInfo
+
+__all__ = ["ScimConfigurationUpdateParams"]
+
+
+class ScimConfigurationUpdateParams(TypedDict, total=False):
+ scim_configuration_id: Required[Annotated[str, PropertyInfo(alias="scimConfigurationId")]]
+ """scim_configuration_id is the ID of the SCIM configuration to update"""
+
+ enabled: Optional[bool]
+ """enabled controls whether SCIM provisioning is active"""
+
+ name: Optional[str]
+ """name is a human-readable name for the SCIM configuration"""
+
+ sso_configuration_id: Annotated[Optional[str], PropertyInfo(alias="ssoConfigurationId")]
+ """sso_configuration_id is the SSO configuration to link"""
diff --git a/src/gitpod/types/organizations/scim_configuration_update_response.py b/src/gitpod/types/organizations/scim_configuration_update_response.py
new file mode 100644
index 0000000..4c4d0ac
--- /dev/null
+++ b/src/gitpod/types/organizations/scim_configuration_update_response.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from pydantic import Field as FieldInfo
+
+from ..._models import BaseModel
+from .scim_configuration import ScimConfiguration
+
+__all__ = ["ScimConfigurationUpdateResponse"]
+
+
+class ScimConfigurationUpdateResponse(BaseModel):
+ scim_configuration: ScimConfiguration = FieldInfo(alias="scimConfiguration")
+ """scim_configuration is the updated SCIM configuration"""
diff --git a/tests/api_resources/organizations/test_scim_configurations.py b/tests/api_resources/organizations/test_scim_configurations.py
new file mode 100644
index 0000000..16c6e25
--- /dev/null
+++ b/tests/api_resources/organizations/test_scim_configurations.py
@@ -0,0 +1,501 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import os
+from typing import Any, cast
+
+import pytest
+
+from gitpod import Gitpod, AsyncGitpod
+from tests.utils import assert_matches_type
+from gitpod.pagination import SyncScimConfigurationsPage, AsyncScimConfigurationsPage
+from gitpod.types.organizations import (
+ ScimConfiguration,
+ ScimConfigurationCreateResponse,
+ ScimConfigurationUpdateResponse,
+ ScimConfigurationRetrieveResponse,
+ ScimConfigurationRegenerateTokenResponse,
+)
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestScimConfigurations:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_create(self, client: Gitpod) -> None:
+ scim_configuration = client.organizations.scim_configurations.create(
+ organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047",
+ sso_configuration_id="d2c94c27-3b76-4a42-b88c-95a85e392c68",
+ )
+ assert_matches_type(ScimConfigurationCreateResponse, scim_configuration, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_create_with_all_params(self, client: Gitpod) -> None:
+ scim_configuration = client.organizations.scim_configurations.create(
+ organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047",
+ sso_configuration_id="d2c94c27-3b76-4a42-b88c-95a85e392c68",
+ name="name",
+ )
+ assert_matches_type(ScimConfigurationCreateResponse, scim_configuration, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_raw_response_create(self, client: Gitpod) -> None:
+ response = client.organizations.scim_configurations.with_raw_response.create(
+ organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047",
+ sso_configuration_id="d2c94c27-3b76-4a42-b88c-95a85e392c68",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ scim_configuration = response.parse()
+ assert_matches_type(ScimConfigurationCreateResponse, scim_configuration, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_streaming_response_create(self, client: Gitpod) -> None:
+ with client.organizations.scim_configurations.with_streaming_response.create(
+ organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047",
+ sso_configuration_id="d2c94c27-3b76-4a42-b88c-95a85e392c68",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ scim_configuration = response.parse()
+ assert_matches_type(ScimConfigurationCreateResponse, scim_configuration, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_retrieve(self, client: Gitpod) -> None:
+ scim_configuration = client.organizations.scim_configurations.retrieve(
+ scim_configuration_id="d2c94c27-3b76-4a42-b88c-95a85e392c68",
+ )
+ assert_matches_type(ScimConfigurationRetrieveResponse, scim_configuration, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_raw_response_retrieve(self, client: Gitpod) -> None:
+ response = client.organizations.scim_configurations.with_raw_response.retrieve(
+ scim_configuration_id="d2c94c27-3b76-4a42-b88c-95a85e392c68",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ scim_configuration = response.parse()
+ assert_matches_type(ScimConfigurationRetrieveResponse, scim_configuration, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_streaming_response_retrieve(self, client: Gitpod) -> None:
+ with client.organizations.scim_configurations.with_streaming_response.retrieve(
+ scim_configuration_id="d2c94c27-3b76-4a42-b88c-95a85e392c68",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ scim_configuration = response.parse()
+ assert_matches_type(ScimConfigurationRetrieveResponse, scim_configuration, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_update(self, client: Gitpod) -> None:
+ scim_configuration = client.organizations.scim_configurations.update(
+ scim_configuration_id="d2c94c27-3b76-4a42-b88c-95a85e392c68",
+ )
+ assert_matches_type(ScimConfigurationUpdateResponse, scim_configuration, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_update_with_all_params(self, client: Gitpod) -> None:
+ scim_configuration = client.organizations.scim_configurations.update(
+ scim_configuration_id="d2c94c27-3b76-4a42-b88c-95a85e392c68",
+ enabled=False,
+ name="name",
+ sso_configuration_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert_matches_type(ScimConfigurationUpdateResponse, scim_configuration, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_raw_response_update(self, client: Gitpod) -> None:
+ response = client.organizations.scim_configurations.with_raw_response.update(
+ scim_configuration_id="d2c94c27-3b76-4a42-b88c-95a85e392c68",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ scim_configuration = response.parse()
+ assert_matches_type(ScimConfigurationUpdateResponse, scim_configuration, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_streaming_response_update(self, client: Gitpod) -> None:
+ with client.organizations.scim_configurations.with_streaming_response.update(
+ scim_configuration_id="d2c94c27-3b76-4a42-b88c-95a85e392c68",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ scim_configuration = response.parse()
+ assert_matches_type(ScimConfigurationUpdateResponse, scim_configuration, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_list(self, client: Gitpod) -> None:
+ scim_configuration = client.organizations.scim_configurations.list()
+ assert_matches_type(SyncScimConfigurationsPage[ScimConfiguration], scim_configuration, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_list_with_all_params(self, client: Gitpod) -> None:
+ scim_configuration = client.organizations.scim_configurations.list(
+ token="token",
+ page_size=0,
+ pagination={
+ "token": "token",
+ "page_size": 20,
+ },
+ )
+ assert_matches_type(SyncScimConfigurationsPage[ScimConfiguration], scim_configuration, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_raw_response_list(self, client: Gitpod) -> None:
+ response = client.organizations.scim_configurations.with_raw_response.list()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ scim_configuration = response.parse()
+ assert_matches_type(SyncScimConfigurationsPage[ScimConfiguration], scim_configuration, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_streaming_response_list(self, client: Gitpod) -> None:
+ with client.organizations.scim_configurations.with_streaming_response.list() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ scim_configuration = response.parse()
+ assert_matches_type(SyncScimConfigurationsPage[ScimConfiguration], scim_configuration, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_delete(self, client: Gitpod) -> None:
+ scim_configuration = client.organizations.scim_configurations.delete(
+ scim_configuration_id="d2c94c27-3b76-4a42-b88c-95a85e392c68",
+ )
+ assert_matches_type(object, scim_configuration, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_raw_response_delete(self, client: Gitpod) -> None:
+ response = client.organizations.scim_configurations.with_raw_response.delete(
+ scim_configuration_id="d2c94c27-3b76-4a42-b88c-95a85e392c68",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ scim_configuration = response.parse()
+ assert_matches_type(object, scim_configuration, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_streaming_response_delete(self, client: Gitpod) -> None:
+ with client.organizations.scim_configurations.with_streaming_response.delete(
+ scim_configuration_id="d2c94c27-3b76-4a42-b88c-95a85e392c68",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ scim_configuration = response.parse()
+ assert_matches_type(object, scim_configuration, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_regenerate_token(self, client: Gitpod) -> None:
+ scim_configuration = client.organizations.scim_configurations.regenerate_token(
+ scim_configuration_id="d2c94c27-3b76-4a42-b88c-95a85e392c68",
+ )
+ assert_matches_type(ScimConfigurationRegenerateTokenResponse, scim_configuration, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_raw_response_regenerate_token(self, client: Gitpod) -> None:
+ response = client.organizations.scim_configurations.with_raw_response.regenerate_token(
+ scim_configuration_id="d2c94c27-3b76-4a42-b88c-95a85e392c68",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ scim_configuration = response.parse()
+ assert_matches_type(ScimConfigurationRegenerateTokenResponse, scim_configuration, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_streaming_response_regenerate_token(self, client: Gitpod) -> None:
+ with client.organizations.scim_configurations.with_streaming_response.regenerate_token(
+ scim_configuration_id="d2c94c27-3b76-4a42-b88c-95a85e392c68",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ scim_configuration = response.parse()
+ assert_matches_type(ScimConfigurationRegenerateTokenResponse, scim_configuration, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+
+class TestAsyncScimConfigurations:
+ parametrize = pytest.mark.parametrize(
+ "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
+ )
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_create(self, async_client: AsyncGitpod) -> None:
+ scim_configuration = await async_client.organizations.scim_configurations.create(
+ organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047",
+ sso_configuration_id="d2c94c27-3b76-4a42-b88c-95a85e392c68",
+ )
+ assert_matches_type(ScimConfigurationCreateResponse, scim_configuration, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_create_with_all_params(self, async_client: AsyncGitpod) -> None:
+ scim_configuration = await async_client.organizations.scim_configurations.create(
+ organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047",
+ sso_configuration_id="d2c94c27-3b76-4a42-b88c-95a85e392c68",
+ name="name",
+ )
+ assert_matches_type(ScimConfigurationCreateResponse, scim_configuration, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_raw_response_create(self, async_client: AsyncGitpod) -> None:
+ response = await async_client.organizations.scim_configurations.with_raw_response.create(
+ organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047",
+ sso_configuration_id="d2c94c27-3b76-4a42-b88c-95a85e392c68",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ scim_configuration = await response.parse()
+ assert_matches_type(ScimConfigurationCreateResponse, scim_configuration, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_streaming_response_create(self, async_client: AsyncGitpod) -> None:
+ async with async_client.organizations.scim_configurations.with_streaming_response.create(
+ organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047",
+ sso_configuration_id="d2c94c27-3b76-4a42-b88c-95a85e392c68",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ scim_configuration = await response.parse()
+ assert_matches_type(ScimConfigurationCreateResponse, scim_configuration, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_retrieve(self, async_client: AsyncGitpod) -> None:
+ scim_configuration = await async_client.organizations.scim_configurations.retrieve(
+ scim_configuration_id="d2c94c27-3b76-4a42-b88c-95a85e392c68",
+ )
+ assert_matches_type(ScimConfigurationRetrieveResponse, scim_configuration, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_raw_response_retrieve(self, async_client: AsyncGitpod) -> None:
+ response = await async_client.organizations.scim_configurations.with_raw_response.retrieve(
+ scim_configuration_id="d2c94c27-3b76-4a42-b88c-95a85e392c68",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ scim_configuration = await response.parse()
+ assert_matches_type(ScimConfigurationRetrieveResponse, scim_configuration, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_streaming_response_retrieve(self, async_client: AsyncGitpod) -> None:
+ async with async_client.organizations.scim_configurations.with_streaming_response.retrieve(
+ scim_configuration_id="d2c94c27-3b76-4a42-b88c-95a85e392c68",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ scim_configuration = await response.parse()
+ assert_matches_type(ScimConfigurationRetrieveResponse, scim_configuration, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_update(self, async_client: AsyncGitpod) -> None:
+ scim_configuration = await async_client.organizations.scim_configurations.update(
+ scim_configuration_id="d2c94c27-3b76-4a42-b88c-95a85e392c68",
+ )
+ assert_matches_type(ScimConfigurationUpdateResponse, scim_configuration, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_update_with_all_params(self, async_client: AsyncGitpod) -> None:
+ scim_configuration = await async_client.organizations.scim_configurations.update(
+ scim_configuration_id="d2c94c27-3b76-4a42-b88c-95a85e392c68",
+ enabled=False,
+ name="name",
+ sso_configuration_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert_matches_type(ScimConfigurationUpdateResponse, scim_configuration, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_raw_response_update(self, async_client: AsyncGitpod) -> None:
+ response = await async_client.organizations.scim_configurations.with_raw_response.update(
+ scim_configuration_id="d2c94c27-3b76-4a42-b88c-95a85e392c68",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ scim_configuration = await response.parse()
+ assert_matches_type(ScimConfigurationUpdateResponse, scim_configuration, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_streaming_response_update(self, async_client: AsyncGitpod) -> None:
+ async with async_client.organizations.scim_configurations.with_streaming_response.update(
+ scim_configuration_id="d2c94c27-3b76-4a42-b88c-95a85e392c68",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ scim_configuration = await response.parse()
+ assert_matches_type(ScimConfigurationUpdateResponse, scim_configuration, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_list(self, async_client: AsyncGitpod) -> None:
+ scim_configuration = await async_client.organizations.scim_configurations.list()
+ assert_matches_type(AsyncScimConfigurationsPage[ScimConfiguration], scim_configuration, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_list_with_all_params(self, async_client: AsyncGitpod) -> None:
+ scim_configuration = await async_client.organizations.scim_configurations.list(
+ token="token",
+ page_size=0,
+ pagination={
+ "token": "token",
+ "page_size": 20,
+ },
+ )
+ assert_matches_type(AsyncScimConfigurationsPage[ScimConfiguration], scim_configuration, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_raw_response_list(self, async_client: AsyncGitpod) -> None:
+ response = await async_client.organizations.scim_configurations.with_raw_response.list()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ scim_configuration = await response.parse()
+ assert_matches_type(AsyncScimConfigurationsPage[ScimConfiguration], scim_configuration, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_streaming_response_list(self, async_client: AsyncGitpod) -> None:
+ async with async_client.organizations.scim_configurations.with_streaming_response.list() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ scim_configuration = await response.parse()
+ assert_matches_type(AsyncScimConfigurationsPage[ScimConfiguration], scim_configuration, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_delete(self, async_client: AsyncGitpod) -> None:
+ scim_configuration = await async_client.organizations.scim_configurations.delete(
+ scim_configuration_id="d2c94c27-3b76-4a42-b88c-95a85e392c68",
+ )
+ assert_matches_type(object, scim_configuration, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_raw_response_delete(self, async_client: AsyncGitpod) -> None:
+ response = await async_client.organizations.scim_configurations.with_raw_response.delete(
+ scim_configuration_id="d2c94c27-3b76-4a42-b88c-95a85e392c68",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ scim_configuration = await response.parse()
+ assert_matches_type(object, scim_configuration, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_streaming_response_delete(self, async_client: AsyncGitpod) -> None:
+ async with async_client.organizations.scim_configurations.with_streaming_response.delete(
+ scim_configuration_id="d2c94c27-3b76-4a42-b88c-95a85e392c68",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ scim_configuration = await response.parse()
+ assert_matches_type(object, scim_configuration, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_regenerate_token(self, async_client: AsyncGitpod) -> None:
+ scim_configuration = await async_client.organizations.scim_configurations.regenerate_token(
+ scim_configuration_id="d2c94c27-3b76-4a42-b88c-95a85e392c68",
+ )
+ assert_matches_type(ScimConfigurationRegenerateTokenResponse, scim_configuration, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_raw_response_regenerate_token(self, async_client: AsyncGitpod) -> None:
+ response = await async_client.organizations.scim_configurations.with_raw_response.regenerate_token(
+ scim_configuration_id="d2c94c27-3b76-4a42-b88c-95a85e392c68",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ scim_configuration = await response.parse()
+ assert_matches_type(ScimConfigurationRegenerateTokenResponse, scim_configuration, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_streaming_response_regenerate_token(self, async_client: AsyncGitpod) -> None:
+ async with async_client.organizations.scim_configurations.with_streaming_response.regenerate_token(
+ scim_configuration_id="d2c94c27-3b76-4a42-b88c-95a85e392c68",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ scim_configuration = await response.parse()
+ assert_matches_type(ScimConfigurationRegenerateTokenResponse, scim_configuration, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
From 87180158231c2ddc56bf7202be6c9dbc4b2ec3e2 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Mon, 19 Jan 2026 08:02:26 +0000
Subject: [PATCH 18/27] codegen metadata
---
.stats.yml | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/.stats.yml b/.stats.yml
index c7d8a2f..c836904 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 167
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-40c6617e0b944168058135c9325d556b21c2edde19518090aefa542c76afcdb3.yml
-openapi_spec_hash: 235404d99aa56e51b933261d195dc206
-config_hash: cec4ffca97dd72023c573623499bc35b
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-041f3ba8dd0f5670e5fe37a61d725bd162d53c10c768bd3aa9b95ddc6d43926a.yml
+openapi_spec_hash: 770ce1f0289034006cbe5279535dbbf3
+config_hash: 21bab2a4731f1e55c0a2c62588576282
From 9cd272f98f2215b834a841ca34c52ce04fd2898e Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Mon, 19 Jan 2026 11:34:35 +0000
Subject: [PATCH 19/27] feat(automations): add before_snapshot trigger type
---
.stats.yml | 4 ++--
src/gitpod/types/runner_capability.py | 1 +
src/gitpod/types/shared/automation_trigger.py | 6 +++++-
src/gitpod/types/shared_params/automation_trigger.py | 6 +++++-
.../api_resources/environments/automations/test_services.py | 4 ++++
tests/api_resources/environments/automations/test_tasks.py | 4 ++++
tests/api_resources/test_environments.py | 4 ++++
7 files changed, 25 insertions(+), 4 deletions(-)
diff --git a/.stats.yml b/.stats.yml
index c836904..0df29b8 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 167
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-041f3ba8dd0f5670e5fe37a61d725bd162d53c10c768bd3aa9b95ddc6d43926a.yml
-openapi_spec_hash: 770ce1f0289034006cbe5279535dbbf3
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-a7829781a00de0869ad8536dcd67bdbbf224a42f5f3f922065a44e73b0534bbf.yml
+openapi_spec_hash: 59381e16e5de8d6de09f92abc0433e02
config_hash: 21bab2a4731f1e55c0a2c62588576282
diff --git a/src/gitpod/types/runner_capability.py b/src/gitpod/types/runner_capability.py
index b63ac78..36bb1f9 100644
--- a/src/gitpod/types/runner_capability.py
+++ b/src/gitpod/types/runner_capability.py
@@ -12,4 +12,5 @@
"RUNNER_CAPABILITY_ALLOW_ENV_TOKEN_POPULATION",
"RUNNER_CAPABILITY_DEFAULT_DEV_CONTAINER_IMAGE",
"RUNNER_CAPABILITY_ENVIRONMENT_SNAPSHOT",
+ "RUNNER_CAPABILITY_PREBUILDS_BEFORE_SNAPSHOT_TRIGGER",
]
diff --git a/src/gitpod/types/shared/automation_trigger.py b/src/gitpod/types/shared/automation_trigger.py
index c21e923..8ffd732 100644
--- a/src/gitpod/types/shared/automation_trigger.py
+++ b/src/gitpod/types/shared/automation_trigger.py
@@ -18,9 +18,13 @@ class AutomationTrigger(BaseModel):
The `post_environment_start` field indicates that the automation should be triggered after the environment has started (devcontainer ready).
The `post_devcontainer_start` field indicates that the automation should be triggered after the dev container has started.
The `prebuild` field starts the automation during a prebuild of an environment. This phase does not have user secrets available.
- Note: The prebuild trigger can only be used with tasks, not services.
+ The `before_snapshot` field triggers the automation after all prebuild tasks complete but before the snapshot is taken.
+ This is used for tasks that need to run last during prebuilds, such as IDE warmup.
+ Note: The prebuild and before_snapshot triggers can only be used with tasks, not services.
"""
+ before_snapshot: Optional[bool] = FieldInfo(alias="beforeSnapshot", default=None)
+
manual: Optional[bool] = None
post_devcontainer_start: Optional[bool] = FieldInfo(alias="postDevcontainerStart", default=None)
diff --git a/src/gitpod/types/shared_params/automation_trigger.py b/src/gitpod/types/shared_params/automation_trigger.py
index 0c840fe..27dc462 100644
--- a/src/gitpod/types/shared_params/automation_trigger.py
+++ b/src/gitpod/types/shared_params/automation_trigger.py
@@ -18,9 +18,13 @@ class AutomationTrigger(TypedDict, total=False):
The `post_environment_start` field indicates that the automation should be triggered after the environment has started (devcontainer ready).
The `post_devcontainer_start` field indicates that the automation should be triggered after the dev container has started.
The `prebuild` field starts the automation during a prebuild of an environment. This phase does not have user secrets available.
- Note: The prebuild trigger can only be used with tasks, not services.
+ The `before_snapshot` field triggers the automation after all prebuild tasks complete but before the snapshot is taken.
+ This is used for tasks that need to run last during prebuilds, such as IDE warmup.
+ Note: The prebuild and before_snapshot triggers can only be used with tasks, not services.
"""
+ before_snapshot: Annotated[bool, PropertyInfo(alias="beforeSnapshot")]
+
manual: bool
post_devcontainer_start: Annotated[bool, PropertyInfo(alias="postDevcontainerStart")]
diff --git a/tests/api_resources/environments/automations/test_services.py b/tests/api_resources/environments/automations/test_services.py
index 650c04b..c0db2dc 100644
--- a/tests/api_resources/environments/automations/test_services.py
+++ b/tests/api_resources/environments/automations/test_services.py
@@ -46,6 +46,7 @@ def test_method_create_with_all_params(self, client: Gitpod) -> None:
"role": "SERVICE_ROLE_UNSPECIFIED",
"triggered_by": [
{
+ "before_snapshot": True,
"manual": True,
"post_devcontainer_start": True,
"post_environment_start": True,
@@ -157,6 +158,7 @@ def test_method_update_with_all_params(self, client: Gitpod) -> None:
"triggered_by": {
"trigger": [
{
+ "before_snapshot": True,
"manual": True,
"post_devcontainer_start": True,
"post_environment_start": True,
@@ -404,6 +406,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncGitpod) ->
"role": "SERVICE_ROLE_UNSPECIFIED",
"triggered_by": [
{
+ "before_snapshot": True,
"manual": True,
"post_devcontainer_start": True,
"post_environment_start": True,
@@ -515,6 +518,7 @@ async def test_method_update_with_all_params(self, async_client: AsyncGitpod) ->
"triggered_by": {
"trigger": [
{
+ "before_snapshot": True,
"manual": True,
"post_devcontainer_start": True,
"post_environment_start": True,
diff --git a/tests/api_resources/environments/automations/test_tasks.py b/tests/api_resources/environments/automations/test_tasks.py
index 057d1a1..289d4f4 100644
--- a/tests/api_resources/environments/automations/test_tasks.py
+++ b/tests/api_resources/environments/automations/test_tasks.py
@@ -47,6 +47,7 @@ def test_method_create_with_all_params(self, client: Gitpod) -> None:
"reference": "build",
"triggered_by": [
{
+ "before_snapshot": True,
"manual": True,
"post_devcontainer_start": True,
"post_environment_start": True,
@@ -151,6 +152,7 @@ def test_method_update_with_all_params(self, client: Gitpod) -> None:
"triggered_by": {
"trigger": [
{
+ "before_snapshot": True,
"manual": True,
"post_devcontainer_start": True,
"post_environment_start": True,
@@ -349,6 +351,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncGitpod) ->
"reference": "build",
"triggered_by": [
{
+ "before_snapshot": True,
"manual": True,
"post_devcontainer_start": True,
"post_environment_start": True,
@@ -453,6 +456,7 @@ async def test_method_update_with_all_params(self, async_client: AsyncGitpod) ->
"triggered_by": {
"trigger": [
{
+ "before_snapshot": True,
"manual": True,
"post_devcontainer_start": True,
"post_environment_start": True,
diff --git a/tests/api_resources/test_environments.py b/tests/api_resources/test_environments.py
index 127cc4b..b2a37f6 100644
--- a/tests/api_resources/test_environments.py
+++ b/tests/api_resources/test_environments.py
@@ -43,6 +43,7 @@ def test_method_create_with_all_params(self, client: Gitpod) -> None:
"session": "session",
"trigger_filter": [
{
+ "before_snapshot": True,
"manual": True,
"post_devcontainer_start": True,
"post_environment_start": True,
@@ -394,6 +395,7 @@ def test_method_create_from_project_with_all_params(self, client: Gitpod) -> Non
"session": "session",
"trigger_filter": [
{
+ "before_snapshot": True,
"manual": True,
"post_devcontainer_start": True,
"post_environment_start": True,
@@ -697,6 +699,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncGitpod) ->
"session": "session",
"trigger_filter": [
{
+ "before_snapshot": True,
"manual": True,
"post_devcontainer_start": True,
"post_environment_start": True,
@@ -1048,6 +1051,7 @@ async def test_method_create_from_project_with_all_params(self, async_client: As
"session": "session",
"trigger_filter": [
{
+ "before_snapshot": True,
"manual": True,
"post_devcontainer_start": True,
"post_environment_start": True,
From 78c0bddc838e217007729d723283f9e9cd04d9a2 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Tue, 20 Jan 2026 03:19:40 +0000
Subject: [PATCH 20/27] feat: [backend] Adding direct_share field to groups
---
.stats.yml | 4 ++--
src/gitpod/types/group.py | 6 ++++++
2 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/.stats.yml b/.stats.yml
index 0df29b8..52fe54a 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 167
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-a7829781a00de0869ad8536dcd67bdbbf224a42f5f3f922065a44e73b0534bbf.yml
-openapi_spec_hash: 59381e16e5de8d6de09f92abc0433e02
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-dfd13e2785a9e0e662f79aab0c03d45144d803fedd87510ec27791b79ede6162.yml
+openapi_spec_hash: 8dcab0c2c65f9eb778e9b2cf3c44bf5c
config_hash: 21bab2a4731f1e55c0a2c62588576282
diff --git a/src/gitpod/types/group.py b/src/gitpod/types/group.py
index ac727d0..1b70f57 100644
--- a/src/gitpod/types/group.py
+++ b/src/gitpod/types/group.py
@@ -107,6 +107,12 @@ class Group(BaseModel):
description: Optional[str] = None
+ direct_share: Optional[bool] = FieldInfo(alias="directShare", default=None)
+ """
+ direct_share indicates that this group is used for direct user sharing on
+ resources. These groups are hidden from regular group listings.
+ """
+
member_count: Optional[int] = FieldInfo(alias="memberCount", default=None)
"""member_count is the total number of members in this group"""
From df1cf39a9c1b387c9e9313bfec68a97759762e0b Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Tue, 20 Jan 2026 05:13:42 +0000
Subject: [PATCH 21/27] feat: [api] Introduce RPCs to share resources with
individual users
---
.stats.yml | 8 +-
api.md | 10 +-
src/gitpod/resources/groups/__init__.py | 14 +
src/gitpod/resources/groups/groups.py | 32 ++
.../resources/groups/role_assignments.py | 9 +-
src/gitpod/resources/groups/shares.py | 441 ++++++++++++++++++
src/gitpod/types/__init__.py | 1 +
src/gitpod/types/groups/__init__.py | 3 +-
src/gitpod/types/groups/role_assignment.py | 2 +-
.../groups/role_assignment_create_params.py | 2 +-
.../groups/role_assignment_list_params.py | 2 +-
.../types/groups/share_create_params.py | 29 ++
.../types/groups/share_delete_params.py | 25 +
src/gitpod/types/shared/__init__.py | 1 +
.../types/{groups => shared}/resource_role.py | 0
src/gitpod/types/shared_params/__init__.py | 1 +
.../types/shared_params/resource_role.py | 61 +++
tests/api_resources/groups/test_shares.py | 181 +++++++
18 files changed, 806 insertions(+), 16 deletions(-)
create mode 100644 src/gitpod/resources/groups/shares.py
create mode 100644 src/gitpod/types/groups/share_create_params.py
create mode 100644 src/gitpod/types/groups/share_delete_params.py
rename src/gitpod/types/{groups => shared}/resource_role.py (100%)
create mode 100644 src/gitpod/types/shared_params/resource_role.py
create mode 100644 tests/api_resources/groups/test_shares.py
diff --git a/.stats.yml b/.stats.yml
index 52fe54a..896d8f2 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
-configured_endpoints: 167
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-dfd13e2785a9e0e662f79aab0c03d45144d803fedd87510ec27791b79ede6162.yml
-openapi_spec_hash: 8dcab0c2c65f9eb778e9b2cf3c44bf5c
-config_hash: 21bab2a4731f1e55c0a2c62588576282
+configured_endpoints: 169
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-6b80aebab53bff73bb7b87c5f91f98c6dd5db2d623b6c613aaa5e61252b74d75.yml
+openapi_spec_hash: 9636e315ac739c1ab9cba65a7ead6559
+config_hash: 73893621fd64bbd87b86671decf334e6
diff --git a/api.md b/api.md
index 8c0b90a..796ab4b 100644
--- a/api.md
+++ b/api.md
@@ -13,6 +13,7 @@ from gitpod.types import (
OrganizationTier,
Principal,
ProjectEnvironmentClass,
+ ResourceRole,
ResourceType,
RunsOn,
SecretRef,
@@ -302,7 +303,7 @@ Methods:
Types:
```python
-from gitpod.types.groups import ResourceRole, RoleAssignment, RoleAssignmentCreateResponse
+from gitpod.types.groups import RoleAssignment, RoleAssignmentCreateResponse
```
Methods:
@@ -311,6 +312,13 @@ Methods:
- client.groups.role_assignments.list(\*\*params) -> SyncAssignmentsPage[RoleAssignment]
- client.groups.role_assignments.delete(\*\*params) -> object
+## Shares
+
+Methods:
+
+- client.groups.shares.create(\*\*params) -> object
+- client.groups.shares.delete(\*\*params) -> object
+
# Identity
Types:
diff --git a/src/gitpod/resources/groups/__init__.py b/src/gitpod/resources/groups/__init__.py
index 83c3111..363f4ea 100644
--- a/src/gitpod/resources/groups/__init__.py
+++ b/src/gitpod/resources/groups/__init__.py
@@ -8,6 +8,14 @@
GroupsResourceWithStreamingResponse,
AsyncGroupsResourceWithStreamingResponse,
)
+from .shares import (
+ SharesResource,
+ AsyncSharesResource,
+ SharesResourceWithRawResponse,
+ AsyncSharesResourceWithRawResponse,
+ SharesResourceWithStreamingResponse,
+ AsyncSharesResourceWithStreamingResponse,
+)
from .memberships import (
MembershipsResource,
AsyncMembershipsResource,
@@ -38,6 +46,12 @@
"AsyncRoleAssignmentsResourceWithRawResponse",
"RoleAssignmentsResourceWithStreamingResponse",
"AsyncRoleAssignmentsResourceWithStreamingResponse",
+ "SharesResource",
+ "AsyncSharesResource",
+ "SharesResourceWithRawResponse",
+ "AsyncSharesResourceWithRawResponse",
+ "SharesResourceWithStreamingResponse",
+ "AsyncSharesResourceWithStreamingResponse",
"GroupsResource",
"AsyncGroupsResource",
"GroupsResourceWithRawResponse",
diff --git a/src/gitpod/resources/groups/groups.py b/src/gitpod/resources/groups/groups.py
index 4a57994..bebd369 100644
--- a/src/gitpod/resources/groups/groups.py
+++ b/src/gitpod/resources/groups/groups.py
@@ -4,6 +4,14 @@
import httpx
+from .shares import (
+ SharesResource,
+ AsyncSharesResource,
+ SharesResourceWithRawResponse,
+ AsyncSharesResourceWithRawResponse,
+ SharesResourceWithStreamingResponse,
+ AsyncSharesResourceWithStreamingResponse,
+)
from ...types import (
group_list_params,
group_create_params,
@@ -56,6 +64,10 @@ def memberships(self) -> MembershipsResource:
def role_assignments(self) -> RoleAssignmentsResource:
return RoleAssignmentsResource(self._client)
+ @cached_property
+ def shares(self) -> SharesResource:
+ return SharesResource(self._client)
+
@cached_property
def with_raw_response(self) -> GroupsResourceWithRawResponse:
"""
@@ -396,6 +408,10 @@ def memberships(self) -> AsyncMembershipsResource:
def role_assignments(self) -> AsyncRoleAssignmentsResource:
return AsyncRoleAssignmentsResource(self._client)
+ @cached_property
+ def shares(self) -> AsyncSharesResource:
+ return AsyncSharesResource(self._client)
+
@cached_property
def with_raw_response(self) -> AsyncGroupsResourceWithRawResponse:
"""
@@ -755,6 +771,10 @@ def memberships(self) -> MembershipsResourceWithRawResponse:
def role_assignments(self) -> RoleAssignmentsResourceWithRawResponse:
return RoleAssignmentsResourceWithRawResponse(self._groups.role_assignments)
+ @cached_property
+ def shares(self) -> SharesResourceWithRawResponse:
+ return SharesResourceWithRawResponse(self._groups.shares)
+
class AsyncGroupsResourceWithRawResponse:
def __init__(self, groups: AsyncGroupsResource) -> None:
@@ -784,6 +804,10 @@ def memberships(self) -> AsyncMembershipsResourceWithRawResponse:
def role_assignments(self) -> AsyncRoleAssignmentsResourceWithRawResponse:
return AsyncRoleAssignmentsResourceWithRawResponse(self._groups.role_assignments)
+ @cached_property
+ def shares(self) -> AsyncSharesResourceWithRawResponse:
+ return AsyncSharesResourceWithRawResponse(self._groups.shares)
+
class GroupsResourceWithStreamingResponse:
def __init__(self, groups: GroupsResource) -> None:
@@ -813,6 +837,10 @@ def memberships(self) -> MembershipsResourceWithStreamingResponse:
def role_assignments(self) -> RoleAssignmentsResourceWithStreamingResponse:
return RoleAssignmentsResourceWithStreamingResponse(self._groups.role_assignments)
+ @cached_property
+ def shares(self) -> SharesResourceWithStreamingResponse:
+ return SharesResourceWithStreamingResponse(self._groups.shares)
+
class AsyncGroupsResourceWithStreamingResponse:
def __init__(self, groups: AsyncGroupsResource) -> None:
@@ -841,3 +869,7 @@ def memberships(self) -> AsyncMembershipsResourceWithStreamingResponse:
@cached_property
def role_assignments(self) -> AsyncRoleAssignmentsResourceWithStreamingResponse:
return AsyncRoleAssignmentsResourceWithStreamingResponse(self._groups.role_assignments)
+
+ @cached_property
+ def shares(self) -> AsyncSharesResourceWithStreamingResponse:
+ return AsyncSharesResourceWithStreamingResponse(self._groups.shares)
diff --git a/src/gitpod/resources/groups/role_assignments.py b/src/gitpod/resources/groups/role_assignments.py
index 754dad3..0dde1df 100644
--- a/src/gitpod/resources/groups/role_assignments.py
+++ b/src/gitpod/resources/groups/role_assignments.py
@@ -16,13 +16,8 @@
)
from ...pagination import SyncAssignmentsPage, AsyncAssignmentsPage
from ..._base_client import AsyncPaginator, make_request_options
-from ...types.groups import (
- ResourceRole,
- role_assignment_list_params,
- role_assignment_create_params,
- role_assignment_delete_params,
-)
-from ...types.groups.resource_role import ResourceRole
+from ...types.groups import role_assignment_list_params, role_assignment_create_params, role_assignment_delete_params
+from ...types.shared.resource_role import ResourceRole
from ...types.shared.resource_type import ResourceType
from ...types.groups.role_assignment import RoleAssignment
from ...types.groups.role_assignment_create_response import RoleAssignmentCreateResponse
diff --git a/src/gitpod/resources/groups/shares.py b/src/gitpod/resources/groups/shares.py
new file mode 100644
index 0000000..fc0c308
--- /dev/null
+++ b/src/gitpod/resources/groups/shares.py
@@ -0,0 +1,441 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import httpx
+
+from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
+from ..._utils import maybe_transform, async_maybe_transform
+from ..._compat import cached_property
+from ..._resource import SyncAPIResource, AsyncAPIResource
+from ..._response import (
+ to_raw_response_wrapper,
+ to_streamed_response_wrapper,
+ async_to_raw_response_wrapper,
+ async_to_streamed_response_wrapper,
+)
+from ..._base_client import make_request_options
+from ...types.groups import share_create_params, share_delete_params
+from ...types.shared.principal import Principal
+from ...types.shared.resource_role import ResourceRole
+from ...types.shared.resource_type import ResourceType
+
+__all__ = ["SharesResource", "AsyncSharesResource"]
+
+
+class SharesResource(SyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> SharesResourceWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers
+ """
+ return SharesResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> SharesResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response
+ """
+ return SharesResourceWithStreamingResponse(self)
+
+ def create(
+ self,
+ *,
+ principal: Principal | Omit = omit,
+ principal_id: str | Omit = omit,
+ resource_id: str | Omit = omit,
+ resource_type: ResourceType | Omit = omit,
+ role: ResourceRole | Omit = omit,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> object:
+ """
+ Shares a resource directly with a principal (user or service account).
+
+ Use this method to:
+
+ - Grant a user or service account direct access to a runner, project, or other
+ resource
+ - Share resources without creating and managing groups manually
+
+ ### Examples
+
+ - Share a runner with a user:
+
+ Grants admin access to a runner for a specific user.
+
+ ```yaml
+ resourceType: RESOURCE_TYPE_RUNNER
+ resourceId: "d2c94c27-3b76-4a42-b88c-95a85e392c68"
+ principal: PRINCIPAL_USER
+ principalId: "f53d2330-3795-4c5d-a1f3-453121af9c60"
+ role: RESOURCE_ROLE_RUNNER_ADMIN
+ ```
+
+ - Share a runner with a service account:
+
+ Grants user access to a runner for a service account.
+
+ ```yaml
+ resourceType: RESOURCE_TYPE_RUNNER
+ resourceId: "d2c94c27-3b76-4a42-b88c-95a85e392c68"
+ principal: PRINCIPAL_SERVICE_ACCOUNT
+ principalId: "a1b2c3d4-5678-90ab-cdef-1234567890ab"
+ role: RESOURCE_ROLE_RUNNER_USER
+ ```
+
+ ### Authorization
+
+ Requires admin role on the specific resource.
+
+ Args:
+ principal: Type of principal to share with (user or service account)
+
+ principal_id: ID of the principal (user or service account) to share with
+
+ resource_id: ID of the resource to share
+
+ resource_type: Type of resource to share (runner, project, etc.)
+
+ role: Role to grant the principal on the resource
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ return self._post(
+ "/gitpod.v1.GroupService/ShareResourceWithPrincipal",
+ body=maybe_transform(
+ {
+ "principal": principal,
+ "principal_id": principal_id,
+ "resource_id": resource_id,
+ "resource_type": resource_type,
+ "role": role,
+ },
+ share_create_params.ShareCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=object,
+ )
+
+ def delete(
+ self,
+ *,
+ principal: Principal | Omit = omit,
+ principal_id: str | Omit = omit,
+ resource_id: str | Omit = omit,
+ resource_type: ResourceType | Omit = omit,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> object:
+ """
+ Removes direct access for a principal (user or service account) from a resource.
+
+ Use this method to:
+
+ - Revoke a principal's direct access to a resource
+ - Remove sharing without affecting group-based access
+
+ ### Examples
+
+ - Remove user access from a runner:
+
+ Revokes a user's direct access to a runner.
+
+ ```yaml
+ resourceType: RESOURCE_TYPE_RUNNER
+ resourceId: "d2c94c27-3b76-4a42-b88c-95a85e392c68"
+ principal: PRINCIPAL_USER
+ principalId: "f53d2330-3795-4c5d-a1f3-453121af9c60"
+ ```
+
+ ### Authorization
+
+ Requires admin role on the specific resource.
+
+ Args:
+ principal: Type of principal to remove access from (user or service account)
+
+ principal_id: ID of the principal (user or service account) to remove access from
+
+ resource_id: ID of the resource to unshare
+
+ resource_type: Type of resource to unshare
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ return self._post(
+ "/gitpod.v1.GroupService/UnshareResourceWithPrincipal",
+ body=maybe_transform(
+ {
+ "principal": principal,
+ "principal_id": principal_id,
+ "resource_id": resource_id,
+ "resource_type": resource_type,
+ },
+ share_delete_params.ShareDeleteParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=object,
+ )
+
+
+class AsyncSharesResource(AsyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> AsyncSharesResourceWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers
+ """
+ return AsyncSharesResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncSharesResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response
+ """
+ return AsyncSharesResourceWithStreamingResponse(self)
+
+ async def create(
+ self,
+ *,
+ principal: Principal | Omit = omit,
+ principal_id: str | Omit = omit,
+ resource_id: str | Omit = omit,
+ resource_type: ResourceType | Omit = omit,
+ role: ResourceRole | Omit = omit,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> object:
+ """
+ Shares a resource directly with a principal (user or service account).
+
+ Use this method to:
+
+ - Grant a user or service account direct access to a runner, project, or other
+ resource
+ - Share resources without creating and managing groups manually
+
+ ### Examples
+
+ - Share a runner with a user:
+
+ Grants admin access to a runner for a specific user.
+
+ ```yaml
+ resourceType: RESOURCE_TYPE_RUNNER
+ resourceId: "d2c94c27-3b76-4a42-b88c-95a85e392c68"
+ principal: PRINCIPAL_USER
+ principalId: "f53d2330-3795-4c5d-a1f3-453121af9c60"
+ role: RESOURCE_ROLE_RUNNER_ADMIN
+ ```
+
+ - Share a runner with a service account:
+
+ Grants user access to a runner for a service account.
+
+ ```yaml
+ resourceType: RESOURCE_TYPE_RUNNER
+ resourceId: "d2c94c27-3b76-4a42-b88c-95a85e392c68"
+ principal: PRINCIPAL_SERVICE_ACCOUNT
+ principalId: "a1b2c3d4-5678-90ab-cdef-1234567890ab"
+ role: RESOURCE_ROLE_RUNNER_USER
+ ```
+
+ ### Authorization
+
+ Requires admin role on the specific resource.
+
+ Args:
+ principal: Type of principal to share with (user or service account)
+
+ principal_id: ID of the principal (user or service account) to share with
+
+ resource_id: ID of the resource to share
+
+ resource_type: Type of resource to share (runner, project, etc.)
+
+ role: Role to grant the principal on the resource
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ return await self._post(
+ "/gitpod.v1.GroupService/ShareResourceWithPrincipal",
+ body=await async_maybe_transform(
+ {
+ "principal": principal,
+ "principal_id": principal_id,
+ "resource_id": resource_id,
+ "resource_type": resource_type,
+ "role": role,
+ },
+ share_create_params.ShareCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=object,
+ )
+
+ async def delete(
+ self,
+ *,
+ principal: Principal | Omit = omit,
+ principal_id: str | Omit = omit,
+ resource_id: str | Omit = omit,
+ resource_type: ResourceType | Omit = omit,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> object:
+ """
+ Removes direct access for a principal (user or service account) from a resource.
+
+ Use this method to:
+
+ - Revoke a principal's direct access to a resource
+ - Remove sharing without affecting group-based access
+
+ ### Examples
+
+ - Remove user access from a runner:
+
+ Revokes a user's direct access to a runner.
+
+ ```yaml
+ resourceType: RESOURCE_TYPE_RUNNER
+ resourceId: "d2c94c27-3b76-4a42-b88c-95a85e392c68"
+ principal: PRINCIPAL_USER
+ principalId: "f53d2330-3795-4c5d-a1f3-453121af9c60"
+ ```
+
+ ### Authorization
+
+ Requires admin role on the specific resource.
+
+ Args:
+ principal: Type of principal to remove access from (user or service account)
+
+ principal_id: ID of the principal (user or service account) to remove access from
+
+ resource_id: ID of the resource to unshare
+
+ resource_type: Type of resource to unshare
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ return await self._post(
+ "/gitpod.v1.GroupService/UnshareResourceWithPrincipal",
+ body=await async_maybe_transform(
+ {
+ "principal": principal,
+ "principal_id": principal_id,
+ "resource_id": resource_id,
+ "resource_type": resource_type,
+ },
+ share_delete_params.ShareDeleteParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=object,
+ )
+
+
+class SharesResourceWithRawResponse:
+ def __init__(self, shares: SharesResource) -> None:
+ self._shares = shares
+
+ self.create = to_raw_response_wrapper(
+ shares.create,
+ )
+ self.delete = to_raw_response_wrapper(
+ shares.delete,
+ )
+
+
+class AsyncSharesResourceWithRawResponse:
+ def __init__(self, shares: AsyncSharesResource) -> None:
+ self._shares = shares
+
+ self.create = async_to_raw_response_wrapper(
+ shares.create,
+ )
+ self.delete = async_to_raw_response_wrapper(
+ shares.delete,
+ )
+
+
+class SharesResourceWithStreamingResponse:
+ def __init__(self, shares: SharesResource) -> None:
+ self._shares = shares
+
+ self.create = to_streamed_response_wrapper(
+ shares.create,
+ )
+ self.delete = to_streamed_response_wrapper(
+ shares.delete,
+ )
+
+
+class AsyncSharesResourceWithStreamingResponse:
+ def __init__(self, shares: AsyncSharesResource) -> None:
+ self._shares = shares
+
+ self.create = async_to_streamed_response_wrapper(
+ shares.create,
+ )
+ self.delete = async_to_streamed_response_wrapper(
+ shares.delete,
+ )
diff --git a/src/gitpod/types/__init__.py b/src/gitpod/types/__init__.py
index 7306513..41613c2 100644
--- a/src/gitpod/types/__init__.py
+++ b/src/gitpod/types/__init__.py
@@ -20,6 +20,7 @@
SecretRef as SecretRef,
FieldValue as FieldValue,
UserStatus as UserStatus,
+ ResourceRole as ResourceRole,
ResourceType as ResourceType,
TaskMetadata as TaskMetadata,
TaskExecution as TaskExecution,
diff --git a/src/gitpod/types/groups/__init__.py b/src/gitpod/types/groups/__init__.py
index abbe99f..384b0a7 100644
--- a/src/gitpod/types/groups/__init__.py
+++ b/src/gitpod/types/groups/__init__.py
@@ -2,9 +2,10 @@
from __future__ import annotations
-from .resource_role import ResourceRole as ResourceRole
from .role_assignment import RoleAssignment as RoleAssignment
from .group_membership import GroupMembership as GroupMembership
+from .share_create_params import ShareCreateParams as ShareCreateParams
+from .share_delete_params import ShareDeleteParams as ShareDeleteParams
from .membership_list_params import MembershipListParams as MembershipListParams
from .membership_create_params import MembershipCreateParams as MembershipCreateParams
from .membership_delete_params import MembershipDeleteParams as MembershipDeleteParams
diff --git a/src/gitpod/types/groups/role_assignment.py b/src/gitpod/types/groups/role_assignment.py
index 38e30ea..39512d0 100644
--- a/src/gitpod/types/groups/role_assignment.py
+++ b/src/gitpod/types/groups/role_assignment.py
@@ -5,7 +5,7 @@
from pydantic import Field as FieldInfo
from ..._models import BaseModel
-from .resource_role import ResourceRole
+from ..shared.resource_role import ResourceRole
from ..shared.resource_type import ResourceType
__all__ = ["RoleAssignment"]
diff --git a/src/gitpod/types/groups/role_assignment_create_params.py b/src/gitpod/types/groups/role_assignment_create_params.py
index d036e80..deee188 100644
--- a/src/gitpod/types/groups/role_assignment_create_params.py
+++ b/src/gitpod/types/groups/role_assignment_create_params.py
@@ -5,7 +5,7 @@
from typing_extensions import Annotated, TypedDict
from ..._utils import PropertyInfo
-from .resource_role import ResourceRole
+from ..shared.resource_role import ResourceRole
from ..shared.resource_type import ResourceType
__all__ = ["RoleAssignmentCreateParams"]
diff --git a/src/gitpod/types/groups/role_assignment_list_params.py b/src/gitpod/types/groups/role_assignment_list_params.py
index 23c236b..63b97bd 100644
--- a/src/gitpod/types/groups/role_assignment_list_params.py
+++ b/src/gitpod/types/groups/role_assignment_list_params.py
@@ -6,7 +6,7 @@
from typing_extensions import Annotated, TypedDict
from ..._utils import PropertyInfo
-from .resource_role import ResourceRole
+from ..shared.resource_role import ResourceRole
from ..shared.resource_type import ResourceType
__all__ = ["RoleAssignmentListParams", "Filter", "Pagination"]
diff --git a/src/gitpod/types/groups/share_create_params.py b/src/gitpod/types/groups/share_create_params.py
new file mode 100644
index 0000000..3aba19d
--- /dev/null
+++ b/src/gitpod/types/groups/share_create_params.py
@@ -0,0 +1,29 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Annotated, TypedDict
+
+from ..._utils import PropertyInfo
+from ..shared.principal import Principal
+from ..shared.resource_role import ResourceRole
+from ..shared.resource_type import ResourceType
+
+__all__ = ["ShareCreateParams"]
+
+
+class ShareCreateParams(TypedDict, total=False):
+ principal: Principal
+ """Type of principal to share with (user or service account)"""
+
+ principal_id: Annotated[str, PropertyInfo(alias="principalId")]
+ """ID of the principal (user or service account) to share with"""
+
+ resource_id: Annotated[str, PropertyInfo(alias="resourceId")]
+ """ID of the resource to share"""
+
+ resource_type: Annotated[ResourceType, PropertyInfo(alias="resourceType")]
+ """Type of resource to share (runner, project, etc.)"""
+
+ role: ResourceRole
+ """Role to grant the principal on the resource"""
diff --git a/src/gitpod/types/groups/share_delete_params.py b/src/gitpod/types/groups/share_delete_params.py
new file mode 100644
index 0000000..e855a21
--- /dev/null
+++ b/src/gitpod/types/groups/share_delete_params.py
@@ -0,0 +1,25 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Annotated, TypedDict
+
+from ..._utils import PropertyInfo
+from ..shared.principal import Principal
+from ..shared.resource_type import ResourceType
+
+__all__ = ["ShareDeleteParams"]
+
+
+class ShareDeleteParams(TypedDict, total=False):
+ principal: Principal
+ """Type of principal to remove access from (user or service account)"""
+
+ principal_id: Annotated[str, PropertyInfo(alias="principalId")]
+ """ID of the principal (user or service account) to remove access from"""
+
+ resource_id: Annotated[str, PropertyInfo(alias="resourceId")]
+ """ID of the resource to unshare"""
+
+ resource_type: Annotated[ResourceType, PropertyInfo(alias="resourceType")]
+ """Type of resource to unshare"""
diff --git a/src/gitpod/types/shared/__init__.py b/src/gitpod/types/shared/__init__.py
index de9766f..04e206d 100644
--- a/src/gitpod/types/shared/__init__.py
+++ b/src/gitpod/types/shared/__init__.py
@@ -11,6 +11,7 @@
from .secret_ref import SecretRef as SecretRef
from .field_value import FieldValue as FieldValue
from .user_status import UserStatus as UserStatus
+from .resource_role import ResourceRole as ResourceRole
from .resource_type import ResourceType as ResourceType
from .task_metadata import TaskMetadata as TaskMetadata
from .task_execution import TaskExecution as TaskExecution
diff --git a/src/gitpod/types/groups/resource_role.py b/src/gitpod/types/shared/resource_role.py
similarity index 100%
rename from src/gitpod/types/groups/resource_role.py
rename to src/gitpod/types/shared/resource_role.py
diff --git a/src/gitpod/types/shared_params/__init__.py b/src/gitpod/types/shared_params/__init__.py
index 093bf76..1d82ded 100644
--- a/src/gitpod/types/shared_params/__init__.py
+++ b/src/gitpod/types/shared_params/__init__.py
@@ -8,6 +8,7 @@
from .secret_ref import SecretRef as SecretRef
from .field_value import FieldValue as FieldValue
from .user_status import UserStatus as UserStatus
+from .resource_role import ResourceRole as ResourceRole
from .resource_type import ResourceType as ResourceType
from .task_metadata import TaskMetadata as TaskMetadata
from .environment_class import EnvironmentClass as EnvironmentClass
diff --git a/src/gitpod/types/shared_params/resource_role.py b/src/gitpod/types/shared_params/resource_role.py
new file mode 100644
index 0000000..053e954
--- /dev/null
+++ b/src/gitpod/types/shared_params/resource_role.py
@@ -0,0 +1,61 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal, TypeAlias
+
+__all__ = ["ResourceRole"]
+
+ResourceRole: TypeAlias = Literal[
+ "RESOURCE_ROLE_UNSPECIFIED",
+ "RESOURCE_ROLE_ORG_ADMIN",
+ "RESOURCE_ROLE_ORG_MEMBER",
+ "RESOURCE_ROLE_ORG_RUNNERS_ADMIN",
+ "RESOURCE_ROLE_GROUP_ADMIN",
+ "RESOURCE_ROLE_GROUP_VIEWER",
+ "RESOURCE_ROLE_USER_IDENTITY",
+ "RESOURCE_ROLE_USER_VIEWER",
+ "RESOURCE_ROLE_USER_ADMIN",
+ "RESOURCE_ROLE_ENVIRONMENT_IDENTITY",
+ "RESOURCE_ROLE_ENVIRONMENT_ADMIN",
+ "RESOURCE_ROLE_ENVIRONMENT_USER",
+ "RESOURCE_ROLE_ENVIRONMENT_VIEWER",
+ "RESOURCE_ROLE_ENVIRONMENT_RUNNER",
+ "RESOURCE_ROLE_RUNNER_IDENTITY",
+ "RESOURCE_ROLE_RUNNER_ADMIN",
+ "RESOURCE_ROLE_RUNNER_LOCAL_ADMIN",
+ "RESOURCE_ROLE_RUNNER_MANAGED_ADMIN",
+ "RESOURCE_ROLE_RUNNER_USER",
+ "RESOURCE_ROLE_RUNNER_CONFIGURATION_READER",
+ "RESOURCE_ROLE_HOST_AUTHENTICATION_TOKEN_ADMIN",
+ "RESOURCE_ROLE_HOST_AUTHENTICATION_TOKEN_UPDATER",
+ "RESOURCE_ROLE_PROJECT_ADMIN",
+ "RESOURCE_ROLE_PROJECT_USER",
+ "RESOURCE_ROLE_PROJECT_EDITOR",
+ "RESOURCE_ROLE_ENVIRONMENT_SERVICE_ADMIN",
+ "RESOURCE_ROLE_ENVIRONMENT_SERVICE_VIEWER",
+ "RESOURCE_ROLE_ENVIRONMENT_SERVICE_USER",
+ "RESOURCE_ROLE_ENVIRONMENT_SERVICE_ENV",
+ "RESOURCE_ROLE_ENVIRONMENT_TASK_ADMIN",
+ "RESOURCE_ROLE_ENVIRONMENT_TASK_VIEWER",
+ "RESOURCE_ROLE_ENVIRONMENT_TASK_USER",
+ "RESOURCE_ROLE_ENVIRONMENT_TASK_ENV",
+ "RESOURCE_ROLE_SERVICE_ACCOUNT_IDENTITY",
+ "RESOURCE_ROLE_SERVICE_ACCOUNT_ADMIN",
+ "RESOURCE_ROLE_AGENT_EXECUTION_IDENTITY",
+ "RESOURCE_ROLE_AGENT_EXECUTION_USER",
+ "RESOURCE_ROLE_AGENT_EXECUTION_ADMIN",
+ "RESOURCE_ROLE_AGENT_EXECUTION_RUNNER",
+ "RESOURCE_ROLE_AGENT_EXECUTION_OUTPUTS_REPORTER",
+ "RESOURCE_ROLE_AGENT_ADMIN",
+ "RESOURCE_ROLE_AGENT_VIEWER",
+ "RESOURCE_ROLE_AGENT_EXECUTOR",
+ "RESOURCE_ROLE_WORKFLOW_ADMIN",
+ "RESOURCE_ROLE_WORKFLOW_USER",
+ "RESOURCE_ROLE_WORKFLOW_VIEWER",
+ "RESOURCE_ROLE_WORKFLOW_EXECUTOR",
+ "RESOURCE_ROLE_SNAPSHOT_ADMIN",
+ "RESOURCE_ROLE_SNAPSHOT_RUNNER",
+ "RESOURCE_ROLE_WEBHOOK_ADMIN",
+ "RESOURCE_ROLE_WEBHOOK_VIEWER",
+]
diff --git a/tests/api_resources/groups/test_shares.py b/tests/api_resources/groups/test_shares.py
new file mode 100644
index 0000000..3e0c57f
--- /dev/null
+++ b/tests/api_resources/groups/test_shares.py
@@ -0,0 +1,181 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import os
+from typing import Any, cast
+
+import pytest
+
+from gitpod import Gitpod, AsyncGitpod
+from tests.utils import assert_matches_type
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestShares:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_create(self, client: Gitpod) -> None:
+ share = client.groups.shares.create()
+ assert_matches_type(object, share, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_create_with_all_params(self, client: Gitpod) -> None:
+ share = client.groups.shares.create(
+ principal="PRINCIPAL_SERVICE_ACCOUNT",
+ principal_id="a1b2c3d4-5678-90ab-cdef-1234567890ab",
+ resource_id="d2c94c27-3b76-4a42-b88c-95a85e392c68",
+ resource_type="RESOURCE_TYPE_RUNNER",
+ role="RESOURCE_ROLE_RUNNER_USER",
+ )
+ assert_matches_type(object, share, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_raw_response_create(self, client: Gitpod) -> None:
+ response = client.groups.shares.with_raw_response.create()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ share = response.parse()
+ assert_matches_type(object, share, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_streaming_response_create(self, client: Gitpod) -> None:
+ with client.groups.shares.with_streaming_response.create() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ share = response.parse()
+ assert_matches_type(object, share, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_delete(self, client: Gitpod) -> None:
+ share = client.groups.shares.delete()
+ assert_matches_type(object, share, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_delete_with_all_params(self, client: Gitpod) -> None:
+ share = client.groups.shares.delete(
+ principal="PRINCIPAL_USER",
+ principal_id="f53d2330-3795-4c5d-a1f3-453121af9c60",
+ resource_id="d2c94c27-3b76-4a42-b88c-95a85e392c68",
+ resource_type="RESOURCE_TYPE_RUNNER",
+ )
+ assert_matches_type(object, share, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_raw_response_delete(self, client: Gitpod) -> None:
+ response = client.groups.shares.with_raw_response.delete()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ share = response.parse()
+ assert_matches_type(object, share, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_streaming_response_delete(self, client: Gitpod) -> None:
+ with client.groups.shares.with_streaming_response.delete() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ share = response.parse()
+ assert_matches_type(object, share, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+
+class TestAsyncShares:
+ parametrize = pytest.mark.parametrize(
+ "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
+ )
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_create(self, async_client: AsyncGitpod) -> None:
+ share = await async_client.groups.shares.create()
+ assert_matches_type(object, share, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_create_with_all_params(self, async_client: AsyncGitpod) -> None:
+ share = await async_client.groups.shares.create(
+ principal="PRINCIPAL_SERVICE_ACCOUNT",
+ principal_id="a1b2c3d4-5678-90ab-cdef-1234567890ab",
+ resource_id="d2c94c27-3b76-4a42-b88c-95a85e392c68",
+ resource_type="RESOURCE_TYPE_RUNNER",
+ role="RESOURCE_ROLE_RUNNER_USER",
+ )
+ assert_matches_type(object, share, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_raw_response_create(self, async_client: AsyncGitpod) -> None:
+ response = await async_client.groups.shares.with_raw_response.create()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ share = await response.parse()
+ assert_matches_type(object, share, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_streaming_response_create(self, async_client: AsyncGitpod) -> None:
+ async with async_client.groups.shares.with_streaming_response.create() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ share = await response.parse()
+ assert_matches_type(object, share, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_delete(self, async_client: AsyncGitpod) -> None:
+ share = await async_client.groups.shares.delete()
+ assert_matches_type(object, share, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_delete_with_all_params(self, async_client: AsyncGitpod) -> None:
+ share = await async_client.groups.shares.delete(
+ principal="PRINCIPAL_USER",
+ principal_id="f53d2330-3795-4c5d-a1f3-453121af9c60",
+ resource_id="d2c94c27-3b76-4a42-b88c-95a85e392c68",
+ resource_type="RESOURCE_TYPE_RUNNER",
+ )
+ assert_matches_type(object, share, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_raw_response_delete(self, async_client: AsyncGitpod) -> None:
+ response = await async_client.groups.shares.with_raw_response.delete()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ share = await response.parse()
+ assert_matches_type(object, share, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_streaming_response_delete(self, async_client: AsyncGitpod) -> None:
+ async with async_client.groups.shares.with_streaming_response.delete() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ share = await response.parse()
+ assert_matches_type(object, share, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
From b34ed1b8ecd39343ed02c5f376e9495775912140 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Tue, 20 Jan 2026 08:59:29 +0000
Subject: [PATCH 22/27] feat(api): add CheckRepositoryAccess API for repository
access validation
---
.stats.yml | 8 +-
api.md | 2 +
src/gitpod/resources/runners/runners.py | 142 ++++++++++++++++++
src/gitpod/types/__init__.py | 6 +
.../runner_check_repository_access_params.py | 19 +++
...runner_check_repository_access_response.py | 20 +++
tests/api_resources/test_runners.py | 75 +++++++++
7 files changed, 268 insertions(+), 4 deletions(-)
create mode 100644 src/gitpod/types/runner_check_repository_access_params.py
create mode 100644 src/gitpod/types/runner_check_repository_access_response.py
diff --git a/.stats.yml b/.stats.yml
index 896d8f2..d450123 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
-configured_endpoints: 169
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-6b80aebab53bff73bb7b87c5f91f98c6dd5db2d623b6c613aaa5e61252b74d75.yml
-openapi_spec_hash: 9636e315ac739c1ab9cba65a7ead6559
-config_hash: 73893621fd64bbd87b86671decf334e6
+configured_endpoints: 170
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-024993504dfc744ff138b0d1b1a151e28129f9f5a8b55adff4c7b559b0556c62.yml
+openapi_spec_hash: 4773277eb2a6ac6be0b2e8f89a2201d8
+config_hash: 942ffc968ca0131e192c1a7ac5dd8990
diff --git a/api.md b/api.md
index 796ab4b..0b70b7b 100644
--- a/api.md
+++ b/api.md
@@ -597,6 +597,7 @@ from gitpod.types import (
RunnerCreateResponse,
RunnerRetrieveResponse,
RunnerCheckAuthenticationForHostResponse,
+ RunnerCheckRepositoryAccessResponse,
RunnerCreateLogsTokenResponse,
RunnerCreateRunnerTokenResponse,
RunnerListScmOrganizationsResponse,
@@ -613,6 +614,7 @@ Methods:
- client.runners.list(\*\*params) -> SyncRunnersPage[Runner]
- client.runners.delete(\*\*params) -> object
- client.runners.check_authentication_for_host(\*\*params) -> RunnerCheckAuthenticationForHostResponse
+- client.runners.check_repository_access(\*\*params) -> RunnerCheckRepositoryAccessResponse
- client.runners.create_logs_token(\*\*params) -> RunnerCreateLogsTokenResponse
- client.runners.create_runner_token(\*\*params) -> RunnerCreateRunnerTokenResponse
- client.runners.list_scm_organizations(\*\*params) -> RunnerListScmOrganizationsResponse
diff --git a/src/gitpod/resources/runners/runners.py b/src/gitpod/resources/runners/runners.py
index 0ba69c1..5a0ee2e 100644
--- a/src/gitpod/resources/runners/runners.py
+++ b/src/gitpod/resources/runners/runners.py
@@ -20,6 +20,7 @@
runner_create_runner_token_params,
runner_search_repositories_params,
runner_list_scm_organizations_params,
+ runner_check_repository_access_params,
runner_check_authentication_for_host_params,
)
from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
@@ -62,6 +63,7 @@
from ...types.runner_create_runner_token_response import RunnerCreateRunnerTokenResponse
from ...types.runner_search_repositories_response import RunnerSearchRepositoriesResponse
from ...types.runner_list_scm_organizations_response import RunnerListScmOrganizationsResponse
+from ...types.runner_check_repository_access_response import RunnerCheckRepositoryAccessResponse
from ...types.runner_check_authentication_for_host_response import RunnerCheckAuthenticationForHostResponse
__all__ = ["RunnersResource", "AsyncRunnersResource"]
@@ -510,6 +512,70 @@ def check_authentication_for_host(
cast_to=RunnerCheckAuthenticationForHostResponse,
)
+ def check_repository_access(
+ self,
+ *,
+ repository_url: str | Omit = omit,
+ runner_id: str | Omit = omit,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> RunnerCheckRepositoryAccessResponse:
+ """
+ Checks if a principal has read access to a repository.
+
+ Use this method to:
+
+ - Validate repository access before workflow execution
+ - Verify executor credentials for automation bindings
+
+ Returns:
+
+ - has_access: true if the principal can read the repository
+ - FAILED_PRECONDITION if authentication is required
+ - INVALID_ARGUMENT if the repository URL is invalid
+
+ ### Examples
+
+ - Check access:
+
+ Verifies read access to a repository.
+
+ ```yaml
+ runnerId: "d2c94c27-3b76-4a42-b88c-95a85e392c68"
+ repositoryUrl: "https://github.com/org/repo"
+ ```
+
+ Args:
+ repository_url: repository_url is the URL of the repository to check access for. Can be a clone
+ URL (https://github.com/org/repo.git) or web URL (https://github.com/org/repo).
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ return self._post(
+ "/gitpod.v1.RunnerService/CheckRepositoryAccess",
+ body=maybe_transform(
+ {
+ "repository_url": repository_url,
+ "runner_id": runner_id,
+ },
+ runner_check_repository_access_params.RunnerCheckRepositoryAccessParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=RunnerCheckRepositoryAccessResponse,
+ )
+
def create_logs_token(
self,
*,
@@ -1273,6 +1339,70 @@ async def check_authentication_for_host(
cast_to=RunnerCheckAuthenticationForHostResponse,
)
+ async def check_repository_access(
+ self,
+ *,
+ repository_url: str | Omit = omit,
+ runner_id: str | Omit = omit,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> RunnerCheckRepositoryAccessResponse:
+ """
+ Checks if a principal has read access to a repository.
+
+ Use this method to:
+
+ - Validate repository access before workflow execution
+ - Verify executor credentials for automation bindings
+
+ Returns:
+
+ - has_access: true if the principal can read the repository
+ - FAILED_PRECONDITION if authentication is required
+ - INVALID_ARGUMENT if the repository URL is invalid
+
+ ### Examples
+
+ - Check access:
+
+ Verifies read access to a repository.
+
+ ```yaml
+ runnerId: "d2c94c27-3b76-4a42-b88c-95a85e392c68"
+ repositoryUrl: "https://github.com/org/repo"
+ ```
+
+ Args:
+ repository_url: repository_url is the URL of the repository to check access for. Can be a clone
+ URL (https://github.com/org/repo.git) or web URL (https://github.com/org/repo).
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ return await self._post(
+ "/gitpod.v1.RunnerService/CheckRepositoryAccess",
+ body=await async_maybe_transform(
+ {
+ "repository_url": repository_url,
+ "runner_id": runner_id,
+ },
+ runner_check_repository_access_params.RunnerCheckRepositoryAccessParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=RunnerCheckRepositoryAccessResponse,
+ )
+
async def create_logs_token(
self,
*,
@@ -1617,6 +1747,9 @@ def __init__(self, runners: RunnersResource) -> None:
self.check_authentication_for_host = to_raw_response_wrapper(
runners.check_authentication_for_host,
)
+ self.check_repository_access = to_raw_response_wrapper(
+ runners.check_repository_access,
+ )
self.create_logs_token = to_raw_response_wrapper(
runners.create_logs_token,
)
@@ -1664,6 +1797,9 @@ def __init__(self, runners: AsyncRunnersResource) -> None:
self.check_authentication_for_host = async_to_raw_response_wrapper(
runners.check_authentication_for_host,
)
+ self.check_repository_access = async_to_raw_response_wrapper(
+ runners.check_repository_access,
+ )
self.create_logs_token = async_to_raw_response_wrapper(
runners.create_logs_token,
)
@@ -1711,6 +1847,9 @@ def __init__(self, runners: RunnersResource) -> None:
self.check_authentication_for_host = to_streamed_response_wrapper(
runners.check_authentication_for_host,
)
+ self.check_repository_access = to_streamed_response_wrapper(
+ runners.check_repository_access,
+ )
self.create_logs_token = to_streamed_response_wrapper(
runners.create_logs_token,
)
@@ -1758,6 +1897,9 @@ def __init__(self, runners: AsyncRunnersResource) -> None:
self.check_authentication_for_host = async_to_streamed_response_wrapper(
runners.check_authentication_for_host,
)
+ self.check_repository_access = async_to_streamed_response_wrapper(
+ runners.check_repository_access,
+ )
self.create_logs_token = async_to_streamed_response_wrapper(
runners.create_logs_token,
)
diff --git a/src/gitpod/types/__init__.py b/src/gitpod/types/__init__.py
index 41613c2..4b195c7 100644
--- a/src/gitpod/types/__init__.py
+++ b/src/gitpod/types/__init__.py
@@ -224,6 +224,9 @@
from .project_prebuild_configuration_param import ProjectPrebuildConfigurationParam as ProjectPrebuildConfigurationParam
from .runner_list_scm_organizations_params import RunnerListScmOrganizationsParams as RunnerListScmOrganizationsParams
from .user_get_authenticated_user_response import UserGetAuthenticatedUserResponse as UserGetAuthenticatedUserResponse
+from .runner_check_repository_access_params import (
+ RunnerCheckRepositoryAccessParams as RunnerCheckRepositoryAccessParams,
+)
from .environment_create_from_project_params import (
EnvironmentCreateFromProjectParams as EnvironmentCreateFromProjectParams,
)
@@ -236,6 +239,9 @@
from .runner_list_scm_organizations_response import (
RunnerListScmOrganizationsResponse as RunnerListScmOrganizationsResponse,
)
+from .runner_check_repository_access_response import (
+ RunnerCheckRepositoryAccessResponse as RunnerCheckRepositoryAccessResponse,
+)
from .environment_create_from_project_response import (
EnvironmentCreateFromProjectResponse as EnvironmentCreateFromProjectResponse,
)
diff --git a/src/gitpod/types/runner_check_repository_access_params.py b/src/gitpod/types/runner_check_repository_access_params.py
new file mode 100644
index 0000000..d118429
--- /dev/null
+++ b/src/gitpod/types/runner_check_repository_access_params.py
@@ -0,0 +1,19 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Annotated, TypedDict
+
+from .._utils import PropertyInfo
+
+__all__ = ["RunnerCheckRepositoryAccessParams"]
+
+
+class RunnerCheckRepositoryAccessParams(TypedDict, total=False):
+ repository_url: Annotated[str, PropertyInfo(alias="repositoryUrl")]
+ """
+ repository_url is the URL of the repository to check access for. Can be a clone
+ URL (https://github.com/org/repo.git) or web URL (https://github.com/org/repo).
+ """
+
+ runner_id: Annotated[str, PropertyInfo(alias="runnerId")]
diff --git a/src/gitpod/types/runner_check_repository_access_response.py b/src/gitpod/types/runner_check_repository_access_response.py
new file mode 100644
index 0000000..11b7536
--- /dev/null
+++ b/src/gitpod/types/runner_check_repository_access_response.py
@@ -0,0 +1,20 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Optional
+
+from pydantic import Field as FieldInfo
+
+from .._models import BaseModel
+
+__all__ = ["RunnerCheckRepositoryAccessResponse"]
+
+
+class RunnerCheckRepositoryAccessResponse(BaseModel):
+ error_message: Optional[str] = FieldInfo(alias="errorMessage", default=None)
+ """
+ error_message provides details when access check fails. Empty when has_access is
+ true.
+ """
+
+ has_access: Optional[bool] = FieldInfo(alias="hasAccess", default=None)
+ """has_access indicates whether the principal has read access to the repository."""
diff --git a/tests/api_resources/test_runners.py b/tests/api_resources/test_runners.py
index 5cf72fe..eaf96b9 100644
--- a/tests/api_resources/test_runners.py
+++ b/tests/api_resources/test_runners.py
@@ -18,6 +18,7 @@
RunnerCreateRunnerTokenResponse,
RunnerSearchRepositoriesResponse,
RunnerListScmOrganizationsResponse,
+ RunnerCheckRepositoryAccessResponse,
RunnerCheckAuthenticationForHostResponse,
)
from gitpod.pagination import SyncRunnersPage, AsyncRunnersPage
@@ -292,6 +293,43 @@ def test_streaming_response_check_authentication_for_host(self, client: Gitpod)
assert cast(Any, response.is_closed) is True
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_check_repository_access(self, client: Gitpod) -> None:
+ runner = client.runners.check_repository_access()
+ assert_matches_type(RunnerCheckRepositoryAccessResponse, runner, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_check_repository_access_with_all_params(self, client: Gitpod) -> None:
+ runner = client.runners.check_repository_access(
+ repository_url="https://github.com/org/repo",
+ runner_id="d2c94c27-3b76-4a42-b88c-95a85e392c68",
+ )
+ assert_matches_type(RunnerCheckRepositoryAccessResponse, runner, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_raw_response_check_repository_access(self, client: Gitpod) -> None:
+ response = client.runners.with_raw_response.check_repository_access()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ runner = response.parse()
+ assert_matches_type(RunnerCheckRepositoryAccessResponse, runner, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_streaming_response_check_repository_access(self, client: Gitpod) -> None:
+ with client.runners.with_streaming_response.check_repository_access() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ runner = response.parse()
+ assert_matches_type(RunnerCheckRepositoryAccessResponse, runner, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
@pytest.mark.skip(reason="Prism tests are disabled")
@parametrize
def test_method_create_logs_token(self, client: Gitpod) -> None:
@@ -754,6 +792,43 @@ async def test_streaming_response_check_authentication_for_host(self, async_clie
assert cast(Any, response.is_closed) is True
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_check_repository_access(self, async_client: AsyncGitpod) -> None:
+ runner = await async_client.runners.check_repository_access()
+ assert_matches_type(RunnerCheckRepositoryAccessResponse, runner, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_check_repository_access_with_all_params(self, async_client: AsyncGitpod) -> None:
+ runner = await async_client.runners.check_repository_access(
+ repository_url="https://github.com/org/repo",
+ runner_id="d2c94c27-3b76-4a42-b88c-95a85e392c68",
+ )
+ assert_matches_type(RunnerCheckRepositoryAccessResponse, runner, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_raw_response_check_repository_access(self, async_client: AsyncGitpod) -> None:
+ response = await async_client.runners.with_raw_response.check_repository_access()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ runner = await response.parse()
+ assert_matches_type(RunnerCheckRepositoryAccessResponse, runner, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_streaming_response_check_repository_access(self, async_client: AsyncGitpod) -> None:
+ async with async_client.runners.with_streaming_response.check_repository_access() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ runner = await response.parse()
+ assert_matches_type(RunnerCheckRepositoryAccessResponse, runner, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
@pytest.mark.skip(reason="Prism tests are disabled")
@parametrize
async def test_method_create_logs_token(self, async_client: AsyncGitpod) -> None:
From 1c670ce07e8c40ce649b758fe70374c7a5ead16e Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Tue, 20 Jan 2026 09:21:58 +0000
Subject: [PATCH 23/27] codegen metadata
---
.stats.yml | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/.stats.yml b/.stats.yml
index d450123..718b910 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 170
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-024993504dfc744ff138b0d1b1a151e28129f9f5a8b55adff4c7b559b0556c62.yml
-openapi_spec_hash: 4773277eb2a6ac6be0b2e8f89a2201d8
-config_hash: 942ffc968ca0131e192c1a7ac5dd8990
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-eeec67988ceb123d93514d894e04b0fa00dbf0c4678b95baa80868c103aaa0c1.yml
+openapi_spec_hash: 3bf178a4e70c15f12fdc23531fe81aea
+config_hash: d726afb2a92132197e4eae04303e8041
From 8262825c21be1de663b9a3aad29e9f9fe1cf219d Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Tue, 20 Jan 2026 13:28:15 +0000
Subject: [PATCH 24/27] feat(api): add inputs array to UserInputBlock proto
---
.stats.yml | 4 +-
src/gitpod/types/user_input_block_param.py | 47 ++++++++++++++++++----
tests/api_resources/test_agents.py | 28 ++++++++++++-
3 files changed, 68 insertions(+), 11 deletions(-)
diff --git a/.stats.yml b/.stats.yml
index 718b910..de7a963 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 170
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-eeec67988ceb123d93514d894e04b0fa00dbf0c4678b95baa80868c103aaa0c1.yml
-openapi_spec_hash: 3bf178a4e70c15f12fdc23531fe81aea
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-f838b3c6096ed0143c969fcdd6acf63cb619865ef707e1213194d3b82afe10bf.yml
+openapi_spec_hash: 00a77c0d2749b833f8e29c8493b7ea98
config_hash: d726afb2a92132197e4eae04303e8041
diff --git a/src/gitpod/types/user_input_block_param.py b/src/gitpod/types/user_input_block_param.py
index 5a6b87e..905b928 100644
--- a/src/gitpod/types/user_input_block_param.py
+++ b/src/gitpod/types/user_input_block_param.py
@@ -2,30 +2,61 @@
from __future__ import annotations
-from typing import Union
+from typing import Union, Iterable
from datetime import datetime
-from typing_extensions import Annotated, TypedDict
+from typing_extensions import Literal, Annotated, TypedDict
from .._types import Base64FileInput
from .._utils import PropertyInfo
from .._models import set_pydantic_config
-__all__ = ["UserInputBlockParam", "Image", "Text"]
+__all__ = ["UserInputBlockParam", "Image", "Input", "InputImage", "InputText", "Text"]
class Image(TypedDict, total=False):
"""
ImageInput allows sending images to the agent.
- Media type is inferred from magic bytes by the backend.
+ Client must provide the MIME type; backend validates against magic bytes.
"""
data: Annotated[Union[str, Base64FileInput], PropertyInfo(format="base64")]
- """Raw image data (max 4MB). Supported formats: PNG, JPEG, WebP."""
+ """Raw image data (max 4MB). Supported formats: PNG, JPEG."""
+
+ mime_type: Annotated[Literal["image/png", "image/jpeg"], PropertyInfo(alias="mimeType")]
set_pydantic_config(Image, {"arbitrary_types_allowed": True})
+class InputImage(TypedDict, total=False):
+ """
+ ImageInput allows sending images to the agent.
+ Client must provide the MIME type; backend validates against magic bytes.
+ """
+
+ data: Annotated[Union[str, Base64FileInput], PropertyInfo(format="base64")]
+ """Raw image data (max 4MB). Supported formats: PNG, JPEG."""
+
+ mime_type: Annotated[Literal["image/png", "image/jpeg"], PropertyInfo(alias="mimeType")]
+
+
+set_pydantic_config(InputImage, {"arbitrary_types_allowed": True})
+
+
+class InputText(TypedDict, total=False):
+ content: str
+
+
+class Input(TypedDict, total=False):
+ image: InputImage
+ """
+ ImageInput allows sending images to the agent. Client must provide the MIME
+ type; backend validates against magic bytes.
+ """
+
+ text: InputText
+
+
class Text(TypedDict, total=False):
content: str
@@ -38,8 +69,10 @@ class UserInputBlockParam(TypedDict, total=False):
image: Image
"""
- ImageInput allows sending images to the agent. Media type is inferred from magic
- bytes by the backend.
+ ImageInput allows sending images to the agent. Client must provide the MIME
+ type; backend validates against magic bytes.
"""
+ inputs: Iterable[Input]
+
text: Text
diff --git a/tests/api_resources/test_agents.py b/tests/api_resources/test_agents.py
index f4f2aad..e006c3c 100644
--- a/tests/api_resources/test_agents.py
+++ b/tests/api_resources/test_agents.py
@@ -361,7 +361,19 @@ def test_method_send_to_execution_with_all_params(self, client: Gitpod) -> None:
user_input={
"id": "id",
"created_at": parse_datetime("2019-12-27T18:11:19.117Z"),
- "image": {"data": "U3RhaW5sZXNzIHJvY2tz"},
+ "image": {
+ "data": "U3RhaW5sZXNzIHJvY2tz",
+ "mime_type": "image/png",
+ },
+ "inputs": [
+ {
+ "image": {
+ "data": "U3RhaW5sZXNzIHJvY2tz",
+ "mime_type": "image/png",
+ },
+ "text": {"content": "x"},
+ }
+ ],
"text": {"content": "Generate a report based on the latest logs."},
},
)
@@ -874,7 +886,19 @@ async def test_method_send_to_execution_with_all_params(self, async_client: Asyn
user_input={
"id": "id",
"created_at": parse_datetime("2019-12-27T18:11:19.117Z"),
- "image": {"data": "U3RhaW5sZXNzIHJvY2tz"},
+ "image": {
+ "data": "U3RhaW5sZXNzIHJvY2tz",
+ "mime_type": "image/png",
+ },
+ "inputs": [
+ {
+ "image": {
+ "data": "U3RhaW5sZXNzIHJvY2tz",
+ "mime_type": "image/png",
+ },
+ "text": {"content": "x"},
+ }
+ ],
"text": {"content": "Generate a report based on the latest logs."},
},
)
From de6bee5d7d337456f1a19de0659cd6957c7c1a9b Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Tue, 20 Jan 2026 13:43:59 +0000
Subject: [PATCH 25/27] feat(agent): add spec mode for planning before
interactive implementation
---
.stats.yml | 4 ++--
src/gitpod/types/agent_mode.py | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/.stats.yml b/.stats.yml
index de7a963..bec4a22 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 170
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-f838b3c6096ed0143c969fcdd6acf63cb619865ef707e1213194d3b82afe10bf.yml
-openapi_spec_hash: 00a77c0d2749b833f8e29c8493b7ea98
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-df34fde966f11e17c7e733280ca1e0aeda7ee786ca7de6d245d649970fa71764.yml
+openapi_spec_hash: 9c8c2465318c2d732de64a455cbd7704
config_hash: d726afb2a92132197e4eae04303e8041
diff --git a/src/gitpod/types/agent_mode.py b/src/gitpod/types/agent_mode.py
index d7bd23b..a58c379 100644
--- a/src/gitpod/types/agent_mode.py
+++ b/src/gitpod/types/agent_mode.py
@@ -5,5 +5,5 @@
__all__ = ["AgentMode"]
AgentMode: TypeAlias = Literal[
- "AGENT_MODE_UNSPECIFIED", "AGENT_MODE_EXECUTION", "AGENT_MODE_PLANNING", "AGENT_MODE_RALPH"
+ "AGENT_MODE_UNSPECIFIED", "AGENT_MODE_EXECUTION", "AGENT_MODE_PLANNING", "AGENT_MODE_RALPH", "AGENT_MODE_SPEC"
]
From bf84d63dbf07f7a6bd5fa51cfa7bec30686ee0a6 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Tue, 20 Jan 2026 13:58:17 +0000
Subject: [PATCH 26/27] codegen metadata
---
.stats.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.stats.yml b/.stats.yml
index bec4a22..886c83c 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 170
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-df34fde966f11e17c7e733280ca1e0aeda7ee786ca7de6d245d649970fa71764.yml
-openapi_spec_hash: 9c8c2465318c2d732de64a455cbd7704
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-2423c089f280cdf34a987d40531692097a69f4aa971c6adf9aeec4fd7984cec2.yml
+openapi_spec_hash: 24037c3ab9ceca689150d07ecec7aa80
config_hash: d726afb2a92132197e4eae04303e8041
From 4073835b00a55b7fe5bcca810116986ab25cc5f1 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Wed, 21 Jan 2026 14:29:16 +0000
Subject: [PATCH 27/27] release: 0.7.0
---
.release-please-manifest.json | 2 +-
CHANGELOG.md | 30 ++++++++++++++++++++++++++++++
pyproject.toml | 2 +-
src/gitpod/_version.py | 2 +-
4 files changed, 33 insertions(+), 3 deletions(-)
diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index 4208b5c..1b77f50 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "0.6.0"
+ ".": "0.7.0"
}
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e6b615d..9d5779c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,35 @@
# Changelog
+## 0.7.0 (2026-01-21)
+
+Full Changelog: [v0.6.0...v0.7.0](https://github.com/gitpod-io/gitpod-sdk-python/compare/v0.6.0...v0.7.0)
+
+### Features
+
+* [api] Introduce RPCs to share resources with individual users ([df1cf39](https://github.com/gitpod-io/gitpod-sdk-python/commit/df1cf39a9c1b387c9e9313bfec68a97759762e0b))
+* [api] sorting for `ListMembers` ([838e74c](https://github.com/gitpod-io/gitpod-sdk-python/commit/838e74c4da4b57590a6dd0af19bdd20faf7d2805))
+* [backend] Adding direct_share field to groups ([78c0bdd](https://github.com/gitpod-io/gitpod-sdk-python/commit/78c0bddc838e217007729d723283f9e9cd04d9a2))
+* [backend] Introduce role and member status filtering for `ListMembers` ([34fb372](https://github.com/gitpod-io/gitpod-sdk-python/commit/34fb372aef655ae57fc99d5b37e152c75d831af5))
+* **agent:** add spec mode for planning before interactive implementation ([de6bee5](https://github.com/gitpod-io/gitpod-sdk-python/commit/de6bee5d7d337456f1a19de0659cd6957c7c1a9b))
+* API for SCIM configuration management ([70becd4](https://github.com/gitpod-io/gitpod-sdk-python/commit/70becd4cd142fac4fc839018d52fb4cb93e17834))
+* **api:** add CheckRepositoryAccess API for repository access validation ([b34ed1b](https://github.com/gitpod-io/gitpod-sdk-python/commit/b34ed1b8ecd39343ed02c5f376e9495775912140))
+* **api:** add draft and state fields to PullRequest proto ([e0023da](https://github.com/gitpod-io/gitpod-sdk-python/commit/e0023da5a30344c2fc87ebce55e26101c4ad40b5))
+* **api:** add inputs array to UserInputBlock proto ([8262825](https://github.com/gitpod-io/gitpod-sdk-python/commit/8262825c21be1de663b9a3aad29e9f9fe1cf219d))
+* **api:** add ListSCMOrganizations endpoint ([9c8f7ea](https://github.com/gitpod-io/gitpod-sdk-python/commit/9c8f7eadd38bc0326ecf1be48706003fa258257c))
+* **api:** add search, creator, and status filters to ListWorkflows ([ddd18c0](https://github.com/gitpod-io/gitpod-sdk-python/commit/ddd18c09beb0f24e076818783d2dae09ca9b9f8b))
+* **api:** improve SearchRepositories pagination with next_page and total_count ([2847a10](https://github.com/gitpod-io/gitpod-sdk-python/commit/2847a10e6cbb09be83b012e8a6fcabd32f49e019))
+* **automations:** add before_snapshot trigger type ([9cd272f](https://github.com/gitpod-io/gitpod-sdk-python/commit/9cd272f98f2215b834a841ca34c52ce04fd2898e))
+* **client:** add support for binary request streaming ([be5a823](https://github.com/gitpod-io/gitpod-sdk-python/commit/be5a8235224ff1ecf25464e716191fbf3c7c7fb1))
+* **dashboard:** show tier badge in org selector ([89fd8fe](https://github.com/gitpod-io/gitpod-sdk-python/commit/89fd8fef7f9de200e4aecd563c965d4209427052))
+* Define SCIMConfiguration database schema ([03bd185](https://github.com/gitpod-io/gitpod-sdk-python/commit/03bd1858ec2aefbd4c20a71c206135c441afa99c))
+* move agent mode from Spec to Status, add AgentModeChange signals ([a55115b](https://github.com/gitpod-io/gitpod-sdk-python/commit/a55115ba054078dcb689222cc150b2b1f56077bf))
+* **secrets:** add ServiceAccountSecret entity with full support ([30e17c5](https://github.com/gitpod-io/gitpod-sdk-python/commit/30e17c55b991286527f64c8857b04dd9b5a2ba7b))
+
+
+### Chores
+
+* **internal:** update `actions/checkout` version ([53dcf30](https://github.com/gitpod-io/gitpod-sdk-python/commit/53dcf30cb41a6cbf30ce510b0b2d46cdd5895008))
+
## 0.6.0 (2026-01-09)
Full Changelog: [v0.5.2...v0.6.0](https://github.com/gitpod-io/gitpod-sdk-python/compare/v0.5.2...v0.6.0)
diff --git a/pyproject.toml b/pyproject.toml
index 6136eaf..4f4d826 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "gitpod-sdk"
-version = "0.6.0"
+version = "0.7.0"
description = "The official Python library for the gitpod API"
dynamic = ["readme"]
license = "Apache-2.0"
diff --git a/src/gitpod/_version.py b/src/gitpod/_version.py
index 850eb95..88739dd 100644
--- a/src/gitpod/_version.py
+++ b/src/gitpod/_version.py
@@ -1,4 +1,4 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
__title__ = "gitpod"
-__version__ = "0.6.0" # x-release-please-version
+__version__ = "0.7.0" # x-release-please-version