@e2b/python-sdk@2.45.0
2 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
f89f8c3f96 |
Add secrets management to JS and Python SDKs (#1728)
## Summary Implements Secrets Management in the SDK per the [Secrets Vault SDK proposal](https://app.notion.com/p/3bab8c29687380b6a8f3e2ecae3f1b50) and the backend Secrets API. Linear: [SDK-133](https://linear.app/e2b/issue/SDK-133/sdk-for-managing-secrets). Docs: [e2b-dev/docs#379](https://github.com/e2b-dev/docs/pull/379). Spec sync: bumps `spec/infra-ref` to `e19a12b8` (the commit that adds the Secrets API), adds the `secrets` tag to the `redocly.yaml` filters, and regenerates via `make codegen` (the regen also pulls in unrelated upstream spec updates, e.g. the `Error.errorCode` field). The js-sdk envd schema generation now bundles through a new `envd` redocly api that filters out operations the upstream spec marks `x-internal: true` (orchestrator control plane: `/init`, `/freeze`, `/unfreeze`, `/collapse`, `/fsfreeze`, `/fsthaw`) plus their now-unused component schemas, so they no longer appear in `src/envd/schema.gen.ts`. The existing `Secret` class (previously only the `iamToken`/`iam_token` workload-identity helper) becomes the secrets management surface, equivalent across JS, sync Python (`Secret`), and async Python (`AsyncSecret`): ```typescript Secret.create(name, value, opts?): Promise<SecretInfo> // POST /secrets Secret.update(secret, value, opts?): Promise<SecretInfo> // POST /secrets/{secretID} (rotates to a new version) Secret.getInfo(secret, opts?): Promise<SecretInfo> // GET /secrets/{secretID} Secret.list(opts?): SecretPaginator // GET /secrets (cursor-paginated) Secret.exists(secret, opts?): Promise<boolean> // 200 → true, 404 → false Secret.destroy(secret, opts?): Promise<boolean> // 204 → true, 404 → false Secret.fill(secret): string // local marker formatting, no network call ``` Design decisions per the proposal: - **Values are write-only**: `SecretInfo` carries only metadata (`secretId`, `name`, `version`, `metadata`, `createdAt`, `updatedAt`); no read surface or error message includes a value. - `update`/`getInfo` throw `SecretNotFoundError` / `SecretNotFoundException` on 404 (subclass of `NotFoundError` / `NotFoundException`, so generic not-found catches keep working; general failures throw the new `SecretError` / `SecretException`); `exists`/`destroy` map 404 to `false` instead. - `secret` selector accepts either the `sec_` ID or the canonical lowercase name (backend resolves both). - `fill` returns the `${e2b.secrets.name}` marker for use in a network rule's request transform — always the current version, purely local. The egress proxy replaces the marker with the secret's current value when it forwards a matching request; unresolvable markers fail open (the request is forwarded with the affected headers omitted). - Version-management endpoints from the proposal are marked TBD and not in the committed backend contract, so they are intentionally not implemented. Python moves `e2b/secret.py` to an `e2b/secret/` package (`base.py` shares `fill`/`iam_token`, `secret_sync.py` / `secret_async.py` mirror each other); `from e2b import Secret` is unchanged. Usage: ```typescript import { Sandbox, Secret } from 'e2b' const info = await Secret.create('stripe_api_key', 'sk_live_...', { metadata: { env: 'prod' } }) await Secret.update('stripe_api_key', 'sk_live_new...') // rotate → version 2 // Inject into matching outbound requests via a network rule's transform: const sandbox = await Sandbox.create({ network: { allowOut: ({ rules }) => [...rules.keys()], denyOut: ({ allTraffic }) => [allTraffic], rules: { 'api.stripe.com': [ { transform: { headers: { Authorization: `Bearer ${Secret.fill('stripe_api_key')}` }, }, }, ], }, }, }) await Secret.destroy('stripe_api_key') ``` ```python from e2b import AsyncSecret info = await AsyncSecret.create("stripe_api_key", "sk_live_...", metadata={"env": "prod"}) paginator = AsyncSecret.list(limit=100) while paginator.has_next: secrets = await paginator.next_items() print(AsyncSecret.fill("stripe_api_key")) # ${e2b.secrets.stripe_api_key} ``` Tests: msw-mocked JS suite (`tests/secret/secret.test.ts`) and monkeypatched sync/async Python suites covering CRUD, pagination, 404 semantics, and `fill`. `pnpm run format/lint/typecheck` pass; changeset included (minor for `e2b` and `@e2b/python-sdk`). Link to Devin session: https://app.devin.ai/sessions/175095f75cbe42df8710718a1ff2a6a3 Requested by: @mishushakov --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: mish@e2b.dev <mish@e2b.dev> |
||
|
|
4fcf7cb150 |
feat: sync API specs from infra and belt with Copybara (#1564)
The specs in `spec/` were copied from their source repos by hand and had
drifted ~2,400 lines behind infra, so they are now imported with
Copybara (`copy.bara.sky`, run in a pinned Docker image by
`scripts/fetch-spec.sh`): `make codegen` re-fetches them at the commits
pinned in `spec/infra-ref` and `spec/belt-ref` before generating, and
the generated-files CI check fails if the tracked copies don't match the
pins. Regenerating from the current pins picks up the accumulated spec
changes in the generated JS/Python clients (renamed request schemas,
`SandboxNetworkConfig`, `SandboxIam` workload identity,
`FILE_TYPE_SYMLINK`, access-token auth deprecation, volume path-metadata
tweaks). The one handwritten SDK change follows from that: the public
`FileType` enums gain a `SYMLINK` member (JS and both Python surfaces)
so entries envd reports as symlinks show up in `files.list()` and
`getInfo()`/`get_info()` instead of being silently skipped as unknown
types. The custom `spec/remove_extra_tags.py` tag-filtering script is
replaced by Redocly CLI's `filter-in` decorator (`redocly.yaml`), which
produces identical generated JS output; a `filter-out` decorator
additionally drops any operation or component schema the upstream specs
mark `x-not-implemented: true` (currently the SOCKS5
`SandboxEgressProxyConfig`/`egressProxy` surface, which infra flagged as
spec-only); each SDK's bundle now goes to its own gitignored
`spec/openapi_generated.<api>.yml` instead of both pipelines overwriting
one shared file; Python client models now list fields in spec order
instead of alphabetical (mechanical reordering only — construct models
with keyword args). Spec fetches try whatever GitHub token is available
and fall back to the tracked copies with a warning (the public infra
specs also fetch anonymously); in CI a short-lived belt-scoped token is
minted from the org-wide Autofixer GitHub App (no new secrets), so fork
PRs simply fall back for the belt spec; the CI workflows also cache the
Copybara image alongside the codegen image, and the previously ignored
`CODEGEN_IMAGE` env is honored by the Makefile.
## Usage
```sh
# update the specs: bump a pin, then regenerate
echo <infra-commit-sha> > spec/infra-ref
make codegen
# fetch a single spec without regenerating
pnpm fetch:api-spec # spec/openapi.yml from infra
pnpm fetch:envd-spec # spec/envd/ from infra
pnpm fetch:volume-spec # spec/openapi-volumecontent.yml from belt
# try the latest spec without touching the pin
E2B_INFRA_REF=main pnpm fetch:api-spec
# change which endpoint tags an SDK exposes
$EDITOR redocly.yaml && make codegen
```
```ts
// symlinks are now visible in the filesystem API (JS; same shape in Python)
const entries = await sandbox.files.list('/home/user')
const link = entries.find((e) => e.type === FileType.SYMLINK)
console.log(link?.symlinkTarget)
```
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
|