{"record":{"id":"053e2d8e093b5889","repo":"ruvnet/RuView","slug":"refusing-cli-access-ruview-repository-markers-are","errorCode":null,"errorMessage":"Refusing CLI access: RuView repository markers are missing${missing.length ? ` (${missing.join(', ')})` : ''}","messagePattern":"Refusing CLI access: RuView repository markers are missing(.+?)\\)` : ''\\}","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"harness/ruview/src/repo-trust.js","lineNumber":18,"sourceCode":"// SPDX-License-Identifier: MIT\nimport { existsSync, realpathSync, readFileSync, statSync } from 'node:fs';\nimport { isAbsolute, join, relative } from 'node:path';\nconst REQUIRED_MARKERS = ['.git', 'README.md', 'v2'];\nconst RUVIEW_MARKERS = ['firmware', 'wifi_densepose'];\nfunction isWithin(parent, child) {\n  const rel = relative(parent, child);\n  return rel === '' || (!rel.startsWith('..') && !isAbsolute(rel));\n}\nexport function assertTrustedRuViewRepo(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) throw new Error('Refusing CLI access: repository does not match the configured trusted root');\n  if (!statSync(root).isDirectory()) throw new Error('Refusing CLI access: trusted root is not a directory');\n  const missing = REQUIRED_MARKERS.filter((marker) => !existsSync(join(root, marker)));\n  if (missing.length || !RUVIEW_MARKERS.some((marker) => existsSync(join(root, marker)))) {\n    throw new Error(`Refusing CLI access: RuView repository markers are missing${missing.length ? ` (${missing.join(', ')})` : ''}`);\n  }\n  const readme = readFileSync(join(root, 'README.md'), 'utf8').slice(0, 131_072);\n  if (!/\\b(?:RuView|wifi[- ]densepose)\\b/i.test(readme)) throw new Error('Refusing CLI access: README does not identify a RuView checkout');\n  return root;\n}\n","sourceCodeStart":1,"sourceCodeEnd":24,"githubUrl":"https://github.com/ruvnet/RuView/blob/4685618388a5e49fad5b3005806f3bdd6a7c25c3/harness/ruview/src/repo-trust.js#L1-L24","documentation":"The repo-trust gate verifies the resolved root looks like a real RuView checkout: REQUIRED_MARKERS ['.git', 'README.md', 'v2'] must all exist, and at least one of RUVIEW_MARKERS ['firmware', 'wifi_densepose'] must exist. Missing required markers are listed in the error message. This defeats pointing the CLI at an unrelated or partial directory.","triggerScenarios":"repoRoot set to harness/ruview or any subdirectory (no .git there), a tarball/sparse checkout shipped without .git or without v2/, or a directory that has never been a RuView clone.","commonSituations":"Downloaded source archives (no .git); partial/sparse checkouts for CI caching; running the CLI from the wrong cwd after cd-ing into a subfolder; copied trees that dropped large dirs like v2.","solutions":["Run from the root of a complete git clone of the RuView repository (has .git, README.md, v2/, firmware/).","If using archives/sparse checkouts in CI, include the missing marker paths or switch to a full clone.","Verify quickly: ls -d .git README.md v2 firmware in the intended repoRoot before invoking."],"exampleFix":"// before\nrunClaudeCode({ prompt, repoRoot: process.cwd() }) // cwd was harness/ruview\n// after\nrunClaudeCode({ prompt, repoRoot: '/repos/RuView' }) // full checkout root containing .git, README.md, v2/, firmware/","handlingStrategy":"validation","validationCode":"import { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nconst required = ['.git', 'README.md', 'v2'];\nconst optional = ['firmware', 'wifi_densepose'];\nconst ok = required.every((m) => existsSync(join(repoRoot, m))) && optional.some((m) => existsSync(join(repoRoot, m)));\nif (!ok) throw new Error(`${repoRoot} is not a complete RuView checkout (needs .git, README.md, v2 and firmware/ or wifi_densepose/)`);\n// safe to invoke host adapters with repoRoot","typeGuard":null,"tryCatchPattern":"try {\n  await runClaudeCode({ prompt, repoRoot });\n} catch (e) {\n  if (e instanceof Error && e.message.includes('repository markers are missing')) {\n    // point the user at a full clone; do not fabricate markers\n    throw new Error(`run from the root of a full RuView clone: ${e.message}`);\n  }\n  throw e;\n}","preventionTips":["Always run harness host commands from the root of a complete git clone.","In CI, avoid sparse checkouts/archive downloads that drop .git or v2/.","Pre-check the four marker paths before invoking so failures name your own context."],"tags":["security","fail-closed","repository-layout","checkout","trust-gate","ruview-harness"],"backgroundTag":null,"analyzedSha":"4685618388a5e49fad5b3005806f3bdd6a7c25c3","analyzedAt":"2026-08-16T06:09:40.886Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}