Merge pull request #1200 from kaitranntt/kai/feat/1199-shared-resource-controls

feat(auth): add shared resource controls
This commit is contained in:
Kai (Tam Nhu) Tran authored and GitHub committed 2026-05-10 22:01:57 -04:00
commit 248b6b735d
46 files changed
+2721 -144

No files matched your search

+29
View File
@@ -63,6 +63,35 @@ describe('auth command args parsing', () => {
expect(parsed.contextGroup).toBe('sprint-a');
});
it('parses shared resource mode value for resources command', () => {
const parsed = parseArgs(['work', '--mode', 'profile-local'], { allowMode: true });
expect(parsed.profileName).toBe('work');
expect(parsed.mode).toBe('profile-local');
});
it('parses inline shared resource mode value', () => {
const parsed = parseArgs(['work', '--mode=shared'], { allowMode: true });
expect(parsed.profileName).toBe('work');
expect(parsed.mode).toBe('shared');
});
it('flags missing shared resource mode value as empty string', () => {
const parsed = parseArgs(['work', '--mode'], { allowMode: true });
expect(parsed.profileName).toBe('work');
expect(parsed.mode).toBe('');
});
it('treats shared resource mode as unknown unless the command opts in', () => {
const parsed = parseArgs(['work', '--mode', 'shared']);
expect(parsed.profileName).toBe('work');
expect(parsed.mode).toBeUndefined();
expect(parsed.unknownFlags).toEqual(['--mode']);
});
it('tracks unknown flags and keeps positional profile intact', () => {
const parsed = parseArgs(['--foo', 'bar', 'work']);
+248
View File
@@ -0,0 +1,248 @@
import { afterEach, beforeEach, describe, expect, it, spyOn } from 'bun:test';
import * as fs from 'fs';
import * as os from 'os';
import * as path from 'path';
import ProfileRegistry from '../../src/auth/profile-registry';
import InstanceManager from '../../src/management/instance-manager';
import { handleResources } from '../../src/auth/commands/resources-command';
import { handleCreate } from '../../src/auth/commands/create-command';
import { handleList } from '../../src/auth/commands/list-command';
import { handleShow } from '../../src/auth/commands/show-command';
import { handleBackup } from '../../src/auth/commands/backup-command';
import { handleRemove } from '../../src/auth/commands/remove-command';
import { handleDefault, handleResetDefault } from '../../src/auth/commands/default-command';
async function expectProfileExit(action: () => Promise<void>): Promise<string> {
const originalExit = process.exit;
const originalLog = console.log;
const originalError = console.error;
const lines: string[] = [];
process.exit = ((code?: number) => {
throw new Error(`process.exit(${code ?? 0})`);
}) as typeof process.exit;
console.log = (...args: unknown[]) => {
lines.push(args.map(String).join(' '));
};
console.error = (...args: unknown[]) => {
lines.push(args.map(String).join(' '));
};
try {
await expect(action()).rejects.toThrow('process.exit(7)');
} finally {
process.exit = originalExit;
console.log = originalLog;
console.error = originalError;
}
return lines.join('\n');
}
describe('auth resources command', () => {
let tempRoot = '';
let originalCcsHome: string | undefined;
let originalUnifiedMode: string | undefined;
beforeEach(() => {
tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'ccs-auth-resources-'));
originalCcsHome = process.env.CCS_HOME;
originalUnifiedMode = process.env.CCS_UNIFIED_CONFIG;
process.env.CCS_HOME = tempRoot;
process.env.CCS_UNIFIED_CONFIG = '1';
});
afterEach(() => {
if (originalCcsHome !== undefined) process.env.CCS_HOME = originalCcsHome;
else delete process.env.CCS_HOME;
if (originalUnifiedMode !== undefined) process.env.CCS_UNIFIED_CONFIG = originalUnifiedMode;
else delete process.env.CCS_UNIFIED_CONFIG;
if (tempRoot && fs.existsSync(tempRoot)) {
fs.rmSync(tempRoot, { recursive: true, force: true });
}
});
it('updates an existing account shared resource mode without changing context metadata', async () => {
const ccsDir = path.join(tempRoot, '.ccs');
fs.mkdirSync(ccsDir, { recursive: true });
fs.writeFileSync(
path.join(ccsDir, 'config.yaml'),
[
'version: 8',
'accounts:',
' work:',
' created: "2026-02-01T00:00:00.000Z"',
' last_used: null',
' context_mode: shared',
' context_group: sprint-a',
'profiles: {}',
'cliproxy:',
' oauth_accounts: {}',
' providers: {}',
' variants: {}',
].join('\n'),
'utf8'
);
const registry = new ProfileRegistry();
const instanceMgr = new InstanceManager();
const ensureSpy = spyOn(InstanceManager.prototype, 'ensureInstance').mockResolvedValue(
path.join(ccsDir, 'instances', 'work')
);
const lines: string[] = [];
const originalLog = console.log;
console.log = (...args: unknown[]) => {
lines.push(args.map(String).join(' '));
};
try {
await handleResources(
{
registry,
instanceMgr,
version: 'test',
},
['work', '--mode', 'profile-local', '--json']
);
} finally {
console.log = originalLog;
ensureSpy.mockRestore();
}
const output = JSON.parse(lines.join('\n')) as {
shared_resource_mode: string;
bare?: boolean;
};
expect(output.shared_resource_mode).toBe('profile-local');
expect(output.bare).toBe(true);
const account = registry.getAllAccountsUnified().work;
expect(account.shared_resource_mode).toBe('profile-local');
expect(account.bare).toBe(true);
expect(account.context_mode).toBe('shared');
expect(account.context_group).toBe('sprint-a');
});
it('rolls back inferred shared metadata when instance reconciliation fails', async () => {
const ccsDir = path.join(tempRoot, '.ccs');
fs.mkdirSync(ccsDir, { recursive: true });
fs.writeFileSync(
path.join(ccsDir, 'config.yaml'),
[
'version: 8',
'accounts:',
' work:',
' created: "2026-02-01T00:00:00.000Z"',
' last_used: null',
'profiles: {}',
'cliproxy:',
' oauth_accounts: {}',
' providers: {}',
' variants: {}',
].join('\n'),
'utf8'
);
const registry = new ProfileRegistry();
const instanceMgr = new InstanceManager();
const ensureSpy = spyOn(InstanceManager.prototype, 'ensureInstance').mockRejectedValue(
new Error('reconcile failed')
);
try {
await expect(
handleResources(
{
registry,
instanceMgr,
version: 'test',
},
['work', '--mode', 'profile-local']
)
).rejects.toThrow('reconcile failed');
} finally {
ensureSpy.mockRestore();
}
const account = registry.getAllAccountsUnified().work;
expect(account.shared_resource_mode).toBeUndefined();
expect(account.bare).toBeUndefined();
});
it('rejects resources --mode without a value instead of showing current mode', async () => {
const ccsDir = path.join(tempRoot, '.ccs');
fs.mkdirSync(ccsDir, { recursive: true });
fs.writeFileSync(
path.join(ccsDir, 'config.yaml'),
[
'version: 8',
'accounts:',
' work:',
' created: "2026-02-01T00:00:00.000Z"',
' last_used: null',
'profiles: {}',
'cliproxy:',
' oauth_accounts: {}',
' providers: {}',
' variants: {}',
].join('\n'),
'utf8'
);
const registry = new ProfileRegistry();
const instanceMgr = new InstanceManager();
const output = await expectProfileExit(() =>
handleResources(
{
registry,
instanceMgr,
version: 'test',
},
['work', '--mode']
)
);
expect(output).toContain('Missing value for --mode: expected shared|profile-local');
});
it('rejects --mode on auth create instead of silently ignoring it', async () => {
const registry = new ProfileRegistry();
const instanceMgr = new InstanceManager();
const output = await expectProfileExit(() =>
handleCreate(
{
registry,
instanceMgr,
version: 'test',
},
['work', '--mode', 'profile-local']
)
);
expect(output).toContain('Unknown option(s): "--mode"');
});
it('rejects --mode on non-resources auth commands instead of silently ignoring it', async () => {
const registry = new ProfileRegistry();
const instanceMgr = new InstanceManager();
const ctx = { registry, instanceMgr, version: 'test' };
const cases: Array<[string, () => Promise<void>]> = [
['list', () => handleList(ctx, ['--mode', 'shared'])],
['show', () => handleShow(ctx, ['work', '--mode=shared'])],
['backup', () => handleBackup(ctx, ['work', '--mode', 'profile-local'])],
['remove', () => handleRemove(ctx, ['work', '--mode', 'shared'])],
['default', () => handleDefault(ctx, ['work', '--mode', 'shared'])],
['reset-default', () => handleResetDefault(ctx, ['--mode', 'shared'])],
];
for (const [commandName, action] of cases) {
const output = await expectProfileExit(action);
expect(`${commandName}\n${output}`).toContain('Unknown option(s): "--mode"');
}
});
});
@@ -98,6 +98,7 @@ describe('profile-registry context normalization', () => {
const profile = registry.getProfile('work');
expect(profile.bare).toBe(true);
expect(profile.shared_resource_mode).toBe('profile-local');
});
it('persists bare flag for unified accounts and merged projection', () => {
@@ -126,8 +127,52 @@ describe('profile-registry context normalization', () => {
const accounts = registry.getAllAccountsUnified();
expect(accounts.work.bare).toBe(true);
expect(accounts.work.shared_resource_mode).toBe('profile-local');
const merged = registry.getAllProfilesMerged();
expect(merged.work.bare).toBe(true);
expect(merged.work.shared_resource_mode).toBe('profile-local');
});
it('lets explicit shared resource mode override stale unified bare metadata', () => {
process.env.CCS_UNIFIED_CONFIG = '1';
const ccsDir = path.join(tempHome, '.ccs');
fs.mkdirSync(ccsDir, { recursive: true });
fs.writeFileSync(
path.join(ccsDir, 'config.yaml'),
[
'version: 8',
'accounts:',
' work:',
' created: "2026-03-05T00:00:00.000Z"',
' last_used: null',
' shared_resource_mode: shared',
' bare: true',
'profiles: {}',
'cliproxy:',
' oauth_accounts: {}',
' providers: {}',
' variants: {}',
].join('\n'),
'utf8'
);
const registry = new ProfileRegistry();
const accounts = registry.getAllAccountsUnified();
expect(accounts.work.shared_resource_mode).toBe('shared');
expect(accounts.work.bare).toBeUndefined();
});
it('persists explicit profile-local mode for legacy profiles', () => {
const registry = new ProfileRegistry();
registry.createProfile('work', {
type: 'account',
shared_resource_mode: 'profile-local',
});
const profile = registry.getProfile('work');
expect(profile.shared_resource_mode).toBe('profile-local');
expect(profile.bare).toBe(true);
});
});
@@ -0,0 +1,55 @@
import { describe, expect, it } from 'bun:test';
import {
normalizeSharedResourceMetadata,
resolveSharedResourcePolicy,
sharedResourceModeToMetadata,
} from '../../../src/auth/shared-resource-policy';
describe('shared resource policy', () => {
it('defaults missing metadata to shared resources', () => {
const policy = resolveSharedResourcePolicy(undefined);
expect(policy.mode).toBe('shared');
expect(policy.inferred).toBe(true);
expect(policy.profileLocal).toBe(false);
});
it('resolves legacy bare metadata as profile-local', () => {
const policy = resolveSharedResourcePolicy({ bare: true });
expect(policy.mode).toBe('profile-local');
expect(policy.inferred).toBe(true);
expect(policy.profileLocal).toBe(true);
});
it('lets explicit shared mode override stale bare metadata', () => {
const normalized = normalizeSharedResourceMetadata({
shared_resource_mode: 'shared',
bare: true,
});
expect(normalized.shared_resource_mode).toBe('shared');
expect(normalized.bare).toBeUndefined();
expect(resolveSharedResourcePolicy(normalized).profileLocal).toBe(false);
});
it('normalizes explicit profile-local mode to legacy-compatible bare metadata', () => {
const normalized = normalizeSharedResourceMetadata({
shared_resource_mode: 'profile-local',
});
expect(normalized.shared_resource_mode).toBe('profile-local');
expect(normalized.bare).toBe(true);
});
it('builds write metadata for both supported modes', () => {
expect(sharedResourceModeToMetadata('profile-local')).toEqual({
shared_resource_mode: 'profile-local',
bare: true,
});
expect(sharedResourceModeToMetadata('shared')).toEqual({
shared_resource_mode: 'shared',
bare: undefined,
});
});
});
+14 -4
View File
@@ -31,7 +31,7 @@ describe('sync command MCP sync behavior', () => {
mock.restore();
});
it('syncs MCP servers only to non-bare profiles', async () => {
it('syncs MCP servers only to shared-resource profiles', async () => {
spyOn(ClaudeDirInstaller.prototype, 'install').mockReturnValue(true);
spyOn(ClaudeDirInstaller.prototype, 'cleanupDeprecated').mockReturnValue({
success: true,
@@ -42,6 +42,8 @@ describe('sync command MCP sync behavior', () => {
spyOn(ProfileRegistry.prototype, 'getAllProfilesMerged').mockReturnValue({
work: profile(),
sandbox: profile({ bare: true }),
local: profile({ shared_resource_mode: 'profile-local' }),
restored: profile({ bare: true, shared_resource_mode: 'shared' }),
personal: profile(),
});
spyOn(InstanceManager.prototype, 'hasInstance').mockReturnValue(true);
@@ -55,8 +57,16 @@ describe('sync command MCP sync behavior', () => {
await expect(handleSyncCommand()).rejects.toThrow('process.exit(0)');
expect(getInstancePathSpy.mock.calls.map((call) => call[0])).toEqual(['work', 'personal']);
expect(syncMcpSpy.mock.calls.map((call) => call[0])).toEqual(['/tmp/work', '/tmp/personal']);
expect(getInstancePathSpy.mock.calls.map((call) => call[0])).toEqual([
'work',
'restored',
'personal',
]);
expect(syncMcpSpy.mock.calls.map((call) => call[0])).toEqual([
'/tmp/work',
'/tmp/restored',
'/tmp/personal',
]);
});
it('skips MCP sync when all profiles are bare', async () => {
@@ -69,7 +79,7 @@ describe('sync command MCP sync behavior', () => {
spyOn(SharedManager.prototype, 'ensureSharedDirectories').mockImplementation(() => {});
spyOn(ProfileRegistry.prototype, 'getAllProfilesMerged').mockReturnValue({
sandbox: profile({ bare: true }),
experiment: profile({ bare: true }),
experiment: profile({ shared_resource_mode: 'profile-local' }),
});
spyOn(InstanceManager.prototype, 'hasInstance').mockReturnValue(true);
@@ -177,6 +177,43 @@ describe('migration-manager legacy kimi compatibility', () => {
expect(unified?.accounts.personal.continuity_mode).toBeUndefined();
});
it('migrates legacy bare accounts to profile-local shared resource mode', async () => {
fs.writeFileSync(
path.join(ccsDir, 'profiles.json'),
JSON.stringify(
{
default: 'sandbox',
profiles: {
sandbox: {
type: 'account',
created: '2026-02-01T00:00:00.000Z',
last_used: null,
bare: true,
},
restored: {
type: 'account',
created: '2026-02-02T00:00:00.000Z',
last_used: null,
shared_resource_mode: 'shared',
bare: true,
},
},
},
null,
2
)
);
const result = await migrate(false);
expect(result.success).toBe(true);
const unified = loadUnifiedConfig();
expect(unified?.accounts.sandbox.shared_resource_mode).toBe('profile-local');
expect(unified?.accounts.sandbox.bare).toBe(true);
expect(unified?.accounts.restored.shared_resource_mode).toBe('shared');
expect(unified?.accounts.restored.bare).toBeUndefined();
});
it('applies safe browser defaults when migrating legacy config files', async () => {
fs.writeFileSync(
path.join(ccsDir, 'config.json'),
@@ -1,4 +1,4 @@
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it } from 'bun:test';
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, spyOn } from 'bun:test';
import express from 'express';
import * as fs from 'fs';
import * as os from 'os';
@@ -262,6 +262,51 @@ describe('web-server account-routes context normalization', () => {
expect(fs.existsSync(instancePath)).toBe(false);
});
it('reports effective shared resource mode without initializing an account instance', async () => {
const ccsDir = path.join(tempHome, '.ccs');
fs.mkdirSync(ccsDir, { recursive: true });
fs.writeFileSync(
path.join(ccsDir, 'config.yaml'),
[
'version: 12',
'accounts:',
' work:',
' created: "2026-02-01T00:00:00.000Z"',
' shared_resource_mode: profile-local',
' restored:',
' created: "2026-02-02T00:00:00.000Z"',
' shared_resource_mode: shared',
' bare: true',
'profiles: {}',
'cliproxy:',
' oauth_accounts: {}',
' providers: {}',
' variants: {}',
].join('\n'),
'utf8'
);
const payload = await getJson<{
accounts: Array<{
name: string;
shared_resource_mode?: string;
shared_resource_inferred?: boolean;
bare?: boolean;
}>;
}>(baseUrl, '/api/accounts');
const work = payload.accounts.find((account) => account.name === 'work');
const restored = payload.accounts.find((account) => account.name === 'restored');
expect(work?.shared_resource_mode).toBe('profile-local');
expect(work?.shared_resource_inferred).toBe(false);
expect(work?.bare).toBe(true);
expect(restored?.shared_resource_mode).toBe('shared');
expect(restored?.shared_resource_inferred).toBe(false);
expect(restored?.bare).toBeUndefined();
expect(fs.existsSync(path.join(ccsDir, 'instances', 'work'))).toBe(false);
});
it('does not delete metadata when instance deletion fails', async () => {
const ccsDir = path.join(tempHome, '.ccs');
fs.mkdirSync(ccsDir, { recursive: true });
@@ -354,6 +399,148 @@ describe('web-server account-routes context normalization', () => {
expect(work?.continuity_mode).toBe('deeper');
});
it('updates existing account shared resource mode without changing history sync metadata', async () => {
const ccsDir = path.join(tempHome, '.ccs');
fs.mkdirSync(ccsDir, { recursive: true });
fs.writeFileSync(
path.join(ccsDir, 'config.yaml'),
[
'version: 8',
'accounts:',
' work:',
' created: "2026-02-01T00:00:00.000Z"',
' last_used: null',
' context_mode: shared',
' context_group: sprint-a',
' continuity_mode: deeper',
'profiles: {}',
'cliproxy:',
' oauth_accounts: {}',
' providers: {}',
' variants: {}',
].join('\n'),
'utf8'
);
const ensureSpy = spyOn(InstanceManager.prototype, 'ensureInstance').mockResolvedValue(
path.join(ccsDir, 'instances', 'work')
);
try {
const response = await putJson(baseUrl, '/api/accounts/work/shared-resources', {
shared_resource_mode: 'profile-local',
});
expect(response.status).toBe(200);
const payload = (await response.json()) as {
shared_resource_mode: string;
shared_resource_inferred?: boolean;
};
expect(payload.shared_resource_mode).toBe('profile-local');
expect(payload.shared_resource_inferred).toBe(false);
expect(ensureSpy).toHaveBeenCalledWith(
'work',
{
mode: 'shared',
group: 'sprint-a',
continuityMode: 'deeper',
},
{ bare: true }
);
} finally {
ensureSpy.mockRestore();
}
const registry = new ProfileRegistry();
const account = registry.getAllAccountsUnified().work;
expect(account.shared_resource_mode).toBe('profile-local');
expect(account.bare).toBe(true);
expect(account.context_mode).toBe('shared');
expect(account.context_group).toBe('sprint-a');
expect(account.continuity_mode).toBe('deeper');
});
it('rolls back inferred shared resource metadata when instance reconciliation fails', async () => {
const ccsDir = path.join(tempHome, '.ccs');
fs.mkdirSync(ccsDir, { recursive: true });
fs.writeFileSync(
path.join(ccsDir, 'config.yaml'),
[
'version: 8',
'accounts:',
' work:',
' created: "2026-02-01T00:00:00.000Z"',
' last_used: null',
'profiles: {}',
'cliproxy:',
' oauth_accounts: {}',
' providers: {}',
' variants: {}',
].join('\n'),
'utf8'
);
const ensureSpy = spyOn(InstanceManager.prototype, 'ensureInstance').mockRejectedValue(
new Error('reconcile failed')
);
try {
const response = await putJson(baseUrl, '/api/accounts/work/shared-resources', {
shared_resource_mode: 'profile-local',
});
expect(response.status).toBe(500);
const payload = (await response.json()) as { error: string };
expect(payload.error).toContain('reconcile failed');
} finally {
ensureSpy.mockRestore();
}
const registry = new ProfileRegistry();
const account = registry.getAllAccountsUnified().work;
expect(account.shared_resource_mode).toBeUndefined();
expect(account.bare).toBeUndefined();
});
it('rejects invalid shared resource mode updates', async () => {
const ccsDir = path.join(tempHome, '.ccs');
fs.mkdirSync(ccsDir, { recursive: true });
fs.writeFileSync(
path.join(ccsDir, 'config.yaml'),
[
'version: 8',
'accounts:',
' work:',
' created: "2026-02-01T00:00:00.000Z"',
' last_used: null',
'profiles: {}',
'cliproxy:',
' oauth_accounts: {}',
' providers: {}',
' variants: {}',
].join('\n'),
'utf8'
);
const response = await putJson(baseUrl, '/api/accounts/work/shared-resources', {
shared_resource_mode: 'plugins-only',
});
expect(response.status).toBe(400);
const payload = (await response.json()) as { error: string };
expect(payload.error).toContain('shared_resource_mode');
});
it('rejects shared resource updates for CLIProxy account identifiers', async () => {
const response = await putJson(baseUrl, '/api/accounts/gemini:test/shared-resources', {
shared_resource_mode: 'profile-local',
});
expect(response.status).toBe(400);
const payload = (await response.json()) as { error: string };
expect(payload.error).toContain('CLIProxy');
});
it('rejects shared mode updates without context_group', async () => {
const ccsDir = path.join(tempHome, '.ccs');
fs.mkdirSync(ccsDir, { recursive: true });
+212
View File
@@ -285,6 +285,218 @@ describe('web-server shared-routes', () => {
expect(payload.contentPath).toBe(fs.realpathSync(path.join(skillTargetDir, 'SKILL.md')));
});
it('hides plugin infrastructure directories when no plugins are installed', async () => {
const pluginsDir = path.join(ccsDir, 'shared', 'plugins');
const cacheDir = path.join(pluginsDir, 'cache');
fs.mkdirSync(path.join(cacheDir, 'payloads'), { recursive: true });
fs.writeFileSync(path.join(cacheDir, 'plugin-index.json'), '{}');
fs.writeFileSync(
path.join(pluginsDir, 'installed_plugins.json'),
JSON.stringify({ version: 2, plugins: {} }, null, 2)
);
const listPayload = await getJson<{
items: Array<{ name: string; type: string; description: string; path: string }>;
}>(baseUrl, '/api/shared/plugins');
expect(listPayload.items).toEqual([]);
const contentResponse = await fetch(
`${baseUrl}/api/shared/content?type=plugins&path=${encodeURIComponent(cacheDir)}`
);
expect(contentResponse.status).toBe(404);
const contentPayload = (await contentResponse.json()) as { error: string };
expect(contentPayload.error).toBe('Shared content not found');
});
it('lists installed plugins from the shared plugin registry', async () => {
const pluginsDir = path.join(ccsDir, 'shared', 'plugins');
fs.mkdirSync(pluginsDir, { recursive: true });
fs.writeFileSync(
path.join(pluginsDir, 'installed_plugins.json'),
JSON.stringify(
{
version: 2,
plugins: {
'discord@claude-plugins-official': [
{
installPath: path.join(pluginsDir, 'cache', 'discord'),
enabled: true,
},
],
},
},
null,
2
)
);
fs.writeFileSync(
path.join(pluginsDir, 'known_marketplaces.json'),
JSON.stringify(
{
'claude-plugins-official': {
source: { type: 'github', repo: 'anthropics/claude-plugins' },
installLocation: path.join(pluginsDir, 'marketplaces', 'claude-plugins-official'),
},
},
null,
2
)
);
const listPayload = await getJson<{
items: Array<{ name: string; type: string; description: string; path: string }>;
}>(baseUrl, '/api/shared/plugins');
expect(listPayload.items).toEqual([
{
name: 'discord@claude-plugins-official',
type: 'plugin',
description: 'Installed from claude-plugins-official; 1 record in shared registry',
path: 'plugin-registry:discord%40claude-plugins-official',
},
]);
const contentPayload = await getJson<{ content: string; contentPath: string }>(
baseUrl,
`/api/shared/content?type=plugins&path=${encodeURIComponent(listPayload.items[0].path)}`
);
expect(contentPayload.content).toContain('# discord@claude-plugins-official');
expect(contentPayload.content).toContain('## Marketplace Registry Entry');
expect(contentPayload.content).toContain('## Plugin Registry Entry');
expect(contentPayload.contentPath).toBe(
fs.realpathSync(path.join(pluginsDir, 'installed_plugins.json'))
);
});
it('rejects plugin registry prototype keys as plugin names', async () => {
const pluginsDir = path.join(ccsDir, 'shared', 'plugins');
fs.mkdirSync(pluginsDir, { recursive: true });
fs.writeFileSync(
path.join(pluginsDir, 'installed_plugins.json'),
JSON.stringify({ version: 2, plugins: {} }, null, 2)
);
const response = await fetch(
`${baseUrl}/api/shared/content?type=plugins&path=${encodeURIComponent('plugin-registry:toString')}`
);
expect(response.status).toBe(404);
const payload = (await response.json()) as { error: string };
expect(payload.error).toBe('Shared content not found');
});
it('returns real shared settings content when settings.json is present', async () => {
const settingsPath = path.join(ccsDir, 'shared', 'settings.json');
fs.writeFileSync(
settingsPath,
JSON.stringify(
{
env: { ANTHROPIC_MODEL: 'claude-sonnet-4-5' },
permissions: { allow: ['Bash(git status)'] },
},
null,
2
)
);
const summaryPayload = await getJson<{ settings: boolean; total: number }>(
baseUrl,
'/api/shared/summary'
);
expect(summaryPayload.settings).toBe(true);
expect(summaryPayload.total).toBe(1);
const contentPayload = await getJson<{ content: string; contentPath: string }>(
baseUrl,
`/api/shared/content?type=settings&path=${encodeURIComponent('settings.json')}`
);
expect(contentPayload.content).toContain('"ANTHROPIC_MODEL": "claude-sonnet-4-5"');
expect(contentPayload.content).toContain('"allow"');
expect(contentPayload.contentPath).toBe(fs.realpathSync(settingsPath));
});
it('returns shared settings content when settings.json links to the Claude config file', async () => {
const claudeDir = path.join(tempHome, '.claude');
process.env.CLAUDE_CONFIG_DIR = claudeDir;
fs.mkdirSync(claudeDir, { recursive: true });
const claudeSettingsPath = path.join(claudeDir, 'settings.json');
fs.writeFileSync(
claudeSettingsPath,
JSON.stringify({ hooks: { PreToolUse: [] }, env: { ANTHROPIC_MODEL: 'claude-opus-4-1' } })
);
const sharedSettingsPath = path.join(ccsDir, 'shared', 'settings.json');
createFileSymlink(claudeSettingsPath, sharedSettingsPath);
const summaryPayload = await getJson<{ settings: boolean; total: number }>(
baseUrl,
'/api/shared/summary'
);
expect(summaryPayload.settings).toBe(true);
expect(summaryPayload.total).toBe(1);
const contentPayload = await getJson<{ content: string; contentPath: string }>(
baseUrl,
`/api/shared/content?type=settings&path=${encodeURIComponent('settings.json')}`
);
expect(contentPayload.content).toContain('"ANTHROPIC_MODEL": "claude-opus-4-1"');
expect(contentPayload.contentPath).toBe(fs.realpathSync(claudeSettingsPath));
});
it('rejects shared settings content when settings.json resolves outside the shared directory', async () => {
const settingsPath = path.join(ccsDir, 'shared', 'settings.json');
const outsideSettingsPath = path.join(tempHome, 'outside-settings.json');
fs.writeFileSync(outsideSettingsPath, '{"env":{"SECRET":"do-not-read"}}');
createFileSymlink(outsideSettingsPath, settingsPath);
const response = await fetch(
`${baseUrl}/api/shared/content?type=settings&path=${encodeURIComponent('settings.json')}`
);
expect(response.status).toBe(404);
const payload = (await response.json()) as { error: string };
expect(payload.error).toBe('Shared content not found');
});
it('rejects shared settings symlinks to non-settings files inside the Claude config directory', async () => {
const claudeDir = path.join(tempHome, '.claude');
process.env.CLAUDE_CONFIG_DIR = claudeDir;
fs.mkdirSync(claudeDir, { recursive: true });
const otherClaudeFile = path.join(claudeDir, 'credentials.json');
fs.writeFileSync(otherClaudeFile, '{"SECRET":"do-not-read"}');
createFileSymlink(otherClaudeFile, path.join(ccsDir, 'shared', 'settings.json'));
const response = await fetch(
`${baseUrl}/api/shared/content?type=settings&path=${encodeURIComponent('settings.json')}`
);
expect(response.status).toBe(404);
const payload = (await response.json()) as { error: string };
expect(payload.error).toBe('Shared content not found');
});
it('returns README content for a shared plugin directory when available', async () => {
const pluginsDir = path.join(ccsDir, 'shared', 'plugins');
const pluginDir = path.join(pluginsDir, 'legacy-plugin');
fs.mkdirSync(pluginDir, { recursive: true });
fs.writeFileSync(path.join(pluginDir, 'README.md'), '# Plugin Marketplace\n\nShared docs');
const payload = await getJson<{ content: string; contentPath: string }>(
baseUrl,
`/api/shared/content?type=plugins&path=${encodeURIComponent(pluginDir)}`
);
expect(payload.content).toContain('Shared docs');
expect(payload.contentPath).toBe(fs.realpathSync(path.join(pluginDir, 'README.md')));
});
it('does not use markdown frontmatter fences as descriptions when frontmatter is malformed', async () => {
const commandsDir = path.join(ccsDir, 'shared', 'commands');
fs.mkdirSync(commandsDir, { recursive: true });