Skip to content

feat: implement clasp#67

Open
jpoehnelt wants to merge 4 commits intomainfrom
feat/replace-clasp
Open

feat: implement clasp#67
jpoehnelt wants to merge 4 commits intomainfrom
feat/replace-clasp

Conversation

@jpoehnelt
Copy link
Member

  • 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

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 4, 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

@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 integration within the gws CLI by introducing several new helper commands that mirror clasp functionality. The changes aim to provide a more comprehensive and secure command-line experience for managing Apps Script projects, including local file synchronization, script execution, and log viewing, all while ensuring compatibility with existing project configurations and safeguarding against potential security vulnerabilities.

Highlights

  • New Google Apps Script Commands: Introduced four new commands: +pull to download 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 Configuration Support: Added support for .clasp.json files, allowing gws commands to automatically resolve scriptId and rootDir when not explicitly provided via flags, enhancing compatibility with existing clasp workflows.
  • Enhanced Security and Validation: Implemented robust path traversal validation within the new clasp_config.rs module and added validate_script_filename() to ensure safe file writes during +pull operations, preventing malicious script names from affecting the local filesystem.
  • Improved +push Command: Updated the existing +push command to leverage .clasp.json for script ID and directory resolution, making it more flexible and consistent with the new commands.
Changelog
  • .changeset/publish-skills-workflow.md
    • Added a new changeset file for publishing OpenClaw skills to ClawHub.
  • Cargo.lock
    • Updated dependencies to include open, is-docker, is-wsl, and pathdiff crates.
  • Cargo.toml
    • Added the open crate as a new dependency.
  • docs/skills.md
    • Updated the skills documentation to list the newly added gws-apps-script-pull, gws-apps-script-open, gws-apps-script-run, and gws-apps-script-logs commands.
  • skills/gws-apps-script-logs/SKILL.md
    • Added documentation for the new gws apps-script +logs command, detailing its usage, flags, examples, and tips for viewing execution logs.
  • skills/gws-apps-script-open/SKILL.md
    • Added documentation for the new gws apps-script +open command, explaining its purpose, usage, flags, and examples for opening the script editor.
  • skills/gws-apps-script-pull/SKILL.md
    • Added documentation for the new gws apps-script +pull command, including its usage, flags for script ID and output directory, and examples for downloading project files.
  • skills/gws-apps-script-push/SKILL.md
    • Modified the gws apps-script +push skill documentation to indicate that --script and --dir flags are now optional and can be resolved from .clasp.json, and updated examples accordingly.
  • skills/gws-apps-script-run/SKILL.md
    • Added documentation for the new gws apps-script +run command, outlining its usage, flags for function name and dev mode, examples, and setup requirements with contextual hints.
  • skills/gws-apps-script/SKILL.md
    • Updated the main gws-apps-script skill documentation to include the new +pull, +open, +run, and +logs subcommands in its command table.
  • src/helpers/clasp_config.rs
    • Added a new module clasp_config to handle parsing, loading, and validating .clasp.json files, including functions to resolve script IDs and root directories with security checks.
  • src/helpers/mod.rs
    • Updated the helpers module to publicly expose the new clasp_config module.
  • src/helpers/script.rs
    • Refactored the ScriptHelper to dispatch to new asynchronous handler functions for +push, +pull, +open, +run, and +logs commands.
    • Integrated clasp_config for resolving script IDs and directories in all relevant commands.
    • Implemented handle_pull to download script project files, including filename sanitization and output directory validation.
    • Implemented handle_open to open the Apps Script editor URL in the default browser.
    • Implemented handle_run to execute script functions, providing detailed error hints for common issues like scope problems or missing GCP project links.
    • Implemented handle_logs to list script execution processes.
    • Added a utility function extract_gcp_project_number to derive the GCP project ID from the OAuth client ID for improved error messaging.
    • Added file_type_to_extension helper for mapping Apps Script file types to local file extensions during pull operations.
  • src/validate.rs
    • Added a new function validate_script_filename to securely validate filenames retrieved from the Apps Script API, preventing path traversal and other unsafe file operations.
    • Added comprehensive unit tests for the new validate_script_filename function.
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.

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 Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, 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 is a significant feature addition, replacing clasp functionality by adding +pull, +open, +run, and +logs helper commands for Google Apps Script. It also introduces support for reading project configuration from .clasp.json, which is a great step for compatibility. The implementation includes robust security measures, such as validation against path traversal when pulling files and handling untrusted input from configuration files.

My review focuses on a couple of areas for improvement:

  • Performance: I've pointed out an inefficiency where the .clasp.json configuration file is read and parsed multiple times within a single command execution.
  • Correctness: I've identified an overly strict validation rule for filenames that could prevent pulling valid Apps Script projects.

Overall, this is a well-structured and security-conscious implementation. The new helper commands and contextual error hints will greatly improve the developer experience for Apps Script users.

Comment on lines +93 to +97
if let Ok(Some(config)) = load_clasp_config() {
if let Some(ref root_dir) = config.root_dir {
return crate::validate::validate_safe_dir_path(root_dir);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

This function calls load_clasp_config() again, which can lead to redundant file I/O and JSON parsing if it was already called by resolve_script_id() within the same command handler. This is inefficient.

Consider refactoring resolve_dir and resolve_script_id to accept an optional ClaspConfig argument. The caller (e.g., handle_push in script.rs) could then load the configuration once and pass it to both functions.

Example refactoring:

// In clasp_config.rs
pub fn resolve_dir(explicit_dir: Option<&String>, config: Option<&ClaspConfig>) -> Result<PathBuf, GwsError> {
    if let Some(dir) = explicit_dir {
        return crate::validate::validate_safe_dir_path(dir);
    }

    if let Some(config) = config {
        if let Some(ref root_dir) = config.root_dir {
            return crate::validate::validate_safe_dir_path(root_dir);
        }
    }

    std::env::current_dir()
        .map_err(|e| GwsError::Validation(format!("Failed to determine current directory: {e}")))
}

// In script.rs handle_push()
async fn handle_push(...) -> Result<(), GwsError> {
    let config = clasp_config::load_clasp_config()?;
    let script_id = clasp_config::resolve_script_id(matches.get_one::<String>("script"), config.as_ref())?;
    let dir = clasp_config::resolve_dir(matches.get_one::<String>("dir"), config.as_ref())?;
    // ...
}

This would improve performance and make the data flow more explicit.

Comment on lines +259 to +266
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.

medium

The allowlist for script filenames is overly restrictive by disallowing dots (.). Apps Script file names can legitimately contain dots (e.g., my.utils.js would have the name my.utils from the API). This restriction could prevent pulling valid projects that use this common naming convention for namespacing.

The existing checks for path traversal (..), directory separators (/, \), and hidden files (names starting with .) are sufficient for security. I suggest allowing dots within the filename.

Suggested change
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}"
)));
}
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}"
)));
}

@jpoehnelt jpoehnelt changed the title Feat/replace clasp feat: implement clasp Mar 4, 2026
@jpoehnelt jpoehnelt added area: skills cla: yes This human has signed the Contributor License Agreement. complexity: high Large or complex change, careful review needed labels Mar 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: skills cla: yes This human has signed the Contributor License Agreement. complexity: high Large or complex change, careful review needed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants