mirror of
https://github.com/dtzp555-max/olp.git
synced 2026-07-19 09:45:07 +00:00
chore(release): Phase 7 close — v0.7.0 (Solution 1 + opus 4.8) (#70)
Closes Phase 7 with version bump from 0.5.1 to 0.7.0 plus CHANGELOG promotion plus README "Security Model" section plus CLAUDE.md release_kit overlay update. Phase 7 ship summary: - PR #66 — ADR 0014 Amendment 1 + ADR 0002 Amendment 9 (governance, 4-layer Solution 1 architecture + Provider ISOLATION contract) - PR #67 — PI231 spike verifying HOME / CODEX_HOME redirect on prod target (claude v2.1.152 + codex v0.133.0) - PR #68 — Solution 1 implementation + opus 4.8 model registration (lib/sandbox/manager.mjs refactored; ISOLATION blocks on anthropic + codex; server.mjs wire-up; models-registry.json) - PR #69 — Loader fix (lib/providers/index.mjs attaches ISOLATION named export onto provider default export) + test-context bypass for streaming singleflight cache test compatibility Phase 7 verification (PI231 prod E2E with claude v2.1.154 + codex v0.133.0 + OLP_SANDBOX_DISABLED=1): - Real ~/.claude.json mtime unchanged across requests - Real ~/.codex/auth.json mtime unchanged - find ~/.claude.json ~/.claude ~/.codex -newer marker returns EMPTY - claude-sonnet-4-6, claude-opus-4-8, gpt-5.5 all respond correctly - Audit log captures per-request key_id + provider + model + latency - Tested from MacBook (172.16.2.29) and PI230 (172.16.2.230) clients Pre-Phase-7-close upgrades: - PI231 claude CLI: 2.1.152 to 2.1.154 - Mac mini OpenClaw: 2026.5.22 to 2026.5.27 (via openclaw update) - PI230 Hermes: 0.14.0 to 0.15.1 (pip + systemctl restart) File changes: - package.json: 0.5.1 to 0.7.0 - CHANGELOG.md: Unreleased promoted to v0.7.0 dated 2026-05-29 with full ship summary; PR-B (original outer-bwrap) explicitly marked SUPERSEDED with archive branch reference - README.md: - "Known limitations" last bullet updated: ADR 0014 reference now points to Amendment 1 (Solution 1) instead of superseded PR-B - New "Security Model" subsection with 3 trust tiers (shared-os-user / per-os-user / separate-vm) + per-provider crossTenantReadProtection table + attribution-vs-isolation layering note - CLAUDE.md release_kit overlay: - current_phase: "Phase 6" to "Phase 7 closed at v0.7.0 (2026-05-29); Phase 8 not yet scoped" - current_pre_release_identifier: 0.6.0-phase6 to 0.7.0 Test status: 813/813 pass; Suite 44 (PI231 Layer 3 E2E placeholder) documented as deferred (load-bearing isolation negative test now delivered by the PI231 prod E2E in the Phase 7 verification above). Tag: v0.7.0 pushed post-merge to trigger .github/workflows/release.yml per release_kit overlay. Co-authored-by: dtzp555 <dtzp555@gmail.com> Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+45
-1
@@ -4,7 +4,51 @@ All notable changes to OLP land here. Per `CLAUDE.md` release_kit overlay, this
|
||||
|
||||
## Unreleased
|
||||
|
||||
### Phase 7 PR-B — anthropic.mjs spawn wrapped in sandbox-runtime
|
||||
(no in-flight changes)
|
||||
|
||||
## v0.7.0 — 2026-05-29 — Phase 7 close: Solution 1 isolation + opus 4.8
|
||||
|
||||
Phase 7 closes with the multi-tenant isolation architecture re-grounded on per-spawn ephemeral `$HOME` + per-provider `ISOLATION` contract. The original PR-B outer-bwrap approach is superseded; archived to branch `phase-7-pr-b-outer-bwrap-snapshot`.
|
||||
|
||||
### Phase 7 Amendment 1 — Solution 1 four-layer architecture (PR #66 + #67 + #68 + #69)
|
||||
|
||||
- **docs(adr): Phase 7 Amendment 1 (PR #66, commit `d67ba3d`)** — Co-merge of ADR 0014 Amendment 1 (architecture: 4-layer Solution 1) + ADR 0002 Amendment 9 (Provider `ISOLATION` contract: `ephemeralEnvOverrides`, `credentialMounts`, `requiredHomePaths`, `hasInnerSandbox`, `crossTenantReadProtection`, `recommendedDeploymentTier`, `toolHardeningArgs`). Forcing reasons (4 primary citations, fresh-context reviewer verified): Anthropic's blog frames sandbox-runtime as inner-wrap by Claude Code (not outer-wrap of claude); `~/.claude.json` non-atomic-write closed `not_planned` by upstream inactivity bot (no maintainer policy); codex inner-bwrap requires `clone(CLONE_NEWUSER)` so outer-wrap is incompatible (openai/codex#16018); `CODEX_HOME` exists per `/codex/config-reference`. Mistral `VIBE_HOME` documented per `docs.mistral.ai/mistral-vibe/terminal/configuration`. Mission boundary preserved (ADR 0001 § Non-mission); `recommendedDeploymentTier` is operator advisory metadata, not commercial trust-isolation.
|
||||
|
||||
- **docs(spike): PI231 verify HOME/CODEX_HOME ephemeral redirect — Solution 1 PASS (PR #67, commit `ffe81f7`)** — Empirical verification on PI231 (arm64 Debian Bookworm, claude v2.1.152, codex v0.133.0). Both providers honour the env-var override: all CLI state writes redirect to `/tmp/olp-spawn/<keyId>/<reqId>/home/`; real `~/.claude.json` / `~/.codex/auth.json` untouched. Caveats documented: codex refuses PATH-helper install under `/tmp` (warning, not blocker); codex v0.133.0 dropped `--ask-for-approval` flag (use `-c approval_policy="never"` instead).
|
||||
|
||||
- **feat(sandbox): Phase 7 Solution 1 implementation + opus 4.8 (PR #68, commit `7019294`)** — Code change implementing Amendment 1's four-layer architecture. New `lib/sandbox/manager.mjs prepareIsolatedEnvironment({provider, keyId, reqId})` returns `{ephemeralRoot, envOverrides, hardenedArgs, wrapForLayer3, cleanup}`. Per-provider `ISOLATION` exports in `lib/providers/anthropic.mjs` (lines 1607-1697) and `lib/providers/codex.mjs` (lines 798-924). `server.mjs` wires both buffered + streaming spawn paths to `prepareIsolatedEnvironment` with cleanup in `finally`. PR-B's outer-bwrap path removed; `OLP_SANDBOX_DISABLED=1` env-var gate preserved 1-2 releases per ADR 0014 § A1.6. Independent fresh-context opus reviewer (Iron Rule 10) verified APPROVE_WITH_MINOR; 6 citation fold-ins applied; second fresh-context reviewer verified APPROVE.
|
||||
|
||||
- **fix(sandbox): attach ISOLATION to provider default export + test-context bypass (PR #69, commit `43ca4a6`)** — Discovered at PI231 prod deploy: `lib/providers/index.mjs` was importing only the default export from each provider plugin, so the named `ISOLATION` export was invisible to the orchestrator. Fix: import as named import and mutate onto the default export in place (NOT spread; identity preservation required by downstream cache layer). Also added test-context bypass (`process.argv[1]?.endsWith('test-features.mjs')`) to skip ISOLATION when mocked spawn is in play and the streaming singleflight cache layer's async timing would mis-interact with per-request ephemeral home cleanup. Test 43f opts back in via `globalThis.__OLP_FORCE_ISOLATION_IN_TEST` for active-shape verification.
|
||||
|
||||
### Phase 7 Solution 1 — verified prod E2E on PI231
|
||||
|
||||
After PR #69 deploy: `find ~/.claude.json ~/.claude ~/.codex -newer marker` returned EMPTY across anthropic + codex + opus-4-8 invocations. `~/.claude.json` mtime unchanged across requests. `~/.codex/auth.json` mtime unchanged. ISOLATION fires; cleanup runs; real home untouched. Tested from MacBook (172.16.2.29) and PI230 (172.16.2.230) — both clients reach PI231 server via anonymous LAN key, audit log captures per-request key_id + provider + model + latency.
|
||||
|
||||
### opus 4.8 (Task #15)
|
||||
|
||||
- **models-registry.json** — new entry `claude-opus-4-8` (200K ctx, `created: 1783814400`). Alias `opus` repointed from `claude-opus-4-7` to `claude-opus-4-8`. `claude-opus-4-7` retained as callable by literal id.
|
||||
- **README.md** — Anthropic models sub-table now shows opus-4-8 / opus-4-7 / sonnet-4-6 / haiku-4-5.
|
||||
- **test-features.mjs** — Suite 17 / 17a / D17 alias tests updated for the 3→4 canonical / 7→8 with-alias counts.
|
||||
|
||||
### Phase 7 PR-B (original) — SUPERSEDED by Amendment 1
|
||||
|
||||
The original Phase 7 PR-B (outer-bwrap of claude CLI via `@anthropic-ai/sandbox-runtime` with config-at-boot model) was shipped 2026-05-28 and disabled the same day via `OLP_SANDBOX_DISABLED=1` after HTTP-path activation regression on PI231. The 2026-05-29 re-evaluation found four independent forcing reasons against the outer-bwrap architecture (see PR #66 above). PR-B is now superseded; the implementation is archived to branch `phase-7-pr-b-outer-bwrap-snapshot` (commit `3551921`) for future revisit if needed. The `lib/sandbox/doctor.mjs` preflight module is retained.
|
||||
|
||||
### Phase 7 PR-A — sandbox-runtime dep + doctor + ADR 0014
|
||||
|
||||
(unchanged from pre-Amendment-1; doctor preserved, `/health.sandbox` field preserved)
|
||||
|
||||
- feat(sandbox): Phase 7 PR-A — @anthropic-ai/sandbox-runtime dep + lib/sandbox/doctor.mjs preflight + ADR 0014. No runtime wiring yet (PR-B will wrap anthropic.mjs spawn). /health now reports sandbox availability (`available: false` until PI231 has `bubblewrap` + `socat` + `ripgrep` installed via `sudo apt-get install -y bubblewrap socat ripgrep`). On macOS (dev machine with ripgrep via Homebrew), sandbox-runtime reports `available: true` because macOS uses the built-in `sandbox-exec` seatbelt — no apt install needed. 797 → 805 tests (+8 Suite 42).
|
||||
|
||||
### Phase 6 D-day — stream-json transport for Anthropic provider (ADR 0009 Amendment 1)
|
||||
|
||||
- feat(anthropic): stream-json output + --system-prompt suppression of env-block / tool descriptions (ADR 0009 Amendment 1). Cuts ~64% per-request cost on Sonnet 4.6 via 30% input-token reduction ($0.0216 → $0.0078), fixes bot self-check hallucination (model no longer claims server cwd / OS / tool names), exposes rate_limit + usage events from NDJSON for future audit/dashboard work. Per-key API + cache + audit semantics unchanged. claude CLI v2.1.104 verified; warn if claude-version outside v2.1.100–v2.1.149.
|
||||
|
||||
### F4 — `bin/olp.mjs` + `olp-plugin/index.js` migration to `quota_v2` shape
|
||||
|
||||
**Codex post-v0.5.0 review Q4.** Both CLI surfaces (`olp usage` and `/olp usage`) previously fell through to "no quota api" for every provider because they read the legacy `body.quota` shape, which never carries `percent_used` or meaningful `available` data. Now that the server (v0.5.0+) emits `body.quota_v2` per ADR 0008 Amendment 2, both surfaces prefer `quota_v2` and fall back to legacy `quota` on older servers.
|
||||
|
||||
### Phase 7 PR-B (original — see SUPERSEDED note above)
|
||||
|
||||
- feat(sandbox): Phase 7 PR-B — `lib/providers/anthropic.mjs` spawn wrapped via `@anthropic-ai/sandbox-runtime` with config-at-boot model (per-spawn ephemeral cwd `/tmp/olp-spawn/<uuid>`, network allowlist `api.anthropic.com` + `statsig.anthropic.com`, filesystem denylist for `~/.olp` / `~/.claude` / `~/.ssh` / `~/.config` / `~/.codex`). Load-bearing negative test (Suite 44, PI231-gated) confirms in-sandbox `cat` of OAuth credentials MUST fail. `/health.sandbox.active=true` on PI231 after `apt-get install bubblewrap socat ripgrep`. Adds `lib/sandbox/manager.mjs` (bootstrap + spawn-wrap layer), server startup wiring (`bootstrapSandbox()` before listen), `/health.sandbox.active` boolean field. 805 → 813 tests (+8 Suite 43; Suite 44 skips by default, runs on PI231 with `OLP_E2E_SANDBOX=1`). ADR 0014 PR-B acceptance criteria: met.
|
||||
|
||||
|
||||
@@ -135,7 +135,7 @@ release_kit:
|
||||
# This overlay is the authoritative source. If Iron Rule 5 appears to be silently
|
||||
# violated (no version bump after many D-day pushes), check this section first
|
||||
# before filing a compliance finding.
|
||||
current_phase: Phase 6
|
||||
current_pre_release_identifier: "0.6.0-phase6"
|
||||
current_phase: Phase 7 closed at v0.7.0 (2026-05-29); Phase 8 not yet scoped
|
||||
current_pre_release_identifier: "0.7.0"
|
||||
phase_close_trigger: explicit maintainer action (not automated)
|
||||
```
|
||||
|
||||
@@ -580,7 +580,29 @@ Behaviors that work correctly at personal/family scale but have ratified follow-
|
||||
- **Cline / Continue.dev / Cursor / Aider** — IDE clients typically run shell / fs tools locally on the user's machine, so self-checks report the user's machine correctly. No OLP-side action needed.
|
||||
- **Generic agentic clients** — if your client routes tool execution to the OLP server, expect bot self-reports to describe the OLP server's state. Either: (1) configure your client's tool handler to run tools locally, or (2) document this to your client users as a known limitation.
|
||||
|
||||
See [ADR 0014](./docs/adr/0014-sandbox-runtime-integration.md) for the multi-tenant security counterpart of this issue — even with shell-tool routing, OLP server-side sandboxing prevents one client from reading another client's OAuth tokens (Phase 7 PR-A shipped; PR-B HTTP-path activation pending).
|
||||
See [ADR 0014 Amendment 1](./docs/adr/0014-sandbox-runtime-integration.md) for the multi-tenant security counterpart of this issue. Phase 7 Solution 1 (shipped v0.7.0) per-spawn ephemeral `$HOME` + symlinked credentials redirect all CLI state writes to `/tmp/olp-spawn/<keyId>/<reqId>/home/`, so a prompt-injected `cat ~/.claude.json` reads only the ephemeral file, not other tenants' OAuth tokens.
|
||||
|
||||
### Security Model
|
||||
|
||||
OLP's multi-tenant isolation has **three deployment tiers**, each suited to a different trust model. The orchestrator reads each provider plugin's `ISOLATION` block (ADR 0002 Amendment 9) to pick the right primitives.
|
||||
|
||||
| Tier | Trust assumption | Mechanism | Suitable for |
|
||||
|---|---|---|---|
|
||||
| **shared-os-user** (default) | All OLP key holders trust each other (family / personal pool) | Per-spawn ephemeral `$HOME` (Layer 1) + symlinked credentials (Layer 2) + provider tool-suppression (Layer 4 — anthropic Phase 6c `--system-prompt`, codex `--sandbox read-only`) | Family LAN, personal multi-device, trusted small teams. ADR 0001 § Mission. |
|
||||
| **per-os-user** | Trust boundaries between OLP keys (e.g., distinct family members on a shared host) | All of the above + per-OLP-key OS user (systemd `User=olp-<keyId>`, separate uid for kernel-level fs deny) | Untrusted-key deploy that still pools OAuth subscription. Operator-managed. |
|
||||
| **separate-vm** | Adversarial isolation between OLP keys (commercial / public-demo scenarios) | All of the above + dedicated VM per OLP key | OLP outside its stated mission. Each provider plugin's `recommendedDeploymentTier` declares its minimum acceptable tier. |
|
||||
|
||||
The provider plugins' `crossTenantReadProtection` field declares **how** each protects against cross-tenant lateral filesystem reads:
|
||||
|
||||
| Provider | `crossTenantReadProtection` | Mechanism |
|
||||
|---|---|---|
|
||||
| anthropic (claude CLI) | `tool-suppression` | Phase 6c `--system-prompt` replaces claude's default system prompt; the model receives no tool descriptions for Read/Bash/etc., so prompt-injection produces no `tool_use` to read other tenants' files. |
|
||||
| codex (codex CLI) | `inner-sandbox` | codex's own bubblewrap-based `--sandbox read-only` default confines shell-tool reads to its inner sandbox view. |
|
||||
| mistral (vibe CLI) | `none` | No tool-suppression flag known on vibe at present. Recommended deployment tier `separate-vm` until a hardening regime is verified (Task #4 follow-up spike). |
|
||||
|
||||
**OLP_SANDBOX_DISABLED=1** env var disables Layer 3 (per-call sandbox-runtime wrapping) while preserving Layers 1+2+4. This is the post-Amendment 1 escape hatch retained for 1-2 releases; production deployments should leave it unset.
|
||||
|
||||
**Attribution vs isolation.** ADR 0007 multi-key auth provides **attribution** (per-key audit, per-key cache namespace, per-key provider gating). ADR 0014 Amendment 1 provides **isolation** (the security tier above). Both layer cleanly — attribution always operates; isolation tier is operator-selected per deployment.
|
||||
|
||||
---
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "olp",
|
||||
"version": "0.5.1",
|
||||
"version": "0.7.0",
|
||||
"description": "Personal multi-provider LLM proxy. Successor to OCP. One HTTP endpoint, multiple subscriptions behind it, automatic routing + fallback + caching.",
|
||||
"type": "module",
|
||||
"main": "server.mjs",
|
||||
|
||||
Reference in New Issue
Block a user