Repository navigation
fix(auth): default to classic token guidance and warn about fine-grained limits (#594) - #604
Conversation
Codex Review Summary: ❌ FailedThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
No actionable comments were generated in the recent review. Walkthrough
Merge Risk:
|
📸 UI 预览
登录页设置 · 通用
|
- CodeQL js/incomplete-sanitization: the sources-dialog has-text selector escaped only quotes; a locale title containing a backslash could escape the escape character and break the selector string. Escape backslashes and quotes together. - isDesktopBridgeOnlyDiff (CodeRabbit majors): the multiset line diff judged pure reorders as no-change, and any line merely mentioning desktopBridge/electronProxy counted as web-inert — a bridge ternary with changed web fallback values or swapped assignments would slip through as ui=false. The diff now separates additions from removals, treats a multiset-empty diff between different contents (a reorder) as non-inert, and only accepts lines shaped like bridge imports, bridge call statements, the isSupported() guard, or bare syntax; anything that assigns from the bridge or branches on it for web values stays non-inert. Verified: the #603 head/base replay still yields ui=false (its diff is purely additive bridge-shaped lines); #604 replay unchanged; node test suite passes with new reorder/ternary regression cases.
Third CodeRabbit round on isDesktopBridgeOnlyDiff — the line-shape whitelist still had three holes, all rooted in the same limitation: a multiset diff plus per-line shapes cannot see what the unchanged lines around a change mean. Replaced with a stronger formulation: - webProjection: the in-order sequence of non-bridge lines must be byte-identical in both versions. This catches pure web reorders the multiset cannot see, including reorders mixed with additive bridge calls (the line-level reorder blind spot). - guard-block analysis: every ADDED if (desktopBridge.isSupported()) block (head) and every REMOVED one (base) must contain only bridge-shaped or bare-syntax lines. Wrapping or unwrapping an unchanged web statement makes its execution conditional on the desktop bridge — web-visible, previously invisible to line shapes. - bridge call arguments are restricted to side-effect-free expressions (no nested calls, assignments or braces), so an argument cannot smuggle web-relevant side effects past the check. Multiset equality between different contents (pure reorder) now falls out of the projection comparison; byte-identical files stay inert; anything unreadable or ambiguous stays non-inert (conservative: more screenshots, never fewer). The #603 head/base replay still yields ui=false; #604 unchanged; experiment baseline unchanged; new regression tests cover guard wrap/unwrap, reorder+bridge mixes, and argument side effects.
Fourth CodeRabbit round: moving an existing guard's closing brace to
absorb (or release) an unchanged web statement left the guard count and
the web line multiset untouched, so the diff passed as web-inert while
the statement's execution became conditional in the browser.
Replaced the occurrence-flag machinery with a single recursive web
projection: bridge-shaped and bare-syntax lines are omitted; a
desktopBridge.isSupported() guard block is transparent only when its own
projection is empty, otherwise it is emitted as a guard{...} token.
Web-inertness now means the base and head projections are identical,
which uniformly covers wrapping, unwrapping, boundary moves, web
reorders, and content edits; pre-existing guards that stay untouched
compare equal on both sides. Unbalanced braces degrade conservatively
(the remaining range is emitted raw).
#603/#604 replays unchanged; experiment baseline unchanged; new
regression tests cover both brace-move directions and the untouched
pre-existing guard.
Fifth CodeRabbit round: the guard-boundary scan counted braces per raw character, so a } inside a comment or a string literal could close a guard block on the scanner's behalf. Two versions whose guard wrapped different statements could then compare equal and pass as web-inert. Added braceDeltasPerLine: a single-pass scanner that skips line/block comments and string/template literals (state carries across lines; unterminated constructs at EOF return null and fail conservatively), and projectRange now derives guard boundaries from those deltas. Comment-only lines join the structural class (they cannot render). Known heuristic edge: regex literals with unpaired braces/quotes may shift the scan and degrade conservatively. Verified: the CodeRabbit comment example and a string-brace variant are non-inert; the #603 head/base replay still yields ui=false; #604 and the experiment baseline are unchanged; the full test suite passes.
Sixth CodeRabbit round: a /}/ inside a regex literal (e.g. void /[}]/.test(language)) was still counted as a code brace, so a guard boundary could close on it and two differently-wrapped versions could compare web-equal. The scanner now recognizes regex literals with the standard previous-token heuristic (operator/opening bracket/keyword before the slash, character-class tracking inside) and skips their contents; misjudging a division as a regex is the direction that keeps braces counted, so any residual imbalance degrades conservatively. Both brace-move directions around a regex-bearing guard are covered by new regression tests; #603/#604 replays and the experiment baseline are unchanged.
Eighth CodeRabbit round: the operator whitelist included + - * % ~ ^, so
a slash after counter++ (division) was scanned as a regex start and its
closing slash swallowed the guard's closing brace, making two
differently-wrapped versions compare web-equal.
The whitelist now contains only token boundaries where a regex is the
only valid continuation (( [ { , ; = : ! & | ? > and the regex-allowing
keywords); every other slash is flagged ambiguous and the file stays
non-inert. There is no guessing path left: a slash either provably opens
a regex or the whole diff keeps its scene classification. Regression
tests cover both brace-move directions around counter++ / 2; the #603
replay, #604 and the experiment baseline are unchanged.
The incremental backward heuristics kept leaking: a line comment's body could masquerade as a token in tokenBefore (whitespace skipping crossed into comment text), and the newline handling left the scanner stuck in the line-comment state after the first //, poisoning the whole file. Both surfaced as the #603 replay regressing to ui=true. Replaced the pair of scanners with one forward pass (analyzeCode) that produces a per-character code mask (comments, strings, template literals and regex contents are unmasked; the ambiguous-slash flag and an unterminated construct at EOF mark the file unanalyzable), the per-line brace deltas, and the mask. tokenBefore is now a mask-based backward skip, so comment bodies can never masquerade as tokens regardless of formatting. Verified: the CodeRabbit comment example, a string-brace variant, and a template absorb all stay non-inert; additive bridge diffs stay inert; the #603 head/base replay is ui=false again; #604 and the experiment baseline are unchanged; the full suite passes.


Description
Resolves #594.
Background
When users use GitHub Fine-grained Personal Access Tokens (PATs) to manage stars:
DELETE /user/starred/{owner}/{repo}orPUT /user/starred/{owner}/{repo}on repositories belonging to other users or organizations often results in403 Forbidden(Resource not accessible by personal access token) or404 Not Foundif scoped via "Only select repositories" or blocked by organization PAT policies.userscope support.Changes
GitHubTokenPermissions.tsx, set the default active mode to'classic'and ordered the "Classic Token" tab first.public_repo,gist,user):https://github.com/settings/tokens/new?description=GithubStarsManager&scopes=public_repo,gist,userThis lets users generate a correctly scoped token with a single click.
zh,zh-TW,en,ja,ko,de,es,fr,pt-BR,ru).src/components/LoginScreen.test.tsxto verify default tab selection, limitation callouts, tab switching, and dynamic creation URLs.Verification
npm run check:i18n(passed)npm run typecheck(passed)npm run lint(passed)npm test -- --run(all 195 test files, 2416 tests passed)Summary by CodeRabbit