Skip to content

Do not erase an approved credential on a single blob-download rejection - #2087

Closed
tyrielv wants to merge 1 commit into
microsoft:masterfrom
tyrielv:tyrielv/blob-credential-reject
Closed

Do not erase an approved credential on a single blob-download rejection#2087
tyrielv wants to merge 1 commit into
microsoft:masterfrom
tyrielv:tyrielv/blob-credential-reject

Conversation

@tyrielv

@tyrielv tyrielv commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Problem

GVFS erases the cached credential and issues git credential reject whenever an
object-download response is 401, 400, or 302. On-demand loose-blob downloads run
many at a time and share one cached credential. When one download fails - even
intermittently, or for a non-auth reason misclassified as an auth failure under
load - the erase removes a credential that sibling downloads are still using
successfully. The erase forces a re-authentication and can start a
credential-manager consent-popup storm.

The single-rejection erase has no protection: GitAuthentication.RejectCredentials
had only a guard against erasing a different credential than the one that
failed. It had no consecutive-failure gate, so one bad response among many good
ones erased a valid credential.

Fix

Gate the erase of an already-approved credential. A credential the server has
accepted at least once this generation is only erased after several consecutive
rejections with no intervening success. Any successful use resets the count.

A credential that has never succeeded (for example a genuinely expired token at
first use) is still erased on the first rejection, so normal re-authentication is
not affected.

The gate runs after the existing reload-from-store check, so a credential that
genuinely changed underneath us is still detected and adopted rather than
deferred.

Tests

Adds unit tests for the new behavior: an approved credential survives up to the
threshold, a success between rejections resets the count, and a never-approved
credential still erases on the first rejection. The full unit-test suite passes.

GVFS erases the cached credential and calls git-credential reject whenever an
object-download response is 401, 400, or 302. On-demand loose-blob downloads run
many at a time and share one cached credential. When one download fails - even
intermittently, or for a non-auth reason misclassified as auth under load - the
erase removes a credential that sibling downloads are still using successfully.
The erase forces a re-authentication and can start a credential-manager
consent-popup storm.

Gate the erase of an already-approved credential. A credential the server has
accepted at least once this generation is only erased after several consecutive
rejections with no intervening success. Any successful use resets the count. A
credential that has never succeeded (for example a genuinely expired token at
first use) is still erased on the first rejection, so normal re-authentication is
not affected.

Assisted-by: Claude Opus 4.8
Signed-off-by: Tyrie Vella <tyrielv@gmail.com>
@tyrielv tyrielv closed this Aug 13, 2026
@tyrielv
tyrielv deleted the tyrielv/blob-credential-reject branch August 13, 2026 20:44
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