From 4857ec762abb9b62636744534a4cad716dd070a9 Mon Sep 17 00:00:00 2001 From: SaladDay <1203511142@qq.com> Date: Wed, 28 Oct 2026 07:10:21 +0000 Subject: [PATCH 1/2] Move microsandbox to the v0.7.11 fork The SDK and its FFI come from the oac branch of SaladDay/microsandbox (upstream v0.7.11 plus the restore DNS rebind and strict options); the runtime is the official v0.7.11 release. --- docs/maintainers.md | 8 ++++--- docs/zh/maintainers.md | 10 ++++---- scripts/build-core-distribution.sh | 4 ++-- scripts/build-microsandbox-provider.py | 23 ++++++++----------- scripts/core-distribution-manifest.py | 6 ++--- .../internal/sandbox/microsandbox/types.go | 2 +- .../tools/microsandbox-provider/README.md | 8 +++---- .../tools/microsandbox-provider/bootstrap.go | 4 ++-- .../tools/microsandbox-provider/deployment.go | 2 +- .../core/tools/microsandbox-provider/go.mod | 13 ++++++----- .../core/tools/microsandbox-provider/go.sum | 4 ++-- .../core/tools/microsandbox-provider/main.go | 13 +++++++---- .../microsandbox-provider/sdk_release_test.go | 4 ++-- .../snapshot_observation_test.go | 2 +- 14 files changed, 54 insertions(+), 49 deletions(-) diff --git a/docs/maintainers.md b/docs/maintainers.md index 549989e06..b1eaaf775 100644 --- a/docs/maintainers.md +++ b/docs/maintainers.md @@ -33,7 +33,7 @@ make build-core-distribution | `OAC_NATIVE_INSTALLER_BUILD_DIR` | Native installer catalog directory; see [Native installers](#native-installers) | | `CORE_DISTRIBUTION_BUILD_DIR` | Output directory under `~/.oac`. Default: `~/.oac/build/core-distribution` | | `CORE_DISTRIBUTION_BUILD_NETWORK` | Docker build network: `default`, `host` or `none` | -| `CORE_DISTRIBUTION_MICROSANDBOX_ARCHIVE` | Cached microsandbox release archive. Default: `~/.oac/cache/microsandbox-v0.7.8-linux-x86_64.tar.gz`, downloaded when missing | +| `CORE_DISTRIBUTION_MICROSANDBOX_ARCHIVE` | Cached microsandbox release archive. Default: `~/.oac/cache/microsandbox-v0.7.11-linux-x86_64.tar.gz`, downloaded when missing | | `CORE_DISTRIBUTION_DATABASE_IMAGE` | PostgreSQL 16 image; the default is the linux/amd64 manifest of the index in `deploy/compose/database-image.txt` | The build reuses the Core, Web, Runtime, SDK and helper builders. The manifest records the commit and its source tree, image config and OCI manifest digests, the Runtime OCI manifest digest, the microsandbox runtime and firmware hashes, and the size and SHA-256 of every Runtime and node artifact; native installers carry only their SHA-256 in the [catalog](#native-installers). Output is the control archive and its `.sha256`, the optional offline archive, and the versioned Runtime, node and native installer assets. Nothing is published. Rebuilding into a directory that already holds this commit's distribution is refused. @@ -112,9 +112,11 @@ make build-microsandbox-provider make check-microsandbox-provider ``` -The helper is written to `~/.oac/build/microsandbox-provider/oac-microsandbox-provider`. Its separate Go module pins the official microsandbox SDK source commit. Both commands and the distribution build use `scripts/build-microsandbox-provider.py`: it stages the module dependencies, verifies the matching official FFI release checksum, fills the SDK's empty release bundle and builds with that FFI embedded. The SDK source is unchanged and no vendored binary is committed. Use this entry point rather than invoking `go build` directly; never build production with the SDK's `microsandbox_ffi_path` tag. Core itself stays a CGO-disabled build. The helper needs glibc and runs only on nodes. +The helper is written to `~/.oac/build/microsandbox-provider/oac-microsandbox-provider`. Its separate Go module pins the microsandbox SDK from the fork described below. Both commands and the distribution build use `scripts/build-microsandbox-provider.py`: it stages the module dependencies, verifies the checksum of the fork's FFI release, fills the SDK's empty release bundle and builds with that FFI embedded. No vendored binary is committed. Use this entry point rather than invoking `go build` directly; never build production with the SDK's `microsandbox_ffi_path` tag. Core itself stays a CGO-disabled build. The helper needs glibc and runs only on nodes. -**microsandbox runtime.** The distribution uses the official [v0.7.8 release](https://github.com/superradcompany/microsandbox/releases/tag/v0.7.8) archive `microsandbox-linux-x86_64.tar.gz`, SHA256 `86f9f72dc3e639c7175bc07909b4b63ce412517c1ef8a2e1921171af5682fded` (`RUNTIME_ARCHIVE_SHA256` in `scripts/core-distribution-manifest.py`). The build verifies the checksum before extracting `msb` and `libkrunfw.so.5.6.1` and records both files' hashes. The helper checks those hashes on every call and never installs or upgrades them. +**microsandbox runtime.** The distribution uses the official [v0.7.11 release](https://github.com/superradcompany/microsandbox/releases/tag/v0.7.11) archive `microsandbox-linux-x86_64.tar.gz`, SHA256 `5fc2206fbe35b471743bd5af15e3931cd2439a0c8b8e6ef08a493ddabcdc1b4c` (`RUNTIME_ARCHIVE_SHA256` in `scripts/core-distribution-manifest.py`). The build verifies the checksum before extracting `msb` and `libkrunfw.so.5.6.1` and records both files' hashes. The helper checks those hashes on every call and never installs or upgrades them. + +**microsandbox fork.** The SDK and its FFI come from the `oac` branch of [SaladDay/microsandbox](https://github.com/SaladDay/microsandbox/tree/oac): an upstream release tag plus a short queue of patches, listed by `git log v0.7.11..oac`. Each patch is also proposed upstream and dropped once an upstream release carries it. Pushing a tag `oac-v-` builds the Linux amd64 FFI in the same manylinux 2.28 container as upstream releases and attaches it, with its SHA256, to a release of that tag. To move to a new tag, point the SDK `replace` in `services/core/tools/microsandbox-provider/go.mod` at the tagged commit and update `FFI_URL` and `FFI_SHA256` in `scripts/build-microsandbox-provider.py`. The runtime stays the official release of the same upstream version. ### Standalone Core builds diff --git a/docs/zh/maintainers.md b/docs/zh/maintainers.md index ece31ac1a..7a6a664f5 100644 --- a/docs/zh/maintainers.md +++ b/docs/zh/maintainers.md @@ -1,7 +1,7 @@ --- title: "构建并发布 OpenAgentCore" source: docs/maintainers.md -source_hash: d222cc5fe4c258dcc4e8956c08757276dc6340511c5eaf2e0fba2698e6718761 +source_hash: 7a78188dee1e8010194c3aef618b33027f1fb1fd2401b4d80c9b21beea85d34b --- 本指南面向负责构建和发布 OpenAgentCore 的维护者。要安装 Core 和 Web,请按 [安装 Core 和 Web](getting-started/install.md) 操作。安装程序代码遵循的规则见 [部署](https://github.com/MiniMax-AI/OpenAgentCore/blob/main/deploy/README.md) 和 [节点安装程序](https://github.com/MiniMax-AI/OpenAgentCore/blob/main/deploy/node/README.md);必需检查见 [CONTRIBUTING](https://github.com/MiniMax-AI/OpenAgentCore/blob/main/CONTRIBUTING.md#required-checks)。 @@ -35,7 +35,7 @@ make build-core-distribution | `OAC_NATIVE_INSTALLER_BUILD_DIR` | 原生安装程序目录;请参阅[原生安装程序](#native-installers) | | `CORE_DISTRIBUTION_BUILD_DIR` | `~/.oac` 下的输出目录。默认值:`~/.oac/build/core-distribution` | | `CORE_DISTRIBUTION_BUILD_NETWORK` | Docker 构建网络:`default`、`host` 或 `none` | -| `CORE_DISTRIBUTION_MICROSANDBOX_ARCHIVE` | 已缓存的 microsandbox 发布归档。默认值:`~/.oac/cache/microsandbox-v0.7.8-linux-x86_64.tar.gz`,缺失时下载 | +| `CORE_DISTRIBUTION_MICROSANDBOX_ARCHIVE` | 已缓存的 microsandbox 发布归档。默认值:`~/.oac/cache/microsandbox-v0.7.11-linux-x86_64.tar.gz`,缺失时下载 | | `CORE_DISTRIBUTION_DATABASE_IMAGE` | PostgreSQL 16 镜像;默认值为 `deploy/compose/database-image.txt` 中索引的 linux/amd64 清单 | 构建过程会复用 Core、Web、Runtime、SDK 和辅助程序构建器。清单会记录提交及其源代码树、镜像配置及 OCI 清单摘要、Runtime OCI 清单摘要、microsandbox 运行时和固件哈希,以及每个 Runtime 和节点构件的大小与 SHA-256;原生安装程序在[目录](#native-installers)中仅记录其 SHA-256。输出包括控制归档及其 `.sha256`、可选的离线归档,以及带版本号的 Runtime、节点和原生安装程序资源。此过程不会发布任何内容。如果目标目录中已包含此提交的分发包,重建会拒绝执行。 @@ -114,9 +114,11 @@ make build-microsandbox-provider make check-microsandbox-provider ``` -该辅助程序会写入 `~/.oac/build/microsandbox-provider/oac-microsandbox-provider`。其独立的 Go 模块固定官方 microsandbox SDK 源码提交。上述两个命令与分发构建均使用 `scripts/build-microsandbox-provider.py`:它暂存模块依赖,验证匹配的官方 FFI 发行文件校验和,填充 SDK 的空发行包,并构建嵌入该 FFI 的程序。SDK 源码保持不变,仓库不提交 vendored 二进制文件。请使用此入口,而非直接调用 `go build`;构建生产版本时,绝不能使用该 SDK 的 `microsandbox_ffi_path` 标签。Core 本身仍采用禁用 CGO 的构建。该辅助程序需要 glibc,并且只能在节点上运行。 +该辅助程序会写入 `~/.oac/build/microsandbox-provider/oac-microsandbox-provider`。其独立的 Go 模块固定来自下文所述 fork 的 microsandbox SDK。上述两个命令与分发构建均使用 `scripts/build-microsandbox-provider.py`:它暂存模块依赖,验证 fork 的 FFI 发行文件校验和,填充 SDK 的空发行包,并构建嵌入该 FFI 的程序。仓库不提交 vendored 二进制文件。请使用此入口,而非直接调用 `go build`;构建生产版本时,绝不能使用该 SDK 的 `microsandbox_ffi_path` 标签。Core 本身仍采用禁用 CGO 的构建。该辅助程序需要 glibc,并且只能在节点上运行。 -**microsandbox 运行时。** 分发包使用官方的 [v0.7.8 release](https://github.com/superradcompany/microsandbox/releases/tag/v0.7.8) 归档 `microsandbox-linux-x86_64.tar.gz`,SHA256 为 `86f9f72dc3e639c7175bc07909b4b63ce412517c1ef8a2e1921171af5682fded`(即 `scripts/core-distribution-manifest.py` 中的 `RUNTIME_ARCHIVE_SHA256`)。构建过程会先验证校验和,再解压 `msb` 和 `libkrunfw.so.5.6.1`,并记录这两个文件的哈希。辅助程序会在每次调用时检查这些哈希,并且绝不安装或升级它们。 +**microsandbox 运行时。** 分发包使用官方的 [v0.7.11 release](https://github.com/superradcompany/microsandbox/releases/tag/v0.7.11) 归档 `microsandbox-linux-x86_64.tar.gz`,SHA256 为 `5fc2206fbe35b471743bd5af15e3931cd2439a0c8b8e6ef08a493ddabcdc1b4c`(即 `scripts/core-distribution-manifest.py` 中的 `RUNTIME_ARCHIVE_SHA256`)。构建过程会先验证校验和,再解压 `msb` 和 `libkrunfw.so.5.6.1`,并记录这两个文件的哈希。辅助程序会在每次调用时检查这些哈希,并且绝不安装或升级它们。 + +**microsandbox fork。** SDK 及其 FFI 来自 [SaladDay/microsandbox](https://github.com/SaladDay/microsandbox/tree/oac) 的 `oac` 分支:一个上游发布标签加上一小队补丁,补丁列表见 `git log v0.7.11..oac`。每个补丁同时向上游提交,上游发布包含它之后就从队列中删除。推送 `oac-v<上游版本>-` 标签会在与上游发布相同的 manylinux 2.28 容器中构建 Linux amd64 FFI,并连同其 SHA256 附加到该标签的 release。要换到新标签,把 `services/core/tools/microsandbox-provider/go.mod` 中 SDK 的 `replace` 指向该标签的提交,并更新 `scripts/build-microsandbox-provider.py` 中的 `FFI_URL` 和 `FFI_SHA256`。运行时仍使用同一上游版本的官方发布。 ### 独立 Core 构建 {#standalone-core-builds} diff --git a/scripts/build-core-distribution.sh b/scripts/build-core-distribution.sh index 36340032b..4b51abb58 100755 --- a/scripts/build-core-distribution.sh +++ b/scripts/build-core-distribution.sh @@ -119,11 +119,11 @@ cp deploy/compose/compose.yaml "$bundle/compose.yaml.template" OAC_DEV_BUILD_REVISION="$revision" scripts/build-core-image-context.sh "$stage/core" cp "$stage/core/bin/oac" "$bundle/oac" python3 scripts/build-microsandbox-provider.py build "$stage/core/bin/oac-microsandbox-provider" -msb_archive="${CORE_DISTRIBUTION_MICROSANDBOX_ARCHIVE:-$runtime_root/cache/microsandbox-v0.7.8-linux-x86_64.tar.gz}" +msb_archive="${CORE_DISTRIBUTION_MICROSANDBOX_ARCHIVE:-$runtime_root/cache/microsandbox-v0.7.11-linux-x86_64.tar.gz}" if [[ ! -f "$msb_archive" ]]; then mkdir -p "$(dirname "$msb_archive")" curl --fail --location --proto '=https' --tlsv1.2 \ - https://github.com/superradcompany/microsandbox/releases/download/v0.7.8/microsandbox-linux-x86_64.tar.gz \ + https://github.com/superradcompany/microsandbox/releases/download/v0.7.11/microsandbox-linux-x86_64.tar.gz \ --output "$stage/microsandbox.download" python3 scripts/core-distribution-manifest.py extract-runtime "$stage/microsandbox.download" "$stage/core/microsandbox" mv "$stage/microsandbox.download" "$msb_archive" diff --git a/scripts/build-microsandbox-provider.py b/scripts/build-microsandbox-provider.py index 2e5e31f90..045361a37 100644 --- a/scripts/build-microsandbox-provider.py +++ b/scripts/build-microsandbox-provider.py @@ -1,19 +1,21 @@ #!/usr/bin/env python3 -"""Build the provider with the official SDK source and matching embedded FFI.""" +"""Build the provider with the pinned SDK fork and its matching embedded FFI.""" import argparse import hashlib import json import os from pathlib import Path -import re import shutil import subprocess import tempfile SDK_MODULE = "github.com/superradcompany/microsandbox/sdk/go" -FFI_SHA256 = "bc079888050a92d3652191ae8e18fba96e1ac66dc78bce4e5aaeb7eca9b04e25" +# The SDK source (go.mod replace) and this FFI come from the same tag of the fork; see docs/maintainers.md. +SDK_FORK = "github.com/SaladDay/microsandbox/sdk/go" FFI_FILE = "libmicrosandbox_go_ffi-linux-amd64.so" +FFI_URL = "https://github.com/SaladDay/microsandbox/releases/download/oac-v0.7.11-1/" + FFI_FILE +FFI_SHA256 = "e489ea93cab3b9c8ea9e8b53a5c0b4fe0e54a66be34b7b2638fb360b1d574642" def verify_ffi(path): @@ -22,13 +24,13 @@ def verify_ffi(path): for block in iter(lambda: stream.read(1024 * 1024), b""): digest.update(block) if digest.hexdigest() != FFI_SHA256: - raise ValueError("Official microsandbox FFI checksum mismatch") + raise ValueError("microsandbox FFI checksum mismatch") def install_ffi(source, destination): verify_ffi(source) if destination.is_symlink() or not destination.is_file() or destination.stat().st_size != 0: - raise ValueError("Official SDK must contain an empty FFI release sentinel") + raise ValueError("The SDK must contain an empty FFI release sentinel") shutil.copyfile(source, destination) @@ -54,12 +56,8 @@ def run(*command, cwd=module): parser.error("the provider distribution requires Linux amd64") run("go", "mod", "download", SDK_MODULE) sdk = json.loads(run("go", "list", "-mod=readonly", "-m", "-json", SDK_MODULE)) - if "Replace" in sdk: - raise ValueError("The SDK must be the pinned official module") - versions = re.findall(r'^const sdkVersion = "([0-9.]+)"$', (Path(sdk["Dir"]) / "setup.go").read_text(), re.M) - if len(versions) != 1: - raise ValueError("Official SDK release declaration changed") - version = versions[0] + if sdk.get("Replace", {}).get("Path") != SDK_FORK: + raise ValueError("The SDK must be the pinned fork module") cache = Path(os.environ.get("OAC_DEV_HOME", str(Path.home() / ".oac"))) / "cache" if not cache.is_absolute(): raise ValueError("OAC_DEV_HOME must be absolute") @@ -69,8 +67,7 @@ def run(*command, cwd=module): stage = Path(temporary) if not ffi.exists(): download = stage / FFI_FILE - run("curl", "--fail", "--location", "--silent", "--show-error", "--retry", "3", "--output", str(download), - f"https://github.com/superradcompany/microsandbox/releases/download/v{version}/{FFI_FILE}") + run("curl", "--fail", "--location", "--silent", "--show-error", "--retry", "3", "--output", str(download), FFI_URL) verify_ffi(download) os.replace(download, ffi) verify_ffi(ffi) diff --git a/scripts/core-distribution-manifest.py b/scripts/core-distribution-manifest.py index b22f3af40..8124d2500 100644 --- a/scripts/core-distribution-manifest.py +++ b/scripts/core-distribution-manifest.py @@ -17,7 +17,7 @@ import zipapp -RUNTIME_ARCHIVE_SHA256 = "86f9f72dc3e639c7175bc07909b4b63ce412517c1ef8a2e1921171af5682fded" +RUNTIME_ARCHIVE_SHA256 = "5fc2206fbe35b471743bd5af15e3931cd2439a0c8b8e6ef08a493ddabcdc1b4c" DIGEST = re.compile(r"sha256:[0-9a-f]{64}\Z") sys.path.insert(0, str(pathlib.Path(__file__).resolve().parents[1] / "deploy/node")) import provider_assets @@ -210,7 +210,7 @@ def verify_runtime(image, daemon, source): def extract_runtime(archive, destination): if sha256(archive) != RUNTIME_ARCHIVE_SHA256: - raise ValueError("microsandbox v0.7.8 release checksum mismatch") + raise ValueError("microsandbox v0.7.11 release checksum mismatch") destination = pathlib.Path(destination) destination.mkdir(parents=True, exist_ok=True) with tarfile.open(archive, "r:gz") as bundle: @@ -355,7 +355,7 @@ def node_payload(bundle, stage, revision, source_tree, artifact_base_url="", off "image_manifest_digests": {name: identity[1] for name, identity in identities.items()}, "runtime_ref": "oac-runtime@" + digest, "microsandbox": { - "version": "0.7.8", + "version": "0.7.11", "runtime_sha256": sha256(stage / "core/microsandbox/msb"), "firmware_sha256": sha256(stage / "core/microsandbox/libkrunfw.so.5.6.1"), }, diff --git a/services/core/internal/sandbox/microsandbox/types.go b/services/core/internal/sandbox/microsandbox/types.go index 2a47ad081..3038e8a52 100644 --- a/services/core/internal/sandbox/microsandbox/types.go +++ b/services/core/internal/sandbox/microsandbox/types.go @@ -10,7 +10,7 @@ import ( ) const ProtocolVersion = 9 -const SDKVersion = "v0.7.8" +const SDKVersion = "v0.7.11" const MaxOutputBytes = 1024 * 1024 const MaxRequestBytes = 72 * 1024 * 1024 const MaxResponseBytes = 16 * 1024 * 1024 diff --git a/services/core/tools/microsandbox-provider/README.md b/services/core/tools/microsandbox-provider/README.md index 7fc82862c..24ffb8814 100644 --- a/services/core/tools/microsandbox-provider/README.md +++ b/services/core/tools/microsandbox-provider/README.md @@ -1,6 +1,6 @@ # microsandbox Sandbox Provider helper -microsandbox runs each hosted Session in its own microVM on a Linux amd64 node with KVM. Core forwards provider operations to the node over the [node protocol](../../../../contracts/agents-api/node-generation-protocol.md); the node's adapter ([`sandbox/microsandbox`](../../internal/sandbox/microsandbox)) runs this helper once per operation. The helper links the microsandbox Go SDK v0.7.8 with its FFI library, so Core and the node program stay CGO-free Go binaries. It implements the checkpoint operations of the provider-neutral `sandbox.SandboxProvider` with full snapshots. It has no daemon, lifecycle database, scheduler or network control plane. +microsandbox runs each hosted Session in its own microVM on a Linux amd64 node with KVM. Core forwards provider operations to the node over the [node protocol](../../../../contracts/agents-api/node-generation-protocol.md); the node's adapter ([`sandbox/microsandbox`](../../internal/sandbox/microsandbox)) runs this helper once per operation. The helper links the microsandbox Go SDK v0.7.11 from the [fork](../../../../docs/maintainers.md) with its FFI library, so Core and the node program stay CGO-free Go binaries. It implements the checkpoint operations of the provider-neutral `sandbox.SandboxProvider` with full snapshots. It has no daemon, lifecycle database, scheduler or network control plane. [Sandbox Provider protocol](../../../../docs/sandbox-provider.md) owns the provider contract. [Sandbox deployment](../../../../contracts/agents-api/sandbox-deployment.md) owns the resources and suspension policy; the [nodes guide](../../../../docs/getting-started/nodes.md) owns node installation, host requirements, the node's directories and its network policy. @@ -8,7 +8,7 @@ microsandbox runs each hosted Session in its own microVM on a Linux amd64 node w The [maintainer guide](../../../../docs/maintainers.md#runtime-images-and-helpers) builds the helper and packages the checksum-verified `msb` runtime and `libkrunfw` firmware. The node's provider configuration, written by the node installer, supplies the absolute helper, runtime and firmware paths with their SHA-256 values, the runtime home, the private checkpoint root, the Runtime image reference, the saved resources and the host network policy. -Before every operation the helper checks that it was built with the exact official SDK module declared in its embedded `go.mod` without a replacement, that the runtime and firmware match their hashes, that the runtime's `.msbver` ELF section reports the declared native release, that the SDK source and embedded FFI report that release, and that the SDK resolves exactly those paths with the local backend ([`main.go`](main.go)). It never installs or upgrades these files; keep them unchanged for the lifetime of the provider's backend. Ambient SDK profiles are ignored. +Before every operation the helper checks that it was built with the exact SDK fork module that its embedded `go.mod` declares as the replacement, that the runtime and firmware match their hashes, that the runtime's `.msbver` ELF section reports the declared native release, that the SDK source and embedded FFI report that release, and that the SDK resolves exactly those paths with the local backend ([`main.go`](main.go)). It never installs or upgrades these files; keep them unchanged for the lifetime of the provider's backend. Ambient SDK profiles are ignored. The adapter-owned SDK configuration sets `snapshots.max_filesystem_state_mib` to 64 MiB per virtio-fs device. The native 4 MiB default cannot capture file-heavy agent work. Capture and restore keep the same bounded budget and native integrity checks; sandbox memory and node capacity do not change. The budget is fixed when a sandbox starts, so changing the helper cannot repair an already-running sandbox's smaller budget. Existing snapshots still undergo native verification before restore. @@ -24,7 +24,7 @@ Create names the VM from a hash of the installation and allocation reference plu Workspace, staging and outputs share the `/environment` filesystem, which keeps the Runtime's cross-device and link checks intact; the layered root filesystem can report different device IDs for a directory and its upper-layer files, so it holds no workspace data. The filesystem provider owns the directory; sandbox removal never deletes it. The binding and resource rules belong to [Workspace filesystem protocol](../../../../docs/workspace-provider.md#attachment). The [Runtime bootstrap](../../../../docs/runtime-bootstrap.md) owns the Runtime directory layout. -VM creation does not run the image's entry point. The bootstrap runs as root through confidential standard input, with a two-minute limit. It creates the Runtime directories and the private suspend control directory, writes the [Runtime bootstrap](../../../../docs/runtime-bootstrap.md) file to `/home/runtime/runtime-bootstrap.json`, bind-mounts `/environment/workspace` at `/workspace` and starts `oac-daemon connect --bootstrap-file` in the background as UID/GID 1000. The `io.oac.bootstrap` label then changes from `pending` to `complete` through the SDK's next-start modification policy, because v0.7.8 cannot update the labels of a running VM. That label confirms only these writes and the launch, not authentication or native readiness. +VM creation does not run the image's entry point. The bootstrap runs as root through confidential standard input, with a two-minute limit. It creates the Runtime directories and the private suspend control directory, writes the [Runtime bootstrap](../../../../docs/runtime-bootstrap.md) file to `/home/runtime/runtime-bootstrap.json`, bind-mounts `/environment/workspace` at `/workspace` and starts `oac-daemon connect --bootstrap-file` in the background as UID/GID 1000. The `io.oac.bootstrap` label then changes from `pending` to `complete` through the SDK's next-start modification policy, which persists it without restarting the guest. That label confirms only these writes and the launch, not authentication or native readiness. A helper response carries `CreateSettled` with a configuration rejection only after native Create has completed, the first inspection has verified the exact compute ID and ownership, and the resource check has rejected the VM before bootstrap started. The adapter keeps the original error and validates the compute identity before passing the proof to Core. The private `initial_info` operation used by `GetInfo` and `Renew` can also return an exact initial `State` with `Status="absent"`, no native ID and `CreateSettled=true`, after typed native absence and durable closure of initial Create admission under the allocation lock. It accepts only generation zero without restored ancestry or a native ID. The adapter validates the complete receipt and returns absence without an error. Ordinary `inspect` used by `GetCompute`, uncertain Create outcomes, timeouts and ownership failures never produce this receipt; missing compute alone is not settlement. @@ -63,7 +63,7 @@ oac-daemon resume --control-file CONTROL_FILE \ ## Metrics -The read-only metrics operation holds the allocation lock and verifies the exact compute ID through the SDK before and after it runs `msb metrics NAME --format json` with the same pinned runtime binary ([`metrics.go`](metrics.go)). The CLI report keeps the native sample timestamp and fractional-second uptime, so the helper reconstructs one run start consistently across polls and Core restarts, and a new run gets a new start. The Go SDK's projection drops the timestamp and truncates uptime to whole seconds, so it cannot provide this; sandbox creation time is not a run start time. In the pinned source (`v0.7.8`, commit `7b7b9dc89e9a1c77801918f7833c3381d1754579`), `crates/metrics/lib/registry.rs` reads `sampled_at_unix_ms` and `started_at_unix_ms` together and subtracts them for uptime, and `crates/cli/lib/commands/metrics.rs` serializes the timestamp and `uptime.as_secs_f64()`. +The read-only metrics operation holds the allocation lock and verifies the exact compute ID through the SDK before and after it runs `msb metrics NAME --format json` with the same pinned runtime binary ([`metrics.go`](metrics.go)). The CLI report keeps the native sample timestamp and fractional-second uptime, so the helper reconstructs one run start consistently across polls and Core restarts, and a new run gets a new start. The Go SDK's projection drops the timestamp and truncates uptime to whole seconds, so it cannot provide this; sandbox creation time is not a run start time. In the pinned source (`v0.7.11`, commit `df3e0f7dd69280b88f6e28d6d3cf5fe4bb4a87a0`), `crates/metrics/lib/registry.rs` reads `sampled_at_unix_ms` and `started_at_unix_ms` together and subtracts them for uptime, and `crates/cli/lib/commands/metrics.rs` serializes the timestamp and `uptime.as_secs_f64()`. The helper returns only the native observation time, exact uptime, cumulative vCPU time and guest memory usage and limit. It rejects stale or exited reports and missing or malformed fields, bounds the CLI output and reports failures only as an unavailable code, never native diagnostics. Metrics never connect to the guest, renew activity, resume paused compute or change lifecycle state. [Runtime observability](../../../../contracts/agents-api/runtime-observability.md) owns the mapping to observations. diff --git a/services/core/tools/microsandbox-provider/bootstrap.go b/services/core/tools/microsandbox-provider/bootstrap.go index ed4b28700..ef5f8ca17 100644 --- a/services/core/tools/microsandbox-provider/bootstrap.go +++ b/services/core/tools/microsandbox-provider/bootstrap.go @@ -103,8 +103,8 @@ func (b backend) create(ctx context.Context) (wire.Response, error) { if result.ExitCode != 0 { return wire.Response{}, sandbox.ErrCommandUnconfirmed } - // Persist the final bootstrap receipt without restarting the live guest. - // v0.7.8 cannot update active labels; ownership reads persisted config. + // Persist the final bootstrap receipt without restarting the live guest; + // ownership reads persisted config. _, e = live.Modify(ctx, sdk.ModifyOptions{Labels: map[string]string{bootstrapLabel: "complete"}, Policy: sdk.ModificationPolicyNextStart}) if e != nil { return wire.Response{}, e diff --git a/services/core/tools/microsandbox-provider/deployment.go b/services/core/tools/microsandbox-provider/deployment.go index 01870c4bb..1c653bf35 100644 --- a/services/core/tools/microsandbox-provider/deployment.go +++ b/services/core/tools/microsandbox-provider/deployment.go @@ -30,7 +30,7 @@ func resourceProof(config wire.Config) string { return hex.EncodeToString(digest[:]) } -// The SDK decodes native CPU/memory/rootfs configuration. Its v0.7.8 projection +// The SDK decodes native CPU/memory/rootfs configuration. Its projection // omits mounts, so the external directory inventory is projected here. // Restored roots have no configured size: a verified full snapshot supplies that // proof, retained as a label only after inspecting the restored target. diff --git a/services/core/tools/microsandbox-provider/go.mod b/services/core/tools/microsandbox-provider/go.mod index c04558e14..52678be60 100644 --- a/services/core/tools/microsandbox-provider/go.mod +++ b/services/core/tools/microsandbox-provider/go.mod @@ -4,13 +4,14 @@ go 1.26.8 require ( github.com/MiniMax-AI/OpenAgentCore v0.0.0 - github.com/superradcompany/microsandbox/sdk/go v0.0.0-20261009155513-7b7b9dc89e9a + github.com/google/uuid v1.6.0 + github.com/superradcompany/microsandbox/sdk/go v0.0.0-20261024213825-df3e0f7dd692 ) -require ( - github.com/google/uuid v1.6.0 // indirect - golang.org/x/sync v0.22.0 // indirect -) +require golang.org/x/sync v0.22.0 // indirect -// The helper ships from this repository; the SDK itself is a released module. +// The helper ships from this repository. replace github.com/MiniMax-AI/OpenAgentCore => ../../../.. + +// The SDK is upstream v0.7.11 plus the fork's patch queue (docs/maintainers.md). +replace github.com/superradcompany/microsandbox/sdk/go => github.com/SaladDay/microsandbox/sdk/go v0.0.0-20261028065500-fc39b5b503f0 diff --git a/services/core/tools/microsandbox-provider/go.sum b/services/core/tools/microsandbox-provider/go.sum index a92270ad0..5d86672d7 100644 --- a/services/core/tools/microsandbox-provider/go.sum +++ b/services/core/tools/microsandbox-provider/go.sum @@ -1,6 +1,6 @@ +github.com/SaladDay/microsandbox/sdk/go v0.0.0-20261028065500-fc39b5b503f0 h1:FOLB4tEDMEO0uCnJrD6FmdS0+a4rk+nv09dzk1F3FLY= +github.com/SaladDay/microsandbox/sdk/go v0.0.0-20261028065500-fc39b5b503f0/go.mod h1:p7Tm/p9zkO7sHO3N8A1fiTVeLB2w/fQoKdYlpN/5neA= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/superradcompany/microsandbox/sdk/go v0.0.0-20261009155513-7b7b9dc89e9a h1:r9mZpz3z3E5tXRWDulZSs0gyM2EEhsTUqUjyZQ6MT4w= -github.com/superradcompany/microsandbox/sdk/go v0.0.0-20261009155513-7b7b9dc89e9a/go.mod h1:p7Tm/p9zkO7sHO3N8A1fiTVeLB2w/fQoKdYlpN/5neA= golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek= golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= diff --git a/services/core/tools/microsandbox-provider/main.go b/services/core/tools/microsandbox-provider/main.go index 3ebaa72da..4c78d7582 100644 --- a/services/core/tools/microsandbox-provider/main.go +++ b/services/core/tools/microsandbox-provider/main.go @@ -226,14 +226,16 @@ func allocationLock(q wire.Request) (*allocationGuard, error) { time.Sleep(20 * time.Millisecond) } } -func sdkModuleVersion() string { + +// sdkReplacement returns the SDK fork module that go.mod pins. +func sdkReplacement() (path, version string) { for _, line := range strings.Split(moduleDefinition, "\n") { fields := strings.Fields(line) - if len(fields) == 2 && fields[0] == "github.com/superradcompany/microsandbox/sdk/go" { - return fields[1] + if len(fields) == 5 && fields[0] == "replace" && fields[1] == "github.com/superradcompany/microsandbox/sdk/go" && fields[2] == "=>" { + return fields[3], fields[4] } } - return "" + return "", "" } func checkInstallation(c wire.Config) error { @@ -244,7 +246,8 @@ func checkInstallation(c wire.Config) error { matched := false for _, d := range build.Deps { if d.Path == "github.com/superradcompany/microsandbox/sdk/go" { - matched = d.Version == sdkModuleVersion() && d.Replace == nil + path, version := sdkReplacement() + matched = d.Replace != nil && d.Replace.Path == path && d.Replace.Version == version } } if !matched { diff --git a/services/core/tools/microsandbox-provider/sdk_release_test.go b/services/core/tools/microsandbox-provider/sdk_release_test.go index 7d528949f..ae1926b5d 100644 --- a/services/core/tools/microsandbox-provider/sdk_release_test.go +++ b/services/core/tools/microsandbox-provider/sdk_release_test.go @@ -10,9 +10,9 @@ import ( sdk "github.com/superradcompany/microsandbox/sdk/go" ) -func TestOfficialSDKReleaseMatchesEmbeddedFFI(t *testing.T) { +func TestSDKReleaseMatchesEmbeddedFFI(t *testing.T) { t.Setenv("MSB_HOME", t.TempDir()) - if sdkModuleVersion() == "" { + if path, _ := sdkReplacement(); path == "" { t.Fatal("missing pinned SDK module identity") } if sdk.SDKVersion() != strings.TrimPrefix(wire.SDKVersion, "v") { diff --git a/services/core/tools/microsandbox-provider/snapshot_observation_test.go b/services/core/tools/microsandbox-provider/snapshot_observation_test.go index 97560eecf..f8058dea0 100644 --- a/services/core/tools/microsandbox-provider/snapshot_observation_test.go +++ b/services/core/tools/microsandbox-provider/snapshot_observation_test.go @@ -357,7 +357,7 @@ func TestFreshRestoreRequestDeadlineClosesBeforeNativeExecution(t *testing.T) { } } -// The official SDK freezes its default backend on first use. Match production's +// The SDK freezes its default backend on first use. Match production's // one-request helper process rather than changing MSB_HOME under a cached pool. func isolatedSDKTest(t *testing.T) bool { t.Helper() From 00ca3c27bfc9f78003fecf23d2b3d78365712951 Mon Sep 17 00:00:00 2001 From: SaladDay <1203511142@qq.com> Date: Wed, 28 Oct 2026 07:13:02 +0000 Subject: [PATCH 2/2] Keep the tag literal in the zh maintainers guide --- docs/zh/maintainers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/zh/maintainers.md b/docs/zh/maintainers.md index 7a6a664f5..dba81803a 100644 --- a/docs/zh/maintainers.md +++ b/docs/zh/maintainers.md @@ -118,7 +118,7 @@ make check-microsandbox-provider **microsandbox 运行时。** 分发包使用官方的 [v0.7.11 release](https://github.com/superradcompany/microsandbox/releases/tag/v0.7.11) 归档 `microsandbox-linux-x86_64.tar.gz`,SHA256 为 `5fc2206fbe35b471743bd5af15e3931cd2439a0c8b8e6ef08a493ddabcdc1b4c`(即 `scripts/core-distribution-manifest.py` 中的 `RUNTIME_ARCHIVE_SHA256`)。构建过程会先验证校验和,再解压 `msb` 和 `libkrunfw.so.5.6.1`,并记录这两个文件的哈希。辅助程序会在每次调用时检查这些哈希,并且绝不安装或升级它们。 -**microsandbox fork。** SDK 及其 FFI 来自 [SaladDay/microsandbox](https://github.com/SaladDay/microsandbox/tree/oac) 的 `oac` 分支:一个上游发布标签加上一小队补丁,补丁列表见 `git log v0.7.11..oac`。每个补丁同时向上游提交,上游发布包含它之后就从队列中删除。推送 `oac-v<上游版本>-` 标签会在与上游发布相同的 manylinux 2.28 容器中构建 Linux amd64 FFI,并连同其 SHA256 附加到该标签的 release。要换到新标签,把 `services/core/tools/microsandbox-provider/go.mod` 中 SDK 的 `replace` 指向该标签的提交,并更新 `scripts/build-microsandbox-provider.py` 中的 `FFI_URL` 和 `FFI_SHA256`。运行时仍使用同一上游版本的官方发布。 +**microsandbox fork。** SDK 及其 FFI 来自 [SaladDay/microsandbox](https://github.com/SaladDay/microsandbox/tree/oac) 的 `oac` 分支:一个上游发布标签加上一小队补丁,补丁列表见 `git log v0.7.11..oac`。每个补丁同时向上游提交,上游发布包含它之后就从队列中删除。推送 `oac-v-` 标签会在与上游发布相同的 manylinux 2.28 容器中构建 Linux amd64 FFI,并连同其 SHA256 附加到该标签的 release。要换到新标签,把 `services/core/tools/microsandbox-provider/go.mod` 中 SDK 的 `replace` 指向该标签的提交,并更新 `scripts/build-microsandbox-provider.py` 中的 `FFI_URL` 和 `FFI_SHA256`。运行时仍使用同一上游版本的官方发布。 ### 独立 Core 构建 {#standalone-core-builds}