























11// OpenClaw state database manages shared persisted state and migrations.
22import { randomUUID } from "node:crypto";
3-import { chmodSync, existsSync, mkdirSync, statSync, unlinkSync, writeFileSync } from "node:fs";
3+import { existsSync, mkdirSync } from "node:fs";
44import path from "node:path";
55import type { DatabaseSync } from "node:sqlite";
66import {
@@ -9,6 +9,7 @@ import {
99getNodeSqliteKysely,
1010} from "../infra/kysely-sync.js";
1111import { requireNodeSqlite } from "../infra/node-sqlite.js";
12+import { applyPrivateModeSync } from "../infra/private-mode.js";
1213import { resolveSqliteDatabaseFilePaths } from "../infra/sqlite-files.js";
1314import { runSqliteImmediateTransactionSync } from "../infra/sqlite-transaction.js";
1415import {
@@ -119,70 +120,17 @@ const stateDbLog = createSubsystemLogger("state/db");
119120/** Targets already warned about, so chmod-less filesystems warn once per path. */
120121const chmodWarnedTargets = new Set<string>();
121122122-// Unambiguous errno codes raised when the filesystem cannot enforce POSIX modes.
123-const CHMOD_UNSUPPORTED_CODES = new Set(["ENOTSUP", "EOPNOTSUPP", "EINVAL"]);
124-125-function hasRestrictivePermissions(target: string): boolean {
126-try {
127-return (statSync(target).mode & 0o077) === 0;
128-} catch {
129-return false;
130-}
131-}
132-133-function filesystemRejectsChmod(target: string): boolean {
134-let probePath: string;
135-try {
136-const probeDir = statSync(target).isDirectory() ? target : path.dirname(target);
137-probePath = path.join(probeDir, `.openclaw-chmod-probe-${randomUUID()}`);
138-writeFileSync(probePath, "", { flag: "wx", mode: OPENCLAW_STATE_FILE_MODE });
139-} catch {
140-return false;
141-}
142-try {
143-chmodSync(probePath, OPENCLAW_STATE_FILE_MODE);
144-return false;
145-} catch (err) {
146-return (err as NodeJS.ErrnoException).code === "EPERM";
147-} finally {
148-try {
149-unlinkSync(probePath);
150-} catch {
151-// The probe is best-effort cleanup after a failed capability check.
152-}
153-}
154-}
155-156-function canIgnoreChmodError(target: string, code: string | undefined): boolean {
157-if (code && CHMOD_UNSUPPORTED_CODES.has(code)) {
158-return true;
159-}
160-if (code !== "EPERM") {
161-return false;
162-}
163-// EPERM is ambiguous: keep restrictive targets usable, otherwise prove the
164-// containing filesystem also rejects chmod before weakening fail-closed behavior.
165-return hasRestrictivePermissions(target) || filesystemRejectsChmod(target);
166-}
167-168123// Permission hardening is best-effort only on filesystems that cannot apply
169124// it: the database stays usable without the chmod, and crashing at open would
170125// take the gateway down on Azure Files/NFS/Docker volumes (#91919). Unexpected
171126// chmod failures still throw so credentials-adjacent hardening stays loud.
172127function bestEffortChmodSync(target: string, mode: number): void {
173-try {
174-chmodSync(target, mode);
175-} catch (err) {
176-const code = (err as NodeJS.ErrnoException).code;
177-if (!canIgnoreChmodError(target, code)) {
178-throw err;
179-}
180-if (chmodWarnedTargets.has(target)) {
181-return;
182-}
183-chmodWarnedTargets.add(target);
184-stateDbLog.warn(`skipped permission hardening for ${target}: ${String(err)}`);
128+const result = applyPrivateModeSync(target, mode);
129+if (result.applied || chmodWarnedTargets.has(target)) {
130+return;
185131}
132+chmodWarnedTargets.add(target);
133+stateDbLog.warn(`skipped permission hardening for ${target}: ${String(result.error)}`);
186134}
187135188136function ensureOpenClawStatePermissions(pathname: string, env: NodeJS.ProcessEnv): void {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。