From d2f721a030dbb011d07ed52b9350d153d5d59ff4 Mon Sep 17 00:00:00 2001 From: haelyra <49814733+haelyra@users.noreply.github.com> Date: Sun, 11 Oct 2026 02:22:24 -0400 Subject: [PATCH] fix: reject recursive callback relays and verify profile display isolation --- docker/plugin-setup/codex-auth-relay.js | 3 +++ tests/docker/codex-auth-relay.test.js | 12 +++++++++- tests/hooks/ecc-statusline-usage.test.js | 29 ++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/docker/plugin-setup/codex-auth-relay.js b/docker/plugin-setup/codex-auth-relay.js index 155abf90d..ec8965d72 100644 --- a/docker/plugin-setup/codex-auth-relay.js +++ b/docker/plugin-setup/codex-auth-relay.js @@ -30,6 +30,9 @@ function portFromEnv(name, fallback) { const listenPort = portFromEnv('ECC_RELAY_LISTEN', 1456); const targetPort = portFromEnv('ECC_RELAY_TARGET', 1455); +if (listenPort === targetPort) { + throw new Error('ECC_RELAY_LISTEN and ECC_RELAY_TARGET must differ'); +} net.createServer(client => { const upstream = net.connect(targetPort, '127.0.0.1'); diff --git a/tests/docker/codex-auth-relay.test.js b/tests/docker/codex-auth-relay.test.js index 9c8aa40ea..2ddc85c87 100644 --- a/tests/docker/codex-auth-relay.test.js +++ b/tests/docker/codex-auth-relay.test.js @@ -3,7 +3,7 @@ const assert = require('node:assert/strict'); const net = require('node:net'); const path = require('node:path'); -const { spawn } = require('node:child_process'); +const { spawn, spawnSync } = require('node:child_process'); const { once } = require('node:events'); const test = require('node:test'); @@ -60,3 +60,13 @@ for (const value of ['0', '-1', '65536', '1.5', 'not-a-port']) { assert.match(stderr, /ECC_RELAY_LISTEN must be an integer port/); }); } + +for (const port of ['1455', '24567']) { + test(`rejects self-relaying port ${port} before listening`, () => { + const child = spawnSync(process.execPath, [script], { timeout: 1500, encoding: 'utf8', + env: { ...process.env, ECC_RELAY_LISTEN: port, ECC_RELAY_TARGET: port } }); + assert.equal(child.status, 1, 'equal ports must exit immediately without a listener'); + assert.match(child.stderr, /ECC_RELAY_LISTEN and ECC_RELAY_TARGET must differ/); + assert.equal(child.stdout, ''); + }); +} diff --git a/tests/hooks/ecc-statusline-usage.test.js b/tests/hooks/ecc-statusline-usage.test.js index 5d045233c..5f1870e53 100644 --- a/tests/hooks/ecc-statusline-usage.test.js +++ b/tests/hooks/ecc-statusline-usage.test.js @@ -29,3 +29,32 @@ test('actual statusline usage display is opt-in and leaves provider settings alo fs.rmSync(home, { recursive: true, force: true }); } }); + +for (const hasSelectedPlugins of [true, false]) { + test(`selected Claude profile plugin metadata ${hasSelectedPlugins ? 'is displayed' : 'never borrows the default'}`, () => { + const home = fs.mkdtempSync(path.join(os.tmpdir(), 'ecc-statusline-profile-')); + try { + const selected = path.join(home, 'selected-profile'); + const writePlugins = (directory, id) => { + fs.mkdirSync(path.join(directory, 'plugins'), { recursive: true }); + fs.writeFileSync(path.join(directory, 'plugins', 'installed_plugins.json'), + JSON.stringify({ version: 2, plugins: { [id]: [{ version: '7.8.9' }] } })); + fs.writeFileSync(path.join(directory, 'settings.json'), + JSON.stringify({ enabledPlugins: { [id]: true } })); + }; + writePlugins(path.join(home, '.claude'), 'default-profile-marker@fixture'); + if (hasSelectedPlugins) writePlugins(selected, 'selected-profile-marker@fixture'); + const child = spawnSync(process.execPath, [path.resolve(__dirname, '../../scripts/hooks/ecc-statusline.js')], { + input: JSON.stringify({ model: { display_name: 'Claude fixture' } }), + encoding: 'utf8', timeout: 5000, + env: { ...process.env, HOME: home, USERPROFILE: home, CLAUDE_CONFIG_DIR: selected, + ECC_STATUSLINE_USAGE: '1', ECC_BAR_GLYPHS: 'ascii' }, + }); + assert.equal(child.status, 0, child.stderr); + assert.doesNotMatch(child.stdout, /default-profile-marker/); + if (hasSelectedPlugins) assert.match(child.stdout, /selected-profile-marker/); + } finally { + fs.rmSync(home, { recursive: true, force: true }); + } + }); +}