Skip to content

feat: honor OCI WorkingDir for Docker and Podman workspaces #2526

Description

@matthewgrossman

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

  1. Docker and Podman inspect OCI Config.WorkingDir alongside Config.User
    from the same immutable image inspected by feat: preserve image-declared identity in Docker and Podman #2331.
  2. Use a normalized absolute WorkingDir when it is non-empty and not /.
  3. For an empty, /, or explicit /sandbox declaration, use /sandbox as an OpenShell-created
    fallback. The image does not need to contain or pre-own it.
  4. 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.
  5. 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 /sandbox fallback 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 HOME contract 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_workdir is true.
  • Stop automatically injecting literal /sandbox as a baseline filesystem
    path. User-authored policy entries that explicitly name /sandbox remain
    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
    /sandbox fallback. 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
    /sandbox declarations. It
    preserves compatibility but should not override a usable OCI WorkingDir.
  • 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_root field: avoid initially because the
    affected CLI operations already establish SSH sessions and can discover the
    canonical cwd directly.
  • Rewrite user-authored /sandbox policy paths: rejected. Explicit policy
    paths must retain their literal meaning.

Definition of Done

  • Docker and Podman use a valid OCI WorkingDir, with driver-created
    /sandbox fallback for empty, /, or explicit /sandbox declarations.
  • Direct and SSH children share the resolved cwd and can write there. The
    cross-runtime HOME contract remains a separate follow-up (feat: define cross-runtime agent HOME behavior #3873).
  • include_workdir grants 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 /sandbox behavior.
  • 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_workdir follows 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 DockerImageMetadata and Podman's ImageInspect already bind OCI
    Config.User to immutable image launch, so Config.WorkingDir can 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

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:sandboxSandbox runtime and isolation workstate:agent-readyApproved for agent implementationstate:pr-openedPR has been opened for this issue

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions