zeroclaw/src/tools
Nim G bbd2556861
feat(tool): google_workspace operation-level allowlist (#4010)
* feat(config): add google workspace operation allowlists

* docs(superpowers): link google workspace operation inventory sources

* docs(superpowers): verify starter operation examples

* fix(google_workspace): remove duplicate credential/audit blocks, fix trim in allowlist check, add duplicate-methods test

- Remove the duplicated credentials_path, default_account, and audit_log
  blocks that were copy-pasted into execute() — they were idempotent but
  misleading and would double-append --account args on every call.
- Trim stored service/resource/method values in is_operation_allowed() to
  match the trim applied during Config::validate(), preventing a mismatch
  where a config entry with surrounding whitespace would pass validation but
  never match at runtime.
- Add google_workspace_allowed_operations_reject_duplicate_methods_within_entry
  test to cover the duplicate-method validation path that was implemented but
  untested.

* fix(google_workspace): close sub_resource bypass, trim allowed_services at runtime, mark spec implemented

- HIGH: extract and validate sub_resource before the allowlist check;
  is_operation_allowed() now accepts Option<&str> for sub_resource and
  returns false (fail-closed) when allowed_operations is non-empty and
  a sub_resource is present — prevents nested gws calls such as
  `drive/files/permissions/list` from slipping past a 3-segment policy
- MEDIUM: runtime allowed_services check now uses s.trim() == service,
  matching the trim() applied during config validation
- LOW: spec status updated to Implemented; stale "does not currently
  support method-level allowlists" line removed
- Added test: operation_allowlist_rejects_sub_resource_when_operations_configured

* docs(google_workspace): document sub_resource limitation and add config-reference entries

Spec updates (superpowers/specs):
- Semantics section: note that sub_resource calls are denied fail-closed when
  allowed_operations is configured
- Mental model: show both 3-segment and 4-segment gws command shapes; explain
  that 4-segment commands are unsupported with allowed_operations in this version
- Runtime enforcement: correct the validation order to match the implementation
  (sub_resource extracted before allowlist check, budget charged last)
- New section: Sub-Resource Limitation — documents impact, operator workaround,
  and confirms the deny is intentional for this slice
- Follow-On Work: add sub_resource config model extension as item 1

Config reference updates (all three locales):
- Add [google_workspace] section with top-level keys, [[allowed_operations]]
  sub-table, sub-resource limitation note, and TOML example

* fix(docs): add classroom and events to allowed_services list in all config-reference locales

* feat(google_workspace): extend allowed_operations to support sub_resource for 4-segment gws commands

All Gmail operations use gws gmail users <sub_resource> <method>, not the flat
3-segment shape. Without sub_resource support in allowed_operations, Gmail could
not be scoped at all, making the email-assistant use case impossible.

Config model:
- Add optional sub_resource field to GoogleWorkspaceAllowedOperation
- An entry without sub_resource matches 3-segment calls (Drive, Calendar, etc.)
- An entry with sub_resource matches only calls with that exact sub_resource value
- Duplicate detection updated to (service, resource, sub_resource) key

Runtime:
- Remove blanket sub_resource deny; is_operation_allowed now matches on all four
  dimensions including the optional sub_resource

Tests:
- Add operation_allowlist_matches_gmail_sub_resource_shape
- Add operation_allowlist_matches_drive_3_segment_shape
- Add rejects_operation_with_unlisted_sub_resource
- Add google_workspace_allowed_operations_allow_same_resource_different_sub_resource
- Add google_workspace_allowed_operations_reject_invalid_sub_resource_characters
- Add google_workspace_allowed_operations_deserialize_without_sub_resource
- Update all existing tests to use correct gws command shapes

Docs:
- Spec: correct Gmail examples throughout; remove Sub-Resource Limitation section;
  update data model, validation rules, example use case, and follow-on work
- Config-reference (en, vi, zh-CN): add sub_resource field to allowed_operations
  table; update Gmail examples to correct 4-segment shapes

Platform:
- email-assistant SKILL.md: update allowed_operations paths to gmail/users/* shape

* fix(google_workspace): add classroom and events to service parameter schema description

* fix(google_workspace): cross-validate allowed_operations service against allowed_services

When allowed_services is explicitly configured, each allowed_operations entry's
service must appear in that list. An entry that can never match at runtime is a
misconfigured policy: it looks valid but silently produces a narrower scope than
the operator intended. Validation now rejects it with a clear error message.

Scope: only applies when allowed_services is non-empty. When it is empty, the tool
uses a built-in default list defined in the tool layer; the validator cannot
enumerate that list without duplicating the constant, so the cross-check is skipped.

Also:
- Update allowed_operations field doc-comment from 3-part (service, resource, method)
  to 4-part (service, resource, sub_resource, method) model
- Soften Gmail sub_resource "required" language in config-reference (en, vi, zh-CN)
  from a validation requirement to a runtime matching requirement — the validator
  does not and should not hardcode API shape knowledge for individual services
- Add tests: rejects operation service not in allowed_services; skips cross-check
  when allowed_services is empty

* fix(google_workspace): cross-validate allowed_operations.service against effective service set

When allowed_services is empty the validator was silently skipping the
service cross-check, allowing impossible configs like an unlisted service
in allowed_operations to pass validation and only fail at runtime.

Move DEFAULT_GWS_SERVICES from the tool layer (google_workspace.rs) into
schema.rs so the validator can use it unconditionally. When allowed_services
is explicitly set, validate against that set; when empty, fall back to
DEFAULT_GWS_SERVICES. Remove the now-incorrect "skips cross-check when empty"
test and add two replacement tests: one confirming a valid default service
passes, one confirming an unknown service is rejected even with empty
allowed_services.

* fix(google_workspace): update test assertion for new error message wording

* docs(google_workspace): fix stale 3-segment gmail example in TDD plan

* fix(google_workspace): address adversarial review round 4 findings

- Error message for denied operations now includes sub_resource when
  present, so gmail/users/messages/send and gmail/users/drafts/send
  produce distinct, debuggable errors.
- Audit log now records sub_resource, completing the trail for 4-segment
  Gmail operations.
- Normalize (trim) allowed_services and allowed_operations fields at
  construction time in new(). Runtime comparisons now use plain equality
  instead of .trim() on every call, removing the latent defect where a
  future code path could forget to trim and silently fail to match.
- Unify runtime character validation with schema validation: sub_resource
  and service/resource/method checks now both require lowercase alphanumeric
  plus underscore and hyphen, matching the validator's character set.
- Add positional_cmd_args() test helper and tests verifying 3-segment
  (Drive) and 4-segment (Gmail) argument ordering.
- Add test confirming page_limit without page_all passes validation.
- Add test confirming whitespace in config values is normalized at
  construction, not deferred to comparison time.
- Fix spec Runtime Enforcement section to reflect actual code order.

* fix(google_workspace): wire production helpers to close test coverage gaps

- Remove #[cfg(test)] from positional_cmd_args; execute() now calls the
  same function the arg-ordering tests exercise, so a drift in the real
  command-building path is caught by the existing tests.
- Extract build_pagination_args(page_all, page_limit) as a production
  method used by execute(). Replace the brittle page_limit_without_page_all
  test (which relied on environment-specific execution failure wording)
  with four direct assertions on build_pagination_args covering all
  page_all/page_limit combinations.

---------

Co-authored-by: argenis de la rosa <theonlyhennygod@gmail.com>
2026-03-20 11:46:22 -04:00
..
microsoft365 feat(tools): add Microsoft 365 integration via Graph API (#3653) 2026-03-16 01:44:39 -04:00
backup_tool.rs feat(tools): add backup/restore and data management tools (#3662) 2026-03-16 02:35:44 -04:00
browser_delegate.rs feat(tools): add browser delegation tool (#3610) 2026-03-16 18:32:20 -04:00
browser_open.rs fix(security): harden redirect/browser_open and restore masked secrets 2026-02-24 16:03:01 +08:00
browser.rs fix(tools): qualify is_service_environment with super:: inside mod native_backend (#3659) 2026-03-16 00:35:09 -04:00
calculator.rs feat(tools): add calculator tool with arithmetic and statistical functions (#4012) 2026-03-19 21:40:27 -04:00
cli_discovery.rs feat(tools): add Google Workspace CLI (gws) integration (#3616) 2026-03-17 00:52:59 -04:00
cloud_ops.rs feat(tools): add cloud transformation accelerator tools (#3663) 2026-03-16 02:43:55 -04:00
cloud_patterns.rs feat(tools): add cloud transformation accelerator tools (#3663) 2026-03-16 02:43:55 -04:00
composio.rs fix(security): harden redirect/browser_open and restore masked secrets 2026-02-24 16:03:01 +08:00
content_search.rs fix(security): respect allowed_roots in tool-level path pre-checks (#3434) 2026-03-13 16:15:30 -04:00
cron_add.rs fix(cron): persist allowed_tools for agent jobs (#3993) 2026-03-19 14:37:55 -04:00
cron_list.rs style: apply rustfmt to async fs updates 2026-02-19 14:52:29 +08:00
cron_remove.rs fix(security): unify cron shell validation across API/CLI/scheduler (#3270) 2026-03-12 12:48:13 +00:00
cron_run.rs style: cargo fmt Box::pin calls in cron scheduler (#3667) 2026-03-15 23:34:26 -04:00
cron_runs.rs style: apply rustfmt to async fs updates 2026-02-19 14:52:29 +08:00
cron_update.rs fix(cron): persist allowed_tools for agent jobs (#3993) 2026-03-19 14:37:55 -04:00
data_management.rs feat(tools): add backup/restore and data management tools (#3662) 2026-03-16 02:35:44 -04:00
delegate.rs Fix delegate agent timeout config regression (#4004) 2026-03-19 18:54:33 -04:00
file_edit.rs Merge pull request #3288 from Alix-007/fix-2400-block-config-self-mutation 2026-03-19 15:16:48 -04:00
file_read.rs fix(security): respect allowed_roots in tool-level path pre-checks (#3434) 2026-03-13 16:15:30 -04:00
file_write.rs Merge pull request #3288 from Alix-007/fix-2400-block-config-self-mutation 2026-03-19 15:16:48 -04:00
git_operations.rs feat(channel): stream LLM responses to Telegram via draft message edits 2026-02-18 16:33:33 +08:00
glob_search.rs fix(security): respect allowed_roots in tool-level path pre-checks (#3434) 2026-03-13 16:15:30 -04:00
google_workspace.rs feat(tool): google_workspace operation-level allowlist (#4010) 2026-03-20 11:46:22 -04:00
hardware_board_info.rs fix: resolve all clippy warnings, formatting, and Mistral endpoint 2026-02-17 20:00:08 +08:00
hardware_memory_map.rs fix: resolve all clippy warnings, formatting, and Mistral endpoint 2026-02-17 20:00:08 +08:00
hardware_memory_read.rs fix(security): resolve rebase conflicts and provider regressions 2026-02-17 19:19:06 +08:00
http_request.rs feat(tool): add allow_private_hosts option to http_request tool (#3568) 2026-03-15 14:23:54 -04:00
image_info.rs chore: Remove blocking read strings 2026-02-19 14:52:29 +08:00
jira_tool.rs Fix Jira tool panics and dedup bug (#4003) 2026-03-19 18:14:34 -04:00
knowledge_tool.rs feat(knowledge): add knowledge graph for expertise capture and reuse (#3596) 2026-03-17 01:11:29 -04:00
linkedin_client.rs feat(multi): LinkedIn tool, WhatsApp voice notes, and Anthropic OAuth fix (#3604) 2026-03-17 01:55:05 -04:00
linkedin.rs feat(multi): LinkedIn tool, WhatsApp voice notes, and Anthropic OAuth fix (#3604) 2026-03-17 01:55:05 -04:00
mcp_client.rs fix: use cfg-conditional AtomicU32 fallback for 32-bit targets in mcp_client (#3432) 2026-03-13 15:33:31 -04:00
mcp_deferred.rs fix(tool): include descriptions in deferred MCP tools system prompt (#4018) 2026-03-19 22:35:55 -04:00
mcp_protocol.rs feat(tools/mcp): add MCP subsystem tools layer with multi-transport client (#3394) 2026-03-13 14:23:48 -04:00
mcp_tool.rs feat(tools/mcp): add MCP subsystem tools layer with multi-transport client (#3394) 2026-03-13 14:23:48 -04:00
mcp_transport.rs feat(tools/mcp): add MCP subsystem tools layer with multi-transport client (#3394) 2026-03-13 14:23:48 -04:00
memory_forget.rs fix(policy): standardize side-effect tool autonomy gates 2026-02-18 12:42:56 +08:00
memory_recall.rs feat(memory): add session_id isolation to Memory trait (#530) 2026-02-17 07:44:05 -05:00
memory_store.rs fix(channels): recover malformed invoke/tool_call output in daemon mode 2026-02-18 17:01:36 +08:00
mod.rs feat(tool): google_workspace operation-level allowlist (#4010) 2026-03-20 11:46:22 -04:00
model_routing_config.rs feat(delegate): make sub-agent timeouts configurable via config.toml (#3909) 2026-03-18 17:07:03 -04:00
model_switch.rs feat(agent): add runtime model switching via model_switch tool (#3853) 2026-03-18 14:17:52 -04:00
node_tool.rs feat(gateway): add dynamic node discovery and capability advertisement (#3448) 2026-03-13 18:23:48 -04:00
notion_tool.rs feat(notion): add Notion database poller channel and API tool (#3650) 2026-03-16 00:55:23 -04:00
pdf_read.rs fix(tools): use resolve_tool_path for consistent path resolution (#3937) 2026-03-18 23:51:35 -04:00
project_intel.rs feat(tools): add Microsoft 365 integration via Graph API (#3653) 2026-03-16 01:44:39 -04:00
proxy_config.rs feat(channels): add Reddit, Bluesky, and generic Webhook adapters (#3598) 2026-03-17 01:26:58 -04:00
pushover.rs chore: Remove blocking read strings 2026-02-19 14:52:29 +08:00
read_skill.rs feat(skills): add read_skill for compact mode 2026-03-19 17:53:40 +08:00
report_templates.rs feat(tools): add Microsoft 365 integration via Graph API (#3653) 2026-03-16 01:44:39 -04:00
schedule.rs fix(security): validate command before rate-limiting in cron once (#3699) (#3719) 2026-03-16 14:21:45 -04:00
schema.rs fix(build): complete strict lint and test cleanup (replacement for #476) 2026-02-18 00:18:54 +08:00
screenshot.rs Addressed clippy lint issues 2026-03-10 01:48:19 -04:00
security_ops.rs feat(security): add MCSS security operations tool (#3657) 2026-03-16 02:28:54 -04:00
shell.rs fix(security): wire sandbox into shell command execution (#3989) 2026-03-19 14:21:42 -04:00
sop_advance.rs fix(web): call doctor endpoint with authenticated POST 2026-02-24 16:02:59 +08:00
sop_approve.rs fix(web): call doctor endpoint with authenticated POST 2026-02-24 16:02:59 +08:00
sop_execute.rs fix(web): call doctor endpoint with authenticated POST 2026-02-24 16:02:59 +08:00
sop_list.rs fix(web): call doctor endpoint with authenticated POST 2026-02-24 16:02:59 +08:00
sop_status.rs fix(web): call doctor endpoint with authenticated POST 2026-02-24 16:02:59 +08:00
swarm.rs feat(delegate): make sub-agent timeouts configurable via config.toml (#3909) 2026-03-18 17:07:03 -04:00
text_browser.rs feat(tools): add text browser tool for headless environments (#4031) 2026-03-20 01:59:43 -04:00
tool_search.rs fix(tools): include tool_search instruction in deferred tools system prompt (#3826) (#3914) 2026-03-18 15:13:58 -04:00
traits.rs test: deepen and complete project-wide test coverage (#297) 2026-02-16 05:58:24 -05:00
web_fetch.rs Harden config secret masking and web_fetch limits 2026-02-24 16:03:01 +08:00
web_search_tool.rs fix(tool): resolve Brave API key lazily with decryption support (#3078) (#3320) 2026-03-12 13:53:35 +00:00
workspace_tool.rs feat(workspace): add multi-client workspace isolation 2026-03-15 22:41:18 -04:00