|
1 | 1 | // Qa Lab plugin module implements generic QA evidence gallery data. |
2 | 2 | import fs from "node:fs/promises"; |
| 3 | +import os from "node:os"; |
3 | 4 | import path from "node:path"; |
| 5 | +import { pathToFileURL } from "node:url"; |
4 | 6 | import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime"; |
5 | 7 | import type { |
6 | 8 | QaEvidenceArtifactView, |
@@ -61,6 +63,27 @@ function isInside(root: string, candidate: string) {
|
61 | 63 | return relative === "" || (!relative.startsWith("..") && !path.isAbsolute(relative)); |
62 | 64 | } |
63 | 65 | |
| 66 | +function sanitizeGalleryText( |
| 67 | +value: string, |
| 68 | +params: { |
| 69 | +extraRoots?: readonly string[]; |
| 70 | +repoRoot: string; |
| 71 | +}, |
| 72 | +) { |
| 73 | +const localRoots = [...new Set([params.repoRoot, ...(params.extraRoots ?? [])])]; |
| 74 | +const roots = [ |
| 75 | + ...localRoots.flatMap((root) => [ |
| 76 | +{ from: path.resolve(root), to: "<repo-root>" }, |
| 77 | +{ from: pathToFileURL(path.resolve(root)).href, to: "file://<repo-root>" }, |
| 78 | +]), |
| 79 | +{ from: os.homedir(), to: "<home>" }, |
| 80 | +{ from: pathToFileURL(os.homedir()).href, to: "file://<home>" }, |
| 81 | +].filter((entry) => entry.from && entry.from !== path.parse(entry.from).root); |
| 82 | +return roots |
| 83 | +.toSorted((a, b) => b.from.length - a.from.length) |
| 84 | +.reduce((text, entry) => text.replaceAll(entry.from, entry.to), value); |
| 85 | +} |
| 86 | + |
64 | 87 | async function realpathIfExists(filePath: string): Promise<string | null> { |
65 | 88 | return fs.realpath(filePath).catch(() => null); |
66 | 89 | } |
@@ -642,7 +665,8 @@ export async function buildQaEvidenceGalleryModel(params: {
|
642 | 665 | evidencePath: string; |
643 | 666 | repoRoot: string; |
644 | 667 | }): Promise<QaEvidenceGalleryModel> { |
645 | | -const repoRoot = await fs.realpath(path.resolve(params.repoRoot)); |
| 668 | +const requestedRepoRoot = path.resolve(params.repoRoot); |
| 669 | +const repoRoot = await fs.realpath(requestedRepoRoot); |
646 | 670 | const evidencePath = await resolveQaEvidenceFile({ |
647 | 671 | inputPath: params.evidencePath, |
648 | 672 | repoRoot, |
@@ -684,7 +708,12 @@ export async function buildQaEvidenceGalleryModel(params: {
|
684 | 708 | ), |
685 | 709 | ), |
686 | 710 | coverage: entry.coverage, |
687 | | -failureReason: entry.result.failure?.reason ?? null, |
| 711 | +failureReason: entry.result.failure?.reason |
| 712 | + ? sanitizeGalleryText(entry.result.failure.reason, { |
| 713 | +extraRoots: [requestedRepoRoot], |
| 714 | + repoRoot, |
| 715 | +}) |
| 716 | + : null, |
688 | 717 | id: entry.test.id, |
689 | 718 | kind: entry.test.kind, |
690 | 719 | sourcePath: entry.test.source?.path ?? null, |
|