Skip to content

Execute debugger REPL commands inside job container#4420

Open
rentziass wants to merge 3 commits into
mainfrom
rentziass/debugger-container-jobs
Open

Execute debugger REPL commands inside job container#4420
rentziass wants to merge 3 commits into
mainfrom
rentziass/debugger-container-jobs

Conversation

@rentziass
Copy link
Copy Markdown
Member

When a job uses a container: definition, the debugger REPL was always executing run commands on the runner host via IProcessInvoker directly. This meant commands like cat /etc/os-release would show the host OS (Ubuntu) instead of the container's OS (e.g. Alpine), making the debugger unreliable for inspecting container job state.

Approach

Instead of duplicating docker exec logic, the REPL executor now reuses IStepHost -- the same abstraction that normal workflow run: steps use. The debugger determines the current step type and creates the appropriate host:

  • Action steps (user-defined run:/uses:) get a ContainerStepHost, which routes execution through docker exec (or container hooks when enabled). Script paths and working directories are translated to container paths, and PrependPath is propagated to the container's PATH.
  • Infrastructure steps (Set up job, Initialize containers, Stop containers, Complete job) get a DefaultStepHost and always execute on the runner host, since these steps operate outside the container lifecycle.

The guiding principle: running a command in the debug console should behave identically to having a run: step in your workflow file.

Execution context banner

Since DAP doesn't support customizing the console prompt, the debugger now emits a banner each time it pauses at a step so the user knows where commands will run:

Commands will run on job container: alpine:3.20 (a1b2c3d4e5f6)
Commands will run on runner host

Testing

Added unit tests for CreateStepHost covering:

  • No container configured -- returns DefaultStepHost
  • Container with ID + action step -- returns ContainerStepHost
  • Container with ID + infrastructure step -- returns DefaultStepHost
  • Container without ID (not yet started) -- falls back to DefaultStepHost

rentziass and others added 2 commits May 14, 2026 13:12
When a job uses a container: definition, the debugger REPL was always
executing run commands on the host via IProcessInvoker directly. This
meant that commands like 'cat /etc/os-release' would show the host OS
instead of the container's OS.

Fix this by reusing IStepHost — the same abstraction that normal run:
steps use — to decide whether to execute on the host or inside the
container via docker exec. The decision is based on the current step
type:

- Action steps (user-defined run:/uses:) execute inside the container,
  matching the behavior of normal workflow run: steps.
- Infrastructure steps (Set up job, Initialize containers, Stop
  containers, Complete job) always execute on the host.

This also correctly handles container hooks (where ContainerId may be
empty but execution should still go through the container hook manager)
and PrependPath propagation for both host and container execution.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When the debugger pauses at a step, emit a console output banner so
the user knows where REPL commands will execute:

  ⬡ alpine:3.20 (abc123def456)   — commands run inside the container
  ⊙ host                          — commands run on the host

This compensates for DAP not supporting custom prompts. The banner
appears automatically each time the debugger stops, using the
container image name and a short container ID for container steps,
or 'host' for infrastructure steps.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 14, 2026 17:54
@rentziass rentziass requested a review from a team as a code owner May 14, 2026 17:54
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the DAP debugger REPL so run("...") commands execute in the same place a normal workflow run: step would: inside the job container for user/action steps, and on the runner host for infrastructure steps. It does so by reusing the existing IStepHost abstraction (including container path translation and PATH propagation), and adds a console banner on each pause to indicate where REPL commands will run.

Changes:

  • Route REPL execution through IStepHost (container vs host) instead of always using IProcessInvoker directly.
  • Add step-type awareness (isActionStep) and emit an execution-context banner on pause.
  • Add unit tests for CreateStepHost decision logic.
Show a summary per file
File Description
src/Runner.Worker/Dap/DapReplExecutor.cs Switch REPL command execution to IStepHost, handling container path translation and PATH propagation, and add CreateStepHost selection logic.
src/Runner.Worker/Dap/DapDebugger.cs Pass action/infrastructure step context into the REPL executor and emit a banner indicating host vs container execution.
src/Test/L0/Worker/DapReplExecutorL0.cs Extend L0 coverage for CreateStepHost across container/no-container and action/infrastructure scenarios.

Copilot's findings

Comments suppressed due to low confidence (1)

src/Runner.Worker/Dap/DapReplExecutor.cs:151

  • PrependPath propagation is currently gated on stepHost is ContainerStepHost. Since the step host is created as IContainerStepHost, this will fail to set PrependPath for any non-ContainerStepHost implementation, causing PATH behavior to diverge from normal container step execution. Consider switching this cast/check to IContainerStepHost so all container step hosts receive PrependPath.
                // 7. Handle PrependPath — mirrors Handler.AddPrependPathToEnvironment
                if (context.Global.PrependPath.Count > 0)
                {
                    if (stepHost is ContainerStepHost containerHost)
                    {
                        containerHost.PrependPath = prependPath;
                    }
  • Files reviewed: 3/3 changed files
  • Comments generated: 3

Comment thread src/Runner.Worker/Dap/DapReplExecutor.cs Outdated
Comment thread src/Runner.Worker/Dap/DapReplExecutor.cs
Comment thread src/Test/L0/Worker/DapReplExecutorL0.cs
…ing and test

- Check against IContainerStepHost interface instead of the concrete
  ContainerStepHost type, so alternative implementations registered
  in the service locator are handled correctly.
- Add a trace warning when container hooks are enabled, since the
  hook manager does not raise OutputDataReceived/ErrorDataReceived
  events and REPL output will not be streamed in that mode.
- Add a test for the container hooks path where ContainerId is empty
  but hooks are enabled, verifying CreateStepHost still returns an
  IContainerStepHost.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants