Skip to content

fix(exec): respect OPENCLAW_STATE_DIR for exec approvals#65736

Closed
oinoom wants to merge 2 commits into
openclaw:mainfrom
oinoom:fix/exec-approvals-state-dir
Closed

fix(exec): respect OPENCLAW_STATE_DIR for exec approvals#65736
oinoom wants to merge 2 commits into
openclaw:mainfrom
oinoom:fix/exec-approvals-state-dir

Conversation

@oinoom

@oinoom oinoom commented Apr 13, 2026

Copy link
Copy Markdown

Use the configured state directory for exec approvals file and socket resolution so Docker and hosted deployments with relocated state roots stop falling back to ~/.openclaw.

Add regression coverage for OPENCLAW_STATE_DIR path resolution.

Summary

Describe the problem and fix in 2–5 bullets:

If this PR fixes a plugin beta-release blocker, title it fix(<plugin-id>): beta blocker - <summary> and link the matching Beta blocker: <plugin-name> - <summary> issue labeled beta-blocker. Contributors cannot label PRs, so the title is the PR-side signal for maintainers and automation.

  • Problem: exec approvals file/socket resolution ignored OPENCLAW_STATE_DIR and continued to use ~/.openclaw/exec-approvals.*.
  • Why it matters: Docker and hosted deployments can legitimately relocate state to paths like /data or /data/openclaw, so exec-backed actions could fail even when the configured state dir was valid and writable.
  • What changed: exec approvals path resolution now derives from the configured state dir, and effective-policy reporting reflects the overridden path when OPENCLAW_STATE_DIR is set.
  • What did NOT change (scope boundary): this does not change default ~/.openclaw behavior for stock installs, exec approval semantics, approval policy evaluation, or Docker docs/runtime wiring outside this path-resolution bug.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

  • Closes #
  • Related #
  • This PR fixes a bug or regression

Root Cause (if applicable)

For bug fixes or regressions, explain why this happened, not just what changed. Otherwise write N/A. If the cause is unclear, write Unknown.

  • Root cause: src/infra/exec-approvals.ts hardcoded the default approvals file/socket under ~/.openclaw, while the rest of OpenClaw already supports relocating mutable state via OPENCLAW_STATE_DIR.
  • Missing detection / guardrail: there was no regression test asserting that exec approvals follow OPENCLAW_STATE_DIR, so this inconsistency was not caught.
  • Contributing context (if known): official/docs-supported deployments already use relocated state roots in some environments, while Docker examples often still assume /home/node/.openclaw, which likely masked the mismatch.

Regression Test Plan (if applicable)

For bug fixes or regressions, name the smallest reliable test coverage that should catch this. Otherwise write N/A.

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file: src/infra/exec-approvals-store.test.ts
  • Scenario the test should lock in: when OPENCLAW_STATE_DIR is set, resolveExecApprovalsPath() and resolveExecApprovalsSocketPath() should resolve inside that directory instead of expanding ~/.openclaw.
  • Why this is the smallest reliable guardrail: the bug is pure path-resolution logic; a unit test on the resolver captures it directly without needing a full gateway/container setup.
  • Existing test that already covers this (if any): none found.
  • If no new test is added, why not: N/A

User-visible / Behavior Changes

Exec-backed actions now respect OPENCLAW_STATE_DIR for approvals file/socket storage. Users with relocated state roots should no longer see host exec approvals fall back to ~/.openclaw or fail because that home-relative path is unavailable.

Diagram (if applicable)

Before:
OPENCLAW_STATE_DIR=/data/openclaw
tools.exec -> resolve approvals path -> ~/.openclaw/exec-approvals.json -> host exec can fail

After:
OPENCLAW_STATE_DIR=/data/openclaw
tools.exec -> resolve approvals path -> /data/openclaw/exec-approvals.json -> host exec uses configured state root

Security Impact (required)

  • New permissions/capabilities? (Yes/No) No
  • Secrets/tokens handling changed? (Yes/No) No
  • New/changed network calls? (Yes/No) No
  • Command/tool execution surface changed? (Yes/No) No
  • Data access scope changed? (Yes/No) No
  • If any Yes, explain risk + mitigation: N/A

Repro + Verification

Environment

  • OS: macOS host with Dockerized OpenClaw runtime
  • Runtime/container: Hyperplane Docker Compose service running OpenClaw
  • Model/provider: openai-codex/gpt-5.4
  • Integration/channel (if any): Slack + local tools.exec path through the gateway
  • Relevant config (redacted): OPENCLAW_STATE_DIR=/data/openclaw, OPENCLAW_WORKSPACE_DIR=/data/workspace, OPENCLAW_CONFIG_PATH=/tmp/openclaw.json

Steps

  1. Export a non-default writable state root, for example OPENCLAW_STATE_DIR=/tmp/repro-state.
  2. Export a different home directory, for example HOME=/tmp/repro-home.
  3. Call resolveExecApprovalsPath() or resolveExecApprovalsSocketPath() and inspect the resolved path.

Expected

  • Exec approvals file/socket resolve under the configured state dir, e.g. /tmp/repro-state/exec-approvals.json.

Actual

  • Before this fix, approvals path resolution fell back to ~/.openclaw/exec-approvals.* under HOME instead of the configured state dir. In relocated-state Docker setups, that mismatch could then surface as runtime failures such as ENOENT when the home-relative path was unavailable.
  • Minimal repro before fix:
    • resolveExecApprovalsPath() resolved to <HOME>/.openclaw/exec-approvals.json
    • resolveExecApprovalsSocketPath() resolved to <HOME>/.openclaw/exec-approvals.sock
  • Supporting runtime failure before fix:
    • saveExecApprovals(...) failed with ENOENT: no such file or directory, mkdir '<HOME>/.openclaw'

Evidence

Attach at least one:

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

Human Verification (required)

What you personally verified (not just CI), and how:

  • Verified scenarios:
    • Targeted tests passed: pnpm exec vitest run src/infra/exec-approvals-store.test.ts src/infra/exec-approvals-policy.test.ts
    • Minimal repro before fix: with OPENCLAW_STATE_DIR set and HOME unusable, saveExecApprovals(...) failed trying to create ~/.openclaw
    • Minimal repro after fix: the same operation succeeded and wrote into the configured state dir
    • Minimal repro after fix:
      • resolveExecApprovalsPath() resolved to <OPENCLAW_STATE_DIR>/exec-approvals.json
      • resolveExecApprovalsSocketPath() resolved to <OPENCLAW_STATE_DIR>/exec-approvals.sock
    • Live Docker verification: tools.exec ran from /data/workspace without the old /home/node/.openclaw ENOENT failure after rebuild/restart
    • Documentation contract checked:
      • OPENCLAW_STATE_DIR is documented as the mutable state root override
      • hosted install docs such as Fly.io explicitly document OPENCLAW_STATE_DIR=/data
  • Edge cases checked:
    • Default path reporting remains ~/.openclaw/... when OPENCLAW_STATE_DIR is not explicitly set
    • State-dir override path reporting now reflects the actual resolved approvals path
  • What you did not verify:
    • Full repo-wide pnpm build && pnpm check && pnpm test
    • Non-Docker hosted targets beyond the targeted path-resolution and live Docker repro

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

If a bot review conversation is addressed by this PR, resolve that conversation yourself. Do not leave bot review conversation cleanup for maintainers.

Compatibility / Migration

  • Backward compatible? (Yes/No) Yes
  • Config/env changes? (Yes/No) No
  • Migration needed? (Yes/No) No
  • If yes, exact upgrade steps: N/A

Risks and Mitigations

List only real risks for this PR. Add/remove entries as needed. If none, write None.

  • Risk: effective-policy output could become confusing if it still reported ~/.openclaw/... while the runtime used a relocated state dir.
    • Mitigation: exec-approvals-effective.ts now reports the resolved approvals path when OPENCLAW_STATE_DIR is explicitly set.

@greptile-apps

greptile-apps Bot commented Apr 13, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes a bug where resolveExecApprovalsPath() and resolveExecApprovalsSocketPath() hardcoded ~/.openclaw/ instead of delegating to resolveStateDir(), causing exec approvals to ignore OPENCLAW_STATE_DIR in Docker and hosted deployments. The fix is minimal and backward-compatible: default behavior for stock installs is unchanged, and a targeted regression test locks in the corrected path resolution.

Confidence Score: 5/5

Safe to merge — the fix is a focused path-resolution correction with no behavioral change for default installs and good regression coverage.

All findings are P2 (style suggestion about a parallel env-var read in the effective-policy helper). The core path-resolution change in exec-approvals.ts is correct and consistent with how other paths already use resolveStateDir(). The test cleanly captures the regression scenario.

src/infra/exec-approvals-effective.ts — the resolveDefaultExecApprovalsHostPath helper could be simplified to avoid a parallel env-var read, but this is non-blocking.

Prompt To Fix All With AI
This is a comment left during a code review.
Path: src/infra/exec-approvals-effective.ts
Line: 149-151

Comment:
**Parallel env-var read may drift from `resolveStateDir`**

`resolveDefaultExecApprovalsHostPath` reads `process.env.OPENCLAW_STATE_DIR` directly to decide which branch to take, while `resolveExecApprovalsPath()` delegates to `resolveStateDir()` which already owns all the normalization logic (trim, `~` expansion, legacy fallback). The two branches are consistent today because both trim, but they can diverge if `resolveStateDir` gains new semantics (e.g., supporting `OPENCLAW_STATE_DIR_BASE`, alias handling, or whitelist checks).

A simpler, more future-proof form would simply always call `resolveExecApprovalsPath()` and drop the fallback to `DEFAULT_HOST_PATH`. The resolved path is already equivalent when `OPENCLAW_STATE_DIR` is unset (e.g., `/home/user/.openclaw/exec-approvals.json`), and users reading policy output typically prefer the expanded path over the literal `~` string. If the tilde representation is required for backward compatibility in snapshot output, that concern belongs in a formatting helper rather than a branching resolver.

```suggestion
function resolveDefaultExecApprovalsHostPath(): string {
  return resolveExecApprovalsPath();
}
```

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "fix(exec): respect OPENCLAW_STATE_DIR fo..." | Re-trigger Greptile

Comment thread src/infra/exec-approvals-effective.ts Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c8cdcba2a3

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/infra/exec-approvals.ts Outdated
@clawsweeper

clawsweeper Bot commented Apr 27, 2026

Copy link
Copy Markdown
Contributor

Codex review: keeping this open for maintainer follow-up; there is still a little grit to resolve.

Keep this PR open. Current main still routes exec approval JSON and socket defaults through the home-relative .openclaw path instead of an explicit OPENCLAW_STATE_DIR, while the PR remains a focused implementation candidate and maintainer discussion says the branch was repaired to keep this contributor path canonical.

Best possible solution:

Keep this PR open for maintainer review and landing, or explicitly supersede it with one canonical implementation. The final fix should make exec approval JSON and socket defaults honor an explicit OPENCLAW_STATE_DIR, preserve the legacy home fallback when unset, update effective-policy reporting and docs/changelog, include focused regression coverage, and verify storage-safety checks for non-home state roots before closing #62917 and any overlapping PR.

What I checked:

  • Current main still hardcodes exec approval defaults: DEFAULT_FILE and DEFAULT_SOCKET are home-relative .openclaw/exec-approvals.* constants, and resolveExecApprovalsPath() / resolveExecApprovalsSocketPath() only call expandHomePrefix(...); there is no explicit state-dir branch in current main. (src/infra/exec-approvals.ts:174, a820a307dfeb)
  • Resolver is active runtime behavior: Snapshot, load, save, and socket defaulting paths call the exec approval resolvers, so the path mismatch affects real storage and reporting rather than dead code. (src/infra/exec-approvals.ts:431, a820a307dfeb)
  • State-dir override contract exists: resolveStateDir() explicitly reads OPENCLAW_STATE_DIR and resolves it as the mutable state root, confirming the broader state-dir contract that exec approvals currently bypass. (src/config/paths.ts:60, a820a307dfeb)
  • Hosted docs use relocated state: The Fly.io install guide configures OPENCLAW_STATE_DIR = "/data", matching the Docker/hosted deployment motivation in the PR body. Public docs: docs/install/fly.md. (docs/install/fly.md:60, a820a307dfeb)
  • Current tests/docs do not cover requested behavior: The store test currently asserts only the home-prefixed default file/socket paths, and targeted searches found no current-main resolveExplicitStateDir, resolveExecApprovalsDefaultHostPath, or exec-approvals OPENCLAW_STATE_DIR regression coverage. (src/infra/exec-approvals-store.test.ts:83, a820a307dfeb)
  • Live PR diff is focused and security-reviewed: The live PR diff changes the state-dir helper, exec approval path resolution, effective-policy reporting, regression tests, docs, and changelog. It does not add workflows, third-party dependencies, lockfile changes, package publishing metadata, install scripts, or downloaded/executed artifacts. (b826cfae8b49)

Likely related people:

  • Peter Steinberger [email protected]: Available local blame attributes the current exec approvals resolver, state-dir resolver, exec approvals docs, and store-test baseline to Peter on current main. This is routing evidence, not fault evidence. (role: recent maintainer / current-main baseline owner; confidence: medium; commits: 7b2b0d07e84e; files: src/infra/exec-approvals.ts, src/config/paths.ts, docs/tools/exec-approvals.md)
  • vincentkoc: The PR discussion says vincentkoc pushed the narrow repair to this branch, and the related merged symlink repair fix: allow trusted exec approvals home symlinks #72377 touched the same exec-approval storage-safety area. (role: recent adjacent maintainer / branch repair owner; confidence: medium; commits: b826cfae8b49, b4c251130643; files: src/infra/exec-approvals.ts, src/infra/exec-approvals-store.test.ts, src/infra/exec-approvals-effective.ts)
  • pashpashpash [email protected]: Current-main commit 6ce1058 recently touched src/infra/exec-approvals.ts while routing diagnostics and trajectory export flows through exec approval. That is adjacent review context, not the path-resolution owner. (role: recent adjacent exec-approval maintainer; confidence: low; commits: 6ce1058296cc; files: src/infra/exec-approvals.ts, src/commands/export-trajectory.ts, src/commands/doctor-command-owner.ts)

Remaining risk / open question:

  • The PR touches host command-execution approval storage. Before landing, maintainers should verify explicit state dirs outside OPENCLAW_HOME preserve intended symlink and trusted-root protections; current ensureDir() only walks symlink components under the resolved home root.
  • There is overlapping open work in fix(exec-approvals): respect OPENCLAW_STATE_DIR for store paths #62938. Maintainers should choose one canonical branch and close the superseded implementation only after one lands.
  • No supply-chain regression was visible in the live PR diff: it does not touch workflows, dependencies, lockfiles, install/build/release scripts, package publishing metadata, or downloaded artifacts.

Codex review notes: model gpt-5.5, reasoning high; reviewed against a820a307dfeb.

oinoom and others added 2 commits April 28, 2026 18:23
Use the configured state directory for exec approvals file and socket
resolution so Docker and hosted deployments with relocated state roots
stop falling back to ~/.openclaw.

Add regression coverage for OPENCLAW_STATE_DIR path resolution.
@vincentkoc

Copy link
Copy Markdown
Member

ProjectClownfish pushed a narrow repair to this branch so the original contributor path can stay canonical.

Source PR: #65736
Validation: pnpm -s vitest run src/infra/exec-approvals-store.test.ts; pnpm check:changed
Contributor credit is preserved in the branch history and PR context.

@vincentkoc
vincentkoc force-pushed the fix/exec-approvals-state-dir branch from 32aad32 to b826cfa Compare April 28, 2026 18:29
@openclaw-barnacle openclaw-barnacle Bot added docs Improvements or additions to documentation size: S and removed size: XS labels Apr 28, 2026
@vincentkoc vincentkoc added clownfish:human-review clawsweeper Tracked by ClawSweeper automation and removed clownfish:merge-ready labels Apr 28, 2026
@openclaw-clownfish

Copy link
Copy Markdown
Contributor

ProjectClownfish could not safely update this branch, so it opened a narrow replacement PR instead.

Replacement PR: #74002
Source PR: #65736
Contributor credit is preserved in the replacement PR body and changelog plan.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clawsweeper Tracked by ClawSweeper automation docs Improvements or additions to documentation size: S

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants