From b8d84471a3585dcdd2063fbefad92ca33dc3d357 Mon Sep 17 00:00:00 2001 From: Dotta Date: Thu, 3 Sep 2026 22:09:10 -0500 Subject: [PATCH] fix(runner): preserve remote continuation state scope --- .github/workflows/runner-full-stack-e2e.yml | 5 +-- .../native-session-executor.test.ts | 31 +++++++++++++++++++ .../native-runtime/native-session-executor.ts | 5 ++- tests/runner-e2e/workflow-security.test.ts | 2 +- 4 files changed, 39 insertions(+), 4 deletions(-) diff --git a/.github/workflows/runner-full-stack-e2e.yml b/.github/workflows/runner-full-stack-e2e.yml index 4f01401e5d..7ba868651a 100644 --- a/.github/workflows/runner-full-stack-e2e.yml +++ b/.github/workflows/runner-full-stack-e2e.yml @@ -42,9 +42,10 @@ permissions: contents: read concurrency: - group: runner-full-stack-e2e-${{ inputs.target_branch || github.event.repository.default_branch }} + group: runner-full-stack-e2e-${{ github.event_name == 'workflow_dispatch' && inputs.target_branch != '' && inputs.target_branch != github.event.repository.default_branch && format('development-{0}', inputs.target_branch) || format('protected-{0}', github.run_id) }} # Development branch campaigns supersede older runs for the same target. - # Preserve every default-branch campaign for its paid audit trail. + # Give protected/default-branch campaigns unique groups because GitHub also + # replaces pending runs when cancel-in-progress is false. cancel-in-progress: ${{ github.event_name == 'workflow_dispatch' && inputs.target_branch != '' && inputs.target_branch != github.event.repository.default_branch }} jobs: diff --git a/server/src/services/native-runtime/native-session-executor.test.ts b/server/src/services/native-runtime/native-session-executor.test.ts index f625ca6ae5..e272de38bb 100644 --- a/server/src/services/native-runtime/native-session-executor.test.ts +++ b/server/src/services/native-runtime/native-session-executor.test.ts @@ -3073,6 +3073,7 @@ describe("runnerd provider runtime wiring", () => { executionWorkspaceId: "run-projectless-next", }, } as NativeExecutionInputV1; + const remoteCwd = "/home/daytona/paperclip-workspace"; try { state.createBackend.mockClear(); state.createTransport.mockClear(); @@ -3135,7 +3136,37 @@ describe("runnerd provider runtime wiring", () => { execution: continuation, runnerInstanceId: "runner-new-heartbeat", useRunnerd: true, + runnerExecutionTarget: { + kind: "remote", + transport: "ssh", + remoteCwd, + spec: { + host: "runner.internal", + port: 22, + username: "runner", + remoteWorkspacePath: remoteCwd, + remoteCwd, + privateKey: null, + knownHosts: null, + strictHostKeyChecking: true, + }, + }, }); + expect(state.createBackend).toHaveBeenCalledWith( + expect.objectContaining({ + workspace: expect.objectContaining({ cwd: remoteCwd }), + }), + expect.objectContaining({ + workingDirectoryAuthority: "remote_runner", + }), + ); + expect(state.execute).toHaveBeenCalledWith( + expect.objectContaining({ + input: expect.objectContaining({ + workspace: expect.objectContaining({ cwd: remoteCwd }), + }), + }), + ); const backendOptions = state.createBackend.mock.calls[0]![1]; backendOptions.codexTransportFactory!(); expect(state.createTransport).toHaveBeenCalledWith( diff --git a/server/src/services/native-runtime/native-session-executor.ts b/server/src/services/native-runtime/native-session-executor.ts index a6bd4b00cf..8007bd57f6 100644 --- a/server/src/services/native-runtime/native-session-executor.ts +++ b/server/src/services/native-runtime/native-session-executor.ts @@ -3865,7 +3865,10 @@ async function executePaperclipNativeSessionWithinScope( input.useRunnerd && input.backend === undefined ? await createRunnerdBackend({ ...input, - execution: runnerExecution, + // Durable scope and prior-run verification use the controller's + // canonical workspace identity. createRunnerdBackend separately + // projects remoteCwd into the provider execution boundary. + execution: input.execution, runnerInstanceId: effectiveRunnerInstanceId, durableEnvironmentLeaseId: durableRunnerBinding?.environmentLeaseId, trace, diff --git a/tests/runner-e2e/workflow-security.test.ts b/tests/runner-e2e/workflow-security.test.ts index 1a3bc09560..927dd4c4de 100644 --- a/tests/runner-e2e/workflow-security.test.ts +++ b/tests/runner-e2e/workflow-security.test.ts @@ -282,7 +282,7 @@ describe("public repository paid workflow security", () => { '[ "$MAX_PARALLEL" -gt "$MAX_PARALLEL_LIMIT" ]', ); expect(fullStack).toContain( - "group: runner-full-stack-e2e-${{ inputs.target_branch || github.event.repository.default_branch }}", + "group: runner-full-stack-e2e-${{ github.event_name == 'workflow_dispatch' && inputs.target_branch != '' && inputs.target_branch != github.event.repository.default_branch && format('development-{0}', inputs.target_branch) || format('protected-{0}', github.run_id) }}", ); expect(fullStack).toContain( "cancel-in-progress: ${{ github.event_name == 'workflow_dispatch' && inputs.target_branch != '' && inputs.target_branch != github.event.repository.default_branch }}",