Skip to content

Commit 9b31116

Browse files
dines-rlclaude
andauthored
feat(network-policy): add network policies (#720)
* cp dines * cp dines * cp dines * fix: address PR review feedback (conventions, KISS, duplication) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * fix: format async_benchmark.py to pass ruff checks Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * fix: address PR review feedback - use SDKNetworkPolicyUpdateParams and rename test IDs - Use SDKNetworkPolicyUpdateParams in update methods for both sync and async NetworkPolicy classes - Rename network policy test IDs from npo_123 to np_123 across all test files - Update test expectations to match new parameter unpacking behavior Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * cp dines --------- Co-authored-by: Claude Code Review Bot <noreply@anthropic.com> Co-authored-by: Claude Sonnet 4.5 <claude@anthropic.com>
1 parent 74db814 commit 9b31116

File tree

16 files changed

+1119
-7
lines changed

16 files changed

+1119
-7
lines changed

src/runloop_api_client/sdk/__init__.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
SnapshotOps,
1515
BenchmarkOps,
1616
BlueprintOps,
17+
NetworkPolicyOps,
1718
StorageObjectOps,
1819
)
1920
from .agent import Agent
@@ -27,6 +28,7 @@
2728
AsyncSnapshotOps,
2829
AsyncBenchmarkOps,
2930
AsyncBlueprintOps,
31+
AsyncNetworkPolicyOps,
3032
AsyncStorageObjectOps,
3133
)
3234
from .devbox import Devbox, NamedShell
@@ -43,6 +45,7 @@
4345
from .benchmark_run import BenchmarkRun
4446
from .async_scenario import AsyncScenario
4547
from .async_snapshot import AsyncSnapshot
48+
from .network_policy import NetworkPolicy
4649
from .storage_object import StorageObject
4750
from .async_benchmark import AsyncBenchmark
4851
from .async_blueprint import AsyncBlueprint
@@ -51,6 +54,7 @@
5154
from .scenario_builder import ScenarioBuilder
5255
from .async_scenario_run import AsyncScenarioRun
5356
from .async_benchmark_run import AsyncBenchmarkRun
57+
from .async_network_policy import AsyncNetworkPolicy
5458
from .async_storage_object import AsyncStorageObject
5559
from .async_execution_result import AsyncExecutionResult
5660
from .async_scenario_builder import AsyncScenarioBuilder
@@ -76,6 +80,8 @@
7680
"AsyncSnapshotOps",
7781
"StorageObjectOps",
7882
"AsyncStorageObjectOps",
83+
"NetworkPolicyOps",
84+
"AsyncNetworkPolicyOps",
7985
# Resource classes
8086
"Agent",
8187
"AsyncAgent",
@@ -104,6 +110,8 @@
104110
"AsyncSnapshot",
105111
"StorageObject",
106112
"AsyncStorageObject",
113+
"NetworkPolicy",
114+
"AsyncNetworkPolicy",
107115
"NamedShell",
108116
"AsyncNamedShell",
109117
]

src/runloop_api_client/sdk/_types.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,13 @@
1919
BenchmarkUpdateParams,
2020
BlueprintCreateParams,
2121
DevboxUploadFileParams,
22+
NetworkPolicyListParams,
2223
DevboxCreateTunnelParams,
2324
DevboxDownloadFileParams,
2425
DevboxRemoveTunnelParams,
2526
DevboxSnapshotDiskParams,
27+
NetworkPolicyCreateParams,
28+
NetworkPolicyUpdateParams,
2629
DevboxReadFileContentsParams,
2730
DevboxWriteFileContentsParams,
2831
)
@@ -236,3 +239,15 @@ class SDKBenchmarkListRunsParams(RunSelfListParams, BaseRequestOptions):
236239

237240
class SDKBenchmarkRunListScenarioRunsParams(RunListScenarioRunsParams, BaseRequestOptions):
238241
pass
242+
243+
244+
class SDKNetworkPolicyCreateParams(NetworkPolicyCreateParams, LongRequestOptions):
245+
pass
246+
247+
248+
class SDKNetworkPolicyListParams(NetworkPolicyListParams, BaseRequestOptions):
249+
pass
250+
251+
252+
class SDKNetworkPolicyUpdateParams(NetworkPolicyUpdateParams, LongRequestOptions):
253+
pass

src/runloop_api_client/sdk/async_.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
SDKBenchmarkCreateParams,
2727
SDKBlueprintCreateParams,
2828
SDKDiskSnapshotListParams,
29+
SDKNetworkPolicyListParams,
30+
SDKNetworkPolicyCreateParams,
2931
SDKDevboxCreateFromImageParams,
3032
)
3133
from .._types import Timeout, NotGiven, not_given
@@ -39,6 +41,7 @@
3941
from .async_benchmark import AsyncBenchmark
4042
from .async_blueprint import AsyncBlueprint
4143
from ..lib.context_loader import TarFilter, build_directory_tar
44+
from .async_network_policy import AsyncNetworkPolicy
4245
from .async_storage_object import AsyncStorageObject
4346
from .async_scenario_builder import AsyncScenarioBuilder
4447
from ..types.object_create_params import ContentType
@@ -867,6 +870,60 @@ async def list(self, **params: Unpack[SDKBenchmarkListParams]) -> list[AsyncBenc
867870
return [AsyncBenchmark(self._client, item.id) for item in page.benchmarks]
868871

869872

873+
class AsyncNetworkPolicyOps:
874+
"""High-level async manager for creating and managing network policies.
875+
876+
Accessed via ``runloop.network_policy`` from :class:`AsyncRunloopSDK`, provides
877+
coroutines to create, retrieve, update, delete, and list network policies.
878+
879+
Example:
880+
>>> runloop = AsyncRunloopSDK()
881+
>>> policy = await runloop.network_policy.create(
882+
... name="my-policy",
883+
... allowed_hostnames=["github.com", "*.npmjs.org"],
884+
... )
885+
>>> policies = await runloop.network_policy.list()
886+
"""
887+
888+
def __init__(self, client: AsyncRunloop) -> None:
889+
"""Initialize AsyncNetworkPolicyOps.
890+
891+
:param client: AsyncRunloop client instance
892+
:type client: AsyncRunloop
893+
"""
894+
self._client = client
895+
896+
async def create(self, **params: Unpack[SDKNetworkPolicyCreateParams]) -> AsyncNetworkPolicy:
897+
"""Create a new network policy.
898+
899+
:param params: See :typeddict:`~runloop_api_client.sdk._types.SDKNetworkPolicyCreateParams` for available parameters
900+
:return: The newly created network policy
901+
:rtype: AsyncNetworkPolicy
902+
"""
903+
response = await self._client.network_policies.create(**params)
904+
return AsyncNetworkPolicy(self._client, response.id)
905+
906+
def from_id(self, network_policy_id: str) -> AsyncNetworkPolicy:
907+
"""Get an AsyncNetworkPolicy instance for an existing network policy ID.
908+
909+
:param network_policy_id: ID of the network policy
910+
:type network_policy_id: str
911+
:return: AsyncNetworkPolicy instance for the given ID
912+
:rtype: AsyncNetworkPolicy
913+
"""
914+
return AsyncNetworkPolicy(self._client, network_policy_id)
915+
916+
async def list(self, **params: Unpack[SDKNetworkPolicyListParams]) -> list[AsyncNetworkPolicy]:
917+
"""List all network policies, optionally filtered by parameters.
918+
919+
:param params: See :typeddict:`~runloop_api_client.sdk._types.SDKNetworkPolicyListParams` for available parameters
920+
:return: List of network policies
921+
:rtype: list[AsyncNetworkPolicy]
922+
"""
923+
page = self._client.network_policies.list(**params)
924+
return [AsyncNetworkPolicy(self._client, item.id) async for item in page]
925+
926+
870927
class AsyncRunloopSDK:
871928
"""High-level asynchronous entry point for the Runloop SDK.
872929
@@ -892,6 +949,8 @@ class AsyncRunloopSDK:
892949
:vartype snapshot: AsyncSnapshotOps
893950
:ivar storage_object: High-level async interface for storage object management
894951
:vartype storage_object: AsyncStorageObjectOps
952+
:ivar network_policy: High-level async interface for network policy management
953+
:vartype network_policy: AsyncNetworkPolicyOps
895954
896955
Example:
897956
>>> runloop = AsyncRunloopSDK() # Uses RUNLOOP_API_KEY env var
@@ -906,6 +965,7 @@ class AsyncRunloopSDK:
906965
benchmark: AsyncBenchmarkOps
907966
devbox: AsyncDevboxOps
908967
blueprint: AsyncBlueprintOps
968+
network_policy: AsyncNetworkPolicyOps
909969
scenario: AsyncScenarioOps
910970
scorer: AsyncScorerOps
911971
snapshot: AsyncSnapshotOps
@@ -953,6 +1013,7 @@ def __init__(
9531013
self.benchmark = AsyncBenchmarkOps(self.api)
9541014
self.devbox = AsyncDevboxOps(self.api)
9551015
self.blueprint = AsyncBlueprintOps(self.api)
1016+
self.network_policy = AsyncNetworkPolicyOps(self.api)
9561017
self.scenario = AsyncScenarioOps(self.api)
9571018
self.scorer = AsyncScorerOps(self.api)
9581019
self.snapshot = AsyncSnapshotOps(self.api)
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
"""NetworkPolicy resource class for asynchronous operations."""
2+
3+
from __future__ import annotations
4+
5+
from typing_extensions import Unpack, override
6+
7+
from ._types import BaseRequestOptions, LongRequestOptions, SDKNetworkPolicyUpdateParams
8+
from .._client import AsyncRunloop
9+
from ..types.network_policy_view import NetworkPolicyView
10+
11+
12+
class AsyncNetworkPolicy:
13+
"""Asynchronous wrapper around a network policy resource."""
14+
15+
def __init__(
16+
self,
17+
client: AsyncRunloop,
18+
network_policy_id: str,
19+
) -> None:
20+
"""Initialize the wrapper.
21+
22+
:param client: Generated AsyncRunloop client
23+
:type client: AsyncRunloop
24+
:param network_policy_id: NetworkPolicy ID returned by the API
25+
:type network_policy_id: str
26+
"""
27+
self._client = client
28+
self._id = network_policy_id
29+
30+
@override
31+
def __repr__(self) -> str:
32+
return f"<AsyncNetworkPolicy id={self._id!r}>"
33+
34+
@property
35+
def id(self) -> str:
36+
"""Return the network policy ID.
37+
38+
:return: Unique network policy ID
39+
:rtype: str
40+
"""
41+
return self._id
42+
43+
async def get_info(
44+
self,
45+
**options: Unpack[BaseRequestOptions],
46+
) -> NetworkPolicyView:
47+
"""Retrieve the latest network policy details.
48+
49+
:param options: Optional request configuration
50+
:return: API response describing the network policy
51+
:rtype: NetworkPolicyView
52+
"""
53+
return await self._client.network_policies.retrieve(
54+
self._id,
55+
**options,
56+
)
57+
58+
async def update(self, **params: Unpack[SDKNetworkPolicyUpdateParams]) -> NetworkPolicyView:
59+
"""Update the network policy.
60+
61+
:param params: See :typeddict:`~runloop_api_client.sdk._types.SDKNetworkPolicyUpdateParams` for available parameters
62+
:return: Updated network policy view
63+
:rtype: NetworkPolicyView
64+
"""
65+
return await self._client.network_policies.update(self._id, **params)
66+
67+
async def delete(
68+
self,
69+
**options: Unpack[LongRequestOptions],
70+
) -> NetworkPolicyView:
71+
"""Delete the network policy.
72+
73+
:param options: Optional long-running request configuration
74+
:return: API response acknowledging deletion
75+
:rtype: NetworkPolicyView
76+
"""
77+
return await self._client.network_policies.delete(
78+
self._id,
79+
**options,
80+
)

src/runloop_api_client/sdk/benchmark.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,5 @@ def list_runs(
163163
**params,
164164
)
165165
return [
166-
BenchmarkRun(self._client, run.id, run.benchmark_id)
167-
for run in page.runs
168-
if run.benchmark_id is not None
166+
BenchmarkRun(self._client, run.id, run.benchmark_id) for run in page.runs if run.benchmark_id is not None
169167
]
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
"""NetworkPolicy resource class for synchronous operations."""
2+
3+
from __future__ import annotations
4+
5+
from typing_extensions import Unpack, override
6+
7+
from ._types import BaseRequestOptions, LongRequestOptions, SDKNetworkPolicyUpdateParams
8+
from .._client import Runloop
9+
from ..types.network_policy_view import NetworkPolicyView
10+
11+
12+
class NetworkPolicy:
13+
"""Synchronous wrapper around a network policy resource."""
14+
15+
def __init__(
16+
self,
17+
client: Runloop,
18+
network_policy_id: str,
19+
) -> None:
20+
"""Initialize the wrapper.
21+
22+
:param client: Generated Runloop client
23+
:type client: Runloop
24+
:param network_policy_id: NetworkPolicy ID returned by the API
25+
:type network_policy_id: str
26+
"""
27+
self._client = client
28+
self._id = network_policy_id
29+
30+
@override
31+
def __repr__(self) -> str:
32+
return f"<NetworkPolicy id={self._id!r}>"
33+
34+
@property
35+
def id(self) -> str:
36+
"""Return the network policy ID.
37+
38+
:return: Unique network policy ID
39+
:rtype: str
40+
"""
41+
return self._id
42+
43+
def get_info(
44+
self,
45+
**options: Unpack[BaseRequestOptions],
46+
) -> NetworkPolicyView:
47+
"""Retrieve the latest network policy details.
48+
49+
:param options: Optional request configuration
50+
:return: API response describing the network policy
51+
:rtype: NetworkPolicyView
52+
"""
53+
return self._client.network_policies.retrieve(
54+
self._id,
55+
**options,
56+
)
57+
58+
def update(self, **params: Unpack[SDKNetworkPolicyUpdateParams]) -> NetworkPolicyView:
59+
"""Update the network policy.
60+
61+
:param params: See :typeddict:`~runloop_api_client.sdk._types.SDKNetworkPolicyUpdateParams` for available parameters
62+
:return: Updated network policy view
63+
:rtype: NetworkPolicyView
64+
"""
65+
return self._client.network_policies.update(self._id, **params)
66+
67+
def delete(
68+
self,
69+
**options: Unpack[LongRequestOptions],
70+
) -> NetworkPolicyView:
71+
"""Delete the network policy.
72+
73+
:param options: Optional long-running request configuration
74+
:return: API response acknowledging deletion
75+
:rtype: NetworkPolicyView
76+
"""
77+
return self._client.network_policies.delete(
78+
self._id,
79+
**options,
80+
)

0 commit comments

Comments
 (0)