Thanks to visit codestin.com
Credit goes to github.com

Skip to content

🤖 fix: report backup repository access denial instead of a login failure - #4226

Merged
ibetitsmike merged 3 commits into
mainfrom
mike/backup-access-denied-message
Sep 13, 2026
Merged

🤖 fix: report backup repository access denial instead of a login failure#4226
ibetitsmike merged 3 commits into
mainfrom
mike/backup-access-denied-message

Conversation

@ibetitsmike

@ibetitsmike ibetitsmike commented Sep 13, 2026

Copy link
Copy Markdown
Contributor

Summary

When the backup repository refuses a credential the host already accepted, the Settings > Backup section now says so, naming the refused credential and quoting the remote's own reason, instead of telling the user to run gh auth login.

Background

With a wrapper-managed gh (for example on a Coder workspace), gh auth status succeeds, but pushing to a backup repository the token cannot write returns remote: Write access to repository not granted. followed by The requested URL returned error: 403. runGitWithCredentialLadder matched that as an authentication failure and threw the fixed message "Could not authenticate to the backup repository. Check your SSH key or gh auth login", sending a logged-in user to log in again. The thrown cause was also only the ambient rung's failure, so the gh rung's informative denial disappeared whenever the ambient rung failed differently (for example "could not read Username ... terminal prompts disabled").

Implementation

  • credentials.ts: ACCESS_DENIED_PATTERN (403, "Write access to repository not granted", "Permission to X denied", "Repository not found", read-only deploy key) selects, among all recorded rung failures in ladder order, the first the remote recognised and refused. The diagnostic line that matched the classifier (a remote: or ERROR: line, else the fatal: line) and the credential label go into the message. Pure login failures keep the existing message. The error code stays AUTH_FAILED, so there is no IPC or schema change and the instanceof checks in gitRepo.ts are unchanged.
  • src/constants/backup.ts: shared BACKUP_CREDENTIAL_LABELS, used by the backend message and by BackupSection.tsx (replaces the local getCredentialLabel).
  • Tests: three new behavioral cases in credentials.test.ts (a 403 denial names the gh rung and quotes the reason; the denying rung wins over a credential-less ambient rung; an ssh ERROR: Permission to ... denied names the ssh rung) plus a login-guidance assertion on the existing exhausted-ladder case.

Validation

  • Remote dogfood UAT (Coder Agents) on this exact head: 403 denial on a read-only public repository via "Back up now", 404 "Repository not found" via Validate, the login message with no credential available at all (credential-stripped server), the network error for an unreachable host, a successful backup to a writable repository, rendering at 1280 px and 375 px, and the ssh rung denial once known_hosts was populated. All passed.
  • Red-green: disabling the access-denied selection fails exactly the three new tests.

Risks

Low. Classification only changes which message is thrown after every rung has already failed; ladder order and retry behaviour are unchanged. The one widening is that a read-only deploy key ("marked as read only") now counts as an auth failure, so the ambient rung gets a turn instead of the raw git error surfacing.

Follow-up (pre-existing, out of scope)

UAT also found that an ssh host-key verification failure (Host key verification failed, here from coder gitssh without a known_hosts entry) still surfaces raw multi-line stderr in the error area. That path matched no classifier before this PR either and is untouched here; it deserves its own classifier and message.

Delivery record (reviews, UAT, CI)

Reviews (process limit: 6 completed code, security, and advisory reviews per PR; 7 completed, see note)

# Kind Head Reviewer Findings Disposition
1 Code (automatic) 42c9038c6 Codex (request, verdict) none ("Didn't find any major issues", reviewed commit 42c9038) clean, no threads
2 Security (automatic) 42c9038c6 Codex (result) none clean
3 Advisory (fresh clean-context final reviewer) 42c9038c6 Xum read-only review sub-agent P2: remoteReason() quoted the first remote: line, which could be server progress rather than the denial. P3: a bare HTTP 403 treated as proof that re-authenticating cannot help. Recommendation: specific blocker on the P2. P2 fixed in 1adb0ed5d (quote the remote line that matched the classifier; new test; red-green verified). P3 was first rejected with reasoning (401 vs 403), then fixed in a56ddd6a6 after Codex raised the same point: the "signing in again will not help" sentence is gone.
4 Code (automatic) 1adb0ed5d Codex (request, review) P2 thread: a progress remote: line could be quoted over a matching fatal: 403 line. P2 thread: bare 403 / not-found treated as proof the credential was accepted. Both fixed in a56ddd6a6 (search remote and fatal lines for the classifier match; sentence removed); replied on both threads and resolved them.
5 Security (automatic) 1adb0ed5d Codex (result) none clean
6 Code (automatic, "New commits" trigger, not requested) a56ddd6a6 Codex (summary row completed 02:16:19Z; 👍 reaction 02:17:16Z) none clean, no threads
7 Security (automatic, "New commits" trigger, not requested) a56ddd6a6 Codex (summary row completed 02:17:11Z) none clean

Process note: the six-review limit was exceeded by one. This repository's Codex integration starts a code and a security review automatically on every push ("New commits" trigger); rows 6 and 7 were not requested and cannot be suppressed without changing repository settings, which was out of bounds. No further review was requested after row 5.

Remote dogfood UAT (Coder Agents, vibe-coding template; evidence kept in the driving workspace under .mux-uat/, not committed)

  • Round 1 on 42c9038c6 (remote chat c742c3f5): the remote agent's own verdict was FAIL, twice. A separate critical UAT runner re-examined the evidence, rejected duplicate and cropped screenshots, forced re-proofs, and endorsed PASS for every claim in scope: 403 denial via "Back up now", 404 "Repository not found" via Validate, login message with no credential available, network error for an unreachable host, successful backup to a writable repository, rendering at 1280 px and 375 px, ssh-rung denial after populating known_hosts. The FAIL came from one pre-existing defect outside this change (below).
  • Smoke on 1adb0ed5d: PASS, superseded by the next push.
  • Smoke-final on a56ddd6a6 (same chat, remote git rev-parse HEAD and the app version badge both confirm the SHA): PASS. 403 via "Back up now" and 404 via Validate both render the final wording; DOM checks confirm the removed sentence and gh auth login are absent. The remote checkout reported -dirty because its bun 1.2.15 rewrote bun.lock (repo pins bun 1.3.5): the diff is a configVersion header plus re-hoisting of the type-only packages @types/node and undici-types; no runtime package changed and nothing under src/ differed, so the tested build is dependency-equivalent to the committed lockfile.

Deferred, pre-existing: an ssh host-key verification failure (Host key verification failed, here from coder gitssh without a known_hosts entry) surfaces raw multi-line stderr in the Backup error area. It matched no classifier before this PR and is untouched by it. Owner: next backup follow-up PR. Trigger: add a host-key classifier and message in credentials.ts next to the network and login classifiers.

CI: on 42c9038c6, attempt 1 failed on "Codex Comments" (ran before Codex answered) and "Test / Unit" (Bun 1.3.5 segfault, zero failing tests). On a56ddd6a6, attempt 1 failed only on "Codex Comments" for the same timing reason; the failed jobs were rerun once Codex had completed.


Generated with xum • Model: anthropic:claude-fable-5-1 • Thinking: xhigh

…ailure

When the remote accepts a credential but refuses the repository (GitHub 403
"Write access to repository not granted", "Permission to X denied to Y",
"Repository not found", or a read-only deploy key), the backup ladder now
throws BackupAuthFailedError carrying the remote's own reason and the denied
credential instead of telling the user to run `gh auth login`. The denying
rung's diagnosis wins over a later rung that merely had no credential to offer,
so the informative denial is no longer lost behind the ambient rung's failure.

Credential labels move to src/constants/backup.ts so the backend message and
the Settings UI share them.
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 13, 2026

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-13T02:16:19.021848Z a56ddd6 New commits
🔒 Security Review Completed 2026-09-13T02:17:11.872786Z a56ddd6 New commits
ℹ️ 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.

@ibetitsmike

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Hooray!

Reviewed commit: 42c9038c68

ℹ️ 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".

@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review · Automatically triggered

Security review completed. No security issues were found in this pull request.

Reviewed commit: 42c9038c68

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

Server progress also arrives as remote: lines, so pick the remote line that
matched the access-denied classifier before falling back to the first one.
@ibetitsmike

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review · Automatically triggered

Security review completed. No security issues were found in this pull request.

Reviewed commit: 1adb0ed5d9

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@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: 1adb0ed5d9

ℹ️ 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".

Comment thread src/node/services/backup/credentials.ts Outdated
Comment thread src/node/services/backup/credentials.ts
…ccepted-credential claim

The classifier can match only the fatal line while an earlier remote: line is
progress, so search remote and fatal lines for the match before falling back.
A bare 403 or "not found" does not prove the credential was accepted, so the
message stops asserting that and keeps the URL and permission guidance.
@ibetitsmike
ibetitsmike added this pull request to the merge queue Sep 13, 2026
Merged via the queue into main with commit 102230b Sep 13, 2026
35 of 38 checks passed
@ibetitsmike
ibetitsmike deleted the mike/backup-access-denied-message branch September 13, 2026 07:09
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.

1 participant