From f7157958de618c6131d83053ed4cd928590e88f6 Mon Sep 17 00:00:00 2001 From: Ayaan Zaidi Date: Fri, 24 Apr 2026 09:27:21 +0530 Subject: [PATCH] test(release): harden npm telegram smoke inputs --- .../telegram/telegram-live.runtime.ts | 7 +++-- scripts/e2e/npm-telegram-live-docker.sh | 15 ++++++++++ scripts/e2e/npm-telegram-live-runner.ts | 30 +++++++++++++++++-- 3 files changed, 48 insertions(+), 4 deletions(-) diff --git a/extensions/qa-lab/src/live-transports/telegram/telegram-live.runtime.ts b/extensions/qa-lab/src/live-transports/telegram/telegram-live.runtime.ts index 9c25e20a956..aa4cf68216e 100644 --- a/extensions/qa-lab/src/live-transports/telegram/telegram-live.runtime.ts +++ b/extensions/qa-lab/src/live-transports/telegram/telegram-live.runtime.ts @@ -1,6 +1,7 @@ import { execFile } from "node:child_process"; import { randomUUID } from "node:crypto"; import fs from "node:fs/promises"; +import os from "node:os"; import path from "node:path"; import { promisify } from "node:util"; import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; @@ -969,10 +970,12 @@ async function runInstalledOpenClawTelegramOnboardingPreflight(params: { openClawCommand: string; sutToken: string; }) { - const tempRoot = await fs.mkdtemp(path.join(process.cwd(), ".tmp-openclaw-npm-telegram-")); + const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-npm-telegram-")); const homeDir = path.join(tempRoot, "home"); const stateDir = path.join(homeDir, ".openclaw"); await fs.mkdir(stateDir, { recursive: true }); + const tokenPath = path.join(tempRoot, "sut-token.txt"); + await fs.writeFile(tokenPath, params.sutToken, { encoding: "utf8", mode: 0o600 }); const env = { ...process.env, HOME: homeDir, @@ -1008,7 +1011,7 @@ async function runInstalledOpenClawTelegramOnboardingPreflight(params: { ); await execFileAsync( params.openClawCommand, - ["channels", "add", "--channel", "telegram", "--token", params.sutToken], + ["channels", "add", "--channel", "telegram", "--token-file", tokenPath], { env }, ); await execFileAsync(params.openClawCommand, ["doctor", "--non-interactive"], { env }); diff --git a/scripts/e2e/npm-telegram-live-docker.sh b/scripts/e2e/npm-telegram-live-docker.sh index ae83146be42..27374665688 100755 --- a/scripts/e2e/npm-telegram-live-docker.sh +++ b/scripts/e2e/npm-telegram-live-docker.sh @@ -9,6 +9,17 @@ DOCKER_TARGET="${OPENCLAW_NPM_TELEGRAM_DOCKER_TARGET:-build}" PACKAGE_SPEC="${OPENCLAW_NPM_TELEGRAM_PACKAGE_SPEC:-openclaw@beta}" OUTPUT_DIR="${OPENCLAW_NPM_TELEGRAM_OUTPUT_DIR:-.artifacts/qa-e2e/npm-telegram-live}" +validate_openclaw_package_spec() { + local spec="$1" + if [[ "$spec" =~ ^openclaw@(beta|latest|[0-9]{4}\.[1-9][0-9]*\.[1-9][0-9]*(-[1-9][0-9]*|-beta\.[1-9][0-9]*)?)$ ]]; then + return 0 + fi + echo "OPENCLAW_NPM_TELEGRAM_PACKAGE_SPEC must be openclaw@beta, openclaw@latest, or an exact OpenClaw release version; got: $spec" >&2 + exit 1 +} + +validate_openclaw_package_spec "$PACKAGE_SPEC" + docker_e2e_build_or_reuse "$IMAGE_NAME" npm-telegram-live "$ROOT_DIR/scripts/e2e/Dockerfile" "$ROOT_DIR" "$DOCKER_TARGET" mkdir -p "$ROOT_DIR/.artifacts/qa-e2e" @@ -75,6 +86,10 @@ export PATH="$NPM_CONFIG_PREFIX/bin:$PATH" export OPENCLAW_NPM_TELEGRAM_REPO_ROOT="/app" package_spec="${OPENCLAW_NPM_TELEGRAM_PACKAGE_SPEC:?missing OPENCLAW_NPM_TELEGRAM_PACKAGE_SPEC}" +if [[ ! "$package_spec" =~ ^openclaw@(beta|latest|[0-9]{4}\.[1-9][0-9]*\.[1-9][0-9]*(-[1-9][0-9]*|-beta\.[1-9][0-9]*)?)$ ]]; then + echo "OPENCLAW_NPM_TELEGRAM_PACKAGE_SPEC must be openclaw@beta, openclaw@latest, or an exact OpenClaw release version; got: $package_spec" >&2 + exit 1 +fi echo "Installing ${package_spec}..." npm install -g "$package_spec" --no-fund --no-audit diff --git a/scripts/e2e/npm-telegram-live-runner.ts b/scripts/e2e/npm-telegram-live-runner.ts index 30dc9db7ed2..a01c3768796 100644 --- a/scripts/e2e/npm-telegram-live-runner.ts +++ b/scripts/e2e/npm-telegram-live-runner.ts @@ -1,5 +1,6 @@ #!/usr/bin/env -S node --import tsx +import fs from "node:fs/promises"; import path from "node:path"; import { runTelegramQaLive } from "../../extensions/qa-lab/src/live-transports/telegram/telegram-live.runtime.ts"; import { formatErrorMessage } from "../../src/infra/errors.ts"; @@ -16,11 +17,36 @@ function splitCsv(value: string | undefined) { .filter((entry) => entry.length > 0); } +async function resolveTrustedOpenClawCommand(rawCommand: string) { + if (!path.isAbsolute(rawCommand)) { + throw new Error("OPENCLAW_NPM_TELEGRAM_SUT_COMMAND must be an absolute path."); + } + const commandName = path.basename(rawCommand); + if (commandName !== "openclaw" && commandName !== "openclaw.cmd") { + throw new Error( + `OPENCLAW_NPM_TELEGRAM_SUT_COMMAND must point to openclaw; got: ${commandName}`, + ); + } + const npmPrefix = process.env.NPM_CONFIG_PREFIX?.trim(); + if (!npmPrefix) { + throw new Error("Missing NPM_CONFIG_PREFIX for installed openclaw command validation."); + } + const [realCommand, realPrefix] = await Promise.all([ + fs.realpath(rawCommand), + fs.realpath(npmPrefix), + ]); + if (realCommand !== realPrefix && !realCommand.startsWith(`${realPrefix}${path.sep}`)) { + throw new Error("OPENCLAW_NPM_TELEGRAM_SUT_COMMAND must resolve inside NPM_CONFIG_PREFIX."); + } + return rawCommand; +} + async function main() { - const sutOpenClawCommand = process.env.OPENCLAW_NPM_TELEGRAM_SUT_COMMAND?.trim(); - if (!sutOpenClawCommand) { + const rawSutOpenClawCommand = process.env.OPENCLAW_NPM_TELEGRAM_SUT_COMMAND?.trim(); + if (!rawSutOpenClawCommand) { throw new Error("Missing OPENCLAW_NPM_TELEGRAM_SUT_COMMAND."); } + const sutOpenClawCommand = await resolveTrustedOpenClawCommand(rawSutOpenClawCommand); const repoRoot = path.resolve(process.env.OPENCLAW_NPM_TELEGRAM_REPO_ROOT ?? process.cwd()); const outputDir =