mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-21 06:51:01 +00:00
* Plugins: stabilize Area 6 loader and Docker smoke * Docker: fail fast on extension npm install errors * Tests: stabilize loader non-native Jiti boundary CI timeout * Tests: stabilize plugin loader Jiti source-runtime coverage * Docker: keep extension deps on lockfile graph * Tests: cover tsx-cache renamed package cwd fallback * Tests: stabilize plugin-sdk export subpath assertions * Plugins: align tsx-cache alias fallback with subpath fallback * Tests: normalize guardrail path checks for Windows * Plugins: restrict plugin-sdk cwd fallback to trusted roots * Tests: exempt outbound-session from extension import guard * Tests: tighten guardrails and cli-entry trust coverage * Tests: guard optional loader fixture exports * Tests: make loader fixture package exports null-safe * Tests: make loader fixture package exports null-safe * Tests: make loader fixture package exports null-safe * changelog Signed-off-by: joshavant <830519+joshavant@users.noreply.github.com> --------- Signed-off-by: joshavant <830519+joshavant@users.noreply.github.com>
76 lines
3.7 KiB
TypeScript
76 lines
3.7 KiB
TypeScript
import { readFile } from "node:fs/promises";
|
|
import { join, resolve } from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
import { describe, expect, it } from "vitest";
|
|
|
|
const repoRoot = resolve(fileURLToPath(new URL(".", import.meta.url)), "..");
|
|
const dockerfilePath = join(repoRoot, "Dockerfile");
|
|
|
|
describe("Dockerfile", () => {
|
|
it("uses shared multi-arch base image refs for all root Node stages", async () => {
|
|
const dockerfile = await readFile(dockerfilePath, "utf8");
|
|
expect(dockerfile).toContain(
|
|
'ARG OPENCLAW_NODE_BOOKWORM_IMAGE="node:24-bookworm@sha256:3a09aa6354567619221ef6c45a5051b671f953f0a1924d1f819ffb236e520e6b"',
|
|
);
|
|
expect(dockerfile).toContain(
|
|
'ARG OPENCLAW_NODE_BOOKWORM_SLIM_IMAGE="node:24-bookworm-slim@sha256:e8e2e91b1378f83c5b2dd15f0247f34110e2fe895f6ca7719dbb780f929368eb"',
|
|
);
|
|
expect(dockerfile).toContain("FROM ${OPENCLAW_NODE_BOOKWORM_IMAGE} AS ext-deps");
|
|
expect(dockerfile).toContain("FROM ${OPENCLAW_NODE_BOOKWORM_IMAGE} AS build");
|
|
expect(dockerfile).toContain("FROM ${OPENCLAW_NODE_BOOKWORM_IMAGE} AS base-default");
|
|
expect(dockerfile).toContain("FROM ${OPENCLAW_NODE_BOOKWORM_SLIM_IMAGE} AS base-slim");
|
|
expect(dockerfile).toContain("current multi-arch manifest list entry");
|
|
expect(dockerfile).not.toContain("current amd64 entry");
|
|
});
|
|
|
|
it("installs optional browser dependencies after pnpm install", async () => {
|
|
const dockerfile = await readFile(dockerfilePath, "utf8");
|
|
const installIndex = dockerfile.indexOf("pnpm install --frozen-lockfile");
|
|
const browserArgIndex = dockerfile.indexOf("ARG OPENCLAW_INSTALL_BROWSER");
|
|
|
|
expect(installIndex).toBeGreaterThan(-1);
|
|
expect(browserArgIndex).toBeGreaterThan(-1);
|
|
expect(browserArgIndex).toBeGreaterThan(installIndex);
|
|
expect(dockerfile).toContain(
|
|
"node /app/node_modules/playwright-core/cli.js install --with-deps chromium",
|
|
);
|
|
expect(dockerfile).toContain("apt-get install -y --no-install-recommends xvfb");
|
|
});
|
|
|
|
it("prunes runtime dependencies after the build stage", async () => {
|
|
const dockerfile = await readFile(dockerfilePath, "utf8");
|
|
expect(dockerfile).toContain("FROM build AS runtime-assets");
|
|
expect(dockerfile).toContain("CI=true pnpm prune --prod");
|
|
expect(dockerfile).not.toContain('npm install --prefix "extensions/$ext" --omit=dev --silent');
|
|
expect(dockerfile).toContain(
|
|
"COPY --from=runtime-assets --chown=node:node /app/node_modules ./node_modules",
|
|
);
|
|
});
|
|
|
|
it("pins bundled plugin discovery to copied source extensions in runtime images", async () => {
|
|
const dockerfile = await readFile(dockerfilePath, "utf8");
|
|
expect(dockerfile).toContain("ENV OPENCLAW_BUNDLED_PLUGINS_DIR=/app/extensions");
|
|
});
|
|
|
|
it("normalizes plugin and agent paths permissions in image layers", async () => {
|
|
const dockerfile = await readFile(dockerfilePath, "utf8");
|
|
expect(dockerfile).toContain("for dir in /app/extensions /app/.agent /app/.agents");
|
|
expect(dockerfile).toContain('find "$dir" -type d -exec chmod 755 {} +');
|
|
expect(dockerfile).toContain('find "$dir" -type f -exec chmod 644 {} +');
|
|
});
|
|
|
|
it("Docker GPG fingerprint awk uses correct quoting for OPENCLAW_SANDBOX=1 build", async () => {
|
|
const dockerfile = await readFile(dockerfilePath, "utf8");
|
|
expect(dockerfile).toContain('== "fpr" {');
|
|
expect(dockerfile).not.toContain('\\"fpr\\"');
|
|
});
|
|
|
|
it("keeps runtime pnpm available", async () => {
|
|
const dockerfile = await readFile(dockerfilePath, "utf8");
|
|
expect(dockerfile).toContain("ENV COREPACK_HOME=/usr/local/share/corepack");
|
|
expect(dockerfile).toContain(
|
|
'corepack prepare "$(node -p "require(\'./package.json\').packageManager")" --activate',
|
|
);
|
|
});
|
|
});
|