[codex] Extract filesystem safety primitives (#77918)

* refactor: extract filesystem safety primitives

* refactor: use fs-safe for file access helpers

* refactor: reuse fs-safe for media reads

* refactor: use fs-safe for image reads

* refactor: reuse fs-safe in qqbot media opener

* refactor: reuse fs-safe for local media checks

* refactor: consume cleaner fs-safe api

* refactor: align fs-safe json option names

* fix: preserve fs-safe migration contracts

* refactor: use fs-safe primitive subpaths

* refactor: use grouped fs-safe subpaths

* refactor: align fs-safe api usage

* refactor: adapt private state store api

* chore: refresh proof gate

* refactor: follow fs-safe json api split

* refactor: follow reduced fs-safe surface

* build: default fs-safe python helper off

* fix: preserve fs-safe plugin sdk aliases

* refactor: consolidate fs-safe usage

* refactor: unify fs-safe store usage

* refactor: trim fs-safe temp workspace usage

* refactor: hide low-level fs-safe primitives

* build: use published fs-safe package

* fix: preserve outbound recovery durability after rebase

* chore: refresh pr checks
This commit is contained in:
Peter Steinberger
2026-05-06 02:15:17 +01:00
committed by GitHub
parent 61481eb34f
commit 538605ff44
356 changed files with 4918 additions and 11913 deletions

View File

@@ -9,12 +9,13 @@ import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
import { withFileLock } from "openclaw/plugin-sdk/file-lock";
import {
createSubsystemLogger,
isPathInside,
root,
resolveAgentContextLimits,
resolveMemorySearchSyncConfig,
resolveAgentWorkspaceDir,
resolveGlobalSingleton,
resolveStateDir,
writeFileWithinRoot,
type OpenClawConfig,
} from "openclaw/plugin-sdk/memory-core-host-engine-foundation";
import {
@@ -1302,7 +1303,15 @@ export class QmdMemoryManager implements MemorySearchManager {
if (!absPath.endsWith(".md")) {
throw new Error("path required");
}
const statResult = await statRegularFile(absPath);
let statResult: Awaited<ReturnType<typeof statRegularFile>>;
try {
statResult = await statRegularFile(absPath);
} catch (err) {
if (err instanceof Error && err.message === "path must be a regular file") {
throw new Error("path required", { cause: err });
}
throw err;
}
if (statResult.missing) {
return { text: "", path: relPath };
}
@@ -2203,6 +2212,7 @@ export class QmdMemoryManager implements MemorySearchManager {
}
const exportDir = this.sessionExporter.dir;
await fs.mkdir(exportDir, { recursive: true });
const exportRoot = await root(exportDir);
const files = await listSessionFilesForAgent(this.agentId);
const keep = new Set<string>();
const tracked = new Set<string>();
@@ -2222,10 +2232,7 @@ export class QmdMemoryManager implements MemorySearchManager {
tracked.add(sessionFile);
const state = this.exportedSessionState.get(sessionFile);
if (!state || state.hash !== entry.hash || state.mtimeMs !== entry.mtimeMs) {
await writeFileWithinRoot({
rootDir: exportDir,
relativePath: targetName,
data: this.renderSessionMarkdown(entry),
await exportRoot.write(targetName, this.renderSessionMarkdown(entry), {
encoding: "utf-8",
});
}
@@ -2236,18 +2243,18 @@ export class QmdMemoryManager implements MemorySearchManager {
});
keep.add(target);
}
const exported = await fs.readdir(exportDir).catch(() => []);
const exported = await exportRoot.list(".").catch(() => []);
for (const name of exported) {
if (!name.endsWith(".md")) {
continue;
}
const full = path.join(exportDir, name);
if (!keep.has(full)) {
await fs.rm(full, { force: true });
await exportRoot.remove(name).catch(() => undefined);
}
}
for (const [sessionFile, state] of this.exportedSessionState) {
if (!tracked.has(sessionFile) || !state.target.startsWith(exportDir + path.sep)) {
if (!tracked.has(sessionFile) || !isPathInside(exportDir, state.target)) {
this.exportedSessionState.delete(sessionFile);
}
}
@@ -2788,23 +2795,11 @@ export class QmdMemoryManager implements MemorySearchManager {
}
private isWithinWorkspace(absPath: string): boolean {
const normalizedWorkspace = this.workspaceDir.endsWith(path.sep)
? this.workspaceDir
: `${this.workspaceDir}${path.sep}`;
if (absPath === this.workspaceDir) {
return true;
}
const candidate = absPath.endsWith(path.sep) ? absPath : `${absPath}${path.sep}`;
return candidate.startsWith(normalizedWorkspace);
return isPathInside(this.workspaceDir, absPath);
}
private isWithinRoot(root: string, candidate: string): boolean {
const normalizedRoot = root.endsWith(path.sep) ? root : `${root}${path.sep}`;
if (candidate === root) {
return true;
}
const next = candidate.endsWith(path.sep) ? candidate : `${candidate}${path.sep}`;
return next.startsWith(normalizedRoot);
return isPathInside(root, candidate);
}
private clampResultsByInjectedChars(results: MemorySearchResult[]): MemorySearchResult[] {