Skip to content
Draft
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
3 changes: 3 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
*
!docker/
!docker/schedulestream-v1.requirements.txt
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -218,3 +218,8 @@ __marimo__/

# Streamlit
.streamlit/secrets.toml

agentic_design/

# Local autonomous-generation artifacts
datasets/autonomous_runs/
54 changes: 54 additions & 0 deletions docker/Dockerfile.schedulestream_v1
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Copyright (c) 2026, The Isaac AutoData Project Developers.
# All rights reserved.
#
# SPDX-License-Identifier: Apache-2.0

# Local-only ScheduleStream/cuRobo-v1 development overlay. ScheduleStream is supplied as a named
# build context because its restricted license does not permit AutoData to vendor or fetch it.
# Build with docker/build_schedulestream_v1.sh; never use the frozen UMI image tag as the base/tag.
ARG BASE_IMAGE=isaac_autodata:curobo
FROM ${BASE_IMAGE}

USER root

ARG SCHEDULESTREAM_COMMIT
ARG SCHEDULESTREAM_VERSION
ARG BASE_IMAGE_ID
RUN test -n "${SCHEDULESTREAM_COMMIT}" \
&& test -n "${SCHEDULESTREAM_VERSION}" \
&& test -n "${BASE_IMAGE_ID}"

LABEL org.opencontainers.image.title="Isaac AutoData ScheduleStream cuRobo-v1 development overlay" \
org.opencontainers.image.description="Local research/evaluation image; not approved for redistribution" \
org.opencontainers.image.schedulestream.commit="${SCHEDULESTREAM_COMMIT}" \
org.opencontainers.image.schedulestream.application="custream" \
org.opencontainers.image.curobo.api-generation="v1" \
org.opencontainers.image.base.digest="${BASE_IMAGE_ID}"

# ScheduleStream's `custream` extra requires structlog but does not constrain it. Pin a reviewed,
# hash-verified universal wheel rather than mutating the host environment or resolving latest.
COPY docker/schedulestream-v1.requirements.txt /tmp/schedulestream-v1.requirements.txt
RUN /isaac-sim/python.sh -m pip install \
--disable-pip-version-check \
--no-cache-dir \
--only-binary=:all: \
--require-hashes \
--requirement /tmp/schedulestream-v1.requirements.txt \
&& rm -f /tmp/schedulestream-v1.requirements.txt

# The named context is an exact, locally available ScheduleStream checkout. Do not copy `.git` or
# unrelated data into the image. Its commit is verified by the host build script and stamped above.
COPY --from=schedulestream pyproject.toml LICENSE /opt/schedulestream/
COPY --from=schedulestream src /opt/schedulestream/src
RUN SETUPTOOLS_SCM_PRETEND_VERSION_FOR_SCHEDULESTREAM="${SCHEDULESTREAM_VERSION}" \
/isaac-sim/python.sh -m pip install \
--disable-pip-version-check \
--no-build-isolation \
--no-deps \
/opt/schedulestream

ENV SCHEDULESTREAM_SOURCE_COMMIT=${SCHEDULESTREAM_COMMIT} \
SCHEDULESTREAM_VERSION=${SCHEDULESTREAM_VERSION}

# Importing the Isaac integration allocates cuRobo CUDA tensors, so the GPU/App smoke test is run
# after the image build by docker/smoke_schedulestream_v1.py rather than in this CPU-only layer.
106 changes: 106 additions & 0 deletions docker/autonomous_entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
#!/bin/bash
# Copyright (c) 2026, The Isaac AutoData Project Developers.
# All rights reserved.
#
# SPDX-License-Identifier: Apache-2.0

set -euo pipefail

readonly AUTODATA_HOME="/autodata-home"
readonly AUTODATA_RUN_ROOT="/autonomous-run"
readonly AUTODATA_RUNTIME_ROOT="/tmp/autodata-runtime"
readonly AUTODATA_KIT_CACHE="/isaac-sim/kit/cache"
readonly AUTODATA_OV_CACHE="${AUTODATA_HOME}/.cache/ov"
readonly AUTODATA_WARP_CACHE="${AUTODATA_HOME}/.cache/warp"
readonly AUTODATA_GL_CACHE="${AUTODATA_HOME}/.cache/nvidia/GLCache"
readonly AUTODATA_COMPUTE_CACHE="${AUTODATA_HOME}/.nv/ComputeCache"

fail() {
echo "error: $*" >&2
exit 2
}

require_positive_id() {
local label="$1"
local value="$2"
[[ "${value}" =~ ^[0-9]+$ ]] || fail "${label} must be a positive integer"
((value > 0 && value <= 4294967294)) || fail "${label} is outside the supported range"
}

[[ "${EUID}" -eq 0 ]] || fail "container entrypoint must start as root"
[[ "$#" -gt 0 ]] || fail "container command is required"

host_uid="${DOCKER_RUN_USER_ID:-}"
host_gid="${DOCKER_RUN_GROUP_ID:-}"
require_positive_id "DOCKER_RUN_USER_ID" "${host_uid}"
require_positive_id "DOCKER_RUN_GROUP_ID" "${host_gid}"

for required_command in chown cut getent groupadd install setpriv useradd; do
command -v "${required_command}" >/dev/null || fail "required command is unavailable: ${required_command}"
done

autodata_group="autodata_g${host_gid}"
if ! getent group "${host_gid}" >/dev/null 2>&1; then
getent group "${autodata_group}" >/dev/null 2>&1 && fail "image group-name collision: ${autodata_group}"
groupadd --key GID_MAX=4294967294 --gid "${host_gid}" "${autodata_group}"
fi

autodata_user="autodata_u${host_uid}"
passwd_entry=$(getent passwd "${host_uid}" || true)
if [[ -z "${passwd_entry}" ]]; then
getent passwd "${autodata_user}" >/dev/null 2>&1 && fail "image user-name collision: ${autodata_user}"
useradd \
--key UID_MAX=4294967294 \
--no-create-home \
--no-log-init \
--uid "${host_uid}" \
--gid "${host_gid}" \
--home-dir "${AUTODATA_HOME}" \
--shell /bin/bash \
"${autodata_user}"
else
autodata_user="${passwd_entry%%:*}"
fi

passwd_entry=$(getent passwd "${host_uid}" || true)
[[ -n "${passwd_entry}" ]] || fail "container passwd lookup failed for host UID"
isaac_group_entry=$(getent group isaac-sim || true)
[[ -n "${isaac_group_entry}" ]] || fail "image does not define the isaac-sim group"
isaac_group_gid=$(printf '%s\n' "${isaac_group_entry}" | cut -d: -f3)
require_positive_id "isaac-sim group ID" "${isaac_group_gid}"

install -d --mode 0700 --owner "${host_uid}" --group "${host_gid}" \
"${AUTODATA_HOME}" \
"${AUTODATA_HOME}/.cache" \
"${AUTODATA_HOME}/.cache/nvidia" \
"${AUTODATA_HOME}/.nv" \
"${AUTODATA_RUNTIME_ROOT}"

cache_roots=(
"${AUTODATA_KIT_CACHE}"
"${AUTODATA_OV_CACHE}"
"${AUTODATA_WARP_CACHE}"
"${AUTODATA_GL_CACHE}"
"${AUTODATA_COMPUTE_CACHE}"
)
for cache_root in "${cache_roots[@]}"; do
[[ -d "${cache_root}" ]] || fail "cache mount is missing: ${cache_root}"
chown "${host_uid}:${host_gid}" "${cache_root}"
done

[[ -d "${AUTODATA_RUN_ROOT}" ]] || fail "run-directory mount is missing: ${AUTODATA_RUN_ROOT}"
chown "${host_uid}:${host_gid}" "${AUTODATA_RUN_ROOT}"

exec setpriv \
--reuid "${host_uid}" \
--regid "${host_gid}" \
--groups "${isaac_group_gid}" \
--no-new-privs \
env \
-u DOCKER_RUN_USER_ID \
-u DOCKER_RUN_GROUP_ID \
HOME="${AUTODATA_HOME}" \
USER="${autodata_user}" \
LOGNAME="${autodata_user}" \
XDG_RUNTIME_DIR="${AUTODATA_RUNTIME_ROOT}" \
"$@"
84 changes: 84 additions & 0 deletions docker/build_schedulestream_v1.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
#!/bin/bash
# Copyright (c) 2026, The Isaac AutoData Project Developers.
# All rights reserved.
#
# SPDX-License-Identifier: Apache-2.0

set -euo pipefail

EXPECTED_SCHEDULESTREAM_COMMIT="f6351b8db8d7da9cb6ddd6854dbfc3123ab048f5"
SCHEDULESTREAM_VERSION="0.0.0.dev0+f6351b8"
BASE_IMAGE="${BASE_IMAGE:-isaac_autodata:curobo}"
OUTPUT_IMAGE="${OUTPUT_IMAGE:-isaac_autodata:schedulestream-v1}"

script_dir=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)
repo_root=$(cd -- "${script_dir}/.." && pwd)
schedulestream_source="${SCHEDULESTREAM_SOURCE:-${repo_root}/../nvplan}"

if [ ! -d "${schedulestream_source}/.git" ]; then
echo "error: ScheduleStream checkout not found at ${schedulestream_source}" >&2
echo "set SCHEDULESTREAM_SOURCE to the reviewed local checkout" >&2
exit 2
fi

actual_commit=$(git -C "${schedulestream_source}" rev-parse HEAD)
if [ "${actual_commit}" != "${EXPECTED_SCHEDULESTREAM_COMMIT}" ]; then
echo "error: ScheduleStream checkout is ${actual_commit}" >&2
echo "expected reviewed commit ${EXPECTED_SCHEDULESTREAM_COMMIT}" >&2
exit 3
fi
if [ -n "$(git -C "${schedulestream_source}" status --porcelain)" ]; then
echo "error: ScheduleStream checkout has local changes; refusing a non-reproducible image" >&2
exit 4
fi

base_image_id=$(docker image inspect --format '{{.Id}}' "${BASE_IMAGE}")
if [[ ! "${base_image_id}" =~ ^sha256:[0-9a-f]{64}$ ]]; then
echo "error: could not resolve ${BASE_IMAGE} to an immutable local image ID" >&2
exit 5
fi
base_image_pin="isaac-autodata-base-pin:${base_image_id#sha256:}-$$"
build_context=""
cleanup() {
if [[ -n "${build_context:-}" && -d "${build_context}" ]]; then
rm -rf -- "${build_context}"
fi
if [[ -n "${base_image_pin:-}" ]]; then
docker image rm "${base_image_pin}" >/dev/null 2>&1 || true
fi
}
trap cleanup EXIT
docker image tag "${base_image_id}" "${base_image_pin}"
build_context=$(mktemp -d "${TMPDIR:-/tmp}/isaac-autodata-schedulestream.XXXXXXXX")
mkdir -p "${build_context}/schedulestream"
# Materialize only paths tracked by the reviewed commit. The checkout was proven clean above, so
# reading those paths from the worktree preserves any reviewed Git-LFS smudge results while a
# NUL-delimited tree listing excludes ignored files and handles arbitrary tracked path names.
git -C "${schedulestream_source}" ls-tree \
-r \
--name-only \
-z \
"${actual_commit}" \
-- \
pyproject.toml \
LICENSE \
src \
| tar \
--create \
--file=- \
--directory="${schedulestream_source}" \
--null \
--files-from=- \
| tar -xf - -C "${build_context}/schedulestream"

echo "Building ${OUTPUT_IMAGE} from ${BASE_IMAGE} (${base_image_id})"
echo "ScheduleStream commit: ${actual_commit}"
docker build \
--build-arg "BASE_IMAGE=${base_image_pin}" \
--build-arg "BASE_IMAGE_ID=${base_image_id}" \
--build-arg "SCHEDULESTREAM_COMMIT=${actual_commit}" \
--build-arg "SCHEDULESTREAM_VERSION=${SCHEDULESTREAM_VERSION}" \
--build-context "schedulestream=${build_context}/schedulestream" \
--file "${script_dir}/Dockerfile.schedulestream_v1" \
--tag "${OUTPUT_IMAGE}" \
"${repo_root}"
Loading