AltimateAI / AltimateAI/altimate-code

Connection registry is process-global: a multi-project server reuses one project's warehouse config (and, since #1204, its resolved store path) for another

Đang mở
#1,237 0 bình luận 0 reaction 0 người được giao Xem trên GitHub
Ngôn ngữ chính
TypeScript
Star
811
Fork
134
Merge trung bình
3 ngày 2 giờ
Pull request đã merge (30 ngày)
50

Mô tả

## Summary

The native connection registry keeps its entire loaded-config state at **module scope**, with a one-shot `loaded` latch. In a long-lived server process that handles requests for more than one project directory, the first request's `load()` wins permanently — every later request for a different project reuses the first project's connection configs and connectors, and never reads the second project's own `.altimate-code/connections.json`.

If two projects define a connection under the same name (a plausible default such as `warehouse` or `local`), project B's `sql_execute` silently runs against **project A's database**.

## Where

`packages/opencode/src/altimate/native/connections/registry.ts`:

```ts
registry.ts:24 let configs = new Map()
registry.ts:27 const connectors = new Map()
registry.ts:30 const pending = new Map>()
registry.ts:33 let loaded = false
```

`load()` (`:85-103`) clears and repopulates `configs` from `Instance.directory`-relative config files, then latches `loaded = true` at `:103`. `ensureLoaded()` (`:107`) is a no-op once the latch is set. In a server that serves multiple project directories from one process, the first `load()` result is reused for all subsequent projects — including connection names, credentials, and (see below) resolved absolute store paths.

## Pre-existing, but recently made worse

This sharing mechanism is **pre-existing** — confirmed by diffing `origin/main` before PR #1204 (commit `d9292ecfe7`): the identical module-scope `configs`/`connectors`/`loaded` pattern with the identical one-shot latch already existed (keyed off `process.cwd()` instead of `Instance.directory`). #1204 did **not** create it.

**What #1204 (merged as `1caa234ff9`) changed is the failure mode.** Before #1204, a leaked config's relative store `path` was resolved lazily at `connect()` time against the then-current `process.cwd()` — ambiguous, and in a server that never `chdir`s this usually just errored or opened nothing meaningful. After #1204, `resolveStorePaths()` (`:109-129`, called at `:175` and `:620`) pre-resolves and caches an **already-absolute** store path into `configs` at first-load time. So the same pre-existing leak now hands project B's request a deterministic absolute path to project A's real store — project B silently **reads and writes project A's actual data** rather than failing ambiguously.

The leak mechanism is old; the escalation from "fails ambiguously" to "silent cross-project read/write" landed with #1204.

## Scope of impact

- **Not** triggered by normal single-project CLI usage (one process serves one project; the registry only ever holds that project's config).
- Triggered when a **long-lived process serves multiple project directories** through this registry and same-named connections exist across them.

## Minimal fix (needs its own design PR)

Move `configs`, `connectors`, `pending`, and `loaded` off module scope into `InstanceState`, keyed by `Instance.directory`, with connector cleanup wired into the instance finalizer so cached native handles (DuckDB/SQLite file locks, SSH tunnels) are closed when an instance goes away rather than leaking for the process lifetime. `ensureLoaded()` / `load()` / `get()` / `list()` / `test()` / `add()` / `remove()` / `reload()` / `reset()` all need to read/write the current instance's slice rather than the shared module map — a real refactor, not a patch.

## Citations

`registry.ts:24,27,30,33` (module state), `:69-75` (`projectRoot()`), `:85-103` (`load()`), `:107` (`ensureLoaded()`), `:109-129` (`resolveStorePaths()`), `:175` and `:620` (call sites).

Surfaced by review threads on #1204 (cubic + codex + coderabbitai all flagged the same pattern, "make registry state instance-scoped"). #1204 merged before these were addressed; this issue tracks the follow-up.

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Đánh giá

Issue này chưa được đánh giá.

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.