Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
102ce1e
fix: update EnvdVersion from 0.1.1 to 0.2.10
AiRanthem Apr 15, 2026
9524cd2
feat: support negative TTL for never delete SandboxClaim (#277)
AiRanthem Apr 16, 2026
e3218dd
fix volume injection problem if user already specified poststarthook
BH4AWS Apr 16, 2026
dbd97a7
update labels when claiming (#201)
furykerry Apr 17, 2026
bc9af25
sandbox printcolumn add claimed
zmberg Apr 16, 2026
0862858
build(deps): bump actions/cache from 5.0.3 to 5.0.5
dependabot[bot] Apr 15, 2026
616acfd
update pod labels when claiming (#288)
furykerry Apr 19, 2026
da8890f
chore: add fmt-imports.sh and fmt imports (#272)
PersistentJZH Apr 19, 2026
bfbd82c
build(deps): bump crate-ci/typos from 1.44.0 to 1.45.1
dependabot[bot] Apr 15, 2026
c6b897a
build(deps): bump ruby/setup-ruby from 1.286.0 to 1.302.0
dependabot[bot] Apr 15, 2026
bf3af2a
feat: support inplace CPU resize for warm pool sandboxes
PersistentJZH Mar 29, 2026
ccf595b
feat(inplace-update): fail fast on CPU resize
PersistentJZH Apr 14, 2026
7b48acb
fix: harden inplace update flow and align sandbox claim/condition sem…
PersistentJZH Apr 17, 2026
cb1b8a4
fix(sandbox): mark inplace update in-progress per successful sub-step
PersistentJZH Apr 19, 2026
cdaf6bb
To optimize the CSI mounting logic, we replace the original serial mo…
BH4AWS Apr 19, 2026
ab2e5db
add ExtensionAnnotations to InPlaceUpdateOptions
zmberg Apr 19, 2026
fd22af6
feat(sandbox-controller): support rolling update of sandboxset (#256)
BITLiutianyang Apr 22, 2026
a527583
feat(e2b/keys): add pluggable KeyStorage with MySQL backend (#291)
AiRanthem Apr 22, 2026
8e44fd0
add docker sandbox-gateway workflows
ZhaoQing7892 Apr 23, 2026
19a3b6d
fix:gateway flows
ZhaoQing7892 Apr 23, 2026
acd52d2
fix(utils): panic when logging sidecar config error
lxs137 Apr 23, 2026
3070d64
feat(e2b): support custom CDP port for browser use
AiRanthem Apr 23, 2026
5267b9e
fix(e2b): enforce connect timeout extension semantics
AiRanthem Apr 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
- name: Checkout Actions Repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Check spelling with custom config file
uses: crate-ci/typos@631208b7aac2daa8b707f55e7331f9112b0e062d # v1.44.0
uses: crate-ci/typos@cf5f1c29a8ac336af8568821ec41919923b05a83 # v1.45.1
with:
config: ./typos.toml

Expand All @@ -49,7 +49,7 @@ jobs:
with:
go-version: ${{ env.GO_VERSION }}
- name: Cache Go Dependencies
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
Expand Down Expand Up @@ -90,7 +90,7 @@ jobs:
with:
go-version: ${{ env.GO_VERSION }}
- name: Cache Go Dependencies
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
Expand Down
29 changes: 29 additions & 0 deletions .github/workflows/docker-image-sandbox-gateway.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: Build and push sandbox-gateway

on:
workflow_dispatch:

# Declare default permissions as read only.
permissions: read-all

jobs:

build:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Login to Docker Hub
uses: docker/login-action@v4
with:
username: ${{ vars.DOCKERHUB_USERNAME }}
password: ${{ secrets.HUB_KRUISE }}
- name: Build the Docker image
run: |
docker buildx create --use --platform=linux/amd64,linux/arm64,linux/ppc64le --name multi-platform-builder
docker buildx ls
GATEWAY_IMG=openkruise/sandbox-gateway:${{ github.ref_name }} make docker-build-sandbox-gateway
docker push openkruise/sandbox-gateway:${{ github.ref_name }}
2 changes: 1 addition & 1 deletion .github/workflows/e2e-e2b-2.4.1.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ jobs:
version: ${{ env.KIND_VERSION }}

- name: Cache Docker images
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: /tmp/docker-images
key: ${{ runner.os }}-docker-${{ env.CODE_INTERPRETER_IMG }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/e2e-e2b-latest.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ jobs:
version: ${{ env.KIND_VERSION }}

- name: Cache Docker images
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: /tmp/docker-images
key: ${{ runner.os }}-docker-${{ env.CODE_INTERPRETER_IMG }}
Expand Down
135 changes: 135 additions & 0 deletions .github/workflows/e2e-e2b-mysql-latest.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
name: E2E for E2B SDK - latest (MySQL Key Storage)

on:
push:
branches:
- master
- release-*
pull_request: { }
workflow_dispatch: { }

# Declare default permissions as read only.
permissions: read-all


env:
# Common versions
GO_VERSION: '1.23'
KIND_VERSION: 'v0.22.0'
KIND_IMAGE: 'kindest/node:v1.32.0'
KIND_CLUSTER_NAME: 'ci-testing'
CONTROLLER_IMG: agent-sandbox-controller:latest
MANAGER_IMG: sandbox-manager:latest
RUNTIME_IMG: agent-runtime:latest
CODE_INTERPRETER_IMG: registry-ap-southeast-1.ack.aliyuncs.com/acs/code-interpreter:v1.6
INPLACE_UPDATE_IMG: registry-ap-southeast-1.ack.aliyuncs.com/acs/code-interpreter:v1.6-new
MYSQL_DATABASE: e2b_keys
MYSQL_ROOT_PASSWORD: ci-password

jobs:
sandbox:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
submodules: true
- name: Setup Go
uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0
with:
go-version: ${{ env.GO_VERSION }}
- name: Setup Kind Cluster
uses: helm/kind-action@ef37e7f390d99f746eb8b610417061a60e82a6cc # v1.14.0
with:
node_image: ${{ env.KIND_IMAGE }}
cluster_name: ${{ env.KIND_CLUSTER_NAME }}
config: ./test/kind-conf.yaml
version: ${{ env.KIND_VERSION }}

- name: Cache Docker images
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: /tmp/docker-images
key: ${{ runner.os }}-docker-${{ env.CODE_INTERPRETER_IMG }}
restore-keys: |
${{ runner.os }}-docker-

- name: Load cached external images
run: |
if [ -f /tmp/docker-images/code-interpreter.tar ]; then
echo "Using cached code-interpreter image"
docker load -i /tmp/docker-images/code-interpreter.tar
else
echo "Pulling code-interpreter image: ${CODE_INTERPRETER_IMG}"
docker pull ${CODE_INTERPRETER_IMG}
mkdir -p /tmp/docker-images
docker save ${CODE_INTERPRETER_IMG} -o /tmp/docker-images/code-interpreter.tar
echo "Cached code-interpreter image"
fi

- name: Load cached inplace update images
run: |
if [ -f /tmp/docker-images/inplace-update.tar ]; then
echo "Using cached inplace-update image"
docker load -i /tmp/docker-images/inplace-update.tar
else
echo "Building inplace-update image: ${INPLACE_UPDATE_IMG}"
docker build -t ${INPLACE_UPDATE_IMG} -f test/e2b/assets/Dockerfile .
mkdir -p /tmp/docker-images
docker save ${INPLACE_UPDATE_IMG} -o /tmp/docker-images/inplace-update.tar
echo "Cached inplace-update image"
fi

# Flow: build/load images → MySQL → deploy agents with MySQL key storage (no post-deploy patch) → E2E
- name: Build and load container images
run: |
make docker-build-manager
make docker-build-controller
make docker-build-runtime
kind load docker-image --name=${KIND_CLUSTER_NAME} ${CONTROLLER_IMG} || { echo >&2 "kind not installed or error loading image: ${CONTROLLER_IMG}"; exit 1; }
docker rmi ${CONTROLLER_IMG}
kind load docker-image --name=${KIND_CLUSTER_NAME} ${MANAGER_IMG} || { echo >&2 "kind not installed or error loading image: ${MANAGER_IMG}"; exit 1; }
docker rmi ${MANAGER_IMG}
kind load docker-image --name=${KIND_CLUSTER_NAME} ${RUNTIME_IMG} || { echo >&2 "kind not installed or error loading image: ${RUNTIME_IMG}"; exit 1; }
docker rmi ${RUNTIME_IMG}
kind load docker-image --name=${KIND_CLUSTER_NAME} ${CODE_INTERPRETER_IMG} || { echo >&2 "kind not installed or error loading image: ${CODE_INTERPRETER_IMG}"; exit 1; }
docker rmi ${CODE_INTERPRETER_IMG}
kind load docker-image --name=${KIND_CLUSTER_NAME} ${INPLACE_UPDATE_IMG} || { echo >&2 "kind not installed or error loading image: ${INPLACE_UPDATE_IMG}"; exit 1; }
docker rmi ${INPLACE_UPDATE_IMG}

- name: Deploy MySQL in Kind cluster
env:
MYSQL_DATABASE: ${{ env.MYSQL_DATABASE }}
MYSQL_ROOT_PASSWORD: ${{ env.MYSQL_ROOT_PASSWORD }}
run: bash hack/deploy-mysql-kind-ci.sh

- name: Install Kruise Agents
env:
MYSQL_DATABASE: ${{ env.MYSQL_DATABASE }}
MYSQL_ROOT_PASSWORD: ${{ env.MYSQL_ROOT_PASSWORD }}
run: |
MYSQL_DSN="root:${MYSQL_ROOT_PASSWORD}@tcp(mysql.sandbox-system.svc.cluster.local:3306)/${MYSQL_DATABASE}?charset=utf8mb4&parseTime=True&loc=Local"
{
echo ""
echo "# E2B MySQL key storage (appended by e2e-e2b-mysql-latest before deploy)"
echo "- op: add"
echo " path: /spec/template/spec/containers/0/args/-"
echo " value: --e2b-key-storage=mysql"
echo "- op: add"
echo " path: /spec/template/spec/containers/0/env/-"
printf ' value: {"name":"E2B_KEY_STORAGE_DSN","value":"%s"}\n' "${MYSQL_DSN}"
echo "- op: add"
echo " path: /spec/template/spec/containers/0/env/-"
printf ' value: {"name":"E2B_KEY_HASH_PEPPER","value":"%s"}\n' "e2e-test-pepper"
} >> config/sandbox-manager/configuration_patch.yaml
echo "deployment patch:"
cat config/sandbox-manager/configuration_patch.yaml
make deploy-agent-sandbox-controller
make deploy-sandbox-manager
bash hack/wait-agent-sandbox-controller.sh

- name: Run E2E Tests
run: |
export KUBECONFIG=/home/runner/.kube/config
export E2B_DOMAIN=localhost
export E2B_API_KEY=some-api-key
bash hack/run-e2b-e2e-test.sh
2 changes: 1 addition & 1 deletion .github/workflows/license.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Set up Ruby
uses: ruby/setup-ruby@90be1154f987f4dc0fe0dd0feedac9e473aa4ba8 # v1.286.0
uses: ruby/setup-ruby@7372622e62b60b3cb750dcd2b9e32c247ffec26a # v1.302.0
with:
ruby-version: 2.6
- name: Install dependencies
Expand Down
32 changes: 25 additions & 7 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -191,10 +191,28 @@ dmypy.json
# Cython debug symbols
cython_debug/

# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/

# Agents

### IMPORTANT FOR Contributors Using Coding Agents
# We recommend using Qoder as the AI coding tool, and we have placed the recommended subagents, skills, and rules in the .qoder directory.
# To avoid duplication, we have ignored the directories of other AI tools.
# If you use coding assistants such as Cursor or Claude Code, you can use symbolic links to link them to the .qoder directory.
# For example: `ln -s .qoder/skills .cursor/skills`
.cursor/
.claude/
.windsurf/
.codeium/
.copilot/
.tabnine/
.cody/
.aider/
.continue/
.supermaven/
.codegpt/
.gitbutler/
.pearai/
.trae/

.gomodcache/
.modcache/
.DS_Store
82 changes: 82 additions & 0 deletions .qoder/skills/generate-mysql-schema/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
---
name: generate-mysql-schema
description: Generate MySQL DDL (CREATE TABLE) and seed data SQL scripts by reading Go entity definitions in pkg/servers/e2b/keys/mysql.go. Use when the user asks for database schema SQL, table creation scripts, initialization SQL, or MySQL migration scripts for the key storage module.
---

# Generate MySQL Schema SQL

Generate MySQL DDL and seed data SQL scripts based on the latest Go entity definitions in the codebase.

## Workflow

### Step 1: Read Source Files

Read the following files to get the latest entity definitions and initialization logic:

1. `pkg/servers/e2b/keys/mysql.go` — Primary source:
- `TeamEntity` struct and its `TableName()` → table name
- `TeamAPIKeyEntity` struct and its `TableName()` → table name
- GORM tags (`gorm:"..."`) → column types, indexes, constraints
- `gorm.Model` embedded fields → `id`, `created_at`, `updated_at`, `deleted_at`
- `ensureAdminTeam()` → admin team seed data
- `ensureAdminKey()` → admin API key seed logic
- `AdminTeamUID` / `AdminKeyID` constants → well-known UUIDs

2. `pkg/servers/e2b/keys/keys.go` — For `AdminKeyID` and other constants if not in mysql.go.

3. `pkg/servers/e2b/models/` — For referenced model types if needed to understand field semantics.

### Step 2: Map GORM Tags to MySQL DDL

Apply these mapping rules:

| GORM Tag | MySQL DDL |
|----------|-----------|
| `gorm.Model` (embedded) | `id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY`, `created_at DATETIME(3)`, `updated_at DATETIME(3)`, `deleted_at DATETIME(3) DEFAULT NULL` + index on `deleted_at` |
| `type:varchar(N)` | `VARCHAR(N)` |
| `type:char(N)` | `CHAR(N)` |
| `not null` | `NOT NULL` |
| `uniqueIndex` | `UNIQUE INDEX` |
| `index` | `INDEX` |
| `column:xxx` | column name = `xxx` |
| No `column` tag | column name = snake_case of Go field name |

### Step 3: Generate DDL SQL

Output `CREATE TABLE IF NOT EXISTS` statements for each entity. Include:
- All columns with correct types and constraints
- Primary key
- Unique indexes and regular indexes (use GORM's default naming: `idx_<table>_<column>`)
- `deleted_at` index from `gorm.Model`
- `ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci`

### Step 4: Generate Seed Data SQL

Based on `ensureAdminTeam()` and `ensureAdminKey()` logic, generate:
- `INSERT ... ON DUPLICATE KEY UPDATE` for the admin team row using `AdminTeamUID`
- A comment explaining that the admin API key hash is computed at runtime via HMAC-SHA256(pepper, raw_key), so the seed SQL includes a placeholder

### Step 5: Output

Produce a single `.sql` file with:

```sql
-- =============================================================
-- Auto-generated from Go entities in pkg/servers/e2b/keys/mysql.go
-- Generated at: <current timestamp>
-- =============================================================

-- DDL
CREATE TABLE IF NOT EXISTS ...;
CREATE TABLE IF NOT EXISTS ...;

-- Seed Data
INSERT INTO ... ON DUPLICATE KEY UPDATE ...;
```

## Important Notes

- Always re-read source files on each invocation; do NOT rely on cached/stale definitions.
- If new entity structs or seed logic are added to `mysql.go`, include them automatically.
- Preserve the foreign-key relationship between `team_api_keys.team_id` and `teams.id` semantically (GORM does not auto-create FK constraints, but add a comment noting the relationship).
- The admin API key hash cannot be pre-computed in SQL because it depends on the runtime pepper config. Add a clear comment about this.
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and
fmt: ## Run go fmt against code.
go fmt ./...

.PHONY: fmt-imports
fmt-imports: ## Format Go import ordering using gci.
@bash hack/fmt-imports.sh

.PHONY: vet
vet: ## Run go vet against code.
go vet ./...
Expand Down
3 changes: 2 additions & 1 deletion api/v1alpha1/annotations.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ const (
// E2B annotations

const (
E2BPrefix = "e2b." + InternalPrefix
E2BPrefix = "e2b." + InternalPrefix
E2BLabelPrefix = "label:"

AnnotationEnvdAccessToken = E2BPrefix + "envd-access-token"
AnnotationEnvdURL = E2BPrefix + "envd-url"
Expand Down
6 changes: 6 additions & 0 deletions api/v1alpha1/sandbox_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,13 @@ import (

const (
// SandboxHashWithoutImageAndResources represents the key of sandbox hash without image and resources.
// Deprecated, use SandboxHashImmutablePart instead
SandboxHashWithoutImageAndResources = "sandbox.agents.kruise.io/hash-without-image-resources"

// SandboxHashImmutablePart represents the key of sandbox hash than exclude immutable part of sandbox
// e.g. metadata, image and resources
SandboxHashImmutablePart = "sandbox.agents.kruise.io/hash-immutable-part"

// PodLabelTemplateHash is pod template hash
PodLabelTemplateHash = "pod-template-hash"

Expand Down Expand Up @@ -255,6 +260,7 @@ const (
// +kubebuilder:storageversion
// +kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.phase"
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp"
// +kubebuilder:printcolumn:name="Claimed",type="string",JSONPath=".metadata.labels.agents\\.kruise\\.io/sandbox-claimed"
// +kubebuilder:printcolumn:name="shutdown_time",type="string",JSONPath=".spec.shutdownTime"
// +kubebuilder:printcolumn:name="pause_time",type="string",JSONPath=".spec.pauseTime"
// +kubebuilder:printcolumn:name="Message",type="string",JSONPath=".status.message"
Expand Down
Loading
Loading