[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

@@ -3,6 +3,7 @@ import path from "node:path";
import process from "node:process";
import { resolveStateDir } from "../config/paths.js";
import { registerFatalErrorHook } from "../infra/fatal-error-hooks.js";
import { replaceFileAtomicSync } from "../infra/replace-file.js";
import {
getDiagnosticStabilitySnapshot,
MAX_DIAGNOSTIC_STABILITY_LIMIT,
@@ -640,14 +641,14 @@ export function writeDiagnosticStabilityBundleSync(
};
const dir = resolveDiagnosticStabilityBundleDir(options);
fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
const file = buildBundlePath(dir, now, reason);
const tmpFile = `${file}.${process.pid}.tmp`;
fs.writeFileSync(tmpFile, `${JSON.stringify(bundle, null, 2)}\n`, {
encoding: "utf8",
replaceFileAtomicSync({
filePath: file,
content: `${JSON.stringify(bundle, null, 2)}\n`,
dirMode: 0o700,
mode: 0o600,
tempPrefix: ".openclaw-stability",
});
fs.renameSync(tmpFile, file);
pruneOldBundles(dir, options.retention ?? DEFAULT_DIAGNOSTIC_STABILITY_BUNDLE_RETENTION);
return { status: "written", path: file, bundle };
} catch (error) {

View File

@@ -1,5 +1,6 @@
import fsp from "node:fs/promises";
import path from "node:path";
import { isPathInside } from "../infra/path-guards.js";
export type DiagnosticSupportBundleFile = {
path: string;
@@ -81,8 +82,7 @@ function resolveSupportBundleFilePath(outputDir: string, pathName: string): stri
const safePath = assertSafeBundleRelativePath(pathName);
const resolvedBase = path.resolve(outputDir);
const resolvedFile = path.resolve(resolvedBase, safePath);
const relative = path.relative(resolvedBase, resolvedFile);
if (!relative || relative.startsWith("..") || path.isAbsolute(relative)) {
if (resolvedFile === resolvedBase || !isPathInside(resolvedBase, resolvedFile)) {
throw new Error(`Bundle file path escaped output directory: ${pathName}`);
}
return resolvedFile;

View File

@@ -13,6 +13,7 @@ import {
} from "../infra/diagnostic-trace-context.js";
import { expandHomePrefix } from "../infra/home-dir.js";
import { isBlockedObjectKey } from "../infra/prototype-keys.js";
import { appendRegularFileSync } from "../infra/regular-file.js";
import {
POSIX_OPENCLAW_TMP_DIR,
resolvePreferredOpenClawTmpDir,
@@ -597,7 +598,7 @@ function getCurrentLogFileBytes(file: string): number {
function appendLogLine(file: string, line: string): boolean {
try {
fs.appendFileSync(file, line, { encoding: "utf8" });
appendRegularFileSync({ filePath: file, content: line });
return true;
} catch {
return false;