Files
riposte-marketplace/integrations/google-drive/manifest.yaml
T
f3nris 45e9cbd269 feat: declare a risk tier on every command in the catalog
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>
2026-09-08 12:55:20 +02:00

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: {} }