fix(webui): exclude *.tmp files from backup archives

Spec 2026-08-11-system-config-design section 6 requires the backup tar
to exclude both backups/ itself and *.tmp files; only the backups/
exclusion was implemented. Adds a <base>/*.tmp exclusion for the webui
data dir and the configured backend data dir, mirroring the existing
top-level exclusion style. Excludes are emitted before any -C operand
so bsdtar does not treat them as member operands.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
m4
2026-08-11 10:49:29 +08:00
parent 72dedba64e
commit 6b009e2c32
2 changed files with 23 additions and 1 deletions
+18
View File
@@ -50,6 +50,24 @@ describe("backup", () => {
expect(listing).not.toContain("stale.txt");
});
it("excludes *.tmp files from the archive", async () => {
fs.writeFileSync(path.join(dataDir, "scratch.tmp"), "tmp");
fs.writeFileSync(path.join(dataDir, "keep.json"), "{}");
fs.writeFileSync(path.join(backendDir, "session.tmp"), "tmp");
fs.writeFileSync(path.join(backendDir, "notes.md"), "notes");
const entry = await backup.createBackup("manual");
const listing = execFileSync("tar", [
"-tzf",
path.join(backup.backupsDir(), entry.name),
]).toString();
expect(listing).toContain("keep.json");
expect(listing).toContain("notes.md");
expect(listing).not.toContain("scratch.tmp");
expect(listing).not.toContain("session.tmp");
});
it("validates names and rejects traversal", () => {
expect(backup.isValidBackupName("backup-20260811T073000-auto.tar.gz")).toBe(true);
expect(backup.isValidBackupName("../etc/passwd")).toBe(false);
+5 -1
View File
@@ -67,13 +67,17 @@ async function runBackup(origin: "manual" | "auto"): Promise<BackupEntry> {
const args = [
"-czf", out,
"--exclude", `${base}/backups`,
"-C", path.dirname(dataDir), base,
"--exclude", `${base}/*.tmp`,
];
const backend = config.backup.backendDataDir.trim();
if (backend) {
if (!fs.existsSync(backend)) {
throw new Error(`Backend data directory does not exist: ${backend}`);
}
args.push("--exclude", `${path.basename(backend)}/*.tmp`);
}
args.push("-C", path.dirname(dataDir), base);
if (backend) {
args.push("-C", path.dirname(backend), path.basename(backend));
}
try {