Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/04_automation_and_utility.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
---
log:
2026-11-07: Optimized `_get_adc_credentials` in `auth.py` to stub `google.auth._cloud_sdk.get_project_id` around `google.auth.default()`. When ADC user credentials lack a `quota_project_id`, `google-auth` otherwise spawns `gcloud config get-value project` on every CLI invocation to resolve a `project_id` that `_get_adc_credentials` immediately discards (`_`).
2026-11-04: `colab drivemount` now opens the Drive consent URL in the system browser (`utils.open_url_in_browser`, also used by `colab pay`/`colab url --open`) instead of only printing it. The URL is still printed first, and a missing browser opener (SSH, containers, CI) is treated as normal: the flow keeps waiting for the user exactly as before. The prompt moved into `commands/automation.py::show_drive_auth_url` so it can be unit-tested.
2026-11-02: Added `_check_linux_keyring_locked` in `auth.py` to inspect the active Linux `SecretService` collection via `secretstorage` before `get_password`/`set_password`, warning immediately when the keyring is locked so users know why the CLI is waiting on an unlock prompt (and suggesting `--auth=adc`).
2026-10-29: Session history files are created readable only by the owner (0600), and existing ones are tightened to 0600 whenever the history logger starts.
Expand Down
17 changes: 16 additions & 1 deletion src/colab_cli/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,22 @@ def _get_adc_credentials() -> Credentials:
# That warning shows up on every single `colab` invocation under ADC,
# which is pure noise. Filter it, but keep the scope as tight as possible:
# only this exact message, only during this one call.
with warnings.catch_warnings():
#
# Additionally, when ADC user credentials lack a `quota_project_id`,
# `google.auth._default._get_gcloud_sdk_credentials` calls
# `google.auth._cloud_sdk.get_project_id()`, which spawns a
# `gcloud config get-value project` subprocess (adding 2-13s of latency on
# every CLI invocation) solely to compute the second tuple element
# (`project_id`) that we immediately discard (`_`). Stubbing
# `get_project_id` during `google.auth.default()` avoids spawning `gcloud`
# while preserving the full ADC discovery chain.
from unittest.mock import patch as _patch
from google.auth import _cloud_sdk

with (
warnings.catch_warnings(),
_patch.object(_cloud_sdk, "get_project_id", return_value="colab-cli"),
):
warnings.filterwarnings(
"ignore",
message=r"Your application has authenticated using end user credentials.*",
Expand Down
27 changes: 27 additions & 0 deletions tests/test_auth_adc.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,3 +200,30 @@ def fake_default(*args, **kwargs):
assert len(matching) == 1, (
"Unrelated UserWarnings from google.auth must NOT be suppressed."
)


def test_get_credentials_adc_skips_gcloud_project_subprocess(mocker):
"""When ADC user credentials have no quota_project_id, google.auth.default()
normally calls google.auth._cloud_sdk.get_project_id(), spawning a slow
`gcloud config get-value project` subprocess on every CLI invocation for a
project_id that _get_adc_credentials discards. Verify that subprocess path
is bypassed during google.auth.default()."""
from google.auth import _cloud_sdk

mock_creds = MagicMock()
mock_creds.requires_scopes = False

observed_project_id = []

def fake_default(*args, **kwargs):
observed_project_id.append(_cloud_sdk.get_project_id())
return mock_creds, observed_project_id[-1]

mocker.patch("google.auth.default", side_effect=fake_default)
m_subproc = mocker.patch("subprocess.check_output")
mocker.patch("colab_cli.auth.requests.AuthorizedSession")

get_credentials(provider=AuthProvider.ADC)

assert observed_project_id == ["colab-cli"]
m_subproc.assert_not_called()
Loading