Skip to content

Commit df7a02b

Browse files
committed
fix(plan): isolate embedded CLI and checkpoint benchmark stages
1 parent 9f68e46 commit df7a02b

5 files changed

Lines changed: 86 additions & 37 deletions

File tree

‎apps/sim/lib/mothership/request/lifecycle/run.test.ts‎

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ const {
7272
INTERNAL_API_SECRET: 'transport-test-secret-000000000000000000',
7373
COPILOT_API_KEY: undefined as string | undefined,
7474
MSHIP_SYSPROMPT_OVERRIDE: undefined as string | undefined,
75+
MOTHERSHIP_BENCHMARK_URL: 'https://benchmark.test',
7576
},
7677
}))
7778

@@ -280,6 +281,7 @@ describe('runCopilotLifecycle', () => {
280281
setEnvFlags({
281282
isHosted: false,
282283
isCopilotToolPermissionsEnabled: false,
284+
isMothershipBenchmarkEnabled: false,
283285
})
284286
mockGetAutoAllowedTools.mockResolvedValue(new Set<string>())
285287
mockGetUserPermissionConfig.mockResolvedValue(null)
@@ -913,24 +915,30 @@ describe('runCopilotLifecycle', () => {
913915
})
914916
})
915917

916-
it('stamps server-owned transport over caller claims without exposing the instance secret', async () => {
917-
let captured = ''
918-
mockRunStreamLoop.mockImplementationOnce(async (_url: string, request: RequestInit) => {
919-
captured = String(request.body)
920-
})
921-
await runCopilotLifecycle(
922-
{ message: 'hello', simConnection: { mode: 'direct' } },
923-
{
924-
userId: 'user-1',
925-
workspaceId: 'ws-1',
926-
}
927-
)
928-
expect(JSON.parse(captured).simConnection).toEqual({
929-
mode: 'checkpoint',
930-
channelId: expect.stringMatching(/^[a-f0-9]{64}$/),
931-
})
932-
expect(captured).not.toContain(mockEnv.INTERNAL_API_SECRET)
933-
})
918+
it.each(['/api/mothership', '/api/copilot', '/api/mothership/execute'])(
919+
'forces benchmark checkpoint transport over caller claims on %s',
920+
async (goRoute) => {
921+
setEnvFlags({ isMothershipBenchmarkEnabled: true })
922+
let captured = ''
923+
mockRunStreamLoop.mockImplementationOnce(async (_url: string, request: RequestInit) => {
924+
captured = String(request.body)
925+
})
926+
await runCopilotLifecycle(
927+
{ message: 'hello', simConnection: { mode: 'direct' } },
928+
{
929+
userId: 'user-1',
930+
workspaceId: 'ws-1',
931+
benchmark: 'distill',
932+
goRoute,
933+
}
934+
)
935+
expect(JSON.parse(captured).simConnection).toEqual({
936+
mode: 'checkpoint',
937+
channelId: expect.stringMatching(/^[a-f0-9]{64}$/),
938+
})
939+
expect(captured).not.toContain(mockEnv.INTERNAL_API_SECRET)
940+
}
941+
)
934942

935943
it.each([false, true])(
936944
'attaches BYOK without letting a hidden hosted default override it (advanced=%s)',

‎apps/sim/lib/mothership/request/lifecycle/run.ts‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1178,7 +1178,11 @@ async function runCheckpointLoop(
11781178
? getBenchmarkMothershipUrl()
11791179
: await getMothershipBaseURL({ userId: options.userId })
11801180
execContext.mothershipBaseURL = mothershipBaseURL
1181-
if (initialRoute === '/api/mothership' || initialRoute === '/api/copilot') {
1181+
if (
1182+
initialRoute === '/api/mothership' ||
1183+
initialRoute === '/api/copilot' ||
1184+
(initialRoute === '/api/mothership/execute' && options.benchmark)
1185+
) {
11821186
const simConnection = getSimConnection(options.benchmark ? 'checkpoint' : undefined)
11831187
payload = { ...payload, simConnection }
11841188
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { mkdtemp, readdir, rm } from 'node:fs/promises'
2+
import { tmpdir } from 'node:os'
3+
import { join } from 'node:path'
4+
import { afterEach, describe, expect, it, vi } from 'vitest'
5+
import { runEmbeddedCli } from '#sim-cli/embed'
6+
7+
const identity = { endpoint: 'https://sim.test', apiKey: 'fixture', workspaceId: 'workspace' }
8+
9+
afterEach(() => vi.unstubAllEnvs())
10+
11+
describe('embedded CLI host isolation', () => {
12+
it.each([
13+
{ name: 'profile configuration', argv: ['configure', '--set-output', 'json'] },
14+
{ name: 'telemetry preferences', argv: ['telemetry', 'disable'] },
15+
])('rejects $name without persisting host settings', async ({ argv }) => {
16+
const directory = await mkdtemp(join(tmpdir(), 'sim-embedded-host-'))
17+
vi.stubEnv('SIM_CONFIG_DIR', directory)
18+
try {
19+
const result = await runEmbeddedCli(argv, identity)
20+
expect.soft(result.exitCode).toBe(1)
21+
expect.soft(await readdir(directory)).toEqual([])
22+
} finally {
23+
await rm(directory, { recursive: true, force: true })
24+
}
25+
})
26+
})

‎packages/sim-cli/src/embed.ts‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,11 @@ export async function runEmbeddedCli(
132132
let exitCode = 0
133133
try {
134134
identity.signal?.throwIfAborted()
135-
const program = buildProgram()
135+
const program = buildProgram({
136+
hostCommands: false,
137+
helpText:
138+
'The embedding application supplies authentication, endpoint and workspace scope.',
139+
})
136140
configureEmbeddedOutput(program)
137141
await program.parseAsync(argv, { from: 'user' })
138142
// Commands that soft-fail (a failed run outcome, wait timeout) report through the

‎packages/sim-cli/src/program.ts‎

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,13 @@ function addVersionOption(program: Command): void {
148148
* release.
149149
*/
150150
export function buildProgram(
151-
options: { version?: boolean; helpText?: string; program?: Command; env?: NodeJS.ProcessEnv } = {}
151+
options: {
152+
version?: boolean
153+
helpText?: string
154+
program?: Command
155+
env?: NodeJS.ProcessEnv
156+
hostCommands?: boolean
157+
} = {}
152158
): Command {
153159
const env = options.env ?? process.env
154160
const program = options.program ?? new Command()
@@ -164,17 +170,23 @@ export function buildProgram(
164170
.addOption(
165171
new Option('--output <format>', 'Output format for this command').choices([...OUTPUT_FORMATS])
166172
)
167-
for (const command of [
168-
loginCommand,
169-
logoutCommand,
170-
whoamiCommand,
171-
profilesCommand,
172-
configureCommand,
173-
])
174-
program.addCommand(command())
175-
const update = updateCommand()
176-
program.addCommand(update)
177-
program.addCommand(telemetryCommand())
173+
if (options.hostCommands !== false) {
174+
for (const command of [
175+
loginCommand,
176+
logoutCommand,
177+
whoamiCommand,
178+
profilesCommand,
179+
configureCommand,
180+
])
181+
program.addCommand(command())
182+
const update = updateCommand()
183+
program.addCommand(update)
184+
program.addCommand(telemetryCommand())
185+
program.hook('preAction', async (_program, command) => {
186+
if (command === update) return
187+
await announceUpdateIfAvailable()
188+
})
189+
}
178190
program.addCommand(cliCommand())
179191

180192
for (const command of buildGeneratedCommands()) {
@@ -190,11 +202,6 @@ export function buildProgram(
190202
detectCodingAgent(env) !== undefined && command.commands.length > 0 ? AGENT_DISCOVERY_NOTE : ''
191203
)
192204

193-
program.hook('preAction', async (_program, command) => {
194-
if (command === update) return
195-
await announceUpdateIfAvailable()
196-
})
197-
198205
refuseHelpAfterUnknownCommand(program)
199206
assertNoReservedProgramFlags(program)
200207

0 commit comments

Comments
 (0)