* Doctor state: warn on Linux SD or eMMC state mounts * Doctor tests: cover Linux SD or eMMC state mount detection * Docs doctor: document Linux SD or eMMC state warning * Changelog: add Linux SD or eMMC doctor warning * Update CHANGELOG.md * Doctor: escape mountinfo control chars in SD warning * Doctor tests: cover escaped mountinfo control chars
126 lines
3.7 KiB
TypeScript
126 lines
3.7 KiB
TypeScript
import path from "node:path";
|
|
import { describe, expect, it } from "vitest";
|
|
import {
|
|
detectLinuxSdBackedStateDir,
|
|
formatLinuxSdBackedStateDirWarning,
|
|
} from "./doctor-state-integrity.js";
|
|
|
|
function encodeMountInfoPath(value: string): string {
|
|
return value
|
|
.replace(/\\/g, "\\134")
|
|
.replace(/\n/g, "\\012")
|
|
.replace(/\t/g, "\\011")
|
|
.replace(/ /g, "\\040");
|
|
}
|
|
|
|
describe("detectLinuxSdBackedStateDir", () => {
|
|
it("detects state dir on mmc-backed mount", () => {
|
|
const mountInfo = [
|
|
"24 19 179:2 / / rw,relatime - ext4 /dev/mmcblk0p2 rw",
|
|
"25 24 0:22 / /proc rw,nosuid,nodev,noexec,relatime - proc proc rw",
|
|
].join("\n");
|
|
|
|
const result = detectLinuxSdBackedStateDir("/home/pi/.openclaw", {
|
|
platform: "linux",
|
|
mountInfo,
|
|
});
|
|
|
|
expect(result).toEqual({
|
|
path: "/home/pi/.openclaw",
|
|
mountPoint: "/",
|
|
fsType: "ext4",
|
|
source: "/dev/mmcblk0p2",
|
|
});
|
|
});
|
|
|
|
it("returns null for non-mmc devices", () => {
|
|
const mountInfo = "24 19 259:2 / / rw,relatime - ext4 /dev/nvme0n1p2 rw";
|
|
|
|
const result = detectLinuxSdBackedStateDir("/home/user/.openclaw", {
|
|
platform: "linux",
|
|
mountInfo,
|
|
});
|
|
|
|
expect(result).toBeNull();
|
|
});
|
|
|
|
it("resolves /dev/disk aliases to mmc devices", () => {
|
|
const mountInfo = "24 19 179:2 / / rw,relatime - ext4 /dev/disk/by-uuid/abcd-1234 rw";
|
|
|
|
const result = detectLinuxSdBackedStateDir("/home/user/.openclaw", {
|
|
platform: "linux",
|
|
mountInfo,
|
|
resolveDeviceRealPath: (devicePath) => {
|
|
if (devicePath === "/dev/disk/by-uuid/abcd-1234") {
|
|
return "/dev/mmcblk0p2";
|
|
}
|
|
return null;
|
|
},
|
|
});
|
|
|
|
expect(result).toEqual({
|
|
path: "/home/user/.openclaw",
|
|
mountPoint: "/",
|
|
fsType: "ext4",
|
|
source: "/dev/disk/by-uuid/abcd-1234",
|
|
});
|
|
});
|
|
|
|
it("uses resolved state path to select mount", () => {
|
|
const mountInfo = [
|
|
"24 19 259:2 / / rw,relatime - ext4 /dev/nvme0n1p2 rw",
|
|
"30 24 179:5 / /mnt/slow rw,relatime - ext4 /dev/mmcblk1p1 rw",
|
|
].join("\n");
|
|
|
|
const result = detectLinuxSdBackedStateDir("/tmp/openclaw-state", {
|
|
platform: "linux",
|
|
mountInfo,
|
|
resolveRealPath: () => "/mnt/slow/openclaw/.openclaw",
|
|
});
|
|
|
|
expect(result).toEqual({
|
|
path: "/mnt/slow/openclaw/.openclaw",
|
|
mountPoint: "/mnt/slow",
|
|
fsType: "ext4",
|
|
source: "/dev/mmcblk1p1",
|
|
});
|
|
});
|
|
|
|
it("returns null outside linux", () => {
|
|
const mountInfo = "24 19 179:2 / / rw,relatime - ext4 /dev/mmcblk0p2 rw";
|
|
|
|
const result = detectLinuxSdBackedStateDir(path.join("/Users", "tester", ".openclaw"), {
|
|
platform: "darwin",
|
|
mountInfo,
|
|
});
|
|
|
|
expect(result).toBeNull();
|
|
});
|
|
|
|
it("escapes decoded mountinfo control characters in warning output", () => {
|
|
const mountRoot = "/home/pi/mnt\nspoofed";
|
|
const stateDir = `${mountRoot}/.openclaw`;
|
|
const encodedSource = "/dev/disk/by-uuid/mmc\\012source";
|
|
const mountInfo = `30 24 179:2 / ${encodeMountInfoPath(mountRoot)} rw,relatime - ext4 ${encodedSource} rw`;
|
|
|
|
const result = detectLinuxSdBackedStateDir(stateDir, {
|
|
platform: "linux",
|
|
mountInfo,
|
|
resolveRealPath: () => stateDir,
|
|
resolveDeviceRealPath: (devicePath) => {
|
|
if (devicePath === "/dev/disk/by-uuid/mmc\nsource") {
|
|
return "/dev/mmcblk0p2";
|
|
}
|
|
return null;
|
|
},
|
|
});
|
|
|
|
expect(result).not.toBeNull();
|
|
const warning = formatLinuxSdBackedStateDirWarning(stateDir, result!);
|
|
expect(warning).toContain("device /dev/disk/by-uuid/mmc\\nsource");
|
|
expect(warning).toContain("mount /home/pi/mnt\\nspoofed");
|
|
expect(warning).not.toContain("device /dev/disk/by-uuid/mmc\nsource");
|
|
expect(warning).not.toContain("mount /home/pi/mnt\nspoofed");
|
|
});
|
|
});
|