test: preserve windows backup-rotation compose coverage (#32286) (thanks @jalehman)

This commit is contained in:
Peter Steinberger
2026-03-02 23:37:57 +00:00
parent 41bdf2df41
commit abec8a4f0a
2 changed files with 26 additions and 26 deletions

View File

@@ -67,6 +67,7 @@ Docs: https://docs.openclaw.ai
- Config/raw redaction safety: preserve non-sensitive literals during raw redaction round-trips, scope SecretRef redaction to secret IDs (not structural fields like `source`/`provider`), and fall back to structured raw redaction when text replacement cannot restore the original config shape. (#32174) Thanks @bmendonca3.
- Models/Codex usage labels: infer weekly secondary usage windows from reset cadence when API window seconds are ambiguously reported as 24h, so `openclaw models status` no longer mislabels weekly limits as daily. (#31938) Thanks @bmendonca3.
- Config/backups hardening: enforce owner-only (`0600`) permissions on rotated config backups and clean orphan `.bak.*` files outside the managed backup ring, reducing credential leakage risk from stale or permissive backup artifacts. (#31718) Thanks @YUJIE2002.
- Tests/Windows backup rotation: skip chmod-only backup permission assertions on Windows while retaining compose/rotation/prune coverage across platforms to avoid false CI failures from Windows non-POSIX mode semantics. (#32286) Thanks @jalehman.
- WhatsApp/inbound self-message context: propagate inbound `fromMe` through the web inbox pipeline and annotate direct self messages as `(self)` in envelopes so agents can distinguish owner-authored turns from contact turns. (#32167) Thanks @scoootscooob.
- Webchat/silent token leak: filter assistant `NO_REPLY`-only transcript entries from `chat.history` responses and add client-side defense-in-depth guards in the chat controller so internal silent tokens never render as visible chat bubbles. (#32015) Consolidates overlap from #32183, #32082, #32045, #32052, #32172, and #32112. Thanks @ademczuk, @liuxiaopai-ai, @ningding97, @bmendonca3, and @x4v13r1120.
- Exec approvals/allowlist matching: escape regex metacharacters in path-pattern literals (while preserving glob wildcards), preventing crashes on allowlisted executables like `/usr/bin/g++` and correctly matching mixed wildcard/literal token paths. (#32162) Thanks @stakeswky.

View File

@@ -116,34 +116,33 @@ describe("config backup rotation", () => {
});
});
// chmod is a no-op on Windows — permission assertions will always fail.
it.skipIf(IS_WINDOWS)(
"maintainConfigBackups composes rotate/copy/harden/prune flow",
async () => {
await withTempHome(async () => {
const stateDir = process.env.OPENCLAW_STATE_DIR?.trim();
if (!stateDir) {
throw new Error("Expected OPENCLAW_STATE_DIR to be set by withTempHome");
}
const configPath = path.join(stateDir, "openclaw.json");
await fs.writeFile(configPath, JSON.stringify({ token: "secret" }), { mode: 0o600 });
await fs.writeFile(`${configPath}.bak`, "previous", { mode: 0o644 });
await fs.writeFile(`${configPath}.bak.orphan`, "old");
it("maintainConfigBackups composes rotate/copy/harden/prune flow", async () => {
await withTempHome(async () => {
const stateDir = process.env.OPENCLAW_STATE_DIR?.trim();
if (!stateDir) {
throw new Error("Expected OPENCLAW_STATE_DIR to be set by withTempHome");
}
const configPath = path.join(stateDir, "openclaw.json");
await fs.writeFile(configPath, JSON.stringify({ token: "secret" }), { mode: 0o600 });
await fs.writeFile(`${configPath}.bak`, "previous", { mode: 0o644 });
await fs.writeFile(`${configPath}.bak.orphan`, "old");
await maintainConfigBackups(configPath, fs);
await maintainConfigBackups(configPath, fs);
// A new primary backup is created from the current config.
await expect(fs.readFile(`${configPath}.bak`, "utf-8")).resolves.toBe(
JSON.stringify({ token: "secret" }),
);
// Prior primary backup gets rotated into ring slot 1.
await expect(fs.readFile(`${configPath}.bak.1`, "utf-8")).resolves.toBe("previous");
// Mode hardening still applies.
// A new primary backup is created from the current config.
await expect(fs.readFile(`${configPath}.bak`, "utf-8")).resolves.toBe(
JSON.stringify({ token: "secret" }),
);
// Prior primary backup gets rotated into ring slot 1.
await expect(fs.readFile(`${configPath}.bak.1`, "utf-8")).resolves.toBe("previous");
// Windows cannot validate POSIX chmod bits, but all other compose assertions
// should still run there.
if (!IS_WINDOWS) {
const primaryBackupStat = await fs.stat(`${configPath}.bak`);
expect(primaryBackupStat.mode & 0o777).toBe(0o600);
// Out-of-ring orphan gets pruned.
await expect(fs.stat(`${configPath}.bak.orphan`)).rejects.toThrow();
});
},
);
}
// Out-of-ring orphan gets pruned.
await expect(fs.stat(`${configPath}.bak.orphan`)).rejects.toThrow();
});
});
});