fix(core): classify EACCES as permission_denied, not auth_failed - #124
Merged
Hydralerne merged 1 commit intoJul 22, 2026
Merged
Conversation
MESSAGE_PATTERNS is documented as ordered most-specific → least, but the auth rule carries a bare `permission denied` token and sits first. Node spells a filesystem permission error as EACCES: permission denied, open '/backups/openship/db.sql' so every EACCES matches the auth rule and is reported as auth_failed. The `eacces` alternative in the later permission_denied rule is unreachable, and the code documented as "authed, but not allowed to do the thing (e.g. write path)" never fires for the exact case it names. Two ways of saying the same thing already disagreed: EACCES: permission denied, open '/x' -> auth_failed Error: access denied writing to /x -> permission_denied EROFS: read-only file system -> permission_denied Since UI copy is keyed off `code`, an operator whose backup destination isn't writable is told their credentials were rejected, and goes off rotating SSH keys when the fix is chown on the destination path. Match the errno tokens ahead of the auth rule. EACCES/EROFS never appear in SSH's "Permission denied (publickey)", so the two stay apart — the existing auth_failed expectations are unchanged, and a test pins them.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
MESSAGE_PATTERNSinpackages/core/src/connectivity.tsis documented as "Ordered most-specific → least", but the auth rule carries a barepermission deniedtoken and sits first:Node spells a filesystem permission error as
EACCES: permission denied, <syscall> '<path>'— which containspermission denied, so it matches the auth rule first.Consequences:
EACCESis classifiedauth_failed.eaccesalternative in thepermission_deniedrule is unreachable for real Node fs errors.permission_denied— documented as "authed, but not allowed to do the thing (e.g. write path)" — never fires for the exact case its comment names.Executed on
main:So two ways of saying the same thing already disagree today.
Impact
ConnectivityCodeexists so "UIs can map copy once", per the type's own comment — the code drives what the operator is told. An operator whose backup destination directory isn't writable gets "credentials rejected" and goes off rotating SSH keys or re-entering a password, when the actual fix ischown/chmodon the destination path.Fix
Match the errno tokens ahead of the auth rule:
EACCES/EROFSnever appear in SSH'sPermission denied (publickey)orPermission denied, please try again, so the errno rule can't swallow genuine auth failures. The auth rule keeps itspermission deniedtoken for those.Tests
Two cases added to the existing
packages/core/test/connectivity.test.ts(@repo/core101 → 103):permission_deniedforEACCES(open + mkdir) andEROFSauth_failedstill forPermission denied (publickey)andPermission denied, please try again— pinning the boundary so the new rule can't widen laterVerified against the unfixed source: the filesystem case fails, the SSH guard passes either way. All pre-existing expectations in that file are untouched.
Full suite:
bun run test→ 5/5 turbo tasks successful (api 714, adapters 240, core 103, db 25, dashboard 17).