fix(docker): package runtime workspace templates

This commit is contained in:
Peter Steinberger
2026-05-27 18:54:08 +01:00
parent 8e8445905f
commit 659b5dce79
3 changed files with 113 additions and 0 deletions

View File

@@ -162,6 +162,50 @@ jobs:
provenance: mode=max
push: true
- name: Smoke test amd64 runtime workspace templates
shell: bash
env:
IMAGE_REFS: ${{ steps.tags.outputs.value }}
run: |
set -euo pipefail
mapfile -t image_refs <<< "${IMAGE_REFS}"
image_ref="${image_refs[0]}"
if [[ -z "${image_ref}" ]]; then
echo "::error::No amd64 image ref resolved for runtime template smoke"
exit 1
fi
docker run --rm --entrypoint /bin/sh "${image_ref}" -lc '
set -eu
test -f /app/src/agents/templates/HEARTBEAT.md
temp_root="$(mktemp -d)"
trap "rm -rf \"${temp_root}\"" EXIT
mkdir -p "${temp_root}/home" "${temp_root}/cwd"
cd "${temp_root}/cwd"
set +e
HOME="${temp_root}/home" \
USERPROFILE="${temp_root}/home" \
OPENCLAW_HOME="${temp_root}/home" \
OPENCLAW_NO_ONBOARD=1 \
OPENCLAW_SUPPRESS_NOTES=1 \
OPENCLAW_DISABLE_BUNDLED_PLUGINS=1 \
OPENCLAW_DISABLE_BUNDLED_ENTRY_SOURCE_FALLBACK=1 \
AWS_EC2_METADATA_DISABLED=true \
AWS_SHARED_CREDENTIALS_FILE="${temp_root}/home/.aws/credentials" \
AWS_CONFIG_FILE="${temp_root}/home/.aws/config" \
node /app/openclaw.mjs agent --message "workspace bootstrap smoke" --session-id "workspace-bootstrap-smoke" --local --timeout 1 --json \
>"${temp_root}/out.log" 2>&1
status="$?"
set -e
if grep -F "Missing workspace template:" "${temp_root}/out.log"; then
cat "${temp_root}/out.log"
exit 1
fi
test -f "${temp_root}/home/.openclaw/workspace/HEARTBEAT.md"
if [ "${status}" -ne 0 ]; then
cat "${temp_root}/out.log"
fi
'
# Build arm64 image. Default and slim tags point to the same slim runtime.
build-arm64:
needs: [approve_manual_backfill]
@@ -260,6 +304,50 @@ jobs:
provenance: mode=max
push: true
- name: Smoke test arm64 runtime workspace templates
shell: bash
env:
IMAGE_REFS: ${{ steps.tags.outputs.value }}
run: |
set -euo pipefail
mapfile -t image_refs <<< "${IMAGE_REFS}"
image_ref="${image_refs[0]}"
if [[ -z "${image_ref}" ]]; then
echo "::error::No arm64 image ref resolved for runtime template smoke"
exit 1
fi
docker run --rm --entrypoint /bin/sh "${image_ref}" -lc '
set -eu
test -f /app/src/agents/templates/HEARTBEAT.md
temp_root="$(mktemp -d)"
trap "rm -rf \"${temp_root}\"" EXIT
mkdir -p "${temp_root}/home" "${temp_root}/cwd"
cd "${temp_root}/cwd"
set +e
HOME="${temp_root}/home" \
USERPROFILE="${temp_root}/home" \
OPENCLAW_HOME="${temp_root}/home" \
OPENCLAW_NO_ONBOARD=1 \
OPENCLAW_SUPPRESS_NOTES=1 \
OPENCLAW_DISABLE_BUNDLED_PLUGINS=1 \
OPENCLAW_DISABLE_BUNDLED_ENTRY_SOURCE_FALLBACK=1 \
AWS_EC2_METADATA_DISABLED=true \
AWS_SHARED_CREDENTIALS_FILE="${temp_root}/home/.aws/credentials" \
AWS_CONFIG_FILE="${temp_root}/home/.aws/config" \
node /app/openclaw.mjs agent --message "workspace bootstrap smoke" --session-id "workspace-bootstrap-smoke" --local --timeout 1 --json \
>"${temp_root}/out.log" 2>&1
status="$?"
set -e
if grep -F "Missing workspace template:" "${temp_root}/out.log"; then
cat "${temp_root}/out.log"
exit 1
fi
test -f "${temp_root}/home/.openclaw/workspace/HEARTBEAT.md"
if [ "${status}" -ne 0 ]; then
cat "${temp_root}/out.log"
fi
'
# Create multi-platform manifests
create-manifest:
needs: [approve_manual_backfill, build-amd64, build-arm64]

View File

@@ -178,6 +178,7 @@ COPY --from=runtime-assets --chown=node:node /app/package.json .
COPY --from=runtime-assets --chown=node:node /app/pnpm-workspace.yaml .
COPY --from=runtime-assets --chown=node:node /app/patches ./patches
COPY --from=runtime-assets --chown=node:node /app/openclaw.mjs .
COPY --from=runtime-assets --chown=node:node /app/src/agents/templates ./src/agents/templates
COPY --from=runtime-assets --chown=node:node /app/${OPENCLAW_BUNDLED_PLUGIN_DIR} ./${OPENCLAW_BUNDLED_PLUGIN_DIR}
COPY --from=runtime-assets --chown=node:node /app/skills ./skills
COPY --from=runtime-assets --chown=node:node /app/docs ./docs

View File

@@ -246,6 +246,20 @@ describe("Dockerfile", () => {
);
});
it("keeps runtime workspace templates in final images", async () => {
const dockerfile = await readFile(dockerfilePath, "utf8");
const runtimeStageIndex = dockerfile.lastIndexOf("FROM base-runtime");
const templatesCopyIndex = dockerfile.indexOf(
"COPY --from=runtime-assets --chown=node:node /app/src/agents/templates ./src/agents/templates",
runtimeStageIndex,
);
const userIndex = dockerfile.indexOf("USER node", runtimeStageIndex);
expect(runtimeStageIndex).toBeGreaterThan(-1);
expect(templatesCopyIndex).toBeGreaterThan(runtimeStageIndex);
expect(templatesCopyIndex).toBeLessThan(userIndex);
});
it("keeps package manager patch files in runtime images", async () => {
const dockerfile = collapseDockerContinuations(await readFile(dockerfilePath, "utf8"));
const pnpmWorkspace = YAML.parse(await readFile(pnpmWorkspacePath, "utf8")) as {
@@ -277,6 +291,16 @@ describe("Dockerfile", () => {
expect(workflow).not.toContain("OPENCLAW_EXTENSIONS=diagnostics-otel\n");
});
it("smokes runtime workspace templates before Docker release manifests publish", async () => {
const workflow = await readFile(dockerReleaseWorkflowPath, "utf8");
expect(workflow).toContain("Smoke test amd64 runtime workspace templates");
expect(workflow).toContain("Smoke test arm64 runtime workspace templates");
expect(workflow).toContain("test -f /app/src/agents/templates/HEARTBEAT.md");
expect(workflow).toContain('grep -F "Missing workspace template:"');
expect(workflow).toContain('test -f "${temp_root}/home/.openclaw/workspace/HEARTBEAT.md"');
});
it("does not override bundled plugin discovery in runtime images", async () => {
const dockerfile = collapseDockerContinuations(await readFile(dockerfilePath, "utf8"));
expect(dockerfile).toContain(`ARG OPENCLAW_BUNDLED_PLUGIN_DIR=${BUNDLED_PLUGIN_ROOT_DIR}`);