Skip to content

fix(computer-use): scope HarmonyOS cleanup to owned temporary files - #5895

Open
Hmbown wants to merge 4 commits into
mainfrom
fix/hdc-owned-temp-0913-20260905
Open

fix(computer-use): scope HarmonyOS cleanup to owned temporary files#5895
Hmbown wants to merge 4 commits into
mainfrom
fix/hdc-owned-temp-0913-20260905

Conversation

@Hmbown

@Hmbown Hmbown commented Sep 5, 2026

Copy link
Copy Markdown
Owner

A successful HarmonyOS file read downloaded directly under the system temporary directory and recursively removed its parent, potentially deleting unrelated temporary files. Failed transfers also left partial downloads behind.

Download into a unique owned directory and remove only that directory in a finally block. This also cleans up failed transfers and failed reads.

Fixes #5894

Validation: computer-use suite 34/34 passed; local file-read smoke returned the downloaded bytes and removed the owned directory. Three isolated filesystem cases preserve an unrelated sentinel and check cleanup on success, transfer failure, and read failure. Running those tests against the prior code reproduces unrelated-file deletion and leaked partial downloads entirely within the fixture. No real HarmonyOS device acceptance is claimed.

Depends on the bundle relocation in #5890; the defect predates that move. This is v0.9.13 work and does not alter the published v0.9.12 tag or assets.


Note

Low Risk
Localized temp-file lifecycle fix in the computer-use HDC transport with regression tests; no auth, data model, or API surface changes.

Overview
HarmonyOS hdc remote reads no longer download into the system temp root and recursively delete the parent folder—a pattern that could wipe unrelated temp files and leave partial files on failed transfers.

hdcExec.readFile now pulls into a dedicated mkdtemp directory under cu-hdc-, reads out, and removes only that directory in a finally block (errors from cleanup are swallowed so they cannot mask transfer or read failures).

Tests add six parametrized cases (success, transfer failure, read failure × cleanup success/failure) that mock pullFile and optionally failing fs.rm, asserting sentinel files survive and the correct error or bytes are returned—including reproducing the old parent-delete behavior in isolation.

Reviewed by Cursor Bugbot for commit 030ff76. Bugbot is set up for automated code reviews on this repo. Configure here.

Fixes #5894. Download into an owned mkdtemp directory and clean it in finally so successful reads cannot delete unrelated temporary files and failed transfers do not leak partial downloads.

Validation: computer-use suite 34/34 passed. Isolated regression fixture reproduces unrelated-file deletion and leaked partial transfer on the previous implementation. Local file-read smoke passed. No live HarmonyOS device acceptance claimed.
Signed-off-by: CodeWhale Bot <bot@codewhale.net>
Copilot AI lite review requested due to automatic review settings September 5, 2026 11:50
@cursor

cursor Bot commented Sep 5, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_48738b28-92ff-4688-8a48-c109e70ab2d1)

Copilot AI 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.

🟡 Changes recommended

The new finally cleanup can throw and mask the original transfer/read error (or fail an otherwise-successful read) unless cleanup errors are made best-effort again.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR fixes unsafe temporary-file cleanup in the HarmonyOS (hdc) transport readFile() implementation by ensuring downloads occur in a uniquely owned temp directory and only that directory is removed, preventing accidental deletion of unrelated files and cleaning up partial downloads on failure.

Changes:

  • Update hdcExec().readFile() to download into an mkdtemp-created owned directory and remove it in a finally block.
  • Add parameterized regression tests covering successful reads, transfer failures, and read failures, ensuring unrelated temp files remain intact and cleanup is complete.
File summaries
File Description
crates/tui/plugins/computer-use/src/transport.mjs Scopes HarmonyOS readFile downloads/cleanup to an owned temp directory to prevent cross-file deletion and ensure cleanup on all outcomes.
crates/tui/plugins/computer-use/tests/exec-transport.test.mjs Adds regression tests asserting unrelated temp files are preserved and owned temp artifacts are cleaned up for success/failure paths.
Review details
  • Files reviewed: 2/2 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +121 to +128
const dir = await fs.promises.mkdtemp(path.join(os.tmpdir(), "cu-hdc-"));
try {
const tmp = path.join(dir, "out");
await this.pullFile(remotePath, tmp, opts);
return await fs.promises.readFile(tmp);
} finally {
await fs.promises.rm(dir, { recursive: true, force: true });
}

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

Copy link
Copy Markdown

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: 7643c0a1c4

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

await this.pullFile(remotePath, tmp, opts);
return await fs.promises.readFile(tmp);
} finally {
await fs.promises.rm(dir, { recursive: true, force: true });

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve the read outcome when cleanup fails

If removing the temporary directory fails—for example because of a transient Windows file lock—this awaited rm replaces a successful read result and also masks any transfer or read error from the try block. The previous cleanup explicitly ignored removal failures, so keep cleanup best-effort or otherwise preserve the primary result/error while reporting the cleanup failure separately.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-05T11:53:40.887464Z 7643c0a PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@Hmbown
Hmbown changed the base branch from fix/v0912-crate-bundle-20260905 to main September 5, 2026 12:07
…13-20260905

Signed-off-by: CodeWhale Bot <bot@codewhale.net>
@cursor

cursor Bot commented Sep 5, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_a3a6043d-1e70-4eb4-8440-08501c9f70c7)

@claude

claude Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Claude finished @Hmbown's task in 1m 16s —— View job


Review: fix(computer-use): scope HarmonyOS cleanup to owned temporary files

  • Gather context (PR diff, existing bot review comments)
  • Review transport.mjs hdcExec().readFile() change
  • Review new tests in exec-transport.test.mjs
  • Post final review

Summary: The core fix — downloading into a dedicated mkdtemp directory instead of a bare file directly under os.tmpdir() — correctly eliminates the reported bug (the old path.dirname(tmp) was os.tmpdir() itself, so a successful read recursively deleted the whole system temp dir). The added parameterized tests are a good, targeted regression check that reproduce the original defect against the prior code. However, the finally block introduces a real correctness regression that both Copilot and Codex already flagged — I confirmed it independently and it should block merge.

1. Correctness bug — unconditional rm in finally can mask the real error or turn success into failure (crates/tui/plugins/computer-use/src/transport.mjs:120-129)

async readFile(remotePath, opts = {}) {
  const dir = await fs.promises.mkdtemp(path.join(os.tmpdir(), "cu-hdc-"));
  try {
    const tmp = path.join(dir, "out");
    await this.pullFile(remotePath, tmp, opts);
    return await fs.promises.readFile(tmp);
  } finally {
    await fs.promises.rm(dir, { recursive: true, force: true });
  }
},

Per JS semantics, if the finally block throws, that exception replaces whatever the try block was about to produce — whether that was a resolved value (a successful read becomes a rejection) or a genuine transport/read error from pullFile/readFile (the real cause is discarded and replaced with the cleanup error). The prior implementation deliberately used .catch(() => {}) on the cleanup step for this reason. Since dir is now a uniquely-owned mkdtemp directory (not the shared system temp root), it's safe to restore best-effort cleanup without reintroducing the original cross-file-deletion bug, e.g.:

} finally {
  await fs.promises.rm(dir, { recursive: true, force: true }).catch(() => {});
}

A transient lock (e.g. Windows EPERM on an open handle) or any unexpected rm failure would otherwise silently swap a successful transfer/legit error for an unrelated cleanup error, which is a worse failure mode for callers than a leaked temp directory. Fix this →

2. Test gap (crates/tui/plugins/computer-use/tests/exec-transport.test.mjs)

The three new cases (success, transfer failure, read failure) all assume fs.promises.rm succeeds, so none of them exercise the masking behavior above. Once best-effort cleanup is restored, it's worth adding a fourth case that mocks fs.rm to reject and asserts the original result/error still surfaces (this is also the case that would have caught the regression before it shipped).

Other observations (no action needed):

  • Scoping the download to a per-call mkdtemp directory and removing exactly that directory is the right shape for the fix — it correctly contains cleanup to only what this call owns.
  • No provider/model/route-selection code is touched by this diff.
  • The rest of the changed files in this PR are the #5890 bundle-relocation rename (path move to crates/tui/plugins/computer-use/... plus the builtin.rs/manifest.rs/extensions.rs/ci.yml/.gitignore reference updates); no additional issues found there beyond what's already merged.

@Hmbown Hmbown added this to the v0.9.13 milestone Sep 5, 2026

@codewhale-agent codewhale-agent Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Codewhale review

Fixes the HarmonyOS readFile cleanup bug where the previous code called fs.promises.rm(path.dirname(tmp), { recursive: true, force: true }) and could delete the entire os.tmpdir(). The new implementation downloads into a unique mkdtemp directory and removes only that directory in a finally block. It also relocates the computer-use plugin bundle to crates/tui/plugins/computer-use and updates CI, .gitignore, Rust include_str paths, manifest validation, and UI source references. Tests cover success, transfer failure, and read failure.

Findings

  • [WARNING] Cleanup failure in finally can mask the original error or reject a successful read (crates/tui/plugins/computer-use/src/transport.mjs:127)
    In readFile, the finally block awaits fs.promises.rm without a catch. If rm rejects, it overrides any transfer/read error, and it can also turn an otherwise successful read into a rejected promise. The previous implementation swallowed cleanup errors with .catch(() => {}). Consider catching cleanup failures in the finally block so they do not mask the primary outcome.

Suggestions

  • crates/tui/plugins/computer-use/src/transport.mjs:127 — Add a catch to the cleanup call in the finally block so a failed rm does not mask the original transfer/read error or reject an already successful read.

            await fs.promises.rm(dir, { recursive: true, force: true }).catch(() => {});
    

Assessment

The core bug fix is correct and well tested: it scopes cleanup to an owned temporary directory and exercises success, transfer failure, and read failure. The path relocation updates are consistent with the new bundle location. The main remaining concern is cleanup error handling in the finally block, which should be adjusted to preserve the original operation result.


Advisory review by Codewhale (codewhale review --pr 5895 --post, head 4f18c59b1a2a1cee37758a13fc7401d40ba8df73). Line-specific findings are also posted as inline review comments; mechanical fixes arrive as committable suggestions you can apply from the Files tab. CODEOWNERS approval still governs merge.

await this.pullFile(remotePath, tmp, opts);
return await fs.promises.readFile(tmp);
} finally {
await fs.promises.rm(dir, { recursive: true, force: true });

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[WARNING] Cleanup failure in finally can mask the original error or reject a successful read

In readFile, the finally block awaits fs.promises.rm without a catch. If rm rejects, it overrides any transfer/read error, and it can also turn an otherwise successful read into a rejected promise. The previous implementation swallowed cleanup errors with .catch(() => {}). Consider catching cleanup failures in the finally block so they do not mask the primary outcome.

await this.pullFile(remotePath, tmp, opts);
return await fs.promises.readFile(tmp);
} finally {
await fs.promises.rm(dir, { recursive: true, force: true });

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Add a catch to the cleanup call in the finally block so a failed rm does not mask the original transfer/read error or reject an already successful read.

Suggested change
await fs.promises.rm(dir, { recursive: true, force: true });
await fs.promises.rm(dir, { recursive: true, force: true }).catch(() => {});

Keep recursive cleanup confined to the owned directory and best effort, so cleanup failure cannot mask a transfer/read error or reject a successful download. Validation: 37/37 plugin tests pass, including six success/failure/cleanup combinations; git diff --check passed. Runtime root has no npm test/check:web scripts.

Signed-off-by: CodeWhale Bot <bot@codewhale.net>
@cursor

cursor Bot commented Sep 5, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_a4630fb9-4154-4a51-b7f6-ece87b1ea16e)

@claude

claude Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Claude finished @Hmbown's task in 1m 7s —— View job


Review: fix(computer-use): scope HarmonyOS cleanup to owned temporary files

  • Gather context (latest diff vs origin/main, prior bot feedback, new commit 29bdcf1)
  • Verify whether the finally/masking issue flagged by Copilot, Codex, and the earlier Claude review was fixed
  • Review new/changed tests
  • Post final review

Summary: The blocking issue from the earlier round (Copilot, Codex, and the prior Claude review all flagged it) is fixed in 29bdcf1. No new correctness issues found.

Previously flagged issue — resolved (crates/tui/plugins/computer-use/src/transport.mjs:127)

The finally block's fs.promises.rm(dir, …) now has .catch(() => {}) restored:

} finally {
  // Cleanup must not replace downloaded bytes or the original I/O error.
  await fs.promises.rm(dir, { recursive: true, force: true }).catch(() => {});
}

This matches exactly what all three reviewers suggested: cleanup is best-effort again, so a transient rm failure (e.g. Windows EPERM on an open handle) can no longer mask a successful read or swap out the real transfer/read error. Since dir is a uniquely-owned mkdtemp directory, best-effort cleanup no longer risks the original cross-file-deletion bug.

Tests (crates/tui/plugins/computer-use/tests/exec-transport.test.mjs)

The parameterized suite was extended from 3 cases to 6 (success / transfer failure / read failure × cleanup succeeds / cleanup fails), closing exactly the gap the earlier review called out. The cleanupFails case mocks fs.rm to reject and asserts:

  • the original result/error still surfaces correctly (success returns bytes, transfer failure returns the transfer error, read failure returns ENOENT), and
  • the mocked rm call target stays confined to the owned cu-hdc-* directory.

This is a good regression test — it would have caught the masking bug before it shipped, and it now guards against it in the future.

Other files (bundle relocation from plugins/computer-usecrates/tui/plugins/computer-use): builtin.rs, manifest.rs, extensions.rs, ci.yml, .gitignore are mechanical path updates consistent with the relocation include_str! paths, manifest test fixture path, CI test path, and UI source-reference string all point at the new location correctly. No provider/model/route-selection code is touched.

No further action needed from my side.

@Hmbown

Hmbown commented Sep 5, 2026

Copy link
Copy Markdown
Owner Author

Review follow-up is pushed at 29bdcf1. Cleanup remains confined to its owned temporary directory and is best effort, preserving both successful bytes and the original transfer/read error when directory removal fails.

37/37 plugin tests pass, including success, transfer failure, and read failure with both successful and failed cleanup. Hosted CI is running on this new head.

@codewhale-agent codewhale-agent Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Codewhale review

The PR fixes unsafe HarmonyOS temp cleanup by creating a unique per-read directory with mkdtemp and removing only that directory in a finally block. It also relocates the computer-use bundle to crates/tui/plugins/computer-use and updates references. The production change is correct and the new filesystem tests cover success, transfer failure, read failure, and cleanup failure paths.

Findings

  • [WARNING] Cleanup-failure test assertions can be swallowed by production catch (crates/tui/plugins/computer-use/tests/exec-transport.test.mjs:73)
    In exec-transport.test.mjs, the cleanupFails branch asserts inside the mocked fs.rm that the removed path is the owned temp directory. However, readFile intentionally catches all cleanup errors with .catch(() => {}), so an AssertionError thrown by those assertions would be swallowed and the test could pass even if readFile attempted to remove the wrong directory. The non-mocked cleanup-success cases still catch root deletion via the sentinel file, so the suite is not currently blind to the original bug, but this branch provides weaker protection than it appears.

Suggestions

  • crates/tui/plugins/computer-use/tests/exec-transport.test.mjs:73 — Record the directory passed to the mocked fs.rm and assert the recorded path after readFile settles, so the assertion is outside the production catch and cannot be swallowed.

Assessment

The production change is correct and limits cleanup blast radius to the owned temporary directory. The path relocation updates are consistent. No production correctness issues found; the only concern is test assertion visibility in the cleanup-failure branch.


Advisory review by Codewhale (codewhale review --pr 5895 --post, head 29bdcf1dcaaa76ec1cf5713fe28826e65f536558). Line-specific findings are also posted as inline review comments; mechanical fixes arrive as committable suggestions you can apply from the Files tab. CODEOWNERS approval still governs merge.

t.mock.method(fs, "rm", async (dir) => {
assert.equal(path.dirname(dir), root, "cleanup stays inside its fixture");
assert.ok(path.basename(dir).startsWith("cu-hdc-"));
throw Object.assign(new Error("cleanup denied"), { code: "EACCES" });

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[WARNING] Cleanup-failure test assertions can be swallowed by production catch

In exec-transport.test.mjs, the cleanupFails branch asserts inside the mocked fs.rm that the removed path is the owned temp directory. However, readFile intentionally catches all cleanup errors with .catch(() => {}), so an AssertionError thrown by those assertions would be swallowed and the test could pass even if readFile attempted to remove the wrong directory. The non-mocked cleanup-success cases still catch root deletion via the sentinel file, so the suite is not currently blind to the original bug, but this branch provides weaker protection than it appears.

assert.ok(path.basename(dir).startsWith("cu-hdc-"));
throw Object.assign(new Error("cleanup denied"), { code: "EACCES" });
});
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Record the directory passed to the mocked fs.rm and assert the recorded path after readFile settles, so the assertion is outside the production catch and cannot be swallowed.

…13-20260905

Signed-off-by: CodeWhale Bot <bot@codewhale.net>
@cursor

cursor Bot commented Sep 5, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_279f7683-ac6e-436b-b26a-c90f933ae540)

@claude

claude Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Claude finished @Hmbown's task in 1m 50s —— View job


Review: fix(computer-use): scope HarmonyOS cleanup to owned temporary files

  • Gather context (diff vs origin/main, full prior review thread)
  • Review transport.mjs current state (post-fixup commit 29bdcf1)
  • Review exec-transport.test.mjs current state
  • Post final review

Summary: Reviewed the current head (030ff76, no changes since 29bdcf1). The correctness bug flagged independently by Copilot, Codex, and two earlier Claude passes — an unguarded finally block cleanup that could mask the real transfer/read error or turn a successful read into a rejection — is fixed and confirmed:

} finally {
  // Cleanup must not replace downloaded bytes or the original I/O error.
  await fs.promises.rm(dir, { recursive: true, force: true }).catch(() => {});
}

(crates/tui/plugins/computer-use/src/transport.mjs:128)

Cleanup is best-effort again, and since dir is now a uniquely-owned mkdtemp directory (not the shared system temp root), best-effort cleanup no longer risks the original cross-file-deletion bug. I checked the rest of transport.mjs for the same class of bug (bare rm/dirname off a shared root) — no other instance exists; tmpFile() at line 44 only creates via mkdtempSync and doesn't remove anything itself.

Outstanding, non-blocking: test-assertion gap (crates/tui/plugins/computer-use/tests/exec-transport.test.mjs:70-74)

A prior Codewhale pass flagged this and it's still present. In the cleanupFails branch, the mocked fs.rm asserts the removed path stays inside the fixture from within the mock body:

t.mock.method(fs, "rm", async (dir) => {
  assert.equal(path.dirname(dir), root, "cleanup stays inside its fixture");
  assert.ok(path.basename(dir).startsWith("cu-hdc-"));
  throw Object.assign(new Error("cleanup denied"), { code: "EACCES" });
});

Because production code does .catch(() => {}) on this same call, an AssertionError thrown here is indistinguishable from the intended "cleanup denied" error to the caller — both are swallowed silently. So if readFile ever passed the wrong directory to rm under the cleanupFails path, this test would not fail on that basis. It's a soft gap, not a blind spot: the unrelated-sentinel-file check and the non-mocked cleanup succeeds cases still catch the original wrong-directory deletion bug. To close it fully, record the path from the mock into a variable and assert on it after readFile settles, outside the try/finally/.catch, e.g.:

let seenDir;
t.mock.method(fs, "rm", async (dir) => {
  seenDir = dir;
  throw Object.assign(new Error("cleanup denied"), { code: "EACCES" });
});
// ...after awaiting/rejecting on readFile:
assert.equal(path.dirname(seenDir), root);
assert.ok(path.basename(seenDir).startsWith("cu-hdc-"));

Fix this →

Other observations (no action needed):

  • No provider/model/route-selection code is touched by this diff.
  • No secret handling, shell/exec policy, or input-validation surface is affected.
  • Note: I was unable to execute node --test locally in this sandbox (command required approval that wasn't available), so I'm relying on static analysis plus the author's reported 37/37 pass. The logic traced through manually (including the os.tmpdir/fs.rm mocking via the shared node:fs/promises module object, which transport.mjs's fs.promises.rm correctly shares) checks out.

No blocking issues. The core fix is correct, all three previously-flagged reviewer concerns are resolved, and the remaining item is a minor hardening of an already-adequate regression test.

@codewhale-agent codewhale-agent Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Codewhale review

The production change correctly scopes HarmonyOS hdc readFile temp cleanup to a dedicated mkdtemp directory and uses finally to clean up failed transfers/reads without masking original errors. Tests cover the main outcome/cleanup matrix, but one cleanup-path assertion is unobservable because production's cleanup catch swallows the mock rejection.

Findings

  • [WARNING] Cleanup path assertions in fs.rm mock are swallowed by production .catch (crates/tui/plugins/computer-use/tests/exec-transport.test.mjs:71)
    In cleanupFails=true cases, the installed fs.rm mock performs assert.equal/assert.ok inside the async function. If cleanup targets the wrong directory, these assertions reject the mock promise, but transport.mjs's finally uses .catch(() => {}), so the AssertionError is swallowed and the test still passes. The path safety check should run outside the mocked call, for example by recording the cleanup path and asserting after readFile settles.

Suggestions

  • crates/tui/plugins/computer-use/tests/exec-transport.test.mjs:71 — Record the cleanup path in a variable inside the mock and assert path.dirname and basename after ex.readFile settles. This makes a wrong cleanup target fail the test despite production's cleanup-error catch.

Assessment

Production fix is correct and scoped. The tests cover the important lifecycle paths, but the cleanup-failure branch should be strengthened so its cleanup-path assertions cannot be swallowed.


Advisory review by Codewhale (codewhale review --pr 5895 --post, head 030ff761a6fc2a1cda14fb9223e524a16abc645c). Line-specific findings are also posted as inline review comments; mechanical fixes arrive as committable suggestions you can apply from the Files tab. CODEOWNERS approval still governs merge.

t.after(() => realRm(root, { recursive: true, force: true }));
if (cleanupFails) {
t.mock.method(fs, "rm", async (dir) => {
assert.equal(path.dirname(dir), root, "cleanup stays inside its fixture");

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[WARNING] Cleanup path assertions in fs.rm mock are swallowed by production .catch

In cleanupFails=true cases, the installed fs.rm mock performs assert.equal/assert.ok inside the async function. If cleanup targets the wrong directory, these assertions reject the mock promise, but transport.mjs's finally uses .catch(() => {}), so the AssertionError is swallowed and the test still passes. The path safety check should run outside the mocked call, for example by recording the cleanup path and asserting after readFile settles.

if (cleanupFails) {
t.mock.method(fs, "rm", async (dir) => {
assert.equal(path.dirname(dir), root, "cleanup stays inside its fixture");
assert.ok(path.basename(dir).startsWith("cu-hdc-"));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Record the cleanup path in a variable inside the mock and assert path.dirname and basename after ex.readFile settles. This makes a wrong cleanup target fail the test despite production's cleanup-error catch.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Prevent HarmonyOS file-read cleanup from deleting unrelated temporary files

2 participants