Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
5db4424
fix(script): keep current Clippy checks passing
ratovarius Sep 11, 2026
f4c9d6b
feat(cli): allow unknown request fields with explicit opt-in
ratovarius Sep 11, 2026
7588c6a
fix(auth): preserve credentials when decryption fails
ratovarius Sep 11, 2026
fd79f17
feat(docs): add structured document reader
ratovarius Sep 11, 2026
78e6e57
fix(docs): preserve automatic text subtypes
ratovarius Sep 11, 2026
a362bce
fix(formatter): separate empty YAML collection values
ratovarius Sep 11, 2026
d969380
fix(auth): skip authentication for request dry-runs
ratovarius Sep 11, 2026
eda58ca
test(auth): isolate dry-run fixtures from profile credentials
ratovarius Sep 11, 2026
e88fbe3
feat(files): add a trusted root for output and upload paths
ratovarius Sep 11, 2026
9b50a02
fix(files): reject unsupported canonical path encodings
ratovarius Sep 11, 2026
5685fe5
feat(docs): add revision-bound reviewed text patch workflow
ratovarius Sep 11, 2026
af8043a
fix(docs): preserve outcomes and validate every tab
ratovarius Sep 11, 2026
fcdd631
feat(docs): add visual review bundle companion
ratovarius Sep 11, 2026
9b50edc
fix(docs): correct bundle mapping and optional output states
ratovarius Sep 11, 2026
d0dbd2f
fix(docs): accept canonical export receipts
ratovarius Sep 11, 2026
d73bb60
ci(docs): isolate companion checks with verified action pins
ratovarius Sep 11, 2026
e3eb4cb
ci(docs): isolate companion checks with verified action pins
ratovarius Sep 11, 2026
8a1cfbd
test(cli): consume complete synthetic HTTP requests
ratovarius Sep 11, 2026
18410e9
chore(fork): publish maintained Docs workflow improvements
ratovarius Sep 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .changeset/allow-unknown-fields.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"@googleworkspace/cli": minor
---

Add `--allow-unknown-fields` to raw API methods with JSON request bodies. Explicitly
allow fields absent from Discovery recursively, including in dry runs, while
preserving validation of known fields, required fields, JSON, URLs and file paths.
Handwritten helpers retain strict validation.
5 changes: 5 additions & 0 deletions .changeset/current-clippy-baseline.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@googleworkspace/cli": patch
---

Keep Apps Script file selection compatible with the current Clippy checks.
11 changes: 11 additions & 0 deletions .changeset/docs-review-bundle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
"@googleworkspace/cli": minor
---

Add a standalone Python companion for visual Google Docs review bundles with
native exports, safe DOCX raster extraction, local HTML, optional PDF page
previews with explicitly unverified page coverage, revision observations,
and an offline fixture workflow. Preserve nested image occurrences and
legitimate asset reuse, and keep oversized optional comments from failing
the required bundle. Verify each export's exact canonical destination against
the real CLI receipt.
9 changes: 9 additions & 0 deletions .changeset/docs-review-workflow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"@googleworkspace/cli": minor
---

Add a standalone Python Docs review example that plans one literal text replacement,
binds it to a source revision and tab, applies it through existing gws commands,
and verifies the result without retrying ambiguous writes. Validate structures
and text ranges across all tabs before normalization, and preserve attempted or
confirmed mutation outcomes through final output failures and interruptions.
9 changes: 9 additions & 0 deletions .changeset/docs-structured-read.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"@googleworkspace/cli": minor
---

Add `gws docs +read` to translate documents into compact structured content with
recursive tabs, headings and an outline, styled text, suggestions, nested tables,
figure metadata, and reference markers. Preserve API indices and revisions,
reject partial field masks, and support the existing formatters, sanitization,
and credential-free dry-run.
7 changes: 7 additions & 0 deletions .changeset/maintained-public-fork.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@googleworkspace/cli": patch
---

Publish the integrated Docs workflow improvements in the independent ratovarius
fork with upstream attribution, source-install instructions, contribution
tracking, and credential-independent CI.
9 changes: 9 additions & 0 deletions .changeset/offline-dry-run.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"@googleworkspace/cli": patch
---

Skip authentication for Discovery-generated API and `docs +write` dry-runs.
Validate and preview requests without accessing the keyring or reading, changing,
or deleting stored credentials and token caches. Dry-runs work offline with a
fresh cached Discovery schema; schema fetching on first use or cache expiry is
unchanged. Real requests retain their existing authentication and error handling.
8 changes: 8 additions & 0 deletions .changeset/preserve-credentials.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"@googleworkspace/cli": patch
---

Preserve saved encrypted credentials and token caches when credential loading,
decryption, or keyring access fails. Report recovery guidance and stop authentication
instead of silently selecting plaintext credentials or another account through ADC.
Explicit token and credentials-file overrides and intentional logout remain unchanged.
13 changes: 13 additions & 0 deletions .changeset/scoped-file-roots.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
"@googleworkspace/cli": minor
---

Allow operators to set `GOOGLE_WORKSPACE_CLI_FILE_ROOT` to an existing directory
for `--output` and `--upload` paths while keeping CWD confinement by default.
Relative CLI paths remain CWD-relative. Reject invalid roots, parent traversal
with an explicit root, control characters, and symlink escapes, including
dangling symlinks. Directory flags retain their existing boundaries.

Reject canonical file paths that cannot be represented as UTF-8 at the CLI
string boundary, so explicit output/upload paths cannot silently become omitted
arguments.
7 changes: 7 additions & 0 deletions .changeset/yaml-empty-collections.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@googleworkspace/cli": patch
---

Fix YAML mapping values containing empty arrays or objects by separating their
inline collection syntax from the mapping colon. This also fixes structured
Docs reader output with empty outlines, child tabs, or style maps.
13 changes: 3 additions & 10 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -1,10 +1,3 @@
# Codeowners

# Core engine code strictly requires your review
# Isolates agents to `skills/` or `src/helpers/` unless absolutely necessary
/src/main.rs @jpoehnelt
/src/executor.rs @jpoehnelt
/src/discovery.rs @jpoehnelt
/src/commands.rs @jpoehnelt
/src/auth.rs @jpoehnelt
/src/schema.rs @jpoehnelt
# Review ownership for the independently maintained ratovarius fork.
# Original project authorship is preserved in FORK.md and the source history.
* @ratovarius
21 changes: 21 additions & 0 deletions .github/upstream-workflows/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Upstream automation reference

These eleven workflow files are preserved unchanged from
`googleworkspace/cli` at `a3768d0e82ad83cca2da97724e46bea4ff0e6dbd`.
GitHub Actions only loads workflows from `.github/workflows`, so these archived
copies do not run in this fork.

The upstream workflows include Google-specific CLA, bot, package publishing,
live-account smoke tests, and policy integrations. The fork instead runs
`fork-ci.yml`, `docs-review.yml`, and `docs-review-bundle.yml` with read-only
permissions and synthetic test data. They need no Google account credentials.

This initial fork CI covers Rust tests/builds and the two Python companions on
Linux and macOS, plus Rust formatting and Clippy. It does not reproduce the
upstream release matrix, Nix checks, coverage reporting, dependency audit, or
scheduled skill regeneration.

When syncing upstream, review changes here and any newly introduced active
workflows. Port useful checks deliberately; restore publishing only after
configuring a distinct fork release identity and destinations. See
[`CONTRIBUTING.md`](../../CONTRIBUTING.md).
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
54 changes: 54 additions & 0 deletions .github/workflows/docs-review-bundle.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

name: Docs Review Bundle

on:
push:
branches: [main]
pull_request:
branches: [main]

permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}

jobs:
docs-review-bundle:
name: Docs Review Bundle (Python)
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
persist-credentials: false
- name: Install Rust
uses: dtolnay/rust-toolchain@d1031067263f94b142dd6c0ce24c5eb9d02d52a0 # master
with:
toolchain: stable
- name: Cache cargo
uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
with:
key: docs-review-bundle-${{ matrix.os }}
- name: Build CLI for export contract regression
run: cargo build --locked
- name: Test stdlib companion with synthetic fixtures
run: python3 -B -m unittest discover -s examples/docs-review-bundle -p 'test_*.py' -v
env:
GWS_TEST_BINARY: ${{ github.workspace }}/target/debug/gws
46 changes: 46 additions & 0 deletions .github/workflows/docs-review.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

name: Docs Review Example

on:
push:
branches: [main]
pull_request:
branches: [main]

permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}

jobs:
docs-review:
name: Docs Review Python Example
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
env:
PYTHONDONTWRITEBYTECODE: "1"
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
persist-credentials: false
- name: Test with synthetic fixtures and stub gws
run: |
python3 --version
python3 -m unittest discover -s examples/docs-review -p 'test_*.py' -v
64 changes: 64 additions & 0 deletions .github/workflows/fork-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
name: Fork CI

on:
push:
branches: [main]
pull_request:
branches: [main]
workflow_dispatch:

permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}

env:
CARGO_TERM_COLOR: always

jobs:
test:
name: Rust tests (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest]
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
persist-credentials: false
- name: Install Rust
uses: dtolnay/rust-toolchain@d1031067263f94b142dd6c0ce24c5eb9d02d52a0 # master
with:
toolchain: stable
- name: Cache cargo
uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
with:
key: fork-test-${{ matrix.os }}
- name: Test workspace with synthetic fixtures
run: cargo test --workspace --locked
- name: Build workspace
run: cargo build --workspace --locked

lint:
name: Rust formatting and Clippy
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
persist-credentials: false
- name: Install Rust
uses: dtolnay/rust-toolchain@d1031067263f94b142dd6c0ce24c5eb9d02d52a0 # master
with:
toolchain: stable
components: rustfmt, clippy
- name: Cache cargo
uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
with:
key: fork-lint
- name: Check formatting
run: cargo fmt --all -- --check
- name: Clippy
run: cargo clippy --workspace --locked -- -D warnings
10 changes: 8 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# AGENTS.md

This is the independently maintained `ratovarius/cli` fork. Read
[FORK.md](FORK.md) for upstream attribution and the feature ledger, and
[CONTRIBUTING.md](CONTRIBUTING.md) for fork PRs, upstream submissions, and CI.

## Project Overview

`gws` is a Rust CLI tool for interacting with Google Workspace APIs. It dynamically generates its command surface at runtime by parsing Google Discovery Service JSON documents.
Expand All @@ -13,7 +17,7 @@
## Build & Test

> [!IMPORTANT]
> **Test Coverage**: The `codecov/patch` check requires that new or modified lines are covered by tests. When adding code, extract testable helper functions rather than embedding logic in `main`/`run` where it's hard to unit-test. Run `cargo test` locally and verify new branches are exercised.
> **Test Coverage**: Cover new or modified behavior with tests. When adding code, extract testable helper functions rather than embedding logic in `main`/`run` where it's hard to unit-test. Run `cargo test` locally and verify new branches are exercised. Upstream submissions may additionally require `codecov/patch`; this fork's active checks are documented in `CONTRIBUTING.md`.

```bash
cargo build # Build in dev mode
Expand All @@ -33,7 +37,7 @@ Every PR must include a changeset file. Create one at `.changeset/<descriptive-n
Brief description of the change
```

Use `patch` for fixes/chores, `minor` for new features, `major` for breaking changes. The CI policy check will fail without a changeset.
Use `patch` for fixes/chores, `minor` for new features, `major` for breaking changes. Keep changesets for upstream portability; the upstream CI policy requires them.

## Architecture

Expand Down Expand Up @@ -112,6 +116,7 @@ When adding new helpers or CLI flags that accept file paths, **always validate**
| -------------------------------------- | ---------------------------------------- | -------------------------------------------------------------------- |
| File path for writing (`--output-dir`) | `validate::validate_safe_output_dir()` | Absolute paths, `../` traversal, symlinks outside CWD, control chars |
| File path for reading (`--dir`) | `validate::validate_safe_dir_path()` | Absolute paths, `../` traversal, symlinks outside CWD, control chars |
| File path (`--output`, `--upload`) | `validate::validate_safe_file_path()` | Paths outside CWD or the trusted `GOOGLE_WORKSPACE_CLI_FILE_ROOT`, control chars, symlink escapes; `..` components with an explicit root |
| Enum/allowlist values (`--msg-format`) | clap `value_parser` (see `gmail/mod.rs`) | Any value not in the allowlist |

```rust
Expand Down Expand Up @@ -208,6 +213,7 @@ See [`src/helpers/README.md`](crates/google-workspace-cli/src/helpers/README.md)
| Variable | Description |
|---|---|
| `GOOGLE_WORKSPACE_CLI_CONFIG_DIR` | Override the config directory (default: `~/.config/gws`) |
| `GOOGLE_WORKSPACE_CLI_FILE_ROOT` | Trusted boundary for `--output` / `--upload` files (default: CWD). Must be an existing directory; canonicalized. Relative CLI paths remain CWD-relative. Does not expand directory validators. |

### OAuth Client

Expand Down
Loading
Loading