Skip to content

feat(podman): honor OCI image working directories - #3933

Merged
matthewgrossman merged 2 commits into
podman-workdir/a-oci-image-suitefrom
podman-workdir/c-oci-workdir
Sep 30, 2026
Merged

matthewgrossman merged 2 commits into
podman-workdir/a-oci-image-suitefrom
podman-workdir/c-oci-workdir

Conversation

@matthewgrossman

@matthewgrossman matthewgrossman commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Podman sandboxes now use an image's custom WORKDIR as the agent workspace, as Docker already does. Images without a custom working directory still use the managed /sandbox volume. Docker behavior does not change.

This is the last of three stacked PRs split out of #3801 (#3931 ← #3932 ← this PR), and it supersedes #3801.

Why this matters

An image can set WORKDIR /home/app/project and prepare that directory with files and permissions for its user. Today, a Podman sandbox ignores that choice and puts the agent in /sandbox instead. Files the image placed in its working directory are not in the agent's workspace, so commands and uploads can go to the wrong place. Docker already works from the image's chosen directory.

With this change, Podman keeps a custom workspace in the image's own filesystem rather than mounting a new volume over it. That preserves the image's files and ownership; OpenShell does not create the directory or grant the user new access. If the image leaves WORKDIR unset, sets it to /, or chooses /sandbox, the existing managed-volume behavior remains, with the ownership fix from #3932.

What you can now do

On a Podman gateway host, build an image with a writable custom working directory:

FROM ubuntu:24.04
RUN mkdir -p /home/app/project && chown -R 1000:1000 /home/app
WORKDIR /home/app/project
USER 1000:1000
podman build -t localhost/agent:workdir .
openshell sandbox create --name workdir-demo --from localhost/agent:workdir --detach -- sleep infinity
openshell sandbox exec --name workdir-demo -- sh -c 'pwd; touch session.txt'
openshell sandbox exec --name workdir-demo -- sh -c 'test -f session.txt && echo persisted'

Previously, Podman used /sandbox regardless of the image's WORKDIR.

Related Issue

Fixes #2526. Supersedes #3801 and the Podman approach in #2715, which needed extra directory checks because the workload and supervisor shared a container. RFC 0012 runs them in separate containers, so those checks are no longer needed.

Follow-ups kept out of this PR:

Changes

  • Resolve the Podman image ID, user, environment, and working directory from one pinned image inspection (ResolvedPodmanImage).
  • Keep a custom workspace in the image's container filesystem: no workspace volume, no archive upload, and no root setup step. The workload starts as the final non-root user, and the existing sandbox-runtime check still requires that user to be able to traverse and write the directory.
  • Validate a custom workdir with the shared OCI rules, and reject Podman control-path overlaps (/.openshell, supervisor CA runtime root). Reject image VOLUMEs or driver mounts that cover the workspace; mounts nested below it remain valid.
  • Pass the resolved path to agent commands via --workdir. Start the runtime from / so Podman neither creates a missing WORKDIR nor fails to chdir into it before OpenShell validates it.
  • Run the oci-image suite on fedora-podman-rootful and fedora-podman-rootless in branch E2E and both release workflows (Docker was added by the base PR). Add podman_oci_identity to the Podman CI test list, and give its image a custom WORKDIR with no workspace mounts.
  • Trim podman_oci_identity to the checks only Podman can make: the pinned image ID and the isolated workload/supervisor container pair (users, capabilities, networking, mounts). The identity seen by the main process and sandbox exec is covered by the shared suite on both runtimes.
  • Update the Podman README, runtime docs, debug skill, and TESTING.md.

Testing

All checks ran against a local rootful Podman machine (macOS, libkrun). Rootless coverage comes from the fedora-podman-rootless CI lane that this PR adds.

  • mise run pre-commit passes
  • Unit tests: cargo test -p openshell-driver-podman --lib (230 passed), covering the workspace spec, custom vs. managed launch, and image volumes and driver mounts that cover the workdir. cargo clippy -p openshell-driver-podman --all-targets -- -D warnings is clean.
  • Feature tests: the full oci-image suite passes 4/4 through e2e/with-podman-gateway.sh, including the WorkspaceValidationFailed reason for an unwritable WORKDIR.
  • E2E: the trimmed podman_oci_identity passes.

Checklist

  • Follows Conventional Commits
  • Commits are signed off (DCO)
  • Architecture docs updated (if applicable)

@copy-pr-bot

copy-pr-bot Bot commented Sep 30, 2026

Copy link
Copy Markdown

Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually.

Contributors can view more details about this message here.

@github-actions

Copy link
Copy Markdown

@matthewgrossman

Copy link
Copy Markdown
Contributor Author

/ok to test b9ab37e

@matthewgrossman matthewgrossman added the test:e2e Requires end-to-end coverage label Sep 30, 2026
@github-actions

Copy link
Copy Markdown

Label test:e2e applied for b9ab37e. Open the existing run and click Re-run all jobs to execute with the label set. The run will execute the standard E2E suite after building the required gateway, sandbox, and supervisor images once. The matching required CI gate status on this PR will flip green automatically once the run finishes.

)
.await
.map_err(ComputeDriverError::from)?;
if managed_workspace {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Custom-workdir sandboxes now skip workspace-volume creation, but the provisioning cleanup and delete paths still remove the deterministic workspace-volume name unconditionally. This can delete a volume that was never created or ownership-verified by this sandbox. Guard failure cleanup with managed_workspace, and make deletion inspect and verify the OpenShell sandbox ownership labels before removing a workspace volume; label verification also preserves cleanup for volumes created by older gateways.

@matthewgrossman
matthewgrossman force-pushed the podman-workdir/c-oci-workdir branch from b9ab37e to 82d8d1c Compare September 30, 2026 08:48
…ValidationFailed

The RFC 0012 split dropped the supervisor exit status that drivers map to
the WorkspaceValidationFailed condition. An image WORKDIR the sandbox
identity cannot use then surfaced as ControlSupervisorStartFailed on
Docker and as a signal kill on Podman.

The supervisor now exits with the reserved status when the sandbox rejects
the image working directory. Docker maps that supervisor exit during
readiness and monitoring, and Podman maps the supervisor companion's exit
instead of the workload's.

Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
Podman sandboxes now use a custom OCI image WORKDIR as the workspace and
as the working directory for agent commands, matching Docker. Empty, /,
and /sandbox values keep the managed /sandbox workspace volume.

A custom workspace stays in the image's container filesystem: no
workspace volume, no archive upload, and no root setup step. Resolve the
image ID, user, environment, and working directory from one pinned
inspection, validate the workdir with the shared OCI rules, and reject
Podman control-path overlaps and image volumes or driver mounts that
cover it. The runtime starts from / and passes the resolved path to agent
commands with --workdir.

Add podman_oci_identity to the Podman CI test list.

Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
@matthewgrossman
matthewgrossman force-pushed the podman-workdir/c-oci-workdir branch from 82d8d1c to 6059307 Compare September 30, 2026 18:33
Base automatically changed from podman-workdir/b-volume-ownership to podman-workdir/a-oci-image-suite September 30, 2026 18:33
@matthewgrossman
matthewgrossman merged commit 6059307 into main Sep 30, 2026
@matthewgrossman
matthewgrossman deleted the podman-workdir/c-oci-workdir branch September 30, 2026 18:33
@matthewgrossman
matthewgrossman restored the podman-workdir/c-oci-workdir branch September 30, 2026 18:52
@matthewgrossman

Copy link
Copy Markdown
Contributor Author

GitHub automatically marked this PR merged when its reordered head became an ancestor of its old base during stack maintenance. The change has not landed on main. Replacement draft PR: #3982, in the new stack #3983.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

test:e2e Requires end-to-end coverage

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: honor OCI WorkingDir for Docker and Podman workspaces

2 participants