Skip to content

feat(account): add Azure & GitHub OAuth sign-in and cross-fork PRs + Big Perf optimisations#40

Open
t1gu1 wants to merge 52 commits into
devlint:mainfrom
t1gu1:feat/account-github-oauth
Open

feat(account): add Azure & GitHub OAuth sign-in and cross-fork PRs + Big Perf optimisations#40
t1gu1 wants to merge 52 commits into
devlint:mainfrom
t1gu1:feat/account-github-oauth

Conversation

@t1gu1

@t1gu1 t1gu1 commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR introduces a major overhaul of the Pull Request workflow and repository management, focusing on GitHub OAuth integration, cross-fork support, Azure DevOps compatibility, and
significant performance optimizations.

🔐 GitHub OAuth & Tokenless Workflow

  • Sign in with GitHub: New device-flow authentication in Settings > Accounts.
  • Keychain Security: Tokens are stored in the OS keychain and never exposed to the frontend.
  • REST-based PR Path: Activates a new tokenless REST path that removes the requirement for the gh CLI for core PR actions (listing, creation, merging, etc.).
  • Cross-Fork Support: Seamlessly handles PRs between forks and their upstream repositories, including listing and creation.

🏢 Azure DevOps Integration

  • Full Lifecycle Support: New AzureProvider for PR listing, creation, merging, and checkout.
  • Rich Features: Support for PR comments, CI check status (branch-policy evaluations), and reviewer votes/reviews.
  • Auto-Refresh: Implemented automatic access token refresh for uninterrupted workflows.

⚡ Performance & Responsiveness

  • PR Cache (SWR): Disk-persisted "Stale-While-Revalidate" cache for PR lists and details. The UI now paints instantly using cached data while revalidating in the background.
  • Async Backend: Converted Tauri commands to async, offloading blocking Git and network operations to background threads to prevent UI freezes.
  • libgit2 Fast Path: Optimized git_status using in-process libgit2, significantly reducing IPC overhead compared to spawning CLI processes.

🎨 UI/UX Enhancements

  • Standardized Avatars: Centralized avatar styling for a consistent "disk" look across all views.
  • Enhanced Status Visibility: Integrated CI check status directly into the sidebar's "waiting dot".
  • Smart Link Handling: External Markdown links now open in the system browser rather than the app webview.
  • Fluid Loading: Replaced manual refresh buttons with automatic spinners during background data fetches.

🛠 Other Improvements

  • GH CLI Guidance: Automatically guides users to account settings when gh CLI auth errors are detected.
  • Standardized "Open in Browser" labels and icons across all forge providers.
  • Optimized PR data loading to reduce redundant API calls.

!! IMPORTANT !!

For that PR i use a Github Client ID that i created to make the github auth works.
But it should the yours/the gitwand project.

Simply go here https://github.com/settings/developers and click on the top right button New Oauth App.
Be sure to have the ---> device flow enabled <---
Then use the given CLIENT ID instead of the one that i used.


Kinda the same thing with Azure

Go to: https://portal.azure.com/#view/Microsoft_AAD_RegisteredApps/ApplicationsListBlade

Steps:

  1. Name it (e.g. "GitWand").
  2. Supported account types → Accounts in any organizational directory (multi-tenant — matches organizations endpoint in code).
  3. Register. Copy Application (client) ID = your GITWAND_AZURE_CLIENT_ID.
  4. Left nav → Authentication → Allow public client flows = Yes (required for device flow). Save.

Why

  • Don't love to have to install gh and configure it (Less pain with oauth for the user)
  • The possibility to create and see fork PRs for a project is a game changing for contributors (me)
  • Azure was a missing platform/forge use a lot by entreprises
  • The app was kinda slow when we changed of context (The optimization part)

PRs is so a nice feature but without the forks functionality, i could not use it. :(

Test plan

  • Sign in with GitHub from Settings and confirm the account persists.
  • Open the PR view from a forked repo and verify the target selector defaults to upstream.
  • Create a same-repo PR and confirm no regression.
  • Verify the new UI strings render in each supported locale.

Tests that i didn't do (If you have these in your setup, could be nice if you test it)

  • Create a cross-fork PR via both the REST and gh code paths. (Edit: I got some time to test it and add some fixes ✅ )
  • Test the changes with GitLab
  • Test changes with BitBucket

Notes:

  • I dont try back when authenticated with gh (Edit: Done ✅ )
  • I dont test with the other services like Gitlab and Bitbucket
  • This PR request was made from GitWand from the fork! ✅

How it looks

image image

Here the icon change from github to Azure (I fix it for every platforms)

image

PRs comments

image

⚙️ Enterprise prerequisites (maintainer note)

Hands-on testing surfaced two org-policy gates that are not bugs but must be
documented, since the stated target for this feature is enterprises. In locked-down
tenants the OAuth/device-flow sign-in will be blocked until the org pre-approves the
GitWand app:

  • GitHub — OAuth App access restrictions. If the organization that owns the repo
    has third-party OAuth app restrictions enabled, authenticated calls return
    403 ("the <org> organization has enabled OAuth App access restrictions") even
    with a valid token. An org owner must approve the GitWand OAuth app
    (Org → Settings → Third-party Access → OAuth app policy), or the user must request
    approval. Personal repos and unrestricted orgs work out of the box.

  • Azure DevOps / Entra ID — admin consent. If the tenant disables user consent
    for third-party apps (and/or enforces app governance / Conditional Access), the
    device-flow sign-in hits the admin-consent wall and a standard user cannot complete
    it. A tenant admin must grant admin consent for the GitWand Entra app
    (Azure Portal → App registrations → GitWand → API permissions → "Grant admin
    consent"), or approve it through app governance. We request the narrow
    user_impersonation delegated scope (rather than .default) so a standard user can
    self-consent wherever the tenant allows it.

TL;DR for enterprise rollout: an org/tenant admin should pre-approve the GitWand
GitHub OAuth app and the GitWand Entra app once; after that, users sign in normally.

Guillaume Huard Hughes added 9 commits June 5, 2026 06:00
🪄 Commit via GitWand
Quand `origin` est un fork, la vue de création de PR propose un sélecteur
de dépôt cible (parent upstream ou fork), avec upstream par défaut. Gère
les chemins REST (`fork-owner:branch`) et `gh` (`--repo`) ; nouvelle
commande `gh_fork_info` pour détecter la relation de fork.

🪄 Commit via GitWand
Users can now configure the language for AI-generated pull request titles and
descriptions to be either English (default) or match the app's UI locale.

Additionally, this commit replaces direct `window.open` calls with
`openExternalUrl` across various components. This ensures that external
links open correctly via the operating system's default browser when running
in the Tauri webview, where `window.open` is a no-op.
When the current repository is a fork, the PR list fetched via the GitHub
REST API will now include pull requests opened from the fork to its
upstream parent repository.

Operations like viewing PR details, diffs, checks, or merging will
also transparently resolve to the correct upstream repository for these
cross-repository pull requests, providing a more complete workflow.
Remove the unused `parent_default_branch` field from the `ForkInfo` struct.
Introduce an `upstream_parent` helper function to centralize the logic for
detecting when a repository is a fork of an upstream parent. This simplifies
PR listing and detail views for cross-repository pull requests.

Additionally, streamline the PR creation view for fork targets and standardize
external URL opening in `App.vue` for consistency.
When the GitHub CLI (`gh`) is not installed, the PR list sidebar now displays an enhanced error message including a hint and a button. Clicking this button directly opens the 'Accounts' tab in Settings. This helps users discover and configure GitHub authentication via the app's built-in OAuth process as an alternative to manual `gh auth login`.

This commit also introduces a generic mechanism to open the Settings panel to a specified tab and expands the range of available tab identifiers.
Set GitHub as the default forge when adding a new account and hide the
manual username input field for GitHub accounts. This anticipates
fetching the username via OAuth, removing a redundant input step for users.
Introduce Azure DevOps as a new forge, allowing users to authenticate via
Entra ID OAuth device flow and manage pull requests directly within the app.

This includes:
- **Entra ID Device Flow:** Authenticate using "Sign in with Azure" in Settings > Accounts, storing the token in the OS keychain.
- **Pull Request Workflow:** List, view details, diffs, files, create, merge, checkout, and convert draft PRs to ready states via the Azure DevOps REST API (v7.1).
- **Auto-detection:** Automatically identify Azure DevOps remotes (`dev.azure.com`, `*.visualstudio.com`).
- **Partial PR Intelligence:** Conflict preview and hotspot analysis are reused (local git-based).

Comments, reviews, reviewer pickers, and CI checks are not yet implemented.
Update 'Open in Browser' buttons to dynamically display the active forge's name (e.g., GitHub, GitLab) instead of a hardcoded 'GitHub'. The GitHub-specific icon has also been replaced with a generic external link icon. This ensures accurate labeling and visual representation across all supported code hosting platforms.
```
@t1gu1 t1gu1 force-pushed the feat/account-github-oauth branch from 89a080c to fe8d7f4 Compare June 5, 2026 11:50
@t1gu1 t1gu1 changed the title feat(account): add GitHub OAuth sign-in and cross-fork PRs feat(account): add Azure & GitHub OAuth sign-in and cross-fork PRs Jun 5, 2026
Guillaume Huard Hughes added 2 commits June 5, 2026 09:36
Prevent clicking http(s) links within rendered PR descriptions and comments from navigating the Tauri webview. Instead, intercept these clicks and open the URLs in the user's default external browser.
Azure DevOps access tokens expire after approximately 1 hour, leading to API failures and often returning an HTML sign-in page rather than a 401 status.

This change introduces an automatic token refresh mechanism to keep Azure DevOps sessions alive:
- Persists the Entra ID refresh token alongside the access token in the OS keychain.
- The `az_json` API wrapper detects authentication failures (including HTML responses) and attempts to exchange the refresh token for a new access token.
- If successful, the API request is retried with the new token, preventing frequent re-authentication and improving the reliability of the Azure DevOps integration.
@t1gu1

t1gu1 commented Jun 5, 2026

Copy link
Copy Markdown
Contributor Author

I fix some issue that i found.

  • When we clicked on a PR description link, it was open inside Gitwand instead of a browser.
  • Diff changes were not display correctly in the PRs list
  • Performance was not crazy when trying to see PRs and PR detail (And no caching)
  • Profile icons was not using the new style

Guillaume Huard Hughes added 6 commits June 5, 2026 10:15
Azure DevOps PR objects lack inherent file/line change statistics and organize comments into "threads."

This change:
- Populates PR `changed_files`, `additions`, and `deletions` by performing a local `git diff --numstat` between the source and target branches. This ensures the Files tab badge and related stats are correctly displayed.
- Adds support for listing and creating general PR comments, mapping Azure's "threads" into a flat comment list for the frontend.
- Synthesizes globally unique comment IDs for Azure threads to avoid collisions.

This enhances the Azure DevOps integration by providing previously missing PR comment functionality and improving the detail view with accurate file change statistics.
Azure DevOps integration now includes:
- **CI checks:** Fetches Azure branch policy evaluations (e.g., build validation, required reviewers) and maps them to CI checks, providing accurate status for merge readiness.
- **Reviews:** Retrieves Azure reviewer votes (approve, changes requested) and maps them to PR reviews, enabling users to submit votes and see approval status.

These enhancements complete key aspects of the Azure DevOps PR workflow, ensuring the merge-readiness chip accurately reflects both build and approval states.
…ewer status

This change refines Azure DevOps PR merge readiness checks by:
- Ensuring reliable policy evaluation fetching through explicit API version pinning (`7.1-preview.1`).
- Clarifying reviewer requirements by automatically spelling out policy names like "At least N reviewer(s) must approve".
- Introducing a fallback mechanism to surface "Waiting for reviewer approval" or "Changes requested" when explicit policy evaluations are unavailable.
- Updating the frontend to display specific failing/pending check names in the merge readiness banner, providing clearer reasons for unready PRs.
This change enhances the Azure DevOps PR experience by:

- Introducing a derived `review_decision` based on reviewer votes, which, along with merge status, powers a new yellow "waiting" dot in the PR list sidebar to quickly identify PRs needing attention.
- Calculating `additions` and `deletions` locally via `git diff --numstat` for each PR, as Azure's API does not provide these statistics directly on the PR object.
- De-duplicating policy names in merge readiness checks to avoid redundant entries when Azure reports the same policy multiple times.
This change improves the Pull Request experience across supported forges by:
- Reducing redundant `git fetch` calls for PR lists, fetching only on the first page during pagination.
- Deriving `review_decision` for GitHub PRs from `requested_reviewers` to enable accurate waiting status.
- Calculating additions and deletions locally for GitHub PRs, as they are absent from the list API.
- Refining the CI check evaluation logic to more accurately determine blocking checks for merge readiness.
This change enhances the GitHub Pull Request experience by:
- Fetching CI status rollups for PRs using a single batched GraphQL query, as
  the REST list API does not include this information.
- Incorporating the CI status into the PR list sidebar's "waiting" dot logic,
  allowing users to quickly identify PRs with pending or failing checks.
@t1gu1 t1gu1 marked this pull request as draft June 5, 2026 14:59
Guillaume Huard Hughes added 6 commits June 5, 2026 11:20
This change enhances the GitHub Pull Request detail view by displaying all associated comments.
- It fetches issue-level comments (general conversation comments not tied to a diff line) in addition to existing inline review comments.
- Both types are merged and presented chronologically in a new section below the PR description, offering a complete discussion history.
- The implementation includes robust API fetching via REST or `gh api` CLI fallback for unauthenticated scenarios.
This change enhances the Pull Request detail view by:
- Adding a "Go to" button next to each comment, allowing users to navigate directly to the comment's permalink on the web platform.
- Implementing platform-specific logic for these links: using direct comment URLs when available (e.g., GitHub, Bitbucket), and falling back to the PR URL with a `#note_` anchor for GitLab.
- Filtering out GitLab system notes (e.g., "changed description", label events) from the displayed comments list to ensure only actual conversation comments are shown.
This change unifies the appearance of author avatars in Pull Request components (comments, details, reviewer lists). Avatars now consistently use the outline style: a transparent fill, a deterministically colored border, and initials. This brings visual consistency with other parts of the application, such as the Dashboard and CommitGraph.
Extrait la logique dupliquée (couleur, initiales) de 9 composants
vers un composable unique pour uniformiser le rendu des avatars.

🪄 Commit via GitWand
…Request lists and detailed views, stored on disk. This significantly enhances perceived performance by:

- Instantly painting cached PR data on repo-switch or app cold start.
- Revalidating data in the background without blocking the UI.
- Displaying subtle refreshing indicators (spinners/badges) during background revalidation, distinguishing it from full-page cold loads.
- Gracefully handling offline scenarios by displaying cached data instead of empty states.

The cache includes LRU eviction and age-based pruning to manage storage footprint, and robust error handling for storage quota issues.
Move long-running Tauri commands (Azure API calls, Git operations) to background threads using `tauri::async_runtime::spawn_blocking`. This prevents UI freezes during blocking network or process I/O, maintaining application responsiveness.

A related change prevents `loadMorePrs` from firing duplicate pagination requests during SWR revalidation, avoiding redundant slow API calls.
@t1gu1

t1gu1 commented Jun 5, 2026

Copy link
Copy Markdown
Contributor Author

There is a new big change on performance side that change everything.
The app feels way faster and reactive now!

It offload blocking commands to background threads

At first, it was for the PRs but it was feeling way too nice to not extend it to all the app.


Example:

Move long-running Tauri commands (Azure API calls, Git operations) to background threads using tauri::async_runtime::spawn_blocking. This prevents UI freezes during blocking network or process I/O, maintaining application responsiveness.

A related change prevents loadMorePrs from firing duplicate pagination requests during SWR revalidation, avoiding redundant slow API calls.


It is more than 174 commands converted from sync fn → async fn across every command file.

Added to that, we added some cache on PRs to makes it feels even more reactive.
Still sync while seeing it. (We see some loading indicators)

Guillaume Huard Hughes added 2 commits June 5, 2026 12:28
Migrate `#[tauri::command]` functions to `async fn` to enable asynchronous execution. This allows these commands to yield control to the Tauri runtime during I/O operations (e.g., network requests, file system access, external process execution), preventing the UI thread from blocking and further enhancing application responsiveness.
This change improves the visual feedback for the Pull Request list. During initial data loading or background stale-while-revalidate (SWR) revalidations, the refresh button is now replaced by an active spinner. This provides a clearer indication that data is being fetched and prevents users from attempting to re-trigger a refresh while an operation is already in progress.
Guillaume Huard Hughes added 15 commits June 5, 2026 13:51
Replaces the previous custom, limited markdown renderer with the MarkdownIt library.
This change enables comprehensive Markdown formatting for pull request comments
and descriptions, including headings, lists, inline code, and fenced code blocks.

This enhances the readability and expressiveness of PR content within the application.
Ensures the CSS custom property value for the suggestion label is correctly quoted,
preventing potential parsing issues if the label itself contains special characters
or if the browser's CSS parser has issues with the double quotes within the template literal.
Introduces consistent red/yellow/green indicators for PR health in both
the list sidebar and detail view.

This change aggregates check, build, and pipeline statuses from the
respective APIs (Azure DevOps policies, Bitbucket commit statuses, GitHub
check-runs, and GitLab pipelines). It fixes previous inaccuracies where
pending or failing checks were sometimes missed, particularly for GitHub,
and uses parallel fetching for improved performance on PR lists.
```
The "no approval" message was previously shown even when all checks passed and no
changes were requested. This change hides the generic "no approval" waiting
banner in such cases, as the PR is functionally just waiting for a final merge
and isn't blocked by active work. Named reviewer policies are still surfaced.
Azure DevOps often reports the same policy twice (e.g., inherited vs. branch-level). This consolidates duplicate checks, prioritizing the most resolved status (e.g., SUCCESS over PENDING) to provide a clearer, more accurate overview of PR health.
Azure DevOps build-validation policies can report 'queued' even if the underlying build
has already completed (and possibly failed). This update fetches the actual build
outcome to ensure the PR status accurately reflects reality.

Additionally, a virtual 'Merge Conflict' check is now added to the CI tab for
unmergeable PRs. This clearly flags the critical blocker and incorporates it into
the overall merge readiness assessment.
Azure DevOps policies for builds can appear generically, leading to incorrect
de-duplication. This update ensures distinct build definitions are treated as
separate checks by including their ID in the de-duplication key.

Additionally, Azure's "Expired (Please Re-queue)" status is now recognized
and surfaced with a warning, clearly indicating that a build needs to be
re-run to resolve a merge block. This was previously treated as a generic
pending state.
Previously, draft PRs were always shown as "ok" (green) in the sidebar,
regardless of their actual CI status. This change ensures that draft PRs
also reflect their underlying CI health, providing a more accurate
visual indicator (e.g., red for failing checks).
The displayed merge status now intelligently factors in the CI state,
preventing a misleading "Mergeable" status when checks are red. It will
show "Problem detected" if CI is failing, or "Conflicting" if there are
Git conflicts.

Additionally, the merge status labels are now localized for a more
user-friendly experience.
Consolidates GitHub and Azure device authorization grant logic into a shared
`useDeviceFlowAuth` composable, improving code reuse and maintainability for
authentication workflows.

Enhances PR list performance by parallelizing diff calculations for additions
and deletions.

Optimizes markdown rendering for PR descriptions and comments by pre-rendering
HTML and centralizing external link handling, reducing re-renders and improving
UI responsiveness.

Standardizes checks for merge conflicts across PR components for consistency.
Integrates `can_merge` status into pull request details across all forges.
The merge button is now proactively disabled when the current viewer lacks
permission to merge the PR. Forges that do not cheaply expose this
information (Azure, Bitbucket) default to `None`, ensuring the UI only
gates on actual errors rather than an unknown permission.
Previously, the `can_merge` status for GitHub pull requests could be inaccurate,
especially in fork-based workflows. The logic incorrectly checked permissions
against the working directory's repository or relied on incomplete API
responses, leading to misreported merge capabilities.

This update ensures merge permissions are accurately determined by explicitly
querying the PR's actual *base* repository, where the merge operation would
occur, for both `gh` CLI and GitHub REST API paths.
The 'Open in Browser' button is now positioned more prominently at the beginning of the PR detail view's action row. Its style has also been updated from a secondary (ghost) button to a standard primary button, improving visibility and discoverability for this frequently used action.
Introduces a 5-minute background revalidation mechanism for the active PR
panel (detail view or list). This prevents data from going stale in
long-open panels by periodically refreshing the displayed information.

The revalidation is visibility-gated, meaning it automatically pauses
when the application tab is hidden and resumes when visible, adhering
to performance discipline by not consuming resources unnecessarily.
Adjusts title spacing to prevent it from consuming all available horizontal
space and ensures proper right-alignment for accompanying action elements.
@t1gu1

t1gu1 commented Jun 5, 2026

Copy link
Copy Markdown
Contributor Author

@devlint Huge PR here, but a lot of news and tweaks around PRs and a lot of optimizations!

This is a really nice PR that unlocks PRs functionalities for other platforms, forks and makes it globally more accessible.

Don't forget to read the "!! IMPORTANT !!" section of the first comment where you should take a time to replace some public CLIENT ID keys. (I mean it works with the current keys, but i think you should own these to be able to manage it more)

t1gu1 added 2 commits June 7, 2026 05:05
This change introduces "fork awareness" to `gh` CLI commands, ensuring they
correctly target the upstream parent repository for actions like listing PRs,
viewing details, and fetching comments when operating from a forked working copy.
Previously, `gh` commands might default to the fork itself, leading to
incomplete or incorrect data.

Additionally, `gh pr list` now includes additions and deletions derived from
local `git diff` for consistency with the REST API path. The `gh_pr_checks`
implementation has been refactored to use `gh api` directly for check-runs,
addressing known inconsistencies and improving reliability of `gh pr checks --json`
output across `gh` CLI versions.

A Linux-specific workaround for the Tauri desktop dev build is also added
to the README.
Previously, the Bitbucket provider's `listReviews` method was a stub, returning
an empty array. This change introduces a backend command to parse PR participants
and extract their approval or change request status, enabling the display of
actual review information in the UI.
@t1gu1 t1gu1 changed the title feat(account): add Azure & GitHub OAuth sign-in and cross-fork PRs feat(account): add Azure & GitHub OAuth sign-in and cross-fork PRs + Big Perf optimisation Jun 8, 2026
@t1gu1 t1gu1 changed the title feat(account): add Azure & GitHub OAuth sign-in and cross-fork PRs + Big Perf optimisation feat(account): add Azure & GitHub OAuth sign-in and cross-fork PRs + Big Perf optimisations Jun 8, 2026
- github_api.rs: default GitHub OAuth client_id → GitWand-owned app
- azure.rs: default Entra client_id → GitWand-owned app (was Azure CLI's)
- azure.rs: request the delegated user_impersonation scope instead of
  .default, so a standard user can consent without a tenant admin in
  locked-down enterprise tenants
@devlint

devlint commented Jun 10, 2026

Copy link
Copy Markdown
Owner

Review + hands-on testing

Thanks for this — it's a big, well-structured contribution and the code is
unusually well-commented. I pulled it locally and exercised the GitHub path
end-to-end; Azure I couldn't fully test (see below). Summary of what I found.

✅ Verified working

  • New Rust modules (github_api.rs, azure.rs) compile clean (incremental,
    through branch switches).
  • GitHub OAuth device flow works end-to-end → token stored in the OS keychain
    (gitwand:github/oauth), never logged, never returned to the frontend. 👍
  • REST routing activates correctly once the keychain token is present; the PR
    list populates via rest_list_prs (title, author, branch→base, state, CI dot).

🔴 Blockers before merge

  1. Default OAuth client_id ships the author's personal app.
    github_api.rs falls back to Ov23licwiCpPiRPRodWN and azure.rs to the
    Azure CLI's well-known id. As written, every user who doesn't set
    GITWAND_GH_CLIENT_ID authenticates against the author's app. Worse, the
    "not configured" guard tests cid.starts_with("REPLACE_WITH"), which never
    matches the real default → dead code. Need GitWand-owned OAuth/Entra apps
    baked via env at build time, and a guard that actually fires.
  2. Bearer token passed as a curl process argument (-H "Authorization: Bearer …") in both github_api.rs and azure.rs. This violates the
    AGENTS.md rule "tokens must never appear in spawned process arguments" — on
    macOS/Linux the token is visible via ps for the request's duration. Pipe
    the header via curl --config - (stdin) instead.

🐛 Confirmed by testing

  1. Cross-fork PRs always show +0 / -0. rest_list_prs computes diff stats
    via git diff --numstat origin/base...origin/head, but a fork PR's head
    branch isn't in origin, so numstat returns 0. Ironically this breaks
    exactly for the cross-fork PRs that are this PR's headline feature (every PR
    in a fork-based repo reads 0/0). Suggest pulling additions/deletions from
    the REST API (GET /pulls/{n}) instead of local numstat.
  2. Azure in locked-down enterprise tenants. The device flow requests
    .default, which triggers admin consent; in a tenant with user-consent
    disabled + third-party-app governance, sign-in is blocked outright. Since the
    stated target is enterprises, this needs documenting as a prerequisite (IT
    must pre-approve the GitWand app). A narrower delegated scope
    (user_impersonation) reduces friction where the tenant allows user consent.

🟠 Worth addressing

  • New parsing surface has no unit tests: parse_azure_remote (5 URL
    shapes), owner_repo, rollup_from_check_runs, dedupe_checks are pure and
    critical — easy regressions, please add tests.
  • Async inconsistency: azure.rs wraps blocking work in spawn_blocking,
    but gh.rs/github_api.rs run blocking curl/git directly inside async fn (occupies Tokio workers). Worth unifying.
  • git fetch origin on every first-page list load is a real network cost under
    the SWR cache revalidation.

Laurent Guitton added 5 commits June 10, 2026 15:24
The 'not configured' guard tested cid.starts_with("REPLACE_WITH"), but the
client_id() default is a real registered client_id, so the branch was
unreachable. With a guaranteed-valid default there is no unconfigured state to
surface, so drop the dead block in github_device_start / azure_device_start.
Bearer access tokens (github_api.rs + azure.rs curl_raw) and Entra form
secrets (azure.rs curl_form: refresh_token, device_code) were passed as
`-H`/`--data-urlencode` argv entries, exposing them to `ps` for the request's
duration — against the AGENTS.md rule 'tokens must never appear in spawned
process arguments'. Feed them through a `curl --config -` file read from stdin
instead (header = / data-urlencode = directives), keeping secrets off argv.
rest_list_prs filled additions/deletions via a local
`git diff --numstat origin/base...origin/head`, but a fork PR's head branch
isn't present in origin, so every cross-fork PR showed +0/-0 — ironic for the
PR whose headline feature is cross-fork support. Fetch the counts from the REST
per-PR detail endpoint instead (GitHub computes them server-side, correct
regardless of where the head branch lives), in parallel per PR. Also drops the
per-list `git fetch origin`.
The PR converted check_remote_reachable to async but left its two unit tests
calling .unwrap() on the returned future, so `cargo test` failed to compile the
whole lib-test target. Block on the future via tauri::async_runtime::block_on.
Add unit tests for the pure, regression-prone helpers introduced by this PR:
- azure.rs: parse_azure_remote (all 5 remote URL shapes + reject), urlenc,
  with_api_version, auth_failed, short_ref, map_status, map_policy_status,
  dedupe_checks, rollup_from_checks, map_vote, form_config.
- github_api.rs: rollup_from_check_runs (failure/pending/success precedence),
  json_to_pr (merged state + review-decision proxy), map_comment issue-level
  nulling, bearer_config.
@devlint

devlint commented Jun 10, 2026

Copy link
Copy Markdown
Owner

Maintainer follow-up — pushed 6 commits

I pushed the following on top of 1fda453 (maintainer edits enabled), addressing
the review blockers and the issues found while testing locally. CI test target now
compiles and passes (35 unit tests green).

Commit What
21fc473 Own OAuth client IDs + Azure scope. Default GitHub OAuth and Entra client IDs switched to the GitWand-owned apps (were the author's personal app / the Azure CLI's well-known id). Azure now requests the user_impersonation delegated scope instead of .default, so a standard user can consent without a tenant admin where the tenant allows it.
b6abdad Remove dead client_id guard. The cid.starts_with("REPLACE_WITH") "not configured" check was unreachable once the default is a real client_id — dropped it.
a34da98 Keep OAuth secrets off argv. Bearer access tokens (github_api.rs + azure.rs) and Entra form secrets (refresh_token, device_code) were passed as -H / --data-urlencode arguments, exposing them to ps. They now go through a curl --config - file read from stdin. Verified end-to-end (a 403 org-restriction response confirms the token is still transmitted).
585b27f Fix +0/-0 on cross-fork PRs. rest_list_prs computed diff stats from a local git diff --numstat origin/base...origin/head, but a fork PR's head branch isn't in origin, so every cross-fork PR read 0/0. Now fetched from the REST per-PR detail endpoint (GitHub computes it server-side), in parallel per PR; also drops the per-list git fetch origin. Verified in-app — real counts now render.
9696552 Unbreak cargo test. check_remote_reachable was made async but its two unit tests still called .unwrap() on the future, so the lib-test target failed to compile. Block on the future in the tests.
a00c06a Tests for the new parsing surface. 22 unit tests covering the pure, regression-prone helpers: parse_azure_remote (all 5 remote URL shapes), urlenc, with_api_version, auth_failed, dedupe_checks, rollup_from_checks/rollup_from_check_runs precedence, json_to_pr, map_comment, map_policy_status, map_vote, bearer_config.

I also documented the enterprise prerequisites (GitHub OAuth App access restrictions /
Azure admin consent) in the PR description.

Still open (not addressed here)

  • Async consistency: gh.rs / github_api.rs run blocking curl/git directly
    inside async fn, whereas azure.rs wraps them in spawn_blocking. Not a UI-freeze
    bug (these run off the webview thread), but worth unifying — left for a follow-up since
    it touches ~15 command signatures.

@devlint devlint left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes to gate the merge until the items below are settled. Solid,
genuinely useful work overall — most blockers are already resolved by the commits
I pushed (maintainer edits), but I'd like these confirmed/closed first.

Resolved on the branch (please review my commits)

  • Own GitHub/Entra OAuth client IDs + Azure user_impersonation scope (21fc473)
  • Dead REPLACE_WITH client_id guard removed (b6abdad)
  • OAuth secrets moved off argvcurl --config - via stdin (a34da98)
  • Cross-fork +0/-0 fixed via REST per-PR stats (585b27f)
  • cargo test unbroken + 22 parsing unit tests added (9696552, a00c06a)

Please address before merge

  1. Confirm the pushed edits read correctly to you, especially the client-id
    change and the stdin-secret refactor.
  2. Async consistency: gh.rs / github_api.rs run blocking curl/git
    directly inside async fn, while azure.rs uses spawn_blocking. Either
    unify on spawn_blocking or add a comment explicitly deferring it to a
    tracked follow-up.
  3. CI green on the new commits (test target now compiles).
  4. Enterprise prerequisites are documented in the description (GitHub OAuth
    App restrictions / Azure admin consent) — please sanity-check the wording.

Optional but recommended: the bitbucket REST path still passes its token on
argv; worth the same stdin treatment for consistency.

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.

2 participants