test: preserve windows backup-rotation compose coverage (#32286) (thanks @jalehman)
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user