Skip to content

fix(storage): honour MAGIC_CONTEXT_TEST_DATA_DIR in the shared storage resolver - #296

Merged
ualtinok merged 3 commits into
cortexkit:masterfrom
randomvariable:fix/storage-test-isolation
Aug 10, 2026
Merged

fix(storage): honour MAGIC_CONTEXT_TEST_DATA_DIR in the shared storage resolver#296
ualtinok merged 3 commits into
cortexkit:masterfrom
randomvariable:fix/storage-test-isolation

Conversation

@randomvariable

@randomvariable randomvariable commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Problem

packages/plugin/test-preload.ts documents MAGIC_CONTEXT_TEST_DATA_DIR as the guard that "cannot be defeated", but only resolveDatabasePath() consulted it. Every other caller of getMagicContextStorageDir() bypassed it — including the CLI doctors, which build join(getMagicContextStorageDir(), "context.db") themselves and run PRAGMA integrity_check against the result.

A test cannot restore isolation by setting process.env.HOME: bun caches os.homedir() at process startup, so getDataDir() still resolves to the real home.

HOME=/tmp/fakehome bun -e '... process.env.HOME="/tmp/mutated"; os.homedir()'
→ /tmp/fakehome   (mutation ignored)

Any test that deletes XDG_DATA_HOME to exercise path fallbacks therefore reaches the user's production database. Observed as two CLI doctor tests taking 8s and 16.5s against a 1.6 GB live DB — a read, not a migration, but the same escape route as the v26 and v41 incidents.

Change

Move the guard into getMagicContextStorageDir() so every caller inherits it:

const testDataDir = process.env.MAGIC_CONTEXT_TEST_DATA_DIR;
const base = testDataDir && !process.env.XDG_DATA_HOME ? testDataDir : getDataDir();
return path.join(base, "cortexkit", "magic-context");

XDG_DATA_HOME still wins, so suites that manage their own data home are unaffected. resolveDatabasePath() drops the now-redundant branch and keeps the NODE_ENV backstop — that one needs a memoized throwaway dir, which a pure path helper has no business creating. The backstop's condition now defers to the test data dir, so precedence is exactly as before; otherwise a test that deleted only XDG_DATA_HOME would have been diverted from the preload dir into a fresh backstop dir.

3 files, +66/−24.

Verification

To prove the hole is closed rather than merely unused, the pre-fix doctor-omp.test.ts (with delete process.env.XDG_DATA_HOME restored) was regenerated into a scratch file and run against the patched resolver: 101ms, 5 pass, versus 34.65s and 2 failures before. The dangerous pattern is now inert.

Three new tests in data-path.test.ts pin the precedence: production layout (test dir lifted), guard honoured when XDG_DATA_HOME is unset, and XDG_DATA_HOME winning over the guard. The pre-existing layout test needed the test dir temporarily lifted — it had only been passing because the helper ignored the preload entirely.

Against a clean master:

  • plugin suite 3621 pass / 0 fail across 346 files
  • host e2e OpenCode 44 pass + cache-analysis oracle 10 pass, 0 fail
  • host e2e Pi 47 pass / 12 skip (pre-existing it.skip placeholders) / 0 fail
  • Docker e2e OpenCode 10/10, Docker e2e Pi 12/12 — these assert the shared DB lands at the production cortexkit path, confirming the guard stays inert when neither NODE_ENV=test nor MAGIC_CONTEXT_TEST_DATA_DIR is set
  • typecheck, biome, git diff --check clean

The Rust e2e lane was not run: it needs a sibling subconscious checkout to build ck-subc, which CI also does not provision.


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.


Summary by cubic

Fixes test isolation by honoring MAGIC_CONTEXT_TEST_DATA_DIR and moving the NODE_ENV=test backstop into getMagicContextStorageDir() so tests, CLI doctors, and other direct callers never touch the real DB when XDG_DATA_HOME is unset or preload is missing. Keeps precedence and simplifies path resolution.

  • Bug Fixes
    • Hoist the NODE_ENV=test backstop into getMagicContextStorageDir() alongside MAGIC_CONTEXT_TEST_DATA_DIR; covers CLI doctors, announcements, and models-dev cache.
    • Preserve precedence: XDG_DATA_HOME > MAGIC_CONTEXT_TEST_DATA_DIR > NODE_ENV=test backstop > default.
    • Remove isolation branches from resolveDatabasePath(); rely on the shared resolver.
    • Tests: add precedence/backstop coverage and snapshot/restore all guard env vars (incl. NODE_ENV) to prevent leaks; doctor test drops from ~34s to ~100ms with no production DB access.

Written for commit 86a7d56. Summary will update on new commits.

Review in cubic

Greptile Summary

The PR centralizes test-storage isolation in the shared storage resolver so direct callers and database-opening paths use consistent precedence.

  • Preserves explicit database-path overrides.
  • Resolves storage in the order XDG_DATA_HOME, MAGIC_CONTEXT_TEST_DATA_DIR, NODE_ENV=test backstop, then the platform default.
  • Adds precedence, isolation, and environment-restoration coverage.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
packages/plugin/src/shared/data-path.ts Centralizes test-directory and test-runner backstop precedence for every shared-storage caller.
packages/plugin/src/features/magic-context/storage-db.ts Removes duplicate test-isolation logic and delegates default database-path resolution to the shared helper.
packages/plugin/src/shared/data-path.test.ts Adds coverage for production layout, test guard precedence, memoization, and environment restoration.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[getMagicContextStorageDir] --> B{XDG_DATA_HOME set?}
    B -- Yes --> C[XDG data directory]
    B -- No --> D{MAGIC_CONTEXT_TEST_DATA_DIR set?}
    D -- Yes --> E[Test data directory]
    D -- No --> F{NODE_ENV equals test?}
    F -- Yes --> G[Memoized temporary directory]
    F -- No --> H[Platform default data directory]
    C --> I[cortexkit/magic-context]
    E --> I
    G --> I
    H --> I
Loading

Reviews (3): Last reviewed commit: "test(data-path): restore-or-delete every..." | Re-trigger Greptile

…e resolver

test-preload.ts documents MAGIC_CONTEXT_TEST_DATA_DIR as the guard that
"cannot be defeated", but only resolveDatabasePath() consulted it. Every
other caller of getMagicContextStorageDir() bypassed it — including the
CLI doctors, which build join(getMagicContextStorageDir(), "context.db")
themselves and run PRAGMA integrity_check against it.

A test cannot restore isolation by setting process.env.HOME: bun caches
os.homedir() at startup, so getDataDir() still resolves to the real home.
Any test that deletes XDG_DATA_HOME to exercise path fallbacks therefore
reached the user's production database. Observed as two doctor tests
taking 8s and 16.5s against a 1.6 GB live DB — a read, not a migration,
but the same escape that migrated the live DB in the v26 and v41
incidents.

Move the guard into getMagicContextStorageDir() so it covers every
caller. XDG_DATA_HOME still wins, so tests that manage their own data
home are unaffected. resolveDatabasePath() drops the now-redundant
branch and keeps the NODE_ENV backstop, which needs a memoized throwaway
dir that a pure path helper has no business creating; its condition now
defers to the test data dir so precedence is unchanged.

@cubic-dev-ai cubic-dev-ai Bot 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.

1 issue found across 3 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/plugin/src/features/magic-context/storage-db.ts">

<violation number="1" location="packages/plugin/src/features/magic-context/storage-db.ts:187">
P2: The rewritten comment/stated goal claim uniform coverage "for every other caller alike" and "structurally impossible for ANY test to read or migrate production data", but the NODE_ENV=test redirect (getTestBackstopDbDir) stays only inside resolveDatabasePath. In the documented no-preload window (NODE_ENV=test, MAGIC_CONTEXT_TEST_DATA_DIR unset, XDG_DATA_HOME unset) callers that use getMagicContextStorageDir() directly — CLI doctors integrity_check (doctor.ts:64, doctor-pi.ts:575, diagnostics-pi.ts:454) and announcement.ts/models-dev-cache.ts — still resolve to the real ~/.local/share and can touch/migrate the production DB, i.e. the v26/v41 incident class this PR says it closes. If MAGIC/CWD-independent protection is intended to be truly uniform, the backstop needs to apply to getMagicContextStorageDir() rather than only the DB-resolver path; otherwise the claim in the comment is overstated for those callers.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

// helper calls), getMagicContextStorageDir() already points inside that
// controlled dir — honor it, do not override.
if (process.env.NODE_ENV === "test" && !process.env.XDG_DATA_HOME) {
if (

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: The rewritten comment/stated goal claim uniform coverage "for every other caller alike" and "structurally impossible for ANY test to read or migrate production data", but the NODE_ENV=test redirect (getTestBackstopDbDir) stays only inside resolveDatabasePath. In the documented no-preload window (NODE_ENV=test, MAGIC_CONTEXT_TEST_DATA_DIR unset, XDG_DATA_HOME unset) callers that use getMagicContextStorageDir() directly — CLI doctors integrity_check (doctor.ts:64, doctor-pi.ts:575, diagnostics-pi.ts:454) and announcement.ts/models-dev-cache.ts — still resolve to the real ~/.local/share and can touch/migrate the production DB, i.e. the v26/v41 incident class this PR says it closes. If MAGIC/CWD-independent protection is intended to be truly uniform, the backstop needs to apply to getMagicContextStorageDir() rather than only the DB-resolver path; otherwise the claim in the comment is overstated for those callers.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/plugin/src/features/magic-context/storage-db.ts, line 187:

<comment>The rewritten comment/stated goal claim uniform coverage "for every other caller alike" and "structurally impossible for ANY test to read or migrate production data", but the NODE_ENV=test redirect (getTestBackstopDbDir) stays only inside resolveDatabasePath. In the documented no-preload window (NODE_ENV=test, MAGIC_CONTEXT_TEST_DATA_DIR unset, XDG_DATA_HOME unset) callers that use getMagicContextStorageDir() directly — CLI doctors integrity_check (doctor.ts:64, doctor-pi.ts:575, diagnostics-pi.ts:454) and announcement.ts/models-dev-cache.ts — still resolve to the real ~/.local/share and can touch/migrate the production DB, i.e. the v26/v41 incident class this PR says it closes. If MAGIC/CWD-independent protection is intended to be truly uniform, the backstop needs to apply to getMagicContextStorageDir() rather than only the DB-resolver path; otherwise the claim in the comment is overstated for those callers.</comment>

<file context>
@@ -198,7 +184,11 @@ export function resolveDatabasePath(dbPathOverride?: string): { dbDir: string; d
     // helper calls), getMagicContextStorageDir() already points inside that
     // controlled dir — honor it, do not override.
-    if (process.env.NODE_ENV === "test" && !process.env.XDG_DATA_HOME) {
+    if (
+        process.env.NODE_ENV === "test" &&
+        !process.env.XDG_DATA_HOME &&
</file context>

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Valid, and fixed in 9cfcad5 by hoisting the backstop rather than softening the claim.

Reproduced first, with NODE_ENV=test and neither guard var set:

getMagicContextStorageDir() -> /home/…/.local/share/cortexkit/magic-context   # production
resolveDatabasePath()       -> /tmp/mc-test-db-backstop-XJ6lvp/…/context.db   # protected

So the callers you named were reaching production while the DB resolver was safely redirected — the exact class this PR claims to close.

getTestBackstopDbDir() moved into data-path.ts and getMagicContextStorageDir() now applies both guards; resolveDatabasePath() has no isolation branch left. Path shape is unchanged (the backstop dir already ended in cortexkit/magic-context). The one-time warning uses console.warn because logger.ts imports data-path.ts.

After: both resolve to the same temp root, memoized across calls, and production (no NODE_ENV) still resolves to the real path. New test pins it; plugin suite 3622 pass, CLI 296 pass / 2 skip.

Comment thread packages/plugin/src/shared/data-path.ts Outdated
Review feedback on cortexkit#296 (cubic, storage-db.ts:187): the PR claimed uniform
coverage, but only MAGIC_CONTEXT_TEST_DATA_DIR moved into
getMagicContextStorageDir(). The CWD-independent NODE_ENV backstop stayed
in resolveDatabasePath(), so in the no-preload window the claim was false
for exactly the callers this PR was about.

Reproduced with NODE_ENV=test and neither guard var set:

  getMagicContextStorageDir() -> ~/.local/share/cortexkit/magic-context
  resolveDatabasePath()       -> /tmp/mc-test-db-backstop-*/…/context.db

The CLI doctors build join(getMagicContextStorageDir(), "context.db")
themselves and run PRAGMA integrity_check on it, so they took the first
path — production — while the DB resolver was safely redirected. Same for
announcement.ts and models-dev-cache.ts.

Move the backstop next to the guard it backs up. resolveDatabasePath()
now has no isolation branch at all; both guards live in one place and
every caller inherits them. Path shape is unchanged: the backstop dir
already ended in cortexkit/magic-context, so the resolver still appends
context.db to the same root.

The warning uses console.warn rather than the logger because logger.ts
imports data-path.ts.

Also correct the doc comment's claim that no test mutates the guard var
(cubic, data-path.ts:180) — data-path.test.ts sets and restores it.

@cubic-dev-ai cubic-dev-ai Bot 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.

All reported issues were addressed across 3 files (changes from recent commits).

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread packages/plugin/src/shared/data-path.test.ts
The suite's afterEach restored a saved value only when it was defined, so
a var that started unset stayed set after the test that set it. Two tests
lift a guard to assert production shape (the layout test deletes
MAGIC_CONTEXT_TEST_DATA_DIR and NODE_ENV; the backstop test sets
NODE_ENV), which made the result order-dependent in any run where those
vars are not already populated — and NODE_ENV was not saved at all.

Replace the hand-rolled restores with a loop over the saved snapshot that
deletes when the original was undefined, and add NODE_ENV to it. Verified
with --rerun-each 5 (125 pass) and against the full plugin suite.

@cubic-dev-ai cubic-dev-ai Bot 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.

1 issue found across 3 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/plugin/src/shared/data-path.ts">

<violation number="1" location="packages/plugin/src/shared/data-path.ts:202">
P1: Tests that unset `XDG_DATA_HOME` still open and checkpoint the user's legacy OpenCode DB during `openDatabase()` migration; apply the same test isolation to the legacy source or skip legacy migration under this guard.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

if (!process.env.XDG_DATA_HOME) {
const testDataDir = process.env.MAGIC_CONTEXT_TEST_DATA_DIR;
if (testDataDir) {
return path.join(testDataDir, "cortexkit", "magic-context");

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1: Tests that unset XDG_DATA_HOME still open and checkpoint the user's legacy OpenCode DB during openDatabase() migration; apply the same test isolation to the legacy source or skip legacy migration under this guard.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/plugin/src/shared/data-path.ts, line 202:

<comment>Tests that unset `XDG_DATA_HOME` still open and checkpoint the user's legacy OpenCode DB during `openDatabase()` migration; apply the same test isolation to the legacy source or skip legacy migration under this guard.</comment>

<file context>
@@ -167,11 +167,76 @@ export function getOpenCodeStorageDir(): string {
+    if (!process.env.XDG_DATA_HOME) {
+        const testDataDir = process.env.MAGIC_CONTEXT_TEST_DATA_DIR;
+        if (testDataDir) {
+            return path.join(testDataDir, "cortexkit", "magic-context");
+        }
+        if (process.env.NODE_ENV === "test") {
</file context>

@ualtinok
ualtinok merged commit 6a3cb2c into cortexkit:master Aug 10, 2026
14 checks passed
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.

2 participants