Repository navigation
feat: honor OCI WorkingDir for Docker and Podman workspaces #2526
Description
Problem Statement
Follow-up to #2331 and stacked on #2509.
#2331 removes the requirement for Docker and Podman images to contain a
sandbox:sandbox account, but intentionally keeps /sandbox as OpenShell's
fixed workspace. OCI images can already declare their intended workspace with
Config.WorkingDir; ignoring it means off-the-shelf images may still require
OpenShell-specific /sandbox preparation, and direct sessions, SSH sessions,
filesystem policy, persistence, transfers, and editor launch can disagree about
the effective workspace.
Docker and Podman should honor the image-declared working directory without
changing Kubernetes/OpenShift or VM workspace behavior.
Proposed Design
Introduce one internal resolved workspace root and use it consistently across
the local container drivers, supervisor, policy runtime, and SSH-based CLI
operations.
Resolution
- Docker and Podman inspect OCI
Config.WorkingDiralongsideConfig.User
from the same immutable image inspected by feat: preserve image-declared identity in Docker and Podman #2331. - Use a normalized absolute
WorkingDirwhen it is non-empty and not/. - For an empty,
/, or explicit/sandboxdeclaration, use/sandboxas an OpenShell-created
fallback. The image does not need to contain or pre-own it. - Reject malformed non-empty declarations, including relative paths. Reject a
custom workspace root that is missing, resolves to a symlink or
non-directory, or cannot be traversed and written by the final workload
identity. Do not create it or change its ownership or permissions. - Kubernetes/OpenShift and VM continue resolving their workspace root to
/sandbox.
This is an internal runtime decision, not a new public setting or gateway
configuration field.
Runtime behavior
- Pass the resolved root through the supervisor's existing workdir mechanism;
do not add a new supervisor flag or identity protocol. - Prepare only the managed
/sandboxfallback for the final effective UID/GID.
Validate custom directories as that identity before launching agent code. - Start trusted runtime binaries from
/so Podman does not create or enter a
custom workspace before validation; agent processes use the resolved root as
their cwd. - Keep the cross-runtime
HOMEcontract in feat: define cross-runtime agent HOME behavior #3873; this change does not add a
new HOME requirement. - Feed the resolved root to Landlock when
filesystem.include_workdiris true. - Stop automatically injecting literal
/sandboxas a baseline filesystem
path. User-authored policy entries that explicitly name/sandboxremain
literal and are never rewritten.
Driver behavior
- Pin both identity and workspace resolution to the immutable image ID already
inspected by Docker and Podman. - Create and initialize Podman's managed workspace volume only for the
/sandboxfallback. Custom workspaces remain in the workload container's
writable layer, with no workspace volume or ownership-setting archive. - Reject image-declared volumes or driver-config mounts that cover a custom
workspace, and reject runtime/control-path overlaps after image inspection.
Continue allowing mounts nested below the workspace. - Preserve existing image files, ownership, and permissions without named-volume
copy-up or directory repair. - Workspace changes survive normal stop/start of the same workload container.
Removing or replacing that container removes its workspace changes; a new
sandbox starts from the image's original files. Export files that must be
retained before deleting the sandbox.
CLI behavior
Use the existing SSH connection to discover the canonical remote workspace with
pwd -P; avoid adding a public workspace_root status field unless a
non-SSH consumer proves it necessary.
- Download containment and symlink checks use the discovered root rather than
a hardcoded/sandbox. - Upload without an explicit destination extracts into the discovered root
rather than relying on SSH~. - Editor launch opens the discovered remote root.
Alternatives Considered
- Recursively chown
/sandbox: rejected in feat(sandbox): use policy-first OCI image identity #2509. It mutates image content,
risks crossing ownership boundaries, and treats the symptom rather than
honoring OCI workspace metadata. - Always use
/sandbox: retained as the empty//fallback and for explicit
/sandboxdeclarations. It
preserves compatibility but should not override a usable OCIWorkingDir. - Use the OCI user's account home as fallback: rejected because Podman must
choose its managed-volume target before the supervisor can resolve
/etc/passwd. A driver-known fallback is simpler and deterministic. - Mount a named volume at a custom
WorkingDir: not selected. Keep the
image directory in the container's writable layer without copy-up or
ownership changes, with persistence tied to that container's lifetime. - Add a public gateway
workspace_rootfield: avoid initially because the
affected CLI operations already establish SSH sessions and can discover the
canonical cwd directly. - Rewrite user-authored
/sandboxpolicy paths: rejected. Explicit policy
paths must retain their literal meaning.
Definition of Done
- Docker and Podman use a valid OCI
WorkingDir, with driver-created
/sandboxfallback for empty,/, or explicit/sandboxdeclarations. - Direct and SSH children share the resolved cwd and can write there. The
cross-runtimeHOMEcontract remains a separate follow-up (feat: define cross-runtime agent HOME behavior #3873). -
include_workdirgrants the resolved root without rewriting explicit
policy paths. - Custom workspaces preserve image contents and permissions without a
workspace-covering volume. Changes persist across stop/start of the same
container, with the container-lifetime limit documented. - Image-declared volumes and driver-config mounts cannot cover the resolved
custom workspace root; nested mounts remain valid. - Upload defaults, download containment, and editor launch use the
SSH-discovered workspace root. - Kubernetes/OpenShift and VM retain their current
/sandboxbehavior. - No public workspace setting, gateway schema field, or new supervisor
launch flag is introduced.
Test Plan
- OCI
WorkingDir: absolute named path, absent,/, relative, malformed,
missing, pre-populated, symlink, non-directory, and read-only. - Driver-owned fallback works without image-prepared
/sandbox. - Direct and SSH identity, cwd, and write behavior agree. HOME is tracked in
feat: define cross-runtime agent HOME behavior #3873 rather than required by this change. - Landlock
include_workdirfollows the resolved root; explicit/sandbox
remains literal. - Custom workspaces retain image files and ownership without a workspace
mount. Changes survive stop/start of the same container and do not transfer
to a replacement container. - Nested/user mounts retain their ownership and existing behavior.
- Upload, download traversal/symlink protection, and editor launch use the
discovered root. - Kubernetes/OpenShift and VM regression coverage remains unchanged.
Agent Investigation
- Searched open and closed issues; found no duplicate OCI WorkingDir proposal.
- Docker's
DockerImageMetadataand Podman'sImageInspectalready bind OCI
Config.Userto immutable image launch, soConfig.WorkingDircan be read in
the same inspection. - The supervisor already accepts and threads a workdir through direct process
launch, SSH process launch, and Landlock preparation. - Podman's managed workspace volume is currently hardcoded to
/sandbox. - Mount validation currently reserves literal
/sandbox. - CLI download guards and editor launch currently hardcode
/sandbox; upload
without a destination currently relies on the SSH home directory.
Scope Boundaries
Do not redesign OCI identity from #2331, add a public workspace setting, change
Kubernetes PVC/fsGroup behavior, change VM guest initialization, or fold this
work back into #2509. Keep cross-runtime HOME behavior in #3873 and
image-declared volume resource admission in #3890. A distinct
WorkspaceValidationFailed condition reason is not required; an unusable
workspace must still be rejected.
Checklist
- I've reviewed existing issues and the architecture docs
- This is a design proposal, not a "please build this" request
Current Implementation
The remaining Podman WORKDIR implementation is in #3982, with shared
Docker/Podman OCI behavior tests in #3931. The managed /sandbox ownership fix
landed in #3981. These supersede the earlier approach in #3801.
Activity
matthewgrossman commentedon Jul 28, 2026
Implementation Plan
Issue type:
featComplexity: Medium
Confidence: High — RFC 0012 provides the required separation, and the Docker/shared workspace plumbing is already present.
Summary
Implement the remaining Podman half of OCI
WORKDIRsupport against the RFC 0012 isolation architecture. ResolveConfig.WorkingDirfrom the same pinned inspection as image identity and environment. Keep a custom workspace in the workload container's writable layer, without a workspace volume or copy-up. Pass its root through the existing supervisor--workdirpath. Empty,/, and explicit/sandboxdeclarations retain the managed/sandboxfallback.Scope
crates/openshell-driver-podman/src/client.rs: deserialize and test OCIWorkingDiralongsideUserandEnv.crates/openshell-driver-podman/src/container.rs: group the requested reference, immutable ID, user, environment, and resolved workspace in image metadata; validate workspace/mount/control-path collisions; distinguish managed/sandboxfrom custom image directories; start trusted runtime binaries from/and pass the workspace to agent processes.crates/openshell-driver-podman/src/driver.rs: resolve metadata before resource creation; create and initialize the owned workspace volume only for managed/sandbox.e2e/rust/tests/podman_oci_identity.rs: cover immutable pinning, custom cwd/write access, image-file and ownership preservation, fallback, and mount collisions. Shared Docker/Podman OCI behavior coverage belongs to test(oci): add a shared Docker and Podman suite for image USER and WORKDIR #3931.Implementation Steps
/, and explicit/sandboxselect managed/sandbox./so Podman does not create or enter a custom workspace before validation. Pass the resolved path through the existing supervisor--workdirmechanism for agent processes.Test Plan
WORKDIR; verify cwd/write access, existing image files, root-owned file preservation, directory identity/mode, immutable image launch, and absence of a managed workspace mount. Keep managed/sandboxcoverage without a baked directory.WorkspaceValidationFailed, persistence across stop/start of the same container, and no transfer of changes to a replacement container. Keep fallback and nested-mount checks.Persistence Contract and Risks
HOMEbehavior stays in feat: define cross-runtime agent HOME behavior #3873; image-declared volume resource admission stays in bug(podman): resource admission rejects image-declared VOLUMEs; lacks Docker parity #3890. Cross-driver failure-classification improvements are not a prerequisite for WORKDIR support.Documentation Impact
Update the Podman crate README, published runtime guide, and operator/debug guidance. Explain that custom workspaces use the container's writable layer and that the
/sandboxfallback remains managed. No gateway TOML, driver option, Helm rendering, or default changes are introduced.Current PRs
/sandboxownership fix (merged).These supersede the earlier implementation in #3801.
Revision 3 — custom workspaces use the workload container's writable layer; replaces the named-volume/copy-up design and documents container-lifetime persistence.
Revision 2 — redesigned for RFC 0012 supervisor/workload separation.
Revision 1 — initial stacked implementation plan.
matthewgrossman commentedon Jul 28, 2026
Implementation is available in stacked PR #2530 (based on #2509).
Implemented OCI WorkingDir resolution for Docker/Podman, consistent supervisor cwd/HOME and workspace preparation, dynamic
include_workdirpolicy handling, Podman workspace-volume placement, SSH-discovered CLI transfer/editor roots, focused tests, and documentation updates.Validation completed:
mise run pre-commitmise run testcustom_imageE2Edriver_config_volumeE2ELive Podman E2E was unavailable locally; Podman inspect/spec/copy-up behavior is covered by focused unit tests.
feat(sandbox): honor OCI image working directories
feat(sandbox): honor OCI image working directories
feat(sandbox): honor OCI image working directories
feat(sandbox): honor OCI image working directories
feat(sandbox): honor OCI image working directories
github-actions commentedon Aug 12, 2026
This issue has had no activity for 14 days and is now marked stale. It may be closed in 7 days if there is no further activity. Comment or remove the state:stale label to keep it open.
matthewgrossman commentedon Sep 28, 2026
Implementation Ready — E2E Blocked
The RFC 0012-aligned Podman WORKDIR implementation is complete on branch
codex/2526-podman-workdir-rfc12at commite073caa915d8c3bd1e0015f523c5cb4717c845d4.Verification
mise run pre-commit: passedmise run ci: Podman tests passed; the workspace task stopped on five unrelated VM-driver tests because this host does not havemke2fsormkfs.ext4mise run e2e:podman:ci: blocked before tests because the localpodman-machine-defaultVM exits immediately after startup and its API endpoint refuses connectionsThe required live Podman E2E gate is not green, so no pull request was opened. The branch is pushed for recovery or verification on a healthy Podman host.