{"record":{"id":"df867170f7895525","repo":"affaan-m/ECC","slug":"invalid-ecc-repo-root-missing-install-script-at","errorCode":null,"errorMessage":"Invalid ECC repo root: missing install script at ${installApplyPath}","messagePattern":"Invalid ECC repo root: missing install script at (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/auto-update.js","lineNumber":140,"sourceCode":"}\n\n// Recognized ECC package names. A repo root is only trusted to run its\n// install-apply.js if its package.json identifies it as ECC — otherwise a\n// cloned project that ships a nested `evil/{package.json,scripts/install-apply.js}`\n// could drive auto-update into executing attacker code (GHSA-hfpv-w6mp-5g95).\nconst ECC_PACKAGE_NAMES = new Set(['ecc-universal', 'everything-claude-code']);\n\nfunction validateRepoRoot(repoRoot) {\n  const normalized = path.resolve(repoRoot);\n  const packageJsonPath = path.join(normalized, 'package.json');\n  const installApplyPath = path.join(normalized, 'scripts', 'install-apply.js');\n\n  if (!fs.existsSync(packageJsonPath)) {\n    throw new Error(`Invalid ECC repo root: missing package.json at ${packageJsonPath}`);\n  }\n\n  if (!fs.existsSync(installApplyPath)) {\n    throw new Error(`Invalid ECC repo root: missing install script at ${installApplyPath}`);\n  }\n\n  let pkgName = null;\n  try {\n    pkgName = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')).name;\n  } catch {\n    throw new Error(`Invalid ECC repo root: unreadable package.json at ${packageJsonPath}`);\n  }\n  if (!ECC_PACKAGE_NAMES.has(pkgName)) {\n    throw new Error(`Refusing to run install from untrusted repo root ${normalized}: package.json name '${pkgName}' is not an official ECC package.`);\n  }\n\n  return normalized;\n}\n\nfunction runExternalCommand(command, args, options = {}) {\n  const result = spawnSync(command, args, {\n    cwd: options.cwd,","sourceCodeStart":122,"sourceCodeEnd":158,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/scripts/auto-update.js#L122-L158","documentation":"Every element of the changedFiles array must be a string path. A non-string entry (e.g. { path: '...' }) would stringify to '[object Object]' when joined into the security-trigger haystack, silently poisoning the security scan with garbage. The gate rejects the whole payload rather than shipping a corrupted haystack.","triggerScenarios":"Passing changedFiles: [{ path: 'a.js' }, { path: 'b.js' }] (objects); changedFiles: ['a.js', 42, null] (mixed types); a .map step that returns the original object instead of the path field.","commonSituations":"Caller maps a list of file objects from git or an API and forgets to extract the string path; a null/undefined slips into the array from an optional field.","solutions":["Map objects to their path string before passing: changedFiles: files.map(f => f.path).","Filter out nullish entries: changedFiles: files.filter(Boolean).","Add a guard: if (!changedFiles.every(f => typeof f === 'string')) throw in your caller first."],"exampleFix":"// before\norchReview({ diff, changedFiles: files }); // files = [{ path: 'a.js' }, ...]\n\n// after\norchReview({ diff, changedFiles: files.map(f => f.path).filter(Boolean) });","handlingStrategy":"type-guard","validationCode":"// Map file objects to string paths and filter nulls before calling.\nconst changedFiles = rawFiles\n  .map(f => (typeof f === 'string' ? f : f?.path))\n  .filter(f => typeof f === 'string' && f.length > 0);\norchReview({ diff, changedFiles });","typeGuard":"function isStringArray(v) {\n  return Array.isArray(v) && v.every(x => typeof x === 'string');\n}","tryCatchPattern":null,"preventionTips":["When mapping file objects, always extract the string path field explicitly.","Filter out null/undefined entries before passing the array.","Run .every(f => typeof f === 'string') in your caller as a cheap precondition."],"tags":["validation","workflow","type","review-gate","array","security"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}