fix: document all environment variables and enable CONFIG_DIR override (#222)
* docs: document all environment variables and enable CONFIG_DIR override (#171) * docs: clarify env vars are trusted inputs in AGENTS.md * chore: add Gemini Code Assist style guide --------- Co-authored-by: jpoehnelt-bot <jpoehnelt-bot@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@googleworkspace/cli": patch
|
||||
---
|
||||
|
||||
Document all environment variables and enable GOOGLE_WORKSPACE_CLI_CONFIG_DIR in release builds
|
||||
+29
-12
@@ -1,18 +1,35 @@
|
||||
# OAuth Client Credentials
|
||||
# Create these at https://console.cloud.google.com/apis/credentials
|
||||
GOOGLE_WORKSPACE_CLI_CLIENT_ID=
|
||||
GOOGLE_WORKSPACE_CLI_CLIENT_SECRET=
|
||||
# gws — Google Workspace CLI
|
||||
# Copy this file to .env and uncomment the variables you need.
|
||||
# All variables are optional. See README.md for details.
|
||||
|
||||
# Authentication
|
||||
# Path to a service account JSON key file or user credentials
|
||||
# ── Authentication ────────────────────────────────────────────────
|
||||
# Pre-obtained OAuth2 access token (highest priority; bypasses all credential loading)
|
||||
# GOOGLE_WORKSPACE_CLI_TOKEN=
|
||||
|
||||
# Path to OAuth credentials JSON (user or service account)
|
||||
# GOOGLE_WORKSPACE_CLI_CREDENTIALS_FILE=
|
||||
|
||||
# Impersonation (Domain-Wide Delegation)
|
||||
# Email address of the user to impersonate when using a service account
|
||||
# Default account email for multi-account usage (overridden by --account flag)
|
||||
# GOOGLE_WORKSPACE_CLI_ACCOUNT=
|
||||
|
||||
# Email of user to impersonate via Domain-Wide Delegation (service accounts only)
|
||||
# GOOGLE_WORKSPACE_CLI_IMPERSONATED_USER=
|
||||
|
||||
# Model Armor Sanitization
|
||||
# Default template resource name for --sanitize
|
||||
# GOOGLE_WORKSPACE_CLI_SANITIZE_TEMPLATE=projects/my-project/locations/us-central1/templates/my-template
|
||||
# Sanitization mode: 'warn' (default) or 'block'
|
||||
# ── OAuth Client ──────────────────────────────────────────────────
|
||||
# OAuth client ID and secret (alternative to saving client_secret.json)
|
||||
# GOOGLE_WORKSPACE_CLI_CLIENT_ID=
|
||||
# GOOGLE_WORKSPACE_CLI_CLIENT_SECRET=
|
||||
|
||||
# ── Configuration ─────────────────────────────────────────────────
|
||||
# Override the config directory (default: ~/.config/gws)
|
||||
# GOOGLE_WORKSPACE_CLI_CONFIG_DIR=
|
||||
|
||||
# ── Model Armor (response sanitization) ──────────────────────────
|
||||
# Default Model Armor template (overridden by --sanitize flag)
|
||||
# GOOGLE_WORKSPACE_CLI_SANITIZE_TEMPLATE=
|
||||
# Sanitization mode: warn (default) or block
|
||||
# GOOGLE_WORKSPACE_CLI_SANITIZE_MODE=warn
|
||||
|
||||
# ── Helpers ───────────────────────────────────────────────────────
|
||||
# GCP project ID fallback for gmail watch and events subscribe (overridden by --project)
|
||||
# GOOGLE_WORKSPACE_PROJECT_ID=
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
# Code Review Style Guide
|
||||
|
||||
## Project Architecture
|
||||
|
||||
`gws` is a Rust CLI that dynamically generates commands from Google Discovery Documents at runtime. It does NOT use generated Rust crates (`google-drive3`, etc.) for API interaction. Do not suggest adding API-specific crates to `Cargo.toml`.
|
||||
|
||||
## Security: Trusted vs Untrusted Inputs
|
||||
|
||||
This CLI is frequently invoked by AI/LLM agents. CLI arguments may be adversarial.
|
||||
|
||||
- **CLI arguments (untrusted)** — Must validate paths against traversal (`../../`), reject control characters, percent-encode URL path segments, and use `reqwest .query()` for query parameters. Validators: `validate_safe_output_dir()`, `validate_safe_dir_path()`, `encode_path_segment()`, `validate_resource_name()`.
|
||||
- **Environment variables (trusted)** — Set by the user in their shell profile, `.env` file, or deployment config. Do NOT flag missing path validation on environment variable values. This is consistent with `XDG_CONFIG_HOME`, `CARGO_HOME`, etc.
|
||||
|
||||
## Test Coverage
|
||||
|
||||
The `codecov/patch` check requires new/modified lines to be covered by tests. Prefer extracting testable helper functions over embedding logic in `main`/`run`. Tests should cover both happy paths and rejection paths (e.g., pass `../../.ssh` and assert `Err`).
|
||||
|
||||
## Changesets
|
||||
|
||||
Every PR must include a `.changeset/<name>.md` file. Use `patch` for fixes/chores, `minor` for features, `major` for breaking changes.
|
||||
|
||||
## Code Style
|
||||
|
||||
- Rust: `cargo clippy -- -D warnings` must pass. `cargo fmt` enforced via pre-commit hook.
|
||||
- Node.js: Use `pnpm` not `npm`.
|
||||
- OAuth scope strings in test code will trigger "restricted/sensitive scope" warnings — these are expected and should be ignored.
|
||||
@@ -84,6 +84,9 @@ ASCII art title cards live in `art/`. The `scripts/show-art.sh` helper clears th
|
||||
> [!IMPORTANT]
|
||||
> This CLI is frequently invoked by AI/LLM agents. Always assume inputs can be adversarial — validate paths against traversal (`../../.ssh`), restrict format strings to allowlists, reject control characters, and encode user values before embedding them in URLs.
|
||||
|
||||
> [!NOTE]
|
||||
> **Environment variables are trusted inputs.** The validation rules above apply to **CLI arguments** that may be passed by untrusted AI agents. Environment variables (e.g. `GOOGLE_WORKSPACE_CLI_CONFIG_DIR`) are set by the user themselves — in their shell profile, `.env` file, or deployment config — and are not subject to path traversal validation. This is consistent with standard conventions like `XDG_CONFIG_HOME`, `CARGO_HOME`, etc.
|
||||
|
||||
### Path Safety (`src/validate.rs`)
|
||||
|
||||
When adding new helpers or CLI flags that accept file paths, **always validate** using the shared helpers:
|
||||
@@ -165,7 +168,40 @@ Use these labels to categorize pull requests and issues:
|
||||
|
||||
## Environment Variables
|
||||
|
||||
- `GOOGLE_WORKSPACE_CLI_TOKEN` — Pre-obtained OAuth2 access token (highest priority; bypasses all credential file loading)
|
||||
- `GOOGLE_WORKSPACE_CLI_CREDENTIALS_FILE` — Path to OAuth credentials JSON (no default; if unset, falls back to credentials secured by the OS Keyring and encrypted in `~/.config/gws/`)
|
||||
- `GOOGLE_WORKSPACE_CLI_ACCOUNT` — Default account email for multi-account usage (overridden by `--account` flag)
|
||||
- Supports `.env` files via `dotenvy`
|
||||
### Authentication
|
||||
|
||||
| Variable | Description |
|
||||
|---|---|
|
||||
| `GOOGLE_WORKSPACE_CLI_TOKEN` | Pre-obtained OAuth2 access token (highest priority; bypasses all credential file loading) |
|
||||
| `GOOGLE_WORKSPACE_CLI_CREDENTIALS_FILE` | Path to OAuth credentials JSON (no default; if unset, falls back to credentials secured by the OS Keyring and encrypted in `~/.config/gws/`) |
|
||||
| `GOOGLE_WORKSPACE_CLI_ACCOUNT` | Default account email for multi-account usage (overridden by `--account` flag) |
|
||||
| `GOOGLE_WORKSPACE_CLI_IMPERSONATED_USER` | Email of user to impersonate with Domain-Wide Delegation (service accounts only) |
|
||||
| `GOOGLE_APPLICATION_CREDENTIALS` | Standard Google ADC path; used as fallback when no gws-specific credentials are configured |
|
||||
|
||||
### Configuration
|
||||
|
||||
| Variable | Description |
|
||||
|---|---|
|
||||
| `GOOGLE_WORKSPACE_CLI_CONFIG_DIR` | Override the config directory (default: `~/.config/gws`) |
|
||||
|
||||
### OAuth Client
|
||||
|
||||
| Variable | Description |
|
||||
|---|---|
|
||||
| `GOOGLE_WORKSPACE_CLI_CLIENT_ID` | OAuth client ID (for `gws auth login` when no `client_secret.json` is saved) |
|
||||
| `GOOGLE_WORKSPACE_CLI_CLIENT_SECRET` | OAuth client secret (paired with `CLIENT_ID` above) |
|
||||
|
||||
### Sanitization (Model Armor)
|
||||
|
||||
| Variable | Description |
|
||||
|---|---|
|
||||
| `GOOGLE_WORKSPACE_CLI_SANITIZE_TEMPLATE` | Default Model Armor template (overridden by `--sanitize` flag) |
|
||||
| `GOOGLE_WORKSPACE_CLI_SANITIZE_MODE` | `warn` (default) or `block` |
|
||||
|
||||
### Helpers
|
||||
|
||||
| Variable | Description |
|
||||
|---|---|
|
||||
| `GOOGLE_WORKSPACE_PROJECT_ID` | GCP project ID fallback for `gmail watch` and `events subscribe` helpers (overridden by `--project` flag) |
|
||||
|
||||
All variables can also live in a `.env` file (loaded via `dotenvy`).
|
||||
|
||||
@@ -33,6 +33,7 @@ npm install -g @googleworkspace/cli
|
||||
- [AI Agent Skills](#ai-agent-skills)
|
||||
- [MCP Server](#mcp-server)
|
||||
- [Advanced Usage](#advanced-usage)
|
||||
- [Environment Variables](#environment-variables)
|
||||
- [Architecture](#architecture)
|
||||
- [Troubleshooting](#troubleshooting)
|
||||
- [Development](#development)
|
||||
@@ -356,6 +357,25 @@ gws gmail users messages get --params '...' \
|
||||
| `GOOGLE_WORKSPACE_CLI_SANITIZE_TEMPLATE` | Default Model Armor template |
|
||||
| `GOOGLE_WORKSPACE_CLI_SANITIZE_MODE` | `warn` (default) or `block` |
|
||||
|
||||
## Environment Variables
|
||||
|
||||
All variables are optional. See [`.env.example`](.env.example) for a copy-paste template.
|
||||
|
||||
| Variable | Description |
|
||||
|---|---|
|
||||
| `GOOGLE_WORKSPACE_CLI_TOKEN` | Pre-obtained OAuth2 access token (highest priority) |
|
||||
| `GOOGLE_WORKSPACE_CLI_CREDENTIALS_FILE` | Path to OAuth credentials JSON (user or service account) |
|
||||
| `GOOGLE_WORKSPACE_CLI_ACCOUNT` | Default account email (overridden by `--account` flag) |
|
||||
| `GOOGLE_WORKSPACE_CLI_IMPERSONATED_USER` | Email for Domain-Wide Delegation (service accounts) |
|
||||
| `GOOGLE_WORKSPACE_CLI_CLIENT_ID` | OAuth client ID (alternative to `client_secret.json`) |
|
||||
| `GOOGLE_WORKSPACE_CLI_CLIENT_SECRET` | OAuth client secret (paired with `CLIENT_ID`) |
|
||||
| `GOOGLE_WORKSPACE_CLI_CONFIG_DIR` | Override config directory (default: `~/.config/gws`) |
|
||||
| `GOOGLE_WORKSPACE_CLI_SANITIZE_TEMPLATE` | Default Model Armor template |
|
||||
| `GOOGLE_WORKSPACE_CLI_SANITIZE_MODE` | `warn` (default) or `block` |
|
||||
| `GOOGLE_WORKSPACE_PROJECT_ID` | GCP project ID fallback for helper commands |
|
||||
|
||||
Environment variables can also be set in a `.env` file (loaded via [dotenvy](https://crates.io/crates/dotenvy)).
|
||||
|
||||
## Architecture
|
||||
|
||||
`gws` uses a **two-phase parsing** strategy:
|
||||
|
||||
@@ -92,7 +92,6 @@ const READONLY_SCOPES: &[&str] = &[
|
||||
];
|
||||
|
||||
pub fn config_dir() -> PathBuf {
|
||||
#[cfg(test)]
|
||||
if let Ok(dir) = std::env::var("GOOGLE_WORKSPACE_CLI_CONFIG_DIR") {
|
||||
return PathBuf::from(dir);
|
||||
}
|
||||
@@ -266,7 +265,7 @@ async fn handle_login(args: &[String]) -> Result<(), GwsError> {
|
||||
}
|
||||
|
||||
// Determine scopes: explicit flags > interactive TUI > defaults
|
||||
let mut scopes = resolve_scopes(
|
||||
let scopes = resolve_scopes(
|
||||
&filtered_args,
|
||||
project_id.as_deref(),
|
||||
services_filter.as_ref(),
|
||||
@@ -277,7 +276,7 @@ async fn handle_login(args: &[String]) -> Result<(), GwsError> {
|
||||
// gmail.metadata blocks query parameters like `q`, and is redundant
|
||||
// when broader scopes (gmail.modify, gmail.readonly, mail.google.com)
|
||||
// are already included.
|
||||
let scopes = filter_redundant_restrictive_scopes(scopes);
|
||||
let mut scopes = filter_redundant_restrictive_scopes(scopes);
|
||||
|
||||
let secret = yup_oauth2::ApplicationSecret {
|
||||
client_id: client_id.clone(),
|
||||
|
||||
+13
@@ -454,6 +454,19 @@ fn print_usage() {
|
||||
println!(
|
||||
" GOOGLE_WORKSPACE_CLI_ACCOUNT Default account email for multi-account"
|
||||
);
|
||||
println!(
|
||||
" GOOGLE_WORKSPACE_CLI_IMPERSONATED_USER Email for Domain-Wide Delegation (service accounts)"
|
||||
);
|
||||
println!(
|
||||
" GOOGLE_WORKSPACE_CLI_CONFIG_DIR Override config directory (default: ~/.config/gws)"
|
||||
);
|
||||
println!(" GOOGLE_WORKSPACE_CLI_SANITIZE_TEMPLATE Default Model Armor template");
|
||||
println!(
|
||||
" GOOGLE_WORKSPACE_CLI_SANITIZE_MODE Sanitization mode: warn (default) or block"
|
||||
);
|
||||
println!(
|
||||
" GOOGLE_WORKSPACE_PROJECT_ID GCP project ID fallback for helper commands"
|
||||
);
|
||||
println!();
|
||||
println!("COMMUNITY:");
|
||||
println!(" Star the repo: https://github.com/googleworkspace/cli");
|
||||
|
||||
Reference in New Issue
Block a user