cyberdesk 2.1.15__py3-none-any.whl → 2.1.17__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of cyberdesk might be problematic. Click here for more details.
- cyberdesk/__init__.py +1 -1
- cyberdesk/client.py +121 -16
- {cyberdesk-2.1.15.dist-info → cyberdesk-2.1.17.dist-info}/METADATA +158 -2
- {cyberdesk-2.1.15.dist-info → cyberdesk-2.1.17.dist-info}/RECORD +23 -15
- openapi_client/cyberdesk_cloud_client/api/computer/copy_to_clipboard_v1_computer_machine_id_copy_to_clipboard_post.py +219 -0
- openapi_client/cyberdesk_cloud_client/api/health/database_health_check_v1_health_db_get.py +9 -68
- openapi_client/cyberdesk_cloud_client/api/machines/delete_machine_v1_machines_machine_id_delete.py +16 -4
- openapi_client/cyberdesk_cloud_client/api/machines/update_machine_v1_machines_machine_id_patch.py +12 -0
- openapi_client/cyberdesk_cloud_client/models/__init__.py +17 -3
- openapi_client/cyberdesk_cloud_client/models/copy_to_clipboard_request.py +59 -0
- openapi_client/cyberdesk_cloud_client/models/copy_to_clipboard_v1_computer_machine_id_copy_to_clipboard_post_response_copy_to_clipboard_v1_computer_machine_id_copy_to_clipboard_post.py +47 -0
- openapi_client/cyberdesk_cloud_client/models/machine_create.py +80 -1
- openapi_client/cyberdesk_cloud_client/models/machine_create_machine_parameters_type_0.py +44 -0
- openapi_client/cyberdesk_cloud_client/models/{database_health_check_v1_health_db_get_response_database_health_check_v1_health_db_get.py → machine_create_machine_sensitive_parameters_type_0.py} +5 -5
- openapi_client/cyberdesk_cloud_client/models/machine_response.py +77 -0
- openapi_client/cyberdesk_cloud_client/models/machine_response_machine_parameters_type_0.py +44 -0
- openapi_client/cyberdesk_cloud_client/models/machine_response_machine_sensitive_parameters_type_0.py +44 -0
- openapi_client/cyberdesk_cloud_client/models/machine_update.py +80 -1
- openapi_client/cyberdesk_cloud_client/models/machine_update_machine_parameters_type_0.py +44 -0
- openapi_client/cyberdesk_cloud_client/models/machine_update_machine_sensitive_parameters_type_0.py +44 -0
- {cyberdesk-2.1.15.dist-info → cyberdesk-2.1.17.dist-info}/WHEEL +0 -0
- {cyberdesk-2.1.15.dist-info → cyberdesk-2.1.17.dist-info}/licenses/LICENSE +0 -0
- {cyberdesk-2.1.15.dist-info → cyberdesk-2.1.17.dist-info}/top_level.txt +0 -0
cyberdesk/__init__.py
CHANGED
cyberdesk/client.py
CHANGED
|
@@ -217,6 +217,10 @@ class MachinesAPI:
|
|
|
217
217
|
status: Machine status filter
|
|
218
218
|
created_at_from: Optional start datetime (UTC or ISO string)
|
|
219
219
|
created_at_to: Optional end datetime (UTC or ISO string)
|
|
220
|
+
|
|
221
|
+
Returns:
|
|
222
|
+
ApiResponse with PaginatedResponseMachineResponse. Each machine includes
|
|
223
|
+
desktop parameters (machine_parameters, machine_sensitive_parameters) if configured.
|
|
220
224
|
"""
|
|
221
225
|
try:
|
|
222
226
|
response = await list_machines_v1_machines_get.asyncio(
|
|
@@ -240,7 +244,19 @@ class MachinesAPI:
|
|
|
240
244
|
created_at_from: Optional[Union[str, datetime]] = None,
|
|
241
245
|
created_at_to: Optional[Union[str, datetime]] = None,
|
|
242
246
|
) -> ApiResponse:
|
|
243
|
-
"""List machines with optional filtering (synchronous).
|
|
247
|
+
"""List machines with optional filtering (synchronous).
|
|
248
|
+
|
|
249
|
+
Args:
|
|
250
|
+
skip: Pagination skip
|
|
251
|
+
limit: Pagination limit
|
|
252
|
+
status: Machine status filter
|
|
253
|
+
created_at_from: Optional start datetime (UTC or ISO string)
|
|
254
|
+
created_at_to: Optional end datetime (UTC or ISO string)
|
|
255
|
+
|
|
256
|
+
Returns:
|
|
257
|
+
ApiResponse with PaginatedResponseMachineResponse. Each machine includes
|
|
258
|
+
desktop parameters (machine_parameters, machine_sensitive_parameters) if configured.
|
|
259
|
+
"""
|
|
244
260
|
try:
|
|
245
261
|
response = list_machines_v1_machines_get.sync(
|
|
246
262
|
client=self.client,
|
|
@@ -255,7 +271,18 @@ class MachinesAPI:
|
|
|
255
271
|
return ApiResponse(error=e)
|
|
256
272
|
|
|
257
273
|
async def create(self, data: MachineCreate) -> ApiResponse:
|
|
258
|
-
"""Create a new machine.
|
|
274
|
+
"""Create a new machine.
|
|
275
|
+
|
|
276
|
+
Args:
|
|
277
|
+
data: MachineCreate object with:
|
|
278
|
+
- fingerprint: Unique machine fingerprint
|
|
279
|
+
- unkey_key_id: API key ID for authentication
|
|
280
|
+
- name: Optional machine name
|
|
281
|
+
- machine_parameters: Optional dict of desktop parameters
|
|
282
|
+
- machine_sensitive_parameters: Optional dict of sensitive desktop parameters
|
|
283
|
+
(provide actual values, they'll be stored in Basis Theory)
|
|
284
|
+
- hostname, os_info, version: Optional machine metadata
|
|
285
|
+
"""
|
|
259
286
|
try:
|
|
260
287
|
response = await create_machine_v1_machines_post.asyncio(
|
|
261
288
|
client=self.client,
|
|
@@ -266,7 +293,18 @@ class MachinesAPI:
|
|
|
266
293
|
return ApiResponse(error=e)
|
|
267
294
|
|
|
268
295
|
def create_sync(self, data: MachineCreate) -> ApiResponse:
|
|
269
|
-
"""Create a new machine (synchronous).
|
|
296
|
+
"""Create a new machine (synchronous).
|
|
297
|
+
|
|
298
|
+
Args:
|
|
299
|
+
data: MachineCreate object with:
|
|
300
|
+
- fingerprint: Unique machine fingerprint
|
|
301
|
+
- unkey_key_id: API key ID for authentication
|
|
302
|
+
- name: Optional machine name
|
|
303
|
+
- machine_parameters: Optional dict of desktop parameters
|
|
304
|
+
- machine_sensitive_parameters: Optional dict of sensitive desktop parameters
|
|
305
|
+
(provide actual values, they'll be stored in Basis Theory)
|
|
306
|
+
- hostname, os_info, version: Optional machine metadata
|
|
307
|
+
"""
|
|
270
308
|
try:
|
|
271
309
|
response = create_machine_v1_machines_post.sync(
|
|
272
310
|
client=self.client,
|
|
@@ -277,7 +315,15 @@ class MachinesAPI:
|
|
|
277
315
|
return ApiResponse(error=e)
|
|
278
316
|
|
|
279
317
|
async def get(self, machine_id: str) -> ApiResponse:
|
|
280
|
-
"""Get a specific machine by ID.
|
|
318
|
+
"""Get a specific machine by ID.
|
|
319
|
+
|
|
320
|
+
Returns:
|
|
321
|
+
ApiResponse with MachineResponse including:
|
|
322
|
+
- Basic info: id, name, status, fingerprint, etc.
|
|
323
|
+
- machine_parameters: Dict of desktop parameters (if configured)
|
|
324
|
+
- machine_sensitive_parameters: Dict of sensitive parameter aliases (if configured)
|
|
325
|
+
- pools: List of pools this machine belongs to
|
|
326
|
+
"""
|
|
281
327
|
try:
|
|
282
328
|
response = await get_machine_v1_machines_machine_id_get.asyncio(
|
|
283
329
|
client=self.client,
|
|
@@ -288,7 +334,15 @@ class MachinesAPI:
|
|
|
288
334
|
return ApiResponse(error=e)
|
|
289
335
|
|
|
290
336
|
def get_sync(self, machine_id: str) -> ApiResponse:
|
|
291
|
-
"""Get a specific machine by ID (synchronous).
|
|
337
|
+
"""Get a specific machine by ID (synchronous).
|
|
338
|
+
|
|
339
|
+
Returns:
|
|
340
|
+
ApiResponse with MachineResponse including:
|
|
341
|
+
- Basic info: id, name, status, fingerprint, etc.
|
|
342
|
+
- machine_parameters: Dict of desktop parameters (if configured)
|
|
343
|
+
- machine_sensitive_parameters: Dict of sensitive parameter aliases (if configured)
|
|
344
|
+
- pools: List of pools this machine belongs to
|
|
345
|
+
"""
|
|
292
346
|
try:
|
|
293
347
|
response = get_machine_v1_machines_machine_id_get.sync(
|
|
294
348
|
client=self.client,
|
|
@@ -300,10 +354,28 @@ class MachinesAPI:
|
|
|
300
354
|
|
|
301
355
|
async def update(self, machine_id: str, data: MachineUpdate) -> ApiResponse:
|
|
302
356
|
"""Update a machine.
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
357
|
+
|
|
358
|
+
Args:
|
|
359
|
+
machine_id: The machine ID to update
|
|
360
|
+
data: MachineUpdate object with fields to update:
|
|
361
|
+
- name: Optional machine name
|
|
362
|
+
- machine_parameters: Optional dict of machine-specific input values that
|
|
363
|
+
automatically populate runs on this desktop. Use {} to clear all.
|
|
364
|
+
- machine_sensitive_parameters: Optional dict of sensitive parameters
|
|
365
|
+
(provide actual values, they'll be stored in Basis Theory). Use {} to clear all.
|
|
366
|
+
- status, is_available, hostname, os_info, version: Other machine fields
|
|
367
|
+
- reserved_session_id: Set to null to clear reservation
|
|
368
|
+
|
|
369
|
+
Desktop Parameters:
|
|
370
|
+
Machine parameters automatically merge into runs assigned to this machine,
|
|
371
|
+
overriding run-level input values. Use {param_name} or {$sensitive_param}
|
|
372
|
+
syntax in workflow prompts.
|
|
373
|
+
|
|
374
|
+
Note:
|
|
375
|
+
- linked_keepalive_machine_id is not writable; it is managed by
|
|
376
|
+
Cyberdriver link events and will be set/cleared automatically by the platform.
|
|
377
|
+
- For machine_sensitive_parameters, provide actual secret values. They will be
|
|
378
|
+
stored securely in Basis Theory and only aliases stored in the database.
|
|
307
379
|
"""
|
|
308
380
|
try:
|
|
309
381
|
response = await update_machine_v1_machines_machine_id_patch.asyncio(
|
|
@@ -317,10 +389,28 @@ class MachinesAPI:
|
|
|
317
389
|
|
|
318
390
|
def update_sync(self, machine_id: str, data: MachineUpdate) -> ApiResponse:
|
|
319
391
|
"""Update a machine (synchronous).
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
392
|
+
|
|
393
|
+
Args:
|
|
394
|
+
machine_id: The machine ID to update
|
|
395
|
+
data: MachineUpdate object with fields to update:
|
|
396
|
+
- name: Optional machine name
|
|
397
|
+
- machine_parameters: Optional dict of machine-specific input values that
|
|
398
|
+
automatically populate runs on this desktop. Use {} to clear all.
|
|
399
|
+
- machine_sensitive_parameters: Optional dict of sensitive parameters
|
|
400
|
+
(provide actual values, they'll be stored in Basis Theory). Use {} to clear all.
|
|
401
|
+
- status, is_available, hostname, os_info, version: Other machine fields
|
|
402
|
+
- reserved_session_id: Set to null to clear reservation
|
|
403
|
+
|
|
404
|
+
Desktop Parameters:
|
|
405
|
+
Machine parameters automatically merge into runs assigned to this machine,
|
|
406
|
+
overriding run-level input values. Use {param_name} or {$sensitive_param}
|
|
407
|
+
syntax in workflow prompts.
|
|
408
|
+
|
|
409
|
+
Note:
|
|
410
|
+
- linked_keepalive_machine_id is not writable; it is managed by
|
|
411
|
+
Cyberdriver link events and will be set/cleared automatically by the platform.
|
|
412
|
+
- For machine_sensitive_parameters, provide actual secret values. They will be
|
|
413
|
+
stored securely in Basis Theory and only aliases stored in the database.
|
|
324
414
|
"""
|
|
325
415
|
try:
|
|
326
416
|
response = update_machine_v1_machines_machine_id_patch.sync(
|
|
@@ -362,7 +452,14 @@ class MachinesAPI:
|
|
|
362
452
|
return ApiResponse(error=e)
|
|
363
453
|
|
|
364
454
|
async def delete(self, machine_id: str) -> ApiResponse:
|
|
365
|
-
"""Delete a machine.
|
|
455
|
+
"""Delete a machine.
|
|
456
|
+
|
|
457
|
+
Associated runs are preserved with machine_id set to NULL to maintain run history.
|
|
458
|
+
Connections and request logs are cascade deleted.
|
|
459
|
+
|
|
460
|
+
If the machine has desktop sensitive parameters, they will be automatically
|
|
461
|
+
cleaned up from Basis Theory before deletion.
|
|
462
|
+
"""
|
|
366
463
|
try:
|
|
367
464
|
await delete_machine_v1_machines_machine_id_delete.asyncio(
|
|
368
465
|
client=self.client,
|
|
@@ -373,7 +470,14 @@ class MachinesAPI:
|
|
|
373
470
|
return ApiResponse(error=e)
|
|
374
471
|
|
|
375
472
|
def delete_sync(self, machine_id: str) -> ApiResponse:
|
|
376
|
-
"""Delete a machine (synchronous).
|
|
473
|
+
"""Delete a machine (synchronous).
|
|
474
|
+
|
|
475
|
+
Associated runs are preserved with machine_id set to NULL to maintain run history.
|
|
476
|
+
Connections and request logs are cascade deleted.
|
|
477
|
+
|
|
478
|
+
If the machine has desktop sensitive parameters, they will be automatically
|
|
479
|
+
cleaned up from Basis Theory before deletion.
|
|
480
|
+
"""
|
|
377
481
|
try:
|
|
378
482
|
delete_machine_v1_machines_machine_id_delete.sync(
|
|
379
483
|
client=self.client,
|
|
@@ -1829,7 +1933,8 @@ class CyberdeskClient:
|
|
|
1829
1933
|
base_url=base_url,
|
|
1830
1934
|
token=api_key,
|
|
1831
1935
|
prefix="Bearer",
|
|
1832
|
-
auth_header_name="Authorization"
|
|
1936
|
+
auth_header_name="Authorization",
|
|
1937
|
+
raise_on_unexpected_status=True # Raise exceptions for non-200/422 responses
|
|
1833
1938
|
)
|
|
1834
1939
|
|
|
1835
1940
|
# Initialize API endpoints
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cyberdesk
|
|
3
|
-
Version: 2.1.
|
|
3
|
+
Version: 2.1.17
|
|
4
4
|
Summary: The official Python SDK for Cyberdesk
|
|
5
5
|
Author-email: Cyberdesk Team <dev@cyberdesk.io>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -12,6 +12,23 @@ Provides-Extra: dev
|
|
|
12
12
|
Requires-Dist: openapi-python-client; extra == "dev"
|
|
13
13
|
Requires-Dist: build; extra == "dev"
|
|
14
14
|
Requires-Dist: twine; extra == "dev"
|
|
15
|
+
Provides-Extra: testing
|
|
16
|
+
Requires-Dist: svix>=1.0.0; extra == "testing"
|
|
17
|
+
Requires-Dist: fastapi>=0.100.0; extra == "testing"
|
|
18
|
+
Requires-Dist: uvicorn[standard]>=0.30.0; extra == "testing"
|
|
19
|
+
Requires-Dist: python-dotenv>=1.0.0; extra == "testing"
|
|
20
|
+
Requires-Dist: pytest>=8.0.0; extra == "testing"
|
|
21
|
+
Requires-Dist: pytest-asyncio>=0.23.0; extra == "testing"
|
|
22
|
+
Provides-Extra: all
|
|
23
|
+
Requires-Dist: openapi-python-client; extra == "all"
|
|
24
|
+
Requires-Dist: build; extra == "all"
|
|
25
|
+
Requires-Dist: twine; extra == "all"
|
|
26
|
+
Requires-Dist: svix>=1.0.0; extra == "all"
|
|
27
|
+
Requires-Dist: fastapi>=0.100.0; extra == "all"
|
|
28
|
+
Requires-Dist: uvicorn[standard]>=0.30.0; extra == "all"
|
|
29
|
+
Requires-Dist: python-dotenv>=1.0.0; extra == "all"
|
|
30
|
+
Requires-Dist: pytest>=8.0.0; extra == "all"
|
|
31
|
+
Requires-Dist: pytest-asyncio>=0.23.0; extra == "all"
|
|
15
32
|
Dynamic: license-file
|
|
16
33
|
|
|
17
34
|
# Cyberdesk Python SDK
|
|
@@ -21,7 +38,14 @@ The official Python SDK for Cyberdesk API. This SDK provides a clean, type-safe
|
|
|
21
38
|
## Installation
|
|
22
39
|
|
|
23
40
|
```bash
|
|
41
|
+
# Basic SDK installation
|
|
24
42
|
pip install cyberdesk
|
|
43
|
+
|
|
44
|
+
# With testing utilities
|
|
45
|
+
pip install "cyberdesk[testing]"
|
|
46
|
+
|
|
47
|
+
# All development dependencies (for SDK contributors)
|
|
48
|
+
pip install "cyberdesk[all]"
|
|
25
49
|
```
|
|
26
50
|
|
|
27
51
|
## Quick Start
|
|
@@ -66,6 +90,38 @@ else:
|
|
|
66
90
|
print("Run failed:", ", ".join(run.error or []))
|
|
67
91
|
```
|
|
68
92
|
|
|
93
|
+
## Desktop Parameters
|
|
94
|
+
|
|
95
|
+
Configure machine-specific values that automatically populate workflows running on specific desktops:
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
from cyberdesk import MachineUpdate
|
|
99
|
+
|
|
100
|
+
# Set desktop parameters for a machine
|
|
101
|
+
client.machines.update_sync(
|
|
102
|
+
machine_id="machine-id",
|
|
103
|
+
data=MachineUpdate(
|
|
104
|
+
machine_parameters={
|
|
105
|
+
"username": "machine_specific_user",
|
|
106
|
+
"api_url": "https://api-region-east.example.com",
|
|
107
|
+
"config_path": "C:\\MachineA\\config.json"
|
|
108
|
+
},
|
|
109
|
+
machine_sensitive_parameters={
|
|
110
|
+
"password": "actual_secret_value", # Stored securely in Basis Theory
|
|
111
|
+
"api_key": "actual_api_key_123"
|
|
112
|
+
}
|
|
113
|
+
)
|
|
114
|
+
)
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Use in workflows with standard syntax:
|
|
118
|
+
```
|
|
119
|
+
Log in to {api_url} using {username} and password {$password}.
|
|
120
|
+
Then open the config at {config_path}.
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Desktop parameters automatically override run-level inputs and persist across runs. See the [Desktop Parameters docs](https://docs.cyberdesk.io/concepts/desktop-parameters) for more details.
|
|
124
|
+
|
|
69
125
|
## Full Documentation
|
|
70
126
|
|
|
71
127
|
For complete documentation including async/sync usage, error handling, and all available methods, visit:
|
|
@@ -281,6 +337,106 @@ from cyberdesk import (
|
|
|
281
337
|
)
|
|
282
338
|
```
|
|
283
339
|
|
|
340
|
+
## Webhooks
|
|
341
|
+
|
|
342
|
+
### Handling Webhooks
|
|
343
|
+
|
|
344
|
+
Cyberdesk sends webhooks when important events occur (e.g., workflow completion). To handle webhooks:
|
|
345
|
+
|
|
346
|
+
```python
|
|
347
|
+
import os
|
|
348
|
+
from fastapi import FastAPI, Request, HTTPException
|
|
349
|
+
from svix.webhooks import Webhook, WebhookVerificationError
|
|
350
|
+
from openapi_client.cyberdesk_cloud_client.models.run_completed_event import RunCompletedEvent
|
|
351
|
+
from openapi_client.cyberdesk_cloud_client.models.run_response import RunResponse
|
|
352
|
+
from typing import cast
|
|
353
|
+
|
|
354
|
+
app = FastAPI()
|
|
355
|
+
|
|
356
|
+
@app.post("/webhooks/cyberdesk")
|
|
357
|
+
async def cyberdesk_webhook(request: Request):
|
|
358
|
+
secret = os.environ["SVIX_WEBHOOK_SECRET"]
|
|
359
|
+
wh = Webhook(secret)
|
|
360
|
+
|
|
361
|
+
payload = await request.body()
|
|
362
|
+
headers = {
|
|
363
|
+
"svix-id": request.headers.get("svix-id"),
|
|
364
|
+
"svix-timestamp": request.headers.get("svix-timestamp"),
|
|
365
|
+
"svix-signature": request.headers.get("svix-signature"),
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
try:
|
|
369
|
+
data = wh.verify(payload, headers)
|
|
370
|
+
# IMPORTANT: Use from_dict() for attrs classes, NOT model_validate()
|
|
371
|
+
evt = RunCompletedEvent.from_dict(data)
|
|
372
|
+
run: RunResponse = cast(RunResponse, evt.run)
|
|
373
|
+
|
|
374
|
+
# Process the run based on status
|
|
375
|
+
if run.status == "success":
|
|
376
|
+
print(f"Run {run.id} completed successfully!")
|
|
377
|
+
print(f"Output: {run.output_data}")
|
|
378
|
+
|
|
379
|
+
return {"ok": True}
|
|
380
|
+
except WebhookVerificationError:
|
|
381
|
+
raise HTTPException(status_code=400, detail="Invalid signature")
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
**Important**: The SDK uses `attrs` classes (not Pydantic), so use `RunCompletedEvent.from_dict(data)` instead of `model_validate(data)`.
|
|
385
|
+
|
|
386
|
+
### Testing Webhooks Locally
|
|
387
|
+
|
|
388
|
+
See [tests/webhooks/WEBHOOK_TESTING.md](./tests/webhooks/WEBHOOK_TESTING.md) for a complete guide on testing webhooks locally without exposing your server to the internet.
|
|
389
|
+
|
|
390
|
+
Quick start:
|
|
391
|
+
```bash
|
|
392
|
+
# Install SDK with testing dependencies
|
|
393
|
+
pip install "cyberdesk[testing]"
|
|
394
|
+
|
|
395
|
+
# Set up .env file
|
|
396
|
+
cp .env.example .env
|
|
397
|
+
# Edit .env with your SVIX_WEBHOOK_SECRET
|
|
398
|
+
|
|
399
|
+
# Run the example webhook handler
|
|
400
|
+
python -m uvicorn tests.webhooks.example_webhook_handler:app --reload
|
|
401
|
+
|
|
402
|
+
# In another terminal, test it
|
|
403
|
+
python -m tests.webhooks.test_webhook_local
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
### Example Files
|
|
407
|
+
|
|
408
|
+
All webhook testing resources are in the `tests/webhooks/` directory:
|
|
409
|
+
- `tests/webhooks/example_webhook_handler.py` - Complete, production-ready webhook handler
|
|
410
|
+
- `tests/webhooks/test_webhook_local.py` - Utility to test webhooks locally
|
|
411
|
+
- `tests/webhooks/test_webhook_integration.py` - pytest integration tests
|
|
412
|
+
- `tests/webhooks/WEBHOOK_TESTING.md` - Comprehensive testing guide
|
|
413
|
+
- `tests/webhooks/WEBHOOK_QUICKSTART.md` - Quick reference guide
|
|
414
|
+
|
|
415
|
+
## Testing
|
|
416
|
+
|
|
417
|
+
The SDK includes comprehensive testing utilities:
|
|
418
|
+
|
|
419
|
+
### Quick Test
|
|
420
|
+
|
|
421
|
+
```bash
|
|
422
|
+
# Install with test dependencies
|
|
423
|
+
pip install ".[testing]"
|
|
424
|
+
|
|
425
|
+
# Set up environment
|
|
426
|
+
cp .env.example .env
|
|
427
|
+
# Edit .env with your credentials
|
|
428
|
+
|
|
429
|
+
# Run all tests
|
|
430
|
+
pytest tests/ -v
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
### Test Categories
|
|
434
|
+
|
|
435
|
+
- **Webhook Tests** (`tests/webhooks/`) - Test webhook handlers locally, no real API
|
|
436
|
+
- **Integration Tests** (`tests/integration/`) - Test SDK with real API calls
|
|
437
|
+
|
|
438
|
+
See [TESTING.md](./TESTING.md) for complete testing documentation.
|
|
439
|
+
|
|
284
440
|
## Limitations
|
|
285
441
|
|
|
286
442
|
- **Screenshot API**: The `/v1/computer/{machine_id}/display/screenshot` endpoint is not included in the generated client due to limitations with binary (PNG) responses in the openapi-python-client generator. This can be added manually if needed - see the TODO comment in `client.py`.
|
|
@@ -289,7 +445,7 @@ from cyberdesk import (
|
|
|
289
445
|
|
|
290
446
|
- Python 3.8+
|
|
291
447
|
- httpx
|
|
292
|
-
-
|
|
448
|
+
- attrs (used by the auto-generated OpenAPI client)
|
|
293
449
|
|
|
294
450
|
## License
|
|
295
451
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
cyberdesk/__init__.py,sha256=
|
|
2
|
-
cyberdesk/client.py,sha256=
|
|
3
|
-
cyberdesk-2.1.
|
|
1
|
+
cyberdesk/__init__.py,sha256=F7lwlebhXFXxkNqQeFS2H9-Se0yS7Q-plLj6SsUnQSE,1158
|
|
2
|
+
cyberdesk/client.py,sha256=S1uq79M3heU_87d64ZZH16LD4Tb1eTeFjTWn6DuSQfQ,77105
|
|
3
|
+
cyberdesk-2.1.17.dist-info/licenses/LICENSE,sha256=06Op63FCwGhuUOz__M8IZW5sxd29WxyGC4X5-Uih7IQ,1071
|
|
4
4
|
openapi_client/cyberdesk_cloud_client/__init__.py,sha256=r_uVkNUL-SOK8j7-KiGMIKdinES5X8K1Q250ySX2F-A,158
|
|
5
5
|
openapi_client/cyberdesk_cloud_client/client.py,sha256=o_mdLqyBCQstu5tS1WZFwqIEbGwkvWQ7eQjuCJw_5VY,12419
|
|
6
6
|
openapi_client/cyberdesk_cloud_client/errors.py,sha256=gO8GBmKqmSNgAg-E5oT-oOyxztvp7V_6XG7OUTT15q0,546
|
|
@@ -8,6 +8,7 @@ openapi_client/cyberdesk_cloud_client/py.typed,sha256=8ZJUsxZiuOy1oJeVhsTWQhTG_6
|
|
|
8
8
|
openapi_client/cyberdesk_cloud_client/types.py,sha256=AX4orxQZQJat3vZrgjJ-TYb2sNBL8kNo9yqYDT-n8y8,1391
|
|
9
9
|
openapi_client/cyberdesk_cloud_client/api/__init__.py,sha256=zTSiG_ujSjAqWPyc435YXaX9XTlpMjiJWBbV-f-YtdA,45
|
|
10
10
|
openapi_client/cyberdesk_cloud_client/api/computer/__init__.py,sha256=5vd9uJWAjRqa9xzxzYkLD1yoZ12Ld_bAaNB5WX4fbE8,56
|
|
11
|
+
openapi_client/cyberdesk_cloud_client/api/computer/copy_to_clipboard_v1_computer_machine_id_copy_to_clipboard_post.py,sha256=LND0wrAEdOJLSDECYWfaQNdwl9QlYMmqi2RXS3F_m-U,6630
|
|
11
12
|
openapi_client/cyberdesk_cloud_client/api/computer/fs_list_v1_computer_machine_id_fs_list_get.py,sha256=gI3DVyJZMiLoeer0YiUNyhjIIBIUq2BeNoRPFSr58rY,5794
|
|
12
13
|
openapi_client/cyberdesk_cloud_client/api/computer/fs_read_v1_computer_machine_id_fs_read_get.py,sha256=QstHlkfxARLnNt6WKjfwgER8wq-JfK1JOvU39veSlLI,5607
|
|
13
14
|
openapi_client/cyberdesk_cloud_client/api/computer/fs_write_v1_computer_machine_id_fs_write_post.py,sha256=4Un-26ll3YEKVMQve1MN_JdGEkOVj65FgNKvH1HWLrg,5808
|
|
@@ -33,16 +34,16 @@ openapi_client/cyberdesk_cloud_client/api/default/health_db_health_db_get.py,sha
|
|
|
33
34
|
openapi_client/cyberdesk_cloud_client/api/default/health_health_get.py,sha256=6PcNUPSNqD1KGgiws7sTbwlWKrnZ-06mO1mZ-8zXv1M,3525
|
|
34
35
|
openapi_client/cyberdesk_cloud_client/api/default/root_get.py,sha256=Wba5aa7-F_8KDoW6hjr4yRWtftT42lTUrNzMlhmBc8A,2153
|
|
35
36
|
openapi_client/cyberdesk_cloud_client/api/health/__init__.py,sha256=5vd9uJWAjRqa9xzxzYkLD1yoZ12Ld_bAaNB5WX4fbE8,56
|
|
36
|
-
openapi_client/cyberdesk_cloud_client/api/health/database_health_check_v1_health_db_get.py,sha256=
|
|
37
|
+
openapi_client/cyberdesk_cloud_client/api/health/database_health_check_v1_health_db_get.py,sha256=H8WX51eQFZPb3wTKMlLC6UMIsXAYKg3f48VLLIdAO_E,2337
|
|
37
38
|
openapi_client/cyberdesk_cloud_client/api/health/health_check_v1_health_get.py,sha256=Lv0XTq99x8W9suZ-haArPlEfzNGNw99rfY-VJmXbSss,4111
|
|
38
39
|
openapi_client/cyberdesk_cloud_client/api/machines/__init__.py,sha256=5vd9uJWAjRqa9xzxzYkLD1yoZ12Ld_bAaNB5WX4fbE8,56
|
|
39
40
|
openapi_client/cyberdesk_cloud_client/api/machines/create_machine_v1_machines_post.py,sha256=4AxFmCuNy7Hqcua9TCeK67-BSXmUTIJ1iVYPVr4_dPs,4795
|
|
40
|
-
openapi_client/cyberdesk_cloud_client/api/machines/delete_machine_v1_machines_machine_id_delete.py,sha256
|
|
41
|
+
openapi_client/cyberdesk_cloud_client/api/machines/delete_machine_v1_machines_machine_id_delete.py,sha256=Pl81435yGpdpbNMo-tGw5gemhEA1hPAYU8hYUvf_jqk,5024
|
|
41
42
|
openapi_client/cyberdesk_cloud_client/api/machines/get_machine_pools_v1_machines_machine_id_pools_get.py,sha256=oqAf2YGONto0zV9pB3fnBX3B9S6fSKGmO5Y7V0nI6jY,4548
|
|
42
43
|
openapi_client/cyberdesk_cloud_client/api/machines/get_machine_v1_machines_machine_id_get.py,sha256=ygavJyYWH59YYO9nwjWItmjYxNf3-jer138RUqscFpM,4502
|
|
43
44
|
openapi_client/cyberdesk_cloud_client/api/machines/list_machines_v1_machines_get.py,sha256=Viw1xwNcnPMi1hdt_g2zlh_ayRpOYJmz8cm2NYKYHls,9299
|
|
44
45
|
openapi_client/cyberdesk_cloud_client/api/machines/update_machine_pools_v1_machines_machine_id_pools_put.py,sha256=L7EUPJh-f3fLlIp7j7D6TDriKG2SzjlT7XCkhx3HkrU,5363
|
|
45
|
-
openapi_client/cyberdesk_cloud_client/api/machines/update_machine_v1_machines_machine_id_patch.py,sha256=
|
|
46
|
+
openapi_client/cyberdesk_cloud_client/api/machines/update_machine_v1_machines_machine_id_patch.py,sha256=31FjodrU1SBiEQ6uAZ1PVTPzSPEIOcEZhmdmS4FGsts,6078
|
|
46
47
|
openapi_client/cyberdesk_cloud_client/api/pools/__init__.py,sha256=5vd9uJWAjRqa9xzxzYkLD1yoZ12Ld_bAaNB5WX4fbE8,56
|
|
47
48
|
openapi_client/cyberdesk_cloud_client/api/pools/add_machines_to_pool_v1_pools_pool_id_machines_post.py,sha256=obWOLy7jQbLwBJbX-OJ6U_ZhXgr24bXmZRqJzIJTKas,5008
|
|
48
49
|
openapi_client/cyberdesk_cloud_client/api/pools/create_pool_v1_pools_post.py,sha256=7dacQgMIDSE1OBFcUwNr1hzFRQUoVZDRzf6tIRdEnDQ,4488
|
|
@@ -90,7 +91,7 @@ openapi_client/cyberdesk_cloud_client/api/workflows/get_workflow_v1_workflows_wo
|
|
|
90
91
|
openapi_client/cyberdesk_cloud_client/api/workflows/get_workflow_versions_v1_workflows_workflow_id_versions_get.py,sha256=ax_5V-lIClvOxr50eXSIAPbyhWP-cS4a4DXzwdxkVYs,5889
|
|
91
92
|
openapi_client/cyberdesk_cloud_client/api/workflows/list_workflows_v1_workflows_get.py,sha256=Aszxh1BlUuRqMHjT7lvZf8g6kDCcNUZtuwoJqhDOwlQ,11258
|
|
92
93
|
openapi_client/cyberdesk_cloud_client/api/workflows/update_workflow_v1_workflows_workflow_id_patch.py,sha256=K_tuO6s_FyM8MUOck5AuX_RNIeYqCQcfYx1aDg9xwhE,5737
|
|
93
|
-
openapi_client/cyberdesk_cloud_client/models/__init__.py,sha256=
|
|
94
|
+
openapi_client/cyberdesk_cloud_client/models/__init__.py,sha256=xuOG5GJyh_fo88QoapR5g1l2H7Rhb7Qu41o-S8zpu3k,11894
|
|
94
95
|
openapi_client/cyberdesk_cloud_client/models/attachment_type.py,sha256=zqPOsSd2AmxGNqb5HQ6ZYBAYL8k-0UbWHhfAJYNHoro,161
|
|
95
96
|
openapi_client/cyberdesk_cloud_client/models/chain_step.py,sha256=RbcnI9FI-e6fPYnvtsTUcKmyOkw_0X0R3YLzQihyMO4,5608
|
|
96
97
|
openapi_client/cyberdesk_cloud_client/models/chain_step_inputs_type_0.py,sha256=fLKmOSl7rEi7pRrXbY1sqiVdbCNg0mGj2cPOb5_7hh4,2368
|
|
@@ -98,7 +99,8 @@ openapi_client/cyberdesk_cloud_client/models/chain_step_sensitive_inputs_type_0.
|
|
|
98
99
|
openapi_client/cyberdesk_cloud_client/models/connection_create.py,sha256=gCI36DmjJDZxzGFPbykyYw9k4QEf_4dVNz9b-xZfLo4,3288
|
|
99
100
|
openapi_client/cyberdesk_cloud_client/models/connection_response.py,sha256=aFxqJX75wSEw5dZ-kvh3Wgv_haJ6xYJ7o72vSAbEtHY,5247
|
|
100
101
|
openapi_client/cyberdesk_cloud_client/models/connection_status.py,sha256=XTpa-W0TinYhypU7P-LaJEI3I2JsEaT3voUZQ3zoJO0,203
|
|
101
|
-
openapi_client/cyberdesk_cloud_client/models/
|
|
102
|
+
openapi_client/cyberdesk_cloud_client/models/copy_to_clipboard_request.py,sha256=6WOqshR7ny2Gz5q8qOzLr-BecfHPLswasoPmQxu-8fs,1527
|
|
103
|
+
openapi_client/cyberdesk_cloud_client/models/copy_to_clipboard_v1_computer_machine_id_copy_to_clipboard_post_response_copy_to_clipboard_v1_computer_machine_id_copy_to_clipboard_post.py,sha256=8czEQNJmejLoMCXFtXtb7ujd08GMqGOzQ7282XWghvA,1789
|
|
102
104
|
openapi_client/cyberdesk_cloud_client/models/display_dimensions.py,sha256=_YjSuYuJIzETS5QzOUxsUJvgrOuvScDlUSUp36sr5Dk,1640
|
|
103
105
|
openapi_client/cyberdesk_cloud_client/models/dummy_test_endpoint_v1_test_post_response_dummy_test_endpoint_v1_test_post.py,sha256=9z2ys68FDs76-xnXgUTB76gFEIss6qOKwTekFbBiGA4,1488
|
|
104
106
|
openapi_client/cyberdesk_cloud_client/models/file_input.py,sha256=7RpWoLxoVkGJsqntD2jh6PJZ-SJGWIM1XQziVEGHu5I,3046
|
|
@@ -112,12 +114,18 @@ openapi_client/cyberdesk_cloud_client/models/health_health_get_response_health_h
|
|
|
112
114
|
openapi_client/cyberdesk_cloud_client/models/http_validation_error.py,sha256=OvQ-alRPbtXXwrQunI1Cp1-BWf7ZkVHkigk-YVMFXN0,2213
|
|
113
115
|
openapi_client/cyberdesk_cloud_client/models/keyboard_key_request.py,sha256=iZ2uFo_pgZ59xX04hJZpl49dfVLqTchtAYVUWZX8MEM,1475
|
|
114
116
|
openapi_client/cyberdesk_cloud_client/models/keyboard_type_request.py,sha256=Jgzt14kcl8kfdEJYI3BSnHgxVbFnUIUjBQDF1ly-vIY,1480
|
|
115
|
-
openapi_client/cyberdesk_cloud_client/models/machine_create.py,sha256=
|
|
117
|
+
openapi_client/cyberdesk_cloud_client/models/machine_create.py,sha256=060_AFiuemh_b0OnMgg67dAfco3-QrXUmwkLKhvh6Y4,8545
|
|
118
|
+
openapi_client/cyberdesk_cloud_client/models/machine_create_machine_parameters_type_0.py,sha256=Lx6VS-pnWBEQ1Qz9xgOHIH-ZxlN9SJg7VdDMfNtJ-xg,1332
|
|
119
|
+
openapi_client/cyberdesk_cloud_client/models/machine_create_machine_sensitive_parameters_type_0.py,sha256=3iODOQ69n4efrEYDqdtEF6_-U2fciXKh77EdT3iBiTk,1380
|
|
116
120
|
openapi_client/cyberdesk_cloud_client/models/machine_pool_assignment.py,sha256=oTctHGs4FQsdRvhc_evjC13vewhiQsaohsztMSWXJ9Q,2011
|
|
117
121
|
openapi_client/cyberdesk_cloud_client/models/machine_pool_update.py,sha256=K1ax3OmPZj2t-VlQ0CsRWYuTR667fBTXsT8hJkZXcWU,1935
|
|
118
|
-
openapi_client/cyberdesk_cloud_client/models/machine_response.py,sha256=
|
|
122
|
+
openapi_client/cyberdesk_cloud_client/models/machine_response.py,sha256=S5dNFGfsggnNIm0xiSOxnHQIceE061QhZlYgMrJqlNk,15786
|
|
123
|
+
openapi_client/cyberdesk_cloud_client/models/machine_response_machine_parameters_type_0.py,sha256=2QZATJUv3aQzshYQH7359szmNCCgC9eMZLr9sV240cM,1342
|
|
124
|
+
openapi_client/cyberdesk_cloud_client/models/machine_response_machine_sensitive_parameters_type_0.py,sha256=KLSFx-ehFfIWyRDIbDGzjh3tGircPSzxQXUakKwCCYQ,1390
|
|
119
125
|
openapi_client/cyberdesk_cloud_client/models/machine_status.py,sha256=mqKyXgK1wcaA2fI6iTo_tS7AMeuVrRN4yE21d2Lsq1I,200
|
|
120
|
-
openapi_client/cyberdesk_cloud_client/models/machine_update.py,sha256=
|
|
126
|
+
openapi_client/cyberdesk_cloud_client/models/machine_update.py,sha256=A_M0el92AmcSUZFqZooDq8euUskPfXWbrk4s4Bd9UQQ,12497
|
|
127
|
+
openapi_client/cyberdesk_cloud_client/models/machine_update_machine_parameters_type_0.py,sha256=zvcMGmHKRdX4Cp6wkndUJCX4-J0b2wznv_TzxP_VpC8,1332
|
|
128
|
+
openapi_client/cyberdesk_cloud_client/models/machine_update_machine_sensitive_parameters_type_0.py,sha256=jSImOtfh4B63-vyzIDbM2gbZq9TnNcRwQiv8FAwb58w,1380
|
|
121
129
|
openapi_client/cyberdesk_cloud_client/models/mouse_click_request.py,sha256=GSBn4fg2sNnL4KQQHKly2YIzyRqbfwVgrQXpaalOUxg,3423
|
|
122
130
|
openapi_client/cyberdesk_cloud_client/models/mouse_drag_request.py,sha256=TRQoT0FUprSE2hBK7U3M_mHWx2VzvE_YKg582OBXgXc,3389
|
|
123
131
|
openapi_client/cyberdesk_cloud_client/models/mouse_move_request.py,sha256=D5sWQwnRvs_IvRocctMeE2czciI-KvuuYh73PLutkPo,1548
|
|
@@ -188,7 +196,7 @@ openapi_client/cyberdesk_cloud_client/models/workflow_create.py,sha256=d0bfNbNBF
|
|
|
188
196
|
openapi_client/cyberdesk_cloud_client/models/workflow_response.py,sha256=k48mouJ6Dcisz2vyM7Rb_cbjU66JudGVPsq4UC7grHA,8977
|
|
189
197
|
openapi_client/cyberdesk_cloud_client/models/workflow_response_old_versions_type_0_item.py,sha256=W9AxxlBlN3rUwLDcoUx5H7MUiYA9UztfX9iEpNGlgAs,1340
|
|
190
198
|
openapi_client/cyberdesk_cloud_client/models/workflow_update.py,sha256=TG2jEitXixS2thtz7lTxTZaE0RBVSWd-apVxWxsvnrg,5333
|
|
191
|
-
cyberdesk-2.1.
|
|
192
|
-
cyberdesk-2.1.
|
|
193
|
-
cyberdesk-2.1.
|
|
194
|
-
cyberdesk-2.1.
|
|
199
|
+
cyberdesk-2.1.17.dist-info/METADATA,sha256=ielAZDIJyp3IiO-L5yoLgvBw5teWilsJA-MX7HRBNrQ,11974
|
|
200
|
+
cyberdesk-2.1.17.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
201
|
+
cyberdesk-2.1.17.dist-info/top_level.txt,sha256=qTYHZHVHh3VClNPQsiFFA8p8tmJgFGhq9G1COd-pX_A,25
|
|
202
|
+
cyberdesk-2.1.17.dist-info/RECORD,,
|