[PR #427] [CLOSED] feat(custom-extension): include sandbox metadata in lifecycle hooks #429

Closed
opened 2026-10-29 14:23:20 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/kvcache-ai/AgentENV/pull/427
Author: @guozy18
Created: 10/23/2026
Status: ❌ Closed

Base: main ← Head: sync/custom-extension-user-metadata


📝 Commits (1)

  • 8cdee8b feat(custom extension): send user metadata

📊 Changes

21 files changed (+159 additions, -9 deletions)

View changed files

📝 docs/src/concepts/custom-extension/lifecycle-hooks.md (+4 -2)
📝 src/custom_extension_api/generated/docs/PatchCustomExtensionParamsHookRequest.md (+1 -0)
📝 src/custom_extension_api/generated/docs/StartFreshHookRequest.md (+1 -0)
📝 src/custom_extension_api/generated/docs/StartResumeHookRequest.md (+1 -0)
📝 src/custom_extension_api/generated/src/models/patch_custom_extension_params_hook_request.rs (+8 -1)
📝 src/custom_extension_api/generated/src/models/start_fresh_hook_request.rs (+4 -0)
📝 src/custom_extension_api/generated/src/models/start_resume_hook_request.rs (+4 -0)
📝 src/custom_extension_api/openapi.yml (+16 -0)
📝 src/orchestrator/launch_plan.rs (+4 -0)
📝 src/orchestrator/persistence/file_backed.rs (+1 -0)
📝 src/orchestrator/service.rs (+5 -1)
📝 src/orchestrator/tests.rs (+1 -0)
📝 src/sandbox/backend.rs (+1 -0)
📝 src/sandbox/custom_extension/client.rs (+43 -3)
📝 src/sandbox/firecracker/config.rs (+5 -0)
📝 src/sandbox/firecracker/factory.rs (+6 -2)
📝 src/sandbox/firecracker/sandbox.rs (+47 -0)
📝 src/sandbox/mock.rs (+1 -0)
📝 src/sandbox/mod.rs (+3 -0)
📝 tests/integration/posix_startup_pack.rs (+1 -0)

...and 1 more files

📄 Description

What

Include the sandbox's user metadata in start-fresh, start-resume and patch-params hook requests. Extensions can use the same metadata available in the sandbox API without a separate lookup.

Why

Hooks currently receive extension parameters and runtime identity but omit the create request's metadata. For example, if a snapshot was captured from a sandbox tagged team=alpha, a new sandbox created with team=beta must send beta to its hooks. If the new request omits metadata, the hooks must not receive alpha from snapshot provenance.

No linked issue. This draft adds optional context to the existing hook protocol.

Scope and non-goals

Hook request metadata, launch/resume propagation, generated bindings and lifecycle documentation. Existing hook failure statuses and resource cleanup remain in place.

Design and behavior changes

  • Fresh and snapshot launches send the new request's metadata. Upstream SnapshotSource::Sandbox.source_sandbox_metadata remains informational provenance and does not control launches. This differs from customExtensionParams, which can be inherited from a snapshot when no launch override is supplied.
  • The upstream path is create request -> SandboxLaunchConfig -> FirecrackerCommonConfig -> hook payload. It uses the existing Firecracker config rather than depending on the internal shared-backend extraction or another open PR.
  • Fork children retain their source sandbox's metadata; pause/resume retains the same sandbox's metadata.
  • Resume takes metadata from the sandbox record, including when an older paused backend config lacks the new field.
  • Parameter patches are forwarded verbatim with metadata in a separate field. Startup-pack recorder VMs continue to suppress hooks.
  • Existing hook errors retain their classification: extension 4xx maps to HTTP 400 for create/connect/patch and HTTP 409 for resume; extension 5xx remains a server error. Upstream fork returns child failures in its per-child result while a successfully executed batch keeps HTTP 201. The stop hook remains best-effort.
  • Upstream persistent-volume reservation, snapshot restoration and fork drive replacement remain in place. Snapshots with volumes still reject explicit volumeMounts, including an empty array.

Compatibility and operations

  • Public API or generated protocol: adds optional string-map metadata to three extension hook requests; OpenAPI bindings regenerated.
  • Configuration or defaults: unchanged. Requests without metadata omit the field.
  • Snapshot manifest, artifact layout, or storage format: optional serde-defaulted field in Firecracker paused common config; repository manifests unchanged.
  • Upgrade and rollback: existing paused records remain readable; resume recovers metadata from their sandbox record. Older readers ignore the optional config field. Strict extension request validators must allow metadata.
  • Host requirements, permissions, ports, or dependencies: unchanged. SandboxBackendFactory::build_from_paused_state now receives user metadata.

Validation

  • make custom-extension-client
  • cargo fmt --all -- --check
  • cargo clippy --locked --workspace --all-targets --all-features -- -D warnings
  • Documentation updated
cargo test --locked -p agentenv --lib: 1018 passed, 4 ignored
HTTP/KVM test against separately built server + ublk daemon: passed
- cold create, patch payload, fork metadata
- capture/publication, snapshot launch with absent and overriding metadata
- graceful shutdown/restart/resume after removing the new field from paused backend state
- upstream hook 422 -> API 400 behavior, sandbox/snapshot cleanup
Additional HTTP/KVM check on the same PR commit: passed
- mounted-volume deletion rejected while in use
- volume-aware fork retains parent metadata
- volume snapshot launch uses child metadata; explicit empty volumeMounts rejected
- metadata preserved through parameter patch and child pause/resume

Validation used this PR alone on upstream 9f62cbe, with all 829 tracked files checked against the tested source tree. It did not use fork/main or #428. The additional VM check reused the exact previously built #427 binary, whose hash was verified.

Generated tracked files match the regeneration output. Existing HTTP hook serialization/status tests and launch-provenance tests are included. Full OSS/P2P and unrelated suites were not run.

GitHub unit-tests is currently blocked before running tests by tikv-jemalloc-sys: inherited MAKEFLAGS=" -- PROFILE=debug -j ..." makes its nested make treat -j as a target. The identical failure is present on the unchanged upstream baseline and in this PR's job. The direct Cargo and isolated runtime results above are separate evidence, not a claim that all GitHub checks pass.

Risks and reviewer notes

Extensions receive operator-visible sandbox metadata in addition to extension parameters. Review the launch-only behavior for snapshots and record-based restore for legacy paused state.

Checklist

  • One coherent change; no dependency on another open PR.
  • Original tests retained and the snapshot provenance regression strengthened.
  • No credentials or private registry information in the diff.
  • Schema and generated clients updated together.

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/kvcache-ai/AgentENV/pull/427 **Author:** [@guozy18](https://github.com/guozy18) **Created:** 10/23/2026 **Status:** ❌ Closed **Base:** `main` ← **Head:** `sync/custom-extension-user-metadata` --- ### 📝 Commits (1) - [`8cdee8b`](https://github.com/kvcache-ai/AgentENV/commit/8cdee8bc32439cf27849376f59f34dc028edaa65) feat(custom extension): send user metadata ### 📊 Changes **21 files changed** (+159 additions, -9 deletions) <details> <summary>View changed files</summary> 📝 `docs/src/concepts/custom-extension/lifecycle-hooks.md` (+4 -2) 📝 `src/custom_extension_api/generated/docs/PatchCustomExtensionParamsHookRequest.md` (+1 -0) 📝 `src/custom_extension_api/generated/docs/StartFreshHookRequest.md` (+1 -0) 📝 `src/custom_extension_api/generated/docs/StartResumeHookRequest.md` (+1 -0) 📝 `src/custom_extension_api/generated/src/models/patch_custom_extension_params_hook_request.rs` (+8 -1) 📝 `src/custom_extension_api/generated/src/models/start_fresh_hook_request.rs` (+4 -0) 📝 `src/custom_extension_api/generated/src/models/start_resume_hook_request.rs` (+4 -0) 📝 `src/custom_extension_api/openapi.yml` (+16 -0) 📝 `src/orchestrator/launch_plan.rs` (+4 -0) 📝 `src/orchestrator/persistence/file_backed.rs` (+1 -0) 📝 `src/orchestrator/service.rs` (+5 -1) 📝 `src/orchestrator/tests.rs` (+1 -0) 📝 `src/sandbox/backend.rs` (+1 -0) 📝 `src/sandbox/custom_extension/client.rs` (+43 -3) 📝 `src/sandbox/firecracker/config.rs` (+5 -0) 📝 `src/sandbox/firecracker/factory.rs` (+6 -2) 📝 `src/sandbox/firecracker/sandbox.rs` (+47 -0) 📝 `src/sandbox/mock.rs` (+1 -0) 📝 `src/sandbox/mod.rs` (+3 -0) 📝 `tests/integration/posix_startup_pack.rs` (+1 -0) _...and 1 more files_ </details> ### 📄 Description ## What Include the sandbox's user metadata in `start-fresh`, `start-resume` and `patch-params` hook requests. Extensions can use the same metadata available in the sandbox API without a separate lookup. ## Why Hooks currently receive extension parameters and runtime identity but omit the create request's metadata. For example, if a snapshot was captured from a sandbox tagged `team=alpha`, a new sandbox created with `team=beta` must send `beta` to its hooks. If the new request omits metadata, the hooks must not receive `alpha` from snapshot provenance. ## Related issue No linked issue. This draft adds optional context to the existing hook protocol. ## Scope and non-goals Hook request metadata, launch/resume propagation, generated bindings and lifecycle documentation. Existing hook failure statuses and resource cleanup remain in place. ## Design and behavior changes - Fresh and snapshot launches send the new request's metadata. Upstream `SnapshotSource::Sandbox.source_sandbox_metadata` remains informational provenance and does not control launches. This differs from `customExtensionParams`, which can be inherited from a snapshot when no launch override is supplied. - The upstream path is create request -> `SandboxLaunchConfig` -> `FirecrackerCommonConfig` -> hook payload. It uses the existing Firecracker config rather than depending on the internal shared-backend extraction or another open PR. - Fork children retain their source sandbox's metadata; pause/resume retains the same sandbox's metadata. - Resume takes metadata from the sandbox record, including when an older paused backend config lacks the new field. - Parameter patches are forwarded verbatim with metadata in a separate field. Startup-pack recorder VMs continue to suppress hooks. - Existing hook errors retain their classification: extension 4xx maps to HTTP 400 for create/connect/patch and HTTP 409 for resume; extension 5xx remains a server error. Upstream fork returns child failures in its per-child result while a successfully executed batch keeps HTTP 201. The stop hook remains best-effort. - Upstream persistent-volume reservation, snapshot restoration and fork drive replacement remain in place. Snapshots with volumes still reject explicit `volumeMounts`, including an empty array. ## Compatibility and operations - Public API or generated protocol: adds optional string-map `metadata` to three extension hook requests; OpenAPI bindings regenerated. - Configuration or defaults: unchanged. Requests without metadata omit the field. - Snapshot manifest, artifact layout, or storage format: optional serde-defaulted field in Firecracker paused common config; repository manifests unchanged. - Upgrade and rollback: existing paused records remain readable; resume recovers metadata from their sandbox record. Older readers ignore the optional config field. Strict extension request validators must allow `metadata`. - Host requirements, permissions, ports, or dependencies: unchanged. `SandboxBackendFactory::build_from_paused_state` now receives user metadata. ## Validation - [x] `make custom-extension-client` - [x] `cargo fmt --all -- --check` - [x] `cargo clippy --locked --workspace --all-targets --all-features -- -D warnings` - [x] Documentation updated ```text cargo test --locked -p agentenv --lib: 1018 passed, 4 ignored HTTP/KVM test against separately built server + ublk daemon: passed - cold create, patch payload, fork metadata - capture/publication, snapshot launch with absent and overriding metadata - graceful shutdown/restart/resume after removing the new field from paused backend state - upstream hook 422 -> API 400 behavior, sandbox/snapshot cleanup Additional HTTP/KVM check on the same PR commit: passed - mounted-volume deletion rejected while in use - volume-aware fork retains parent metadata - volume snapshot launch uses child metadata; explicit empty volumeMounts rejected - metadata preserved through parameter patch and child pause/resume ``` Validation used this PR alone on upstream `9f62cbe`, with all 829 tracked files checked against the tested source tree. It did not use fork/main or #428. The additional VM check reused the exact previously built #427 binary, whose hash was verified. Generated tracked files match the regeneration output. Existing HTTP hook serialization/status tests and launch-provenance tests are included. Full OSS/P2P and unrelated suites were not run. GitHub `unit-tests` is currently blocked before running tests by `tikv-jemalloc-sys`: inherited `MAKEFLAGS=" -- PROFILE=debug -j ..."` makes its nested make treat `-j` as a target. The identical failure is present on the unchanged [upstream baseline](https://github.com/kvcache-ai/AgentENV/actions/runs/39892803013/job/120216239840) and in [this PR's job](https://github.com/kvcache-ai/AgentENV/actions/runs/39910415804/job/120271856972). The direct Cargo and isolated runtime results above are separate evidence, not a claim that all GitHub checks pass. ## Risks and reviewer notes Extensions receive operator-visible sandbox metadata in addition to extension parameters. Review the launch-only behavior for snapshots and record-based restore for legacy paused state. ## Checklist - [x] One coherent change; no dependency on another open PR. - [x] Original tests retained and the snapshot provenance regression strengthened. - [x] No credentials or private registry information in the diff. - [x] Schema and generated clients updated together. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-10-29 14:23:20 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
kvcache-ai/AgentENV#429
No description provided.