[PR #415] [MERGED] feat(compose): add the Compose planner #417

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

📋 Pull Request Information

Original PR: https://github.com/kvcache-ai/AgentENV/pull/415
Author: @Primary33
Created: 10/22/2026
Status: ✅ Merged
Merged: 10/28/2026
Merged by: @yingdi-shan

Base: main ← Head: feat/compose-planner


📝 Commits (1)

  • f5d5f49 feat(compose): add the Compose planner

📊 Changes

7 files changed (+820 additions, -2 deletions)

View changed files

📝 services/Makefile (+6 -0)
📝 services/README.md (+7 -2)
➕ services/compose/cmd/main.go (+46 -0)
➕ services/compose/plan.go (+451 -0)
➕ services/compose/plan_test.go (+271 -0)
📝 services/go.mod (+11 -0)
📝 services/go.sum (+28 -0)

📄 Description

What

Add aenv-compose-plan to normalize and validate image-only Compose projects with compose-go.

Why

Provide a standalone planner that the Compose sandbox API can invoke.

Planner part of the #349 split. The server integration remains in #349.

Scope and non-goals

Go planner, dependencies, and services build/test/format/vet targets.

Design and behavior changes

  • Read one Request JSON from stdin (unknown fields rejected) and write a Plan JSON to stdout. A Compose project the sandbox cannot run exits with code 65; every other failure, including a recovered panic, exits with 1. Go itself exits with 2 on panics, so 2 is not used.
  • Use only explicit interpolation variables and selected profiles, and assign a separate local image alias to each service. YAML expansion, interpolation and resolved environment values are each bounded, and the rendered plan is checked against 4 MiB.
  • The VM, not the guest Docker daemon, is the isolation boundary. Fields that make the loader read planner-host files (env_file, label_file, extends, include) are never allowed. Fields that cannot work in a sandbox are rejected: builds, replicas above 1 (one writable image drive per service), relative bind mounts (no project directory), external resources, configs/secrets, custom IPAM and non-default drivers. Guest-only options pass through, e.g. privileged, any cap_add, absolute guest bind mounts, anonymous volumes and network_mode: none/host/bridge/service:<name>.
  • Raw validation fails closed: a mapping with a non-string key (e.g. a !!binary key) and custom YAML tags such as !reset are rejected. Volume types and drivers are checked on the loaded project, after interpolation.
  • Published ports must be fixed, unique TCP ports with host_ip empty, 0.0.0.0 or ::, because the sandbox proxy connects to the guest address. The envd port is reserved; the server passes it as envdPort (default 49983).

Compatibility and operations

The executable is built by make -C services build. Release packaging is added with the server integration in #349.

Validation

On the designated Ubuntu test host as a non-root user (Go 1.27.1):

  • go test ./compose/... -count=1 -v — all planner tests passed.
  • make -C services build test fmt-check vet — passed; the three RedisBindingStore integration tests were skipped because redis-server is not installed.
  • aenv-compose-plan smoke checks: valid input exits 0 with a JSON plan; unsupported Compose and a reserved envdPort exit 65; an unknown request field exits 1.

Risks and reviewer notes

The standalone command and its tests exercise the planner protocol; #349 connects it to the Rust server.

Checklist

  • One coherent change with focused tests.
  • Logs and examples contain no credentials or private settings.

🔄 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/415 **Author:** [@Primary33](https://github.com/Primary33) **Created:** 10/22/2026 **Status:** ✅ Merged **Merged:** 10/28/2026 **Merged by:** [@yingdi-shan](https://github.com/yingdi-shan) **Base:** `main` ← **Head:** `feat/compose-planner` --- ### 📝 Commits (1) - [`f5d5f49`](https://github.com/kvcache-ai/AgentENV/commit/f5d5f491d6762a1aed8597f5f5c2d7b5cfce99fb) feat(compose): add the Compose planner ### 📊 Changes **7 files changed** (+820 additions, -2 deletions) <details> <summary>View changed files</summary> 📝 `services/Makefile` (+6 -0) 📝 `services/README.md` (+7 -2) ➕ `services/compose/cmd/main.go` (+46 -0) ➕ `services/compose/plan.go` (+451 -0) ➕ `services/compose/plan_test.go` (+271 -0) 📝 `services/go.mod` (+11 -0) 📝 `services/go.sum` (+28 -0) </details> ### 📄 Description ## What Add `aenv-compose-plan` to normalize and validate image-only Compose projects with compose-go. ## Why Provide a standalone planner that the Compose sandbox API can invoke. ## Related issue Planner part of the #349 split. The server integration remains in #349. ## Scope and non-goals Go planner, dependencies, and services build/test/format/vet targets. ## Design and behavior changes - Read one Request JSON from stdin (unknown fields rejected) and write a Plan JSON to stdout. A Compose project the sandbox cannot run exits with code 65; every other failure, including a recovered panic, exits with 1. Go itself exits with 2 on panics, so 2 is not used. - Use only explicit interpolation variables and selected profiles, and assign a separate local image alias to each service. YAML expansion, interpolation and resolved environment values are each bounded, and the rendered plan is checked against 4 MiB. - The VM, not the guest Docker daemon, is the isolation boundary. Fields that make the loader read planner-host files (`env_file`, `label_file`, `extends`, `include`) are never allowed. Fields that cannot work in a sandbox are rejected: builds, replicas above 1 (one writable image drive per service), relative bind mounts (no project directory), external resources, configs/secrets, custom IPAM and non-default drivers. Guest-only options pass through, e.g. `privileged`, any `cap_add`, absolute guest bind mounts, anonymous volumes and `network_mode: none/host/bridge/service:<name>`. - Raw validation fails closed: a mapping with a non-string key (e.g. a `!!binary` key) and custom YAML tags such as `!reset` are rejected. Volume types and drivers are checked on the loaded project, after interpolation. - Published ports must be fixed, unique TCP ports with `host_ip` empty, `0.0.0.0` or `::`, because the sandbox proxy connects to the guest address. The envd port is reserved; the server passes it as `envdPort` (default 49983). ## Compatibility and operations The executable is built by `make -C services build`. Release packaging is added with the server integration in #349. ## Validation On the designated Ubuntu test host as a non-root user (Go 1.27.1): - [x] `go test ./compose/... -count=1 -v` — all planner tests passed. - [x] `make -C services build test fmt-check vet` — passed; the three `RedisBindingStore` integration tests were skipped because `redis-server` is not installed. - [x] `aenv-compose-plan` smoke checks: valid input exits 0 with a JSON plan; unsupported Compose and a reserved `envdPort` exit 65; an unknown request field exits 1. ## Risks and reviewer notes The standalone command and its tests exercise the planner protocol; #349 connects it to the Rust server. ## Checklist - [x] One coherent change with focused tests. - [x] Logs and examples contain no credentials or private settings. --- <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:09 +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#417
No description provided.