Skip to content

feat(apps-script): add +pull, +open, +run, +logs helpers with .clasp.json support#533

Open
qihan-bot wants to merge 4 commits intogoogleworkspace:mainfrom
qihan-bot:feat-replace-clasp
Open

feat(apps-script): add +pull, +open, +run, +logs helpers with .clasp.json support#533
qihan-bot wants to merge 4 commits intogoogleworkspace:mainfrom
qihan-bot:feat-replace-clasp

Conversation

@qihan-bot
Copy link

Summary

  • Add +pull: download Apps Script project files to local directory with filename sanitization
  • Add +open: open script editor in browser
  • Add +run: execute functions with cloud-platform scope and contextual error hints (extracts GCP project number from OAuth client ID for setup guidance)
  • Add +logs: view execution logs via processes.listScriptProcesses
  • Add .clasp.json support: auto-resolve scriptId/rootDir for all helpers
  • Add clasp_config.rs module with path traversal validation
  • Add validate_script_filename() for safe file writes during +pull
  • Regenerate skills for new helper commands

Motivation

These helpers replace the need for Google's clasp CLI tool, providing a native gws experience for Apps Script development workflows.

Test plan

  • Changeset included
  • Code compiles and passes cargo clippy
  • Skills regenerated for new helper commands

jpoehnelt-bot and others added 4 commits March 4, 2026 12:11
- Pin clawhub@0.7.0 for supply-chain safety
- Add concurrency group to prevent parallel publishes
- Add PR dry-run validation
- Guard against missing CLAWHUB_TOKEN secret
- Add changeset file
…json support

- Add +pull: download project files to local directory with filename sanitization
- Add +open: open script editor in browser
- Add +run: execute functions with cloud-platform scope and contextual error hints
  (extracts GCP project number from OAuth client ID for setup guidance)
- Add +logs: view execution logs via processes.listScriptProcesses
- Add .clasp.json support: auto-resolve scriptId/rootDir for all helpers
- Add clasp_config.rs module with path traversal validation
- Add validate_script_filename() for safe file writes during +pull
- Regenerate skills for new helper commands
@changeset-bot
Copy link

changeset-bot bot commented Mar 18, 2026

🦋 Changeset detected

Latest commit: b5c8ef8

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 Patch

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 area: skills area: distribution area: docs area: core Core CLI parsing, commands, error handling, utilities labels Mar 18, 2026
@google-cla
Copy link

google-cla bot commented Mar 18, 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 expands the Google Apps Script development experience within gws by introducing several new helper commands. These additions aim to provide a native gws alternative to the clasp CLI tool, streamlining common development workflows such as pulling code, opening the editor, running functions, and viewing logs. The changes also include robust configuration file parsing and filename validation to ensure secure and reliable operation.

Highlights

  • New Apps Script Helpers: Introduced +pull to download Apps Script project files with filename sanitization, +open to launch the script editor in a browser, +run to execute functions with cloud-platform scope and contextual error hints, and +logs to view execution logs.
  • .clasp.json Support: Added support for .clasp.json files, allowing scriptId and rootDir to be automatically resolved for all Apps Script helpers, enhancing compatibility with existing clasp workflows.
  • Security Enhancements: Implemented a new clasp_config.rs module for robust .clasp.json parsing and validation, including path traversal checks for rootDir and scriptId. A validate_script_filename() function was also added to ensure safe file writes during +pull operations.
  • Skills Regeneration: The skills documentation has been regenerated to include the newly added Apps Script helper commands.
Ignored Files
  • Ignored by pattern: .github/workflows/** (1)
    • .github/workflows/publish-skills.yml
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
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 several new helper commands for Google Apps Script (+pull, +open, +run, +logs) and adds support for .clasp.json configuration files, which is a great step towards providing a native gws workflow for Apps Script developers. The code is well-structured and includes important security validations for file and path handling.

My review focuses on a couple of critical areas. I've identified a potential panic in the +pull command's directory resolution logic and an overly restrictive filename validation that could affect compatibility with existing Apps Script projects. The suggestions provided aim to fix these issues to make the new helpers more robust and user-friendly.

Comment on lines +276 to +282
let output_dir = matches
.get_one::<String>("dir")
.map(|d| crate::validate::validate_safe_output_dir(d))
.transpose()?
.unwrap_or_else(|| {
clasp_config::resolve_dir(None).unwrap_or_else(|_| std::env::current_dir().unwrap())
});
Copy link
Contributor

Choose a reason for hiding this comment

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

critical

The logic for resolving the output directory in handle_pull has a critical flaw that can lead to a panic. It incorrectly uses clasp_config::resolve_dir, which is designed for existing input directories and will fail if the target directory doesn't exist. Additionally, the .unwrap() in the fallback logic will panic if it's unable to determine the current working directory.

This should be rewritten to use validate_safe_output_dir for all directory paths and to handle potential errors gracefully without panicking. When implementing or refining validate_safe_output_dir, please ensure that potential Time-of-check to time-of-use (TOCTOU) race conditions are acknowledged and documented as a known limitation if a full mitigation (e.g., using openat(O_NOFOLLOW)) is considered out of scope.

Suggested change
let output_dir = matches
.get_one::<String>("dir")
.map(|d| crate::validate::validate_safe_output_dir(d))
.transpose()?
.unwrap_or_else(|| {
clasp_config::resolve_dir(None).unwrap_or_else(|_| std::env::current_dir().unwrap())
});
let output_dir = if let Some(dir) = matches.get_one::<String>("dir") {
crate::validate::validate_safe_output_dir(dir)?
} else {
let clasp_dir = clasp_config::load_clasp_config()?.and_then(|c| c.root_dir);
if let Some(dir) = clasp_dir {
crate::validate::validate_safe_output_dir(&dir)?
} else {
std::env::current_dir().map_err(|e| GwsError::Validation(format!("Failed to determine current directory: {e}")))?
}
};
References
  1. When implementing file path validation, acknowledge and document potential Time-of-check to time-of-use (TOCTOU) race conditions as a known limitation if a full mitigation (e.g., using openat(O_NOFOLLOW)) is considered out of scope.

Comment on lines +258 to +266
// Allowlist: only alphanumeric, underscore, hyphen
if !name
.chars()
.all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '-')
{
return Err(GwsError::Validation(format!(
"Script file name contains invalid characters (allowed: a-z, A-Z, 0-9, _, -): {name}"
)));
}
Copy link
Contributor

Choose a reason for hiding this comment

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

high

The character allowlist in validate_script_filename is overly restrictive by disallowing dots (.) in filenames. Apps Script files can have names that include dots (e.g., a local file my.utils.js is pushed as a script file named my.utils). This restriction will cause +pull to fail for valid projects that use dots in their script file names, which is a common practice for namespacing and is supported by clasp.

To improve compatibility and support valid use cases, dots should be allowed in filenames. The existing check that prevents filenames from starting with a dot is sufficient to avoid creating hidden files. The test test_validate_script_filename_special_chars will also need to be updated to assert that filenames with dots are now valid.

Suggested change
// Allowlist: only alphanumeric, underscore, hyphen
if !name
.chars()
.all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '-')
{
return Err(GwsError::Validation(format!(
"Script file name contains invalid characters (allowed: a-z, A-Z, 0-9, _, -): {name}"
)));
}
// Allowlist: only alphanumeric, underscore, hyphen, and dot (but not as first char)
if !name
.chars()
.all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '-' || c == '.')
{
return Err(GwsError::Validation(format!(
"Script file name contains invalid characters (allowed: a-z, A-Z, 0-9, _, -, .): {name}"
)));
}

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: distribution area: docs area: skills

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants