Skip to content

feat: support GOOGLE_WORKSPACE_CLI_API_BASE to override Google API base URL#431

Open
Drew-Goddyn wants to merge 1 commit intogoogleworkspace:mainfrom
Drew-Goddyn:feat/api-relay-env-var
Open

feat: support GOOGLE_WORKSPACE_CLI_API_BASE to override Google API base URL#431
Drew-Goddyn wants to merge 1 commit intogoogleworkspace:mainfrom
Drew-Goddyn:feat/api-relay-env-var

Conversation

@Drew-Goddyn
Copy link

@Drew-Goddyn Drew-Goddyn commented Mar 12, 2026

Override the base URL for all Google API calls via GOOGLE_WORKSPACE_CLI_API_BASE.

When set, discovery document fetches, all executor-driven API requests, and Gmail helper commands (+triage, +reply, +send, +forward, +watch) route through the specified URL instead of *.googleapis.com.

export GOOGLE_WORKSPACE_CLI_API_BASE=https://my-proxy.example.com
gws gmail +triage          # fetches from my-proxy.example.com
gws drive files list       # same

When unset, behavior is unchanged — no breaking changes.

Why: In locked-down environments (corporate proxies, sandboxed CI, cloud VMs with egress restrictions), direct access to *.googleapis.com is often blocked. A transparent proxy/relay can bridge the gap, but gws had no way to route traffic through one.

What changed:

File Change
discovery.rs Route discovery doc fetches through override URL; rewrite rootUrl/baseUrl in parsed docs (both fresh fetch and cache hit)
helpers/gmail/mod.rs New gmail_api_base() reads the env var (Gmail helpers hardcode gmail.googleapis.com)
helpers/gmail/triage.rs Use gmail_api_base()
helpers/gmail/reply.rs Use gmail_api_base()
helpers/gmail/watch.rs Use gmail_api_base()
helpers/workflows.rs Use gmail_api_base()

6 files, ~45 insertions, ~16 deletions. Single squashed commit.

Related: #422 — requests native http_proxy/https_proxy support in the HTTP client. This PR provides a complementary workaround for environments where a transparent relay is available.

@Drew-Goddyn Drew-Goddyn requested a review from jpoehnelt as a code owner March 12, 2026 13:27
@changeset-bot
Copy link

changeset-bot bot commented Mar 12, 2026

⚠️ No Changeset found

Latest commit: 75c054d

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@googleworkspace-bot googleworkspace-bot added area: discovery area: core Core CLI parsing, commands, error handling, utilities labels Mar 12, 2026
@google-cla
Copy link

google-cla bot commented Mar 12, 2026

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the Google Workspace CLI by introducing a mechanism to route all Google API traffic through a user-defined relay URL. This feature is particularly beneficial for users operating in network-restricted environments, such as those behind corporate firewalls or in sandboxed cloud setups, where direct access to Google APIs might be blocked. By providing a simple environment variable, the CLI can now seamlessly adapt to these network configurations, ensuring continued functionality without requiring any modifications to the application's binary.

Highlights

  • Custom API Relay Support: Introduced the GOOGLE_WORKSPACE_CLI_API_RELAY environment variable to allow all Google API traffic to be routed through a custom relay URL, addressing connectivity issues in restricted network environments.
  • Dynamic Discovery Document Rewriting: Implemented logic to dynamically rewrite rootUrl and baseUrl within fetched and cached discovery documents, ensuring all subsequent API calls for any Google service are directed through the specified relay.
  • Gmail Helper Integration: Updated various Gmail helper functions (e.g., triage, reply, watch, workflows) to respect the new GOOGLE_WORKSPACE_CLI_API_RELAY environment variable, with GOOGLE_WORKSPACE_CLI_GMAIL_API_BASE serving as a Gmail-specific override.
  • Backward Compatibility: Ensured that when the new environment variable is unset, the CLI's behavior remains identical to the current release, maintaining full backward compatibility.
Changelog
  • src/discovery.rs
    • Added support for reading the GOOGLE_WORKSPACE_CLI_API_RELAY environment variable.
    • Implemented logic to rewrite root_url and base_url in RestDescription objects, both when loading from cache and after a fresh fetch, if a relay URL is provided.
    • Modified the base URL used for fetching discovery documents to respect the GOOGLE_WORKSPACE_CLI_API_RELAY variable.
    • Updated the fallback discovery URL pattern to also use the specified relay.
  • src/helpers/gmail/mod.rs
    • Introduced a new helper function gmail_api_base() to centralize the logic for determining the base URL for Gmail API calls, prioritizing GOOGLE_WORKSPACE_CLI_API_RELAY, then GOOGLE_WORKSPACE_CLI_GMAIL_API_BASE, and finally defaulting to https://gmail.googleapis.com.
    • Updated fetch_message_metadata to use the new gmail_api_base() function.
  • src/helpers/gmail/reply.rs
    • Modified fetch_user_email to utilize gmail_api_base() for constructing the profile API endpoint.
  • src/helpers/gmail/triage.rs
    • Updated handle_triage to use gmail_api_base() for both listing and retrieving Gmail messages.
  • src/helpers/gmail/watch.rs
    • Integrated gmail_api_base() into handle_watch for constructing URLs for watch, profile, history, and message endpoints.
  • src/helpers/workflows.rs
    • Updated handle_email_to_task and handle_weekly_digest to use crate::helpers::gmail::gmail_api_base() for their respective Gmail API calls.
Activity
  • No activity has occurred on this pull request yet.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Generative AI Prohibited Use Policy, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@Drew-Goddyn Drew-Goddyn marked this pull request as draft March 12, 2026 13:28
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a GOOGLE_WORKSPACE_CLI_API_RELAY environment variable to route all Google API traffic through a custom URL, which is a valuable feature for sandboxed or proxied environments. The implementation correctly updates discovery document fetching, URL rewriting for both cached and fresh documents, and extends the logic to Gmail helper functions. The changes are well-contained and backward compatible. I've identified one area for improvement regarding code duplication in src/discovery.rs to enhance maintainability.

@Drew-Goddyn Drew-Goddyn force-pushed the feat/api-relay-env-var branch from deae628 to efd9525 Compare March 12, 2026 13:33
@Drew-Goddyn Drew-Goddyn changed the title feat: add GOOGLE_WORKSPACE_CLI_API_RELAY env var for custom API routing feat: support GOOGLE_WORKSPACE_CLI_API_BASE to override Google API base URL Mar 12, 2026
@googleworkspace-bot
Copy link
Collaborator

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a valuable feature to support custom API base URLs via the GOOGLE_WORKSPACE_CLI_API_BASE environment variable, which is particularly useful for environments with network proxies. The implementation correctly applies this override to most API calls, including those in the Gmail and Workflow helpers. However, I've identified a critical issue in how the alternative discovery URL is constructed, which will cause discovery to fail for certain services when the override is active. Additionally, there's an opportunity to improve maintainability by refactoring some duplicated code in the discovery document handling. Addressing these points will ensure the feature is robust and reliable across all Google Workspace services.

@googleworkspace-bot
Copy link
Collaborator

/gemini review

@Drew-Goddyn Drew-Goddyn force-pushed the feat/api-relay-env-var branch from 189928b to 2052ba2 Compare March 12, 2026 13:43
@googleworkspace-bot
Copy link
Collaborator

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a valuable feature to override the Google API base URL, which is particularly useful for environments with proxies. The implementation is well-integrated across various helper modules. However, I've identified a couple of critical issues in src/discovery.rs related to code duplication and flawed tests that should be addressed to ensure the correctness and maintainability of the new logic.

I am having trouble creating individual review comments. Click here to see my feedback.

src/discovery.rs (379-410)

critical

This test appears to be re-implementing the logic from fetch_discovery_document rather than testing the function itself. This means you are testing the test's implementation, not the production code. This can lead to tests passing even if the production code is broken.

The test should be refactored to call fetch_discovery_document and assert its output. You can set up a temporary cache directory and file to test the cache-hit path without making network requests.

    async fn test_api_base_override_rewrites_cached_doc() {
        let _guard = EnvVarGuard::set(
            "GOOGLE_WORKSPACE_CLI_API_BASE",
            "https://my-proxy.example.com",
        );

        let temp_dir = tempfile::tempdir().unwrap();
        // The `config_dir` function uses this env var.
        let _config_dir_guard =
            EnvVarGuard::set("GOOGLE_WORKSPACE_CLI_CONFIG_DIR", temp_dir.path().to_str().unwrap());

        let cache_dir = temp_dir.path().join("cache");
        std::fs::create_dir_all(&cache_dir).unwrap();
        let cache_file = cache_dir.join("test_v1.json");

        let doc_json = r#"{
            "name": "test",
            "version": "v1",
            "rootUrl": "https://www.googleapis.com/",
            "servicePath": "test/v1/"
        }"#;
        std::fs::write(&cache_file, doc_json).unwrap();

        // This will read from cache and should apply the override.
        let doc = fetch_discovery_document("test", "v1").await.unwrap();

        assert_eq!(doc.root_url, "https://my-proxy.example.com/");
        assert_eq!(
            doc.base_url.as_deref(),
            Some("https://my-proxy.example.com/test/v1/")
        );
    }

src/discovery.rs (414-434)

critical

Similar to the previous test, this test re-implements the logic from fetch_discovery_document instead of testing the function itself. This test is also flawed because it asserts that doc.base_url is None, which is true for the input JSON regardless of the override logic.

To properly test this, you should call fetch_discovery_document and verify that it preserves the original URLs from the cached document when the override is not set. The test should use a cached document that has a baseUrl.

    async fn test_api_base_override_unset_preserves_original() {
        let _guard = EnvVarGuard::remove("GOOGLE_WORKSPACE_CLI_API_BASE");

        let temp_dir = tempfile::tempdir().unwrap();
        let _config_dir_guard =
            EnvVarGuard::set("GOOGLE_WORKSPACE_CLI_CONFIG_DIR", temp_dir.path().to_str().unwrap());

        let cache_dir = temp_dir.path().join("cache");
        std::fs::create_dir_all(&cache_dir).unwrap();
        let cache_file = cache_dir.join("drive_v3.json");

        let doc_json = r#"{
            "name": "drive",
            "version": "v3",
            "rootUrl": "https://www.googleapis.com/",
            "baseUrl": "https://www.googleapis.com/drive/v3/",
            "servicePath": "drive/v3/"
        }"#;
        std::fs::write(&cache_file, doc_json).unwrap();

        // This will read from cache. Since the override is not set, it should return the original values.
        let doc = fetch_discovery_document("drive", "v3").await.unwrap();

        assert_eq!(doc.root_url, "https://www.googleapis.com/");
        assert_eq!(
            doc.base_url.as_deref(),
            Some("https://www.googleapis.com/drive/v3/")
        );
    }

src/discovery.rs (264-268)

high

This logic for applying the API base override is duplicated from lines 212-216. To improve maintainability, consider extracting this into a helper function that can be called from both places. For example:

fn apply_api_base_override(doc: &mut RestDescription, api_base_override: &Option<String>) {
    if let Some(ref override_url) = api_base_override {
        let base = override_url.trim_end_matches('/');
        doc.root_url = format!("{base}/");
        doc.base_url = Some(format!("{base}/{}", doc.service_path));
    }
}

You could then call apply_api_base_override(&mut doc, &api_base_override) here and in the cache-hit logic.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a valuable feature for overriding the Google API base URL, which is particularly useful for environments with proxies. The implementation is consistent and well-executed across all modified files. My review includes one high-severity suggestion to improve the new tests in src/discovery.rs by refactoring them to remove duplicated logic, which will make them more robust and easier to maintain.

@Drew-Goddyn Drew-Goddyn force-pushed the feat/api-relay-env-var branch from 2052ba2 to 356e09e Compare March 12, 2026 14:03
@googleworkspace-bot
Copy link
Collaborator

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a valuable feature by allowing the Google API base URL to be overridden via the GOOGLE_WORKSPACE_CLI_API_BASE environment variable. This is a great addition for users in environments with network proxies. The implementation is well-structured, particularly the refactoring in the Gmail helpers to use a new gmail_api_base() function.

My review includes one high-severity comment on src/discovery.rs regarding the construction of the alternative discovery URL. The current implementation uses a query parameter to pass the service name, which contradicts the code comment and may be less robust for generic proxies compared to including the service name in the URL path. The suggested change aligns the code with the comment and improves compatibility.

@googleworkspace-bot
Copy link
Collaborator

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces support for overriding the Google API base URL via the GOOGLE_WORKSPACE_CLI_API_BASE environment variable, which is a great feature for environments with network proxies. The implementation correctly handles discovery document fetching and URL rewriting. My review includes one high-severity suggestion to improve performance by caching the environment variable lookup in the Gmail helper functions, as it's currently read on every API call within that module.

@Drew-Goddyn Drew-Goddyn force-pushed the feat/api-relay-env-var branch from 13a6afc to 4fe877e Compare March 12, 2026 14:41
…se URL

Override the base URL for all Google API calls via a single env var.
When set, discovery document fetches and all API requests (including
helper commands like +triage, +reply, +send) route through the
specified URL instead of *.googleapis.com.

When unset, behavior is unchanged.
@Drew-Goddyn Drew-Goddyn force-pushed the feat/api-relay-env-var branch from 4fe877e to 75c054d Compare March 12, 2026 14:41
@googleworkspace-bot
Copy link
Collaborator

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces support for overriding the Google API base URL via the GOOGLE_WORKSPACE_CLI_API_BASE environment variable. This is a valuable feature for users operating in environments with network proxies. The implementation correctly modifies discovery document fetching and parsing in discovery.rs to use the override URL. It also consistently updates the Gmail helper modules to respect the override, replacing hardcoded URLs. The changes are well-structured, and the addition of unit tests for the new logic is commendable. I have reviewed the code and found no issues; the changes are solid and ready for merging.

@Drew-Goddyn
Copy link
Author

Note: this is related to but distinct from #422 (HTTP proxy support). That issue asks for native http_proxy/https_proxy support in the Rust HTTP client. This PR provides a different escape hatch — routing all API traffic through a custom base URL, which works for cases where a transparent proxy/relay is available. Both would be useful and they don't conflict.

@Drew-Goddyn Drew-Goddyn marked this pull request as ready for review March 12, 2026 15:31
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces the GOOGLE_WORKSPACE_CLI_API_BASE environment variable, allowing users to override the base URL for Google API calls. The changes span discovery document handling and several helper modules, replacing hardcoded URLs with a configurable base URL. The implementation also includes unit tests for the new URL rewriting logic. After a thorough review, I have no specific comments or suggestions for improvement.

@codecov
Copy link

codecov bot commented Mar 12, 2026

Codecov Report

❌ Patch coverage is 62.96296% with 40 lines in your changes missing coverage. Please review.
✅ Project coverage is 64.44%. Comparing base (7e22a3d) to head (75c054d).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
src/discovery.rs 80.00% 17 Missing ⚠️
src/helpers/gmail/mod.rs 0.00% 10 Missing ⚠️
src/helpers/workflows.rs 0.00% 5 Missing ⚠️
src/helpers/gmail/watch.rs 0.00% 4 Missing ⚠️
src/helpers/gmail/triage.rs 0.00% 3 Missing ⚠️
src/helpers/gmail/reply.rs 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #431      +/-   ##
==========================================
+ Coverage   64.40%   64.44%   +0.03%     
==========================================
  Files          38       38              
  Lines       15584    15677      +93     
==========================================
+ Hits        10037    10103      +66     
- Misses       5547     5574      +27     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: core Core CLI parsing, commands, error handling, utilities area: discovery area: distribution area: docs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants