{"record":{"id":"e94efd4c3154ab00","repo":"ruvnet/RuView","slug":"refusing-cli-access-trusted-root-is-not-a-directo","errorCode":null,"errorMessage":"Refusing CLI access: trusted root is not a directory","messagePattern":"Refusing CLI access: trusted root is not a directory","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"harness/homecore/src/repo-trust.js","lineNumber":71,"sourceCode":"  const root = parse(current).root;\n  while (true) {\n    if (looksLikeHomecoreRepo(current)) return realpathSync(current);\n    if (current === root) return null;\n    const parent = dirname(current);\n    if (parent === current) return null;\n    current = parent;\n  }\n}\n\nexport function assertTrustedHomecoreRepo(repoRoot, { trustedRoot = repoRoot } = {}) {\n  if (!repoRoot || !trustedRoot) throw new TypeError('repoRoot and trustedRoot are required');\n  const root = realpathSync(repoRoot);\n  const trustAnchor = realpathSync(trustedRoot);\n  if (!isWithin(trustAnchor, root) || root !== trustAnchor) {\n    throw new Error('Refusing CLI access: repository does not match the configured trusted root');\n  }\n  if (!statSync(root).isDirectory()) {\n    throw new Error('Refusing CLI access: trusted root is not a directory');\n  }\n  const missing = REQUIRED_MARKERS.filter((marker) => !existsSync(join(root, marker)));\n  if (missing.length) {\n    throw new Error(`Refusing CLI access: Homecore repository markers are missing (${missing.join(', ')})`);\n  }\n  const readme = readContainedPrefix(root, join(root, 'README.md'), 131_072);\n  if (!/\\b(?:RuView|wifi[- ]densepose)\\b/i.test(readme)) {\n    throw new Error('Refusing CLI access: README does not identify a RuView checkout');\n  }\n  return root;\n}\n","sourceCodeStart":53,"sourceCodeEnd":83,"githubUrl":"https://github.com/ruvnet/RuView/blob/4685618388a5e49fad5b3005806f3bdd6a7c25c3/harness/homecore/src/repo-trust.js#L53-L83","documentation":"Once repoRoot and trustedRoot are confirmed equal, repo-trust stats the resolved root and requires a directory. If the shared path exists but is not a directory (a regular file, archive, or replaced node), trust verification aborts with this error.","triggerScenarios":"assertTrustedHomecoreRepo('/path/ruview.tar.gz') where the same file path is used for both arguments, or the checkout directory being swapped for a file between configuration and call.","commonSituations":"Passing a file (README.md, repo archive) where the repository root is expected, typos pointing at a similarly named file, corrupted checkouts.","solutions":["Pass the checkout directory itself, not any file inside or beside it","Pre-check with statSync(p).isDirectory() before calling","Re-clone the repository if the checkout is corrupted"],"exampleFix":"// before\nawait runVerification({ repo: '/opt/ruview.tar.gz' });\n\n// after\nawait runVerification({ repo: '/opt/RuView' });","handlingStrategy":"validation","validationCode":"import { statSync } from 'node:fs';\nfunction isDirectory(p) {\n  try {\n    return statSync(p).isDirectory();\n  } catch {\n    return false;\n  }\n}\n// use: if (!isDirectory(repoRoot)) throw new Error('repo must be a directory');","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Pass directories only — never archives or files — as the repository root","Validate the shape of user-supplied paths (directory, absolute) at the CLI boundary","If a checkout reports this unexpectedly, verify it was not replaced by a downloaded file"],"tags":["security","filesystem","cli","homecore"],"backgroundTag":null,"analyzedSha":"4685618388a5e49fad5b3005806f3bdd6a7c25c3","analyzedAt":"2026-08-16T06:09:40.886Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}