mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-20 01:21:41 -06:00
fix(doctor): complete v6.11 automated import guard
Completes the v6.11 adaptation ofcd9db5ed9aafter prerequisite2b3dc3042fby disabling cross-state approval imports for implicit and automated doctor callers.
This commit is contained in:
@@ -103,6 +103,23 @@ function hasBundledChannelLegacyStateMigrationInputs(stateDir: string, oauthDir:
|
||||
return dirHasFile(oauthDir, isLegacyWhatsAppAuthFile);
|
||||
}
|
||||
|
||||
function hasCrossStateDirApprovalMigrationInputs(stateDir: string): boolean {
|
||||
if (!process.env.OPENCLAW_STATE_DIR?.trim()) {
|
||||
return false;
|
||||
}
|
||||
const homeDir = resolveRequiredHomeDir(process.env, os.homedir);
|
||||
const defaultStateDir = resolveNewStateDir(() => homeDir);
|
||||
if (path.resolve(defaultStateDir) === path.resolve(stateDir)) {
|
||||
return false;
|
||||
}
|
||||
const execApprovalsSource = path.join(defaultStateDir, "exec-approvals.json");
|
||||
const execApprovalsTarget = path.join(stateDir, "exec-approvals.json");
|
||||
return (
|
||||
(fileOrDirExists(execApprovalsSource) && !fileOrDirExists(execApprovalsTarget)) ||
|
||||
fileOrDirExists(path.join(defaultStateDir, "plugin-binding-approvals.json"))
|
||||
);
|
||||
}
|
||||
|
||||
function hasPendingSqliteSidecarArchive(sourcePath: string): boolean {
|
||||
return (
|
||||
fileOrDirExists(`${sourcePath}.migrated`) &&
|
||||
@@ -137,7 +154,8 @@ function hasLegacyStateMigrationInputs(): boolean {
|
||||
sqliteSidecarPaths.some(
|
||||
(sourcePath) => fileOrDirExists(sourcePath) || hasPendingSqliteSidecarArchive(sourcePath),
|
||||
) ||
|
||||
hasBundledChannelLegacyStateMigrationInputs(stateDir, oauthDir)
|
||||
hasBundledChannelLegacyStateMigrationInputs(stateDir, oauthDir) ||
|
||||
hasCrossStateDirApprovalMigrationInputs(stateDir)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -195,6 +213,7 @@ export async function ensureConfigReady(params: {
|
||||
migrateState: true,
|
||||
migrateLegacyConfig: false,
|
||||
invalidConfigNote: false,
|
||||
crossStateDirImports: false,
|
||||
...(params.beforeStateMigrations
|
||||
? { beforeStateMigrations: params.beforeStateMigrations }
|
||||
: {}),
|
||||
|
||||
@@ -11,7 +11,6 @@ import {
|
||||
noteOpencodeProviderOverrides,
|
||||
} from "./doctor-config-analysis.js";
|
||||
import { runDoctorConfigPreflight } from "./doctor-config-preflight.js";
|
||||
import { normalizeCompatibilityConfigValues } from "./doctor/shared/legacy-config-core-migrate.js";
|
||||
import type { DoctorOptions, DoctorPrompter } from "./doctor-prompter.js";
|
||||
import { emitDoctorNotes, sanitizeDoctorNote } from "./doctor/emit-notes.js";
|
||||
import { finalizeDoctorConfigFlow } from "./doctor/finalize-config-flow.js";
|
||||
@@ -24,6 +23,7 @@ import {
|
||||
collectMissingDefaultAccountBindingWarnings,
|
||||
collectMissingExplicitDefaultAccountWarnings,
|
||||
} from "./doctor/shared/default-account-warnings.js";
|
||||
import { normalizeCompatibilityConfigValues } from "./doctor/shared/legacy-config-core-migrate.js";
|
||||
|
||||
function hasLegacyInternalHookHandlers(raw: unknown): boolean {
|
||||
const handlers = (raw as { hooks?: { internal?: { handlers?: unknown } } })?.hooks?.internal
|
||||
@@ -145,7 +145,7 @@ export async function loadAndMaybeMigrateDoctorConfig(params: {
|
||||
const preflight = await runDoctorConfigPreflight({
|
||||
repairPrefixedConfig: shouldRepair,
|
||||
recoverCorruptTargetStore: shouldRepair,
|
||||
crossStateDirImports: shouldRepair,
|
||||
crossStateDirImports: shouldRepair && params.options.crossStateDirImports === true,
|
||||
});
|
||||
const snapshot = preflight.snapshot;
|
||||
const baseCfg = preflight.baseConfig;
|
||||
|
||||
@@ -514,16 +514,15 @@ async function runLegacyStateHealth(ctx: DoctorHealthFlowContext): Promise<void>
|
||||
const { detectLegacyStateMigrations, runLegacyStateMigrations } =
|
||||
await import("../commands/doctor-state-migrations.js");
|
||||
const { note } = await loadNoteModule();
|
||||
// Cross-state-dir imports (default home dir -> OPENCLAW_STATE_DIR) are
|
||||
// allowed here only when the operator either confirms the previewed plan
|
||||
// interactively or asked for repair; a bare non-interactive doctor stays
|
||||
// read-only toward the default state dir.
|
||||
// Only a direct operator-owned doctor may inspect the default state dir for
|
||||
// imports. Automated repair callers explicitly lack this capability so a
|
||||
// temporary OPENCLAW_STATE_DIR cannot capture and archive production trust.
|
||||
const operatorCanApproveCrossStateDirImports =
|
||||
ctx.prompter.repairMode.canPrompt || ctx.prompter.shouldRepair;
|
||||
const legacyState = await detectLegacyStateMigrations({
|
||||
cfg: ctx.cfg,
|
||||
crossStateDirImports:
|
||||
ctx.options.nonInteractive !== true ||
|
||||
ctx.options.repair === true ||
|
||||
ctx.options.yes === true,
|
||||
ctx.options.crossStateDirImports === true && operatorCanApproveCrossStateDirImports,
|
||||
});
|
||||
if (legacyState.warnings.length > 0) {
|
||||
note(legacyState.warnings.join("\n"), "Doctor warnings");
|
||||
|
||||
Reference in New Issue
Block a user