From 32cbaecd0965166e2ec2051383c2c4d3190c03d5 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Sat, 20 Jun 2026 18:47:02 +0200 Subject: [PATCH] fix(telegram): stage full proof artifacts safely --- scripts/e2e/telegram-user-crabbox-proof.ts | 31 ++++++++++++++++- .../telegram-user-crabbox-proof.test.ts | 34 +++++++++++++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/scripts/e2e/telegram-user-crabbox-proof.ts b/scripts/e2e/telegram-user-crabbox-proof.ts index 196655013f28..1e9398dfa561 100644 --- a/scripts/e2e/telegram-user-crabbox-proof.ts +++ b/scripts/e2e/telegram-user-crabbox-proof.ts @@ -1930,6 +1930,35 @@ function writeSession(pathname: string, session: SessionFile) { fs.chmodSync(pathname, 0o600); } +const FULL_ARTIFACT_JSON_NAMES = new Set([ + "probe.json", + "status.json", + "telegram-user-crabbox-proof-summary.json", + "telegram-user-crabbox-session-summary.json", +]); +const FULL_ARTIFACT_FILE_EXTENSIONS = new Set([".gif", ".log", ".md", ".mp4", ".png"]); + +export function stageFullSessionArtifacts(outputDir: string) { + const publishDir = path.join(outputDir, "publish-full-artifacts"); + fs.rmSync(publishDir, { force: true, recursive: true }); + fs.mkdirSync(publishDir, { recursive: true }); + + for (const entry of fs.readdirSync(outputDir, { withFileTypes: true })) { + if (!entry.isFile()) { + continue; + } + const extension = path.extname(entry.name); + const isPublishableArtifact = + FULL_ARTIFACT_FILE_EXTENSIONS.has(extension) || FULL_ARTIFACT_JSON_NAMES.has(entry.name); + if (!isPublishableArtifact) { + continue; + } + fs.copyFileSync(path.join(outputDir, entry.name), path.join(publishDir, entry.name)); + } + + return publishDir; +} + function readSession(root: string, opts: Options, outputDir: string) { const pathname = sessionPath(root, opts, outputDir); if (!fs.existsSync(pathname)) { @@ -2462,7 +2491,7 @@ async function publishSessionArtifacts(root: string, opts: Options, outputDir: s ); const publishGifPath = fs.existsSync(croppedMotionGifPath) ? croppedMotionGifPath : motionGifPath; const publishDir = opts.publishFullArtifacts - ? session.outputDir + ? stageFullSessionArtifacts(session.outputDir) : path.join(session.outputDir, "publish-gif-only"); if (!opts.publishFullArtifacts) { if (!fs.existsSync(publishGifPath)) { diff --git a/test/scripts/telegram-user-crabbox-proof.test.ts b/test/scripts/telegram-user-crabbox-proof.test.ts index 6df17abcf07e..f84869d1592f 100644 --- a/test/scripts/telegram-user-crabbox-proof.test.ts +++ b/test/scripts/telegram-user-crabbox-proof.test.ts @@ -18,6 +18,7 @@ import { renderRemoteSetup, renderSelectDesktopChat, runCommand, + stageFullSessionArtifacts, startLocalSut, waitForLog, } from "../../scripts/e2e/telegram-user-crabbox-proof.ts"; @@ -210,6 +211,39 @@ describe("telegram user Crabbox proof log polling", () => { expect(renderSelectDesktopChat({ chatTitle: payload })).toContain(`chat_title='${payload}'`); }); + it("stages full publish artifacts without session control files", () => { + const outputDir = makeTempDir(); + const publishDir = path.join(outputDir, "publish-full-artifacts"); + fs.mkdirSync(publishDir); + fs.writeFileSync(path.join(publishDir, "stale.txt"), "stale"); + fs.mkdirSync(path.join(outputDir, "publish-gif-only")); + fs.writeFileSync(path.join(outputDir, "session.json"), '{"sshKey":"/private/tmp/openclaw/key"}'); + fs.writeFileSync(path.join(outputDir, "lease.json"), '{"token":"secret"}'); + fs.writeFileSync(path.join(outputDir, "status.json"), '{"ok":true}'); + fs.writeFileSync(path.join(outputDir, "probe.json"), '{"ok":true}'); + fs.writeFileSync(path.join(outputDir, "telegram-user-crabbox-session-summary.json"), "{}"); + fs.writeFileSync(path.join(outputDir, "telegram-user-crabbox-proof.md"), "report"); + fs.writeFileSync(path.join(outputDir, "telegram-desktop.log"), "log"); + fs.writeFileSync(path.join(outputDir, "telegram-user-crabbox-session-motion.gif"), "gif"); + fs.writeFileSync(path.join(outputDir, "telegram-user-crabbox-session.mp4"), "video"); + + const stagedDir = stageFullSessionArtifacts(outputDir); + + expect(stagedDir).toBe(publishDir); + expect(fs.readdirSync(stagedDir).sort()).toEqual([ + "probe.json", + "status.json", + "telegram-desktop.log", + "telegram-user-crabbox-proof.md", + "telegram-user-crabbox-session-motion.gif", + "telegram-user-crabbox-session-summary.json", + "telegram-user-crabbox-session.mp4", + ]); + expect(fs.existsSync(path.join(stagedDir, "session.json"))).toBe(false); + expect(fs.existsSync(path.join(stagedDir, "lease.json"))).toBe(false); + expect(fs.existsSync(path.join(stagedDir, "stale.txt"))).toBe(false); + }); + posixIt("does not expand generated remote probe arguments in the shell", () => { const root = makeTempDir(); const fakePython = path.join(root, "python3");