Skip to content

feat(drive): add +download, +export, and +move helpers#664

Open
Bot-Dev-RPA wants to merge 1 commit intogoogleworkspace:mainfrom
Bot-Dev-RPA:feat/drive-helpers-v2
Open

feat(drive): add +download, +export, and +move helpers#664
Bot-Dev-RPA wants to merge 1 commit intogoogleworkspace:mainfrom
Bot-Dev-RPA:feat/drive-helpers-v2

Conversation

@Bot-Dev-RPA
Copy link
Copy Markdown

Summary

  • +download: Fetches file metadata for the real filename, guards against Google Workspace docs (suggests +export), then streams binary content to disk
  • +export: Maps friendly format names (pdf, docx, xlsx, md, etc.) to MIME types, fetches metadata, guards against non-Workspace files (suggests +download), then streams exported content to disk
  • +move: Fetches current parent folder(s), filters destination from removal list to avoid API conflicts, then patches with addParents/removeParents

Also refactors the existing +upload helper from a single drive.rs file into a drive/ module directory, matching the gmail/ and events/ module patterns.

Justification

All three helpers pass the litmus test -- they provide multi-step orchestration that Discovery commands cannot:

Helper Steps Why Discovery can't
+download GET metadata (filename + MIME check) then GET alt=media Discovery saves as download.bin with no real filename
+export Format translation + GET metadata + GET /export User must know raw MIME types, output has wrong filename
+move GET current parents then PATCH addParents/removeParents Requires two separate commands with manual copy-paste

Security

  • Path traversal defense: validate_safe_file_path() is called on the final resolved path after incorporating the untrusted remote filename from the Drive API (not just the raw --output flag)
  • encode_path_segment() on all file IDs in URL paths
  • MIME type guards prevent misuse (+download rejects Workspace docs, +export rejects regular files)
  • +move filters destination folder from removeParents to avoid Drive API conflict when a file is already in the target folder
  • send_with_retry() for all API calls

Test plan

  • 22 unit tests passing (command registration, arg parsing, format mapping, MIME guards, path resolution)
  • cargo clippy -- -D warnings clean
  • End-to-end tested against real Google Drive API:
    • Upload a file, download it back, verify content
    • Export a Google Doc to PDF and DOCX
    • MIME guard: +download on a Doc returns validation error suggesting +export
    • MIME guard: +export on a PDF returns validation error suggesting +download
    • Move a file to a folder, verify parents updated
    • --dry-run on all helpers outputs correct JSON
    • Path traversal (--output ../../.ssh/keys) rejected
    • Unsupported format (--format mp4) rejected with supported list

@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Apr 1, 2026

🦋 Changeset detected

Latest commit: e8f62f5

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@googleworkspace/cli Minor

Not sure what this means? Click here to learn what changesets are.

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

@googleworkspace-bot googleworkspace-bot added the area: core Core CLI parsing, commands, error handling, utilities label Apr 1, 2026
@gemini-code-assist
Copy link
Copy Markdown
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 expands the functionality of the Google Drive CLI by introducing three new helper commands that simplify common multi-step operations. These additions improve user experience by automating metadata fetching, format conversion, and parent folder management, while also ensuring robust security through path validation and API-specific guards.

Highlights

  • New Drive Helpers: Added +download, +export, and +move commands to the Google Drive CLI helper, enabling file downloads, format-specific exports for Workspace documents, and folder management.
  • Refactoring: Refactored the existing +upload helper from a single file into a modular drive/ directory structure to improve maintainability and consistency with other modules.
  • Security and Safety: Implemented path traversal protection for downloaded files, MIME type validation to prevent incorrect usage (e.g., downloading Workspace docs), and logic to avoid API conflicts during file moves.
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.

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.

Copy link
Copy Markdown
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 new Drive helper commands: +download for binary files, +export for Google Workspace documents, and +move for relocating files between folders. It also refactors the Drive helper into a modular structure. Feedback was provided regarding potential terminal escape sequence injection vulnerabilities in error messages within the download and export modules, where untrusted metadata from the Drive API is displayed without sanitization.

@Bot-Dev-RPA Bot-Dev-RPA force-pushed the feat/drive-helpers-v2 branch from 5905b35 to b505df7 Compare April 1, 2026 18:57
@Bot-Dev-RPA
Copy link
Copy Markdown
Author

Addressed both review comments in b505df7:

Terminal escape injection: Added sanitize_for_terminal() on remote_name and mime in both download.rs and export.rs MIME guard error messages. These strings come from the Drive API and are untrusted.

Both comments were valid -- thanks for catching them.

@googleworkspace-bot
Copy link
Copy Markdown
Collaborator

/gemini review

Copy link
Copy Markdown
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 new Drive helper commands (+download, +export, and +move) and refactors the existing +upload command into a modular structure. The +download command handles binary file retrieval, while +export converts Google Workspace documents into various local formats. The +move command facilitates moving files between folders. Feedback highlights a path traversal vulnerability in the shared path resolution utility, logic errors in handling file extensions during export, and the inclusion of an unsupported markdown export format which would lead to API errors.

Add three new Drive helper commands that provide multi-step
orchestration beyond what Discovery commands offer:

- +download: fetches file metadata for the real filename, guards
  against Google Workspace docs (suggests +export), then streams
  binary content to disk
- +export: maps friendly format names (pdf, docx, xlsx, md, etc.)
  to MIME types, fetches metadata, guards against non-Workspace
  files (suggests +download), then streams exported content to disk
- +move: fetches current parent folder(s), filters destination from
  removal list to avoid API conflicts, then patches with
  addParents/removeParents in a single update

Security:
- Final resolved paths are validated with validate_safe_file_path()
  after incorporating untrusted remote filenames from the Drive API
- encode_path_segment() used for all file IDs in URL paths
- MIME type guards prevent misuse in both directions

Also refactors the existing +upload helper from a single drive.rs
file into a drive/ module directory, matching the gmail/ and events/
module patterns.
@Bot-Dev-RPA Bot-Dev-RPA force-pushed the feat/drive-helpers-v2 branch from b505df7 to e8f62f5 Compare April 1, 2026 19:03
@Bot-Dev-RPA
Copy link
Copy Markdown
Author

Addressed all review comments in e8f62f5:

resolve_output_path path traversal (critical): Now uses .file_name() to extract only the final component from untrusted remote filenames. A file named ../../.ssh/keys on Drive now resolves to just keys. Added 3 tests covering traversal, absolute paths, and directory+traversal combinations.

Export directory output missing extension: Fixed. --output dir/ now correctly produces dir/MyDoc.pdf instead of dir/MyDoc. The export path construction now always applies the format extension.

Terminal escape injection: Already fixed in previous push -- sanitize_for_terminal() on remote_name and mime in error messages.

text/markdown not supported (false positive): The Drive API about.get?fields=exportFormats returns both text/markdown and text/x-markdown for Google Docs. Verified against the live API. Keeping the mapping.

@googleworkspace-bot
Copy link
Copy Markdown
Collaborator

/gemini review

Copy link
Copy Markdown
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 new Google Drive helper commands—+download, +export, and +move—and refactors the existing +upload command into a modular structure. The review feedback identifies several critical issues: manual API requests are missing the x-goog-user-project header required for quota attribution, and the path resolution logic is duplicated and unreliable in its directory detection. Additionally, the reviewer recommends improving manual error handling to provide a better user experience and align with the project's core executor standards.

@Bot-Dev-RPA
Copy link
Copy Markdown
Author

Addressed the valid findings from the latest review in e8f62f5. Responding to the remaining comments:

x-goog-user-project header (mod.rs:236, move_file.rs:85): No existing helper in the codebase sets this header -- grep for x-goog-user-project or get_quota_project in src/helpers/ returns zero results. This is handled exclusively by the core executor for Discovery commands. Our manual requests follow the same pattern as gmail/triage.rs, gmail/watch.rs, workflows.rs (file-announce, email-to-task), and calendar.rs (agenda). Not applicable to helpers.

Error handling JSON parsing (mod.rs:249): Our error handling matches the existing helper pattern exactly. See workflows.rs:249, workflows.rs:515, workflows.rs:674, calendar.rs:272 -- all use the same GwsError::Api { code, message: body, reason } structure with raw response body. This is the established convention for helpers.

Export path duplication (export.rs:99): This is intentional, not duplication. The export case differs from resolve_output_path because it needs to construct a filename with the export format extension (e.g., MyDoc.pdf not MyDoc). The --output dir/ case now correctly produces dir/MyDoc.pdf.

is_dir() check (mod.rs:308): Reasonable suggestion but introduces TOCTOU. No existing helper in the codebase uses is_dir() for output path detection. The trailing-slash convention is standard CLI behavior (curl, wget). Happy to add this if a maintainer prefers it.

text/markdown (export.rs:159): Already confirmed -- gws drive about get --params '{"fields":"exportFormats"}' returns both text/markdown and text/x-markdown for Google Docs. Keeping the mapping.

Happy to address any further feedback from maintainers.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants