diff --git a/scripts/check-docker-e2e-boundaries.mjs b/scripts/check-docker-e2e-boundaries.mjs index 84a36640d1e..b20ffec0e22 100644 --- a/scripts/check-docker-e2e-boundaries.mjs +++ b/scripts/check-docker-e2e-boundaries.mjs @@ -12,9 +12,9 @@ const ROOT_DIR = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".." const errors = []; const packageJson = JSON.parse(readText("package.json")); const packageScripts = new Set(Object.keys(packageJson.scripts ?? {})); -// This lane proves the published Codex npm plugin against live OpenAI auth, so -// it intentionally needs both live credentials and the package-backed image. -const livePackageBackedLanes = new Set(["live-codex-npm-plugin"]); +// These lanes prove package-installed surfaces against live auth, so they +// intentionally need both live credentials and a package-backed image. +const livePackageBackedLanes = new Set(["live-codex-npm-plugin", "openwebui"]); function readText(relativePath) { return fs.readFileSync(path.join(ROOT_DIR, relativePath), "utf8"); diff --git a/scripts/lib/docker-e2e-plan.mjs b/scripts/lib/docker-e2e-plan.mjs index 421128108ab..b8de69eb664 100644 --- a/scripts/lib/docker-e2e-plan.mjs +++ b/scripts/lib/docker-e2e-plan.mjs @@ -369,7 +369,7 @@ function buildPlanJson(params) { bareImage: imageKinds.includes("bare"), e2eImage: imageKinds.length > 0, functionalImage: imageKinds.includes("functional"), - liveImage: scheduledLanes.some((poolLane) => poolLane.live), + liveImage: scheduledLanes.some((poolLane) => poolLane.needsLiveImage), package: lanesNeedOpenClawPackage(scheduledLanes), }, profile: params.profile, diff --git a/scripts/lib/docker-e2e-scenarios.mjs b/scripts/lib/docker-e2e-scenarios.mjs index e462220fe41..911e2d4922c 100644 --- a/scripts/lib/docker-e2e-scenarios.mjs +++ b/scripts/lib/docker-e2e-scenarios.mjs @@ -36,6 +36,7 @@ function lane(name, command, options = {}) { live: options.live === true, noOutputTimeoutMs: options.noOutputTimeoutMs, name, + needsLiveImage: options.needsLiveImage, retryPatterns: options.retryPatterns ?? [], retries: options.retries ?? 0, resources: options.resources ?? [], @@ -79,6 +80,7 @@ function liveLane(name, command, options = {}) { return lane(name, command, { ...options, live: true, + needsLiveImage: options.needsLiveImage ?? true, resources: ["live", ...liveProviderResources(options), ...(options.resources ?? [])], retryPatterns: options.retryPatterns ?? LIVE_RETRY_PATTERNS, retries: options.retries ?? DEFAULT_LIVE_RETRIES, @@ -158,6 +160,8 @@ export const mainLanes = [ }, ), liveLane("openwebui", "OPENCLAW_SKIP_DOCKER_BUILD=1 pnpm test:docker:openwebui", { + e2eImageKind: "functional", + needsLiveImage: false, provider: "openai", resources: ["service"], timeoutMs: OPENWEBUI_TIMEOUT_MS, @@ -583,6 +587,8 @@ const legacyReleasePathChunks = { function openWebUILane() { return liveLane("openwebui", "OPENCLAW_SKIP_DOCKER_BUILD=1 pnpm test:docker:openwebui", { + e2eImageKind: "functional", + needsLiveImage: false, provider: "openai", resources: ["service"], timeoutMs: OPENWEBUI_TIMEOUT_MS, diff --git a/test/scripts/docker-e2e-plan.test.ts b/test/scripts/docker-e2e-plan.test.ts index c94a2a19978..d4160b16557 100644 --- a/test/scripts/docker-e2e-plan.test.ts +++ b/test/scripts/docker-e2e-plan.test.ts @@ -472,7 +472,7 @@ describe("scripts/lib/docker-e2e-plan", () => { }); }); - it("plans Open WebUI as a live-only lane with OpenAI credentials", () => { + it("plans Open WebUI as a live-auth functional image lane", () => { const plan = planFor({ includeOpenWebUI: true, selectedLaneNames: ["openwebui"], @@ -481,17 +481,17 @@ describe("scripts/lib/docker-e2e-plan", () => { expect(plan.credentials).toEqual(["openai"]); expect(plan.lanes).toEqual([ expect.objectContaining({ - imageKind: undefined, + imageKind: "functional", live: true, name: "openwebui", resources: expect.arrayContaining(["docker", "live", "live:openai", "service"]), }), ]); expect(plan.needs).toMatchObject({ - e2eImage: false, - functionalImage: false, - liveImage: true, - package: false, + e2eImage: true, + functionalImage: true, + liveImage: false, + package: true, }); });