Repository navigation
fix: Windows consoles (PowerShell and cmd) and Drive mount consent - #1
Merged
Merged
Conversation
Interactive colab console on cmd.exe and PowerShell no longer depends on termios. It enables ANSI processing, switches the console to raw input, and translates Windows scan codes to the sequences a POSIX tty would send. colab ssh --proxy-mode reads stdin with a blocking os.read and quotes its ProxyCommand for cmd.exe. colab drivemount passes timeout_ms=600000 so the kernel does not abandon the browser consent step at 120s, runs the handshake off the websocket thread, opens the consent URL, and explains the multi-account HTTP 400 instead of dumping Google's HTML error page. Co-authored-by: János Rózsavölgyi <arlinamid@users.noreply.github.com>
arlinamid
marked this pull request as ready for review
October 7, 2026 18:20
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
Fixes Windows terminal handling so the CLI can run in PowerShell and cmd.exe, and fixes the Google Drive mount failures reported upstream. This fork's issues are disabled; the reports below are from the parent repo googlecolab/google-colab-cli.
mainalready contained the merged googlecolab#135 guard (import termiosno longer crashes every command, and/dev/ttyfalls back to stdin). That was not enough for an interactive console, forcolab ssh --proxy-mode, or for Drive mount.Upstream issues
Windows / TTY
colab --helpdies withModuleNotFoundError: No module named 'termios'becauseconsole.pyimportedtermiosat import time. Open Windows PRs that never landed: #70, #75, #84, #86, #99.msvcrt/SetConsoleMode, POSIX path unchanged).termioscrash, plusopen("/dev/tty")in Drive auth,select()on stdin incolab ssh --proxy-mode, and aKernelClientattribute error. TheKernelClientfallback is already onmain(fix: support PyPI jupyter-kernel-client>=1.0 (JupyterKernelClient rename) googlecolab/google-colab-cli#125). Theselect()fix is the still-open #158. A comment on [Bug]: Windows compatibility crashes ('termios' ModuleNotFoundError & KernelClient AttributeError) googlecolab/google-colab-cli#100 (checkinga84e094, before fix: Windows termios crash and portable Drive auth prompt googlecolab/google-colab-cli#135) confirmedtermioswas still unguarded in the PyPI release.Google Drive
colab drivemountprints the consent URL, the browser lands on the Colab success page, then the command fails withValueError: mount failedafter exactly ~120s. Not the HTTP 400 case. Reproduced on a single-account incognito window.authuser=0on the propagation request is not the cause. Overriding that parameter did not help. Thegsessioncreated atauthorize-for-drive-credentials-ephemis attributed to whichever Google account is active in the browser.login_hintonly affects the consent screen. What worked was explicitly choosing the CLI account on the account chooser. Incognito did not work in their correction.Root causes
Windows startup crash (googlecolab#78, googlecolab#100).
execution.pyimportsconnect_consoleat import time, andconsole.pyimportedtermios/ttyunconditionally. googlecolab#135 wrapped that import. Commands that do not need a TTY no longer crash. This PR keeps that guard.Interactive console still wrong on Windows (googlecolab#85, googlecolab#100). With
termiosmissing,connect_consolestayed in cooked mode. In cmd.exe and PowerShell that means:sys.stdin.read(1)does not return until Enter, so the remote shell never sees individual keys.\x03for the remote shell.SIGWINCH, so a resize never updates the remote PTY.ENABLE_VIRTUAL_TERMINAL_PROCESSINGoff, so ANSI from/colab/ttyis printed as garbage. Writing tostdout.bufferbypasses Rich, which would otherwise turn VT on for its own output.colab ssh --proxy-mode(googlecolab#100, googlecolab#158).select.select([stdin_fd], ...)only accepts sockets on Windows. It raisesOSError, the pump thread exits, and the runtime never receives input. Separately,shlex.joinquotes with single quotes, but Windows OpenSSH runsProxyCommandthroughcmd.exe, which does not treat single quotes as quoting.UserKnownHostsFile=/dev/nullis also wrong there (nul).signal.SIGHUPdoes not exist, so building the--rmsignal list by namingsignal.SIGHUPraisesAttributeError.Drive mount timeout (googlecolab#113). Current
google.colab.drive.mountcalls_message.blocking_request(..., timeout_sec=timeout_ms/1000)with the defaulttimeout_ms=120000before DriveFS starts. That 120s includes the time the user spends in the browser. When it expires,blocking_requestreturnsNone(it does not raise), DriveFS starts without credentials, andmountraisesValueError: mount failedwith an empty extra reason.colab logthen shows ~120s betweendrive_auth_neededandautomation_result. The CLI's ownexecute()timeout was already 600s (googlecolab#11); the kernel timeout was not. The handshake also ran inside the websocketon_messagecallback, so the recv loop could not deliver the kernel's result until the user pressed Enter.Drive HTTP 400 (googlecolab#103). Confirmed by the reporter's later comments, not by the original
authuser=0theory. The propagation POST returns 400 when the browser's active account is not the VM owner's account. The CLI printedresp.text, which is a full HTML error page, and then did not send acolab_reply, so the kernel waited outtimeout_msand failed with the same emptymount failed.Consent URL (googlecolab#108). The URL was only printed. Windows has no
xdg-open; the right opener isos.startfile(whatstartuses in cmd and PowerShell).What changed
src/colab_cli/terminal.py— Windows console VT + UTF-8, rawSetConsoleMode,msvcrtscan-code to ANSI translation, controlling-terminal line read (/dev/ttyorCONIN$), GUI browser open, andcmd.exevs/bin/shargv quoting.console.py— POSIXtermiospath unchanged. On a Windows TTY, raw console mode, key translation, and a size poll (noSIGWINCH). Piped stdin still usessys.stdin.readand the existingexit\nEOF behavior.ssh.py— blockingos.readinstead ofselect,join_argvfor the ProxyCommand,UserKnownHostsFile=os.devnull,SIGHUPskipped when missing.drive_auth.py/drivemount—drive.mount(path, timeout_ms=600000); propagation runs on a daemon thread; consent URL is printed and opened; the prompt names thelogin_hintaccount and points at drivemount fails with "Error propagating: 400" when the authenticated account is not authuser=0 googlecolab/google-colab-cli#103; HTTP 400 is a short account-mismatch message; a failed propagation sendscolab_replywitherrorso the kernel raisesMessageErrorinstead of hanging.--authuser Nappendsauthuserto the consent URL only when the user passes it. The default URL is not rewritten toauthuser=0(that can pin the chooser to the wrong account). The propagation request still sendsauthuser=0unless--authuseris set; drivemount fails with "Error propagating: 400" when the authenticated account is not authuser=0 googlecolab/google-colab-cli#103 showed that parameter alone does not fix the 400.What cannot be fixed in this repo
Google attributes the Drive
gsessionto the browser's active account, not tologin_hint. This CLI cannot change that. There is no fully non-interactivedrivemount: the ephemeral consent page is required. The practical workaround, now printed next to the URL, is:colab whoamiand note the email.colab drivemount -s <session>.login_hintwhile another account is active.--authuser Nis an opt-in attempt to steer the chooser. googlecolab#103 did not verify that the authorize URL honorsauthuser, so it is not the default.Verification
uv run pytest tests/— 382 passed.uv run ruff check src tests— clean.os.name == "nt"/ missingtermiosand cover: scan-code translation,CONIN$vs/dev/tty,os.startfilevsxdg-open, cmd.exe ProxyCommand quoting, blocking stdin pump (noselect.select(call), missingSIGHUP,drive.mount(..., timeout_ms=600000), consent-URL rewrite only when--authuseris set, and HTTP 400 text that names the account and does not dump the HTML page.colab drivemountwas not run. It needs a human at a TTY and a successful mount allocates a billable VM. Interactivecolab console/colab sshcannot be exercised from this Linux agent against cmd.exe or PowerShell.Manual test on a real Windows machine
Install this branch, then use both Windows PowerShell and cmd.exe (not Windows Terminal only — conhost is the case that hides ANSI unless VT mode is enabled):
Expect
--helpandversionto print with notermiostraceback, and with color if the console supports it.Interactive console (needs a live session; this allocates a VM, so
colab stopwhen finished):In both PowerShell and cmd.exe, confirm:
\x1b[A, not a local line-editor action).colabprocess immediately.echo $COLUMNSafter a resize).exitreturns to the local prompt and the local console still echoes normally afterward.SSH proxy (Windows OpenSSH):
Type into that process only if you are driving it as a ProxyCommand. The meaningful check is an
sshconfig:Then
ssh colabfrom both PowerShell and cmd.exe. Typing in the remote shell must work (previously the stdin pump died at startup). Disconnect anduv run colab stop -s win-tty.Drive (human, any OS; the Windows-specific part is the Enter prompt and the browser launch):
os.startfileon Windows).login_hintemail. Select that account on the chooser if several are signed in.Credentials propagatedandMounted at /content/drive, including when the browser step takes longer than 2 minutes (previously a hard 120s kernel timeout).uv run colab stop -s win-drivewhen done.uv run colab sessionsshould report no active sessions.