Skip to content

B1:Sandbox 接口一次定全 + Docker 搬到接口后面(行为不变) - #523

Closed
jiangkoumo wants to merge 1 commit into
Ephemeral-AI-Lab:mainfrom
jiangkoumo:b1-interface
Closed

jiangkoumo wants to merge 1 commit into
Ephemeral-AI-Lab:mainfrom
jiangkoumo:b1-interface

Conversation

@jiangkoumo

Copy link
Copy Markdown
Collaborator

对应 layerfs-connect #45(Area B1),基于 main 35d3657。原 #498 拆成四个 PR:本 PR(B1)、B2 Linux 原生、B3 macOS 原生、#515 VM 放置。B2、B3、#515 都只立在 B1 上,彼此不叠,两两合并 0 冲突:先合 B1,其余三个可按任意顺序合入。四个合起来与原 #498 头 9aa10e6 相比,只多出 B3 真正 merge #427 最新头(fa02a1b2f)带来的内容,以及 B2、#515 各一处小修复(见各自正文)。

改了什么

  1. 接口(约 1000 行):backend/runtime.rs 的 Runtime/Sandbox enum 一次写全所有变体(Docker、Linux 原生、macOS 原生、Namespaces、VM、Windows 占位);provider/ 启动选项和能力标签;types/ 请求、镜像、失败类型;各后端共用的小工具。非 Docker 变体在本 PR 里只是桩,返回 Unsupported。
  2. Docker 搬到接口后面(新增约 800 行,大部分是从 layerfs-api/src/sandbox/create.rs 搬过来):Docker 的行为、record 格式、错误码都不变。
  3. Linux/macOS 共用的本地进程实现(约 1230 行,backend/native/)和 Node 端本地部署接入(约 1100 行,layerfs-node/src 的 local.rs、runtime.rs、discovery.rs 等)。这部分不是 Docker,但 Linux 和 macOS 都要用。放在 B1 是有意的:如果分别放进 B2、B3,两边会改同一批文件(上一版试合 90 多处冲突),B2 和 B3 就不能并行评审。放在 B1 后,B2 只剩 Linux 特有的约 100 行,B3 只剩 macOS 特有部分和 feat: macOS 原生适配——daemon 内置 loopback NFSv3 导出,普通用户 mount_nfs 挂载 Workspace(无 Docker / 无 macFUSE / 无 root) #427。在 B2/B3 合入前,这部分代码在 Linux/macOS 上走不到(对应变体返回 Unsupported),不影响 Docker 默认路径。

为什么

#13 的完成标准是「B1 以上不改代码」。所以把所有后端要用的接口和共用实现一次放进 B1,之后每个后端 PR 只往自己的目录里填。

怎么验证(结果)

  • macOS:cargo check / clippy -D warnings(含 linux target)/ 边界守卫:通过;与 9aa10e6 逐文件对照 71/80 文件逐字一致,其余是按设计留给 docs(512): propose a VM Sandbox backend (Sandboxes as namespaces in one VM per Store) #515 的 helper_spec 两行和 Namespaces 桩。
  • Linux(Debian 13,Rust 1.85.1,非 root):workspace check、clippy -D warnings、release 构建:通过;真实 Docker 9 个场景(sandbox、idle_close、calls_store 28 次、calls_ws 15 次、reap、sandbox_image、fs_mode、exec_lookup、exec_output)全部通过,残留容器 0;cargo test:layerfs-sandbox 48/48、layerfs-node 8/8、layerfs-api 10/11(失败的 kernel_application 在 main 35d3657 同环境同样失败,与本 PR 无关)。
  • 生产代码行数:102831 → 106022(+3191)。

风险

  • 体积大(80 文件,+5800/-880),其中约一半是第 3 点的共用实现,评审可按「接口 → Docker → 共用实现」三块看。
  • exec_output 场景第一次运行失败一次,重试通过,未复现。

…der (Area B1)

Extract the complete Sandbox runtime interface and shared native/node plumbing from 9aa10e6 onto upstream/main (35d3657), implementing the Docker backend and leaving same-signature Unsupported slots for backend/{linux,macos,namespaces}/ so B2, B3 and Ephemeral-AI-Lab#515 only replace their own backend directories.

In layerfs-sandbox:
- Define concrete Runtime (Docker, MacosNative, LinuxNative, Namespaces, Windows) and Sandbox (Docker, Native, Namespaces) enums in backend/runtime.rs.
- Add provider capabilities (including LoopbackNfs, MicroVm, RemoteCloud), LaunchPhase/LaunchFailure, ProviderLaunchOptions (Local, Namespaces, Docker) and SandboxRecord (Local, Namespaces, Docker).
- Add types::Image and cross-backend ExecRequest; move shared json and strings helpers to backend/.
- Implement DockerProvider and DockerInstance over existing Docker Engine lifecycle and streaming execution.
- Include shared backend/native/* lifecycle, identity, listener and streams modules under cfg(any(linux, macos)), with same-signature Unsupported stubs in backend/{linux,macos,namespaces}/.

In layerfs-api:
- Route SandboxApi through Arc<Runtime> via with_runtime and create_provider_file, retaining local resource ownership and command identity validation.
- Share TCP/Noise/Hello and Store install pipeline in sandbox/connection.rs.

In layerfs-node and @layerfs/agent:
- Take verbatim 9aa10e6 shared binding modules (local, discovery, runtime, sandbox, workspace, exec, registry, lib) with a no-op unmount slot for B3.
- Expose deploy.sandbox, deploy.localDir, deploy.sandboxBackend and deploy.imageArchive settings in @layerfs/agent.

Production LOC: 102831 -> 106022 (delta +3191)
First-parent comparison: upstream/main 35d3657 (tree ddea2b5) -> committed tree ae48e29.
Scopes:
  - core:   38395 -> 38395 (delta 0)
  - engine: 61777 -> 64938 (delta +3161)
    * layerfs-sandbox: 3417 -> 5526 (delta +2109)
    * layerfs-api:     1940 -> 2081 (delta +141)
    * layerfs-node:    2744 -> 3655 (delta +911)
  - api:     2659 ->  2689 (delta +30)
    * @layerfs/agent:   849 ->  879 (delta +30)
  - dsh:        0 ->     0 (delta 0)
  - reference: absent (retired R9c; last counted 65,417 at tree 498dd19)
Method: tools/production_loc.py (blob 3341e4d), --root <exact exported tree> --json for both snapshots; first-party production Rust, runtime SQL and JavaScript; tests, docs, tooling, generated and third-party files excluded.
Copilot AI balanced review requested due to automatic review settings October 31, 2026 14:13

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota. Try requesting a review at a lower effort level.

An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing.

yifanxuaaa added a commit that referenced this pull request Oct 31, 2026
B1 (layerfs-connect#45): one Sandbox interface, with Docker moved behind it.
Merged at PR head a32da57. B1 was cut from main 35d3657, before the
#506 Store-backend work on this branch, so the merge ports #506 onto B1's
provider interface:

- PostgreSQL Stores: ProviderLaunchOptions::Docker and DockerRecord carry
  `store_volume: Option<String>` like SandboxRequest; v2's create_postgres
  becomes SandboxApi::create_provider_postgres (Docker launch with no
  volume, no install, starts ready); the provider's startup Hello waits on
  DaemonSetup::opens_existing() as v2's create did. B1's create.rs is
  taken whole, since both v2 edits there now live in provider.rs.
- Node binding: v2's DaemonStore start path runs through
  create_provider_file / create_provider_postgres. A native Sandbox of a
  PostgreSQL Store is refused Unsupported (B1's native daemon opens a
  Store file). Native Sandboxes take v2's shared-Store naming
  (<prefix><store>.<project>-<n>) and the layerfs.store label.
- Two modules named local.rs: B1's native Sandbox module keeps
  `local` (B2, B3 and #526 call crate::local); v2's Store size/heads
  module (#506 E1, E2) is renamed `local_stores`, unchanged otherwise.
- Records save and read an optional `volume`; the creation-intent hint
  names the volume or, without one, the project label.
- client.js keeps v2's `postgresql` deployment flag and B1's native
  deployment; the boundary guard keeps both sides' entries.
- Tests: the node mock Engine keeps v2's version (same behaviour as B1's);
  B1's new tests get `Some(...)` volumes and `postgresql: None`.

Verified on macOS (Rust 1.85.1): workspace check and warning-denying
Clippy, all targets; layerfs-sandbox, layerfs-node and layerfs-api tests
220 passed, 0 failed, 15 ignored; boundary guard PASS and its 34
self-tests; agent calls/exec_output and packaging surface/sandbox/
lifecycle PASS. Not run: Linux build and tests (no Linux C toolchain on
the host, Docker not running), Docker and FUSE E2E, packaging dispatch
(needs the built addon). Disposable only; Durable NOT_RUN, disabled by owner.

Production LOC: 111893 -> 115107 (delta +3214)
First-parent comparison: layerfs_v2_0_0 da70f98 (tree a949ae7) to
prepared merge tree cae5bb4.
Scopes: core 38400 -> 38400 (+0), engine 70228 -> 73412 (+3184),
api 3265 -> 3295 (+30). By crate: layerfs-sandbox +2109, layerfs-node
+927, layerfs-api +148, @layerfs/agent +30.
Method: tools/production_loc.py (blob 686d269)
--root <exported tree> --json for both snapshots; first-party production
Rust, runtime SQL and JavaScript; tests, docs, tooling, generated and
third-party files excluded.
Reference absent (retired R9c; last counted 65,417 at tree 498dd19).
Deleted tests: none.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@yifanxuaaa

Copy link
Copy Markdown
Contributor

@jiangkoumo Merged into layerfs_v2_0_0 at this PR's head a32da57326 (merge commit d39bb6c). That branch already had the #506 Store-backend work, so the merge ports it onto your interface: PostgreSQL Stores (optional store_volume) start through a new SandboxApi::create_provider_postgres, and v2's own layerfs-node/src/local.rs was renamed local_stores.rs so your local.rs keeps its name for B2, B3 and #526. Closing here because this PR targets main. Thank you!

已合入 layerfs_v2_0_0,合入的是本 PR 的头 a32da57326(合并提交 d39bb6c)。该分支已有 #506 的 Store 后端改动,所以合并时把它移植到了你的接口上:PostgreSQL Store(store_volume 变为可选)通过新增的 SandboxApi::create_provider_postgres 启动;v2 原有的 layerfs-node/src/local.rs 改名为 local_stores.rs,你的 local.rs 保持原名,B2、B3 和 #526 无需改动。本 PR 的目标分支是 main,因此在此关闭。感谢!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants