diff --git a/CHANGELOG.md b/CHANGELOG.md index ec6f87ba552..098238883dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ Docs: https://docs.openclaw.ai - Agents: omit the sandbox workspace marker from compact command progress previews while keeping internal sandbox diagnostics unchanged. - Agents: widen progress draft command preview lines by 50% so Discord inline tool updates preserve more useful command context. - Codex app-server: retire timed-out app-server clients after bounded turn interrupts so Discord agents do not reuse a CPU-spinning Codex process after an attempt timeout. +- Codex app-server: default migrated native plugin destructive-action policy to enabled while preserving explicit global and per-plugin false overrides. - Build: upgrade workspace package management to pnpm 11 and keep Docker, install, update, and release workflows on the pnpm 11 config surface. (#79414) Thanks @altaywtf. - Build: align Telegram QA workflows and git source installs with the pnpm 11 workspace build allowlist surface. (#80588) Thanks @altaywtf. - Models: add provider-level `localService` startup for on-demand local model servers before OpenAI-compatible requests, including one-shot model probes. diff --git a/docs/cli/migrate.md b/docs/cli/migrate.md index ff18bdeff78..064b7fd2bc1 100644 --- a/docs/cli/migrate.md +++ b/docs/cli/migrate.md @@ -173,7 +173,7 @@ For migrated source-installed curated plugins, apply writes: - `plugins.entries.codex.enabled: true` - `plugins.entries.codex.config.codexPlugins.enabled: true` -- `plugins.entries.codex.config.codexPlugins.allow_destructive_actions: false` +- `plugins.entries.codex.config.codexPlugins.allow_destructive_actions: true` - one explicit plugin entry with `marketplaceName: "openai-curated"` and `pluginName` for each selected plugin diff --git a/docs/gateway/configuration-reference.md b/docs/gateway/configuration-reference.md index 3be96a2b899..56ceb8b1959 100644 --- a/docs/gateway/configuration-reference.md +++ b/docs/gateway/configuration-reference.md @@ -238,7 +238,7 @@ conversation bindings, or any non-Codex harness. config: { codexPlugins: { enabled: true, - allow_destructive_actions: false, + allow_destructive_actions: true, plugins: { "google-calendar": { enabled: true, @@ -259,7 +259,7 @@ conversation bindings, or any non-Codex harness. plugin/app support for the Codex harness. Default: `false`. - `plugins.entries.codex.config.codexPlugins.allow_destructive_actions`: default destructive-action policy for migrated plugin app elicitations. - Default: `false`. + Default: `true`. - `plugins.entries.codex.config.codexPlugins.plugins..enabled`: enables a migrated plugin entry when global `codexPlugins.enabled` is also true. Default: `true` for explicit entries. diff --git a/docs/plugins/codex-harness.md b/docs/plugins/codex-harness.md index 75bac9b4c74..b90a3ed853f 100644 --- a/docs/plugins/codex-harness.md +++ b/docs/plugins/codex-harness.md @@ -551,7 +551,7 @@ Minimal migrated config: config: { codexPlugins: { enabled: true, - allow_destructive_actions: false, + allow_destructive_actions: true, plugins: { "google-calendar": { enabled: true, diff --git a/docs/plugins/codex-native-plugins.md b/docs/plugins/codex-native-plugins.md index f5beca848a7..852e3ab438b 100644 --- a/docs/plugins/codex-native-plugins.md +++ b/docs/plugins/codex-native-plugins.md @@ -58,7 +58,7 @@ config looks like this: config: { codexPlugins: { enabled: true, - allow_destructive_actions: false, + allow_destructive_actions: true, plugins: { "google-calendar": { enabled: true, @@ -143,9 +143,10 @@ controlled by each app's `destructive_enabled` policy. ## Destructive action policy -Destructive plugin elicitations fail closed by default: +Destructive plugin elicitations are allowed by default for migrated Codex +plugins, while unsafe schemas and ambiguous ownership still fail closed: -- Global `allow_destructive_actions` defaults to `false`. +- Global `allow_destructive_actions` defaults to `true`. - Per-plugin `allow_destructive_actions` overrides the global policy for that plugin. - When policy is `false`, OpenClaw returns a deterministic decline. diff --git a/extensions/codex/openclaw.plugin.json b/extensions/codex/openclaw.plugin.json index bfaa9d35a7f..30d8ed64251 100644 --- a/extensions/codex/openclaw.plugin.json +++ b/extensions/codex/openclaw.plugin.json @@ -101,7 +101,7 @@ }, "allow_destructive_actions": { "type": "boolean", - "default": false + "default": true }, "plugins": { "type": "object", @@ -272,7 +272,7 @@ }, "codexPlugins.allow_destructive_actions": { "label": "Allow Destructive Plugin Actions", - "help": "Default policy for plugin app write or destructive action elicitations. Defaults to false.", + "help": "Default policy for plugin app write or destructive action elicitations. Defaults to true.", "advanced": true }, "codexPlugins.plugins": { diff --git a/extensions/codex/src/app-server/config.test.ts b/extensions/codex/src/app-server/config.test.ts index 3938a23e9ce..f0581ce9c48 100644 --- a/extensions/codex/src/app-server/config.test.ts +++ b/extensions/codex/src/app-server/config.test.ts @@ -518,6 +518,35 @@ allowed_sandbox_modes = ["read-only", "workspace-write"] }); }); + it("defaults native Codex plugin destructive policy to enabled", () => { + const policy = resolveCodexPluginsPolicy({ + codexPlugins: { + enabled: true, + plugins: { + slack: { + marketplaceName: "openai-curated", + pluginName: "slack", + }, + }, + }, + }); + + expect(policy).toEqual({ + configured: true, + enabled: true, + allowDestructiveActions: true, + pluginPolicies: [ + { + configKey: "slack", + marketplaceName: "openai-curated", + pluginName: "slack", + enabled: true, + allowDestructiveActions: true, + }, + ], + }); + }); + it("rejects non-curated native plugin identities", () => { const config = readCodexPluginConfig({ codexPlugins: { diff --git a/extensions/codex/src/app-server/config.ts b/extensions/codex/src/app-server/config.ts index 2277da29725..498302b5d2b 100644 --- a/extensions/codex/src/app-server/config.ts +++ b/extensions/codex/src/app-server/config.ts @@ -282,7 +282,7 @@ export function resolveCodexPluginsPolicy(pluginConfig?: unknown): ResolvedCodex const config = readCodexPluginConfig(pluginConfig).codexPlugins; const configured = config !== undefined; const enabled = config?.enabled === true; - const allowDestructiveActions = config?.allow_destructive_actions ?? false; + const allowDestructiveActions = config?.allow_destructive_actions ?? true; const pluginPolicies = Object.entries(config?.plugins ?? {}) .flatMap(([configKey, entry]): ResolvedCodexPluginPolicy[] => { if (entry.marketplaceName !== CODEX_PLUGINS_MARKETPLACE_NAME || !entry.pluginName) { diff --git a/extensions/codex/src/app-server/plugin-thread-config.test.ts b/extensions/codex/src/app-server/plugin-thread-config.test.ts index c263781c339..93a193190a3 100644 --- a/extensions/codex/src/app-server/plugin-thread-config.test.ts +++ b/extensions/codex/src/app-server/plugin-thread-config.test.ts @@ -11,7 +11,7 @@ import { import type { v2 } from "./protocol.js"; describe("Codex plugin thread config", () => { - it("builds restrictive app config for accessible migrated plugin apps", async () => { + it("defaults destructive app access on for accessible migrated plugin apps", async () => { const appCache = new CodexAppInventoryCache(); await appCache.refreshNow({ key: "runtime", @@ -26,7 +26,6 @@ describe("Codex plugin thread config", () => { pluginConfig: { codexPlugins: { enabled: true, - allow_destructive_actions: true, plugins: { "google-calendar": { marketplaceName: CODEX_PLUGINS_MARKETPLACE_NAME, @@ -254,7 +253,7 @@ describe("Codex plugin thread config", () => { }, "google-calendar-app": { enabled: true, - destructive_enabled: false, + destructive_enabled: true, open_world_enabled: true, default_tools_approval_mode: "auto", }, @@ -264,7 +263,7 @@ describe("Codex plugin thread config", () => { configKey: "google-calendar", marketplaceName: CODEX_PLUGINS_MARKETPLACE_NAME, pluginName: "google-calendar", - allowDestructiveActions: false, + allowDestructiveActions: true, mcpServerNames: [], }); expect(config.diagnostics).toStrictEqual([]); @@ -328,7 +327,7 @@ describe("Codex plugin thread config", () => { marketplaceName: CODEX_PLUGINS_MARKETPLACE_NAME, pluginName: "google-calendar", enabled: true, - allowDestructiveActions: false, + allowDestructiveActions: true, }, message: "google-calendar-app is not accessible or enabled for google-calendar.", }, @@ -403,7 +402,7 @@ describe("Codex plugin thread config", () => { }, "google-calendar-app": { enabled: true, - destructive_enabled: false, + destructive_enabled: true, open_world_enabled: true, default_tools_approval_mode: "auto", }, @@ -412,7 +411,7 @@ describe("Codex plugin thread config", () => { configKey: "google-calendar", marketplaceName: CODEX_PLUGINS_MARKETPLACE_NAME, pluginName: "google-calendar", - allowDestructiveActions: false, + allowDestructiveActions: true, mcpServerNames: [], }); expect(config.diagnostics).toStrictEqual([]); diff --git a/extensions/codex/src/migration/apply.ts b/extensions/codex/src/migration/apply.ts index 0b426b59a69..d17bf059fb3 100644 --- a/extensions/codex/src/migration/apply.ts +++ b/extensions/codex/src/migration/apply.ts @@ -242,7 +242,7 @@ function readCodexPluginPolicy(item: MigrationItem): ResolvedCodexPluginPolicy | marketplaceName: CODEX_PLUGINS_MARKETPLACE_NAME, pluginName, enabled: true, - allowDestructiveActions: false, + allowDestructiveActions: true, }; } diff --git a/extensions/codex/src/migration/plan.ts b/extensions/codex/src/migration/plan.ts index 9492666cb5b..f1103ac15a4 100644 --- a/extensions/codex/src/migration/plan.ts +++ b/extensions/codex/src/migration/plan.ts @@ -251,8 +251,8 @@ export function buildCodexPluginsConfigValue( enabled: true, allow_destructive_actions: params.config === undefined - ? false - : (readExistingAllowDestructiveActions(params.config) ?? false), + ? true + : (readExistingAllowDestructiveActions(params.config) ?? true), plugins, }, }; diff --git a/extensions/codex/src/migration/provider.test.ts b/extensions/codex/src/migration/provider.test.ts index 43570c114cc..a8679cdc89b 100644 --- a/extensions/codex/src/migration/provider.test.ts +++ b/extensions/codex/src/migration/provider.test.ts @@ -331,7 +331,7 @@ describe("buildCodexMigrationProvider", () => { }); expect(configState.plugins?.entries?.codex?.config?.codexPlugins).toEqual({ enabled: true, - allow_destructive_actions: false, + allow_destructive_actions: true, plugins: { "google-calendar": { enabled: true, @@ -651,7 +651,7 @@ describe("buildCodexMigrationProvider", () => { }); expect(configState.plugins?.entries?.codex?.config?.codexPlugins).toEqual({ enabled: true, - allow_destructive_actions: false, + allow_destructive_actions: true, plugins: { "google-calendar": { enabled: false, diff --git a/src/commands/migrate.test.ts b/src/commands/migrate.test.ts index 9dfdca05a15..37090c94d9a 100644 --- a/src/commands/migrate.test.ts +++ b/src/commands/migrate.test.ts @@ -161,7 +161,7 @@ function codexPluginPlan(overrides: Partial = {}): MigrationPlan config: { codexPlugins: { enabled: true, - allow_destructive_actions: false, + allow_destructive_actions: true, plugins: { "google-calendar": { enabled: true, diff --git a/src/commands/migrate/selection.test.ts b/src/commands/migrate/selection.test.ts index 4289b039031..923282fb7c5 100644 --- a/src/commands/migrate/selection.test.ts +++ b/src/commands/migrate/selection.test.ts @@ -75,7 +75,7 @@ function codexPluginConfigItem(pluginNames: string[]): MigrationItem { config: { codexPlugins: { enabled: true, - allow_destructive_actions: false, + allow_destructive_actions: true, plugins: Object.fromEntries( pluginNames.map((name) => [ name,