From 7de2c752dbfd684136dd52f26d6c6be0f8efbad6 Mon Sep 17 00:00:00 2001 From: Merge Sim Date: Mon, 31 Aug 2026 15:53:31 -0700 Subject: [PATCH] fix(repos): recognise underscore errno families, and route runtime errors safely MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Final review found the errno-shape rule still failed open. `/^E[A-Z0-9]+$/` misses `EAI_AGAIN` and `EAI_NONAME` — real libuv codes this repo already treats as transient in ssh-connection-utils. A DNS/transport failure whose message quotes ENOENT therefore skipped the code arm, matched the message, and read as proven absence: the `.git` probe would continue into `git init` on a transient fault, in all three lanes. Underscores are now allowed. The consequence is that an unrecognised E-prefixed code counts as an errno and so is NOT absence — it biases toward refusing, which is the safe direction here and is now stated in the comment rather than implied. Only a code that is not errno-shaped at all (a domain string, or the relay's numeric -32000) falls through to the message. The runtime lane also still formatted its probe failure with `error.message` directly, so a throwing getter could escape the refusal. It uses describeError, matching the other two lanes. --- src/main/ipc/repos/proven-absence.test.ts | 12 ++++++++++++ src/main/ipc/repos/proven-absence.ts | 11 ++++++++--- src/main/runtime/orca-runtime.ts | 4 ++-- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/main/ipc/repos/proven-absence.test.ts b/src/main/ipc/repos/proven-absence.test.ts index f0d377cb4f8..18335fdadb7 100644 --- a/src/main/ipc/repos/proven-absence.test.ts +++ b/src/main/ipc/repos/proven-absence.test.ts @@ -111,4 +111,16 @@ describe('proven-absence', () => { }) expect(() => describeError(e)).not.toThrow() }) + + it('treats underscore errno families like EAI_* as authoritative', () => { + // EAI_AGAIN is a real libuv code; missing it let a transient DNS failure whose message + // quotes ENOENT read as proven absence. + for (const code of ['EAI_AGAIN', 'EAI_NONAME']) { + expect( + isProvenAbsent( + Object.assign(new Error("ENOENT: no such file or directory, stat '/x'"), { code }) + ) + ).toBe(false) + } + }) }) diff --git a/src/main/ipc/repos/proven-absence.ts b/src/main/ipc/repos/proven-absence.ts index 36daa6f6b5d..247c118d6b1 100644 --- a/src/main/ipc/repos/proven-absence.ts +++ b/src/main/ipc/repos/proven-absence.ts @@ -7,9 +7,14 @@ const ENOTDIR_MESSAGE = /^ENOTDIR: not a directory\b/ // Why shape rather than a fixed list: EVERY real errno is authoritative, not just the two we care // about — an EACCES or ELOOP is a definitive non-absence answer even when the message quotes -// ENOENT. But a wrapper attaching a domain string (`REMOTE_FS_ERROR`) is not an errno and must not -// suppress the message fallback, which is the only classification path over the SSH relay. -const ERRNO_NAME = /^E[A-Z0-9]+$/ +// ENOENT. Underscores are required: `EAI_AGAIN`/`EAI_NONAME` are real libuv codes, and missing them +// let a transient DNS failure fall through to the message and read as proven absence. +// +// An E-prefixed code we do not recognise is therefore treated as an errno, i.e. NOT absence. That +// biases toward refusing, which is the safe direction for this helper. Only a code that is not +// errno-shaped at all (`REMOTE_FS_ERROR`, or the relay's numeric -32000) falls through to the +// message — the only classification path that survives the SSH relay. +const ERRNO_NAME = /^E[A-Z0-9_]+$/ /** Whether a failed probe proves the path is absent. Never throws. */ export function isProvenAbsent(error: unknown): boolean { diff --git a/src/main/runtime/orca-runtime.ts b/src/main/runtime/orca-runtime.ts index db2651c8270..18902a58cdb 100644 --- a/src/main/runtime/orca-runtime.ts +++ b/src/main/runtime/orca-runtime.ts @@ -1278,7 +1278,7 @@ import { LEFTOVER_GIT_DIR_RETRY_HINT, repositoryCheckUnavailableError } from '../ipc/repos/repository-creation-messages' -import { isProvenAbsent } from '../ipc/repos/proven-absence' +import { describeError, isProvenAbsent } from '../ipc/repos/proven-absence' import { getWorktreeWatcherRemoval } from '../ipc/worktree-watcher-removal' import { acquireWatcherRemovalGate } from '../ipc/watcher-removal-gate' import { @@ -23925,7 +23925,7 @@ export class OrcaRuntimeService { // as "no failure" and fail open into `git init`. if (!isProvenAbsent(error)) { gitProbeFailed = true - gitProbeFailure = error instanceof Error ? error.message : String(error) + gitProbeFailure = describeError(error) } return null })