{"record":{"id":"de8c153ea13d73ee","repo":"EveryInc/compound-engineering-plugin","slug":"skipping-storedir-resolves-outside-the-managed","errorCode":null,"errorMessage":"Skipping ${storeDir}: resolves outside the managed root via a symlinked ancestor (not modified)","messagePattern":"Skipping (.+?): resolves outside the managed root via a symlinked ancestor \\(not modified\\)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src/targets/managed-artifacts.ts","lineNumber":323,"sourceCode":"  const rel = path.relative(rootResolved, targetResolved)\n  return rel === \"\" || (!rel.startsWith(\"..\") && !path.isAbsolute(rel))\n}\n\nexport async function isPathWithinRoot(rootDir: string, targetPath: string): Promise<boolean> {\n  return isContainedPath(await realpathNearestExisting(rootDir), await realpathNearestExisting(targetPath))\n}\n\n/**\n * Guards a managed store directory against ancestor-symlink traversal. Returns\n * true (and warns once) when `storeDir` escapes `rootDir` via a symlinked\n * ancestor, meaning the caller must skip EVERY operation on that store --\n * cleanup sweeps and writes alike -- since all of them would otherwise act\n * through the link into whatever the user pointed it at. `rootDir` is the\n * writer's target root (e.g. `~/.codex`), not the store dir itself.\n */\nexport async function storeRootEscapesManagedRoot(rootDir: string, storeDir: string): Promise<boolean> {\n  if (await isPathWithinRoot(rootDir, storeDir)) return false\n  console.warn(`Skipping ${storeDir}: resolves outside the managed root via a symlinked ancestor (not modified)`)\n  return true\n}\n","sourceCodeStart":305,"sourceCodeEnd":326,"githubUrl":"https://github.com/EveryInc/compound-engineering-plugin/blob/c9c10f8c75412c7232cb2bd663e5fd1cea98d84e/src/targets/managed-artifacts.ts#L305-L326","documentation":"storeRootEscapesManagedRoot in src/targets/managed-artifacts.ts guards against a symlinked ancestor directory making the managed store path resolve outside the writer's target root (e.g. ~/.codex). If the resolved store directory is not within rootDir, every cleanup and write that would act through that link is skipped, because they would otherwise modify whatever external location the user pointed the link at.","triggerScenarios":"Calling any of promptsEscaped, skillsEscaped, agentsEscaped, commandsEscaped, pluginsEscaped, or extensionsEscaped when isPathWithinRoot(rootDir, storeDir) returns false — i.e. storeDir (or an ancestor) is a symlink resolving outside the target root such as ~/.codex.","commonSituations":"Users symlink ~/.codex/skills or ~/.codex/agents to a directory elsewhere (dotfiles sync, shared machines, secondary disks); users whose HOME is symlinked (e.g. /home/user -> /usr/home/user) so realpath resolution moves the store outside the nominal root.","solutions":["If the redirection is intentional, accept the warning: the converter intentionally will not follow the link; manage that location manually or via your dotfiles tooling.","If the symlink is accidental, remove or replace it with a real directory (mkdir after rm) and re-run the install.","If you want per-item links instead, install normally first, then replace individual managed items with symlinks — they will then be preserved per the user-managed-symlink rule.","Verify with `readlink -f <storeDir>` that it resolves where you expect before re-running."],"exampleFix":"// before\nls -la ~/.codex/skills  # symlink -> /data/shared/skills\n// after\nrm ~/.codex/skills\nmkdir ~/.codex/skills\nbun run convert --to codex","handlingStrategy":"validation","validationCode":"import { realpath } from 'node:fs/promises'\nimport path from 'node:path'\nasync function storeWithinRoot(rootDir: string, storeDir: string): Promise<boolean> {\n  const root = await realpath(rootDir).catch(() => rootDir)\n  const store = await realpath(path.dirname(storeDir)).catch(() => path.dirname(storeDir))\n  return store === root || store.startsWith(root + path.sep)\n}\n// if false, a symlinked ancestor redirects the store outside the root","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Avoid symlinking intermediate directories under the target root (~/.codex/skills etc.); link individual files only if needed","Run `readlink -f ~/.codex <storeDir>` before installing to confirm resolution stays inside the root","Beware symlinked HOME directories when the tool compares literal vs resolved paths"],"tags":["symlink","path-traversal","filesystem-safety","codex"],"backgroundTag":"symlink-escape-managed-root","analyzedSha":"c9c10f8c75412c7232cb2bd663e5fd1cea98d84e","analyzedAt":"2026-08-31T15:18:07.959Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}