Files
NetMesh/domain/sftpDirectoryCheckpoint.test.ts
zhaolei 3c72efcb7f
Some checks failed
build-packages / resolve bundled mosh-client (push) Has been cancelled
build-packages / resolve bundled et-client (push) Has been cancelled
build-packages / build-macos (push) Has been cancelled
build-packages / build-windows (push) Has been cancelled
build-packages / build-linux-x64 (push) Has been cancelled
build-packages / build-linux-arm64 (push) Has been cancelled
build-packages / release (push) Has been cancelled
build-packages / update Nix release metadata (push) Has been cancelled
build-packages / bump homebrew tap (push) Has been cancelled
test / lint-and-test (push) Has been cancelled
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
build-et-binaries / build-linux-x64 (push) Has been cancelled
build-et-binaries / build-linux-arm64 (push) Has been cancelled
build-et-binaries / build-macos-universal (push) Has been cancelled
build-et-binaries / build-windows-x64 (push) Has been cancelled
build-et-binaries / release (push) Has been cancelled
[Init] Initial commit - NetMesh terminal manager
2026-09-13 18:24:01 +08:00

126 lines
5.2 KiB
TypeScript

import assert from "node:assert/strict";
import { createHash } from "node:crypto";
import test from "node:test";
import {
accountSftpDirectoryEntries,
appendDirectoryCheckpointIdentity,
appendDirectoryManifestIdentity,
claimSftpDirectoryVisit,
createDirectoryManifestAccumulator,
createEmptyDirectoryResumeCheckpoint,
createSftpDirectoryBranchAncestors,
createSftpDirectoryTraversalBudget,
EMPTY_DIRECTORY_MANIFEST_HASH,
isValidDirectoryResumeCheckpoint,
MAX_SFTP_FOLLOWED_SYMLINK_DEPTH,
releaseSftpDirectoryVisit,
shouldFollowSftpSymlinkDirectory,
} from "./sftpDirectoryCheckpoint";
test("versioned directory manifests detect changed and reordered entries", () => {
const first = "a".repeat(64);
const second = "b".repeat(64);
const changed = "c".repeat(64);
const build = (identities: string[]) => {
const checkpoint = createEmptyDirectoryResumeCheckpoint();
for (const identity of identities) {
checkpoint.manifestHash = appendDirectoryCheckpointIdentity(checkpoint, identity);
checkpoint.coveredEntries += 1;
}
return checkpoint;
};
const original = build([first, second]);
const batched = createDirectoryManifestAccumulator(createEmptyDirectoryResumeCheckpoint());
batched.append(first);
batched.append(second);
assert.equal(original.version, 2);
assert.equal(original.manifestHash, batched.digest());
assert.equal(original.manifestHash, build([first, second]).manifestHash);
assert.notEqual(original.manifestHash, build([first, changed]).manifestHash);
assert.notEqual(original.manifestHash, build([second, first]).manifestHash);
});
test("legacy chained manifests remain valid and append-compatible", () => {
const legacy = {
version: 1 as const,
coveredEntries: 1,
completedEntries: 1,
manifestHash: appendDirectoryManifestIdentity(
EMPTY_DIRECTORY_MANIFEST_HASH,
"a".repeat(64),
),
};
assert.equal(isValidDirectoryResumeCheckpoint(legacy), true);
assert.equal(
legacy.manifestHash,
createHash("sha256")
.update(`${EMPTY_DIRECTORY_MANIFEST_HASH}:${"a".repeat(64)}`)
.digest("hex"),
);
assert.equal(
appendDirectoryCheckpointIdentity(legacy, "b".repeat(64)),
appendDirectoryManifestIdentity(legacy.manifestHash, "b".repeat(64)),
);
});
test("live and resumed directory transfers share the same symlink depth policy", () => {
assert.equal(MAX_SFTP_FOLLOWED_SYMLINK_DEPTH, 32);
assert.equal(shouldFollowSftpSymlinkDirectory(8), true);
assert.equal(shouldFollowSftpSymlinkDirectory(31), true);
assert.equal(shouldFollowSftpSymlinkDirectory(32), false);
});
test("remote directory traversal rejects ancestor cycles but allows sibling aliases", () => {
const budget = createSftpDirectoryTraversalBudget({ maxDirectories: 3, maxEntries: 3 });
const root = claimSftpDirectoryVisit(budget, "/srv/root");
assert.ok(root);
accountSftpDirectoryEntries(budget, 2);
// Re-entering the same canonical path on the current branch is a cycle.
assert.equal(claimSftpDirectoryVisit(budget, "/srv/root"), null);
// Distinct symlink aliases to one target must both be traversed.
const aliasA = claimSftpDirectoryVisit(budget, "/srv/shared");
assert.ok(aliasA);
releaseSftpDirectoryVisit(budget, aliasA);
const aliasB = claimSftpDirectoryVisit(budget, "/srv/shared");
assert.ok(aliasB);
releaseSftpDirectoryVisit(budget, aliasB);
assert.throws(() => accountSftpDirectoryEntries(budget, 2), /entry limit/i);
assert.throws(() => claimSftpDirectoryVisit(budget, "/srv/third"), /directory limit/i);
releaseSftpDirectoryVisit(budget, root);
assert.equal(budget.activeCanonicalDirectories.size, 0);
});
test("parallel sibling branches may both claim the same canonical alias", () => {
const budget = createSftpDirectoryTraversalBudget({ maxDirectories: 8, maxEntries: 8 });
const rootAncestors = createSftpDirectoryBranchAncestors();
const root = claimSftpDirectoryVisit(budget, "/srv/root", rootAncestors);
assert.ok(root);
const branchA = createSftpDirectoryBranchAncestors(rootAncestors);
const branchB = createSftpDirectoryBranchAncestors(rootAncestors);
const aliasA = claimSftpDirectoryVisit(budget, "/srv/shared", branchA);
const aliasB = claimSftpDirectoryVisit(budget, "/srv/shared", branchB);
assert.ok(aliasA);
assert.ok(aliasB);
assert.equal(claimSftpDirectoryVisit(budget, "/srv/root", branchA), null);
assert.equal(claimSftpDirectoryVisit(budget, "/srv/root", branchB), null);
releaseSftpDirectoryVisit(budget, aliasA, branchA);
releaseSftpDirectoryVisit(budget, aliasB, branchB);
releaseSftpDirectoryVisit(budget, root, rootAncestors);
});
test("remote directory traversal releases sibling visits without retaining history", () => {
const budget = createSftpDirectoryTraversalBudget({ maxDirectories: 50_000 });
const root = claimSftpDirectoryVisit(budget, "/srv/root");
assert.ok(root);
for (let index = 1; index < 50_000; index += 1) {
const sibling = claimSftpDirectoryVisit(budget, `/srv/root/alias-${index}`);
assert.ok(sibling);
releaseSftpDirectoryVisit(budget, sibling);
}
assert.equal(budget.activeCanonicalDirectories.size, 1);
releaseSftpDirectoryVisit(budget, root);
assert.equal(budget.activeCanonicalDirectories.size, 0);
});