mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-28 05:16:23 -06:00
refactor(infra): trim dead archive facade exports
This commit is contained in:
@@ -1,17 +1,6 @@
|
||||
// Covers archive entry path normalization and traversal rejection.
|
||||
import path from "node:path";
|
||||
// Covers the archive-path facade used by runtime path classification.
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
isWindowsDrivePath,
|
||||
normalizeArchiveEntryPath,
|
||||
resolveArchiveOutputPath,
|
||||
stripArchivePath,
|
||||
validateArchiveEntryPath,
|
||||
} from "./archive-path.js";
|
||||
|
||||
function expectArchivePathError(run: () => void, message: string) {
|
||||
expect(run).toThrow(message);
|
||||
}
|
||||
import { isWindowsDrivePath } from "./archive-path.js";
|
||||
|
||||
describe("archive path helpers", () => {
|
||||
it.each([
|
||||
@@ -22,108 +11,4 @@ describe("archive path helpers", () => {
|
||||
])("detects Windows drive paths for %j", ({ value, expected }) => {
|
||||
expect(isWindowsDrivePath(value)).toBe(expected);
|
||||
});
|
||||
|
||||
it.each([
|
||||
{ raw: "dir\\file.txt", expected: "dir/file.txt" },
|
||||
{ raw: "dir/file.txt", expected: "dir/file.txt" },
|
||||
])("normalizes archive separators for %j", ({ raw, expected }) => {
|
||||
expect(normalizeArchiveEntryPath(raw)).toBe(expected);
|
||||
});
|
||||
|
||||
it.each(["", ".", "./"])("accepts empty-like entry paths: %j", (entryPath) => {
|
||||
expect(validateArchiveEntryPath(entryPath)).toBeUndefined();
|
||||
});
|
||||
|
||||
it.each([
|
||||
{
|
||||
name: "uses custom escape labels in traversal errors",
|
||||
entryPath: "../escape.txt",
|
||||
message: "archive entry escapes targetDir: ../escape.txt",
|
||||
},
|
||||
{
|
||||
name: "rejects Windows drive paths",
|
||||
entryPath: "C:\\temp\\file.txt",
|
||||
message: "archive entry uses a drive path: C:\\temp\\file.txt",
|
||||
},
|
||||
{
|
||||
name: "rejects absolute paths after normalization",
|
||||
entryPath: "/tmp/file.txt",
|
||||
message: "archive entry is absolute: /tmp/file.txt",
|
||||
},
|
||||
{
|
||||
name: "rejects double-slash absolute paths after normalization",
|
||||
entryPath: "\\\\server\\share.txt",
|
||||
message: "archive entry is absolute: \\\\server\\share.txt",
|
||||
},
|
||||
])("$name", ({ entryPath, message }) => {
|
||||
expectArchivePathError(
|
||||
() =>
|
||||
validateArchiveEntryPath(entryPath, {
|
||||
escapeLabel: "targetDir",
|
||||
}),
|
||||
message,
|
||||
);
|
||||
});
|
||||
|
||||
it.each([
|
||||
{ entryPath: "a/../escape.txt", stripComponents: 1, expected: "../escape.txt" },
|
||||
{ entryPath: "a//b/file.txt", stripComponents: 1, expected: "b/file.txt" },
|
||||
{ entryPath: "./", stripComponents: 0, expected: null },
|
||||
{ entryPath: "a", stripComponents: 3, expected: null },
|
||||
{ entryPath: "dir\\sub\\file.txt", stripComponents: 1, expected: "sub/file.txt" },
|
||||
])("strips archive paths for %j", ({ entryPath, stripComponents, expected }) => {
|
||||
expect(stripArchivePath(entryPath, stripComponents)).toBe(expected);
|
||||
});
|
||||
|
||||
it("preserves strip-induced traversal for follow-up validation", () => {
|
||||
const stripped = stripArchivePath("a/../escape.txt", 1);
|
||||
expect(stripped).toBe("../escape.txt");
|
||||
expectArchivePathError(
|
||||
() =>
|
||||
validateArchiveEntryPath(stripped ?? "", {
|
||||
escapeLabel: "targetDir",
|
||||
}),
|
||||
"archive entry escapes targetDir: ../escape.txt",
|
||||
);
|
||||
});
|
||||
|
||||
const rootDir = path.join(path.sep, "tmp", "archive-root");
|
||||
|
||||
it.each([
|
||||
{
|
||||
name: "keeps resolved output paths inside the root",
|
||||
relPath: "sub/file.txt",
|
||||
originalPath: "sub/file.txt",
|
||||
expected: path.resolve(rootDir, "sub/file.txt"),
|
||||
},
|
||||
{
|
||||
name: "rejects output paths that escape the root",
|
||||
relPath: "../escape.txt",
|
||||
originalPath: "../escape.txt",
|
||||
escapeLabel: "targetDir",
|
||||
message: "archive entry escapes targetDir: ../escape.txt",
|
||||
},
|
||||
])("$name", ({ relPath, originalPath, escapeLabel, expected, message }) => {
|
||||
if (message) {
|
||||
expectArchivePathError(
|
||||
() =>
|
||||
resolveArchiveOutputPath({
|
||||
rootDir,
|
||||
relPath,
|
||||
originalPath,
|
||||
escapeLabel,
|
||||
}),
|
||||
message,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
expect(
|
||||
resolveArchiveOutputPath({
|
||||
rootDir,
|
||||
relPath,
|
||||
originalPath,
|
||||
}),
|
||||
).toBe(expected);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -4,8 +4,4 @@ import "./fs-safe-defaults.js";
|
||||
// Archive path facade kept in infra so callers share one traversal policy.
|
||||
export {
|
||||
isWindowsDrivePath,
|
||||
normalizeArchiveEntryPath,
|
||||
resolveArchiveOutputPath,
|
||||
stripArchivePath,
|
||||
validateArchiveEntryPath,
|
||||
} from "@openclaw/fs-safe/archive";
|
||||
|
||||
@@ -10,13 +10,11 @@ export {
|
||||
DEFAULT_MAX_ENTRIES,
|
||||
DEFAULT_MAX_EXTRACTED_BYTES,
|
||||
DEFAULT_MAX_ENTRY_BYTES,
|
||||
createArchiveSymlinkTraversalError,
|
||||
createTarEntryPreflightChecker,
|
||||
extractArchive,
|
||||
loadZipArchiveWithPreflight,
|
||||
mergeExtractedTreeIntoDestination,
|
||||
prepareArchiveDestinationDir,
|
||||
prepareArchiveOutputPath,
|
||||
readZipCentralDirectoryEntryCount,
|
||||
resolveArchiveKind,
|
||||
resolvePackedRootDir,
|
||||
|
||||
Reference in New Issue
Block a user