- docs/v1-vs-v2/: full v1→v2 regression analysis (SUMMARY + 21 per-module docs + ACTION-ITEMS rollup with decisions + timezone recreation spec). - container/agent-runner/scripts/sdk-signal-probe.ts: empirical harness used to characterise Claude Agent SDK event/hook/stderr timing for the stuck-detection design in item 9. - src/channels/chat-sdk-bridge.ts: document the conversations Map staleness in a code comment; fix deferred to when dynamic group registration lands (ACTION-ITEMS item 17). No runtime behavior change. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
47 lines
3.1 KiB
Markdown
47 lines
3.1 KiB
Markdown
# container-runtime + mount-security: v1 vs v2
|
|
|
|
## Scope
|
|
- v1: `src/v1/container-runtime.ts` (81 LOC), `container-runtime.test.ts` (148 LOC), `mount-security.ts` (406 LOC)
|
|
- v2: `src/container-runtime.ts` (81 LOC), `container-runtime.test.ts` (149 LOC), `mount-security.ts` (390 LOC)
|
|
|
|
## Capability map
|
|
|
|
### container-runtime.ts
|
|
|
|
| v1 behavior | v2 location | Status | Notes |
|
|
|---|---|---|---|
|
|
| `CONTAINER_RUNTIME_BIN = 'docker'` | `container-runtime.ts:1` | kept | Hardcoded; Apple Container runtime is NOT handled here in either version |
|
|
| `hostGatewayArgs()` | `container-runtime.ts` | kept | Identical |
|
|
| `readonlyMountArgs()` | `container-runtime.ts` | kept | Identical |
|
|
| `stopContainer()` | `container-runtime.ts` | kept | Identical |
|
|
| `ensureContainerRuntimeRunning()` | `container-runtime.ts` | kept | Identical |
|
|
| `cleanupOrphans()` | `container-runtime.ts:60-80` | kept | Identical logic |
|
|
| Logging module | | **changed** | v1 imports `logger` (data-first); v2 imports `log` (message-first) |
|
|
|
|
### mount-security.ts
|
|
|
|
| v1 behavior | v2 location | Status | Notes |
|
|
|---|---|---|---|
|
|
| `AdditionalMount` / `AllowedRoot` / `MountAllowlist` types | `mount-security.ts:16-29` | kept | Same shape except `nonMainReadOnly` removed |
|
|
| Default blocked patterns | `mount-security.ts:39` | kept | Same list |
|
|
| Allowlist load + file-watch cache | `mount-security.ts:64-102` | kept | |
|
|
| Path expansion (`~`) | `mount-security.ts` | kept | |
|
|
| Symlink resolution | `mount-security.ts` | kept | |
|
|
| Container-path validation | `mount-security.ts` | kept | |
|
|
| Template generation | `mount-security.ts:362-386` | changed | v2 template omits `nonMainReadOnly: true` |
|
|
| `validateMount(mount, isMain)` | `mount-security.ts:230-307` | **signature changed** | v2 is `validateMount(mount)` — no `isMain` |
|
|
| `validateAdditionalMounts(mounts, groupName, isMain)` | same | **signature changed** | v2 drops `isMain` |
|
|
| Non-main groups forced to read-only | — | **removed** | v1 lines 283-291; v2 only checks `allowedRoot.allowReadWrite` |
|
|
|
|
## Missing from v2
|
|
1. **`nonMainReadOnly` flag on `MountAllowlist`** — v1 could force non-main agent groups to read-only even when their allowlist permitted RW
|
|
2. **`isMain` param flow** through `validateMount` / `validateAdditionalMounts`
|
|
3. **Non-main group RW enforcement** at mount-validation time — now delegated entirely to `allowedRoot.allowReadWrite`
|
|
|
|
## Behavioral discrepancies
|
|
1. **Isolation model weakened**: a non-main ("shared" or auxiliary) agent group can now mount RW on any path its root permits. v1's defense-in-depth (allowlist permits RW + group must be main) is reduced to just the allowlist check
|
|
2. **Logger import**: only surface difference in container-runtime.ts
|
|
|
|
## Worth preserving?
|
|
**`nonMainReadOnly` restoration has security value** for multi-tenant setups where shared/sandbox agent groups should not mutate filesystem even if the allowlist is permissive. Low-cost to reintroduce: restore the field on `MountAllowlist`, restore the `isMain` param, restore the check in `validateMount()`. If v2 has explicitly decided isolation is enforced elsewhere (agent-group config), document that; otherwise this is a regression.
|