45e9cbd269
467 of the 1592 commands carried no `risk:`. An unset risk is read as
destructive by the agent approval gate, so half the catalog's write side sat
behind the same prompt — and, in HarfangLab's case, 39 pure lookups did too.
A gate that stops everything stops being read as a signal, which is the
argument already made for the toolkit and for sentinelone (df27876).
The catalog is now 1027 read, 261 safe_write, 304 destructive, with nothing
defaulted. The line follows the one sentinelone drew: impact on the estate,
not reversibility — isolate-agent is reversible and is the canonical
destructive example.
read only queries; changes nothing outside Riposte
safe_write additive or reversible inside the tool's own case/enrichment
plane: comments, tickets, tags, alert statuses, threat-intel
records, sandbox submissions, collection jobs, outbound messages
destructive changes the estate or weakens a control: containment, blocklists
and allowlists, exclusions and detection rules, every delete,
identity and credential operations, code on a host, generic
API escape hatches
Three calls that were not obvious, and are now applied throughout:
- Undoing a containment is tiered like the containment it lifts. Un-isolating
a host or un-banning an IP mid-incident is its own decision, not a return to
a neutral state. The catalog contradicted itself here — crowdstrike's
lift_containment was destructive while harfanglab's deisolate_from_threat
was safe_write — so deisolate_from_threat and unquarantine_file are
re-tiered to destructive, the only two existing tiers this pass changes.
- Retrieving a live secret is destructive: cyberark get_password, delinea
get_secret, vault read_secret, beyondtrust get_credential. It is a GET, but
the tier describes the stake, not the HTTP verb.
- Sending outward to humans stays safe_write — slack, teams, twilio, telegram,
mail. Irreversible, but it is the collaboration plane, not the estate.
An object created but not yet referenced by a rule is safe_write; editing one
a rule already reads is destructive. That is why fortigate create_address and
panos create_custom_url_category are safe_write while update_address_group and
edit_custom_url_category are not.
The template and README never documented the field, which is how 467 commands
came to omit it. Both now carry the tier table and these rules, so the next
integration declares a tier instead of inheriting one.
111 packages get a MINOR bump and a changelog entry: an instance compares
versions to offer an update, so an unbumped manifest would leave the tiers
sitting in the catalog and never reaching the estates that need them.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
329 lines
18 KiB
YAML
329 lines
18 KiB
YAML
id: google_drive
|
|
name: Google Drive
|
|
version: 1.1.0
|
|
description: "Google Drive (Drive API v3) — manage shared drives (create/list/get/delete), track file changes (start page token + change lists), query Drive activity, search and read files, create folders and metadata, upload/replace/download file content, copy, move and delete files, manage permissions (list/create/update/delete) and work with Drive labels. Authenticates with a Google service account (JWT bearer flow with domain-wide delegation to impersonate a Workspace user). Runs on a remote engine. Requires the Python 'PyJWT' and 'cryptography' libraries on the engine host (pip install pyjwt cryptography)."
|
|
changelog: "1.1.0 — Declare the risk tier on the 12 commands that carried none: 6 safe_write, 6 destructive. An unset risk is read as destructive by the agent approval gate, so the 6 that only annotate sat behind the same prompt as the ones that change the estate. | 1.0.0 — Initial release: shared drive management, changes tracking, Drive activity queries, file search/get/create, content upload/replace/download, copy/move/delete, parents, permissions management, Drive labels, test connection."
|
|
category: productivity
|
|
|
|
# Per-instance configuration. Authentication uses the Google service-account
|
|
# JWT bearer flow: the scripts build a signed RS256 assertion from the service
|
|
# account's private_key/client_email, exchange it at the token endpoint for an
|
|
# access token, and set the JWT "sub" claim to the impersonated user (domain-wide
|
|
# delegation must be granted to the service account's client ID in the Google
|
|
# Workspace admin console, with the Drive scopes). user_id is the default user
|
|
# to impersonate; every command also accepts a per-call user_id override.
|
|
config_schema:
|
|
properties:
|
|
service_account_json:
|
|
type: string
|
|
description: "Full service account key JSON (as downloaded from Google Cloud IAM — must contain client_email and private_key)"
|
|
x-soar-sensitive: true
|
|
user_id:
|
|
type: string
|
|
description: "Default user email to impersonate via domain-wide delegation (e.g. admin@company.com)"
|
|
required:
|
|
- service_account_json
|
|
- user_id
|
|
|
|
commands:
|
|
- id: drive_create
|
|
name: google-drive-drive-create
|
|
description: "Create a new shared drive."
|
|
risk: safe_write
|
|
inputs_schema:
|
|
properties:
|
|
name: { type: string, description: "Name of the shared drive to create" }
|
|
hidden: { type: boolean, description: "Create the shared drive hidden from the default view" }
|
|
user_id: { type: string, description: "Override the impersonated user" }
|
|
required: [name]
|
|
outputs_schema: { properties: {} }
|
|
- id: drives_list
|
|
name: google-drive-drives-list
|
|
description: "List the user's shared drives, optionally filtered by a query."
|
|
risk: read
|
|
inputs_schema:
|
|
properties:
|
|
query: { type: string, description: "Search query for shared drives (e.g. name contains 'IR')" }
|
|
page_size: { type: number, description: "Maximum shared drives per page (default 100)" }
|
|
page_token: { type: string, description: "Page token from a previous list call" }
|
|
use_domain_admin_access: { type: boolean, description: "Issue the request as a domain administrator (returns all shared drives of the domain)" }
|
|
user_id: { type: string, description: "Override the impersonated user" }
|
|
required: []
|
|
outputs_schema: { properties: {} }
|
|
- id: drive_get
|
|
name: google-drive-drive-get
|
|
description: "Get a shared drive's metadata by ID."
|
|
risk: read
|
|
inputs_schema:
|
|
properties:
|
|
drive_id: { type: string, description: "ID of the shared drive" }
|
|
use_domain_admin_access: { type: boolean, description: "Issue the request as a domain administrator" }
|
|
user_id: { type: string, description: "Override the impersonated user" }
|
|
required: [drive_id]
|
|
outputs_schema: { properties: {} }
|
|
- id: drive_delete
|
|
name: google-drive-drive-delete
|
|
description: "Permanently delete a shared drive."
|
|
risk: destructive
|
|
inputs_schema:
|
|
properties:
|
|
drive_id: { type: string, description: "ID of the shared drive to delete" }
|
|
use_domain_admin_access: { type: boolean, description: "Issue the request as a domain administrator" }
|
|
allow_item_deletion: { type: boolean, description: "Also delete items inside the shared drive (requires use_domain_admin_access)" }
|
|
user_id: { type: string, description: "Override the impersonated user" }
|
|
required: [drive_id]
|
|
outputs_schema: { properties: {} }
|
|
- id: changes_start_token
|
|
name: google-drive-changes-start-token
|
|
description: "Get the starting page token for listing future changes (per user or per shared drive)."
|
|
risk: read
|
|
inputs_schema:
|
|
properties:
|
|
drive_id: { type: string, description: "Shared drive ID to get the start token for (omit for the user's own changes)" }
|
|
user_id: { type: string, description: "Override the impersonated user" }
|
|
required: []
|
|
outputs_schema: { properties: {} }
|
|
- id: changes_list
|
|
name: google-drive-changes-list
|
|
description: "List the changes for a user or shared drive from a given page token."
|
|
risk: read
|
|
inputs_schema:
|
|
properties:
|
|
page_token: { type: string, description: "Token from a previous changes list or from changes-start-token" }
|
|
drive_id: { type: string, description: "Shared drive ID to list changes from (omit for the user's own changes)" }
|
|
page_size: { type: number, description: "Maximum changes per page (default 100)" }
|
|
include_removed: { type: boolean, description: "Include changes for removed/trashed files (default true)" }
|
|
include_items_from_all_drives: { type: boolean, description: "Include changes from both My Drive and shared drive items" }
|
|
restrict_to_my_drive: { type: boolean, description: "Restrict results to files inside My Drive" }
|
|
spaces: { type: string, description: "Comma-separated spaces to query: drive and/or appDataFolder" }
|
|
fields: { type: string, description: "Response detail: basic (default fields) or advance (all fields)" }
|
|
user_id: { type: string, description: "Override the impersonated user" }
|
|
required: [page_token]
|
|
outputs_schema: { properties: {} }
|
|
- id: activity_list
|
|
name: google-drive-activity-list
|
|
description: "Query Drive activity (Drive Activity API v2) for an item or a folder subtree."
|
|
risk: read
|
|
inputs_schema:
|
|
properties:
|
|
item_name: { type: string, description: "Activity for a single item, format items/ITEM_ID" }
|
|
folder_name: { type: string, description: "Activity for everything under a folder, format items/FOLDER_ID (sent as ancestorName)" }
|
|
filter: { type: string, description: "Activity filter (e.g. time > \"2026-01-01T00:00:00Z\" detail.action_detail_case:RENAME)" }
|
|
page_token: { type: string, description: "Page token from a previous activity query" }
|
|
page_size: { type: number, description: "Maximum activities per page" }
|
|
user_id: { type: string, description: "Override the impersonated user" }
|
|
required: []
|
|
outputs_schema: { properties: {} }
|
|
- id: files_list
|
|
name: google-drive-files-list
|
|
description: "Search and list files, optionally scoped to a shared drive or corpora."
|
|
risk: read
|
|
inputs_schema:
|
|
properties:
|
|
query: { type: string, description: "Search query (e.g. name contains 'report' and trashed = false)" }
|
|
page_size: { type: number, description: "Maximum files per page (default 100)" }
|
|
page_token: { type: string, description: "Page token from a previous list call" }
|
|
drive_id: { type: string, description: "Shared drive ID to search in (forces corpora=drive)" }
|
|
corpora: { type: string, description: "Bodies of items to query: user, domain, drive or allDrives (default user)" }
|
|
include_items_from_all_drives: { type: boolean, description: "Include items from both My Drive and shared drives" }
|
|
user_id: { type: string, description: "Override the impersonated user" }
|
|
required: []
|
|
outputs_schema: { properties: {} }
|
|
- id: file_get
|
|
name: google-drive-file-get
|
|
description: "Get a file's metadata by ID."
|
|
risk: read
|
|
inputs_schema:
|
|
properties:
|
|
file_id: { type: string, description: "ID of the file" }
|
|
fields: { type: string, description: "Fields to return (default * — all fields)" }
|
|
user_id: { type: string, description: "Override the impersonated user" }
|
|
required: [file_id]
|
|
outputs_schema: { properties: {} }
|
|
- id: file_create
|
|
name: google-drive-file-create
|
|
description: "Create a folder or an empty file (metadata only — use file-upload for content)."
|
|
risk: safe_write
|
|
inputs_schema:
|
|
properties:
|
|
file_name: { type: string, description: "Name of the file or folder to create" }
|
|
mime_type: { type: string, description: "MIME type (default application/vnd.google-apps.folder — a folder)" }
|
|
parent: { type: string, description: "ID of the parent folder or shared drive" }
|
|
description: { type: string, description: "Short description of the file" }
|
|
user_id: { type: string, description: "Override the impersonated user" }
|
|
required: [file_name]
|
|
outputs_schema: { properties: {} }
|
|
- id: file_upload
|
|
name: google-drive-file-upload
|
|
description: "Upload a new file with content (base64-encoded)."
|
|
risk: safe_write
|
|
inputs_schema:
|
|
properties:
|
|
file_name: { type: string, description: "Name of the file to create" }
|
|
content_base64: { type: string, description: "File content, base64-encoded" }
|
|
parent: { type: string, description: "ID of the parent folder or shared drive" }
|
|
user_id: { type: string, description: "Override the impersonated user" }
|
|
required: [file_name, content_base64]
|
|
outputs_schema: { properties: {} }
|
|
- id: file_replace
|
|
name: google-drive-file-replace
|
|
description: "Replace an existing file's content (base64-encoded)."
|
|
risk: destructive
|
|
inputs_schema:
|
|
properties:
|
|
file_id: { type: string, description: "ID of the file to update" }
|
|
content_base64: { type: string, description: "New file content, base64-encoded" }
|
|
user_id: { type: string, description: "Override the impersonated user" }
|
|
required: [file_id, content_base64]
|
|
outputs_schema: { properties: {} }
|
|
- id: file_download
|
|
name: google-drive-file-download
|
|
description: "Download a file's content — returns file_name, mime_type, size and content_base64."
|
|
risk: read
|
|
inputs_schema:
|
|
properties:
|
|
file_id: { type: string, description: "ID of the file to download" }
|
|
user_id: { type: string, description: "Override the impersonated user" }
|
|
required: [file_id]
|
|
outputs_schema: { properties: {} }
|
|
- id: file_copy
|
|
name: google-drive-file-copy
|
|
description: "Copy a file, optionally with a new title."
|
|
risk: safe_write
|
|
inputs_schema:
|
|
properties:
|
|
file_id: { type: string, description: "ID of the file to copy" }
|
|
copy_title: { type: string, description: "Name of the copy (defaults to the original name)" }
|
|
user_id: { type: string, description: "Override the impersonated user" }
|
|
required: [file_id]
|
|
outputs_schema: { properties: {} }
|
|
- id: file_move
|
|
name: google-drive-file-move
|
|
description: "Move a file between folders (add one parent, remove another)."
|
|
risk: safe_write
|
|
inputs_schema:
|
|
properties:
|
|
file_id: { type: string, description: "ID of the file to move" }
|
|
add_parent_id: { type: string, description: "ID of the destination folder to add" }
|
|
remove_parent_id: { type: string, description: "ID of the current folder to remove" }
|
|
user_id: { type: string, description: "Override the impersonated user" }
|
|
required: [file_id, add_parent_id, remove_parent_id]
|
|
outputs_schema: { properties: {} }
|
|
- id: file_delete
|
|
name: google-drive-file-delete
|
|
description: "Delete a file — permanently, or move it to the trash with soft_delete."
|
|
risk: destructive
|
|
inputs_schema:
|
|
properties:
|
|
file_id: { type: string, description: "ID of the file to delete" }
|
|
soft_delete: { type: boolean, description: "Move the file to the trash instead of deleting it permanently" }
|
|
user_id: { type: string, description: "Override the impersonated user" }
|
|
required: [file_id]
|
|
outputs_schema: { properties: {} }
|
|
- id: file_get_parents
|
|
name: google-drive-file-get-parents
|
|
description: "Get the parent folder IDs of a file."
|
|
risk: read
|
|
inputs_schema:
|
|
properties:
|
|
file_id: { type: string, description: "ID of the file" }
|
|
user_id: { type: string, description: "Override the impersonated user" }
|
|
required: [file_id]
|
|
outputs_schema: { properties: {} }
|
|
- id: permissions_list
|
|
name: google-drive-permissions-list
|
|
description: "List the permissions of a file or shared drive."
|
|
risk: read
|
|
inputs_schema:
|
|
properties:
|
|
file_id: { type: string, description: "ID of the file or shared drive" }
|
|
page_size: { type: number, description: "Maximum permissions per page" }
|
|
page_token: { type: string, description: "Page token from a previous list call" }
|
|
use_domain_admin_access: { type: boolean, description: "Issue the request as a domain administrator" }
|
|
user_id: { type: string, description: "Override the impersonated user" }
|
|
required: [file_id]
|
|
outputs_schema: { properties: {} }
|
|
- id: permission_create
|
|
name: google-drive-permission-create
|
|
description: "Grant a permission on a file or shared drive (share with a user, group, domain or anyone)."
|
|
risk: destructive
|
|
inputs_schema:
|
|
properties:
|
|
file_id: { type: string, description: "ID of the file or shared drive" }
|
|
role: { type: string, description: "Role to grant: reader, commenter, writer, fileOrganizer, organizer or owner (default reader)" }
|
|
type: { type: string, description: "Grantee type: user, group, domain or anyone (default user)" }
|
|
email_address: { type: string, description: "Email address of the user or group (type user/group)" }
|
|
domain: { type: string, description: "Domain name (type domain)" }
|
|
send_notification_email: { type: boolean, description: "Send a notification email to the grantee" }
|
|
transfer_ownership: { type: boolean, description: "Transfer ownership to the grantee (role owner)" }
|
|
move_to_new_owners_root: { type: boolean, description: "Move the file to the new owner's My Drive root on ownership transfer" }
|
|
user_id: { type: string, description: "Override the impersonated user" }
|
|
required: [file_id]
|
|
outputs_schema: { properties: {} }
|
|
- id: permission_update
|
|
name: google-drive-permission-update
|
|
description: "Update a permission's role or expiration time."
|
|
risk: destructive
|
|
inputs_schema:
|
|
properties:
|
|
file_id: { type: string, description: "ID of the file or shared drive" }
|
|
permission_id: { type: string, description: "ID of the permission to update" }
|
|
role: { type: string, description: "New role: reader, commenter, writer, fileOrganizer, organizer or owner" }
|
|
expiration_time: { type: string, description: "Expiration time (RFC 3339, e.g. 2026-12-31T23:59:59Z)" }
|
|
user_id: { type: string, description: "Override the impersonated user" }
|
|
required: [file_id, permission_id]
|
|
outputs_schema: { properties: {} }
|
|
- id: permission_delete
|
|
name: google-drive-permission-delete
|
|
description: "Revoke a permission from a file or shared drive."
|
|
risk: destructive
|
|
inputs_schema:
|
|
properties:
|
|
file_id: { type: string, description: "ID of the file or shared drive" }
|
|
permission_id: { type: string, description: "ID of the permission to delete" }
|
|
user_id: { type: string, description: "Override the impersonated user" }
|
|
required: [file_id, permission_id]
|
|
outputs_schema: { properties: {} }
|
|
- id: get_labels
|
|
name: google-drive-get-labels
|
|
description: "List the Drive label definitions available to the user."
|
|
risk: read
|
|
inputs_schema:
|
|
properties:
|
|
user_id: { type: string, description: "Override the impersonated user" }
|
|
required: []
|
|
outputs_schema: { properties: {} }
|
|
- id: get_file_labels
|
|
name: google-drive-get-file-labels
|
|
description: "List the labels applied to a file."
|
|
risk: read
|
|
inputs_schema:
|
|
properties:
|
|
file_id: { type: string, description: "ID of the file" }
|
|
user_id: { type: string, description: "Override the impersonated user" }
|
|
required: [file_id]
|
|
outputs_schema: { properties: {} }
|
|
- id: modify_label
|
|
name: google-drive-modify-label
|
|
description: "Apply, update or remove a Drive label on a file."
|
|
risk: safe_write
|
|
inputs_schema:
|
|
properties:
|
|
file_id: { type: string, description: "ID of the file" }
|
|
label_id: { type: string, description: "ID of the label to modify" }
|
|
field_id: { type: string, description: "ID of the label field to set (selection fields)" }
|
|
selection_label_id: { type: string, description: "Selection choice ID to set on the field" }
|
|
remove_label: { type: boolean, description: "Remove the label from the file instead of applying it" }
|
|
user_id: { type: string, description: "Override the impersonated user" }
|
|
required: [file_id, label_id]
|
|
outputs_schema: { properties: {} }
|
|
|
|
- id: test_connection
|
|
name: google-drive-test-connection
|
|
description: "Verify service-account credentials and delegation (used by the Test button)."
|
|
risk: read
|
|
inputs_schema:
|
|
properties: {}
|
|
required: []
|
|
outputs_schema: { properties: {} }
|