fix: support gists through GitHub App login (#875)

* fix: prompt OAuth reconnection when gist credentials are rejected

* fix: support gist reads through GitHub App user grants

* test: adapt truncated gist regression to provider selection

* fix: address gist reconnect visibility and token renewal review

* fix: verify App authorization before revoking OAuth
This commit is contained in:
Thomas Durieux authored and GitHub committed 2026-10-08 10:26:13 +01:00
1 parent 4fd31a59c8
commit db966356ec
14 files changed
+283 -54

No files matched your search

+13 -8
View File
@@ -17,7 +17,7 @@
<button type="button" :aria-pressed="githubConnection === 'github-app'" :disabled="githubConnection === 'github-app'" @click="chooseGitHubConnection('github-app')"><svg class="ui-icon" aria-hidden="true"><use href="#ui-icon-shield"></use></svg> <span class="sr-only">Read-only </span>GitHub App</button>
<button type="button" :aria-pressed="githubConnection === 'oauth'" :disabled="githubConnection === 'oauth'" @click="chooseGitHubConnection('oauth')">Legacy OAuth</button>
</div>
<span class="connection-badge" v-if="isUpdate || detectedType === 'gist'">{{ detectedType !== 'gist' &amp;&amp; githubConnection === 'github-app' ? 'Read-only GitHub App' : 'Legacy OAuth' }}</span>
<span class="connection-badge" v-if="isUpdate || detectedType === 'gist'">{{ (detectedType === 'gist' ? githubConnections?.gistConnection === 'github-app' : githubConnection === 'github-app') ? 'Read-only GitHub App' : 'Legacy OAuth' }}</span>
</aside>
</div>
<input id="sourceUrl-landing" type="text" class="form-control form-control-lg" placeholder="https://github.com/owner/repository" v-field="{ state: viewState, set: value =&gt; { sourceUrl = value }, value: sourceUrl, form: null, options: { debounce: {default: 1000, blur: 0, click: 0}, updateOn: &#x27;default blur click&#x27; }, change: () =&gt; { urlSelected() } }">
@@ -27,12 +27,6 @@
<small class="form-text" style="color: var(--ink-muted);">
Repository, pull request (…/pull/42) and gist (gist.github.com/…) URLs are all accepted.
</small>
<aside class="alert alert-info" role="status" v-if="detectedType === 'gist' &amp;&amp; gistOAuthRequired">
<p>Connect GitHub OAuth to access gists. Your account and existing anonymizations stay the same, and your draft will be restored when you return.</p>
<p>GitHub's legacy OAuth connection includes write access to private repositories.</p>
<button type="button" class="btn btn-ink" @click="connectGistOAuth()" v-if="githubConnections?.oauthEnabled">Connect GitHub OAuth to access gists</button>
<p v-else>GitHub OAuth is currently unavailable. Please try again later.</p>
</aside>
<aside class="repo-access-details" aria-label="GitHub access" v-if="!sourceUrl &amp;&amp; githubConnections?.appEnabled &amp;&amp; githubConnections.appConnected &amp;&amp; githubConnections.oauthConnected">
<div class="repo-access-main">
<div class="repo-access-controls">
@@ -65,6 +59,17 @@
</div>
</header>
<aside class="alert alert-info" role="status" v-if="detectedType === 'gist' &amp;&amp; gistAppRequired">
<p>Reconnect your GitHub account to read this gist. Your draft will be restored when you return.</p>
<button type="button" class="btn btn-ink" @click="connectGistApp()">Connect GitHub App to access gists</button>
</aside>
<aside class="alert alert-info" role="status" v-if="detectedType === 'gist' &amp;&amp; gistOAuthRequired">
<p>Connect GitHub OAuth to access gists. Your account and existing anonymizations stay the same, and your draft will be restored when you return.</p>
<p>GitHub's legacy OAuth connection includes write access to private repositories.</p>
<button type="button" class="btn btn-ink" @click="connectGistOAuth()" v-if="githubConnections?.oauthEnabled">Connect GitHub OAuth to access gists</button>
<p v-else>GitHub OAuth is currently unavailable. Please try again later.</p>
</aside>
<nav class="anonymize-mobile-tabs" role="tablist" aria-label="Anonymization workspace">
<button id="workspace-settings-tab" role="tab" type="button" :aria-selected="mobilePane === 'settings'" aria-controls="workspace-settings" :tabindex="mobilePane === 'settings' ? 0 : -1" @keydown="previewTabKeydown($event)" @click="selectMobilePane('settings')">Settings</button>
<button id="workspace-preview-tab" role="tab" type="button" :aria-selected="mobilePane === 'preview'" aria-controls="workspace-preview" :tabindex="mobilePane === 'preview' ? 0 : -1" @keydown="previewTabKeydown($event)" @click="selectMobilePane('preview')">Reviewer preview</button>
@@ -86,7 +91,7 @@
<button type="button" :aria-pressed="githubConnection === 'github-app'" :disabled="githubConnection === 'github-app'" @click="chooseGitHubConnection('github-app')"><svg class="ui-icon" aria-hidden="true"><use href="#ui-icon-shield"></use></svg> <span class="sr-only">Read-only </span>GitHub App</button>
<button type="button" :aria-pressed="githubConnection === 'oauth'" :disabled="githubConnection === 'oauth'" @click="chooseGitHubConnection('oauth')">Legacy OAuth</button>
</div>
<span class="connection-badge" v-if="isUpdate || detectedType === 'gist'">{{ detectedType !== 'gist' &amp;&amp; githubConnection === 'github-app' ? 'Read-only GitHub App' : 'Legacy OAuth' }}</span>
<span class="connection-badge" v-if="isUpdate || detectedType === 'gist'">{{ (detectedType === 'gist' ? githubConnections?.gistConnection === 'github-app' : githubConnection === 'github-app') ? 'Read-only GitHub App' : 'Legacy OAuth' }}</span>
</aside>
</div>
<input type="text" class="form-control" name="sourceUrl" id="sourceUrl" :disabled="isUpdate &amp;&amp; detectedType !== &#x27;repo&#x27;" placeholder="Paste a GitHub repo or pull request URL" v-field="{ state: viewState, set: value =&gt; { sourceUrl = value }, value: sourceUrl, form: &quot;anonymize&quot;, options: { debounce: {default: 1000, blur: 0, click: 0}, updateOn: &#x27;default blur click&#x27; }, change: () =&gt; { urlSelected() } }" :class="{&#x27;is-invalid&#x27;: anonymize?.sourceUrl?.invalid}">
+5 -5
View File
@@ -12,7 +12,7 @@
<section v-if="connections.appEnabled">
<div class="connection-top"><i class="fab fa-github" aria-hidden="true"></i><span class="connection-badge">Recommended</span></div>
<div class="connection-title"><h2>GitHub App</h2><span class="connection-status" :class="{'is-connected': connections.appConnected &amp;&amp; !connections.appError}">{{ connections.appError ? 'Needs attention' : connections.appConnected ? 'Connected' : 'Not connected' }}</span></div>
<p>Read-only access to the repositories you choose.</p>
<p>Read-only access to gists and the repositories you choose.</p>
<p class="paper-inline-alert paper-inline-alert-error" v-if="connections.appError" role="alert">{{ connections.appError }}. Reconnect to restore access.</p>
<div class="connection-actions">
<a class="btn btn-ink" v-if="connections.appConnected &amp;&amp; !connections.appError" target="_self" href="/github/app/install">Manage repository access <svg class="ui-icon" aria-hidden="true"><use href="#ui-icon-external-link"></use></svg></a>
@@ -27,13 +27,13 @@
<section>
<div class="connection-top"><svg class="ui-icon" aria-hidden="true"><use href="#ui-icon-key"></use></svg><span class="connection-badge connection-badge-muted">Legacy</span></div>
<div class="connection-title"><h2>GitHub OAuth</h2><span class="connection-status" :class="{'is-connected': connections.oauthConnected}">{{ connections.oauthConnected ? 'Connected' : 'Not connected' }}</span></div>
<p>For existing OAuth anonymizations and gists.</p>
<p>For existing OAuth anonymizations.</p>
<p class="connection-help">This connection uses GitHub's broader repository permissions. Existing work keeps using it until you switch below.</p>
<a v-if="connections.oauthEnabled" target="_self" href="/github/login" class="btn btn-outline-ink">{{ connections.oauthConnected ? 'Reconnect OAuth' : 'Connect legacy OAuth' }}</a>
<div class="connection-revoke" v-if="connections.oauthConnected">
<p v-if="connections.gistCount">{{ connections.gistCount }} gist(s) still require OAuth.</p>
<p>Switch all dependent repositories before revoking access. Gists still require OAuth.</p>
<button v-if="connections.appConnected" class="connection-link connection-danger" :disabled="busy || connections.gistCount || connections.resources.some(r => r.connection === 'oauth')" @click="disconnectOAuth()">Revoke OAuth access</button>
<p v-if="connections.gistCount">{{ connections.gistCount }} gist(s) use your GitHub App connection when available.</p>
<p>Switch all dependent repositories before revoking access. Gists can use your GitHub App connection.</p>
<button v-if="connections.appConnected" class="connection-link connection-danger" :disabled="busy || connections.resources.some(r => r.connection === 'oauth')" @click="disconnectOAuth()">Revoke OAuth access</button>
</div>
</section>
</div>
+2 -2
View File
@@ -162,8 +162,8 @@
<div class="q">
<a href="/faq#permissions">What access does GitHub sign-in require?</a>
<p>
The GitHub App has read-only access to the repositories you choose.
Legacy OAuth uses broader permissions and is still needed for gists.
The GitHub App has read-only access to gists and the repositories you choose.
Legacy OAuth uses broader permissions.
Anonymous GitHub never writes to your repositories.
</p>
</div>