fix(repos): recognise underscore errno families, and route runtime errors safely

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.
This commit is contained in:
Merge Sim
2026-08-31 15:53:31 -07:00
parent 23dd0b01fe
commit 7de2c752db
3 changed files with 22 additions and 5 deletions
+12
View File
@@ -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)
}
})
})
+8 -3
View File
@@ -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 {
+2 -2
View File
@@ -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
})