Skip to content

OpenShellSpawner: Cross-platform skills_image extraction via crane #106

Closed

Description

@jameswnl

Context

_load_skills() in OpenShellSpawner currently extracts skills from OCI images using the Podman Python SDK, which requires a Podman socket. This works when:

  • OpenShell gateway uses the Podman driver (runner has Podman socket mounted) ✅
  • Runner runs on a host with Podman ✅

It fails when:

  • OpenShell gateway uses the K8s driver (runner is a K8s pod with no Podman socket) ❌
  • Any environment without a container runtime accessible to the runner ❌

The current code raises RuntimeError("neither Podman SDK nor podman CLI available") in these cases.

Solution

Use crane (google/go-containerregistry) as the primary skills image extraction method:

  • Single static Go binary (~15MB), no daemon required
  • Pulls from any OCI registry using standard auth (registry credentials, service account tokens)
  • Exports image content as a tar stream: crane export <image> -
  • Works in any environment — K8s pods, containers, bare metal

Changes

  1. Runner Containerfile: Add crane binary (download from GitHub releases during build)
  2. _extract_skills_image(): Use crane export <image> - | tar xf - -C /tmp/skills/ as primary path
  3. Fallback chain: crane → Podman SDK → podman CLI → RuntimeError
  4. Tests: Cover crane path, Podman SDK fallback, and no-runtime error

Flow

Runner                              Sandbox
  |                                    |
  |-- crane export <image> ----------> tar bytes in memory
  |                                    |
  |-- exec_stream(tar xf stdin) -----> /app/skills/ populated

The sandbox-side upload (exec_stream with tar) is unchanged — only the extraction method changes.

Verification

  1. Unit tests: mock subprocess.run for crane, verify tar output piped to exec_stream
  2. E2E on EC2: OpenShell + Podman driver with skills_image workflow
  3. E2E on Kind: OpenShell + K8s driver (runner as K8s pod) with skills_image workflow

Activity

  1. added
    plan-createdIssue has an implementation plan ready for bot review
    on Jul 11, 2026
  2. beesarmy commented on Jul 11, 2026

    @beesarmy
    Collaborator

    Triage

    Summary: Replace Podman-dependent skills image extraction with crane (static Go binary) for cross-platform support — enables K8s driver deployments where no Podman socket is available.

    Affected components:

    • src/cloud_agents/spawner/openshell_spawner.py — _load_skills() (line 575), _extract_skills_image() (line 601)
    • Runner Containerfile — add crane binary

    Related issues/PRs:

    Suggested labels: enhancement, area/spawner

    Plan review:

    • ✅ Problem accurately identified — _extract_skills_image() uses Podman SDK/CLI, confirmed at line 601. Fails on K8s driver deployments.
    • ✅ crane is a well-known tool for daemon-less OCI image operations — correct choice for this use case
    • ✅ Sandbox-side upload (exec_stream tar) unchanged — clean separation of extraction vs injection
    • ✅ Fallback chain (crane → Podman SDK → podman CLI → error) is defensive
    • ✅ Verification plan covers both Podman and K8s driver paths
    • ⚠️ crane binary in runner image adds ~15MB. Consider whether it should be optional (only included in OpenShell-aware runner builds) or always bundled.
    • ⚠️ Registry auth for crane — plan says "standard auth" but doesn't specify how credentials reach crane in a K8s pod. crane reads ~/.docker/config.json or DOCKER_CONFIG by default. If the runner pod has a pull secret mounted, crane needs to be pointed at it.

    Non-blocking ⚠️ only. Plan approved.


    🤖 Triaged by beesarmy via Claude Code

  3. jameswnl commented on Aug 28, 2026

    @jameswnl
    CollaboratorAuthor

    Closing as superseded, not implemented as originally planned. #202 (closed 2026-08-28) found the whole crane/Podman-extraction + tar-upload approach broken for two stacked reasons (this issue, plus a separate permissions bug in #201) and redesigned the mechanism entirely: skills now ship baked into the sandbox image at build time, scoped per-run via allowed_skills/Landlock instead of extracted at runtime. _load_skills()/_extract_skills_image() no longer exist in openshell_spawner.py -- the Podman-socket dependency this issue was about is gone along with the code that needed it.

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

    plan-approvedImplementation plan reviewed and approved by botplan-createdIssue has an implementation plan ready for bot review

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions