/** * DeepSeek Harness (`dsh`) run mode. * * The interesting assertions here are the ones that differ from every sibling * CLI, because dsh is shaped differently in two ways: * * 1. the agent is a PROFILE, not the binary, so the spawn line carries * `--profile ` and a profile name has to be treated as a path segment; * 2. the permission switch is an ENV VAR (`DSH_PERMISSION_MODE`), not a flag, * so the thing to pin is that nothing permission-shaped ever reaches the * command line. */ import { describe, expect, it, vi, beforeEach, afterEach } from 'vitest'; import { CreateSessionSchema, QuickStartSchema, HookEventSchema } from '../src/web/schemas.js'; import { buildSpawnCommand } from '../src/tmux-manager.js'; import { defaultDockerCommandForMode } from '../src/docker-hosts.js'; import { defaultRemoteCommandForMode } from '../src/remote-hosts.js'; import { isExternalCliMode, isAltScreenStripMode } from '../src/session.js'; import { hooksAvailableForMode } from '../src/web/session-wait-registry.js'; import { _clampExternalCliBypassForOwner } from '../src/web/routes/session-routes.js'; import { DEEPSEEK_STATE_TO_HOOK_EVENT } from '../src/deepseek-status-shim.js'; vi.mock('../src/utils/deepseek-cli-resolver.js', async (importOriginal) => { const actual = await importOriginal(); return { ...actual, resolveDefaultDeepSeekProfile: vi.fn(() => 'dsh-tui') }; }); describe('DeepSeek mode schemas', () => { it('accepts DeepSeek session creation config', () => { const parsed = CreateSessionSchema.parse({ workingDir: '/tmp', mode: 'deepseek', deepSeekConfig: { profile: 'dsh-tui', permissionMode: 'danger-full-access' }, }); expect(parsed.mode).toBe('deepseek'); expect(parsed.deepSeekConfig).toEqual({ profile: 'dsh-tui', permissionMode: 'danger-full-access' }); }); it('accepts DeepSeek quick-start config', () => { const parsed = QuickStartSchema.parse({ caseName: 'dsh-case', mode: 'deepseek', deepSeekConfig: { resumeSessionId: 'sess_01H9', statusReporting: false }, }); expect(parsed.mode).toBe('deepseek'); expect(parsed.deepSeekConfig?.resumeSessionId).toBe('sess_01H9'); expect(parsed.deepSeekConfig?.statusReporting).toBe(false); }); it('rejects a profile name that is not a single path segment', () => { // A profile is BOTH interpolated into a `bash -c "…"` line and joined into a // filesystem path under $DSH_HOME/profiles, so separators and traversal have // to die at the schema boundary. for (const profile of ['../../etc/passwd', 'a/b', './x', '-rf', 'has space', 'semi;colon']) { expect(() => CreateSessionSchema.parse({ workingDir: '/tmp', mode: 'deepseek', deepSeekConfig: { profile } }) ).toThrow(); } }); it('rejects an unknown permission preset', () => { // The three presets are the harness's own; anything else would be exported // verbatim as DSH_PERMISSION_MODE and silently fall back to its default. expect(() => CreateSessionSchema.parse({ workingDir: '/tmp', mode: 'deepseek', deepSeekConfig: { permissionMode: 'yolo' }, }) ).toThrow(); }); it('rejects unsafe resumeSessionId values', () => { expect(() => CreateSessionSchema.parse({ workingDir: '/tmp', mode: 'deepseek', deepSeekConfig: { resumeSessionId: '../../etc/passwd' }, }) ).toThrow(); }); it('allows DSH_* and DEEPSEEK_* env overrides but not a foreign provider key', () => { const ok = CreateSessionSchema.parse({ workingDir: '/tmp', mode: 'deepseek', envOverrides: { DSH_HOME: '/tmp/dsh', DEEPSEEK_API_KEY: 'sk-test' }, }); expect(ok.envOverrides).toEqual({ DSH_HOME: '/tmp/dsh', DEEPSEEK_API_KEY: 'sk-test' }); // A dsh settings.yaml can name ANY env var as a provider credential // (apiKeyEnv), which is pi's 34-provider-key problem in a new shape. The // allowlist is global, so admitting them would widen every mode at once. expect(() => CreateSessionSchema.parse({ workingDir: '/tmp', mode: 'deepseek', envOverrides: { QWEN5090_API_KEY: 'sk-test' }, }) ).toThrow(); }); }); describe('DeepSeek spawn command', () => { it('boots the requested profile', () => { const cmd = buildSpawnCommand({ mode: 'deepseek', sessionId: 's1', deepSeekConfig: { profile: 'dsh-tui' }, }); expect(cmd).toBe('dsh --profile dsh-tui'); }); it('falls back to the resolved default profile when none was requested', () => { const cmd = buildSpawnCommand({ mode: 'deepseek', sessionId: 's1' }); expect(cmd).toBe('dsh --profile dsh-tui'); }); it('never puts anything permission-shaped on the command line', () => { // The harness has NO permission flag: the switch is the DSH_PERMISSION_MODE // env export, applied via `tmux setenv`. If this ever starts failing, someone // has invented a flag that does not exist. const cmd = buildSpawnCommand({ mode: 'deepseek', sessionId: 's1', deepSeekConfig: { profile: 'dsh-tui', permissionMode: 'danger-full-access' }, }); expect(cmd).toBe('dsh --profile dsh-tui'); expect(cmd).not.toMatch(/danger|approve|permission|yolo|dangerously/i); }); it('prefers an explicit resume id over the most-recent form', () => { const cmd = buildSpawnCommand({ mode: 'deepseek', sessionId: 's1', deepSeekConfig: { profile: 'p', resumeSession: true, resumeSessionId: 'sess_42' }, }); expect(cmd).toBe('dsh --profile p --resume sess_42'); }); it('resumes the most recent session when only the flag is set', () => { const cmd = buildSpawnCommand({ mode: 'deepseek', sessionId: 's1', deepSeekConfig: { profile: 'p', resumeSession: true }, }); expect(cmd).toBe('dsh --profile p --resume'); }); it('drops an unsafe profile rather than interpolating it', () => { // Defense in depth behind the schema: builders must not trust their callers, // because this string is interpolated into a `bash -c "…"` argument. const cmd = buildSpawnCommand({ mode: 'deepseek', sessionId: 's1', deepSeekConfig: { profile: 'evil; rm -rf /' }, }); expect(cmd).not.toContain('rm -rf'); expect(cmd).toBe('dsh --profile dsh-tui'); }); }); describe('DeepSeek mode wiring', () => { it('is an external CLI mode', () => { expect(isExternalCliMode('deepseek')).toBe(true); }); it('is NOT an alt-screen strip mode', () => { // The strip is for Ink-style repaint TUIs (claude/codex/gemini). A dsh // terminal profile is a third-party fullscreen TUI, i.e. the opencode case. expect(isAltScreenStripMode('deepseek')).toBe(false); }); it('has default remote and docker commands', () => { expect(defaultRemoteCommandForMode('deepseek')).toContain('dsh'); expect(defaultDockerCommandForMode('deepseek')).toBe('exec dsh'); }); }); describe('DeepSeek status bridge', () => { it('is the only non-claude mode allowed to deliver hook signals', () => { // Earned, not granted: the harness terminal front door REPORTS its state to // a supervisor, so `stop` and `blocked` for a dsh session are definitive // rather than inferred. Every other external CLI must keep failing this. expect(hooksAvailableForMode('deepseek')).toBe(true); expect(hooksAvailableForMode('claude')).toBe(true); for (const mode of ['shell', 'opencode', 'codex', 'gemini', 'antigravity', 'pi', 'grok'] as const) { expect(hooksAvailableForMode(mode)).toBe(false); } }); it('maps the harness lifecycle states onto real hook events', () => { expect(DEEPSEEK_STATE_TO_HOOK_EVENT.idle).toBe('stop'); expect(DEEPSEEK_STATE_TO_HOOK_EVENT.blocked).toBe('permission_prompt'); expect(DEEPSEEK_STATE_TO_HOOK_EVENT.working).toBe('agent_working'); // Every mapped event must be one the hook endpoint actually accepts, or the // bridge would post reports the schema silently rejects. for (const event of Object.values(DEEPSEEK_STATE_TO_HOOK_EVENT)) { expect(() => HookEventSchema.parse({ event, sessionId: 's1' })).not.toThrow(); } }); }); describe('DeepSeek multi-user clamp', () => { const ORIGINAL = process.env.CODEMAN_MULTIUSER; beforeEach(() => { process.env.CODEMAN_MULTIUSER = '1'; }); afterEach(() => { if (ORIGINAL === undefined) delete process.env.CODEMAN_MULTIUSER; else process.env.CODEMAN_MULTIUSER = ORIGINAL; }); it('clamps a sent danger-full-access down to workspace-write, not read-only', () => { // The clamp removes PRIVILEGE; it must not also break the session's ability // to edit its own workspace, which read-only would. return _clampExternalCliBypassForOwner('nobody', undefined, undefined, undefined, undefined, undefined, { permissionMode: 'danger-full-access', }).then((out) => { expect(out.deepSeekConfig?.permissionMode).toBe('workspace-write'); }); }); it('leaves an ABSENT config absent (the only-if-sent branch)', async () => { // Omitting DSH_PERMISSION_MODE leaves the harness on its own workspace-write // preset, which still asks — so there is nothing to materialize, unlike pi. const out = await _clampExternalCliBypassForOwner( 'nobody', undefined, undefined, undefined, undefined, undefined, undefined ); expect(out.deepSeekConfig).toBeUndefined(); }); });