[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

@@ -28,6 +28,7 @@ import os from "node:os";
import path from "node:path";
import { resolveStateDir } from "../../../config/paths.js";
import { formatErrorMessage } from "../../../infra/errors.js";
import { appendRegularFile } from "../../../infra/fs-safe.js";
import { createSubsystemLogger } from "../../../logging/subsystem.js";
import type { HookHandler } from "../../hooks.js";
@@ -59,7 +60,11 @@ const logCommand: HookHandler = async (event) => {
source: event.context.commandSource ?? "unknown",
}) + "\n";
await fs.appendFile(logFile, logLine, "utf-8");
await appendRegularFile({
filePath: logFile,
content: logLine,
rejectSymlinkParents: true,
});
} catch (err) {
const message = formatErrorMessage(err);
log.error(`Failed to log command: ${message}`);

View File

@@ -14,7 +14,7 @@ import {
} from "../../../agents/agent-scope.js";
import { resolveStateDir } from "../../../config/paths.js";
import type { OpenClawConfig } from "../../../config/types.openclaw.js";
import { writeFileWithinRoot } from "../../../infra/fs-safe.js";
import { root } from "../../../infra/fs-safe.js";
import { createSubsystemLogger } from "../../../logging/subsystem.js";
import {
parseAgentSessionKey,
@@ -277,12 +277,8 @@ async function saveSessionMemoryNow(event: Parameters<HookHandler>[0]): Promise<
const entry = entryParts.join("\n");
// Write under memory root with alias-safe file validation.
await writeFileWithinRoot({
rootDir: memoryDir,
relativePath: filename,
data: entry,
encoding: "utf-8",
});
const memoryRoot = await root(memoryDir);
await memoryRoot.write(filename, entry, { encoding: "utf-8" });
log.debug("Memory file written successfully");
// Log completion (but don't send user-visible confirmation - it's internal housekeeping)

View File

@@ -1,4 +1,5 @@
import { fileExists, readJsonFile, resolveArchiveKind } from "../infra/archive.js";
import { resolveArchiveKind } from "../infra/archive.js";
import { pathExists } from "../infra/fs-safe.js";
import { resolveExistingInstallPath, withExtractedArchiveRoot } from "../infra/install-flow.js";
import { installFromValidatedNpmSpecArchive } from "../infra/install-from-npm-spec.js";
import {
@@ -18,19 +19,20 @@ import {
ensureInstallTargetAvailable,
resolveCanonicalInstallTarget,
} from "../infra/install-target.js";
import { readJson } from "../infra/json-files.js";
import { isPathInside, isPathInsideWithRealpath } from "../security/scan-paths.js";
export type { NpmIntegrityDrift, NpmSpecResolution };
export {
ensureInstallTargetAvailable,
fileExists,
pathExists as fileExists,
installFromValidatedNpmSpecArchive,
installPackageDir,
installPackageDirWithManifestDeps,
isPathInside,
isPathInsideWithRealpath,
readJsonFile,
readJson as readJsonFile,
resolveArchiveKind,
resolveArchiveSourcePath,
resolveCanonicalInstallTarget,

View File

@@ -8,7 +8,7 @@
import fs from "node:fs";
import path from "node:path";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import { openBoundaryFile } from "../infra/boundary-file-read.js";
import { openRootFile } from "../infra/boundary-file-read.js";
import { formatErrorMessage } from "../infra/errors.js";
import { createSubsystemLogger } from "../logging/subsystem.js";
import { resolveGlobalSingleton } from "../shared/global-singleton.js";
@@ -119,7 +119,7 @@ export async function loadInternalHooks(
);
continue;
}
const opened = await openBoundaryFile({
const opened = await openRootFile({
absolutePath: entry.hook.handlerPath,
rootPath: hookBaseDir,
boundaryLabel: "hook directory",
@@ -215,7 +215,7 @@ export async function loadInternalHooks(
log.error(`Handler module path must stay within workspaceDir: ${safeLogValue(rawModule)}`);
continue;
}
const opened = await openBoundaryFile({
const opened = await openRootFile({
absolutePath: modulePathSafe,
rootPath: baseDirReal,
boundaryLabel: "workspace directory",

View File

@@ -2,7 +2,7 @@ import fs from "node:fs";
import path from "node:path";
import { MANIFEST_KEY } from "../compat/legacy-names.js";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import { openBoundaryFileSync } from "../infra/boundary-file-read.js";
import { openRootFileSync } from "../infra/boundary-file-read.js";
import { createSubsystemLogger } from "../logging/subsystem.js";
import { isPathInsideWithRealpath } from "../security/scan-paths.js";
import { CONFIG_DIR, resolveUserPath } from "../utils.js";
@@ -28,7 +28,7 @@ type LoadedHook = {
function readHookPackageManifest(dir: string): HookPackageManifest | null {
const manifestPath = path.join(dir, "package.json");
const raw = readBoundaryFileUtf8({
const raw = readRootFileUtf8({
absolutePath: manifestPath,
rootPath: dir,
boundaryLabel: "hook package directory",
@@ -71,7 +71,7 @@ function loadHookFromDir(params: {
nameHint?: string;
}): LoadedHook | null {
const hookMdPath = path.join(params.hookDir, "HOOK.md");
const content = readBoundaryFileUtf8({
const content = readRootFileUtf8({
absolutePath: hookMdPath,
rootPath: params.hookDir,
boundaryLabel: "hook directory",
@@ -89,7 +89,7 @@ function loadHookFromDir(params: {
let handlerPath: string | undefined;
for (const candidate of handlerCandidates) {
const candidatePath = path.join(params.hookDir, candidate);
const safeCandidatePath = resolveBoundaryFilePath({
const safeCandidatePath = resolveRootFilePath({
absolutePath: candidatePath,
rootPath: params.hookDir,
boundaryLabel: "hook directory",
@@ -293,12 +293,12 @@ export function loadWorkspaceHookEntries(
});
}
function readBoundaryFileUtf8(params: {
function readRootFileUtf8(params: {
absolutePath: string;
rootPath: string;
boundaryLabel: string;
}): string | null {
return withOpenedBoundaryFileSync(params, (opened) => {
return withOpenedRootFileSync(params, (opened) => {
try {
return fs.readFileSync(opened.fd, "utf-8");
} catch {
@@ -307,7 +307,7 @@ function readBoundaryFileUtf8(params: {
});
}
function withOpenedBoundaryFileSync<T>(
function withOpenedRootFileSync<T>(
params: {
absolutePath: string;
rootPath: string;
@@ -315,7 +315,7 @@ function withOpenedBoundaryFileSync<T>(
},
read: (opened: { fd: number; path: string }) => T,
): T | null {
const opened = openBoundaryFileSync({
const opened = openRootFileSync({
absolutePath: params.absolutePath,
rootPath: params.rootPath,
boundaryLabel: params.boundaryLabel,
@@ -330,10 +330,10 @@ function withOpenedBoundaryFileSync<T>(
}
}
function resolveBoundaryFilePath(params: {
function resolveRootFilePath(params: {
absolutePath: string;
rootPath: string;
boundaryLabel: string;
}): string | null {
return withOpenedBoundaryFileSync(params, (opened) => opened.path);
return withOpenedRootFileSync(params, (opened) => opened.path);
}