Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 13 additions & 10 deletions .github/workflows/build-sandboxes.yml
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,17 @@ jobs:
with:
driver-opts: ${{ github.ref != 'refs/heads/main' && 'network=host' || '' }}

- name: Set build platforms
id: platforms
run: |
if [ "${{ github.ref }}" = "refs/heads/main" ]; then
echo "value=linux/amd64,linux/arm64" >> "$GITHUB_OUTPUT"
elif [[ "${{ matrix.sandbox }}" == "nvidia-gpu" || "${{ matrix.sandbox }}" == gpu-workload-* ]]; then
echo "value=linux/amd64,linux/arm64" >> "$GITHUB_OUTPUT"
else
echo "value=linux/amd64" >> "$GITHUB_OUTPUT"
fi

- name: Log in to GHCR
uses: docker/login-action@v3
with:
Expand Down Expand Up @@ -209,6 +220,7 @@ jobs:
uses: docker/build-push-action@v6
with:
context: sandboxes/base
platforms: ${{ steps.platforms.outputs.value }}
push: true
tags: localhost:5000/sandboxes/base:latest
cache-from: type=gha,scope=base
Expand All @@ -220,6 +232,7 @@ jobs:
uses: docker/build-push-action@v6
with:
context: sandboxes/${{ steps.parent.outputs.sandbox }}
platforms: ${{ steps.platforms.outputs.value }}
push: true
tags: localhost:5000/sandboxes/${{ steps.parent.outputs.sandbox }}:latest
build-args: |
Expand Down Expand Up @@ -247,15 +260,6 @@ jobs:
type=sha,prefix=
type=raw,value=latest,enable={{is_default_branch}}

- name: Set build platforms
id: platforms
run: |
if [ "${{ github.ref }}" = "refs/heads/main" ] || [ "${{ matrix.sandbox }}" = "nvidia-gpu" ]; then
echo "value=linux/amd64,linux/arm64" >> "$GITHUB_OUTPUT"
else
echo "value=linux/amd64" >> "$GITHUB_OUTPUT"
fi

- name: Build and push
uses: docker/build-push-action@v6
with:
Expand All @@ -268,4 +272,3 @@ jobs:
BASE_IMAGE=${{ steps.base.outputs.image }}
cache-from: type=gha,scope=${{ matrix.sandbox }}
cache-to: type=gha,mode=max,scope=${{ matrix.sandbox }}

3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ This repo is the community ecosystem around OpenShell -- a hub for contributed s
| `sandboxes/base/` | Foundational image with system tools, users, and dev environment |
| `sandboxes/droid/` | Android automation and mobile testing workflows |
| `sandboxes/gemini/` | Gemini CLI workflows |
| `sandboxes/gpu-workload-cuda-basic/` | CUDA `deviceQuery` and `vectorAdd` GPU e2e validation workload |
| `sandboxes/gpu-workload-smoke-fail/` | Intentional-failure GPU e2e workload fixture |
| `sandboxes/gpu-workload-smoke-pass/` | Success-path GPU e2e workload fixture |
| `sandboxes/nvidia-gpu/` | GPU-enabled VM sandbox image with NVIDIA userspace tooling |
| `sandboxes/ollama/` | Ollama for local and cloud LLMs with Claude Code, Codex, OpenCode pre-installed |
| `sandboxes/pi/` | [Pi](https://pi.dev) pre-installed |
Expand Down
12 changes: 12 additions & 0 deletions THIRD-PARTY-NOTICES
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,18 @@ Image: nvidia/cuda:12.8.1-base-ubuntu22.04
License: NVIDIA CUDA Toolkit End User License Agreement and Ubuntu component licenses
URL: https://hub.docker.com/r/nvidia/cuda

Image: nvcr.io/nvidia/cuda:12.8.1-base-ubuntu22.04
License: NVIDIA CUDA Toolkit End User License Agreement and Ubuntu component licenses
URL: https://catalog.ngc.nvidia.com/orgs/nvidia/containers/cuda

================================================================================
Source Artifacts
================================================================================

Source: NVIDIA/cuda-samples v12.8
License: NVIDIA CUDA Samples License
URL: https://github.com/NVIDIA/cuda-samples

================================================================================
System Packages (APT — Ubuntu 24.04)
================================================================================
Expand Down
72 changes: 72 additions & 0 deletions sandboxes/gpu-workload-cuda-basic/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# syntax=docker/dockerfile:1

# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

ARG CUDA_BUILD_IMAGE=nvcr.io/nvidia/cuda:12.8.1-base-ubuntu22.04
ARG BASE_IMAGE=ghcr.io/nvidia/openshell-community/sandboxes/base:latest

FROM ${CUDA_BUILD_IMAGE} AS builder

ARG DEBIAN_FRONTEND=noninteractive
ARG CUDA_SAMPLES_REF=v12.8
ARG CUDA_SAMPLES_REPO=https://github.com/NVIDIA/cuda-samples

RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
ca-certificates \
cmake \
cuda-nvcc-12-8 \
curl \
g++ \
&& rm -rf /var/lib/apt/lists/*

WORKDIR /build/cuda-samples

RUN set -eux; \
curl -fsSL "${CUDA_SAMPLES_REPO}/archive/refs/tags/${CUDA_SAMPLES_REF}.tar.gz" \
-o /tmp/cuda-samples.tar.gz; \
tar -xzf /tmp/cuda-samples.tar.gz \
--strip-components=1 \
--wildcards \
'*/Common/*' \
'*/cmake/*' \
'*/Samples/0_Introduction/vectorAdd/*' \
'*/Samples/1_Utilities/deviceQuery/*' \
'*/LICENSE'; \
sed -i 's/CUDA::cudart/CUDA::cudart_static/g' \
Samples/1_Utilities/deviceQuery/CMakeLists.txt; \
cmake -S Samples/1_Utilities/deviceQuery -B /tmp/build-device-query \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_CUDA_RUNTIME_LIBRARY=Static; \
cmake --build /tmp/build-device-query --parallel; \
cmake -S Samples/0_Introduction/vectorAdd -B /tmp/build-vector-add \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_CUDA_RUNTIME_LIBRARY=Static; \
cmake --build /tmp/build-vector-add --parallel; \
mkdir -p /opt/openshell-gpu-workload; \
cp /tmp/build-device-query/deviceQuery /opt/openshell-gpu-workload/deviceQuery; \
cp /tmp/build-vector-add/vectorAdd /opt/openshell-gpu-workload/vectorAdd; \
cp LICENSE /opt/openshell-gpu-workload/cuda-samples.LICENSE; \
rm -f /tmp/cuda-samples.tar.gz

FROM ${BASE_IMAGE}

ARG CUDA_SAMPLES_REF=v12.8

LABEL com.nvidia.openshell.gpu-workload.name="cuda-basic" \
com.nvidia.openshell.gpu-workload.cuda-samples-ref="${CUDA_SAMPLES_REF}"

USER root
RUN mkdir -p /usr/local/lib/openshell-gpu-workload \
/usr/local/share/doc/openshell-gpu-workload
COPY --from=builder /opt/openshell-gpu-workload/deviceQuery /usr/local/lib/openshell-gpu-workload/deviceQuery
COPY --from=builder /opt/openshell-gpu-workload/vectorAdd /usr/local/lib/openshell-gpu-workload/vectorAdd
COPY --from=builder /opt/openshell-gpu-workload/cuda-samples.LICENSE /usr/local/share/doc/openshell-gpu-workload/cuda-samples.LICENSE
COPY workload.sh /usr/local/bin/openshell-gpu-workload
RUN chmod 0755 /usr/local/bin/openshell-gpu-workload \
/usr/local/lib/openshell-gpu-workload/deviceQuery \
/usr/local/lib/openshell-gpu-workload/vectorAdd

USER sandbox
ENTRYPOINT ["/usr/local/bin/openshell-gpu-workload"]
52 changes: 52 additions & 0 deletions sandboxes/gpu-workload-cuda-basic/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<!-- SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -->
<!-- SPDX-License-Identifier: Apache-2.0 -->

# GPU Workload CUDA Basic

`gpu-workload-cuda-basic` validates that a GPU-enabled environment can run a
basic CUDA runtime workload. It is a single image that runs two validation
steps:

1. `deviceQuery` checks CUDA runtime, driver, and device discovery.
2. `vectorAdd` checks kernel launch, device memory allocation, host/device
copies, synchronization, and result validation.

The image builds the samples from `NVIDIA/cuda-samples` tag `v12.8` with a CUDA
12.8 builder image, then copies only the compiled binaries into the OpenShell
community base final image. Published builds are multiarch for `linux/amd64`
and `linux/arm64`.

The workload prints `OPENSHELL_GPU_WORKLOAD_SUCCESS` only after both samples
pass. On failure it prints `OPENSHELL_GPU_WORKLOAD_FAILURE` and exits non-zero.

## Contract

The image installs the workload at `/usr/local/bin/openshell-gpu-workload`.
Direct container execution runs the workload as the image entrypoint. OpenShell
tests that create a sandbox from this image should run the workload path
explicitly because sandbox creation replaces the OCI entrypoint.

The workload requires no network access after the image is pulled. It does not
vendor GPU driver libraries such as `libcuda.so.1`; those libraries must be
provided by the host GPU runtime or CDI injection.

## Build

```shell
docker build -t gpu-workload-cuda-basic .
```

## Run

Run it directly with Docker CDI:

```shell
docker run --rm --device nvidia.com/gpu=all gpu-workload-cuda-basic
```

Use `podman run` with the same `--device nvidia.com/gpu=all` option when Podman
CDI is configured.

The CUDA samples are redistributed under the NVIDIA CUDA samples license. The
license text is copied into the image at
`/usr/local/share/doc/openshell-gpu-workload/cuda-samples.LICENSE`.
40 changes: 40 additions & 0 deletions sandboxes/gpu-workload-cuda-basic/workload.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#!/usr/bin/env bash

# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

set -euo pipefail

readonly SUCCESS_MARKER="OPENSHELL_GPU_WORKLOAD_SUCCESS"
readonly FAILURE_MARKER="OPENSHELL_GPU_WORKLOAD_FAILURE"
readonly WORKLOAD_DIR="/usr/local/lib/openshell-gpu-workload"

run_sample() {
local name=$1
local expected=$2
local binary="${WORKLOAD_DIR}/${name}"
local output

output="$(mktemp)"
echo "running CUDA sample: ${name}"
if ! "${binary}" >"${output}" 2>&1; then
cat "${output}"
echo "${FAILURE_MARKER} ${name} exited non-zero" >&2
rm -f "${output}"
exit 1
fi

cat "${output}"
if ! grep -Fq "${expected}" "${output}"; then
echo "${FAILURE_MARKER} ${name} did not print expected output: ${expected}" >&2
rm -f "${output}"
exit 1
fi

rm -f "${output}"
}

run_sample "deviceQuery" "Result = PASS"
run_sample "vectorAdd" "Test PASSED"

echo "${SUCCESS_MARKER} cuda-basic"
15 changes: 15 additions & 0 deletions sandboxes/gpu-workload-smoke-fail/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# syntax=docker/dockerfile:1

# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

ARG BASE_IMAGE=ghcr.io/nvidia/openshell-community/sandboxes/base:latest

FROM ${BASE_IMAGE}

USER root
COPY workload.sh /usr/local/bin/openshell-gpu-workload
RUN chmod 0755 /usr/local/bin/openshell-gpu-workload

USER sandbox
ENTRYPOINT ["/usr/local/bin/openshell-gpu-workload"]
34 changes: 34 additions & 0 deletions sandboxes/gpu-workload-smoke-fail/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<!-- SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -->
<!-- SPDX-License-Identifier: Apache-2.0 -->

# GPU Workload Smoke Fail

`gpu-workload-smoke-fail` validates negative-path diagnostics in e2e test
plumbing.

The workload does not perform GPU-specific work. It prints
`OPENSHELL_GPU_WORKLOAD_FAILURE`, emits a stable diagnostic, and exits with
status `42`.

## Contract

The image installs the workload at `/usr/local/bin/openshell-gpu-workload`.
Direct container execution runs the workload as the image entrypoint. OpenShell
tests that create a sandbox from this image should run the workload path
explicitly because sandbox creation replaces the OCI entrypoint.

The workload requires no network access after the image is pulled.

## Build

```shell
docker build -t gpu-workload-smoke-fail .
```

## Run

```shell
docker run --rm gpu-workload-smoke-fail
```

The direct run should fail.
9 changes: 9 additions & 0 deletions sandboxes/gpu-workload-smoke-fail/workload.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/usr/bin/env bash

# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

set -euo pipefail

echo "OPENSHELL_GPU_WORKLOAD_FAILURE smoke-fail intentional failure" >&2
exit 42
15 changes: 15 additions & 0 deletions sandboxes/gpu-workload-smoke-pass/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# syntax=docker/dockerfile:1

# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

ARG BASE_IMAGE=ghcr.io/nvidia/openshell-community/sandboxes/base:latest

FROM ${BASE_IMAGE}

USER root
COPY workload.sh /usr/local/bin/openshell-gpu-workload
RUN chmod 0755 /usr/local/bin/openshell-gpu-workload

USER sandbox
ENTRYPOINT ["/usr/local/bin/openshell-gpu-workload"]
32 changes: 32 additions & 0 deletions sandboxes/gpu-workload-smoke-pass/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<!-- SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -->
<!-- SPDX-License-Identifier: Apache-2.0 -->

# GPU Workload Smoke Pass

`gpu-workload-smoke-pass` validates image publishing, sandbox image
compatibility, default entrypoint execution, and success-marker assertion
plumbing.

The workload does not perform GPU-specific work. It prints
`OPENSHELL_GPU_WORKLOAD_SUCCESS` and exits `0`.

## Contract

The image installs the workload at `/usr/local/bin/openshell-gpu-workload`.
Direct container execution runs the workload as the image entrypoint. OpenShell
tests that create a sandbox from this image should run the workload path
explicitly because sandbox creation replaces the OCI entrypoint.

The workload requires no network access after the image is pulled.

## Build

```shell
docker build -t gpu-workload-smoke-pass .
```

## Run

```shell
docker run --rm gpu-workload-smoke-pass
```
8 changes: 8 additions & 0 deletions sandboxes/gpu-workload-smoke-pass/workload.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/usr/bin/env bash

# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

set -euo pipefail

echo "OPENSHELL_GPU_WORKLOAD_SUCCESS smoke-pass"
Loading