Skip to content

Commit 331ef80

Browse files
committed
added regular secret example
1 parent 7589dcb commit 331ef80

4 files changed

Lines changed: 68 additions & 30 deletions

File tree

EXAMPLES.md

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Runnable examples live in [`examples/`](./examples).
1212
- [Devbox Snapshot and Resume](#devbox-snapshot-resume)
1313
- [Devbox Tunnel (HTTP Server Access)](#devbox-tunnel)
1414
- [MCP Hub + Claude Code + GitHub](#mcp-github-tools)
15-
- [Secrets with Devbox via Agent Gateway](#secrets-with-devbox)
15+
- [Secrets with Devbox and Agent Gateway](#secrets-with-devbox)
1616

1717
<a id="blueprint-with-build-context"></a>
1818
## Blueprint with Build Context
@@ -168,18 +168,19 @@ uv run pytest -m smoketest tests/smoketests/examples/
168168
**Source:** [`examples/mcp_github_tools.py`](./examples/mcp_github_tools.py)
169169

170170
<a id="secrets-with-devbox"></a>
171-
## Secrets with Devbox via Agent Gateway
171+
## Secrets with Devbox and Agent Gateway
172172

173-
**Use case:** Create a secret, proxy it into a devbox through agent gateway, verify the devbox only gets gateway credentials, and clean up.
173+
**Use case:** Use a normal secret for sensitive app data in the devbox and agent gateway for upstream API credentials that should never be exposed to the agent.
174174

175-
**Tags:** `secrets`, `devbox`, `agent-gateway`, `credentials`, `cleanup`
175+
**Tags:** `secrets`, `devbox`, `agent-gateway`, `credentials`, `environment-variables`, `cleanup`
176176

177177
### Workflow
178-
- Create a secret with a test credential
178+
- Create a secret for application data that should be available inside the devbox
179+
- Create a separate secret for an upstream API credential
179180
- Create an agent gateway config for an upstream API
180-
- Launch a devbox with the gateway wired to the secret
181-
- Verify the devbox receives a gateway URL and token instead of the raw secret
182-
- Shutdown the devbox and delete the gateway config and secret
181+
- Launch a devbox with one secret injected directly and the credential wired through agent gateway
182+
- Verify the devbox can read MAGIC_NUMBER while the upstream API credential is replaced with gateway values
183+
- Shutdown the devbox and delete the gateway config and both secrets
183184

184185
### Prerequisites
185186
- `RUNLOOP_API_KEY`

examples/registry.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
},
5656
{
5757
"slug": "secrets-with-devbox",
58-
"title": "Secrets with Devbox via Agent Gateway",
58+
"title": "Secrets with Devbox and Agent Gateway",
5959
"file_name": "secrets_with_devbox.py",
6060
"required_env": ["RUNLOOP_API_KEY"],
6161
"run": run_secrets_with_devbox_example,

examples/secrets_with_devbox.py

Lines changed: 57 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,22 @@
11
#!/usr/bin/env -S uv run python
22
"""
33
---
4-
title: Secrets with Devbox via Agent Gateway
4+
title: Secrets with Devbox and Agent Gateway
55
slug: secrets-with-devbox
6-
use_case: Create a secret, proxy it into a devbox through agent gateway, verify the devbox only gets gateway credentials, and clean up.
6+
use_case: Use a normal secret for sensitive app data in the devbox and agent gateway for upstream API credentials that should never be exposed to the agent.
77
workflow:
8-
- Create a secret with a test credential
8+
- Create a secret for application data that should be available inside the devbox
9+
- Create a separate secret for an upstream API credential
910
- Create an agent gateway config for an upstream API
10-
- Launch a devbox with the gateway wired to the secret
11-
- Verify the devbox receives a gateway URL and token instead of the raw secret
12-
- Shutdown the devbox and delete the gateway config and secret
11+
- Launch a devbox with one secret injected directly and the credential wired through agent gateway
12+
- Verify the devbox can read MAGIC_NUMBER while the upstream API credential is replaced with gateway values
13+
- Shutdown the devbox and delete the gateway config and both secrets
1314
tags:
1415
- secrets
1516
- devbox
1617
- agent-gateway
1718
- credentials
19+
- environment-variables
1820
- cleanup
1921
prerequisites:
2022
- RUNLOOP_API_KEY
@@ -33,34 +35,56 @@
3335
# Note: do NOT hardcode secret values in your code!
3436
# This is example code only; use environment variables instead!
3537
_EXAMPLE_GATEWAY_ENDPOINT = "https://api.example.com"
36-
_EXAMPLE_SECRET_VALUE = "example-upstream-api-key"
38+
_UPSTREAM_CREDENTIAL_VALUE = "example-upstream-api-key"
39+
_MAGIC_NUMBER_VALUE = "42"
3740

3841

3942
def recipe(ctx: RecipeContext) -> RecipeOutput:
40-
"""Create a secret, proxy it through an agent gateway, and verify the devbox only gets gateway credentials."""
43+
"""Demonstrate direct secret injection for app data and agent gateway protection for upstream credentials."""
4144
cleanup = ctx.cleanup
4245

4346
sdk = RunloopSDK()
4447
resources_created: list[str] = []
4548
checks: list[ExampleCheck] = []
4649

47-
secret_name = unique_name("agent-gateway-secret")
50+
magic_number_name = unique_name("magic-number-secret")
51+
upstream_credential_name = unique_name("agent-gateway-secret")
4852

49-
secret = sdk.secret.create(name=secret_name, value=_EXAMPLE_SECRET_VALUE)
50-
resources_created.append(f"secret:{secret_name}")
51-
cleanup.add(f"secret:{secret_name}", lambda: secret.delete())
53+
magic_number_secret = sdk.secret.create(name=magic_number_name, value=_MAGIC_NUMBER_VALUE)
54+
resources_created.append(f"secret:{magic_number_name}")
55+
cleanup.add(f"secret:{magic_number_name}", magic_number_secret.delete)
5256

53-
secret_info = secret.get_info()
57+
magic_number_info = magic_number_secret.get_info()
5458
checks.append(
5559
ExampleCheck(
56-
name="secret created successfully",
57-
passed=secret.name == secret_name and secret_info.id.startswith("sec_"),
58-
details=f"name={secret.name}, id={secret_info.id}",
60+
name="magic number secret created successfully",
61+
passed=(magic_number_secret.name == magic_number_name and magic_number_info.id.startswith("sec_")),
62+
details=f"name={magic_number_secret.name}, id={magic_number_info.id}",
5963
)
6064
)
6165

62-
# Hide upstream credentials from the devbox by routing requests through an
63-
# agent gateway config. This prevents direct secret exfiltration.
66+
upstream_credential_secret = sdk.secret.create(
67+
name=upstream_credential_name,
68+
value=_UPSTREAM_CREDENTIAL_VALUE,
69+
)
70+
resources_created.append(f"secret:{upstream_credential_name}")
71+
cleanup.add(f"secret:{upstream_credential_name}", upstream_credential_secret.delete)
72+
73+
upstream_credential_info = upstream_credential_secret.get_info()
74+
checks.append(
75+
ExampleCheck(
76+
name="upstream credential secret created successfully",
77+
passed=(
78+
upstream_credential_secret.name == upstream_credential_name
79+
and upstream_credential_info.id.startswith("sec_")
80+
),
81+
details=(f"name={upstream_credential_secret.name}, id={upstream_credential_info.id}"),
82+
)
83+
)
84+
85+
# Use direct secret injection when code inside the devbox legitimately needs
86+
# the secret value at runtime. Use agent gateway for upstream credentials
87+
# that should never be exposed to the agent.
6488
gateway_config = sdk.gateway_config.create(
6589
name=unique_name("agent-gateway-config"),
6690
endpoint=_EXAMPLE_GATEWAY_ENDPOINT,
@@ -81,10 +105,13 @@ def recipe(ctx: RecipeContext) -> RecipeOutput:
81105

82106
devbox = sdk.devbox.create(
83107
name=unique_name("agent-gateway-devbox"),
108+
secrets={
109+
"MAGIC_NUMBER": magic_number_secret.name,
110+
},
84111
gateways={
85112
"MY_API": {
86113
"gateway": gateway_config.id,
87-
"secret": secret.name,
114+
"secret": upstream_credential_secret.name,
88115
}
89116
},
90117
launch_parameters={
@@ -112,6 +139,16 @@ def recipe(ctx: RecipeContext) -> RecipeOutput:
112139
)
113140
)
114141

142+
magic_number_result = devbox.cmd.exec("echo $MAGIC_NUMBER")
143+
magic_number = magic_number_result.stdout().strip()
144+
checks.append(
145+
ExampleCheck(
146+
name="devbox receives plain secret when app needs the value",
147+
passed=(magic_number_result.exit_code == 0 and magic_number == _MAGIC_NUMBER_VALUE),
148+
details=(f"exit_code={magic_number_result.exit_code}, MAGIC_NUMBER={magic_number}"),
149+
)
150+
)
151+
115152
url_result = devbox.cmd.exec("echo $MY_API_URL")
116153
gateway_url = url_result.stdout().strip()
117154
checks.append(
@@ -130,7 +167,7 @@ def recipe(ctx: RecipeContext) -> RecipeOutput:
130167
passed=(
131168
token_result.exit_code == 0
132169
and gateway_token.startswith("gws_")
133-
and gateway_token != _EXAMPLE_SECRET_VALUE
170+
and gateway_token != _UPSTREAM_CREDENTIAL_VALUE
134171
),
135172
details=(f"exit_code={token_result.exit_code}, token_prefix={gateway_token[:4] or 'missing'}"),
136173
)

llms.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
- [Devbox lifecycle example](examples/devbox_from_blueprint_lifecycle.py): Create blueprint, launch devbox, run commands, cleanup
1414
- [Devbox snapshot and resume example](examples/devbox_snapshot_resume.py): Snapshot disk, resume from snapshot, verify state isolation
1515
- [MCP GitHub example](examples/mcp_github_tools.py): MCP Hub integration with Claude Code
16-
- [Secrets with Devbox example](examples/secrets_with_devbox.py): Create secret, protect it with agent gateway config, verify gateway credentials in devbox, cleanup
16+
- [Secrets with Devbox example](examples/secrets_with_devbox.py): Inject a normal secret for app runtime use, protect upstream credentials with agent gateway, verify both behaviors, cleanup
1717

1818
## API Reference
1919

0 commit comments

Comments
 (0)