fix(automations): keep a desktop automation's dispatch token off a runtime host's create (#34525)

A desktop-scheduled automation whose project lives on a managed Orca server
sent its dispatch token to the server, which never minted it and rejected every
run with "Invalid automation provenance request". The token now goes only to
this desktop's own create.

Fixes #34433
This commit is contained in:
Neil
2026-10-27 13:58:49 -07:00
committed by GitHub
parent 1d2778fa99
commit 2bf43b7140
2 changed files with 41 additions and 4 deletions
@@ -96,6 +96,42 @@ describe('background creation host capture', () => {
})
})
// #34433: the dispatch token lives in this desktop's main process, so a runtime host can only reject it.
it.each<ExecutionHostId>(['local', 'runtime:env-1'])(
'sends the automation provenance request only to this desktop for %s',
async (executionHostId) => {
const store = createTestStore()
const worktree = makeWorktree({ id: 'repo1::/path/feature', repoId: 'repo1' })
mockApi.worktrees.create.mockResolvedValue({ worktree })
runtimeEnvironmentCall.mockResolvedValue({
id: 'create',
ok: true,
result: { worktree },
_meta: { runtimeId: 'runtime-remote' }
})
store.setState({ repos: [], worktreesByRepo: { repo1: [] } })
const automationProvenanceRequest = {
automationId: 'automation-1',
automationRunId: 'run-1',
dispatchToken: 'token-1',
createRequestId: 'create-1'
}
const createWorktree = store.getState().createWorktree
const args: Parameters<typeof createWorktree> = ['repo1', 'feature']
args[25] = { executionHostId, automationProvenanceRequest }
await createWorktree(...args)
if (executionHostId === 'local') {
expect(mockApi.worktrees.create).toHaveBeenCalledWith(
expect.objectContaining({ automationProvenanceRequest })
)
} else {
const hostParams = runtimeEnvironmentCall.mock.calls[0]?.[0]?.params
expect(hostParams).toMatchObject({ repo: 'repo1' })
expect(hostParams).not.toHaveProperty('automationProvenanceRequest')
}
}
)
// #18097: the unresolved-owner sentinel must not ride the direct-SSH fallback onto this machine.
it('refuses a create whose captured owner is the unresolved-owner sentinel', async () => {
const store = createTestStore()
@@ -113,9 +113,6 @@ function sharedCreateFields(
...(options?.linkedWorkItem !== undefined ? { linkedWorkItem: options.linkedWorkItem } : {}),
...(options?.linkedTaskSourceContext !== undefined
? { linkedTaskSourceContext: options.linkedTaskSourceContext }
: {}),
...(options?.automationProvenanceRequest
? { automationProvenanceRequest: options.automationProvenanceRequest }
: {})
}
}
@@ -128,7 +125,11 @@ export function buildLocalWorktreeCreateArgs(
repoId: request.repoId,
...sharedCreateFields(request, attempt),
...(request.startup ? { startup: request.startup } : {}),
...(request.creationId ? { creationId: request.creationId } : {})
...(request.creationId ? { creationId: request.creationId } : {}),
// Why local only: this desktop's main minted the dispatch token, so a runtime host must reject it.
...(request.options?.automationProvenanceRequest
? { automationProvenanceRequest: request.options.automationProvenanceRequest }
: {})
}
}