fix: accessible GitHub auth dialog + argv-form exec at three sites - #288
Open
NovakPAai wants to merge 1 commit into
Open
fix: accessible GitHub auth dialog + argv-form exec at three sites#288NovakPAai wants to merge 1 commit into
NovakPAai wants to merge 1 commit into
Conversation
Clears the last two items from the UX/server audit backlog.
GitHub device-code modal (leaderboard):
- Was a bare div with no dialog semantics. Now role="dialog" +
aria-modal + aria-labelledby, focus moved inside on open, Tab trapped
within it, Escape closes, and focus returns to whatever opened it
(guarded against the node having been replaced by render()).
- The status line is aria-live so "Code expired" / "Connection error" is
announced rather than silently repainted.
- The poll loop had a bare `catch {}`: every network failure was
swallowed and the user watched "Waiting for authorization..." until
the tries ran out, with nothing ever indicating a problem. It now
counts consecutive failures (3 → surface and stop), reports a
server-sent `error` field, and honours `slow_down` per RFC 8628 §3.5
— matching pollRepoScopeOnce() in app.js, which already did all this.
- Cancel is a real handler instead of an inline
this.parentElement.parentElement DOM walk.
Shell-string exec → argv form:
- data.js findQwenSessionByPid interpolated a pid into an `lsof …` shell
string; the sibling lsof call in getActiveSessions already used
execFileSync, so this was the outlier. stderr now suppressed via stdio
rather than a `2>/dev/null` that required a shell.
- migrate.js built `find "$path" … | wc -l` from a home path; now argv
form with the count done in JS (which also drops the pipe).
- Removed the adjacent `du -sb … || du -sk …` call entirely: its result
(totalSize) was computed and never printed. It was also wrong — BSD du
has no -b, so on macOS it always fell through to -sk and added
KILOBYTES to a byte total. Dead code hiding a unit bug behind a shell
`||`.
Verified: modal semantics/Tab-trap/Escape/focus-return driven in a real
browser; lsof argv vs shell forms confirmed to find the same session on
a process holding a matching file open; find argv form matches the old
pipe count on paths containing quotes, $ and backticks; `codbash export`
end-to-end reports 934 files against 934 actually in the archive.
vakovalskii
added a commit
that referenced
this pull request
Aug 3, 2026
Conflict in leaderboard.js: #288 replaces the inline GitHub device-code modal markup with _lbBuildAuthModal() (focus trap + Escape + focus return). Took #288 for that hunk only — resolving the whole file to either side would have dropped the other PR's work; #286's rel="noopener noreferrer" on the remaining three target="_blank" links is kept (its test asserts all four).
vakovalskii
added a commit
that referenced
this pull request
Aug 3, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Clears the last two items from the UX/server audit backlog.
GitHub device-code modal (leaderboard)
div— no dialog semantics at all. Nowrole="dialog"+aria-modal+aria-labelledby, focus moved inside on open, Tab trapped within it, Escape closes, and focus returns to whatever opened it (guarded against that node having been replaced byrender()).aria-liveso "Code expired" / "Connection error" is announced rather than silently repainted.catch {}: every network failure was swallowed and the user watched "Waiting for authorization..." until the tries ran out, with nothing ever indicating a problem. It now counts consecutive failures (3 → surface and stop), reports a server-senterrorfield, and honoursslow_downper RFC 8628 §3.5 — matchingpollRepoScopeOnce()inapp.js, which already did all of this.this.parentElement.parentElementDOM walk.Shell-string exec → argv form
The codebase already documents argv-form
execFileSyncas the injection-safe pattern (see thetarcall inmigrate.js). Three sites didn't follow it:data.jsfindQwenSessionByPidinterpolated a pid into anlsof …shell string — the sibling lsof call ingetActiveSessionsalready usedexecFileSync, so this was the outlier. stderr is now suppressed viastdiorather than a2>/dev/nullthat required a shell.migrate.jsbuiltfind "$path" … | wc -lfrom a home path; now argv form with the count done in JS (which also drops the pipe).du -sb … || du -sk …call entirely. Its result (totalSize) was computed and never printed — and it was wrong besides: BSDduhas no-b, so on macOS it always fell through to-skand added kilobytes to a byte total. Dead code hiding a unit bug behind a shell||.Today's inputs at all three sites are non-attacker-controlled (a pid parsed from
ps, a fixed home-relative path list), so this is pattern-consistency hardening rather than a live vulnerability fix.Test plan
node --test "test/**/*.test.js"— 267 passed, 1 skipped (win32-only); 10 new contract testsrole=dialog/aria-modal/aria-labelledbycorrect, focus lands on "Open GitHub", Tab cycles link→cancel→link without escaping, Escape closes, focus returns to the openerlsofargv vs shell form confirmed to find the same session id on a process deliberately holding a matching.qwen/.../*.jsonlopen (the raw outputs differ only in ephemeral socket fds, which churn between any two invocations)findargv form matches the old| wc -lcount on a tree with quotes,$and backticks in the pathcodbash exportend-to-end: reports 934 files, archive contains exactly 934Note on merge order
Touches one line that #286 also touches (
rel="noopener noreferrer"on the modal's link). The new markup here already includes that attribute, so if #286 lands first the conflict resolves to identical content.Follow-up worth doing once this queue drains:
_installModalFocusTrapinapp.jsdispatches Escape through a hardcoded if-chain of overlay ids, which is why this dialog handles its own keys instead of reusing it. Generalizing that to a close-callback would let all four dialogs share one implementation.🤖 Generated with Claude Code