From d7e6bb242aedbe83b712ac13cefb0e3c06c6580d Mon Sep 17 00:00:00 2001 From: Affaan Mustafa Date: Fri, 27 Mar 2026 07:59:19 -0400 Subject: [PATCH] fix(installer): reject invalid claude settings roots --- scripts/lib/install/apply.js | 3 +++ tests/scripts/install-apply.test.js | 21 +++++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/scripts/lib/install/apply.js b/scripts/lib/install/apply.js index 26fce135..857a1617 100644 --- a/scripts/lib/install/apply.js +++ b/scripts/lib/install/apply.js @@ -49,6 +49,9 @@ function mergeHooksIntoSettings(plan) { if (fs.existsSync(settingsPath)) { try { settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8')); + if (!settings || typeof settings !== 'object' || Array.isArray(settings)) { + throw new Error('root value must be a JSON object'); + } } catch (error) { throw new Error(`Failed to parse existing settings at ${settingsPath}: ${error.message}`); } diff --git a/tests/scripts/install-apply.test.js b/tests/scripts/install-apply.test.js index 13b9d7fa..b82d67aa 100644 --- a/tests/scripts/install-apply.test.js +++ b/tests/scripts/install-apply.test.js @@ -441,6 +441,27 @@ function runTests() { } })) passed++; else failed++; + if (test('fails when existing settings.json root is not an object', () => { + const homeDir = createTempDir('install-apply-home-'); + const projectDir = createTempDir('install-apply-project-'); + + try { + const claudeRoot = path.join(homeDir, '.claude'); + fs.mkdirSync(claudeRoot, { recursive: true }); + const settingsPath = path.join(claudeRoot, 'settings.json'); + fs.writeFileSync(settingsPath, '[]\n'); + + const result = run(['--profile', 'core'], { cwd: projectDir, homeDir }); + assert.strictEqual(result.code, 1); + assert.ok(result.stderr.includes('Failed to parse existing settings at')); + assert.ok(result.stderr.includes('root value must be a JSON object')); + assert.strictEqual(fs.readFileSync(settingsPath, 'utf8'), '[]\n'); + } finally { + cleanup(homeDir); + cleanup(projectDir); + } + })) passed++; else failed++; + if (test('installs from ecc-install.json and persists component selections', () => { const homeDir = createTempDir('install-apply-home-'); const projectDir = createTempDir('install-apply-project-');