From 068762b62fb5e7f05ed04015623cd6304589b37e Mon Sep 17 00:00:00 2001 From: PaperMtn Date: Tue, 10 Mar 2026 15:07:00 +0000 Subject: [PATCH 1/8] fix: PyLint error on f-strings --- src/secops/chronicle/utils/request_utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/secops/chronicle/utils/request_utils.py b/src/secops/chronicle/utils/request_utils.py index 70395141..c3b2cd8a 100644 --- a/src/secops/chronicle/utils/request_utils.py +++ b/src/secops/chronicle/utils/request_utils.py @@ -347,7 +347,7 @@ def chronicle_request_bytes( try: data = response.json() raise APIError( - f"{error_message or "API request failed"}: method={method}, url={url}, " + f"{error_message or 'API request failed'}: method={method}, url={url}, " f"status={response.status_code}, response={data}" ) from None except ValueError: @@ -355,7 +355,7 @@ def chronicle_request_bytes( getattr(response, "text", ""), limit=MAX_BODY_CHARS ) raise APIError( - f"{error_message or "API request failed"}: method={method}, url={url}, " + f"{error_message or 'API request failed'}: method={method}, url={url}, " f"status={response.status_code}, response_text={preview}" ) from None From 3936b15300a5e6ff2c7c4ce4232e0923b3e26486 Mon Sep 17 00:00:00 2001 From: PaperMtn Date: Tue, 10 Mar 2026 15:23:02 +0000 Subject: [PATCH 2/8] chore: refactor for split PR --- CLI.md | 1584 +---- README.md | 3063 +--------- src/secops/chronicle/__init__.py | 247 - src/secops/chronicle/client.py | 5352 ++--------------- .../connector_context_properties.py | 299 - .../integration/connector_instance_logs.py | 130 - .../integration/connector_instances.py | 489 -- .../integration/connector_revisions.py | 202 - .../chronicle/integration/connectors.py | 405 -- .../integration/integration_instances.py | 403 -- .../chronicle/integration/integrations.py | 686 --- .../integration/job_context_properties.py | 298 - .../integration/job_instance_logs.py | 125 - .../chronicle/integration/job_instances.py | 399 -- .../chronicle/integration/job_revisions.py | 204 - src/secops/chronicle/integration/jobs.py | 371 -- .../integration/logical_operator_revisions.py | 212 - .../integration/logical_operators.py | 411 -- .../integration/marketplace_integrations.py | 199 - .../integration/transformer_revisions.py | 202 - .../chronicle/integration/transformers.py | 406 -- .../connector_context_properties.py | 375 -- .../integration/connector_instance_logs.py | 142 - .../integration/connector_instances.py | 473 -- .../integration/connector_revisions.py | 217 - .../cli/commands/integration/connectors.py | 325 - .../cli/commands/integration/integration.py | 775 --- .../integration/integration_client.py | 36 - .../integration/integration_instances.py | 392 -- .../integration/job_context_properties.py | 354 -- .../commands/integration/job_instance_logs.py | 140 - .../cli/commands/integration/job_instances.py | 407 -- .../cli/commands/integration/job_revisions.py | 213 - src/secops/cli/commands/integration/jobs.py | 356 -- .../integration/logical_operator_revisions.py | 239 - .../commands/integration/logical_operators.py | 395 -- .../integration/marketplace_integration.py | 204 - .../integration/transformer_revisions.py | 236 - .../cli/commands/integration/transformers.py | 387 -- .../test_connector_context_properties.py | 561 -- .../test_connector_instance_logs.py | 256 - .../integration/test_connector_instances.py | 845 --- .../integration/test_connector_revisions.py | 385 -- .../chronicle/integration/test_connectors.py | 665 -- .../integration/test_integration_instances.py | 623 -- .../integration/test_integrations.py | 909 --- .../test_job_context_properties.py | 506 -- .../integration/test_job_instance_logs.py | 256 - .../integration/test_job_instances.py | 733 --- .../integration/test_job_revisions.py | 378 -- tests/chronicle/integration/test_jobs.py | 594 -- .../test_logical_operator_revisions.py | 367 -- .../integration/test_logical_operators.py | 547 -- .../test_marketplace_integrations.py | 522 -- .../integration/test_transformer_revisions.py | 366 -- .../integration/test_transformers.py | 555 -- 56 files changed, 633 insertions(+), 29788 deletions(-) delete mode 100644 src/secops/chronicle/integration/connector_context_properties.py delete mode 100644 src/secops/chronicle/integration/connector_instance_logs.py delete mode 100644 src/secops/chronicle/integration/connector_instances.py delete mode 100644 src/secops/chronicle/integration/connector_revisions.py delete mode 100644 src/secops/chronicle/integration/connectors.py delete mode 100644 src/secops/chronicle/integration/integration_instances.py delete mode 100644 src/secops/chronicle/integration/integrations.py delete mode 100644 src/secops/chronicle/integration/job_context_properties.py delete mode 100644 src/secops/chronicle/integration/job_instance_logs.py delete mode 100644 src/secops/chronicle/integration/job_instances.py delete mode 100644 src/secops/chronicle/integration/job_revisions.py delete mode 100644 src/secops/chronicle/integration/jobs.py delete mode 100644 src/secops/chronicle/integration/logical_operator_revisions.py delete mode 100644 src/secops/chronicle/integration/logical_operators.py delete mode 100644 src/secops/chronicle/integration/marketplace_integrations.py delete mode 100644 src/secops/chronicle/integration/transformer_revisions.py delete mode 100644 src/secops/chronicle/integration/transformers.py delete mode 100644 src/secops/cli/commands/integration/connector_context_properties.py delete mode 100644 src/secops/cli/commands/integration/connector_instance_logs.py delete mode 100644 src/secops/cli/commands/integration/connector_instances.py delete mode 100644 src/secops/cli/commands/integration/connector_revisions.py delete mode 100644 src/secops/cli/commands/integration/connectors.py delete mode 100644 src/secops/cli/commands/integration/integration.py delete mode 100644 src/secops/cli/commands/integration/integration_instances.py delete mode 100644 src/secops/cli/commands/integration/job_context_properties.py delete mode 100644 src/secops/cli/commands/integration/job_instance_logs.py delete mode 100644 src/secops/cli/commands/integration/job_instances.py delete mode 100644 src/secops/cli/commands/integration/job_revisions.py delete mode 100644 src/secops/cli/commands/integration/jobs.py delete mode 100644 src/secops/cli/commands/integration/logical_operator_revisions.py delete mode 100644 src/secops/cli/commands/integration/logical_operators.py delete mode 100644 src/secops/cli/commands/integration/marketplace_integration.py delete mode 100644 src/secops/cli/commands/integration/transformer_revisions.py delete mode 100644 src/secops/cli/commands/integration/transformers.py delete mode 100644 tests/chronicle/integration/test_connector_context_properties.py delete mode 100644 tests/chronicle/integration/test_connector_instance_logs.py delete mode 100644 tests/chronicle/integration/test_connector_instances.py delete mode 100644 tests/chronicle/integration/test_connector_revisions.py delete mode 100644 tests/chronicle/integration/test_connectors.py delete mode 100644 tests/chronicle/integration/test_integration_instances.py delete mode 100644 tests/chronicle/integration/test_integrations.py delete mode 100644 tests/chronicle/integration/test_job_context_properties.py delete mode 100644 tests/chronicle/integration/test_job_instance_logs.py delete mode 100644 tests/chronicle/integration/test_job_instances.py delete mode 100644 tests/chronicle/integration/test_job_revisions.py delete mode 100644 tests/chronicle/integration/test_jobs.py delete mode 100644 tests/chronicle/integration/test_logical_operator_revisions.py delete mode 100644 tests/chronicle/integration/test_logical_operators.py delete mode 100644 tests/chronicle/integration/test_marketplace_integrations.py delete mode 100644 tests/chronicle/integration/test_transformer_revisions.py delete mode 100644 tests/chronicle/integration/test_transformers.py diff --git a/CLI.md b/CLI.md index bbf327b5..7fa8d2a0 100644 --- a/CLI.md +++ b/CLI.md @@ -959,1617 +959,155 @@ secops integration action-revisions delete \ --revision-id "r789" ``` -#### Integration Connectors +#### Integration Managers -List integration connectors: +List integration managers: ```bash -# List all connectors for an integration -secops integration connectors list --integration-name "MyIntegration" +# List all managers for an integration +secops integration managers list --integration-name "MyIntegration" -# List connectors as a direct list (fetches all pages automatically) -secops integration connectors list --integration-name "MyIntegration" --as-list +# List managers as a direct list (fetches all pages automatically) +secops integration managers list --integration-name "MyIntegration" --as-list # List with pagination -secops integration connectors list --integration-name "MyIntegration" --page-size 50 +secops integration managers list --integration-name "MyIntegration" --page-size 50 # List with filtering -secops integration connectors list --integration-name "MyIntegration" --filter-string "enabled = true" +secops integration managers list --integration-name "MyIntegration" --filter-string "enabled = true" ``` -Get connector details: +Get manager details: ```bash -secops integration connectors get --integration-name "MyIntegration" --connector-id "c1" +secops integration managers get --integration-name "MyIntegration" --manager-id "mgr1" ``` -Create a new connector: +Create a new manager: ```bash -secops integration connectors create \ +secops integration managers create \ --integration-name "MyIntegration" \ - --display-name "Data Ingestion" \ - --code "def fetch_data(context): return []" + --display-name "Configuration Manager" \ + --code "def manage_config(context): return {'status': 'configured'}" # Create with description and custom ID -secops integration connectors create \ +secops integration managers create \ --integration-name "MyIntegration" \ - --display-name "My Connector" \ - --code "def fetch_data(context): return []" \ - --description "Connector description" \ - --connector-id "custom-connector-id" + --display-name "My Manager" \ + --code "def manage(context): return {}" \ + --description "Manager description" \ + --manager-id "custom-manager-id" ``` -Update an existing connector: +Update an existing manager: ```bash # Update display name -secops integration connectors update \ +secops integration managers update \ --integration-name "MyIntegration" \ - --connector-id "c1" \ - --display-name "Updated Connector Name" + --manager-id "mgr1" \ + --display-name "Updated Manager Name" # Update code -secops integration connectors update \ +secops integration managers update \ --integration-name "MyIntegration" \ - --connector-id "c1" \ - --code "def fetch_data(context): return updated_data()" + --manager-id "mgr1" \ + --code "def manage(context): return {'status': 'updated'}" # Update multiple fields with update mask -secops integration connectors update \ +secops integration managers update \ --integration-name "MyIntegration" \ - --connector-id "c1" \ + --manager-id "mgr1" \ --display-name "New Name" \ --description "New description" \ --update-mask "displayName,description" ``` -Delete a connector: - -```bash -secops integration connectors delete --integration-name "MyIntegration" --connector-id "c1" -``` - -Test a connector: +Delete a manager: ```bash -secops integration connectors test --integration-name "MyIntegration" --connector-id "c1" +secops integration managers delete --integration-name "MyIntegration" --manager-id "mgr1" ``` -Get connector template: +Get manager template: ```bash -secops integration connectors template --integration-name "MyIntegration" +secops integration managers template --integration-name "MyIntegration" ``` -#### Connector Revisions +#### Manager Revisions -List connector revisions: +List manager revisions: ```bash -# List all revisions for a connector -secops integration connector-revisions list \ +# List all revisions for a manager +secops integration manager-revisions list \ --integration-name "MyIntegration" \ - --connector-id "c1" + --manager-id "mgr1" # List revisions as a direct list -secops integration connector-revisions list \ +secops integration manager-revisions list \ --integration-name "MyIntegration" \ - --connector-id "c1" \ + --manager-id "mgr1" \ --as-list # List with pagination -secops integration connector-revisions list \ +secops integration manager-revisions list \ --integration-name "MyIntegration" \ - --connector-id "c1" \ + --manager-id "mgr1" \ --page-size 10 # List with filtering and ordering -secops integration connector-revisions list \ +secops integration manager-revisions list \ --integration-name "MyIntegration" \ - --connector-id "c1" \ + --manager-id "mgr1" \ --filter-string 'version = "1.0"' \ --order-by "createTime desc" ``` +Get a specific revision: + +```bash +secops integration manager-revisions get \ + --integration-name "MyIntegration" \ + --manager-id "mgr1" \ + --revision-id "r456" +``` + Create a revision backup: ```bash # Create revision with comment -secops integration connector-revisions create \ +secops integration manager-revisions create \ --integration-name "MyIntegration" \ - --connector-id "c1" \ - --comment "Backup before field mapping changes" + --manager-id "mgr1" \ + --comment "Backup before major refactor" # Create revision without comment -secops integration connector-revisions create \ +secops integration manager-revisions create \ --integration-name "MyIntegration" \ - --connector-id "c1" + --manager-id "mgr1" ``` Rollback to a previous revision: ```bash -secops integration connector-revisions rollback \ +secops integration manager-revisions rollback \ --integration-name "MyIntegration" \ - --connector-id "c1" \ + --manager-id "mgr1" \ --revision-id "r456" ``` Delete an old revision: ```bash -secops integration connector-revisions delete \ +secops integration manager-revisions delete \ --integration-name "MyIntegration" \ - --connector-id "c1" \ + --manager-id "mgr1" \ --revision-id "r789" ``` -#### Connector Context Properties - -List connector context properties: - -```bash -# List all properties for a connector context -secops integration connector-context-properties list \ - --integration-name "MyIntegration" \ - --connector-id "c1" \ - --context-id "mycontext" - -# List properties as a direct list -secops integration connector-context-properties list \ - --integration-name "MyIntegration" \ - --connector-id "c1" \ - --context-id "mycontext" \ - --as-list - -# List with pagination -secops integration connector-context-properties list \ - --integration-name "MyIntegration" \ - --connector-id "c1" \ - --context-id "mycontext" \ - --page-size 50 - -# List with filtering -secops integration connector-context-properties list \ - --integration-name "MyIntegration" \ - --connector-id "c1" \ - --context-id "mycontext" \ - --filter-string 'key = "last_run_time"' -``` - -Get a specific context property: - -```bash -secops integration connector-context-properties get \ - --integration-name "MyIntegration" \ - --connector-id "c1" \ - --context-id "mycontext" \ - --property-id "prop123" -``` - -Create a new context property: - -```bash -# Store last run time -secops integration connector-context-properties create \ - --integration-name "MyIntegration" \ - --connector-id "c1" \ - --context-id "mycontext" \ - --key "last_run_time" \ - --value "2026-03-09T10:00:00Z" - -# Store checkpoint for incremental sync -secops integration connector-context-properties create \ - --integration-name "MyIntegration" \ - --connector-id "c1" \ - --context-id "mycontext" \ - --key "checkpoint" \ - --value "page_token_xyz123" -``` - -Update a context property: - -```bash -# Update last run time -secops integration connector-context-properties update \ - --integration-name "MyIntegration" \ - --connector-id "c1" \ - --context-id "mycontext" \ - --property-id "prop123" \ - --value "2026-03-09T11:00:00Z" -``` - -Delete a context property: - -```bash -secops integration connector-context-properties delete \ - --integration-name "MyIntegration" \ - --connector-id "c1" \ - --context-id "mycontext" \ - --property-id "prop123" -``` - -Clear all context properties: - -```bash -# Clear all properties for a specific context -secops integration connector-context-properties clear-all \ - --integration-name "MyIntegration" \ - --connector-id "c1" \ - --context-id "mycontext" -``` - -#### Connector Instance Logs - -List connector instance logs: - -```bash -# List all logs for a connector instance -secops integration connector-instance-logs list \ - --integration-name "MyIntegration" \ - --connector-id "c1" \ - --connector-instance-id "inst123" - -# List logs as a direct list -secops integration connector-instance-logs list \ - --integration-name "MyIntegration" \ - --connector-id "c1" \ - --connector-instance-id "inst123" \ - --as-list - -# List with pagination -secops integration connector-instance-logs list \ - --integration-name "MyIntegration" \ - --connector-id "c1" \ - --connector-instance-id "inst123" \ - --page-size 50 - -# List with filtering (filter by severity or timestamp) -secops integration connector-instance-logs list \ - --integration-name "MyIntegration" \ - --connector-id "c1" \ - --connector-instance-id "inst123" \ - --filter-string 'severity = "ERROR"' \ - --order-by "createTime desc" -``` - -Get a specific log entry: - -```bash -secops integration connector-instance-logs get \ - --integration-name "MyIntegration" \ - --connector-id "c1" \ - --connector-instance-id "inst123" \ - --log-id "log456" -``` - -#### Connector Instances - -List connector instances: - -```bash -# List all instances for a connector -secops integration connector-instances list \ - --integration-name "MyIntegration" \ - --connector-id "c1" - -# List instances as a direct list -secops integration connector-instances list \ - --integration-name "MyIntegration" \ - --connector-id "c1" \ - --as-list - -# List with pagination -secops integration connector-instances list \ - --integration-name "MyIntegration" \ - --connector-id "c1" \ - --page-size 50 - -# List with filtering -secops integration connector-instances list \ - --integration-name "MyIntegration" \ - --connector-id "c1" \ - --filter-string 'enabled = true' -``` - -Get connector instance details: - -```bash -secops integration connector-instances get \ - --integration-name "MyIntegration" \ - --connector-id "c1" \ - --connector-instance-id "inst123" -``` - -Create a new connector instance: - -```bash -# Create basic connector instance -secops integration connector-instances create \ - --integration-name "MyIntegration" \ - --connector-id "c1" \ - --environment "production" \ - --display-name "Production Data Collector" - -# Create with schedule and timeout -secops integration connector-instances create \ - --integration-name "MyIntegration" \ - --connector-id "c1" \ - --environment "production" \ - --display-name "Hourly Sync" \ - --interval-seconds 3600 \ - --timeout-seconds 300 \ - --enabled -``` - -Update a connector instance: - -```bash -# Update display name -secops integration connector-instances update \ - --integration-name "MyIntegration" \ - --connector-id "c1" \ - --connector-instance-id "inst123" \ - --display-name "Updated Display Name" - -# Update interval and timeout -secops integration connector-instances update \ - --integration-name "MyIntegration" \ - --connector-id "c1" \ - --connector-instance-id "inst123" \ - --interval-seconds 7200 \ - --timeout-seconds 600 - -# Enable or disable instance -secops integration connector-instances update \ - --integration-name "MyIntegration" \ - --connector-id "c1" \ - --connector-instance-id "inst123" \ - --enabled true - -# Update multiple fields with update mask -secops integration connector-instances update \ - --integration-name "MyIntegration" \ - --connector-id "c1" \ - --connector-instance-id "inst123" \ - --display-name "New Name" \ - --interval-seconds 3600 \ - --update-mask "displayName,intervalSeconds" -``` - -Delete a connector instance: - -```bash -secops integration connector-instances delete \ - --integration-name "MyIntegration" \ - --connector-id "c1" \ - --connector-instance-id "inst123" -``` - -Fetch latest definition: - -```bash -# Get the latest definition of a connector instance -secops integration connector-instances fetch-latest \ - --integration-name "MyIntegration" \ - --connector-id "c1" \ - --connector-instance-id "inst123" -``` - -Enable or disable log collection: - -```bash -# Enable log collection for debugging -secops integration connector-instances set-logs \ - --integration-name "MyIntegration" \ - --connector-id "c1" \ - --connector-instance-id "inst123" \ - --enabled true - -# Disable log collection -secops integration connector-instances set-logs \ - --integration-name "MyIntegration" \ - --connector-id "c1" \ - --connector-instance-id "inst123" \ - --enabled false -``` - -Run connector instance on demand: - -```bash -# Trigger an immediate execution for testing -secops integration connector-instances run-ondemand \ - --integration-name "MyIntegration" \ - --connector-id "c1" \ - --connector-instance-id "inst123" -``` - -#### Integration Jobs - -List integration jobs: - -```bash -# List all jobs for an integration -secops integration jobs list --integration-name "MyIntegration" - -# List jobs as a direct list (fetches all pages automatically) -secops integration jobs list --integration-name "MyIntegration" --as-list - -# List with pagination -secops integration jobs list --integration-name "MyIntegration" --page-size 50 - -# List with filtering -secops integration jobs list --integration-name "MyIntegration" --filter-string "enabled = true" - -# Exclude staging jobs -secops integration jobs list --integration-name "MyIntegration" --exclude-staging -``` - -Get job details: - -```bash -secops integration jobs get --integration-name "MyIntegration" --job-id "job1" -``` - -Create a new job: - -```bash -secops integration jobs create \ - --integration-name "MyIntegration" \ - --display-name "Data Processing Job" \ - --code "def process_data(context): return {'status': 'processed'}" - -# Create with description and custom ID -secops integration jobs create \ - --integration-name "MyIntegration" \ - --display-name "Scheduled Report" \ - --code "def generate_report(context): return report_data()" \ - --description "Daily report generation job" \ - --job-id "daily-report-job" - -# Create with parameters -secops integration jobs create \ - --integration-name "MyIntegration" \ - --display-name "Configurable Job" \ - --code "def run(context, params): return process(params)" \ - --parameters '[{"name":"interval","type":"STRING","required":true}]' -``` - -Update an existing job: - -```bash -# Update display name -secops integration jobs update \ - --integration-name "MyIntegration" \ - --job-id "job1" \ - --display-name "Updated Job Name" - -# Update code -secops integration jobs update \ - --integration-name "MyIntegration" \ - --job-id "job1" \ - --code "def run(context): return {'status': 'updated'}" - -# Update multiple fields with update mask -secops integration jobs update \ - --integration-name "MyIntegration" \ - --job-id "job1" \ - --display-name "New Name" \ - --description "New description" \ - --update-mask "displayName,description" - -# Update parameters -secops integration jobs update \ - --integration-name "MyIntegration" \ - --job-id "job1" \ - --parameters '[{"name":"timeout","type":"INTEGER","required":false}]' -``` - -Delete a job: - -```bash -secops integration jobs delete --integration-name "MyIntegration" --job-id "job1" -``` - -Test a job: - -```bash -secops integration jobs test --integration-name "MyIntegration" --job-id "job1" -``` - -Get job template: - -```bash -secops integration jobs template --integration-name "MyIntegration" -``` - -#### Job Revisions - -List job revisions: - -```bash -# List all revisions for a job -secops integration job-revisions list \ - --integration-name "MyIntegration" \ - --job-id "job1" - -# List revisions as a direct list -secops integration job-revisions list \ - --integration-name "MyIntegration" \ - --job-id "job1" \ - --as-list - -# List with pagination -secops integration job-revisions list \ - --integration-name "MyIntegration" \ - --job-id "job1" \ - --page-size 10 - -# List with filtering and ordering -secops integration job-revisions list \ - --integration-name "MyIntegration" \ - --job-id "job1" \ - --filter-string 'version = "1.0"' \ - --order-by "createTime desc" -``` - -Create a revision backup: - -```bash -# Create revision with comment -secops integration job-revisions create \ - --integration-name "MyIntegration" \ - --job-id "job1" \ - --comment "Backup before refactoring job logic" - -# Create revision without comment -secops integration job-revisions create \ - --integration-name "MyIntegration" \ - --job-id "job1" -``` - -Rollback to a previous revision: - -```bash -secops integration job-revisions rollback \ - --integration-name "MyIntegration" \ - --job-id "job1" \ - --revision-id "r456" -``` - -Delete an old revision: - -```bash -secops integration job-revisions delete \ - --integration-name "MyIntegration" \ - --job-id "job1" \ - --revision-id "r789" -``` - -#### Job Context Properties - -List job context properties: - -```bash -# List all properties for a job context -secops integration job-context-properties list \ - --integration-name "MyIntegration" \ - --job-id "job1" \ - --context-id "mycontext" - -# List properties as a direct list -secops integration job-context-properties list \ - --integration-name "MyIntegration" \ - --job-id "job1" \ - --context-id "mycontext" \ - --as-list - -# List with pagination -secops integration job-context-properties list \ - --integration-name "MyIntegration" \ - --job-id "job1" \ - --context-id "mycontext" \ - --page-size 50 - -# List with filtering -secops integration job-context-properties list \ - --integration-name "MyIntegration" \ - --job-id "job1" \ - --context-id "mycontext" \ - --filter-string 'key = "last_run_time"' -``` - -Get a specific context property: - -```bash -secops integration job-context-properties get \ - --integration-name "MyIntegration" \ - --job-id "job1" \ - --context-id "mycontext" \ - --property-id "prop123" -``` - -Create a new context property: - -```bash -# Store last execution time -secops integration job-context-properties create \ - --integration-name "MyIntegration" \ - --job-id "job1" \ - --context-id "mycontext" \ - --key "last_execution_time" \ - --value "2026-03-09T10:00:00Z" - -# Store job state for resumable operations -secops integration job-context-properties create \ - --integration-name "MyIntegration" \ - --job-id "job1" \ - --context-id "mycontext" \ - --key "processing_offset" \ - --value "1000" -``` - -Update a context property: - -```bash -# Update execution time -secops integration job-context-properties update \ - --integration-name "MyIntegration" \ - --job-id "job1" \ - --context-id "mycontext" \ - --property-id "prop123" \ - --value "2026-03-09T11:00:00Z" -``` - -Delete a context property: - -```bash -secops integration job-context-properties delete \ - --integration-name "MyIntegration" \ - --job-id "job1" \ - --context-id "mycontext" \ - --property-id "prop123" -``` - -Clear all context properties: - -```bash -# Clear all properties for a specific context -secops integration job-context-properties clear-all \ - --integration-name "MyIntegration" \ - --job-id "job1" \ - --context-id "mycontext" -``` - -#### Job Instance Logs - -List job instance logs: - -```bash -# List all logs for a job instance -secops integration job-instance-logs list \ - --integration-name "MyIntegration" \ - --job-id "job1" \ - --job-instance-id "inst123" - -# List logs as a direct list -secops integration job-instance-logs list \ - --integration-name "MyIntegration" \ - --job-id "job1" \ - --job-instance-id "inst123" \ - --as-list - -# List with pagination -secops integration job-instance-logs list \ - --integration-name "MyIntegration" \ - --job-id "job1" \ - --job-instance-id "inst123" \ - --page-size 50 - -# List with filtering (filter by severity or timestamp) -secops integration job-instance-logs list \ - --integration-name "MyIntegration" \ - --job-id "job1" \ - --job-instance-id "inst123" \ - --filter-string 'severity = "ERROR"' \ - --order-by "createTime desc" -``` - -Get a specific log entry: - -```bash -secops integration job-instance-logs get \ - --integration-name "MyIntegration" \ - --job-id "job1" \ - --job-instance-id "inst123" \ - --log-id "log456" -``` - -#### Job Instances - -List job instances: - -```bash -# List all instances for a job -secops integration job-instances list \ - --integration-name "MyIntegration" \ - --job-id "job1" - -# List instances as a direct list -secops integration job-instances list \ - --integration-name "MyIntegration" \ - --job-id "job1" \ - --as-list - -# List with pagination -secops integration job-instances list \ - --integration-name "MyIntegration" \ - --job-id "job1" \ - --page-size 50 - -# List with filtering -secops integration job-instances list \ - --integration-name "MyIntegration" \ - --job-id "job1" \ - --filter-string 'enabled = true' -``` - -Get job instance details: - -```bash -secops integration job-instances get \ - --integration-name "MyIntegration" \ - --job-id "job1" \ - --job-instance-id "inst123" -``` - -Create a new job instance: - -```bash -# Create basic job instance -secops integration job-instances create \ - --integration-name "MyIntegration" \ - --job-id "job1" \ - --environment "production" \ - --display-name "Daily Report Generator" - -# Create with schedule and timeout -secops integration job-instances create \ - --integration-name "MyIntegration" \ - --job-id "job1" \ - --environment "production" \ - --display-name "Hourly Data Sync" \ - --schedule "0 * * * *" \ - --timeout-seconds 300 \ - --enabled - -# Create with parameters -secops integration job-instances create \ - --integration-name "MyIntegration" \ - --job-id "job1" \ - --environment "production" \ - --display-name "Custom Job Instance" \ - --schedule "0 0 * * *" \ - --parameters '[{"name":"batch_size","value":"1000"}]' -``` - -Update a job instance: - -```bash -# Update display name -secops integration job-instances update \ - --integration-name "MyIntegration" \ - --job-id "job1" \ - --job-instance-id "inst123" \ - --display-name "Updated Display Name" - -# Update schedule and timeout -secops integration job-instances update \ - --integration-name "MyIntegration" \ - --job-id "job1" \ - --job-instance-id "inst123" \ - --schedule "0 */2 * * *" \ - --timeout-seconds 600 - -# Enable or disable instance -secops integration job-instances update \ - --integration-name "MyIntegration" \ - --job-id "job1" \ - --job-instance-id "inst123" \ - --enabled true - -# Update multiple fields with update mask -secops integration job-instances update \ - --integration-name "MyIntegration" \ - --job-id "job1" \ - --job-instance-id "inst123" \ - --display-name "New Name" \ - --schedule "0 6 * * *" \ - --update-mask "displayName,schedule" - -# Update parameters -secops integration job-instances update \ - --integration-name "MyIntegration" \ - --job-id "job1" \ - --job-instance-id "inst123" \ - --parameters '[{"name":"batch_size","value":"2000"}]' -``` - -Delete a job instance: - -```bash -secops integration job-instances delete \ - --integration-name "MyIntegration" \ - --job-id "job1" \ - --job-instance-id "inst123" -``` - -Run job instance on demand: - -```bash -# Trigger an immediate execution for testing -secops integration job-instances run-ondemand \ - --integration-name "MyIntegration" \ - --job-id "job1" \ - --job-instance-id "inst123" - -# Run with custom parameters -secops integration job-instances run-ondemand \ - --integration-name "MyIntegration" \ - --job-id "job1" \ - --job-instance-id "inst123" \ - --parameters '[{"name":"batch_size","value":"500"}]' -``` - -#### Integration Managers - -List integration managers: - -```bash -# List all managers for an integration -secops integration managers list --integration-name "MyIntegration" - -# List managers as a direct list (fetches all pages automatically) -secops integration managers list --integration-name "MyIntegration" --as-list - -# List with pagination -secops integration managers list --integration-name "MyIntegration" --page-size 50 - -# List with filtering -secops integration managers list --integration-name "MyIntegration" --filter-string "enabled = true" -``` - -Get manager details: - -```bash -secops integration managers get --integration-name "MyIntegration" --manager-id "mgr1" -``` - -Create a new manager: - -```bash -secops integration managers create \ - --integration-name "MyIntegration" \ - --display-name "Configuration Manager" \ - --code "def manage_config(context): return {'status': 'configured'}" - -# Create with description and custom ID -secops integration managers create \ - --integration-name "MyIntegration" \ - --display-name "My Manager" \ - --code "def manage(context): return {}" \ - --description "Manager description" \ - --manager-id "custom-manager-id" -``` - -Update an existing manager: - -```bash -# Update display name -secops integration managers update \ - --integration-name "MyIntegration" \ - --manager-id "mgr1" \ - --display-name "Updated Manager Name" - -# Update code -secops integration managers update \ - --integration-name "MyIntegration" \ - --manager-id "mgr1" \ - --code "def manage(context): return {'status': 'updated'}" - -# Update multiple fields with update mask -secops integration managers update \ - --integration-name "MyIntegration" \ - --manager-id "mgr1" \ - --display-name "New Name" \ - --description "New description" \ - --update-mask "displayName,description" -``` - -Delete a manager: - -```bash -secops integration managers delete --integration-name "MyIntegration" --manager-id "mgr1" -``` - -Get manager template: - -```bash -secops integration managers template --integration-name "MyIntegration" -``` - -#### Manager Revisions - -List manager revisions: - -```bash -# List all revisions for a manager -secops integration manager-revisions list \ - --integration-name "MyIntegration" \ - --manager-id "mgr1" - -# List revisions as a direct list -secops integration manager-revisions list \ - --integration-name "MyIntegration" \ - --manager-id "mgr1" \ - --as-list - -# List with pagination -secops integration manager-revisions list \ - --integration-name "MyIntegration" \ - --manager-id "mgr1" \ - --page-size 10 - -# List with filtering and ordering -secops integration manager-revisions list \ - --integration-name "MyIntegration" \ - --manager-id "mgr1" \ - --filter-string 'version = "1.0"' \ - --order-by "createTime desc" -``` - -Get a specific revision: - -```bash -secops integration manager-revisions get \ - --integration-name "MyIntegration" \ - --manager-id "mgr1" \ - --revision-id "r456" -``` - -Create a revision backup: - -```bash -# Create revision with comment -secops integration manager-revisions create \ - --integration-name "MyIntegration" \ - --manager-id "mgr1" \ - --comment "Backup before major refactor" - -# Create revision without comment -secops integration manager-revisions create \ - --integration-name "MyIntegration" \ - --manager-id "mgr1" -``` - -Rollback to a previous revision: - -```bash -secops integration manager-revisions rollback \ - --integration-name "MyIntegration" \ - --manager-id "mgr1" \ - --revision-id "r456" -``` - -Delete an old revision: - -```bash -secops integration manager-revisions delete \ - --integration-name "MyIntegration" \ - --manager-id "mgr1" \ - --revision-id "r789" -``` - -#### Integration Instances - -List integration instances: - -```bash -# List all instances for an integration -secops integration instances list --integration-name "MyIntegration" - -# List instances as a direct list (fetches all pages automatically) -secops integration instances list --integration-name "MyIntegration" --as-list - -# List with pagination -secops integration instances list --integration-name "MyIntegration" --page-size 50 - -# List with filtering -secops integration instances list --integration-name "MyIntegration" --filter-string "enabled = true" -``` - -Get integration instance details: - -```bash -secops integration instances get \ - --integration-name "MyIntegration" \ - --instance-id "inst123" -``` - -Create a new integration instance: - -```bash -# Create basic integration instance -secops integration instances create \ - --integration-name "MyIntegration" \ - --display-name "Production Instance" \ - --environment "production" - -# Create with description and custom ID -secops integration instances create \ - --integration-name "MyIntegration" \ - --display-name "Test Instance" \ - --environment "test" \ - --description "Testing environment instance" \ - --instance-id "test-inst-001" - -# Create with configuration -secops integration instances create \ - --integration-name "MyIntegration" \ - --display-name "Configured Instance" \ - --environment "production" \ - --config '{"api_key":"secret123","region":"us-east1"}' -``` - -Update an integration instance: - -```bash -# Update display name -secops integration instances update \ - --integration-name "MyIntegration" \ - --instance-id "inst123" \ - --display-name "Updated Instance Name" - -# Update configuration -secops integration instances update \ - --integration-name "MyIntegration" \ - --instance-id "inst123" \ - --config '{"api_key":"newsecret456","region":"us-west1"}' - -# Update multiple fields with update mask -secops integration instances update \ - --integration-name "MyIntegration" \ - --instance-id "inst123" \ - --display-name "New Name" \ - --description "New description" \ - --update-mask "displayName,description" -``` - -Delete an integration instance: - -```bash -secops integration instances delete \ - --integration-name "MyIntegration" \ - --instance-id "inst123" -``` - -Test an integration instance: - -```bash -# Test the instance configuration -secops integration instances test \ - --integration-name "MyIntegration" \ - --instance-id "inst123" -``` - -Get affected items: - -```bash -# Get items affected by this instance -secops integration instances get-affected-items \ - --integration-name "MyIntegration" \ - --instance-id "inst123" -``` - -Get default instance: - -```bash -# Get the default integration instance -secops integration instances get-default \ - --integration-name "MyIntegration" -``` - -#### Integration Transformers - -List integration transformers: - -```bash -# List all transformers for an integration -secops integration transformers list --integration-name "MyIntegration" - -# List transformers as a direct list (fetches all pages automatically) -secops integration transformers list --integration-name "MyIntegration" --as-list - -# List with pagination -secops integration transformers list --integration-name "MyIntegration" --page-size 50 - -# List with filtering -secops integration transformers list --integration-name "MyIntegration" --filter-string "enabled = true" - -# Exclude staging transformers -secops integration transformers list --integration-name "MyIntegration" --exclude-staging - -# List with expanded details -secops integration transformers list --integration-name "MyIntegration" --expand "parameters" -``` - -Get transformer details: - -```bash -# Get basic transformer details -secops integration transformers get \ - --integration-name "MyIntegration" \ - --transformer-id "t1" - -# Get transformer with expanded parameters -secops integration transformers get \ - --integration-name "MyIntegration" \ - --transformer-id "t1" \ - --expand "parameters" -``` - -Create a new transformer: - -```bash -# Create a basic transformer -secops integration transformers create \ - --integration-name "MyIntegration" \ - --display-name "JSON Parser" \ - --script "def transform(data): import json; return json.loads(data)" \ - --script-timeout "60s" \ - --enabled - -# Create transformer with description -secops integration transformers create \ - --integration-name "MyIntegration" \ - --display-name "Data Enricher" \ - --script "def transform(data): return {'enriched': data, 'timestamp': '2024-01-01'}" \ - --script-timeout "120s" \ - --description "Enriches data with additional fields" \ - --enabled -``` - -> **Note:** When creating a transformer: -> - `--script-timeout` should be specified with a unit (e.g., "60s", "2m") -> - Use `--enabled` flag to enable the transformer on creation (default is disabled) -> - The script must be valid Python code with a `transform()` function - -Update an existing transformer: - -```bash -# Update display name -secops integration transformers update \ - --integration-name "MyIntegration" \ - --transformer-id "t1" \ - --display-name "Updated Transformer Name" - -# Update script -secops integration transformers update \ - --integration-name "MyIntegration" \ - --transformer-id "t1" \ - --script "def transform(data): return data.upper()" - -# Update multiple fields -secops integration transformers update \ - --integration-name "MyIntegration" \ - --transformer-id "t1" \ - --display-name "Enhanced Transformer" \ - --description "Updated with better error handling" \ - --script-timeout "90s" \ - --enabled true - -# Update with custom update mask -secops integration transformers update \ - --integration-name "MyIntegration" \ - --transformer-id "t1" \ - --display-name "New Name" \ - --description "New description" \ - --update-mask "displayName,description" -``` - -Delete a transformer: - -```bash -secops integration transformers delete \ - --integration-name "MyIntegration" \ - --transformer-id "t1" -``` - -Test a transformer: - -```bash -# Test an existing transformer to verify it works correctly -secops integration transformers test \ - --integration-name "MyIntegration" \ - --transformer-id "t1" -``` - -Get transformer template: - -```bash -# Get a boilerplate template for creating a new transformer -secops integration transformers template --integration-name "MyIntegration" -``` - -#### Transformer Revisions - -List transformer revisions: - -```bash -# List all revisions for a transformer -secops integration transformer-revisions list \ - --integration-name "MyIntegration" \ - --transformer-id "t1" - -# List revisions as a direct list -secops integration transformer-revisions list \ - --integration-name "MyIntegration" \ - --transformer-id "t1" \ - --as-list - -# List with pagination -secops integration transformer-revisions list \ - --integration-name "MyIntegration" \ - --transformer-id "t1" \ - --page-size 10 - -# List with filtering and ordering -secops integration transformer-revisions list \ - --integration-name "MyIntegration" \ - --transformer-id "t1" \ - --filter-string "version = '1.0'" \ - --order-by "createTime desc" -``` - -Delete a transformer revision: - -```bash -# Delete a specific revision -secops integration transformer-revisions delete \ - --integration-name "MyIntegration" \ - --transformer-id "t1" \ - --revision-id "rev-456" -``` - -Create a new revision: - -```bash -# Create a backup revision before making changes -secops integration transformer-revisions create \ - --integration-name "MyIntegration" \ - --transformer-id "t1" \ - --comment "Backup before major refactor" - -# Create a revision with descriptive comment -secops integration transformer-revisions create \ - --integration-name "MyIntegration" \ - --transformer-id "t1" \ - --comment "Version 2.0 - Enhanced error handling" -``` - -Rollback to a previous revision: - -```bash -# Rollback transformer to a specific revision -secops integration transformer-revisions rollback \ - --integration-name "MyIntegration" \ - --transformer-id "t1" \ - --revision-id "rev-456" -``` - -Example workflow: Safe transformer updates with revision control: - -```bash -# 1. Create a backup revision -secops integration transformer-revisions create \ - --integration-name "MyIntegration" \ - --transformer-id "t1" \ - --comment "Backup before updating transformation logic" - -# 2. Update the transformer -secops integration transformers update \ - --integration-name "MyIntegration" \ - --transformer-id "t1" \ - --script "def transform(data): return data.upper()" \ - --description "Updated with new transformation" - -# 3. Test the updated transformer -secops integration transformers test \ - --integration-name "MyIntegration" \ - --transformer-id "t1" - -# 4. If test fails, rollback to the backup revision -# First, list revisions to get the backup revision ID -secops integration transformer-revisions list \ - --integration-name "MyIntegration" \ - --transformer-id "t1" \ - --order-by "createTime desc" \ - --page-size 1 - -# Then rollback using the revision ID -secops integration transformer-revisions rollback \ - --integration-name "MyIntegration" \ - --transformer-id "t1" \ - --revision-id "rev-backup-id" -``` - -#### Logical Operators - -List logical operators: - -```bash -# List all logical operators for an integration -secops integration logical-operators list --integration-name "MyIntegration" - -# List logical operators as a direct list -secops integration logical-operators list \ - --integration-name "MyIntegration" \ - --as-list - -# List with pagination -secops integration logical-operators list \ - --integration-name "MyIntegration" \ - --page-size 50 - -# List with filtering -secops integration logical-operators list \ - --integration-name "MyIntegration" \ - --filter-string "enabled = true" - -# Exclude staging logical operators -secops integration logical-operators list \ - --integration-name "MyIntegration" \ - --exclude-staging - -# List with expanded details -secops integration logical-operators list \ - --integration-name "MyIntegration" \ - --expand "parameters" -``` - -Get logical operator details: - -```bash -# Get basic logical operator details -secops integration logical-operators get \ - --integration-name "MyIntegration" \ - --logical-operator-id "lo1" - -# Get logical operator with expanded parameters -secops integration logical-operators get \ - --integration-name "MyIntegration" \ - --logical-operator-id "lo1" \ - --expand "parameters" -``` - -Create a new logical operator: - -```bash -# Create a basic equality operator -secops integration logical-operators create \ - --integration-name "MyIntegration" \ - --display-name "Equals Operator" \ - --script "def evaluate(a, b): return a == b" \ - --script-timeout "60s" \ - --enabled - -# Create logical operator with description -secops integration logical-operators create \ - --integration-name "MyIntegration" \ - --display-name "Threshold Checker" \ - --script "def evaluate(value, threshold): return value > threshold" \ - --script-timeout "30s" \ - --description "Checks if value exceeds threshold" \ - --enabled -``` - -> **Note:** When creating a logical operator: -> - `--script-timeout` should be specified with a unit (e.g., "60s", "2m") -> - Use `--enabled` flag to enable the operator on creation (default is disabled) -> - The script must be valid Python code with an `evaluate()` function - -Update an existing logical operator: - -```bash -# Update display name -secops integration logical-operators update \ - --integration-name "MyIntegration" \ - --logical-operator-id "lo1" \ - --display-name "Updated Operator Name" - -# Update script -secops integration logical-operators update \ - --integration-name "MyIntegration" \ - --logical-operator-id "lo1" \ - --script "def evaluate(a, b): return a != b" - -# Update multiple fields -secops integration logical-operators update \ - --integration-name "MyIntegration" \ - --logical-operator-id "lo1" \ - --display-name "Enhanced Operator" \ - --description "Updated with better logic" \ - --script-timeout "45s" \ - --enabled true - -# Update with custom update mask -secops integration logical-operators update \ - --integration-name "MyIntegration" \ - --logical-operator-id "lo1" \ - --display-name "New Name" \ - --description "New description" \ - --update-mask "displayName,description" -``` - -Delete a logical operator: - -```bash -secops integration logical-operators delete \ - --integration-name "MyIntegration" \ - --logical-operator-id "lo1" -``` - -Test a logical operator: - -```bash -# Test an existing logical operator to verify it works correctly -secops integration logical-operators test \ - --integration-name "MyIntegration" \ - --logical-operator-id "lo1" -``` - -Get logical operator template: - -```bash -# Get a boilerplate template for creating a new logical operator -secops integration logical-operators template --integration-name "MyIntegration" -``` - -Example workflow: Building conditional logic: - -```bash -# 1. Get a template to start with -secops integration logical-operators template \ - --integration-name "MyIntegration" - -# 2. Create a severity checker operator -secops integration logical-operators create \ - --integration-name "MyIntegration" \ - --display-name "Severity Level Check" \ - --script "def evaluate(severity, min_level): return severity >= min_level" \ - --script-timeout "30s" \ - --description "Checks if severity meets minimum threshold" - -# 3. Test the operator -secops integration logical-operators test \ - --integration-name "MyIntegration" \ - --logical-operator-id "lo1" - -# 4. Enable the operator if test passes -secops integration logical-operators update \ - --integration-name "MyIntegration" \ - --logical-operator-id "lo1" \ - --enabled true - -# 5. List all operators to see what's available -secops integration logical-operators list \ - --integration-name "MyIntegration" \ - --as-list -``` - -#### Logical Operator Revisions - -List logical operator revisions: - -```bash -# List all revisions for a logical operator -secops integration logical-operator-revisions list \ - --integration-name "MyIntegration" \ - --logical-operator-id "lo1" - -# List revisions as a direct list -secops integration logical-operator-revisions list \ - --integration-name "MyIntegration" \ - --logical-operator-id "lo1" \ - --as-list - -# List with pagination -secops integration logical-operator-revisions list \ - --integration-name "MyIntegration" \ - --logical-operator-id "lo1" \ - --page-size 10 - -# List with filtering and ordering -secops integration logical-operator-revisions list \ - --integration-name "MyIntegration" \ - --logical-operator-id "lo1" \ - --filter-string "version = '1.0'" \ - --order-by "createTime desc" -``` - -Delete a logical operator revision: - -```bash -# Delete a specific revision -secops integration logical-operator-revisions delete \ - --integration-name "MyIntegration" \ - --logical-operator-id "lo1" \ - --revision-id "rev-456" -``` - -Create a new revision: - -```bash -# Create a backup revision before making changes -secops integration logical-operator-revisions create \ - --integration-name "MyIntegration" \ - --logical-operator-id "lo1" \ - --comment "Backup before refactoring evaluation logic" - -# Create a revision with descriptive comment -secops integration logical-operator-revisions create \ - --integration-name "MyIntegration" \ - --logical-operator-id "lo1" \ - --comment "Version 2.0 - Enhanced comparison logic" -``` - -Rollback to a previous revision: - -```bash -# Rollback logical operator to a specific revision -secops integration logical-operator-revisions rollback \ - --integration-name "MyIntegration" \ - --logical-operator-id "lo1" \ - --revision-id "rev-456" -``` - -Example workflow: Safe logical operator updates with revision control: - -```bash -# 1. Create a backup revision -secops integration logical-operator-revisions create \ - --integration-name "MyIntegration" \ - --logical-operator-id "lo1" \ - --comment "Backup before updating conditional logic" - -# 2. Update the logical operator -secops integration logical-operators update \ - --integration-name "MyIntegration" \ - --logical-operator-id "lo1" \ - --script "def evaluate(a, b): return a >= b" \ - --description "Updated with greater-than-or-equal logic" - -# 3. Test the updated logical operator -secops integration logical-operators test \ - --integration-name "MyIntegration" \ - --logical-operator-id "lo1" - -# 4. If test fails, rollback to the backup revision -# First, list revisions to get the backup revision ID -secops integration logical-operator-revisions list \ - --integration-name "MyIntegration" \ - --logical-operator-id "lo1" \ - --order-by "createTime desc" \ - --page-size 1 - -# Then rollback using the revision ID -secops integration logical-operator-revisions rollback \ - --integration-name "MyIntegration" \ - --logical-operator-id "lo1" \ - --revision-id "rev-backup-id" -``` - ### Rule Management List detection rules: diff --git a/README.md b/README.md index 9a49afe9..ccc72370 100644 --- a/README.md +++ b/README.md @@ -1911,280 +1911,6 @@ for watchlist in watchlists: ## Integration Management -### Marketplace Integrations - -List available marketplace integrations: - -```python -# Get all available marketplace integration -integrations = chronicle.list_marketplace_integrations() -for integration in integrations.get("marketplaceIntegrations", []): - integration_title = integration.get("title") - integration_id = integration.get("name", "").split("/")[-1] - integration_version = integration.get("version", "") - documentation_url = integration.get("documentationUri", "") - -# Get all integration as a list -integrations = chronicle.list_marketplace_integrations(as_list=True) - -# Get all currently installed integration -integrations = chronicle.list_marketplace_integrations(filter_string="installed = true") - -# Get all installed integration with updates available -integrations = chronicle.list_marketplace_integrations(filter_string="installed = true AND updateAvailable = true") - -# Specify use of V1 Alpha API version -integrations = chronicle.list_marketplace_integrations(api_version=APIVersion.V1ALPHA) -``` - -Get a specific marketplace integration: - -```python -integration = chronicle.get_marketplace_integration("AWSSecurityHub") -``` - -Get the diff between the currently installed version and the latest -available version of an integration: - -```python -diff = chronicle.get_marketplace_integration_diff("AWSSecurityHub") -``` - -Install or update a marketplace integration: - -```python -# Install an integration with the default settings -integration_name = "AWSSecurityHub" -integration = chronicle.install_marketplace_integration(integration_name) - -# Install to staging environment and override any existing ontology mappings -integration = chronicle.install_marketplace_integration( - integration_name, - staging=True, - override_ontology_mappings=True -) - -# Installing a currently installed integration with no specified version -# number will update it to the latest version -integration = chronicle.install_marketplace_integration(integration_name) - -# Or you can specify a specific version to install -integration = chronicle.install_marketplace_integration( - integration_name, - version="5.0" -) -``` - -Uninstall a marketplace integration: - -```python -chronicle.uninstall_marketplace_integration("AWSSecurityHub") -``` - -### Integrations -List all installed integrations: - -```python -# Get all integrations -integrations = chronicle.list_integrations() -for i in integrations.get("integrations", []): - integration_id = i["identifier"] - integration_display_name = i["displayName"] - integration_type = i["type"] - -# Get all integrations as a list -integrations = chronicle.list_integrations(as_list=True) - -for i in integrations: - integration = chronicle.get_integration(i["identifier"]) - if integration.get("parameters"): - print(json.dumps(integration, indent=2)) - - -# Get integrations ordered by display name -integrations = chronicle.list_integrations(order_by="displayName", as_list=True) - ``` - -Get details of a specific integration: - -```python -integration = chronicle.get_integration("AWSSecurityHub") -``` - -Create an integration: - -```python -from secops.chronicle.models ( - IntegrationParam, - IntegrationParamType, - IntegrationType, - PythonVersion -) - -integration = chronicle.create_integration( - display_name="MyNewIntegration", - staging=True, - description="This is my integration", - python_version=PythonVersion.PYTHON_3_11, - parameters=[ - IntegrationParam( - display_name="AWS Access Key", - property_name="aws_access_key", - type=IntegrationParamType.STRING, - description="AWS access key for authentication", - mandatory=True, - ), - IntegrationParam( - display_name="AWS Secret Key", - property_name="aws_secret_key", - type=IntegrationParamType.PASSWORD, - description="AWS secret key for authentication", - mandatory=False, - ), - ], - categories=[ - "Cloud Security", - "Cloud", - "Security" - ], - integration_type=IntegrationType.RESPONSE, -) -``` - -Update an integration: - -```python -from secops.chronicle.models import IntegrationParam, IntegrationParamType - -updated_integration = chronicle.update_integration( - integration_name="MyNewIntegration", - display_name="Updated Integration Name", - description="Updated description", - parameters=[ - IntegrationParam( - display_name="AWS Region", - property_name="aws_region", - type=IntegrationParamType.STRING, - description="AWS region to use", - mandatory=True, - ), - ], - categories=[ - "Cloud Security", - "Cloud", - "Security" - ], -) -``` - -Delete an integration: - -```python -chronicle.delete_integration("MyNewIntegration") -``` - -Download an entire integration as a bytes object and save it as a .zip file -This includes all the integration details, parameters, and actions in a format that can be re-uploaded to Chronicle or used for backup purposes. - -```python -integration_bytes = chronicle.download_integration("MyIntegration") -with open("MyIntegration.zip", "wb") as f: - f.write(integration_bytes) -``` - -Export selected items from an integration (e.g. only actions) as a .zip file: - -```python -# Export only actions with IDs 1 and 2 from the integration - -export_bytes = chronicle.export_integration_items( - integration_name="AWSSecurityHub", - actions=["1", "2"] # IDs of the actions to export -) -with open("AWSSecurityHub_FullExport.zip", "wb") as f: - f.write(export_bytes) -``` - -Get dependencies for an integration: - -```python -dependencies = chronicle.get_integration_dependencies("AWSSecurityHub") -for dep in dependencies.get("dependencies", []): - parts = dep.split("-") - dependency_name = parts[0] - dependency_version = parts[1] if len(parts) > 1 else "latest" - print(f"Dependency: {dependency_name}, Version: {dependency_version}") -``` - -Force dependency update for an integration: - -```python -# Defining a version: -chronicle.download_integration_dependency( - "MyIntegration", - "boto3==1.42.44" -) - -# Install the latest version of a dependency: -chronicle.download_integration_dependency( - "MyIntegration", - "boto3" -) -``` - -Get remote agents that would be restricted from running an updated version of the integration - -```python -from secops.chronicle.models import PythonVersion - -agents = chronicle.get_integration_restricted_agents( - integration_name="AWSSecurityHub", - required_python_version=PythonVersion.PYTHON_3_11, -) -``` - -Get integration diff between two versions of an integration: - -```python -from secops.chronicle.models import DiffType - -# Get the diff between the commercial version of the integration and the current version in the environment. -diff = chronicle.get_integration_diff( - integration_name="AWSSecurityHub", - diff_type=DiffType.COMMERCIAL -) - -# Get the difference between the staging integration and its matching production version. -diff = chronicle.get_integration_diff( - integration_name="AWSSecurityHub", - diff_type=DiffType.PRODUCTION -) - -# Get the difference between the production integration and its corresponding staging version. -diff = chronicle.get_integration_diff( - integration_name="AWSSecurityHub", - diff_type=DiffType.STAGING -) -``` - -Transition an integration to staging or production environment: - -```python -from secops.chronicle.models import TargetMode - -# Transition to staging environment -chronicle.transition_integration_environment( - integration_name="AWSSecurityHub", - target_mode=TargetMode.STAGING -) - -# Transition to production environment -chronicle.transition_integration_environment( - integration_name="AWSSecurityHub", - target_mode=TargetMode.PRODUCTION -) -``` - ### Integration Actions List all available actions for an integration: @@ -2427,2784 +2153,185 @@ else: print("Test passed - changes saved") ``` -### Integration Connectors +### Integration Managers -List all available connectors for an integration: +List all available managers for an integration: ```python -# Get all connectors for an integration -connectors = chronicle.list_integration_connectors("AWSSecurityHub") +# Get all managers for an integration +managers = chronicle.list_integration_managers("MyIntegration") +for manager in managers.get("managers", []): + print(f"Manager: {manager.get('displayName')}, ID: {manager.get('name')}") -# Get all connectors as a list -connectors = chronicle.list_integration_connectors("AWSSecurityHub", as_list=True) +# Get all managers as a list +managers = chronicle.list_integration_managers("MyIntegration", as_list=True) -# Get only enabled connectors -connectors = chronicle.list_integration_connectors( - "AWSSecurityHub", - filter_string="enabled = true" +# Filter managers by display name +managers = chronicle.list_integration_managers( + "MyIntegration", + filter_string='displayName = "API Helper"' ) -# Exclude staging connectors -connectors = chronicle.list_integration_connectors( - "AWSSecurityHub", - exclude_staging=True +# Sort managers by display name +managers = chronicle.list_integration_managers( + "MyIntegration", + order_by="displayName" ) ``` -Get details of a specific connector: +Get details of a specific manager: ```python -connector = chronicle.get_integration_connector( - integration_name="AWSSecurityHub", - connector_id="123" +manager = chronicle.get_integration_manager( + integration_name="MyIntegration", + manager_id="123" ) ``` -Create an integration connector: +Create an integration manager: ```python -from secops.chronicle.models import ( - ConnectorParameter, - ParamType, - ConnectorParamMode, - ConnectorRule, - ConnectorRuleType -) +new_manager = chronicle.create_integration_manager( + integration_name="MyIntegration", + display_name="API Helper", + description="Shared utility functions for API calls", + script=""" +def make_api_request(url, headers=None): + '''Helper function to make API requests''' + import requests + return requests.get(url, headers=headers) -new_connector = chronicle.create_integration_connector( - integration_name="MyIntegration", - display_name="New Connector", - description="This is a new connector", - script="print('Fetching data...')", - timeout_seconds=300, - enabled=True, - product_field_name="product", - event_field_name="event_type", - parameters=[ - ConnectorParameter( - display_name="API Key", - type=ParamType.PASSWORD, - mode=ConnectorParamMode.CONNECTIVITY, - mandatory=True, - description="API key for authentication" - ) - ], - rules=[ - ConnectorRule( - display_name="Allow List", - type=ConnectorRuleType.ALLOW_LIST - ) - ] +def parse_response(response): + '''Parse API response''' + return response.json() +""" ) ``` -Update an integration connector: +Update an integration manager: ```python -from secops.chronicle.models import ( - ConnectorParameter, - ParamType, - ConnectorParamMode -) - -updated_connector = chronicle.update_integration_connector( - integration_name="MyIntegration", - connector_id="123", - display_name="Updated Connector Name", - description="Updated description", - enabled=False, - timeout_seconds=600, - parameters=[ - ConnectorParameter( - display_name="API Token", - type=ParamType.PASSWORD, - mode=ConnectorParamMode.CONNECTIVITY, - mandatory=True, - description="Updated authentication token" - ) - ], - script="print('Updated connector script')" +updated_manager = chronicle.update_integration_manager( + integration_name="MyIntegration", + manager_id="123", + display_name="Updated API Helper", + description="Updated shared utility functions", + script=""" +def make_api_request(url, headers=None, method='GET'): + '''Updated helper function with method parameter''' + import requests + if method == 'GET': + return requests.get(url, headers=headers) + elif method == 'POST': + return requests.post(url, headers=headers) +""" ) -``` - -Delete an integration connector: -```python -chronicle.delete_integration_connector( +# Update only specific fields +updated_manager = chronicle.update_integration_manager( integration_name="MyIntegration", - connector_id="123" + manager_id="123", + description="New description only" ) ``` -Execute a test run of an integration connector: +Delete an integration manager: ```python -# Test a connector before saving it -connector_config = { - "displayName": "Test Connector", - "script": "print('Testing connector')", - "enabled": True, - "timeoutSeconds": 300, - "productFieldName": "product", - "eventFieldName": "event_type" -} - -test_result = chronicle.execute_integration_connector_test( - integration_name="MyIntegration", - connector=connector_config -) - -print(f"Output: {test_result.get('outputMessage')}") -print(f"Debug: {test_result.get('debugOutputMessage')}") - -# Test with a specific agent for remote execution -test_result = chronicle.execute_integration_connector_test( +chronicle.delete_integration_manager( integration_name="MyIntegration", - connector=connector_config, - agent_identifier="agent-123" + manager_id="123" ) ``` -Get a template for creating a connector in an integration: +Get a template for creating a manager in an integration: ```python -template = chronicle.get_integration_connector_template("MyIntegration") +template = chronicle.get_integration_manager_template("MyIntegration") print(f"Template script: {template.get('script')}") ``` -### Integration Connector Revisions +### Integration Manager Revisions -List all revisions for a specific integration connector: +List all revisions for a specific manager: ```python -# Get all revisions for a connector -revisions = chronicle.list_integration_connector_revisions( +# Get all revisions for a manager +revisions = chronicle.list_integration_manager_revisions( integration_name="MyIntegration", - connector_id="c1" + manager_id="123" ) for revision in revisions.get("revisions", []): - print(f"Revision ID: {revision.get('name')}") - print(f"Comment: {revision.get('comment')}") - print(f"Created: {revision.get('createTime')}") + print(f"Revision: {revision.get('name')}, Comment: {revision.get('comment')}") # Get all revisions as a list -revisions = chronicle.list_integration_connector_revisions( +revisions = chronicle.list_integration_manager_revisions( integration_name="MyIntegration", - connector_id="c1", + manager_id="123", as_list=True ) -# Filter revisions with order -revisions = chronicle.list_integration_connector_revisions( +# Filter revisions +revisions = chronicle.list_integration_manager_revisions( integration_name="MyIntegration", - connector_id="c1", - order_by="createTime desc", - page_size=10 + manager_id="123", + filter_string='comment contains "backup"', + order_by="createTime desc" ) ``` -Delete a specific connector revision: +Get details of a specific revision: ```python -# Clean up old revision from version history -chronicle.delete_integration_connector_revision( +revision = chronicle.get_integration_manager_revision( integration_name="MyIntegration", - connector_id="c1", + manager_id="123", revision_id="r1" ) +print(f"Revision script: {revision.get('manager', {}).get('script')}") ``` -Create a new connector revision snapshot: +Create a new revision snapshot: ```python -# Get the current connector configuration -connector = chronicle.get_integration_connector( - integration_name="MyIntegration", - connector_id="c1" -) - -# Create a revision without comment -new_revision = chronicle.create_integration_connector_revision( - integration_name="MyIntegration", - connector_id="c1", - connector=connector -) - -# Create a revision with descriptive comment -new_revision = chronicle.create_integration_connector_revision( +# Get the current manager +manager = chronicle.get_integration_manager( integration_name="MyIntegration", - connector_id="c1", - connector=connector, - comment="Stable version before adding new field mapping" + manager_id="123" ) -print(f"Created revision: {new_revision.get('name')}") -``` - -Rollback a connector to a previous revision: - -```python -# Revert to a known good configuration -rolled_back = chronicle.rollback_integration_connector_revision( +# Create a revision before making changes +revision = chronicle.create_integration_manager_revision( integration_name="MyIntegration", - connector_id="c1", - revision_id="r1" + manager_id="123", + manager=manager, + comment="Backup before major refactor" ) - -print(f"Rolled back to revision: {rolled_back.get('name')}") -print(f"Connector script restored") +print(f"Created revision: {revision.get('name')}") ``` -Example workflow: Safe connector updates with revisions: +Rollback to a previous revision: ```python -# 1. Get current connector -connector = chronicle.get_integration_connector( - integration_name="MyIntegration", - connector_id="c1" -) - -# 2. Create backup revision before changes -backup = chronicle.create_integration_connector_revision( - integration_name="MyIntegration", - connector_id="c1", - connector=connector, - comment="Backup before timeout increase" -) -print(f"Backup created: {backup.get('name')}") - -# 3. Update the connector -updated_connector = chronicle.update_integration_connector( - integration_name="MyIntegration", - connector_id="c1", - timeout_seconds=600, - description="Increased timeout for large data pulls" -) - -# 4. Test the updated connector -test_result = chronicle.execute_integration_connector_test( +# Rollback to a previous working version +rollback_result = chronicle.rollback_integration_manager_revision( integration_name="MyIntegration", - connector=updated_connector + manager_id="123", + revision_id="acb123de-abcd-1234-ef00-1234567890ab" ) - -# 5. If test fails, rollback to the backup -if not test_result.get("outputMessage"): - print("Test failed, rolling back...") - chronicle.rollback_integration_connector_revision( - integration_name="MyIntegration", - connector_id="c1", - revision_id=backup.get("name").split("/")[-1] - ) - print("Rollback complete") -else: - print("Test passed, changes applied successfully") +print(f"Rolled back to: {rollback_result.get('name')}") ``` -### Connector Context Properties - -List all context properties for a specific connector: +Delete a revision: ```python -# Get all context properties for a connector -context_properties = chronicle.list_connector_context_properties( - integration_name="MyIntegration", - connector_id="c1" -) -for prop in context_properties.get("contextProperties", []): - print(f"Key: {prop.get('key')}, Value: {prop.get('value')}") - -# Get all context properties as a list -context_properties = chronicle.list_connector_context_properties( - integration_name="MyIntegration", - connector_id="c1", - as_list=True -) - -# Filter context properties -context_properties = chronicle.list_connector_context_properties( +chronicle.delete_integration_manager_revision( integration_name="MyIntegration", - connector_id="c1", - filter_string='key = "last_run_time"', - order_by="key" + manager_id="123", + revision_id="r1" ) ``` -Get a specific context property: - -```python -property_value = chronicle.get_connector_context_property( - integration_name="MyIntegration", - connector_id="c1", - context_property_id="last_run_time" -) -print(f"Value: {property_value.get('value')}") -``` - -Create a new context property: - -```python -# Create context property with auto-generated key -new_property = chronicle.create_connector_context_property( - integration_name="MyIntegration", - connector_id="c1", - value="2026-03-09T10:00:00Z" -) - -# Create context property with custom key -new_property = chronicle.create_connector_context_property( - integration_name="MyIntegration", - connector_id="c1", - value="2026-03-09T10:00:00Z", - key="last-sync-time" -) -print(f"Created property: {new_property.get('name')}") -``` - -Update an existing context property: - -```python -# Update property value -updated_property = chronicle.update_connector_context_property( - integration_name="MyIntegration", - connector_id="c1", - context_property_id="last-sync-time", - value="2026-03-09T11:00:00Z" -) -print(f"Updated value: {updated_property.get('value')}") -``` - -Delete a context property: - -```python -chronicle.delete_connector_context_property( - integration_name="MyIntegration", - connector_id="c1", - context_property_id="last-sync-time" -) -``` - -Delete all context properties: - -```python -# Clear all properties for a connector -chronicle.delete_all_connector_context_properties( - integration_name="MyIntegration", - connector_id="c1" -) - -# Clear all properties for a specific context ID -chronicle.delete_all_connector_context_properties( - integration_name="MyIntegration", - connector_id="c1", - context_id="my-context" -) -``` - -Example workflow: Track connector state with context properties: - -```python -# 1. Check if we have a last run time stored -try: - last_run = chronicle.get_connector_context_property( - integration_name="MyIntegration", - connector_id="c1", - context_property_id="last-run-time" - ) - print(f"Last run: {last_run.get('value')}") -except APIError: - print("No previous run time found") - # Create initial property - chronicle.create_connector_context_property( - integration_name="MyIntegration", - connector_id="c1", - value="2026-01-01T00:00:00Z", - key="last-run-time" - ) - -# 2. Run the connector and process data -# ... connector execution logic ... - -# 3. Update the last run time after successful execution -from datetime import datetime -current_time = datetime.utcnow().isoformat() + "Z" -chronicle.update_connector_context_property( - integration_name="MyIntegration", - connector_id="c1", - context_property_id="last-run-time", - value=current_time -) - -# 4. Store additional context like record count -chronicle.create_connector_context_property( - integration_name="MyIntegration", - connector_id="c1", - value="1500", - key="records-processed" -) - -# 5. List all context to see connector state -all_context = chronicle.list_connector_context_properties( - integration_name="MyIntegration", - connector_id="c1", - as_list=True -) -for prop in all_context: - print(f"{prop.get('key')}: {prop.get('value')}") -``` - -### Connector Instance Logs - -List all execution logs for a connector instance: - -```python -# Get all logs for a connector instance -logs = chronicle.list_connector_instance_logs( - integration_name="MyIntegration", - connector_id="c1", - connector_instance_id="ci1" -) -for log in logs.get("logs", []): - print(f"Log ID: {log.get('name')}, Severity: {log.get('severity')}") - print(f"Timestamp: {log.get('timestamp')}") - print(f"Message: {log.get('message')}") - -# Get all logs as a list -logs = chronicle.list_connector_instance_logs( - integration_name="MyIntegration", - connector_id="c1", - connector_instance_id="ci1", - as_list=True -) - -# Filter logs by severity -logs = chronicle.list_connector_instance_logs( - integration_name="MyIntegration", - connector_id="c1", - connector_instance_id="ci1", - filter_string='severity = "ERROR"', - order_by="timestamp desc" -) -``` - -Get a specific log entry: - -```python -log_entry = chronicle.get_connector_instance_log( - integration_name="MyIntegration", - connector_id="c1", - connector_instance_id="ci1", - log_id="log123" -) -print(f"Severity: {log_entry.get('severity')}") -print(f"Timestamp: {log_entry.get('timestamp')}") -print(f"Message: {log_entry.get('message')}") -``` - -Monitor connector execution and troubleshooting: - -```python -# Get recent logs for monitoring -recent_logs = chronicle.list_connector_instance_logs( - integration_name="MyIntegration", - connector_id="c1", - connector_instance_id="ci1", - order_by="timestamp desc", - page_size=10, - as_list=True -) - -# Check for errors -for log in recent_logs: - if log.get("severity") in ["ERROR", "CRITICAL"]: - print(f"Error at {log.get('timestamp')}") - log_details = chronicle.get_connector_instance_log( - integration_name="MyIntegration", - connector_id="c1", - connector_instance_id="ci1", - log_id=log.get("name").split("/")[-1] - ) - print(f"Error message: {log_details.get('message')}") -``` - -Analyze connector performance and reliability: - -```python -# Get all logs to calculate error rate -all_logs = chronicle.list_connector_instance_logs( - integration_name="MyIntegration", - connector_id="c1", - connector_instance_id="ci1", - as_list=True -) - -errors = sum(1 for log in all_logs if log.get("severity") in ["ERROR", "CRITICAL"]) -warnings = sum(1 for log in all_logs if log.get("severity") == "WARNING") -total = len(all_logs) - -if total > 0: - error_rate = (errors / total) * 100 - print(f"Error Rate: {error_rate:.2f}%") - print(f"Total Logs: {total}") - print(f"Errors: {errors}, Warnings: {warnings}") -``` - -### Connector Instances - -List all connector instances for a specific connector: - -```python -# Get all instances for a connector -instances = chronicle.list_connector_instances( - integration_name="MyIntegration", - connector_id="c1" -) -for instance in instances.get("connectorInstances", []): - print(f"Instance: {instance.get('displayName')}, Enabled: {instance.get('enabled')}") - -# Get all instances as a list -instances = chronicle.list_connector_instances( - integration_name="MyIntegration", - connector_id="c1", - as_list=True -) - -# Filter instances -instances = chronicle.list_connector_instances( - integration_name="MyIntegration", - connector_id="c1", - filter_string='enabled = true', - order_by="displayName" -) -``` - -Get a specific connector instance: - -```python -instance = chronicle.get_connector_instance( - integration_name="MyIntegration", - connector_id="c1", - connector_instance_id="ci1" -) -print(f"Display Name: {instance.get('displayName')}") -print(f"Environment: {instance.get('environment')}") -print(f"Interval: {instance.get('intervalSeconds')} seconds") -``` - -Create a new connector instance: - -```python -from secops.chronicle.models import ConnectorInstanceParameter - -# Create basic connector instance -new_instance = chronicle.create_connector_instance( - integration_name="MyIntegration", - connector_id="c1", - environment="production", - display_name="Production Instance", - interval_seconds=3600, # Run every hour - timeout_seconds=300, # 5 minute timeout - enabled=True -) - -# Create instance with parameters -param = ConnectorInstanceParameter() -param.value = "my-api-key" - -new_instance = chronicle.create_connector_instance( - integration_name="MyIntegration", - connector_id="c1", - environment="production", - display_name="Production Instance", - interval_seconds=3600, - timeout_seconds=300, - description="Main production connector instance", - parameters=[param], - enabled=True -) -print(f"Created instance: {new_instance.get('name')}") -``` - -Update an existing connector instance: - -```python -# Update display name -updated_instance = chronicle.update_connector_instance( - integration_name="MyIntegration", - connector_id="c1", - connector_instance_id="ci1", - display_name="Updated Production Instance" -) - -# Update multiple fields including parameters -param = ConnectorInstanceParameter() -param.value = "new-api-key" - -updated_instance = chronicle.update_connector_instance( - integration_name="MyIntegration", - connector_id="c1", - connector_instance_id="ci1", - display_name="Updated Instance", - interval_seconds=7200, # Change to every 2 hours - parameters=[param], - enabled=True -) -``` - -Delete a connector instance: - -```python -chronicle.delete_connector_instance( - integration_name="MyIntegration", - connector_id="c1", - connector_instance_id="ci1" -) -``` - -Refresh instance with latest connector definition: - -```python -# Fetch latest definition from marketplace -refreshed_instance = chronicle.get_connector_instance_latest_definition( - integration_name="MyIntegration", - connector_id="c1", - connector_instance_id="ci1" -) -print(f"Updated to latest definition") -``` - -Enable/disable logs collection for debugging: - -```python -# Enable logs collection -result = chronicle.set_connector_instance_logs_collection( - integration_name="MyIntegration", - connector_id="c1", - connector_instance_id="ci1", - enabled=True -) -print(f"Logs enabled until: {result.get('loggingEnabledUntilUnixMs')}") - -# Disable logs collection -chronicle.set_connector_instance_logs_collection( - integration_name="MyIntegration", - connector_id="c1", - connector_instance_id="ci1", - enabled=False -) -``` - -Run a connector instance on demand for testing: - -```python -# Get the current instance configuration -instance = chronicle.get_connector_instance( - integration_name="MyIntegration", - connector_id="c1", - connector_instance_id="ci1" -) - -# Run on demand to test configuration -test_result = chronicle.run_connector_instance_on_demand( - integration_name="MyIntegration", - connector_id="c1", - connector_instance_id="ci1", - connector_instance=instance -) - -if test_result.get("success"): - print("Test execution successful!") - print(f"Debug output: {test_result.get('debugOutput')}") -else: - print("Test execution failed") - print(f"Error: {test_result.get('debugOutput')}") -``` - -Example workflow: Deploy and test a new connector instance: - -```python -from secops.chronicle.models import ConnectorInstanceParameter - -# 1. Create a new connector instance -param = ConnectorInstanceParameter() -param.value = "test-api-key" - -new_instance = chronicle.create_connector_instance( - integration_name="MyIntegration", - connector_id="c1", - environment="development", - display_name="Dev Test Instance", - interval_seconds=3600, - timeout_seconds=300, - description="Development testing instance", - parameters=[param], - enabled=False # Start disabled for testing -) - -instance_id = new_instance.get("name").split("/")[-1] -print(f"Created instance: {instance_id}") - -# 2. Enable logs collection for debugging -chronicle.set_connector_instance_logs_collection( - integration_name="MyIntegration", - connector_id="c1", - connector_instance_id=instance_id, - enabled=True -) - -# 3. Run on demand to test -test_result = chronicle.run_connector_instance_on_demand( - integration_name="MyIntegration", - connector_id="c1", - connector_instance_id=instance_id, - connector_instance=new_instance -) - -# 4. Check test results -if test_result.get("success"): - print("✓ Test passed - enabling instance") - # Enable the instance for scheduled runs - chronicle.update_connector_instance( - integration_name="MyIntegration", - connector_id="c1", - connector_instance_id=instance_id, - enabled=True - ) -else: - print("✗ Test failed - reviewing logs") - # Get logs to debug the issue - logs = chronicle.list_connector_instance_logs( - integration_name="MyIntegration", - connector_id="c1", - connector_instance_id=instance_id, - filter_string='severity = "ERROR"', - as_list=True - ) - for log in logs: - print(f"Error: {log.get('message')}") - -# 5. Monitor execution after enabling -instances = chronicle.list_connector_instances( - integration_name="MyIntegration", - connector_id="c1", - filter_string=f'name = "{new_instance.get("name")}"', - as_list=True -) -if instances: - print(f"Instance status: Enabled={instances[0].get('enabled')}") -``` - -### Integration Jobs - -List all available jobs for an integration: - -```python -# Get all jobs for an integration -jobs = chronicle.list_integration_jobs("MyIntegration") -for job in jobs.get("jobs", []): - print(f"Job: {job.get('displayName')}, ID: {job.get('name')}") - -# Get all jobs as a list -jobs = chronicle.list_integration_jobs("MyIntegration", as_list=True) - -# Get only custom jobs -jobs = chronicle.list_integration_jobs( - "MyIntegration", - filter_string="custom = true" -) - -# Exclude staging jobs -jobs = chronicle.list_integration_jobs( - "MyIntegration", - exclude_staging=True -) -``` - -Get details of a specific job: - -```python -job = chronicle.get_integration_job( - integration_name="MyIntegration", - job_id="123" -) -``` - -Create an integration job: - -```python -from secops.chronicle.models import JobParameter, ParamType - -new_job = chronicle.create_integration_job( - integration_name="MyIntegration", - display_name="Scheduled Sync Job", - description="Syncs data from external source", - script="print('Running scheduled job...')", - version=1, - enabled=True, - custom=True, - parameters=[ - JobParameter( - id=1, - display_name="Sync Interval", - description="Interval in minutes", - type=ParamType.INT, - mandatory=True, - default_value="60" - ) - ] -) -``` - -Update an integration job: - -```python -from secops.chronicle.models import JobParameter, ParamType - -updated_job = chronicle.update_integration_job( - integration_name="MyIntegration", - job_id="123", - display_name="Updated Job Name", - description="Updated description", - enabled=False, - version=2, - parameters=[ - JobParameter( - id=1, - display_name="New Parameter", - description="Updated parameter", - type=ParamType.STRING, - mandatory=True, - ) - ], - script="print('Updated job script')" -) -``` - -Delete an integration job: - -```python -chronicle.delete_integration_job( - integration_name="MyIntegration", - job_id="123" -) -``` - -Execute a test run of an integration job: - -```python -# Test a job before saving it -job = chronicle.get_integration_job( - integration_name="MyIntegration", - job_id="123" -) - -test_result = chronicle.execute_integration_job_test( - integration_name="MyIntegration", - job=job -) - -print(f"Output: {test_result.get('output')}") -print(f"Debug: {test_result.get('debugOutput')}") - -# Test with a specific agent for remote execution -test_result = chronicle.execute_integration_job_test( - integration_name="MyIntegration", - job=job, - agent_identifier="agent-123" -) -``` - -Get a template for creating a job in an integration: - -```python -template = chronicle.get_integration_job_template("MyIntegration") -print(f"Template script: {template.get('script')}") -``` - -### Integration Managers - -List all available managers for an integration: - -```python -# Get all managers for an integration -managers = chronicle.list_integration_managers("MyIntegration") -for manager in managers.get("managers", []): - print(f"Manager: {manager.get('displayName')}, ID: {manager.get('name')}") - -# Get all managers as a list -managers = chronicle.list_integration_managers("MyIntegration", as_list=True) - -# Filter managers by display name -managers = chronicle.list_integration_managers( - "MyIntegration", - filter_string='displayName = "API Helper"' -) - -# Sort managers by display name -managers = chronicle.list_integration_managers( - "MyIntegration", - order_by="displayName" -) -``` - -Get details of a specific manager: - -```python -manager = chronicle.get_integration_manager( - integration_name="MyIntegration", - manager_id="123" -) -``` - -Create an integration manager: - -```python -new_manager = chronicle.create_integration_manager( - integration_name="MyIntegration", - display_name="API Helper", - description="Shared utility functions for API calls", - script=""" -def make_api_request(url, headers=None): - '''Helper function to make API requests''' - import requests - return requests.get(url, headers=headers) - -def parse_response(response): - '''Parse API response''' - return response.json() -""" -) -``` - -Update an integration manager: - -```python -updated_manager = chronicle.update_integration_manager( - integration_name="MyIntegration", - manager_id="123", - display_name="Updated API Helper", - description="Updated shared utility functions", - script=""" -def make_api_request(url, headers=None, method='GET'): - '''Updated helper function with method parameter''' - import requests - if method == 'GET': - return requests.get(url, headers=headers) - elif method == 'POST': - return requests.post(url, headers=headers) -""" -) - -# Update only specific fields -updated_manager = chronicle.update_integration_manager( - integration_name="MyIntegration", - manager_id="123", - description="New description only" -) -``` - -Delete an integration manager: - -```python -chronicle.delete_integration_manager( - integration_name="MyIntegration", - manager_id="123" -) -``` - -Get a template for creating a manager in an integration: - -```python -template = chronicle.get_integration_manager_template("MyIntegration") -print(f"Template script: {template.get('script')}") -``` - -### Integration Manager Revisions - -List all revisions for a specific manager: - -```python -# Get all revisions for a manager -revisions = chronicle.list_integration_manager_revisions( - integration_name="MyIntegration", - manager_id="123" -) -for revision in revisions.get("revisions", []): - print(f"Revision: {revision.get('name')}, Comment: {revision.get('comment')}") - -# Get all revisions as a list -revisions = chronicle.list_integration_manager_revisions( - integration_name="MyIntegration", - manager_id="123", - as_list=True -) - -# Filter revisions -revisions = chronicle.list_integration_manager_revisions( - integration_name="MyIntegration", - manager_id="123", - filter_string='comment contains "backup"', - order_by="createTime desc" -) -``` - -Get details of a specific revision: - -```python -revision = chronicle.get_integration_manager_revision( - integration_name="MyIntegration", - manager_id="123", - revision_id="r1" -) -print(f"Revision script: {revision.get('manager', {}).get('script')}") -``` - -Create a new revision snapshot: - -```python -# Get the current manager -manager = chronicle.get_integration_manager( - integration_name="MyIntegration", - manager_id="123" -) - -# Create a revision before making changes -revision = chronicle.create_integration_manager_revision( - integration_name="MyIntegration", - manager_id="123", - manager=manager, - comment="Backup before major refactor" -) -print(f"Created revision: {revision.get('name')}") -``` - -Rollback to a previous revision: - -```python -# Rollback to a previous working version -rollback_result = chronicle.rollback_integration_manager_revision( - integration_name="MyIntegration", - manager_id="123", - revision_id="acb123de-abcd-1234-ef00-1234567890ab" -) -print(f"Rolled back to: {rollback_result.get('name')}") -``` - -Delete a revision: - -```python -chronicle.delete_integration_manager_revision( - integration_name="MyIntegration", - manager_id="123", - revision_id="r1" -) -``` - -### Integration Job Revisions - -List all revisions for a specific job: - -```python -# Get all revisions for a job -revisions = chronicle.list_integration_job_revisions( - integration_name="MyIntegration", - job_id="456" -) -for revision in revisions.get("revisions", []): - print(f"Revision: {revision.get('name')}, Comment: {revision.get('comment')}") - -# Get all revisions as a list -revisions = chronicle.list_integration_job_revisions( - integration_name="MyIntegration", - job_id="456", - as_list=True -) - -# Filter revisions by version -revisions = chronicle.list_integration_job_revisions( - integration_name="MyIntegration", - job_id="456", - filter_string='version = "2"', - order_by="createTime desc" -) -``` - -Delete a job revision: - -```python -chronicle.delete_integration_job_revision( - integration_name="MyIntegration", - job_id="456", - revision_id="r2" -) -``` - -Create a new job revision snapshot: - -```python -# Get the current job -job = chronicle.get_integration_job( - integration_name="MyIntegration", - job_id="456" -) - -# Create a revision before making changes -revision = chronicle.create_integration_job_revision( - integration_name="MyIntegration", - job_id="456", - job=job, - comment="Backup before scheduled update" -) -print(f"Created revision: {revision.get('name')}") -``` - -Rollback to a previous job revision: - -```python -# Rollback to a previous working version -rollback_result = chronicle.rollback_integration_job_revision( - integration_name="MyIntegration", - job_id="456", - revision_id="r2" -) -print(f"Rolled back to: {rollback_result.get('name')}") -``` - -### Integration Job Instances - -List all job instances for a specific job: - -```python -# Get all job instances for a job -job_instances = chronicle.list_integration_job_instances( - integration_name="MyIntegration", - job_id="456" -) -for instance in job_instances.get("jobInstances", []): - print(f"Instance: {instance.get('displayName')}, Enabled: {instance.get('enabled')}") - -# Get all job instances as a list -job_instances = chronicle.list_integration_job_instances( - integration_name="MyIntegration", - job_id="456", - as_list=True -) - -# Filter job instances -job_instances = chronicle.list_integration_job_instances( - integration_name="MyIntegration", - job_id="456", - filter_string="enabled = true", - order_by="displayName" -) -``` - -Get details of a specific job instance: - -```python -job_instance = chronicle.get_integration_job_instance( - integration_name="MyIntegration", - job_id="456", - job_instance_id="ji1" -) -print(f"Interval: {job_instance.get('intervalSeconds')} seconds") -``` - -Create a new job instance: - -```python -from secops.chronicle.models import IntegrationJobInstanceParameter - -# Create a job instance with basic scheduling (interval-based) -new_job_instance = chronicle.create_integration_job_instance( - integration_name="MyIntegration", - job_id="456", - display_name="Daily Data Sync", - description="Syncs data from external source daily", - interval_seconds=86400, # 24 hours - enabled=True, - advanced=False, - parameters=[ - IntegrationJobInstanceParameter(value="production"), - IntegrationJobInstanceParameter(value="https://api.example.com") - ] -) -``` - -Create a job instance with advanced scheduling: - -```python -from secops.chronicle.models import ( - AdvancedConfig, - ScheduleType, - DailyScheduleDetails, - Date, - TimeOfDay -) - -# Create with daily schedule -advanced_job_instance = chronicle.create_integration_job_instance( - integration_name="MyIntegration", - job_id="456", - display_name="Daily Backup at 2 AM", - interval_seconds=86400, - enabled=True, - advanced=True, - advanced_config=AdvancedConfig( - time_zone="America/New_York", - schedule_type=ScheduleType.DAILY, - daily_schedule=DailyScheduleDetails( - start_date=Date(year=2025, month=1, day=1), - time=TimeOfDay(hours=2, minutes=0), - interval=1 # Every 1 day - ) - ), - agent="agent-123" # For remote execution -) -``` - -Create a job instance with weekly schedule: - -```python -from secops.chronicle.models import ( - AdvancedConfig, - ScheduleType, - WeeklyScheduleDetails, - DayOfWeek, - Date, - TimeOfDay -) - -# Run every Monday and Friday at 9 AM -weekly_job_instance = chronicle.create_integration_job_instance( - integration_name="MyIntegration", - job_id="456", - display_name="Weekly Report", - interval_seconds=604800, # 1 week - enabled=True, - advanced=True, - advanced_config=AdvancedConfig( - time_zone="UTC", - schedule_type=ScheduleType.WEEKLY, - weekly_schedule=WeeklyScheduleDetails( - start_date=Date(year=2025, month=1, day=1), - days=[DayOfWeek.MONDAY, DayOfWeek.FRIDAY], - time=TimeOfDay(hours=9, minutes=0), - interval=1 # Every 1 week - ) - ) -) -``` - -Create a job instance with monthly schedule: - -```python -from secops.chronicle.models import ( - AdvancedConfig, - ScheduleType, - MonthlyScheduleDetails, - Date, - TimeOfDay -) - -# Run on the 1st of every month at midnight -monthly_job_instance = chronicle.create_integration_job_instance( - integration_name="MyIntegration", - job_id="456", - display_name="Monthly Cleanup", - interval_seconds=2592000, # ~30 days - enabled=True, - advanced=True, - advanced_config=AdvancedConfig( - time_zone="America/Los_Angeles", - schedule_type=ScheduleType.MONTHLY, - monthly_schedule=MonthlyScheduleDetails( - start_date=Date(year=2025, month=1, day=1), - day=1, # Day of month (1-31) - time=TimeOfDay(hours=0, minutes=0), - interval=1 # Every 1 month - ) - ) -) -``` - -Create a one-time job instance: - -```python -from secops.chronicle.models import ( - AdvancedConfig, - ScheduleType, - OneTimeScheduleDetails, - Date, - TimeOfDay -) - -# Run once at a specific date and time -onetime_job_instance = chronicle.create_integration_job_instance( - integration_name="MyIntegration", - job_id="456", - display_name="One-Time Migration", - interval_seconds=0, # Not used for one-time - enabled=True, - advanced=True, - advanced_config=AdvancedConfig( - time_zone="Europe/London", - schedule_type=ScheduleType.ONCE, - one_time_schedule=OneTimeScheduleDetails( - start_date=Date(year=2025, month=12, day=25), - time=TimeOfDay(hours=10, minutes=30) - ) - ) -) -``` - -Update a job instance: - -```python -from secops.chronicle.models import IntegrationJobInstanceParameter - -# Update scheduling and enable/disable -updated_instance = chronicle.update_integration_job_instance( - integration_name="MyIntegration", - job_id="456", - job_instance_id="ji1", - display_name="Updated Sync Job", - interval_seconds=43200, # 12 hours - enabled=False -) - -# Update parameters -updated_instance = chronicle.update_integration_job_instance( - integration_name="MyIntegration", - job_id="456", - job_instance_id="ji1", - parameters=[ - IntegrationJobInstanceParameter(value="staging"), - IntegrationJobInstanceParameter(value="https://staging-api.example.com") - ] -) - -# Update to use advanced scheduling -from secops.chronicle.models import ( - AdvancedConfig, - ScheduleType, - DailyScheduleDetails, - Date, - TimeOfDay -) - -updated_instance = chronicle.update_integration_job_instance( - integration_name="MyIntegration", - job_id="456", - job_instance_id="ji1", - advanced=True, - advanced_config=AdvancedConfig( - time_zone="UTC", - schedule_type=ScheduleType.DAILY, - daily_schedule=DailyScheduleDetails( - start_date=Date(year=2025, month=1, day=1), - time=TimeOfDay(hours=12, minutes=0), - interval=1 - ) - ) -) - -# Update only specific fields -updated_instance = chronicle.update_integration_job_instance( - integration_name="MyIntegration", - job_id="456", - job_instance_id="ji1", - enabled=True, - update_mask="enabled" -) -``` - -Delete a job instance: - -```python -chronicle.delete_integration_job_instance( - integration_name="MyIntegration", - job_id="456", - job_instance_id="ji1" -) -``` - -Run a job instance on demand: - -```python -# Run immediately without waiting for schedule -result = chronicle.run_integration_job_instance_on_demand( - integration_name="MyIntegration", - job_id="456", - job_instance_id="ji1" -) -print(f"Job execution started: {result}") - -# Run with parameter overrides -result = chronicle.run_integration_job_instance_on_demand( - integration_name="MyIntegration", - job_id="456", - job_instance_id="ji1", - parameters=[ - IntegrationJobInstanceParameter(id=1, value="test-mode") - ] -) -``` - -### Job Context Properties - -List all context properties for a job: - -```python -# Get all context properties for a job -context_properties = chronicle.list_job_context_properties( - integration_name="MyIntegration", - job_id="456" -) -for prop in context_properties.get("contextProperties", []): - print(f"Key: {prop.get('key')}, Value: {prop.get('value')}") - -# Get all context properties as a list -context_properties = chronicle.list_job_context_properties( - integration_name="MyIntegration", - job_id="456", - as_list=True -) - -# Filter context properties -context_properties = chronicle.list_job_context_properties( - integration_name="MyIntegration", - job_id="456", - filter_string='key = "api-token"', - order_by="key" -) -``` - -Get a specific context property: - -```python -property_value = chronicle.get_job_context_property( - integration_name="MyIntegration", - job_id="456", - context_property_id="api-endpoint" -) -print(f"Value: {property_value.get('value')}") -``` - -Create a new context property: - -```python -# Create with auto-generated key -new_property = chronicle.create_job_context_property( - integration_name="MyIntegration", - job_id="456", - value="https://api.example.com/v2" -) -print(f"Created property: {new_property.get('key')}") - -# Create with custom key (must be 4-63 chars, match /[a-z][0-9]-/) -new_property = chronicle.create_job_context_property( - integration_name="MyIntegration", - job_id="456", - value="my-secret-token", - key="apitoken" -) -``` - -Update a context property: - -```python -# Update the value of an existing property -updated_property = chronicle.update_job_context_property( - integration_name="MyIntegration", - job_id="456", - context_property_id="api-endpoint", - value="https://api.example.com/v3" -) -print(f"Updated to: {updated_property.get('value')}") -``` - -Delete a context property: - -```python -chronicle.delete_job_context_property( - integration_name="MyIntegration", - job_id="456", - context_property_id="api-endpoint" -) -``` - -Delete all context properties: - -```python -# Clear all context properties for a job -chronicle.delete_all_job_context_properties( - integration_name="MyIntegration", - job_id="456" -) - -# Clear all properties for a specific context ID -chronicle.delete_all_job_context_properties( - integration_name="MyIntegration", - job_id="456", - context_id="mycontext" -) -``` - -### Job Instance Logs - -List all execution logs for a job instance: - -```python -# Get all logs for a job instance -logs = chronicle.list_job_instance_logs( - integration_name="MyIntegration", - job_id="456", - job_instance_id="ji1" -) -for log in logs.get("logs", []): - print(f"Log ID: {log.get('name')}, Status: {log.get('status')}") - print(f"Start: {log.get('startTime')}, End: {log.get('endTime')}") - -# Get all logs as a list -logs = chronicle.list_job_instance_logs( - integration_name="MyIntegration", - job_id="456", - job_instance_id="ji1", - as_list=True -) - -# Filter logs by status -logs = chronicle.list_job_instance_logs( - integration_name="MyIntegration", - job_id="456", - job_instance_id="ji1", - filter_string="status = SUCCESS", - order_by="startTime desc" -) -``` - -Get a specific log entry: - -```python -log_entry = chronicle.get_job_instance_log( - integration_name="MyIntegration", - job_id="456", - job_instance_id="ji1", - log_id="log123" -) -print(f"Status: {log_entry.get('status')}") -print(f"Start Time: {log_entry.get('startTime')}") -print(f"End Time: {log_entry.get('endTime')}") -print(f"Output: {log_entry.get('output')}") -``` - -Browse historical execution logs to monitor job performance: - -```python -# Get recent logs for monitoring -recent_logs = chronicle.list_job_instance_logs( - integration_name="MyIntegration", - job_id="456", - job_instance_id="ji1", - order_by="startTime desc", - page_size=10, - as_list=True -) - -# Check for failures -for log in recent_logs: - if log.get("status") == "FAILED": - print(f"Failed execution at {log.get('startTime')}") - log_details = chronicle.get_job_instance_log( - integration_name="MyIntegration", - job_id="456", - job_instance_id="ji1", - log_id=log.get("name").split("/")[-1] - ) - print(f"Error output: {log_details.get('output')}") -``` - -Monitor job reliability and performance: - -```python -# Get all logs to calculate success rate -all_logs = chronicle.list_job_instance_logs( - integration_name="MyIntegration", - job_id="456", - job_instance_id="ji1", - as_list=True -) - -successful = sum(1 for log in all_logs if log.get("status") == "SUCCESS") -failed = sum(1 for log in all_logs if log.get("status") == "FAILED") -total = len(all_logs) - -if total > 0: - success_rate = (successful / total) * 100 - print(f"Success Rate: {success_rate:.2f}%") - print(f"Total Executions: {total}") - print(f"Successful: {successful}, Failed: {failed}") -``` - -### Integration Instances - -List all instances for a specific integration: - -```python -# Get all instances for an integration -instances = chronicle.list_integration_instances("MyIntegration") -for instance in instances.get("integrationInstances", []): - print(f"Instance: {instance.get('displayName')}, ID: {instance.get('name')}") - print(f"Environment: {instance.get('environment')}") - -# Get all instances as a list -instances = chronicle.list_integration_instances("MyIntegration", as_list=True) - -# Get instances for a specific environment -instances = chronicle.list_integration_instances( - "MyIntegration", - filter_string="environment = 'production'" -) -``` - -Get details of a specific integration instance: - -```python -instance = chronicle.get_integration_instance( - integration_name="MyIntegration", - integration_instance_id="ii1" -) -print(f"Display Name: {instance.get('displayName')}") -print(f"Environment: {instance.get('environment')}") -print(f"Agent: {instance.get('agent')}") -``` - -Create a new integration instance: - -```python -from secops.chronicle.models import IntegrationInstanceParameter - -# Create instance with required fields only -new_instance = chronicle.create_integration_instance( - integration_name="MyIntegration", - environment="production" -) - -# Create instance with all fields -new_instance = chronicle.create_integration_instance( - integration_name="MyIntegration", - environment="production", - display_name="Production Instance", - description="Main production integration instance", - parameters=[ - IntegrationInstanceParameter( - value="api_key_value" - ), - IntegrationInstanceParameter( - value="https://api.example.com" - ) - ], - agent="agent-123" -) -``` - -Update an existing integration instance: - -```python -from secops.chronicle.models import IntegrationInstanceParameter - -# Update instance display name -updated_instance = chronicle.update_integration_instance( - integration_name="MyIntegration", - integration_instance_id="ii1", - display_name="Updated Production Instance" -) - -# Update multiple fields including parameters -updated_instance = chronicle.update_integration_instance( - integration_name="MyIntegration", - integration_instance_id="ii1", - display_name="Updated Instance", - description="Updated description", - environment="staging", - parameters=[ - IntegrationInstanceParameter( - value="new_api_key" - ) - ] -) - -# Use custom update mask -updated_instance = chronicle.update_integration_instance( - integration_name="MyIntegration", - integration_instance_id="ii1", - display_name="New Name", - update_mask="displayName" -) -``` - -Delete an integration instance: - -```python -chronicle.delete_integration_instance( - integration_name="MyIntegration", - integration_instance_id="ii1" -) -``` - -Execute a connectivity test for an integration instance: - -```python -# Test if the instance can connect to the third-party service -test_result = chronicle.execute_integration_instance_test( - integration_name="MyIntegration", - integration_instance_id="ii1" -) -print(f"Test Successful: {test_result.get('successful')}") -print(f"Message: {test_result.get('message')}") -``` - -Get affected items (playbooks) that depend on an integration instance: - -```python -# Perform impact analysis before deleting or modifying an instance -affected_items = chronicle.get_integration_instance_affected_items( - integration_name="MyIntegration", - integration_instance_id="ii1" -) -for playbook in affected_items.get("affectedPlaybooks", []): - print(f"Playbook: {playbook.get('displayName')}") - print(f" ID: {playbook.get('name')}") -``` - -Get the default integration instance: - -```python -# Get the system default configuration for a commercial product -default_instance = chronicle.get_default_integration_instance( - integration_name="AWSSecurityHub" -) -print(f"Default Instance: {default_instance.get('displayName')}") -print(f"Environment: {default_instance.get('environment')}") -``` - -### Integration Transformers - -List all transformers for a specific integration: - -```python -# Get all transformers for an integration -transformers = chronicle.list_integration_transformers("MyIntegration") -for transformer in transformers.get("transformers", []): - print(f"Transformer: {transformer.get('displayName')}, ID: {transformer.get('name')}") - -# Get all transformers as a list -transformers = chronicle.list_integration_transformers("MyIntegration", as_list=True) - -# Get only enabled transformers -transformers = chronicle.list_integration_transformers( - "MyIntegration", - filter_string="enabled = true" -) - -# Exclude staging transformers -transformers = chronicle.list_integration_transformers( - "MyIntegration", - exclude_staging=True -) - -# Get transformers with expanded details -transformers = chronicle.list_integration_transformers( - "MyIntegration", - expand="parameters" -) -``` - -Get details of a specific transformer: - -```python -transformer = chronicle.get_integration_transformer( - integration_name="MyIntegration", - transformer_id="t1" -) -print(f"Display Name: {transformer.get('displayName')}") -print(f"Script: {transformer.get('script')}") -print(f"Enabled: {transformer.get('enabled')}") - -# Get transformer with expanded parameters -transformer = chronicle.get_integration_transformer( - integration_name="MyIntegration", - transformer_id="t1", - expand="parameters" -) -``` - -Create a new transformer: - -```python -# Create a basic transformer -new_transformer = chronicle.create_integration_transformer( - integration_name="MyIntegration", - display_name="JSON Parser", - script=""" -def transform(data): - import json - try: - return json.loads(data) - except Exception as e: - return {"error": str(e)} -""", - script_timeout="60s", - enabled=True -) - -# Create transformer with all fields -new_transformer = chronicle.create_integration_transformer( - integration_name="MyIntegration", - display_name="Advanced Data Transformer", - description="Transforms and enriches incoming data", - script=""" -def transform(data, api_key, endpoint_url): - import json - import requests - - # Parse input data - parsed = json.loads(data) - - # Enrich with external API call - response = requests.get( - endpoint_url, - headers={"Authorization": f"Bearer {api_key}"} - ) - parsed["enrichment"] = response.json() - - return parsed -""", - script_timeout="120s", - enabled=True, - parameters=[ - { - "name": "api_key", - "type": "STRING", - "displayName": "API Key", - "mandatory": True - }, - { - "name": "endpoint_url", - "type": "STRING", - "displayName": "Endpoint URL", - "mandatory": True - } - ], - usage_example="Used to enrich security events with external threat intelligence", - expected_input='{"event": "data", "timestamp": "2024-01-01T00:00:00Z"}', - expected_output='{"event": "data", "timestamp": "2024-01-01T00:00:00Z", "enrichment": {...}}' -) -``` - -Update an existing transformer: - -```python -# Update transformer display name -updated_transformer = chronicle.update_integration_transformer( - integration_name="MyIntegration", - transformer_id="t1", - display_name="Updated Transformer Name" -) - -# Update transformer script -updated_transformer = chronicle.update_integration_transformer( - integration_name="MyIntegration", - transformer_id="t1", - script=""" -def transform(data): - # Updated transformation logic - return data.upper() -""" -) - -# Update multiple fields including parameters -updated_transformer = chronicle.update_integration_transformer( - integration_name="MyIntegration", - transformer_id="t1", - display_name="Enhanced Transformer", - description="Updated with better error handling", - script=""" -def transform(data, timeout=30): - import json - try: - result = json.loads(data) - result["processed"] = True - return result - except Exception as e: - return {"error": str(e), "original": data} -""", - script_timeout="90s", - enabled=True, - parameters=[ - { - "name": "timeout", - "type": "INTEGER", - "displayName": "Processing Timeout", - "mandatory": False, - "defaultValue": "30" - } - ] -) - -# Use custom update mask -updated_transformer = chronicle.update_integration_transformer( - integration_name="MyIntegration", - transformer_id="t1", - display_name="New Name", - description="New Description", - update_mask="displayName,description" -) -``` - -Delete a transformer: - -```python -chronicle.delete_integration_transformer( - integration_name="MyIntegration", - transformer_id="t1" -) -``` - -Execute a test run of a transformer: - -```python -# Get the transformer -transformer = chronicle.get_integration_transformer( - integration_name="MyIntegration", - transformer_id="t1" -) - -# Test the transformer with sample data -test_result = chronicle.execute_integration_transformer_test( - integration_name="MyIntegration", - transformer=transformer -) -print(f"Output Message: {test_result.get('outputMessage')}") -print(f"Debug Output: {test_result.get('debugOutputMessage')}") -print(f"Result Value: {test_result.get('resultValue')}") - -# You can also test a transformer before creating it -test_transformer = { - "displayName": "Test Transformer", - "script": """ -def transform(data): - return {"transformed": data, "status": "success"} -""", - "scriptTimeout": "60s", - "enabled": True -} - -test_result = chronicle.execute_integration_transformer_test( - integration_name="MyIntegration", - transformer=test_transformer -) -``` - -Get a template for creating a transformer: - -```python -# Get a boilerplate template for a new transformer -template = chronicle.get_integration_transformer_template("MyIntegration") -print(f"Template Script: {template.get('script')}") -print(f"Template Display Name: {template.get('displayName')}") - -# Use the template as a starting point -new_transformer = chronicle.create_integration_transformer( - integration_name="MyIntegration", - display_name="My Custom Transformer", - script=template.get('script'), # Customize this - script_timeout="60s", - enabled=True -) -``` - -Example workflow: Safe transformer development with testing: - -```python -# 1. Get a template to start with -template = chronicle.get_integration_transformer_template("MyIntegration") - -# 2. Customize the script -custom_transformer = { - "displayName": "CSV to JSON Transformer", - "description": "Converts CSV data to JSON format", - "script": """ -def transform(data): - import csv - import json - from io import StringIO - - # Parse CSV - reader = csv.DictReader(StringIO(data)) - rows = list(reader) - - return json.dumps(rows) -""", - "scriptTimeout": "60s", - "enabled": False, # Start disabled for testing - "usageExample": "Input CSV with headers, output JSON array of objects" -} - -# 3. Test the transformer before creating it -test_result = chronicle.execute_integration_transformer_test( - integration_name="MyIntegration", - transformer=custom_transformer -) - -# 4. If test is successful, create the transformer -if test_result.get('resultValue'): - created_transformer = chronicle.create_integration_transformer( - integration_name="MyIntegration", - display_name=custom_transformer["displayName"], - description=custom_transformer["description"], - script=custom_transformer["script"], - script_timeout=custom_transformer["scriptTimeout"], - enabled=True, # Enable after successful testing - usage_example=custom_transformer["usageExample"] - ) - print(f"Transformer created: {created_transformer.get('name')}") -else: - print(f"Test failed: {test_result.get('debugOutputMessage')}") - -# 5. Continue testing and refining -transformer_id = created_transformer.get('name').split('/')[-1] -updated = chronicle.update_integration_transformer( - integration_name="MyIntegration", - transformer_id=transformer_id, - script=""" -def transform(data, delimiter=','): - import csv - import json - from io import StringIO - - # Parse CSV with custom delimiter - reader = csv.DictReader(StringIO(data), delimiter=delimiter) - rows = list(reader) - - return json.dumps(rows, indent=2) -""", - parameters=[ - { - "name": "delimiter", - "type": "STRING", - "displayName": "CSV Delimiter", - "mandatory": False, - "defaultValue": "," - } - ] -) -``` - -### Integration Transformer Revisions - -List all revisions for a transformer: - -```python -# Get all revisions for a transformer -revisions = chronicle.list_integration_transformer_revisions( - integration_name="MyIntegration", - transformer_id="t1" -) -for revision in revisions.get("revisions", []): - print(f"Revision: {revision.get('name')}, Comment: {revision.get('comment')}") - -# Get all revisions as a list -revisions = chronicle.list_integration_transformer_revisions( - integration_name="MyIntegration", - transformer_id="t1", - as_list=True -) - -# Filter revisions -revisions = chronicle.list_integration_transformer_revisions( - integration_name="MyIntegration", - transformer_id="t1", - filter_string='version = "1.0"', - order_by="createTime desc" -) -``` - -Delete a specific transformer revision: - -```python -chronicle.delete_integration_transformer_revision( - integration_name="MyIntegration", - transformer_id="t1", - revision_id="rev-456" -) -``` - -Create a new revision before making changes: - -```python -# Get the current transformer -transformer = chronicle.get_integration_transformer( - integration_name="MyIntegration", - transformer_id="t1" -) - -# Create a backup revision -new_revision = chronicle.create_integration_transformer_revision( - integration_name="MyIntegration", - transformer_id="t1", - transformer=transformer, - comment="Backup before major refactor" -) -print(f"Created revision: {new_revision.get('name')}") - -# Create revision with custom comment -new_revision = chronicle.create_integration_transformer_revision( - integration_name="MyIntegration", - transformer_id="t1", - transformer=transformer, - comment="Version 2.0 - Enhanced error handling" -) -``` - -Rollback to a previous revision: - -```python -# Rollback to a previous working version -rollback_result = chronicle.rollback_integration_transformer_revision( - integration_name="MyIntegration", - transformer_id="t1", - revision_id="rev-456" -) -print(f"Rolled back to: {rollback_result.get('name')}") -``` - -Example workflow: Safe transformer updates with revision control: - -```python -# 1. Get the current transformer -transformer = chronicle.get_integration_transformer( - integration_name="MyIntegration", - transformer_id="t1" -) - -# 2. Create a backup revision -backup = chronicle.create_integration_transformer_revision( - integration_name="MyIntegration", - transformer_id="t1", - transformer=transformer, - comment="Backup before updating transformation logic" -) - -# 3. Make changes to the transformer -updated_transformer = chronicle.update_integration_transformer( - integration_name="MyIntegration", - transformer_id="t1", - display_name="Enhanced Transformer", - script=""" -def transform(data, enrichment_enabled=True): - import json - - try: - # Parse input data - parsed = json.loads(data) - - # Apply transformations - parsed["processed"] = True - parsed["timestamp"] = "2024-01-01T00:00:00Z" - - # Optional enrichment - if enrichment_enabled: - parsed["enriched"] = True - - return json.dumps(parsed) - except Exception as e: - return json.dumps({"error": str(e), "original": data}) -""" -) - -# 4. Test the updated transformer -test_result = chronicle.execute_integration_transformer_test( - integration_name="MyIntegration", - transformer=updated_transformer -) - -# 5. If test fails, rollback to backup -if not test_result.get("resultValue"): - print("Test failed - rolling back") - chronicle.rollback_integration_transformer_revision( - integration_name="MyIntegration", - transformer_id="t1", - revision_id=backup.get("name").split("/")[-1] - ) -else: - print("Test passed - transformer updated successfully") - -# 6. List all revisions to see history -all_revisions = chronicle.list_integration_transformer_revisions( - integration_name="MyIntegration", - transformer_id="t1", - as_list=True -) -print(f"Total revisions: {len(all_revisions)}") -for rev in all_revisions: - print(f" - {rev.get('comment', 'No comment')} (ID: {rev.get('name').split('/')[-1]})") -``` - -### Integration Logical Operators - -List all logical operators for a specific integration: - -```python -# Get all logical operators for an integration -logical_operators = chronicle.list_integration_logical_operators("MyIntegration") -for operator in logical_operators.get("logicalOperators", []): - print(f"Operator: {operator.get('displayName')}, ID: {operator.get('name')}") - -# Get all logical operators as a list -logical_operators = chronicle.list_integration_logical_operators( - "MyIntegration", - as_list=True -) - -# Get only enabled logical operators -logical_operators = chronicle.list_integration_logical_operators( - "MyIntegration", - filter_string="enabled = true" -) - -# Exclude staging logical operators -logical_operators = chronicle.list_integration_logical_operators( - "MyIntegration", - exclude_staging=True -) - -# Get logical operators with expanded details -logical_operators = chronicle.list_integration_logical_operators( - "MyIntegration", - expand="parameters" -) -``` - -Get details of a specific logical operator: - -```python -operator = chronicle.get_integration_logical_operator( - integration_name="MyIntegration", - logical_operator_id="lo1" -) -print(f"Display Name: {operator.get('displayName')}") -print(f"Script: {operator.get('script')}") -print(f"Enabled: {operator.get('enabled')}") - -# Get logical operator with expanded parameters -operator = chronicle.get_integration_logical_operator( - integration_name="MyIntegration", - logical_operator_id="lo1", - expand="parameters" -) -``` - -Create a new logical operator: - -```python -# Create a basic equality operator -new_operator = chronicle.create_integration_logical_operator( - integration_name="MyIntegration", - display_name="Equals Operator", - script=""" -def evaluate(a, b): - return a == b -""", - script_timeout="60s", - enabled=True -) - -# Create a more complex conditional operator with parameters -new_operator = chronicle.create_integration_logical_operator( - integration_name="MyIntegration", - display_name="Threshold Checker", - description="Checks if a value exceeds a threshold", - script=""" -def evaluate(value, threshold, inclusive=False): - if inclusive: - return value >= threshold - else: - return value > threshold -""", - script_timeout="30s", - enabled=True, - parameters=[ - { - "name": "value", - "type": "INTEGER", - "displayName": "Value to Check", - "mandatory": True - }, - { - "name": "threshold", - "type": "INTEGER", - "displayName": "Threshold Value", - "mandatory": True - }, - { - "name": "inclusive", - "type": "BOOLEAN", - "displayName": "Inclusive Comparison", - "mandatory": False, - "defaultValue": "false" - } - ] -) - -# Create a string matching operator -pattern_operator = chronicle.create_integration_logical_operator( - integration_name="MyIntegration", - display_name="Pattern Matcher", - description="Matches strings against patterns", - script=""" -def evaluate(text, pattern, case_sensitive=True): - import re - flags = 0 if case_sensitive else re.IGNORECASE - return bool(re.search(pattern, text, flags)) -""", - script_timeout="60s", - enabled=True, - parameters=[ - { - "name": "text", - "type": "STRING", - "displayName": "Text to Match", - "mandatory": True - }, - { - "name": "pattern", - "type": "STRING", - "displayName": "Regex Pattern", - "mandatory": True - }, - { - "name": "case_sensitive", - "type": "BOOLEAN", - "displayName": "Case Sensitive", - "mandatory": False, - "defaultValue": "true" - } - ] -) -``` - -Update an existing logical operator: - -```python -# Update logical operator display name -updated_operator = chronicle.update_integration_logical_operator( - integration_name="MyIntegration", - logical_operator_id="lo1", - display_name="Updated Operator Name" -) - -# Update logical operator script -updated_operator = chronicle.update_integration_logical_operator( - integration_name="MyIntegration", - logical_operator_id="lo1", - script=""" -def evaluate(a, b): - # Updated logic with type checking - if type(a) != type(b): - return False - return a == b -""" -) - -# Update multiple fields including parameters -updated_operator = chronicle.update_integration_logical_operator( - integration_name="MyIntegration", - logical_operator_id="lo1", - display_name="Enhanced Operator", - description="Updated with better validation", - script=""" -def evaluate(value, min_value, max_value): - try: - return min_value <= value <= max_value - except Exception: - return False -""", - script_timeout="45s", - enabled=True, - parameters=[ - { - "name": "value", - "type": "INTEGER", - "displayName": "Value", - "mandatory": True - }, - { - "name": "min_value", - "type": "INTEGER", - "displayName": "Minimum Value", - "mandatory": True - }, - { - "name": "max_value", - "type": "INTEGER", - "displayName": "Maximum Value", - "mandatory": True - } - ] -) - -# Use custom update mask -updated_operator = chronicle.update_integration_logical_operator( - integration_name="MyIntegration", - logical_operator_id="lo1", - display_name="New Name", - description="New Description", - update_mask="displayName,description" -) -``` - -Delete a logical operator: - -```python -chronicle.delete_integration_logical_operator( - integration_name="MyIntegration", - logical_operator_id="lo1" -) -``` - -Execute a test run of a logical operator: - -```python -# Get the logical operator -operator = chronicle.get_integration_logical_operator( - integration_name="MyIntegration", - logical_operator_id="lo1" -) - -# Test the logical operator with sample data -test_result = chronicle.execute_integration_logical_operator_test( - integration_name="MyIntegration", - logical_operator=operator -) -print(f"Output Message: {test_result.get('outputMessage')}") -print(f"Debug Output: {test_result.get('debugOutputMessage')}") -print(f"Result Value: {test_result.get('resultValue')}") # True or False - -# You can also test a logical operator before creating it -test_operator = { - "displayName": "Test Equality Operator", - "script": """ -def evaluate(a, b): - return a == b -""", - "scriptTimeout": "30s", - "enabled": True -} - -test_result = chronicle.execute_integration_logical_operator_test( - integration_name="MyIntegration", - logical_operator=test_operator -) -``` - -Get a template for creating a logical operator: - -```python -# Get a boilerplate template for a new logical operator -template = chronicle.get_integration_logical_operator_template("MyIntegration") -print(f"Template Script: {template.get('script')}") -print(f"Template Display Name: {template.get('displayName')}") - -# Use the template as a starting point -new_operator = chronicle.create_integration_logical_operator( - integration_name="MyIntegration", - display_name="My Custom Operator", - script=template.get('script'), # Customize this - script_timeout="60s", - enabled=True -) -``` - -Example workflow: Building conditional logic for integration workflows: - -```python -# 1. Get a template to start with -template = chronicle.get_integration_logical_operator_template("MyIntegration") - -# 2. Create a custom logical operator for severity checking -severity_operator = chronicle.create_integration_logical_operator( - integration_name="MyIntegration", - display_name="Severity Level Check", - description="Checks if severity meets minimum threshold", - script=""" -def evaluate(severity, min_severity='MEDIUM'): - severity_levels = { - 'LOW': 1, - 'MEDIUM': 2, - 'HIGH': 3, - 'CRITICAL': 4 - } - - current_level = severity_levels.get(severity.upper(), 0) - min_level = severity_levels.get(min_severity.upper(), 0) - - return current_level >= min_level -""", - script_timeout="30s", - enabled=False, # Start disabled for testing - parameters=[ - { - "name": "severity", - "type": "STRING", - "displayName": "Event Severity", - "mandatory": True - }, - { - "name": "min_severity", - "type": "STRING", - "displayName": "Minimum Severity", - "mandatory": False, - "defaultValue": "MEDIUM" - } - ] -) - -# 3. Test the operator before enabling -test_result = chronicle.execute_integration_logical_operator_test( - integration_name="MyIntegration", - logical_operator=severity_operator -) - -# 4. If test is successful, enable the operator -if test_result.get('resultValue') is not None: - operator_id = severity_operator.get('name').split('/')[-1] - enabled_operator = chronicle.update_integration_logical_operator( - integration_name="MyIntegration", - logical_operator_id=operator_id, - enabled=True - ) - print(f"Operator enabled: {enabled_operator.get('name')}") -else: - print(f"Test failed: {test_result.get('debugOutputMessage')}") - -# 5. Create additional operators for workflow automation -# IP address validation operator -ip_validator = chronicle.create_integration_logical_operator( - integration_name="MyIntegration", - display_name="IP Address Validator", - description="Validates if a string is a valid IP address", - script=""" -def evaluate(ip_string): - import ipaddress - try: - ipaddress.ip_address(ip_string) - return True - except ValueError: - return False -""", - script_timeout="30s", - enabled=True -) - -# Time range checker -time_checker = chronicle.create_integration_logical_operator( - integration_name="MyIntegration", - display_name="Business Hours Checker", - description="Checks if timestamp falls within business hours", - script=""" -def evaluate(timestamp, start_hour=9, end_hour=17): - from datetime import datetime - - dt = datetime.fromisoformat(timestamp.replace('Z', '+00:00')) - hour = dt.hour - - return start_hour <= hour < end_hour -""", - script_timeout="30s", - enabled=True, - parameters=[ - { - "name": "timestamp", - "type": "STRING", - "displayName": "Timestamp", - "mandatory": True - }, - { - "name": "start_hour", - "type": "INTEGER", - "displayName": "Business Day Start Hour", - "mandatory": False, - "defaultValue": "9" - }, - { - "name": "end_hour", - "type": "INTEGER", - "displayName": "Business Day End Hour", - "mandatory": False, - "defaultValue": "17" - } - ] -) - -# 6. List all logical operators for the integration -all_operators = chronicle.list_integration_logical_operators( - integration_name="MyIntegration", - as_list=True -) -print(f"Total logical operators: {len(all_operators)}") -for op in all_operators: - print(f" - {op.get('displayName')} (Enabled: {op.get('enabled')})") -``` - -### Integration Logical Operator Revisions - -List all revisions for a logical operator: - -```python -# Get all revisions for a logical operator -revisions = chronicle.list_integration_logical_operator_revisions( - integration_name="MyIntegration", - logical_operator_id="lo1" -) -for revision in revisions.get("revisions", []): - print(f"Revision: {revision.get('name')}, Comment: {revision.get('comment')}") - -# Get all revisions as a list -revisions = chronicle.list_integration_logical_operator_revisions( - integration_name="MyIntegration", - logical_operator_id="lo1", - as_list=True -) - -# Filter revisions -revisions = chronicle.list_integration_logical_operator_revisions( - integration_name="MyIntegration", - logical_operator_id="lo1", - filter_string='version = "1.0"', - order_by="createTime desc" -) -``` - -Delete a specific logical operator revision: - -```python -chronicle.delete_integration_logical_operator_revision( - integration_name="MyIntegration", - logical_operator_id="lo1", - revision_id="rev-456" -) -``` - -Create a new revision before making changes: - -```python -# Get the current logical operator -logical_operator = chronicle.get_integration_logical_operator( - integration_name="MyIntegration", - logical_operator_id="lo1" -) - -# Create a backup revision -new_revision = chronicle.create_integration_logical_operator_revision( - integration_name="MyIntegration", - logical_operator_id="lo1", - logical_operator=logical_operator, - comment="Backup before refactoring conditional logic" -) -print(f"Created revision: {new_revision.get('name')}") - -# Create revision with custom comment -new_revision = chronicle.create_integration_logical_operator_revision( - integration_name="MyIntegration", - logical_operator_id="lo1", - logical_operator=logical_operator, - comment="Version 2.0 - Enhanced comparison logic" -) -``` - -Rollback to a previous revision: - -```python -# Rollback to a previous working version -rollback_result = chronicle.rollback_integration_logical_operator_revision( - integration_name="MyIntegration", - logical_operator_id="lo1", - revision_id="rev-456" -) -print(f"Rolled back to: {rollback_result.get('name')}") -``` - -Example workflow: Safe logical operator updates with revision control: - -```python -# 1. Get the current logical operator -logical_operator = chronicle.get_integration_logical_operator( - integration_name="MyIntegration", - logical_operator_id="lo1" -) - -# 2. Create a backup revision -backup = chronicle.create_integration_logical_operator_revision( - integration_name="MyIntegration", - logical_operator_id="lo1", - logical_operator=logical_operator, - comment="Backup before updating evaluation logic" -) - -# 3. Make changes to the logical operator -updated_operator = chronicle.update_integration_logical_operator( - integration_name="MyIntegration", - logical_operator_id="lo1", - display_name="Enhanced Conditional Operator", - script=""" -def evaluate(severity, threshold, include_medium=False): - severity_levels = { - 'LOW': 1, - 'MEDIUM': 2, - 'HIGH': 3, - 'CRITICAL': 4 - } - - current = severity_levels.get(severity.upper(), 0) - min_level = severity_levels.get(threshold.upper(), 0) - - if include_medium and current >= severity_levels['MEDIUM']: - return True - - return current >= min_level -""" -) - -# 4. Test the updated logical operator -test_result = chronicle.execute_integration_logical_operator_test( - integration_name="MyIntegration", - logical_operator=updated_operator -) - -# 5. If test fails, rollback to backup -if test_result.get("resultValue") is None or "error" in test_result.get("debugOutputMessage", "").lower(): - print("Test failed - rolling back") - chronicle.rollback_integration_logical_operator_revision( - integration_name="MyIntegration", - logical_operator_id="lo1", - revision_id=backup.get("name").split("/")[-1] - ) -else: - print("Test passed - logical operator updated successfully") - -# 6. List all revisions to see history -all_revisions = chronicle.list_integration_logical_operator_revisions( - integration_name="MyIntegration", - logical_operator_id="lo1", - as_list=True -) -print(f"Total revisions: {len(all_revisions)}") -for rev in all_revisions: - print(f" - {rev.get('comment', 'No comment')} (ID: {rev.get('name').split('/')[-1]})") -``` - - ## Rule Management The SDK provides comprehensive support for managing Chronicle detection rules: diff --git a/src/secops/chronicle/__init__.py b/src/secops/chronicle/__init__.py index b3d0b286..e9bd5b46 100644 --- a/src/secops/chronicle/__init__.py +++ b/src/secops/chronicle/__init__.py @@ -214,19 +214,6 @@ create_watchlist, update_watchlist, ) -from secops.chronicle.integration.integrations import ( - list_integrations, - get_integration, - delete_integration, - create_integration, - transition_integration, - update_integration, - update_custom_integration, - get_integration_affected_items, - get_integration_dependencies, - get_integration_diff, - get_integration_restricted_agents, -) from secops.chronicle.integration.actions import ( list_integration_actions, get_integration_action, @@ -243,52 +230,6 @@ create_integration_action_revision, rollback_integration_action_revision, ) -from secops.chronicle.integration.connectors import ( - list_integration_connectors, - get_integration_connector, - delete_integration_connector, - create_integration_connector, - update_integration_connector, - execute_integration_connector_test, - get_integration_connector_template, -) -from secops.chronicle.integration.connector_revisions import ( - list_integration_connector_revisions, - delete_integration_connector_revision, - create_integration_connector_revision, - rollback_integration_connector_revision, -) -from secops.chronicle.integration.connector_context_properties import ( - list_connector_context_properties, - get_connector_context_property, - delete_connector_context_property, - create_connector_context_property, - update_connector_context_property, - delete_all_connector_context_properties, -) -from secops.chronicle.integration.connector_instance_logs import ( - list_connector_instance_logs, - get_connector_instance_log, -) -from secops.chronicle.integration.connector_instances import ( - list_connector_instances, - get_connector_instance, - delete_connector_instance, - create_connector_instance, - update_connector_instance, - get_connector_instance_latest_definition, - set_connector_instance_logs_collection, - run_connector_instance_on_demand, -) -from secops.chronicle.integration.jobs import ( - list_integration_jobs, - get_integration_job, - delete_integration_job, - create_integration_job, - update_integration_job, - execute_integration_job_test, - get_integration_job_template, -) from secops.chronicle.integration.managers import ( list_integration_managers, get_integration_manager, @@ -304,79 +245,6 @@ create_integration_manager_revision, rollback_integration_manager_revision, ) -from secops.chronicle.integration.job_revisions import ( - list_integration_job_revisions, - delete_integration_job_revision, - create_integration_job_revision, - rollback_integration_job_revision, -) -from secops.chronicle.integration.job_instances import ( - list_integration_job_instances, - get_integration_job_instance, - delete_integration_job_instance, - create_integration_job_instance, - update_integration_job_instance, - run_integration_job_instance_on_demand, -) -from secops.chronicle.integration.job_context_properties import ( - list_job_context_properties, - get_job_context_property, - delete_job_context_property, - create_job_context_property, - update_job_context_property, - delete_all_job_context_properties, -) -from secops.chronicle.integration.job_instance_logs import ( - list_job_instance_logs, - get_job_instance_log, -) -from secops.chronicle.integration.integration_instances import ( - list_integration_instances, - get_integration_instance, - delete_integration_instance, - create_integration_instance, - update_integration_instance, - execute_integration_instance_test, - get_integration_instance_affected_items, - get_default_integration_instance, -) -from secops.chronicle.integration.transformers import ( - list_integration_transformers, - get_integration_transformer, - delete_integration_transformer, - create_integration_transformer, - update_integration_transformer, - execute_integration_transformer_test, - get_integration_transformer_template, -) -from secops.chronicle.integration.transformer_revisions import ( - list_integration_transformer_revisions, - delete_integration_transformer_revision, - create_integration_transformer_revision, - rollback_integration_transformer_revision, -) -from secops.chronicle.integration.logical_operators import ( - list_integration_logical_operators, - get_integration_logical_operator, - delete_integration_logical_operator, - create_integration_logical_operator, - update_integration_logical_operator, - execute_integration_logical_operator_test, - get_integration_logical_operator_template, -) -from secops.chronicle.integration.logical_operator_revisions import ( - list_integration_logical_operator_revisions, - delete_integration_logical_operator_revision, - create_integration_logical_operator_revision, - rollback_integration_logical_operator_revision, -) -from secops.chronicle.integration.marketplace_integrations import ( - list_marketplace_integrations, - get_marketplace_integration, - get_marketplace_integration_diff, - install_marketplace_integration, - uninstall_marketplace_integration, -) __all__ = [ # Client @@ -556,18 +424,6 @@ "delete_watchlist", "create_watchlist", "update_watchlist", - # Integrations - "list_integrations", - "get_integration", - "delete_integration", - "create_integration", - "transition_integration", - "update_integration", - "update_custom_integration", - "get_integration_affected_items", - "get_integration_dependencies", - "get_integration_diff", - "get_integration_restricted_agents", # Integration Actions "list_integration_actions", "get_integration_action", @@ -582,46 +438,6 @@ "delete_integration_action_revision", "create_integration_action_revision", "rollback_integration_action_revision", - # Integration Connectors - "list_integration_connectors", - "get_integration_connector", - "delete_integration_connector", - "create_integration_connector", - "update_integration_connector", - "execute_integration_connector_test", - "get_integration_connector_template", - # Integration Connector Revisions - "list_integration_connector_revisions", - "delete_integration_connector_revision", - "create_integration_connector_revision", - "rollback_integration_connector_revision", - # Connector Context Properties - "list_connector_context_properties", - "get_connector_context_property", - "delete_connector_context_property", - "create_connector_context_property", - "update_connector_context_property", - "delete_all_connector_context_properties", - # Connector Instance Logs - "list_connector_instance_logs", - "get_connector_instance_log", - # Connector Instances - "list_connector_instances", - "get_connector_instance", - "delete_connector_instance", - "create_connector_instance", - "update_connector_instance", - "get_connector_instance_latest_definition", - "set_connector_instance_logs_collection", - "run_connector_instance_on_demand", - # Integration Jobs - "list_integration_jobs", - "get_integration_job", - "delete_integration_job", - "create_integration_job", - "update_integration_job", - "execute_integration_job_test", - "get_integration_job_template", # Integration Managers "list_integration_managers", "get_integration_manager", @@ -635,67 +451,4 @@ "delete_integration_manager_revision", "create_integration_manager_revision", "rollback_integration_manager_revision", - # Integration Job Revisions - "list_integration_job_revisions", - "delete_integration_job_revision", - "create_integration_job_revision", - "rollback_integration_job_revision", - # Integration Job Instances - "list_integration_job_instances", - "get_integration_job_instance", - "delete_integration_job_instance", - "create_integration_job_instance", - "update_integration_job_instance", - "run_integration_job_instance_on_demand", - # Job Context Properties - "list_job_context_properties", - "get_job_context_property", - "delete_job_context_property", - "create_job_context_property", - "update_job_context_property", - "delete_all_job_context_properties", - # Job Instance Logs - "list_job_instance_logs", - "get_job_instance_log", - # Integration Instances - "list_integration_instances", - "get_integration_instance", - "delete_integration_instance", - "create_integration_instance", - "update_integration_instance", - "execute_integration_instance_test", - "get_integration_instance_affected_items", - "get_default_integration_instance", - # Integration Transformers - "list_integration_transformers", - "get_integration_transformer", - "delete_integration_transformer", - "create_integration_transformer", - "update_integration_transformer", - "execute_integration_transformer_test", - "get_integration_transformer_template", - # Integration Transformer Revisions - "list_integration_transformer_revisions", - "delete_integration_transformer_revision", - "create_integration_transformer_revision", - "rollback_integration_transformer_revision", - # Integration Logical Operators - "list_integration_logical_operators", - "get_integration_logical_operator", - "delete_integration_logical_operator", - "create_integration_logical_operator", - "update_integration_logical_operator", - "execute_integration_logical_operator_test", - "get_integration_logical_operator_template", - # Integration Logical Operator Revisions - "list_integration_logical_operator_revisions", - "delete_integration_logical_operator_revision", - "create_integration_logical_operator_revision", - "rollback_integration_logical_operator_revision", - # Marketplace Integrations - "list_marketplace_integrations", - "get_marketplace_integration", - "get_marketplace_integration_diff", - "install_marketplace_integration", - "uninstall_marketplace_integration", ] diff --git a/src/secops/chronicle/client.py b/src/secops/chronicle/client.py index e69a9fd2..4c5b13e9 100644 --- a/src/secops/chronicle/client.py +++ b/src/secops/chronicle/client.py @@ -130,30 +130,6 @@ is_valid_log_type as _is_valid_log_type, search_log_types as _search_log_types, ) -from secops.chronicle.integration.marketplace_integrations import ( - get_marketplace_integration as _get_marketplace_integration, - get_marketplace_integration_diff as _get_marketplace_integration_diff, - install_marketplace_integration as _install_marketplace_integration, - list_marketplace_integrations as _list_marketplace_integrations, - uninstall_marketplace_integration as _uninstall_marketplace_integration, -) -from secops.chronicle.integration.integrations import ( - create_integration as _create_integration, - delete_integration as _delete_integration, - download_integration as _download_integration, - download_integration_dependency as _download_integration_dependency, - export_integration_items as _export_integration_items, - get_agent_integrations as _get_agent_integrations, - get_integration as _get_integration, - get_integration_affected_items as _get_integration_affected_items, - get_integration_dependencies as _get_integration_dependencies, - get_integration_diff as _get_integration_diff, - get_integration_restricted_agents as _get_integration_restricted_agents, - list_integrations as _list_integrations, - transition_integration as _transition_integration, - update_custom_integration as _update_custom_integration, - update_integration as _update_integration, -) from secops.chronicle.integration.actions import ( create_integration_action as _create_integration_action, delete_integration_action as _delete_integration_action, @@ -170,52 +146,6 @@ list_integration_action_revisions as _list_integration_action_revisions, rollback_integration_action_revision as _rollback_integration_action_revision, ) -from secops.chronicle.integration.connectors import ( - create_integration_connector as _create_integration_connector, - delete_integration_connector as _delete_integration_connector, - execute_integration_connector_test as _execute_integration_connector_test, - get_integration_connector as _get_integration_connector, - get_integration_connector_template as _get_integration_connector_template, - list_integration_connectors as _list_integration_connectors, - update_integration_connector as _update_integration_connector, -) -from secops.chronicle.integration.connector_revisions import ( - create_integration_connector_revision as _create_integration_connector_revision, - delete_integration_connector_revision as _delete_integration_connector_revision, - list_integration_connector_revisions as _list_integration_connector_revisions, - rollback_integration_connector_revision as _rollback_integration_connector_revision, -) -from secops.chronicle.integration.connector_context_properties import ( - create_connector_context_property as _create_connector_context_property, - delete_all_connector_context_properties as _delete_all_connector_context_properties, - delete_connector_context_property as _delete_connector_context_property, - get_connector_context_property as _get_connector_context_property, - list_connector_context_properties as _list_connector_context_properties, - update_connector_context_property as _update_connector_context_property, -) -from secops.chronicle.integration.connector_instance_logs import ( - get_connector_instance_log as _get_connector_instance_log, - list_connector_instance_logs as _list_connector_instance_logs, -) -from secops.chronicle.integration.connector_instances import ( - create_connector_instance as _create_connector_instance, - delete_connector_instance as _delete_connector_instance, - get_connector_instance as _get_connector_instance, - get_connector_instance_latest_definition as _get_connector_instance_latest_definition, - list_connector_instances as _list_connector_instances, - run_connector_instance_on_demand as _run_connector_instance_on_demand, - set_connector_instance_logs_collection as _set_connector_instance_logs_collection, - update_connector_instance as _update_connector_instance, -) -from secops.chronicle.integration.jobs import ( - create_integration_job as _create_integration_job, - delete_integration_job as _delete_integration_job, - execute_integration_job_test as _execute_integration_job_test, - get_integration_job as _get_integration_job, - get_integration_job_template as _get_integration_job_template, - list_integration_jobs as _list_integration_jobs, - update_integration_job as _update_integration_job, -) from secops.chronicle.integration.managers import ( create_integration_manager as _create_integration_manager, delete_integration_manager as _delete_integration_manager, @@ -231,90 +161,14 @@ list_integration_manager_revisions as _list_integration_manager_revisions, rollback_integration_manager_revision as _rollback_integration_manager_revision, ) -from secops.chronicle.integration.job_revisions import ( - create_integration_job_revision as _create_integration_job_revision, - delete_integration_job_revision as _delete_integration_job_revision, - list_integration_job_revisions as _list_integration_job_revisions, - rollback_integration_job_revision as _rollback_integration_job_revision, -) -from secops.chronicle.integration.job_instances import ( - create_integration_job_instance as _create_integration_job_instance, - delete_integration_job_instance as _delete_integration_job_instance, - get_integration_job_instance as _get_integration_job_instance, - list_integration_job_instances as _list_integration_job_instances, - run_integration_job_instance_on_demand as _run_integration_job_instance_on_demand, - update_integration_job_instance as _update_integration_job_instance, -) -from secops.chronicle.integration.job_context_properties import ( - create_job_context_property as _create_job_context_property, - delete_all_job_context_properties as _delete_all_job_context_properties, - delete_job_context_property as _delete_job_context_property, - get_job_context_property as _get_job_context_property, - list_job_context_properties as _list_job_context_properties, - update_job_context_property as _update_job_context_property, -) -from secops.chronicle.integration.job_instance_logs import ( - get_job_instance_log as _get_job_instance_log, - list_job_instance_logs as _list_job_instance_logs, -) -from secops.chronicle.integration.integration_instances import ( - create_integration_instance as _create_integration_instance, - delete_integration_instance as _delete_integration_instance, - execute_integration_instance_test as _execute_integration_instance_test, - get_default_integration_instance as _get_default_integration_instance, - get_integration_instance as _get_integration_instance, - get_integration_instance_affected_items as _get_integration_instance_affected_items, - list_integration_instances as _list_integration_instances, - update_integration_instance as _update_integration_instance, -) -from secops.chronicle.integration.transformers import ( - create_integration_transformer as _create_integration_transformer, - delete_integration_transformer as _delete_integration_transformer, - execute_integration_transformer_test as _execute_integration_transformer_test, - get_integration_transformer as _get_integration_transformer, - get_integration_transformer_template as _get_integration_transformer_template, - list_integration_transformers as _list_integration_transformers, - update_integration_transformer as _update_integration_transformer, -) -from secops.chronicle.integration.transformer_revisions import ( - create_integration_transformer_revision as _create_integration_transformer_revision, - delete_integration_transformer_revision as _delete_integration_transformer_revision, - list_integration_transformer_revisions as _list_integration_transformer_revisions, - rollback_integration_transformer_revision as _rollback_integration_transformer_revision, -) -from secops.chronicle.integration.logical_operators import ( - create_integration_logical_operator as _create_integration_logical_operator, - delete_integration_logical_operator as _delete_integration_logical_operator, - execute_integration_logical_operator_test as _execute_integration_logical_operator_test, - get_integration_logical_operator as _get_integration_logical_operator, - get_integration_logical_operator_template as _get_integration_logical_operator_template, - list_integration_logical_operators as _list_integration_logical_operators, - update_integration_logical_operator as _update_integration_logical_operator, -) -from secops.chronicle.integration.logical_operator_revisions import ( - create_integration_logical_operator_revision as _create_integration_logical_operator_revision, - delete_integration_logical_operator_revision as _delete_integration_logical_operator_revision, - list_integration_logical_operator_revisions as _list_integration_logical_operator_revisions, - rollback_integration_logical_operator_revision as _rollback_integration_logical_operator_revision, -) from secops.chronicle.models import ( APIVersion, CaseList, - ConnectorParameter, - ConnectorRule, DashboardChart, DashboardQuery, - DiffType, EntitySummary, InputInterval, - IntegrationInstanceParameter, - IntegrationType, - JobParameter, - PythonVersion, - TargetMode, TileType, - IntegrationParam, - ConnectorInstanceParameter, ) from secops.chronicle.nl_search import ( nl_search as _nl_search, @@ -853,4622 +707,407 @@ def update_watchlist( ) # ------------------------------------------------------------------------- - # Marketplace Integration methods + # Integration Action methods # ------------------------------------------------------------------------- - def list_marketplace_integrations( + def list_integration_actions( self, + integration_name: str, page_size: int | None = None, page_token: str | None = None, filter_string: str | None = None, order_by: str | None = None, + expand: str | None = None, api_version: APIVersion | None = APIVersion.V1BETA, as_list: bool = False, ) -> dict[str, Any] | list[dict[str, Any]]: - """Get a list of all marketplace integration. + """Get a list of actions for a given integration. Args: - page_size: Maximum number of integration to return per page - page_token: Token for the next page of results, if available - filter_string: Filter expression to filter marketplace integration - order_by: Field to sort the marketplace integration by - api_version: API version to use. Defaults to V1BETA - as_list: If True, return a list of integration instead of a dict - with integration list and nextPageToken. + integration_name: Name of the integration to get actions for + page_size: Number of results to return per page + page_token: Token for the page to retrieve + filter_string: Filter expression to filter actions + order_by: Field to sort the actions by + expand: Comma-separated list of fields to expand in the response + api_version: API version to use for the request. Default is V1BETA. + as_list: If True, return a list of actions instead of a dict with + actions list and nextPageToken. Returns: - If as_list is True: List of marketplace integration. - If as_list is False: Dict with marketplace integration list and - nextPageToken. + If as_list is True: List of actions. + If as_list is False: Dict with actions list and nextPageToken. Raises: APIError: If the API request fails """ - return _list_marketplace_integrations( + return _list_integration_actions( self, - page_size, - page_token, - filter_string, - order_by, - api_version, - as_list, + integration_name, + page_size=page_size, + page_token=page_token, + filter_string=filter_string, + order_by=order_by, + expand=expand, + api_version=api_version, + as_list=as_list, ) - def get_marketplace_integration( + def get_integration_action( self, integration_name: str, + action_id: str, api_version: APIVersion | None = APIVersion.V1BETA, ) -> dict[str, Any]: - """Get a specific marketplace integration by integration name. + """Get details of a specific action for a given integration. Args: - integration_name: name of the marketplace integration to retrieve - api_version: API version to use. Defaults to V1BETA + integration_name: Name of the integration the action belongs to + action_id: ID of the action to retrieve + api_version: API version to use for the request. Default is V1BETA. Returns: - Marketplace integration details + Dict containing details of the specified action. Raises: APIError: If the API request fails """ - return _get_marketplace_integration(self, integration_name, api_version) + return _get_integration_action( + self, + integration_name, + action_id, + api_version=api_version, + ) - def get_marketplace_integration_diff( + def delete_integration_action( self, integration_name: str, + action_id: str, api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Get the differences between the currently installed version of - an integration and the commercial version available in the - marketplace. + ) -> None: + """Delete a specific action from a given integration. Args: - integration_name: name of the marketplace integration - api_version: API version to use. Defaults to V1BETA + integration_name: Name of the integration the action belongs to + action_id: ID of the action to delete + api_version: API version to use for the request. Default is V1BETA. Returns: - Marketplace integration diff details + None Raises: APIError: If the API request fails """ - return _get_marketplace_integration_diff( - self, integration_name, api_version + return _delete_integration_action( + self, + integration_name, + action_id, + api_version=api_version, ) - def install_marketplace_integration( + def create_integration_action( self, integration_name: str, - override_mapping: bool | None = None, - staging: bool | None = None, - version: str | None = None, - restore_from_snapshot: bool | None = None, + display_name: str, + script: str, + timeout_seconds: int, + enabled: bool, + script_result_name: str, + is_async: bool, + description: str | None = None, + default_result_value: str | None = None, + async_polling_interval_seconds: int | None = None, + async_total_timeout_seconds: int | None = None, + dynamic_results: list[dict[str, Any]] | None = None, + parameters: list[dict[str, Any]] | None = None, + ai_generated: bool | None = None, api_version: APIVersion | None = APIVersion.V1BETA, ) -> dict[str, Any]: - """Install a marketplace integration by integration name - - Args: - integration_name: Name of the marketplace integration to install - override_mapping: Optional. Determines if the integration should - override the ontology if already installed, if not provided, - set to false by default. - staging: Optional. Determines if the integration should be installed - as staging or production, - if not provided, installed as production. - version: Optional. Determines which version of the integration - should be installed. - restore_from_snapshot: Optional. Determines if the integration - should be installed from existing integration snapshot. + """Create a new custom action for a given integration. + + Args: + integration_name: Name of the integration to + create the action for. + display_name: Action's display name. + Maximum 150 characters. Required. + script: Action's Python script. Maximum size 5MB. Required. + timeout_seconds: Action timeout in seconds. Maximum 1200. Required. + enabled: Whether the action is enabled or disabled. Required. + script_result_name: Field name that holds the script result. + Maximum 100 characters. Required. + is_async: Whether the action is asynchronous. Required. + description: Action's description. Maximum 400 characters. Optional. + default_result_value: Action's default result value. + Maximum 1000 characters. Optional. + async_polling_interval_seconds: Polling interval + in seconds for async actions. + Cannot exceed total timeout. Optional. + async_total_timeout_seconds: Total async timeout in seconds. Maximum + 1209600 (14 days). Optional. + dynamic_results: List of dynamic result metadata dicts. + Max 50. Optional. + parameters: List of action parameter dicts. Max 50. Optional. + ai_generated: Whether the action was generated by AI. Optional. api_version: API version to use for the request. Default is V1BETA. Returns: - Installed marketplace integration details + Dict containing the newly created IntegrationAction resource. Raises: - APIError: If the API request fails + APIError: If the API request fails. """ - return _install_marketplace_integration( + return _create_integration_action( self, integration_name, - override_mapping, - staging, - version, - restore_from_snapshot, - api_version, + display_name, + script, + timeout_seconds, + enabled, + script_result_name, + is_async, + description=description, + default_result_value=default_result_value, + async_polling_interval_seconds=async_polling_interval_seconds, + async_total_timeout_seconds=async_total_timeout_seconds, + dynamic_results=dynamic_results, + parameters=parameters, + ai_generated=ai_generated, + api_version=api_version, ) - def uninstall_marketplace_integration( + def update_integration_action( self, integration_name: str, + action_id: str, + display_name: str | None = None, + script: str | None = None, + timeout_seconds: int | None = None, + enabled: bool | None = None, + script_result_name: str | None = None, + is_async: bool | None = None, + description: str | None = None, + default_result_value: str | None = None, + async_polling_interval_seconds: int | None = None, + async_total_timeout_seconds: int | None = None, + dynamic_results: list[dict[str, Any]] | None = None, + parameters: list[dict[str, Any]] | None = None, + ai_generated: bool | None = None, + update_mask: str | None = None, api_version: APIVersion | None = APIVersion.V1BETA, ) -> dict[str, Any]: - """Uninstall a marketplace integration by integration name + """Update an existing custom action for a given integration. + + Only custom actions can be updated; predefined commercial actions are + immutable. Args: - integration_name: Name of the marketplace integration to uninstall + integration_name: Name of the integration the action belongs to. + action_id: ID of the action to update. + display_name: Action's display name. Maximum 150 characters. + script: Action's Python script. Maximum size 5MB. + timeout_seconds: Action timeout in seconds. Maximum 1200. + enabled: Whether the action is enabled or disabled. + script_result_name: Field name that holds the script result. + Maximum 100 characters. + is_async: Whether the action is asynchronous. + description: Action's description. Maximum 400 characters. + default_result_value: Action's default result value. + Maximum 1000 characters. + async_polling_interval_seconds: Polling interval + in seconds for async actions. Cannot exceed total timeout. + async_total_timeout_seconds: Total async timeout in seconds. Maximum + 1209600 (14 days). + dynamic_results: List of dynamic result metadata dicts. Max 50. + parameters: List of action parameter dicts. Max 50. + ai_generated: Whether the action was generated by AI. + update_mask: Comma-separated list of fields to update. If omitted, + the mask is auto-generated from whichever fields are provided. + Example: "displayName,script". api_version: API version to use for the request. Default is V1BETA. Returns: - Empty dictionary if uninstallation is successful + Dict containing the updated IntegrationAction resource. Raises: - APIError: If the API request fails + APIError: If the API request fails. """ - return _uninstall_marketplace_integration( - self, integration_name, api_version + return _update_integration_action( + self, + integration_name, + action_id, + display_name=display_name, + script=script, + timeout_seconds=timeout_seconds, + enabled=enabled, + script_result_name=script_result_name, + is_async=is_async, + description=description, + default_result_value=default_result_value, + async_polling_interval_seconds=async_polling_interval_seconds, + async_total_timeout_seconds=async_total_timeout_seconds, + dynamic_results=dynamic_results, + parameters=parameters, + ai_generated=ai_generated, + update_mask=update_mask, + api_version=api_version, ) - # ------------------------------------------------------------------------- - # Integration methods - # ------------------------------------------------------------------------- - - def list_integrations( + def execute_integration_action_test( self, - page_size: int | None = None, - page_token: str | None = None, - filter_string: str | None = None, - order_by: str | None = None, + integration_name: str, + test_case_id: int, + action: dict[str, Any], + scope: str, + integration_instance_id: str, api_version: APIVersion | None = APIVersion.V1BETA, - as_list: bool = False, - ) -> dict[str, Any] | list[dict[str, Any]]: - """Get a list of all integrations. + ) -> dict[str, Any]: + """Execute a test run of an integration action's script. + + Use this method to verify custom action logic, connectivity, and data + parsing against a specified integration instance and test case before + making the action available in playbooks. Args: - page_size: Maximum number of integrations to return per page - page_token: Token for the next page of results, if available - filter_string: Filter expression to filter integrations. - Only supports "displayName:" prefix. - order_by: Field to sort the integrations by - api_version: API version to use. Defaults to V1BETA - as_list: If True, return a list of integrations instead of a dict - with integration list and nextPageToken. + integration_name: Name of the integration the action belongs to. + test_case_id: ID of the action test case. + action: Dict containing the IntegrationAction to test. + scope: The action test scope. + integration_instance_id: The integration instance ID to use. + api_version: API version to use for the request. Default is V1BETA. Returns: - If as_list is True: List of integrations. - If as_list is False: Dict with integration list and nextPageToken. + Dict with the test execution results with the following fields: + - output: The script output. + - debugOutput: The script debug output. + - resultJson: The result JSON if it exists (optional). + - resultName: The script result name (optional). Raises: - APIError: If the API request fails + APIError: If the API request fails. """ - return _list_integrations( + return _execute_integration_action_test( self, - page_size, - page_token, - filter_string, - order_by, - api_version, - as_list, + integration_name, + test_case_id, + action, + scope, + integration_instance_id, + api_version=api_version, ) - def get_integration( + def get_integration_actions_by_environment( self, integration_name: str, + environments: list[str], + include_widgets: bool, api_version: APIVersion | None = APIVersion.V1BETA, ) -> dict[str, Any]: - """Get a specific integration by integration name. - - Args: - integration_name: name of the integration to retrieve - api_version: API version to use. Defaults to V1BETA + """List actions executable within specified environments. - Returns: - Integration details - - Raises: - APIError: If the API request fails - """ - return _get_integration(self, integration_name, api_version) - - def delete_integration( - self, - integration_name: str, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> None: - """Deletes a specific custom integration. Commercial integrations - cannot be deleted via this method. - - Args: - integration_name: Name of the integration to delete - api_version: API version to use for the request. - Default is V1BETA. - - Raises: - APIError: If the API request fails - """ - _delete_integration(self, integration_name, api_version) - - def create_integration( - self, - display_name: str, - staging: bool, - description: str | None = None, - image_base64: str | None = None, - svg_icon: str | None = None, - python_version: PythonVersion | None = None, - parameters: list[IntegrationParam | dict[str, Any]] | None = None, - categories: list[str] | None = None, - integration_type: IntegrationType | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Creates a new custom SOAR integration. - - Args: - display_name: Required. The display name of the integration - (max 150 characters) - staging: Required. True if the integration is in staging mode - description: Optional. The integration's description - (max 1,500 characters) - image_base64: Optional. The integration's image encoded as a - base64 string (max 5 MB) - svg_icon: Optional. The integration's SVG icon (max 1 MB) - python_version: Optional. The integration's Python version - parameters: Optional. Integration parameters (max 50). - Each entry may be an IntegrationParam dataclass instance - or a plain dict with keys: id, defaultValue, - displayName, propertyName, type, description, mandatory. - categories: Optional. Integration categories (max 50) - integration_type: Optional. The integration's type - (response/extension) - api_version: API version to use for the request. - Default is V1BETA. - - Returns: - Dict containing the details of the newly created integration - - Raises: - APIError: If the API request fails - """ - return _create_integration( - self, - display_name=display_name, - staging=staging, - description=description, - image_base64=image_base64, - svg_icon=svg_icon, - python_version=python_version, - parameters=parameters, - categories=categories, - integration_type=integration_type, - api_version=api_version, - ) - - def download_integration( - self, - integration_name: str, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> bytes: - """Exports the entire integration package as a ZIP file. Includes - all scripts, definitions, and the manifest file. Use this method - for backup or sharing. - - Args: - integration_name: Name of the integration to download - api_version: API version to use for the request. - Default is V1BETA. - - Returns: - Bytes of the ZIP file containing the integration package - - Raises: - APIError: If the API request fails - """ - return _download_integration(self, integration_name, api_version) - - def download_integration_dependency( - self, - integration_name: str, - dependency_name: str, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Initiates the download of a Python dependency (e.g., a library - from PyPI) for a custom integration. - - Args: - integration_name: Name of the integration whose dependency - to download - dependency_name: The dependency name to download. It can - contain the version or the repository. - api_version: API version to use for the request. - Default is V1BETA. - - Returns: - Empty dict if the download was successful, - or a dict containing error - details if the download failed - - Raises: - APIError: If the API request fails - """ - return _download_integration_dependency( - self, integration_name, dependency_name, api_version - ) - - def export_integration_items( - self, - integration_name: str, - actions: list[str] | str | None = None, - jobs: list[str] | str | None = None, - connectors: list[str] | str | None = None, - managers: list[str] | str | None = None, - transformers: list[str] | str | None = None, - logical_operators: list[str] | str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> bytes: - """Exports specific items from an integration into a ZIP folder. - Use this method to extract only a subset of capabilities (e.g., - just the connectors) for reuse. - - Args: - integration_name: Name of the integration to export items from - actions: Optional. IDs of the actions to export as a list or - comma-separated string. Format: [1,2,3] or "1,2,3" - jobs: Optional. IDs of the jobs to export as a list or - comma-separated string. - connectors: Optional. IDs of the connectors to export as a - list or comma-separated string. - managers: Optional. IDs of the managers to export as a list - or comma-separated string. - transformers: Optional. IDs of the transformers to export as - a list or comma-separated string. - logical_operators: Optional. IDs of the logical operators to - export as a list or comma-separated string. - api_version: API version to use for the request. - Default is V1BETA. - - Returns: - Bytes of the ZIP file containing the exported items - - Raises: - APIError: If the API request fails - """ - return _export_integration_items( - self, - integration_name, - actions=actions, - jobs=jobs, - connectors=connectors, - managers=managers, - transformers=transformers, - logical_operators=logical_operators, - api_version=api_version, - ) - - def get_integration_affected_items( - self, - integration_name: str, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Identifies all system items (e.g., connector instances, job - instances, playbooks) that would be affected by a change to or - deletion of this integration. Use this method to conduct impact - analysis before making breaking changes. - - Args: - integration_name: Name of the integration to check for - affected items - api_version: API version to use for the request. - Default is V1BETA. - - Returns: - Dict containing the list of items affected by changes to - the specified integration - - Raises: - APIError: If the API request fails - """ - return _get_integration_affected_items( - self, integration_name, api_version - ) - - def get_agent_integrations( - self, - agent_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Returns the set of integrations currently installed and - configured on a specific agent. - - Args: - agent_id: The agent identifier - api_version: API version to use for the request. - Default is V1BETA. - - Returns: - Dict containing the list of agent-based integrations - - Raises: - APIError: If the API request fails - """ - return _get_agent_integrations(self, agent_id, api_version) - - def get_integration_dependencies( - self, - integration_name: str, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Returns the complete list of Python dependencies currently - associated with a custom integration. - - Args: - integration_name: Name of the integration to check for - dependencies - api_version: API version to use for the request. - Default is V1BETA. - - Returns: - Dict containing the list of dependencies for the specified - integration - - Raises: - APIError: If the API request fails - """ - return _get_integration_dependencies( - self, integration_name, api_version - ) - - def get_integration_diff( - self, - integration_name: str, - diff_type: DiffType | None = DiffType.COMMERCIAL, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Get the configuration diff of a specific integration. - - Args: - integration_name: ID of the integration to retrieve the diff for - diff_type: Type of diff to retrieve (Commercial, Production, or - Staging). Default is Commercial. - COMMERCIAL: Diff between the commercial version of the - integration and the current version in the environment. - PRODUCTION: Returns the difference between the staging - integration and its matching production version. - STAGING: Returns the difference between the production - integration and its corresponding staging version. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing the configuration diff of the specified integration - - Raises: - APIError: If the API request fails - """ - return _get_integration_diff( - self, integration_name, diff_type, api_version - ) - - def get_integration_restricted_agents( - self, - integration_name: str, - required_python_version: PythonVersion, - push_request: bool = False, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Identifies remote agents that would be restricted from running - an updated version of the integration, typically due to environment - incompatibilities like unsupported Python versions. - - Args: - integration_name: Name of the integration to check for - restricted agents - required_python_version: Python version required for the - updated integration - push_request: Optional. Indicates whether the integration is - being pushed to a different mode (production/staging). - False by default. - api_version: API version to use for the request. - Default is V1BETA. - - Returns: - Dict containing the list of agents that would be restricted - from running the updated integration - - Raises: - APIError: If the API request fails - """ - return _get_integration_restricted_agents( - self, - integration_name, - required_python_version=required_python_version, - push_request=push_request, - api_version=api_version, - ) - - def transition_integration( - self, - integration_name: str, - target_mode: TargetMode, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Transitions an integration to a different environment - (e.g. staging to production). - - Args: - integration_name: Name of the integration to transition - target_mode: Target mode to transition the integration to. - PRODUCTION: Transition the integration to production. - STAGING: Transition the integration to staging. - api_version: API version to use for the request. - Default is V1BETA. - - Returns: - Dict containing the details of the transitioned integration - - Raises: - APIError: If the API request fails - """ - return _transition_integration( - self, integration_name, target_mode, api_version - ) - - def update_integration( - self, - integration_name: str, - display_name: str | None = None, - description: str | None = None, - image_base64: str | None = None, - svg_icon: str | None = None, - python_version: PythonVersion | None = None, - parameters: list[dict[str, Any]] | None = None, - categories: list[str] | None = None, - integration_type: IntegrationType | None = None, - staging: bool | None = None, - dependencies_to_remove: list[str] | None = None, - update_mask: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Updates an existing integration's metadata. Use this method to - change the description or display image of a custom integration. - - Args: - integration_name: Name of the integration to update - display_name: Optional. The display name of the integration - (max 150 characters) - description: Optional. The integration's description - (max 1,500 characters) - image_base64: Optional. The integration's image encoded as a - base64 string (max 5 MB) - svg_icon: Optional. The integration's SVG icon (max 1 MB) - python_version: Optional. The integration's Python version - parameters: Optional. Integration parameters (max 50) - categories: Optional. Integration categories (max 50) - integration_type: Optional. The integration's type - (response/extension) - staging: Optional. True if the integration is in staging mode - dependencies_to_remove: Optional. List of dependencies to - remove from the integration - update_mask: Optional. Comma-separated list of fields to - update. If not provided, all non-None fields are updated. - api_version: API version to use for the request. - Default is V1BETA. - - Returns: - Dict containing the details of the updated integration - - Raises: - APIError: If the API request fails - """ - return _update_integration( - self, - integration_name, - display_name=display_name, - description=description, - image_base64=image_base64, - svg_icon=svg_icon, - python_version=python_version, - parameters=parameters, - categories=categories, - integration_type=integration_type, - staging=staging, - dependencies_to_remove=dependencies_to_remove, - update_mask=update_mask, - api_version=api_version, - ) - - def update_custom_integration( - self, - integration_name: str, - display_name: str | None = None, - description: str | None = None, - image_base64: str | None = None, - svg_icon: str | None = None, - python_version: PythonVersion | None = None, - parameters: list[dict[str, Any]] | None = None, - categories: list[str] | None = None, - integration_type: IntegrationType | None = None, - staging: bool | None = None, - dependencies_to_remove: list[str] | None = None, - update_mask: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Updates a custom integration definition, including its - parameters and dependencies. Use this method to refine the - operational behavior of a locally developed integration. - - Args: - integration_name: Name of the integration to update - display_name: Optional. The display name of the integration - (max 150 characters) - description: Optional. The integration's description - (max 1,500 characters) - image_base64: Optional. The integration's image encoded as a - base64 string (max 5 MB) - svg_icon: Optional. The integration's SVG icon (max 1 MB) - python_version: Optional. The integration's Python version - parameters: Optional. Integration parameters (max 50) - categories: Optional. Integration categories (max 50) - integration_type: Optional. The integration's type - (response/extension) - staging: Optional. True if the integration is in staging mode - dependencies_to_remove: Optional. List of dependencies to - remove from the integration - update_mask: Optional. Comma-separated list of fields to - update. If not provided, all non-None fields are updated. - api_version: API version to use for the request. - Default is V1BETA. - - Returns: - Dict containing: - - successful: Whether the integration was updated - successfully - - integration: The updated integration (if successful) - - dependencies: Dependency installation statuses - (if failed) - - Raises: - APIError: If the API request fails - """ - return _update_custom_integration( - self, - integration_name, - display_name=display_name, - description=description, - image_base64=image_base64, - svg_icon=svg_icon, - python_version=python_version, - parameters=parameters, - categories=categories, - integration_type=integration_type, - staging=staging, - dependencies_to_remove=dependencies_to_remove, - update_mask=update_mask, - api_version=api_version, - ) - - # ------------------------------------------------------------------------- - # Integration Action methods - # ------------------------------------------------------------------------- - - def list_integration_actions( - self, - integration_name: str, - page_size: int | None = None, - page_token: str | None = None, - filter_string: str | None = None, - order_by: str | None = None, - expand: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - as_list: bool = False, - ) -> dict[str, Any] | list[dict[str, Any]]: - """Get a list of actions for a given integration. - - Args: - integration_name: Name of the integration to get actions for - page_size: Number of results to return per page - page_token: Token for the page to retrieve - filter_string: Filter expression to filter actions - order_by: Field to sort the actions by - expand: Comma-separated list of fields to expand in the response - api_version: API version to use for the request. Default is V1BETA. - as_list: If True, return a list of actions instead of a dict with - actions list and nextPageToken. - - Returns: - If as_list is True: List of actions. - If as_list is False: Dict with actions list and nextPageToken. - - Raises: - APIError: If the API request fails - """ - return _list_integration_actions( - self, - integration_name, - page_size=page_size, - page_token=page_token, - filter_string=filter_string, - order_by=order_by, - expand=expand, - api_version=api_version, - as_list=as_list, - ) - - def get_integration_action( - self, - integration_name: str, - action_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Get details of a specific action for a given integration. - - Args: - integration_name: Name of the integration the action belongs to - action_id: ID of the action to retrieve - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing details of the specified action. - - Raises: - APIError: If the API request fails - """ - return _get_integration_action( - self, - integration_name, - action_id, - api_version=api_version, - ) - - def delete_integration_action( - self, - integration_name: str, - action_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> None: - """Delete a specific action from a given integration. - - Args: - integration_name: Name of the integration the action belongs to - action_id: ID of the action to delete - api_version: API version to use for the request. Default is V1BETA. - - Returns: - None - - Raises: - APIError: If the API request fails - """ - return _delete_integration_action( - self, - integration_name, - action_id, - api_version=api_version, - ) - - def create_integration_action( - self, - integration_name: str, - display_name: str, - script: str, - timeout_seconds: int, - enabled: bool, - script_result_name: str, - is_async: bool, - description: str | None = None, - default_result_value: str | None = None, - async_polling_interval_seconds: int | None = None, - async_total_timeout_seconds: int | None = None, - dynamic_results: list[dict[str, Any]] | None = None, - parameters: list[dict[str, Any]] | None = None, - ai_generated: bool | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Create a new custom action for a given integration. - - Args: - integration_name: Name of the integration to - create the action for. - display_name: Action's display name. - Maximum 150 characters. Required. - script: Action's Python script. Maximum size 5MB. Required. - timeout_seconds: Action timeout in seconds. Maximum 1200. Required. - enabled: Whether the action is enabled or disabled. Required. - script_result_name: Field name that holds the script result. - Maximum 100 characters. Required. - is_async: Whether the action is asynchronous. Required. - description: Action's description. Maximum 400 characters. Optional. - default_result_value: Action's default result value. - Maximum 1000 characters. Optional. - async_polling_interval_seconds: Polling interval - in seconds for async actions. - Cannot exceed total timeout. Optional. - async_total_timeout_seconds: Total async timeout in seconds. Maximum - 1209600 (14 days). Optional. - dynamic_results: List of dynamic result metadata dicts. - Max 50. Optional. - parameters: List of action parameter dicts. Max 50. Optional. - ai_generated: Whether the action was generated by AI. Optional. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing the newly created IntegrationAction resource. - - Raises: - APIError: If the API request fails. - """ - return _create_integration_action( - self, - integration_name, - display_name, - script, - timeout_seconds, - enabled, - script_result_name, - is_async, - description=description, - default_result_value=default_result_value, - async_polling_interval_seconds=async_polling_interval_seconds, - async_total_timeout_seconds=async_total_timeout_seconds, - dynamic_results=dynamic_results, - parameters=parameters, - ai_generated=ai_generated, - api_version=api_version, - ) - - def update_integration_action( - self, - integration_name: str, - action_id: str, - display_name: str | None = None, - script: str | None = None, - timeout_seconds: int | None = None, - enabled: bool | None = None, - script_result_name: str | None = None, - is_async: bool | None = None, - description: str | None = None, - default_result_value: str | None = None, - async_polling_interval_seconds: int | None = None, - async_total_timeout_seconds: int | None = None, - dynamic_results: list[dict[str, Any]] | None = None, - parameters: list[dict[str, Any]] | None = None, - ai_generated: bool | None = None, - update_mask: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Update an existing custom action for a given integration. - - Only custom actions can be updated; predefined commercial actions are - immutable. - - Args: - integration_name: Name of the integration the action belongs to. - action_id: ID of the action to update. - display_name: Action's display name. Maximum 150 characters. - script: Action's Python script. Maximum size 5MB. - timeout_seconds: Action timeout in seconds. Maximum 1200. - enabled: Whether the action is enabled or disabled. - script_result_name: Field name that holds the script result. - Maximum 100 characters. - is_async: Whether the action is asynchronous. - description: Action's description. Maximum 400 characters. - default_result_value: Action's default result value. - Maximum 1000 characters. - async_polling_interval_seconds: Polling interval - in seconds for async actions. Cannot exceed total timeout. - async_total_timeout_seconds: Total async timeout in seconds. Maximum - 1209600 (14 days). - dynamic_results: List of dynamic result metadata dicts. Max 50. - parameters: List of action parameter dicts. Max 50. - ai_generated: Whether the action was generated by AI. - update_mask: Comma-separated list of fields to update. If omitted, - the mask is auto-generated from whichever fields are provided. - Example: "displayName,script". - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing the updated IntegrationAction resource. - - Raises: - APIError: If the API request fails. - """ - return _update_integration_action( - self, - integration_name, - action_id, - display_name=display_name, - script=script, - timeout_seconds=timeout_seconds, - enabled=enabled, - script_result_name=script_result_name, - is_async=is_async, - description=description, - default_result_value=default_result_value, - async_polling_interval_seconds=async_polling_interval_seconds, - async_total_timeout_seconds=async_total_timeout_seconds, - dynamic_results=dynamic_results, - parameters=parameters, - ai_generated=ai_generated, - update_mask=update_mask, - api_version=api_version, - ) - - def execute_integration_action_test( - self, - integration_name: str, - test_case_id: int, - action: dict[str, Any], - scope: str, - integration_instance_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Execute a test run of an integration action's script. - - Use this method to verify custom action logic, connectivity, and data - parsing against a specified integration instance and test case before - making the action available in playbooks. - - Args: - integration_name: Name of the integration the action belongs to. - test_case_id: ID of the action test case. - action: Dict containing the IntegrationAction to test. - scope: The action test scope. - integration_instance_id: The integration instance ID to use. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict with the test execution results with the following fields: - - output: The script output. - - debugOutput: The script debug output. - - resultJson: The result JSON if it exists (optional). - - resultName: The script result name (optional). - - Raises: - APIError: If the API request fails. - """ - return _execute_integration_action_test( - self, - integration_name, - test_case_id, - action, - scope, - integration_instance_id, - api_version=api_version, - ) - - def get_integration_actions_by_environment( - self, - integration_name: str, - environments: list[str], - include_widgets: bool, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """List actions executable within specified environments. - - Use this method to discover which automated tasks have active - integration instances configured for a particular - network or organizational context. - - Args: - integration_name: Name of the integration to fetch actions for. - environments: List of environments to filter actions by. - include_widgets: Whether to include widget actions in the response. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing a list of IntegrationAction objects that have - integration instances in one of the given environments. - - Raises: - APIError: If the API request fails. - """ - return _get_integration_actions_by_environment( - self, - integration_name, - environments, - include_widgets, - api_version=api_version, - ) - - def get_integration_action_template( - self, - integration_name: str, - is_async: bool = False, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Retrieve a default Python script template for a new - integration action. - - Use this method to jumpstart the development of a custom automated task - by providing boilerplate code for either synchronous or asynchronous - operations. - - Args: - integration_name: Name of the integration to fetch the template for. - is_async: Whether to fetch a template for an async action. Default - is False. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing the IntegrationAction template. - - Raises: - APIError: If the API request fails. - """ - return _get_integration_action_template( - self, - integration_name, - is_async=is_async, - api_version=api_version, - ) - - # ------------------------------------------------------------------------- - # Integration Action Revisions methods - # ------------------------------------------------------------------------- - - def list_integration_action_revisions( - self, - integration_name: str, - action_id: str, - page_size: int | None = None, - page_token: str | None = None, - filter_string: str | None = None, - order_by: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - as_list: bool = False, - ) -> dict[str, Any] | list[dict[str, Any]]: - """List all revisions for a specific integration action. - - Use this method to view the history of changes to an action, - enabling version control and the ability to rollback to - previous configurations. - - Args: - integration_name: Name of the integration the action - belongs to. - action_id: ID of the action to list revisions for. - page_size: Maximum number of revisions to return. - page_token: Page token from a previous call to retrieve the - next page. - filter_string: Filter expression to filter revisions. - order_by: Field to sort the revisions by. - api_version: API version to use for the request. Default is - V1BETA. - as_list: If True, return a list of revisions instead of a - dict with revisions list and nextPageToken. - - Returns: - If as_list is True: List of action revisions. - If as_list is False: Dict with action revisions list and - nextPageToken. - - Raises: - APIError: If the API request fails. - """ - return _list_integration_action_revisions( - self, - integration_name, - action_id, - page_size=page_size, - page_token=page_token, - filter_string=filter_string, - order_by=order_by, - api_version=api_version, - as_list=as_list, - ) - - def delete_integration_action_revision( - self, - integration_name: str, - action_id: str, - revision_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> None: - """Delete a specific action revision. - - Use this method to permanently remove a revision from the - action's history. - - Args: - integration_name: Name of the integration the action - belongs to. - action_id: ID of the action the revision belongs to. - revision_id: ID of the revision to delete. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - None - - Raises: - APIError: If the API request fails. - """ - return _delete_integration_action_revision( - self, - integration_name, - action_id, - revision_id, - api_version=api_version, - ) - - def create_integration_action_revision( - self, - integration_name: str, - action_id: str, - action: dict[str, Any], - comment: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Create a new revision for an integration action. - - Use this method to save a snapshot of the current action - configuration before making changes, enabling easy rollback if - needed. - - Args: - integration_name: Name of the integration the action - belongs to. - action_id: ID of the action to create a revision for. - action: The action object to save as a revision. - comment: Optional comment describing the revision. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - Dict containing the newly created ActionRevision resource. - - Raises: - APIError: If the API request fails. - """ - return _create_integration_action_revision( - self, - integration_name, - action_id, - action, - comment=comment, - api_version=api_version, - ) - - def rollback_integration_action_revision( - self, - integration_name: str, - action_id: str, - revision_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Rollback an integration action to a previous revision. - - Use this method to restore an action to a previously saved - state, reverting any changes made since that revision. - - Args: - integration_name: Name of the integration the action - belongs to. - action_id: ID of the action to rollback. - revision_id: ID of the revision to rollback to. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - Dict containing the rolled back IntegrationAction resource. - - Raises: - APIError: If the API request fails. - """ - return _rollback_integration_action_revision( - self, - integration_name, - action_id, - revision_id, - api_version=api_version, - ) - - # ------------------------------------------------------------------------- - # Integration Connector methods - # ------------------------------------------------------------------------- - - def list_integration_connectors( - self, - integration_name: str, - page_size: int | None = None, - page_token: str | None = None, - filter_string: str | None = None, - order_by: str | None = None, - exclude_staging: bool | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - as_list: bool = False, - ) -> dict[str, Any] | list[dict[str, Any]]: - """List all connectors defined for a specific integration. - - Args: - integration_name: Name of the integration to list connectors - for. - page_size: Maximum number of connectors to return. Defaults - to 50, maximum is 1000. - page_token: Page token from a previous call to retrieve the - next page. - filter_string: Filter expression to filter connectors. - order_by: Field to sort the connectors by. - exclude_staging: Whether to exclude staging connectors from - the response. By default, staging connectors are included. - api_version: API version to use for the request. Default is - V1BETA. - as_list: If True, return a list of connectors instead of a - dict with connectors list and nextPageToken. - - Returns: - If as_list is True: List of connectors. - If as_list is False: Dict with connectors list and - nextPageToken. - - Raises: - APIError: If the API request fails. - """ - return _list_integration_connectors( - self, - integration_name, - page_size=page_size, - page_token=page_token, - filter_string=filter_string, - order_by=order_by, - exclude_staging=exclude_staging, - api_version=api_version, - as_list=as_list, - ) - - def get_integration_connector( - self, - integration_name: str, - connector_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Get a single connector for a given integration. - - Use this method to retrieve the Python script, configuration parameters, - and field mapping logic for a specific connector. - - Args: - integration_name: Name of the integration the connector belongs to. - connector_id: ID of the connector to retrieve. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing details of the specified IntegrationConnector. - - Raises: - APIError: If the API request fails. - """ - return _get_integration_connector( - self, - integration_name, - connector_id, - api_version=api_version, - ) - - def delete_integration_connector( - self, - integration_name: str, - connector_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> None: - """Delete a specific custom connector from a given integration. - - Only custom connectors can be deleted; commercial connectors are - immutable. - - Args: - integration_name: Name of the integration the connector belongs to. - connector_id: ID of the connector to delete. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - None - - Raises: - APIError: If the API request fails. - """ - return _delete_integration_connector( - self, - integration_name, - connector_id, - api_version=api_version, - ) - - def create_integration_connector( - self, - integration_name: str, - display_name: str, - script: str, - timeout_seconds: int, - enabled: bool, - product_field_name: str, - event_field_name: str, - description: str | None = None, - parameters: list[dict[str, Any] | ConnectorParameter] | None = None, - rules: list[dict[str, Any] | ConnectorRule] | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Create a new custom connector for a given integration. - - Use this method to define how to fetch and parse alerts from a - unique or unofficial data source. Each connector must have a - unique display name and a functional Python script. - - Args: - integration_name: Name of the integration to create the - connector for. - display_name: Connector's display name. Required. - script: Connector's Python script. Required. - timeout_seconds: Timeout in seconds for a single script run. - Required. - enabled: Whether the connector is enabled or disabled. - Required. - product_field_name: Field name used to determine the device - product. Required. - event_field_name: Field name used to determine the event - name (sub-type). Required. - description: Connector's description. Optional. - parameters: List of ConnectorParameter instances or dicts. - Optional. - rules: List of ConnectorRule instances or dicts. Optional. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - Dict containing the newly created IntegrationConnector - resource. - - Raises: - APIError: If the API request fails. - """ - return _create_integration_connector( - self, - integration_name, - display_name, - script, - timeout_seconds, - enabled, - product_field_name, - event_field_name, - description=description, - parameters=parameters, - rules=rules, - api_version=api_version, - ) - - def update_integration_connector( - self, - integration_name: str, - connector_id: str, - display_name: str | None = None, - script: str | None = None, - timeout_seconds: int | None = None, - enabled: bool | None = None, - product_field_name: str | None = None, - event_field_name: str | None = None, - description: str | None = None, - parameters: list[dict[str, Any] | ConnectorParameter] | None = None, - rules: list[dict[str, Any] | ConnectorRule] | None = None, - update_mask: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Update an existing custom connector for a given integration. - - Only custom connectors can be updated; commercial connectors are - immutable. - - Args: - integration_name: Name of the integration the connector belongs to. - connector_id: ID of the connector to update. - display_name: Connector's display name. - script: Connector's Python script. - timeout_seconds: Timeout in seconds for a single script run. - enabled: Whether the connector is enabled or disabled. - product_field_name: Field name used to determine the device product. - event_field_name: Field name used to determine the event name - (sub-type). - description: Connector's description. - parameters: List of ConnectorParameter instances or dicts. - rules: List of ConnectorRule instances or dicts. - update_mask: Comma-separated list of fields to update. If omitted, - the mask is auto-generated from whichever fields are provided. - Example: "displayName,script". - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing the updated IntegrationConnector resource. - - Raises: - APIError: If the API request fails. - """ - return _update_integration_connector( - self, - integration_name, - connector_id, - display_name=display_name, - script=script, - timeout_seconds=timeout_seconds, - enabled=enabled, - product_field_name=product_field_name, - event_field_name=event_field_name, - description=description, - parameters=parameters, - rules=rules, - update_mask=update_mask, - api_version=api_version, - ) - - def execute_integration_connector_test( - self, - integration_name: str, - connector: dict[str, Any], - agent_identifier: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Execute a test run of a connector's Python script. - - Use this method to verify data fetching logic, authentication, - and parsing logic before enabling the connector for production - ingestion. The full connector object is required as the test - can be run without saving the connector first. - - Args: - integration_name: Name of the integration the connector - belongs to. - connector: Dict containing the IntegrationConnector to test. - agent_identifier: Agent identifier for remote testing. - Optional. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - Dict containing the test execution results with the - following fields: - - outputMessage: Human-readable output message set by - the script. - - debugOutputMessage: The script debug output. - - resultJson: The result JSON if it exists (optional). - - Raises: - APIError: If the API request fails. - """ - return _execute_integration_connector_test( - self, - integration_name, - connector, - agent_identifier=agent_identifier, - api_version=api_version, - ) - - def get_integration_connector_template( - self, - integration_name: str, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Retrieve a default Python script template for a new - integration connector. - - Use this method to rapidly initialize the development of a new - connector. - - Args: - integration_name: Name of the integration to fetch the - template for. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - Dict containing the IntegrationConnector template. - - Raises: - APIError: If the API request fails. - """ - return _get_integration_connector_template( - self, - integration_name, - api_version=api_version, - ) - - # ------------------------------------------------------------------------- - # Integration Connector Revisions methods - # ------------------------------------------------------------------------- - - def list_integration_connector_revisions( - self, - integration_name: str, - connector_id: str, - page_size: int | None = None, - page_token: str | None = None, - filter_string: str | None = None, - order_by: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - as_list: bool = False, - ) -> dict[str, Any] | list[dict[str, Any]]: - """List all revisions for a specific integration connector. - - Use this method to browse the version history and identify - potential rollback targets. - - Args: - integration_name: Name of the integration the connector - belongs to. - connector_id: ID of the connector to list revisions for. - page_size: Maximum number of revisions to return. - page_token: Page token from a previous call to retrieve the - next page. - filter_string: Filter expression to filter revisions. - order_by: Field to sort the revisions by. - api_version: API version to use for the request. Default is - V1BETA. - as_list: If True, return a list of revisions instead of a - dict with revisions list and nextPageToken. - - Returns: - If as_list is True: List of revisions. - If as_list is False: Dict with revisions list and - nextPageToken. - - Raises: - APIError: If the API request fails. - """ - return _list_integration_connector_revisions( - self, - integration_name, - connector_id, - page_size=page_size, - page_token=page_token, - filter_string=filter_string, - order_by=order_by, - api_version=api_version, - as_list=as_list, - ) - - def delete_integration_connector_revision( - self, - integration_name: str, - connector_id: str, - revision_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> None: - """Delete a specific revision for a given integration - connector. - - Use this method to clean up old or incorrect snapshots from the - version history. - - Args: - integration_name: Name of the integration the connector - belongs to. - connector_id: ID of the connector the revision belongs to. - revision_id: ID of the revision to delete. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - None - - Raises: - APIError: If the API request fails. - """ - return _delete_integration_connector_revision( - self, - integration_name, - connector_id, - revision_id, - api_version=api_version, - ) - - def create_integration_connector_revision( - self, - integration_name: str, - connector_id: str, - connector: dict[str, Any], - comment: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Create a new revision snapshot of the current integration - connector. - - Use this method to save a stable configuration before making - experimental changes. Only custom connectors can be versioned. - - Args: - integration_name: Name of the integration the connector - belongs to. - connector_id: ID of the connector to create a revision for. - connector: Dict containing the IntegrationConnector to - snapshot. - comment: Comment describing the revision. Maximum 400 - characters. Optional. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - Dict containing the newly created ConnectorRevision - resource. - - Raises: - APIError: If the API request fails. - """ - return _create_integration_connector_revision( - self, - integration_name, - connector_id, - connector, - comment=comment, - api_version=api_version, - ) - - def rollback_integration_connector_revision( - self, - integration_name: str, - connector_id: str, - revision_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Revert the current connector definition to a previously - saved revision. - - Use this method to quickly revert to a known good configuration - if an investigation or update is unsuccessful. - - Args: - integration_name: Name of the integration the connector - belongs to. - connector_id: ID of the connector to rollback. - revision_id: ID of the revision to rollback to. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - Dict containing the ConnectorRevision rolled back to. - - Raises: - APIError: If the API request fails. - """ - return _rollback_integration_connector_revision( - self, - integration_name, - connector_id, - revision_id, - api_version=api_version, - ) - - # ------------------------------------------------------------------------- - # Connector Context Properties methods - # ------------------------------------------------------------------------- - - def list_connector_context_properties( - self, - integration_name: str, - connector_id: str, - page_size: int | None = None, - page_token: str | None = None, - filter_string: str | None = None, - order_by: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - as_list: bool = False, - ) -> dict[str, Any] | list[dict[str, Any]]: - """List all context properties for a specific integration - connector. - - Use this method to discover all custom data points associated - with a connector. - - Args: - integration_name: Name of the integration the connector - belongs to. - connector_id: ID of the connector to list context - properties for. - page_size: Maximum number of context properties to return. - page_token: Page token from a previous call to retrieve the - next page. - filter_string: Filter expression to filter context - properties. - order_by: Field to sort the context properties by. - api_version: API version to use for the request. Default is - V1BETA. - as_list: If True, return a list of context properties - instead of a dict with context properties list and - nextPageToken. - - Returns: - If as_list is True: List of context properties. - If as_list is False: Dict with context properties list and - nextPageToken. - - Raises: - APIError: If the API request fails. - """ - return _list_connector_context_properties( - self, - integration_name, - connector_id, - page_size=page_size, - page_token=page_token, - filter_string=filter_string, - order_by=order_by, - api_version=api_version, - as_list=as_list, - ) - - def get_connector_context_property( - self, - integration_name: str, - connector_id: str, - context_property_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Get a single context property for a specific integration - connector. - - Use this method to retrieve the value of a specific key within - a connector's context. - - Args: - integration_name: Name of the integration the connector - belongs to. - connector_id: ID of the connector the context property - belongs to. - context_property_id: ID of the context property to - retrieve. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - Dict containing details of the specified ContextProperty. - - Raises: - APIError: If the API request fails. - """ - return _get_connector_context_property( - self, - integration_name, - connector_id, - context_property_id, - api_version=api_version, - ) - - def delete_connector_context_property( - self, - integration_name: str, - connector_id: str, - context_property_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> None: - """Delete a specific context property for a given integration - connector. - - Use this method to remove a custom data point that is no longer - relevant to the connector's context. - - Args: - integration_name: Name of the integration the connector - belongs to. - connector_id: ID of the connector the context property - belongs to. - context_property_id: ID of the context property to delete. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - None - - Raises: - APIError: If the API request fails. - """ - return _delete_connector_context_property( - self, - integration_name, - connector_id, - context_property_id, - api_version=api_version, - ) - - def create_connector_context_property( - self, - integration_name: str, - connector_id: str, - value: str, - key: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Create a new context property for a specific integration - connector. - - Use this method to attach custom data to a connector's context. - Property keys must be unique within their context. Key values - must be 4-63 characters and match /[a-z][0-9]-/. - - Args: - integration_name: Name of the integration the connector - belongs to. - connector_id: ID of the connector to create the context - property for. - value: The property value. Required. - key: The context property ID to use. Must be 4-63 - characters and match /[a-z][0-9]-/. Optional. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - Dict containing the newly created ContextProperty resource. - - Raises: - APIError: If the API request fails. - """ - return _create_connector_context_property( - self, - integration_name, - connector_id, - value, - key=key, - api_version=api_version, - ) - - def update_connector_context_property( - self, - integration_name: str, - connector_id: str, - context_property_id: str, - value: str, - update_mask: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Update an existing context property for a given integration - connector. - - Use this method to modify the value of a previously saved key. - - Args: - integration_name: Name of the integration the connector - belongs to. - connector_id: ID of the connector the context property - belongs to. - context_property_id: ID of the context property to update. - value: The new property value. Required. - update_mask: Comma-separated list of fields to update. Only - "value" is supported. If omitted, defaults to "value". - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - Dict containing the updated ContextProperty resource. - - Raises: - APIError: If the API request fails. - """ - return _update_connector_context_property( - self, - integration_name, - connector_id, - context_property_id, - value, - update_mask=update_mask, - api_version=api_version, - ) - - def delete_all_connector_context_properties( - self, - integration_name: str, - connector_id: str, - context_id: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> None: - """Delete all context properties for a specific integration - connector. - - Use this method to quickly clear all supplemental data from a - connector's context. - - Args: - integration_name: Name of the integration the connector - belongs to. - connector_id: ID of the connector to clear context - properties from. - context_id: The context ID to remove context properties - from. Must be 4-63 characters and match /[a-z][0-9]-/. - Optional. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - None - - Raises: - APIError: If the API request fails. - """ - return _delete_all_connector_context_properties( - self, - integration_name, - connector_id, - context_id=context_id, - api_version=api_version, - ) - - # ------------------------------------------------------------------------- - # Connector Instance Logs methods - # ------------------------------------------------------------------------- - - def list_connector_instance_logs( - self, - integration_name: str, - connector_id: str, - connector_instance_id: str, - page_size: int | None = None, - page_token: str | None = None, - filter_string: str | None = None, - order_by: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - as_list: bool = False, - ) -> dict[str, Any] | list[dict[str, Any]]: - """List all logs for a specific connector instance. - - Use this method to browse the execution history and diagnostic - output of a connector. Supports filtering and pagination to - efficiently navigate large volumes of log data. - - Args: - integration_name: Name of the integration the connector - belongs to. - connector_id: ID of the connector the instance belongs to. - connector_instance_id: ID of the connector instance to list - logs for. - page_size: Maximum number of logs to return. - page_token: Page token from a previous call to retrieve the - next page. - filter_string: Filter expression to filter logs. - order_by: Field to sort the logs by. - api_version: API version to use for the request. Default is - V1BETA. - as_list: If True, return a list of logs instead of a dict - with logs list and nextPageToken. - - Returns: - If as_list is True: List of logs. - If as_list is False: Dict with logs list and nextPageToken. - - Raises: - APIError: If the API request fails. - """ - return _list_connector_instance_logs( - self, - integration_name, - connector_id, - connector_instance_id, - page_size=page_size, - page_token=page_token, - filter_string=filter_string, - order_by=order_by, - api_version=api_version, - as_list=as_list, - ) - - def get_connector_instance_log( - self, - integration_name: str, - connector_id: str, - connector_instance_id: str, - log_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Get a single log entry for a specific connector instance. - - Use this method to retrieve a specific log entry from a - connector instance's execution, including its message, - timestamp, and severity level. Useful for auditing and detailed - troubleshooting of a specific connector run. - - Args: - integration_name: Name of the integration the connector - belongs to. - connector_id: ID of the connector the instance belongs to. - connector_instance_id: ID of the connector instance the log - belongs to. - log_id: ID of the log entry to retrieve. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - Dict containing details of the specified ConnectorLog. - - Raises: - APIError: If the API request fails. - """ - return _get_connector_instance_log( - self, - integration_name, - connector_id, - connector_instance_id, - log_id, - api_version=api_version, - ) - - # ------------------------------------------------------------------------- - # Connector Instance methods - # ------------------------------------------------------------------------- - - def list_connector_instances( - self, - integration_name: str, - connector_id: str, - page_size: int | None = None, - page_token: str | None = None, - filter_string: str | None = None, - order_by: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - as_list: bool = False, - ) -> dict[str, Any] | list[dict[str, Any]]: - """List all instances for a specific integration connector. - - Use this method to discover all configured instances of a - connector. - - Args: - integration_name: Name of the integration the connector - belongs to. - connector_id: ID of the connector to list instances for. - page_size: Maximum number of instances to return. - page_token: Page token from a previous call to retrieve the - next page. - filter_string: Filter expression to filter instances. - order_by: Field to sort the instances by. - api_version: API version to use for the request. Default is - V1BETA. - as_list: If True, return a list of instances instead of a - dict with instances list and nextPageToken. - - Returns: - If as_list is True: List of connector instances. - If as_list is False: Dict with connector instances list and - nextPageToken. - - Raises: - APIError: If the API request fails. - """ - return _list_connector_instances( - self, - integration_name, - connector_id, - page_size=page_size, - page_token=page_token, - filter_string=filter_string, - order_by=order_by, - api_version=api_version, - as_list=as_list, - ) - - def get_connector_instance( - self, - integration_name: str, - connector_id: str, - connector_instance_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Get a single connector instance by ID. - - Use this method to retrieve the configuration of a specific - connector instance, including its parameters, schedule, and - runtime settings. - - Args: - integration_name: Name of the integration the connector - belongs to. - connector_id: ID of the connector the instance belongs to. - connector_instance_id: ID of the connector instance to - retrieve. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - Dict containing details of the specified ConnectorInstance. - - Raises: - APIError: If the API request fails. - """ - return _get_connector_instance( - self, - integration_name, - connector_id, - connector_instance_id, - api_version=api_version, - ) - - def delete_connector_instance( - self, - integration_name: str, - connector_id: str, - connector_instance_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> None: - """Delete a specific connector instance. - - Use this method to permanently remove a connector instance and - its configuration. - - Args: - integration_name: Name of the integration the connector - belongs to. - connector_id: ID of the connector the instance belongs to. - connector_instance_id: ID of the connector instance to - delete. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - None - - Raises: - APIError: If the API request fails. - """ - return _delete_connector_instance( - self, - integration_name, - connector_id, - connector_instance_id, - api_version=api_version, - ) - - def create_connector_instance( - self, - integration_name: str, - connector_id: str, - environment: str, - display_name: str, - interval_seconds: int, - timeout_seconds: int, - description: str | None = None, - parameters: list[ConnectorInstanceParameter | dict] | None = None, - agent: str | None = None, - allow_list: list[str] | None = None, - product_field_name: str | None = None, - event_field_name: str | None = None, - integration_version: str | None = None, - version: str | None = None, - logging_enabled_until_unix_ms: str | None = None, - connector_instance_id: str | None = None, - enabled: bool | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Create a new connector instance. - - Use this method to configure a new instance of a connector with - specific parameters and schedule settings. - - Args: - integration_name: Name of the integration the connector - belongs to. - connector_id: ID of the connector to create an instance for. - environment: Environment for the instance (e.g., - "production"). - display_name: Display name for the instance. Required. - interval_seconds: Interval in seconds for recurring - execution. Required. - timeout_seconds: Timeout in seconds for execution. Required. - description: Description of the instance. Optional. - parameters: List of parameters for the instance. Optional. - agent: Agent identifier for remote execution. Optional. - allow_list: List of allowed IP addresses. Optional. - product_field_name: Product field name. Optional. - event_field_name: Event field name. Optional. - integration_version: Integration version. Optional. - version: Version. Optional. - logging_enabled_until_unix_ms: Logging enabled until - timestamp. Optional. - connector_instance_id: Custom ID for the instance. Optional. - enabled: Whether the instance is enabled. Optional. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - Dict containing the newly created ConnectorInstance resource. - - Raises: - APIError: If the API request fails. - """ - return _create_connector_instance( - self, - integration_name, - connector_id, - environment, - display_name, - interval_seconds, - timeout_seconds, - description=description, - parameters=parameters, - agent=agent, - allow_list=allow_list, - product_field_name=product_field_name, - event_field_name=event_field_name, - integration_version=integration_version, - version=version, - logging_enabled_until_unix_ms=logging_enabled_until_unix_ms, - connector_instance_id=connector_instance_id, - enabled=enabled, - api_version=api_version, - ) - - def update_connector_instance( - self, - integration_name: str, - connector_id: str, - connector_instance_id: str, - display_name: str | None = None, - description: str | None = None, - interval_seconds: int | None = None, - timeout_seconds: int | None = None, - parameters: list[ConnectorInstanceParameter | dict] | None = None, - allow_list: list[str] | None = None, - product_field_name: str | None = None, - event_field_name: str | None = None, - integration_version: str | None = None, - version: str | None = None, - logging_enabled_until_unix_ms: str | None = None, - enabled: bool | None = None, - update_mask: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Update an existing connector instance. - - Use this method to modify the configuration, parameters, or - schedule of a connector instance. - - Args: - integration_name: Name of the integration the connector - belongs to. - connector_id: ID of the connector the instance belongs to. - connector_instance_id: ID of the connector instance to - update. - display_name: Display name for the instance. Optional. - description: Description of the instance. Optional. - interval_seconds: Interval in seconds for recurring - execution. Optional. - timeout_seconds: Timeout in seconds for execution. Optional. - parameters: List of parameters for the instance. Optional. - agent: Agent identifier for remote execution. Optional. - allow_list: List of allowed IP addresses. Optional. - product_field_name: Product field name. Optional. - event_field_name: Event field name. Optional. - integration_version: Integration version. Optional. - version: Version. Optional. - logging_enabled_until_unix_ms: Logging enabled until - timestamp. Optional. - enabled: Whether the instance is enabled. Optional. - update_mask: Comma-separated list of fields to update. If - omitted, all provided fields will be updated. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - Dict containing the updated ConnectorInstance resource. - - Raises: - APIError: If the API request fails. - """ - return _update_connector_instance( - self, - integration_name, - connector_id, - connector_instance_id, - display_name=display_name, - description=description, - interval_seconds=interval_seconds, - timeout_seconds=timeout_seconds, - parameters=parameters, - allow_list=allow_list, - product_field_name=product_field_name, - event_field_name=event_field_name, - integration_version=integration_version, - version=version, - logging_enabled_until_unix_ms=logging_enabled_until_unix_ms, - enabled=enabled, - update_mask=update_mask, - api_version=api_version, - ) - - def get_connector_instance_latest_definition( - self, - integration_name: str, - connector_id: str, - connector_instance_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Fetch the latest definition for a connector instance. - - Use this method to refresh a connector instance with the latest - connector definition from the marketplace. - - Args: - integration_name: Name of the integration the connector - belongs to. - connector_id: ID of the connector the instance belongs to. - connector_instance_id: ID of the connector instance to - refresh. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - Dict containing the refreshed ConnectorInstance with latest - definition. - - Raises: - APIError: If the API request fails. - """ - return _get_connector_instance_latest_definition( - self, - integration_name, - connector_id, - connector_instance_id, - api_version=api_version, - ) - - def set_connector_instance_logs_collection( - self, - integration_name: str, - connector_id: str, - connector_instance_id: str, - enabled: bool, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Enable or disable logs collection for a connector instance. - - Use this method to control whether execution logs are collected - for a specific connector instance. - - Args: - integration_name: Name of the integration the connector - belongs to. - connector_id: ID of the connector the instance belongs to. - connector_instance_id: ID of the connector instance to - configure. - enabled: Whether to enable or disable logs collection. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - Dict containing the updated logs collection status. - - Raises: - APIError: If the API request fails. - """ - return _set_connector_instance_logs_collection( - self, - integration_name, - connector_id, - connector_instance_id, - enabled, - api_version=api_version, - ) - - def run_connector_instance_on_demand( - self, - integration_name: str, - connector_id: str, - connector_instance_id: str, - connector_instance: dict[str, Any], - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Run a connector instance on demand for testing. - - Use this method to execute a connector instance immediately - without waiting for its scheduled run. Useful for testing - configuration changes. - - Args: - integration_name: Name of the integration the connector - belongs to. - connector_id: ID of the connector the instance belongs to. - connector_instance_id: ID of the connector instance to run. - connector_instance: The connector instance configuration to - test. Should include parameters and other settings. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - Dict containing the execution result, including success - status and debug output. - - Raises: - APIError: If the API request fails. - """ - return _run_connector_instance_on_demand( - self, - integration_name, - connector_id, - connector_instance_id, - connector_instance, - api_version=api_version, - ) - - # ------------------------------------------------------------------------- - # Integration Job methods - # ------------------------------------------------------------------------- - - def list_integration_jobs( - self, - integration_name: str, - page_size: int | None = None, - page_token: str | None = None, - filter_string: str | None = None, - order_by: str | None = None, - exclude_staging: bool | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - as_list: bool = False, - ) -> dict[str, Any] | list[dict[str, Any]]: - """List all jobs defined for a specific integration. - - Use this method to browse the available background and scheduled - automation capabilities provided by a third-party connection. - - Args: - integration_name: Name of the integration to list jobs for. - page_size: Maximum number of jobs to return. - page_token: Page token from a previous call to retrieve the - next page. - filter_string: Filter expression to filter jobs. Allowed - filters are: id, custom, system, author, version, - integration. - order_by: Field to sort the jobs by. - exclude_staging: Whether to exclude staging jobs from the - response. By default, staging jobs are included. - api_version: API version to use for the request. Default is - V1BETA. - as_list: If True, return a list of jobs instead of a dict - with jobs list and nextPageToken. - - Returns: - If as_list is True: List of jobs. - If as_list is False: Dict with jobs list and nextPageToken. - - Raises: - APIError: If the API request fails. - """ - return _list_integration_jobs( - self, - integration_name, - page_size=page_size, - page_token=page_token, - filter_string=filter_string, - order_by=order_by, - exclude_staging=exclude_staging, - api_version=api_version, - as_list=as_list, - ) - - def get_integration_job( - self, - integration_name: str, - job_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Get a single job for a given integration. - - Use this method to retrieve the Python script, execution - parameters, and versioning information for a background - automation task. - - Args: - integration_name: Name of the integration the job belongs - to. - job_id: ID of the job to retrieve. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - Dict containing details of the specified IntegrationJob. - - Raises: - APIError: If the API request fails. - """ - return _get_integration_job( - self, - integration_name, - job_id, - api_version=api_version, - ) - - def delete_integration_job( - self, - integration_name: str, - job_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> None: - """Delete a specific custom job from a given integration. - - Only custom jobs can be deleted; commercial and system jobs - are immutable. - - Args: - integration_name: Name of the integration the job belongs - to. - job_id: ID of the job to delete. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - None - - Raises: - APIError: If the API request fails. - """ - return _delete_integration_job( - self, - integration_name, - job_id, - api_version=api_version, - ) - - def create_integration_job( - self, - integration_name: str, - display_name: str, - script: str, - version: int, - enabled: bool, - custom: bool, - description: str | None = None, - parameters: list[dict[str, Any] | JobParameter] | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Create a new custom job for a given integration. - - Each job must have a unique display name and a functional - Python script for its background execution. - - Args: - integration_name: Name of the integration to create the job - for. - display_name: Job's display name. Maximum 400 characters. - Required. - script: Job's Python script. Required. - version: Job's version. Required. - enabled: Whether the job is enabled. Required. - custom: Whether the job is custom or commercial. Required. - description: Job's description. Optional. - parameters: List of JobParameter instances or dicts. - Optional. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - Dict containing the newly created IntegrationJob resource. - - Raises: - APIError: If the API request fails. - """ - return _create_integration_job( - self, - integration_name, - display_name, - script, - version, - enabled, - custom, - description=description, - parameters=parameters, - api_version=api_version, - ) - - def update_integration_job( - self, - integration_name: str, - job_id: str, - display_name: str | None = None, - script: str | None = None, - version: int | None = None, - enabled: bool | None = None, - custom: bool | None = None, - description: str | None = None, - parameters: list[dict[str, Any] | JobParameter] | None = None, - update_mask: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Update an existing custom job for a given integration. - - Use this method to modify the Python script or adjust the - parameter definitions for a job. - - Args: - integration_name: Name of the integration the job belongs - to. - job_id: ID of the job to update. - display_name: Job's display name. Maximum 400 characters. - script: Job's Python script. - version: Job's version. - enabled: Whether the job is enabled. - custom: Whether the job is custom or commercial. - description: Job's description. - parameters: List of JobParameter instances or dicts. - update_mask: Comma-separated list of fields to update. If - omitted, the mask is auto-generated from whichever - fields are provided. Example: "displayName,script". - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - Dict containing the updated IntegrationJob resource. - - Raises: - APIError: If the API request fails. - """ - return _update_integration_job( - self, - integration_name, - job_id, - display_name=display_name, - script=script, - version=version, - enabled=enabled, - custom=custom, - description=description, - parameters=parameters, - update_mask=update_mask, - api_version=api_version, - ) - - def execute_integration_job_test( - self, - integration_name: str, - job: dict[str, Any], - agent_identifier: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Execute a test run of an integration job's Python script. - - Use this method to verify background automation logic and - connectivity before deploying the job to an instance for - recurring execution. - - Args: - integration_name: Name of the integration the job belongs - to. - job: Dict containing the IntegrationJob to test. - agent_identifier: Agent identifier for remote testing. - Optional. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - Dict containing the test execution results with the - following fields: - - output: The script output. - - debugOutput: The script debug output. - - resultObjectJson: The result JSON if it exists - (optional). - - resultName: The script result name (optional). - - resultValue: The script result value (optional). - - Raises: - APIError: If the API request fails. - """ - return _execute_integration_job_test( - self, - integration_name, - job, - agent_identifier=agent_identifier, - api_version=api_version, - ) - - def get_integration_job_template( - self, - integration_name: str, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Retrieve a default Python script template for a new - integration job. - - Use this method to rapidly initialize the development of a new - job. - - Args: - integration_name: Name of the integration to fetch the - template for. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - Dict containing the IntegrationJob template. - - Raises: - APIError: If the API request fails. - """ - return _get_integration_job_template( - self, - integration_name, - api_version=api_version, - ) - - # ------------------------------------------------------------------------- - # Integration Manager methods - # ------------------------------------------------------------------------- - - def list_integration_managers( - self, - integration_name: str, - page_size: int | None = None, - page_token: str | None = None, - filter_string: str | None = None, - order_by: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - as_list: bool = False, - ) -> dict[str, Any] | list[dict[str, Any]]: - """List all managers defined for a specific integration. - - Use this method to discover the library of managers available - within a particular integration's scope. - - Args: - integration_name: Name of the integration to list managers - for. - page_size: Maximum number of managers to return. Defaults to - 100, maximum is 100. - page_token: Page token from a previous call to retrieve the - next page. - filter_string: Filter expression to filter managers. - order_by: Field to sort the managers by. - api_version: API version to use for the request. Default is - V1BETA. - as_list: If True, return a list of managers instead of a - dict with managers list and nextPageToken. - - Returns: - If as_list is True: List of managers. - If as_list is False: Dict with managers list and - nextPageToken. - - Raises: - APIError: If the API request fails. - """ - return _list_integration_managers( - self, - integration_name, - page_size=page_size, - page_token=page_token, - filter_string=filter_string, - order_by=order_by, - api_version=api_version, - as_list=as_list, - ) - - def get_integration_manager( - self, - integration_name: str, - manager_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Get a single manager for a given integration. - - Use this method to retrieve the manager script and its metadata - for review or reference. - - Args: - integration_name: Name of the integration the manager - belongs to. - manager_id: ID of the manager to retrieve. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - Dict containing details of the specified IntegrationManager. - - Raises: - APIError: If the API request fails. - """ - return _get_integration_manager( - self, - integration_name, - manager_id, - api_version=api_version, - ) - - def delete_integration_manager( - self, - integration_name: str, - manager_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> None: - """Delete a specific custom manager from a given integration. - - Note that deleting a manager may break components (actions, - jobs) that depend on its code. - - Args: - integration_name: Name of the integration the manager - belongs to. - manager_id: ID of the manager to delete. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - None - - Raises: - APIError: If the API request fails. - """ - return _delete_integration_manager( - self, - integration_name, - manager_id, - api_version=api_version, - ) - - def create_integration_manager( - self, - integration_name: str, - display_name: str, - script: str, - description: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Create a new custom manager for a given integration. - - Use this method to add a new shared code utility. Each manager - must have a unique display name and a script containing valid - Python logic for reuse across actions, jobs, and connectors. - - Args: - integration_name: Name of the integration to create the - manager for. - display_name: Manager's display name. Maximum 150 - characters. Required. - script: Manager's Python script. Maximum 5MB. Required. - description: Manager's description. Maximum 400 characters. - Optional. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - Dict containing the newly created IntegrationManager - resource. - - Raises: - APIError: If the API request fails. - """ - return _create_integration_manager( - self, - integration_name, - display_name, - script, - description=description, - api_version=api_version, - ) - - def update_integration_manager( - self, - integration_name: str, - manager_id: str, - display_name: str | None = None, - script: str | None = None, - description: str | None = None, - update_mask: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Update an existing custom manager for a given integration. - - Use this method to modify the shared code, adjust its - description, or refine its logic across all components that - import it. - - Args: - integration_name: Name of the integration the manager - belongs to. - manager_id: ID of the manager to update. - display_name: Manager's display name. Maximum 150 - characters. - script: Manager's Python script. Maximum 5MB. - description: Manager's description. Maximum 400 characters. - update_mask: Comma-separated list of fields to update. If - omitted, the mask is auto-generated from whichever - fields are provided. Example: "displayName,script". - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - Dict containing the updated IntegrationManager resource. - - Raises: - APIError: If the API request fails. - """ - return _update_integration_manager( - self, - integration_name, - manager_id, - display_name=display_name, - script=script, - description=description, - update_mask=update_mask, - api_version=api_version, - ) - - def get_integration_manager_template( - self, - integration_name: str, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Retrieve a default Python script template for a new - integration manager. - - Use this method to quickly start developing new managers. - - Args: - integration_name: Name of the integration to fetch the - template for. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - Dict containing the IntegrationManager template. - - Raises: - APIError: If the API request fails. - """ - return _get_integration_manager_template( - self, - integration_name, - api_version=api_version, - ) - - # ------------------------------------------------------------------------- - # Integration Manager Revisions methods - # ------------------------------------------------------------------------- - - def list_integration_manager_revisions( - self, - integration_name: str, - manager_id: str, - page_size: int | None = None, - page_token: str | None = None, - filter_string: str | None = None, - order_by: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - as_list: bool = False, - ) -> dict[str, Any] | list[dict[str, Any]]: - """List all revisions for a specific integration manager. - - Use this method to browse the version history and identify - previous functional states of a manager. - - Args: - integration_name: Name of the integration the manager - belongs to. - manager_id: ID of the manager to list revisions for. - page_size: Maximum number of revisions to return. - page_token: Page token from a previous call to retrieve the - next page. - filter_string: Filter expression to filter revisions. - order_by: Field to sort the revisions by. - api_version: API version to use for the request. Default is - V1BETA. - as_list: If True, return a list of revisions instead of a - dict with revisions list and nextPageToken. - - Returns: - If as_list is True: List of revisions. - If as_list is False: Dict with revisions list and - nextPageToken. - - Raises: - APIError: If the API request fails. - """ - return _list_integration_manager_revisions( - self, - integration_name, - manager_id, - page_size=page_size, - page_token=page_token, - filter_string=filter_string, - order_by=order_by, - api_version=api_version, - as_list=as_list, - ) - - def get_integration_manager_revision( - self, - integration_name: str, - manager_id: str, - revision_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Get a single revision for a specific integration manager. - - Use this method to retrieve a specific snapshot of an - IntegrationManagerRevision for comparison or review. - - Args: - integration_name: Name of the integration the manager - belongs to. - manager_id: ID of the manager the revision belongs to. - revision_id: ID of the revision to retrieve. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - Dict containing details of the specified - IntegrationManagerRevision. - - Raises: - APIError: If the API request fails. - """ - return _get_integration_manager_revision( - self, - integration_name, - manager_id, - revision_id, - api_version=api_version, - ) - - def delete_integration_manager_revision( - self, - integration_name: str, - manager_id: str, - revision_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> None: - """Delete a specific revision for a given integration manager. - - Use this method to clean up obsolete snapshots and manage the - historical record of managers. - - Args: - integration_name: Name of the integration the manager - belongs to. - manager_id: ID of the manager the revision belongs to. - revision_id: ID of the revision to delete. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - None - - Raises: - APIError: If the API request fails. - """ - return _delete_integration_manager_revision( - self, - integration_name, - manager_id, - revision_id, - api_version=api_version, - ) - - def create_integration_manager_revision( - self, - integration_name: str, - manager_id: str, - manager: dict[str, Any], - comment: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Create a new revision snapshot of the current integration - manager. - - Use this method to establish a recovery point before making - significant updates to a manager. - - Args: - integration_name: Name of the integration the manager - belongs to. - manager_id: ID of the manager to create a revision for. - manager: Dict containing the IntegrationManager to snapshot. - comment: Comment describing the revision. Maximum 400 - characters. Optional. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - Dict containing the newly created - IntegrationManagerRevision resource. - - Raises: - APIError: If the API request fails. - """ - return _create_integration_manager_revision( - self, - integration_name, - manager_id, - manager, - comment=comment, - api_version=api_version, - ) - - def rollback_integration_manager_revision( - self, - integration_name: str, - manager_id: str, - revision_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Revert the current manager definition to a previously saved - revision. - - Use this method to rapidly recover a functional state for - common code if an update causes operational issues in dependent - actions or jobs. - - Args: - integration_name: Name of the integration the manager - belongs to. - manager_id: ID of the manager to rollback. - revision_id: ID of the revision to rollback to. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - Dict containing the IntegrationManagerRevision rolled back - to. - - Raises: - APIError: If the API request fails. - """ - return _rollback_integration_manager_revision( - self, - integration_name, - manager_id, - revision_id, - api_version=api_version, - ) - - # ------------------------------------------------------------------------- - # Integration Job Revisions methods - # ------------------------------------------------------------------------- - - def list_integration_job_revisions( - self, - integration_name: str, - job_id: str, - page_size: int | None = None, - page_token: str | None = None, - filter_string: str | None = None, - order_by: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - as_list: bool = False, - ) -> dict[str, Any] | list[dict[str, Any]]: - """List all revisions for a specific integration job. - - Use this method to browse the version history of a job and - identify previous functional states. - - Args: - integration_name: Name of the integration the job belongs - to. - job_id: ID of the job to list revisions for. - page_size: Maximum number of revisions to return. - page_token: Page token from a previous call to retrieve the - next page. - filter_string: Filter expression to filter revisions. - order_by: Field to sort the revisions by. - api_version: API version to use for the request. Default is - V1BETA. - as_list: If True, return a list of revisions instead of a - dict with revisions list and nextPageToken. - - Returns: - If as_list is True: List of revisions. - If as_list is False: Dict with revisions list and - nextPageToken. - - Raises: - APIError: If the API request fails. - """ - return _list_integration_job_revisions( - self, - integration_name, - job_id, - page_size=page_size, - page_token=page_token, - filter_string=filter_string, - order_by=order_by, - api_version=api_version, - as_list=as_list, - ) - - def delete_integration_job_revision( - self, - integration_name: str, - job_id: str, - revision_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> None: - """Delete a specific revision for a given integration job. - - Use this method to clean up obsolete snapshots and manage the - historical record of jobs. - - Args: - integration_name: Name of the integration the job belongs - to. - job_id: ID of the job the revision belongs to. - revision_id: ID of the revision to delete. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - None - - Raises: - APIError: If the API request fails. - """ - return _delete_integration_job_revision( - self, - integration_name, - job_id, - revision_id, - api_version=api_version, - ) - - def create_integration_job_revision( - self, - integration_name: str, - job_id: str, - job: dict[str, Any], - comment: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Create a new revision snapshot of the current integration - job. - - Use this method to establish a recovery point before making - significant updates to a job. - - Args: - integration_name: Name of the integration the job belongs - to. - job_id: ID of the job to create a revision for. - job: Dict containing the IntegrationJob to snapshot. - comment: Comment describing the revision. Maximum 400 - characters. Optional. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - Dict containing the newly created IntegrationJobRevision - resource. - - Raises: - APIError: If the API request fails. - """ - return _create_integration_job_revision( - self, - integration_name, - job_id, - job, - comment=comment, - api_version=api_version, - ) - - def rollback_integration_job_revision( - self, - integration_name: str, - job_id: str, - revision_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Revert the current job definition to a previously saved - revision. - - Use this method to rapidly recover a functional state if an - update causes operational issues in scheduled or background - automation. - - Args: - integration_name: Name of the integration the job belongs - to. - job_id: ID of the job to rollback. - revision_id: ID of the revision to rollback to. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - Dict containing the IntegrationJobRevision rolled back to. - - Raises: - APIError: If the API request fails. - """ - return _rollback_integration_job_revision( - self, - integration_name, - job_id, - revision_id, - api_version=api_version, - ) - - # ------------------------------------------------------------------------- - # Integration Job Instances methods - # ------------------------------------------------------------------------- - - def list_integration_job_instances( - self, - integration_name: str, - job_id: str, - page_size: int | None = None, - page_token: str | None = None, - filter_string: str | None = None, - order_by: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - as_list: bool = False, - ) -> dict[str, Any] | list[dict[str, Any]]: - """List all job instances for a specific integration job. - - Use this method to browse the active job instances and their - last execution status. - - Args: - integration_name: Name of the integration the job belongs - to. - job_id: ID of the job to list instances for. - page_size: Maximum number of job instances to return. - page_token: Page token from a previous call to retrieve the - next page. - filter_string: Filter expression to filter job instances. - order_by: Field to sort the job instances by. - api_version: API version to use for the request. Default is - V1BETA. - as_list: If True, return a list of job instances instead of - a dict with job instances list and nextPageToken. - - Returns: - If as_list is True: List of job instances. - If as_list is False: Dict with job instances list and - nextPageToken. - - Raises: - APIError: If the API request fails. - """ - return _list_integration_job_instances( - self, - integration_name, - job_id, - page_size=page_size, - page_token=page_token, - filter_string=filter_string, - order_by=order_by, - api_version=api_version, - as_list=as_list, - ) - - def get_integration_job_instance( - self, - integration_name: str, - job_id: str, - job_instance_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Get a single job instance for a specific integration job. - - Use this method to retrieve configuration details and the - current schedule settings for a job instance. - - Args: - integration_name: Name of the integration the job belongs - to. - job_id: ID of the job the instance belongs to. - job_instance_id: ID of the job instance to retrieve. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - Dict containing details of the specified - IntegrationJobInstance. - - Raises: - APIError: If the API request fails. - """ - return _get_integration_job_instance( - self, - integration_name, - job_id, - job_instance_id, - api_version=api_version, - ) - - def delete_integration_job_instance( - self, - integration_name: str, - job_id: str, - job_instance_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> None: - """Delete a specific job instance for a given integration job. - - Use this method to remove scheduled or configured job instances - that are no longer needed. - - Args: - integration_name: Name of the integration the job belongs - to. - job_id: ID of the job the instance belongs to. - job_instance_id: ID of the job instance to delete. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - None - - Raises: - APIError: If the API request fails. - """ - return _delete_integration_job_instance( - self, - integration_name, - job_id, - job_instance_id, - api_version=api_version, - ) - - def create_integration_job_instance( - self, - integration_name: str, - job_id: str, - display_name: str, - interval_seconds: int, - enabled: bool, - advanced: bool, - description: str | None = None, - parameters: list[dict[str, Any]] | None = None, - agent: str | None = None, - advanced_config: dict[str, Any] | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Create a new job instance for a given integration job. - - Use this method to schedule a job to run at regular intervals - or with advanced cron-style scheduling. - - Args: - integration_name: Name of the integration the job belongs - to. - job_id: ID of the job to create an instance for. - display_name: Display name for the job instance. - interval_seconds: Interval in seconds between job runs. - enabled: Whether the job instance is enabled. - advanced: Whether advanced scheduling is used. - description: Description of the job instance. Optional. - parameters: List of parameter values for the job instance. - Optional. - agent: Agent identifier for remote execution. Optional. - advanced_config: Advanced scheduling configuration. - Optional. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - Dict containing the newly created IntegrationJobInstance - resource. - - Raises: - APIError: If the API request fails. - """ - return _create_integration_job_instance( - self, - integration_name, - job_id, - display_name, - interval_seconds, - enabled, - advanced, - description=description, - parameters=parameters, - agent=agent, - advanced_config=advanced_config, - api_version=api_version, - ) - - def update_integration_job_instance( - self, - integration_name: str, - job_id: str, - job_instance_id: str, - display_name: str | None = None, - description: str | None = None, - interval_seconds: int | None = None, - enabled: bool | None = None, - advanced: bool | None = None, - parameters: list[dict[str, Any]] | None = None, - advanced_config: dict[str, Any] | None = None, - update_mask: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Update an existing job instance for a given integration job. - - Use this method to modify scheduling, parameters, or enable/ - disable a job instance. - - Args: - integration_name: Name of the integration the job belongs - to. - job_id: ID of the job the instance belongs to. - job_instance_id: ID of the job instance to update. - display_name: Display name for the job instance. Optional. - description: Description of the job instance. Optional. - interval_seconds: Interval in seconds between job runs. - Optional. - enabled: Whether the job instance is enabled. Optional. - advanced: Whether advanced scheduling is used. Optional. - parameters: List of parameter values for the job instance. - Optional. - advanced_config: Advanced scheduling configuration. - Optional. - update_mask: Comma-separated field paths to update. If not - provided, will be auto-generated. Optional. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - Dict containing the updated IntegrationJobInstance. - - Raises: - APIError: If the API request fails. - """ - return _update_integration_job_instance( - self, - integration_name, - job_id, - job_instance_id, - display_name=display_name, - description=description, - interval_seconds=interval_seconds, - enabled=enabled, - advanced=advanced, - parameters=parameters, - advanced_config=advanced_config, - update_mask=update_mask, - api_version=api_version, - ) - - def run_integration_job_instance_on_demand( - self, - integration_name: str, - job_id: str, - job_instance_id: str, - parameters: list[dict[str, Any]] | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Run a job instance immediately without waiting for the next - scheduled execution. - - Use this method to manually trigger a job instance for testing - or immediate data collection. - - Args: - integration_name: Name of the integration the job belongs - to. - job_id: ID of the job the instance belongs to. - job_instance_id: ID of the job instance to run. - parameters: Optional parameter overrides for this run. - Optional. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - Dict containing the result of the on-demand run. - - Raises: - APIError: If the API request fails. - """ - return _run_integration_job_instance_on_demand( - self, - integration_name, - job_id, - job_instance_id, - parameters=parameters, - api_version=api_version, - ) - - # ------------------------------------------------------------------------- - # Job Context Properties methods - # ------------------------------------------------------------------------- - - def list_job_context_properties( - self, - integration_name: str, - job_id: str, - page_size: int | None = None, - page_token: str | None = None, - filter_string: str | None = None, - order_by: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - as_list: bool = False, - ) -> dict[str, Any] | list[dict[str, Any]]: - """List all context properties for a specific integration job. - - Use this method to discover all custom data points associated - with a job. - - Args: - integration_name: Name of the integration the job belongs - to. - job_id: ID of the job to list context properties for. - page_size: Maximum number of context properties to return. - page_token: Page token from a previous call to retrieve the - next page. - filter_string: Filter expression to filter context - properties. - order_by: Field to sort the context properties by. - api_version: API version to use for the request. Default is - V1BETA. - as_list: If True, return a list of context properties - instead of a dict with context properties list and - nextPageToken. - - Returns: - If as_list is True: List of context properties. - If as_list is False: Dict with context properties list and - nextPageToken. - - Raises: - APIError: If the API request fails. - """ - return _list_job_context_properties( - self, - integration_name, - job_id, - page_size=page_size, - page_token=page_token, - filter_string=filter_string, - order_by=order_by, - api_version=api_version, - as_list=as_list, - ) - - def get_job_context_property( - self, - integration_name: str, - job_id: str, - context_property_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Get a single context property for a specific integration - job. - - Use this method to retrieve the value of a specific key within - a job's context. - - Args: - integration_name: Name of the integration the job belongs - to. - job_id: ID of the job the context property belongs to. - context_property_id: ID of the context property to - retrieve. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - Dict containing details of the specified ContextProperty. - - Raises: - APIError: If the API request fails. - """ - return _get_job_context_property( - self, - integration_name, - job_id, - context_property_id, - api_version=api_version, - ) - - def delete_job_context_property( - self, - integration_name: str, - job_id: str, - context_property_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> None: - """Delete a specific context property for a given integration - job. - - Use this method to remove a custom data point that is no longer - relevant to the job's context. - - Args: - integration_name: Name of the integration the job belongs - to. - job_id: ID of the job the context property belongs to. - context_property_id: ID of the context property to delete. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - None - - Raises: - APIError: If the API request fails. - """ - return _delete_job_context_property( - self, - integration_name, - job_id, - context_property_id, - api_version=api_version, - ) - - def create_job_context_property( - self, - integration_name: str, - job_id: str, - value: str, - key: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Create a new context property for a specific integration - job. - - Use this method to attach custom data to a job's context. - Property keys must be unique within their context. - - Args: - integration_name: Name of the integration the job belongs - to. - job_id: ID of the job to create the context property for. - value: The property value. Required. - key: The context property ID to use. Must be 4-63 - characters and match /[a-z][0-9]-/. Optional. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - Dict containing the newly created ContextProperty resource. - - Raises: - APIError: If the API request fails. - """ - return _create_job_context_property( - self, - integration_name, - job_id, - value, - key=key, - api_version=api_version, - ) - - def update_job_context_property( - self, - integration_name: str, - job_id: str, - context_property_id: str, - value: str, - update_mask: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Update an existing context property for a given integration - job. - - Use this method to modify the value of a previously saved key. - - Args: - integration_name: Name of the integration the job belongs - to. - job_id: ID of the job the context property belongs to. - context_property_id: ID of the context property to update. - value: The new property value. Required. - update_mask: Comma-separated list of fields to update. Only - "value" is supported. If omitted, defaults to "value". - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - Dict containing the updated ContextProperty resource. - - Raises: - APIError: If the API request fails. - """ - return _update_job_context_property( - self, - integration_name, - job_id, - context_property_id, - value, - update_mask=update_mask, - api_version=api_version, - ) - - def delete_all_job_context_properties( - self, - integration_name: str, - job_id: str, - context_id: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> None: - """Delete all context properties for a specific integration - job. - - Use this method to quickly clear all supplemental data from a - job's context. - - Args: - integration_name: Name of the integration the job belongs - to. - job_id: ID of the job to clear context properties from. - context_id: The context ID to remove context properties - from. Must be 4-63 characters and match /[a-z][0-9]-/. - Optional. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - None - - Raises: - APIError: If the API request fails. - """ - return _delete_all_job_context_properties( - self, - integration_name, - job_id, - context_id=context_id, - api_version=api_version, - ) - - # ------------------------------------------------------------------------- - # Job Instance Logs methods - # ------------------------------------------------------------------------- - - def list_job_instance_logs( - self, - integration_name: str, - job_id: str, - job_instance_id: str, - page_size: int | None = None, - page_token: str | None = None, - filter_string: str | None = None, - order_by: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - as_list: bool = False, - ) -> dict[str, Any] | list[dict[str, Any]]: - """List all execution logs for a specific job instance. - - Use this method to browse the historical performance and - reliability of a background automation schedule. - - Args: - integration_name: Name of the integration the job belongs - to. - job_id: ID of the job the instance belongs to. - job_instance_id: ID of the job instance to list logs for. - page_size: Maximum number of logs to return. - page_token: Page token from a previous call to retrieve the - next page. - filter_string: Filter expression to filter logs. - order_by: Field to sort the logs by. - api_version: API version to use for the request. Default is - V1BETA. - as_list: If True, return a list of logs instead of a dict - with logs list and nextPageToken. - - Returns: - If as_list is True: List of logs. - If as_list is False: Dict with logs list and nextPageToken. - - Raises: - APIError: If the API request fails. - """ - return _list_job_instance_logs( - self, - integration_name, - job_id, - job_instance_id, - page_size=page_size, - page_token=page_token, - filter_string=filter_string, - order_by=order_by, - api_version=api_version, - as_list=as_list, - ) - - def get_job_instance_log( - self, - integration_name: str, - job_id: str, - job_instance_id: str, - log_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Get a single log entry for a specific job instance. - - Use this method to retrieve the detailed output message, - start/end times, and final status of a specific background task - execution. - - Args: - integration_name: Name of the integration the job belongs - to. - job_id: ID of the job the instance belongs to. - job_instance_id: ID of the job instance the log belongs to. - log_id: ID of the log entry to retrieve. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - Dict containing details of the specified JobInstanceLog. - - Raises: - APIError: If the API request fails. - """ - return _get_job_instance_log( - self, - integration_name, - job_id, - job_instance_id, - log_id, - api_version=api_version, - ) - - # ------------------------------------------------------------------------- - # Integration Instances methods - # ------------------------------------------------------------------------- - - def list_integration_instances( - self, - integration_name: str, - page_size: int | None = None, - page_token: str | None = None, - filter_string: str | None = None, - order_by: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - as_list: bool = False, - ) -> dict[str, Any] | list[dict[str, Any]]: - """List all instances for a specific integration. - - Use this method to browse the configured integration instances - available for a custom or third-party product across different - environments. - - Args: - integration_name: Name of the integration to list instances - for. - page_size: Maximum number of integration instances to - return. - page_token: Page token from a previous call to retrieve the - next page. - filter_string: Filter expression to filter integration - instances. - order_by: Field to sort the integration instances by. - api_version: API version to use for the request. Default is - V1BETA. - as_list: If True, return a list of integration instances - instead of a dict with integration instances list and - nextPageToken. - - Returns: - If as_list is True: List of integration instances. - If as_list is False: Dict with integration instances list - and nextPageToken. - - Raises: - APIError: If the API request fails. - """ - return _list_integration_instances( - self, - integration_name, - page_size=page_size, - page_token=page_token, - filter_string=filter_string, - order_by=order_by, - api_version=api_version, - as_list=as_list, - ) - - def get_integration_instance( - self, - integration_name: str, - integration_instance_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Get a single instance for a specific integration. - - Use this method to retrieve the specific configuration, - connection status, and environment mapping for an active - integration. - - Args: - integration_name: Name of the integration the instance - belongs to. - integration_instance_id: ID of the integration instance to - retrieve. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - Dict containing details of the specified - IntegrationInstance. - - Raises: - APIError: If the API request fails. - """ - return _get_integration_instance( - self, - integration_name, - integration_instance_id, - api_version=api_version, - ) - - def delete_integration_instance( - self, - integration_name: str, - integration_instance_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> None: - """Delete a specific integration instance. - - Use this method to permanently remove an integration instance - and stop all associated automated tasks (connectors or jobs) - using this instance. - - Args: - integration_name: Name of the integration the instance - belongs to. - integration_instance_id: ID of the integration instance to - delete. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - None - - Raises: - APIError: If the API request fails. - """ - return _delete_integration_instance( - self, - integration_name, - integration_instance_id, - api_version=api_version, - ) - - def create_integration_instance( - self, - integration_name: str, - environment: str, - display_name: str | None = None, - description: str | None = None, - parameters: ( - list[dict[str, Any] | IntegrationInstanceParameter] | None - ) = None, - agent: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Create a new integration instance for a specific - integration. - - Use this method to establish a new integration instance to a - custom or third-party security product for a specific - environment. All mandatory parameters required by the - integration definition must be provided. - - Args: - integration_name: Name of the integration to create the - instance for. - environment: The integration instance environment. Required. - display_name: The display name of the integration instance. - Automatically generated if not provided. Maximum 110 - characters. - description: The integration instance description. Maximum - 1500 characters. - parameters: List of IntegrationInstanceParameter instances - or dicts. - agent: Agent identifier for a remote integration instance. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - Dict containing the newly created IntegrationInstance - resource. - - Raises: - APIError: If the API request fails. - """ - return _create_integration_instance( - self, - integration_name, - environment, - display_name=display_name, - description=description, - parameters=parameters, - agent=agent, - api_version=api_version, - ) - - def update_integration_instance( - self, - integration_name: str, - integration_instance_id: str, - environment: str | None = None, - display_name: str | None = None, - description: str | None = None, - parameters: ( - list[dict[str, Any] | IntegrationInstanceParameter] | None - ) = None, - agent: str | None = None, - update_mask: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Update an existing integration instance. - - Use this method to modify connection parameters (e.g., rotate - an API key), change the display name, or update the description - of a configured integration instance. - - Args: - integration_name: Name of the integration the instance - belongs to. - integration_instance_id: ID of the integration instance to - update. - environment: The integration instance environment. - display_name: The display name of the integration instance. - Maximum 110 characters. - description: The integration instance description. Maximum - 1500 characters. - parameters: List of IntegrationInstanceParameter instances - or dicts. - agent: Agent identifier for a remote integration instance. - update_mask: Comma-separated list of fields to update. If - omitted, the mask is auto-generated from whichever - fields are provided. Example: - "displayName,description". - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - Dict containing the updated IntegrationInstance resource. - - Raises: - APIError: If the API request fails. - """ - return _update_integration_instance( - self, - integration_name, - integration_instance_id, - environment=environment, - display_name=display_name, - description=description, - parameters=parameters, - agent=agent, - update_mask=update_mask, - api_version=api_version, - ) - - def execute_integration_instance_test( - self, - integration_name: str, - integration_instance_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Execute a connectivity test for a specific integration - instance. - - Use this method to verify that SecOps can successfully - communicate with the third-party security product using the - provided credentials. - - Args: - integration_name: Name of the integration the instance - belongs to. - integration_instance_id: ID of the integration instance to - test. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - Dict containing the test results with the following fields: - - successful: Indicates if the test was successful. - - message: Test result message (optional). - - Raises: - APIError: If the API request fails. - """ - return _execute_integration_instance_test( - self, - integration_name, - integration_instance_id, - api_version=api_version, - ) - - def get_integration_instance_affected_items( - self, - integration_name: str, - integration_instance_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """List all playbooks that depend on a specific integration - instance. - - Use this method to perform impact analysis before deleting or - significantly changing a connection configuration. + Use this method to discover which automated tasks have active + integration instances configured for a particular + network or organizational context. Args: - integration_name: Name of the integration the instance - belongs to. - integration_instance_id: ID of the integration instance to - fetch affected items for. - api_version: API version to use for the request. Default is - V1BETA. + integration_name: Name of the integration to fetch actions for. + environments: List of environments to filter actions by. + include_widgets: Whether to include widget actions in the response. + api_version: API version to use for the request. Default is V1BETA. Returns: - Dict containing a list of AffectedPlaybookResponse objects - that depend on the specified integration instance. + Dict containing a list of IntegrationAction objects that have + integration instances in one of the given environments. Raises: APIError: If the API request fails. """ - return _get_integration_instance_affected_items( + return _get_integration_actions_by_environment( self, integration_name, - integration_instance_id, + environments, + include_widgets, api_version=api_version, ) - def get_default_integration_instance( + def get_integration_action_template( self, integration_name: str, + is_async: bool = False, api_version: APIVersion | None = APIVersion.V1BETA, ) -> dict[str, Any]: - """Get the system default configuration for a specific - integration. - - Use this method to retrieve the baseline integration instance - details provided for a commercial product. - - Args: - integration_name: Name of the integration to fetch the - default instance for. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - Dict containing the default IntegrationInstance resource. - - Raises: - APIError: If the API request fails. - """ - return _get_default_integration_instance( - self, - integration_name, - api_version=api_version, - ) - - # -- Integration Transformers methods -- - - def list_integration_transformers( - self, - integration_name: str, - page_size: int | None = None, - page_token: str | None = None, - filter_string: str | None = None, - order_by: str | None = None, - exclude_staging: bool | None = None, - expand: str | None = None, - api_version: APIVersion | None = APIVersion.V1ALPHA, - ) -> dict[str, Any] | list[dict[str, Any]]: - """List all transformer definitions for a specific integration. - - Use this method to browse the available transformers. - - Args: - integration_name: Name of the integration to list transformers - for. - page_size: Maximum number of transformers to return. Defaults - to 100, maximum is 200. - page_token: Page token from a previous call to retrieve the - next page. - filter_string: Filter expression to filter transformers. - order_by: Field to sort the transformers by. - exclude_staging: Whether to exclude staging transformers from - the response. By default, staging transformers are included. - expand: Expand the response with the full transformer details. - api_version: API version to use for the request. Default is - V1ALPHA. - - Returns: - If as_list is True: List of transformers. - If as_list is False: Dict with transformers list and - nextPageToken. - - Raises: - APIError: If the API request fails. - """ - return _list_integration_transformers( - self, - integration_name, - page_size=page_size, - page_token=page_token, - filter_string=filter_string, - order_by=order_by, - exclude_staging=exclude_staging, - expand=expand, - api_version=api_version, - ) - - def get_integration_transformer( - self, - integration_name: str, - transformer_id: str, - expand: str | None = None, - api_version: APIVersion | None = APIVersion.V1ALPHA, - ) -> dict[str, Any]: - """Get a single transformer definition for a specific integration. - - Use this method to retrieve the Python script, input parameters, - and expected input, output and usage example schema for a specific - data transformation logic within an integration. - - Args: - integration_name: Name of the integration the transformer - belongs to. - transformer_id: ID of the transformer to retrieve. - expand: Expand the response with the full transformer details. - Optional. - api_version: API version to use for the request. Default is - V1ALPHA. - - Returns: - Dict containing details of the specified TransformerDefinition. - - Raises: - APIError: If the API request fails. - """ - return _get_integration_transformer( - self, - integration_name, - transformer_id, - expand=expand, - api_version=api_version, - ) - - def delete_integration_transformer( - self, - integration_name: str, - transformer_id: str, - api_version: APIVersion | None = APIVersion.V1ALPHA, - ) -> None: - """Delete a custom transformer definition from a given integration. - - Use this method to permanently remove an obsolete transformer from - an integration. - - Args: - integration_name: Name of the integration the transformer - belongs to. - transformer_id: ID of the transformer to delete. - api_version: API version to use for the request. Default is - V1ALPHA. - - Returns: - None - - Raises: - APIError: If the API request fails. - """ - return _delete_integration_transformer( - self, - integration_name, - transformer_id, - api_version=api_version, - ) - - def create_integration_transformer( - self, - integration_name: str, - display_name: str, - script: str, - script_timeout: str, - enabled: bool, - description: str | None = None, - parameters: list[dict[str, Any]] | None = None, - usage_example: str | None = None, - expected_output: str | None = None, - expected_input: str | None = None, - api_version: APIVersion | None = APIVersion.V1ALPHA, - ) -> dict[str, Any]: - """Create a new transformer definition for a given integration. - - Use this method to define a transformer, specifying its functional - Python script and necessary input parameters. - - Args: - integration_name: Name of the integration to create the - transformer for. - display_name: Transformer's display name. Maximum 150 characters. - Required. - script: Transformer's Python script. Required. - script_timeout: Timeout in seconds for a single script run. - Default is 60. Required. - enabled: Whether the transformer is enabled or disabled. - Required. - description: Transformer's description. Maximum 2050 characters. - Optional. - parameters: List of transformer parameter dicts. Optional. - usage_example: Transformer's usage example. Optional. - expected_output: Transformer's expected output. Optional. - expected_input: Transformer's expected input. Optional. - api_version: API version to use for the request. Default is - V1ALPHA. - - Returns: - Dict containing the newly created TransformerDefinition - resource. - - Raises: - APIError: If the API request fails. - """ - return _create_integration_transformer( - self, - integration_name, - display_name, - script, - script_timeout, - enabled, - description=description, - parameters=parameters, - usage_example=usage_example, - expected_output=expected_output, - expected_input=expected_input, - api_version=api_version, - ) - - def update_integration_transformer( - self, - integration_name: str, - transformer_id: str, - display_name: str | None = None, - script: str | None = None, - script_timeout: str | None = None, - enabled: bool | None = None, - description: str | None = None, - parameters: list[dict[str, Any]] | None = None, - usage_example: str | None = None, - expected_output: str | None = None, - expected_input: str | None = None, - update_mask: str | None = None, - api_version: APIVersion | None = APIVersion.V1ALPHA, - ) -> dict[str, Any]: - """Update an existing transformer definition for a given - integration. - - Use this method to modify a transformation's Python script, adjust - its description, or refine its parameter definitions. - - Args: - integration_name: Name of the integration the transformer - belongs to. - transformer_id: ID of the transformer to update. - display_name: Transformer's display name. Maximum 150 - characters. - script: Transformer's Python script. - script_timeout: Timeout in seconds for a single script run. - enabled: Whether the transformer is enabled or disabled. - description: Transformer's description. Maximum 2050 characters. - parameters: List of transformer parameter dicts. When updating - existing parameters, id must be provided in each parameter. - usage_example: Transformer's usage example. - expected_output: Transformer's expected output. - expected_input: Transformer's expected input. - update_mask: Comma-separated list of fields to update. If - omitted, the mask is auto-generated from whichever fields - are provided. Example: "displayName,script". - api_version: API version to use for the request. Default is - V1ALPHA. - - Returns: - Dict containing the updated TransformerDefinition resource. - - Raises: - APIError: If the API request fails. - """ - return _update_integration_transformer( - self, - integration_name, - transformer_id, - display_name=display_name, - script=script, - script_timeout=script_timeout, - enabled=enabled, - description=description, - parameters=parameters, - usage_example=usage_example, - expected_output=expected_output, - expected_input=expected_input, - update_mask=update_mask, - api_version=api_version, - ) - - def execute_integration_transformer_test( - self, - integration_name: str, - transformer: dict[str, Any], - api_version: APIVersion | None = APIVersion.V1ALPHA, - ) -> dict[str, Any]: - """Execute a test run of a transformer's Python script. - - Use this method to verify transformation logic and ensure data is - being parsed and formatted correctly before saving or deploying - the transformer. The full transformer object is required as the - test can be run without saving the transformer first. - - Args: - integration_name: Name of the integration the transformer - belongs to. - transformer: Dict containing the TransformerDefinition to test. - api_version: API version to use for the request. Default is - V1ALPHA. - - Returns: - Dict containing the test execution results with the following - fields: - - outputMessage: Human-readable output message set by the - script. - - debugOutputMessage: The script debug output. - - resultValue: The script result value. - - Raises: - APIError: If the API request fails. - """ - return _execute_integration_transformer_test( - self, - integration_name, - transformer, - api_version=api_version, - ) - - def get_integration_transformer_template( - self, - integration_name: str, - api_version: APIVersion | None = APIVersion.V1ALPHA, - ) -> dict[str, Any]: - """Retrieve a default Python script template for a new transformer. + """Retrieve a default Python script template for a new + integration action. - Use this method to jumpstart the development of a custom data - transformation logic by providing boilerplate code. + Use this method to jumpstart the development of a custom automated task + by providing boilerplate code for either synchronous or asynchronous + operations. Args: - integration_name: Name of the integration to fetch the template - for. - api_version: API version to use for the request. Default is - V1ALPHA. + integration_name: Name of the integration to fetch the template for. + is_async: Whether to fetch a template for an async action. Default + is False. + api_version: API version to use for the request. Default is V1BETA. Returns: - Dict containing the TransformerDefinition template. + Dict containing the IntegrationAction template. Raises: APIError: If the API request fails. """ - return _get_integration_transformer_template( + return _get_integration_action_template( self, integration_name, + is_async=is_async, api_version=api_version, ) - # -- Integration Transformer Revisions methods -- + # ------------------------------------------------------------------------- + # Integration Action Revisions methods + # ------------------------------------------------------------------------- - def list_integration_transformer_revisions( + def list_integration_action_revisions( self, integration_name: str, - transformer_id: str, + action_id: str, page_size: int | None = None, page_token: str | None = None, filter_string: str | None = None, order_by: str | None = None, - api_version: APIVersion | None = APIVersion.V1ALPHA, + api_version: APIVersion | None = APIVersion.V1BETA, as_list: bool = False, ) -> dict[str, Any] | list[dict[str, Any]]: - """List all revisions for a specific transformer. + """List all revisions for a specific integration action. - Use this method to view the revision history of a transformer, - enabling you to track changes and potentially rollback to previous - versions. + Use this method to view the history of changes to an action, + enabling version control and the ability to rollback to + previous configurations. Args: - integration_name: Name of the integration the transformer + integration_name: Name of the integration the action belongs to. - transformer_id: ID of the transformer to list revisions for. - page_size: Maximum number of revisions to return. Defaults to - 100, maximum is 200. + action_id: ID of the action to list revisions for. + page_size: Maximum number of revisions to return. page_token: Page token from a previous call to retrieve the next page. filter_string: Filter expression to filter revisions. order_by: Field to sort the revisions by. api_version: API version to use for the request. Default is - V1ALPHA. - as_list: If True, automatically fetches all pages and returns - a list of revisions. If False, returns dict with revisions - and nextPageToken. + V1BETA. + as_list: If True, return a list of revisions instead of a + dict with revisions list and nextPageToken. Returns: - If as_list is True: List of transformer revisions. - If as_list is False: Dict with revisions list and nextPageToken. + If as_list is True: List of action revisions. + If as_list is False: Dict with action revisions list and + nextPageToken. Raises: APIError: If the API request fails. """ - return _list_integration_transformer_revisions( + return _list_integration_action_revisions( self, integration_name, - transformer_id, + action_id, page_size=page_size, page_token=page_token, filter_string=filter_string, @@ -5477,25 +1116,25 @@ def list_integration_transformer_revisions( as_list=as_list, ) - def delete_integration_transformer_revision( + def delete_integration_action_revision( self, integration_name: str, - transformer_id: str, + action_id: str, revision_id: str, - api_version: APIVersion | None = APIVersion.V1ALPHA, + api_version: APIVersion | None = APIVersion.V1BETA, ) -> None: - """Delete a specific transformer revision. + """Delete a specific action revision. - Use this method to remove obsolete or incorrect revisions from - a transformer's history. + Use this method to permanently remove a revision from the + action's history. Args: - integration_name: Name of the integration the transformer + integration_name: Name of the integration the action belongs to. - transformer_id: ID of the transformer. + action_id: ID of the action the revision belongs to. revision_id: ID of the revision to delete. api_version: API version to use for the request. Default is - V1ALPHA. + V1BETA. Returns: None @@ -5503,198 +1142,186 @@ def delete_integration_transformer_revision( Raises: APIError: If the API request fails. """ - return _delete_integration_transformer_revision( + return _delete_integration_action_revision( self, integration_name, - transformer_id, + action_id, revision_id, api_version=api_version, ) - def create_integration_transformer_revision( + def create_integration_action_revision( self, integration_name: str, - transformer_id: str, - transformer: dict[str, Any], + action_id: str, + action: dict[str, Any], comment: str | None = None, - api_version: APIVersion | None = APIVersion.V1ALPHA, + api_version: APIVersion | None = APIVersion.V1BETA, ) -> dict[str, Any]: - """Create a new revision for a transformer. + """Create a new revision for an integration action. - Use this method to create a snapshot of the transformer's current - state before making changes, enabling you to rollback if needed. + Use this method to save a snapshot of the current action + configuration before making changes, enabling easy rollback if + needed. Args: - integration_name: Name of the integration the transformer + integration_name: Name of the integration the action belongs to. - transformer_id: ID of the transformer to create a revision for. - transformer: Dict containing the TransformerDefinition to save - as a revision. - comment: Optional comment describing the revision or changes. + action_id: ID of the action to create a revision for. + action: The action object to save as a revision. + comment: Optional comment describing the revision. api_version: API version to use for the request. Default is - V1ALPHA. + V1BETA. Returns: - Dict containing the newly created TransformerRevision resource. + Dict containing the newly created ActionRevision resource. Raises: APIError: If the API request fails. """ - return _create_integration_transformer_revision( + return _create_integration_action_revision( self, integration_name, - transformer_id, - transformer, + action_id, + action, comment=comment, api_version=api_version, ) - def rollback_integration_transformer_revision( + def rollback_integration_action_revision( self, integration_name: str, - transformer_id: str, + action_id: str, revision_id: str, - api_version: APIVersion | None = APIVersion.V1ALPHA, + api_version: APIVersion | None = APIVersion.V1BETA, ) -> dict[str, Any]: - """Rollback a transformer to a previous revision. + """Rollback an integration action to a previous revision. - Use this method to restore a transformer to a previous working - state by rolling back to a specific revision. + Use this method to restore an action to a previously saved + state, reverting any changes made since that revision. Args: - integration_name: Name of the integration the transformer + integration_name: Name of the integration the action belongs to. - transformer_id: ID of the transformer to rollback. + action_id: ID of the action to rollback. revision_id: ID of the revision to rollback to. api_version: API version to use for the request. Default is - V1ALPHA. + V1BETA. Returns: - Dict containing the updated TransformerDefinition resource. + Dict containing the rolled back IntegrationAction resource. Raises: APIError: If the API request fails. """ - return _rollback_integration_transformer_revision( + return _rollback_integration_action_revision( self, integration_name, - transformer_id, + action_id, revision_id, api_version=api_version, ) - # -- Integration Logical Operators methods -- + # ------------------------------------------------------------------------- + # Integration Manager methods + # ------------------------------------------------------------------------- - def list_integration_logical_operators( + def list_integration_managers( self, integration_name: str, page_size: int | None = None, page_token: str | None = None, filter_string: str | None = None, order_by: str | None = None, - exclude_staging: bool | None = None, - expand: str | None = None, - api_version: APIVersion | None = APIVersion.V1ALPHA, + api_version: APIVersion | None = APIVersion.V1BETA, as_list: bool = False, ) -> dict[str, Any] | list[dict[str, Any]]: - """List all logical operator definitions for a specific integration. + """List all managers defined for a specific integration. - Use this method to browse the available logical operators that can - be used for conditional logic in your integration workflows. + Use this method to discover the library of managers available + within a particular integration's scope. Args: - integration_name: Name of the integration to list logical - operators for. - page_size: Maximum number of logical operators to return. - Defaults to 100, maximum is 200. + integration_name: Name of the integration to list managers + for. + page_size: Maximum number of managers to return. Defaults to + 100, maximum is 100. page_token: Page token from a previous call to retrieve the next page. - filter_string: Filter expression to filter logical operators. - order_by: Field to sort the logical operators by. - exclude_staging: Whether to exclude staging logical operators - from the response. By default, staging operators are included. - expand: Expand the response with the full logical operator - details. + filter_string: Filter expression to filter managers. + order_by: Field to sort the managers by. api_version: API version to use for the request. Default is - V1ALPHA. - as_list: If True, automatically fetches all pages and returns - a list. If False, returns dict with list and nextPageToken. + V1BETA. + as_list: If True, return a list of managers instead of a + dict with managers list and nextPageToken. Returns: - If as_list is True: List of logical operators. - If as_list is False: Dict with logicalOperators list and + If as_list is True: List of managers. + If as_list is False: Dict with managers list and nextPageToken. Raises: APIError: If the API request fails. """ - return _list_integration_logical_operators( + return _list_integration_managers( self, integration_name, page_size=page_size, page_token=page_token, filter_string=filter_string, order_by=order_by, - exclude_staging=exclude_staging, - expand=expand, api_version=api_version, as_list=as_list, ) - def get_integration_logical_operator( + def get_integration_manager( self, integration_name: str, - logical_operator_id: str, - expand: str | None = None, - api_version: APIVersion | None = APIVersion.V1ALPHA, + manager_id: str, + api_version: APIVersion | None = APIVersion.V1BETA, ) -> dict[str, Any]: - """Get a single logical operator definition for a specific integration. + """Get a single manager for a given integration. - Use this method to retrieve the Python script, input parameters, - and evaluation logic for a specific logical operator within an - integration. + Use this method to retrieve the manager script and its metadata + for review or reference. Args: - integration_name: Name of the integration the logical operator + integration_name: Name of the integration the manager belongs to. - logical_operator_id: ID of the logical operator to retrieve. - expand: Expand the response with the full logical operator - details. Optional. + manager_id: ID of the manager to retrieve. api_version: API version to use for the request. Default is - V1ALPHA. + V1BETA. Returns: - Dict containing details of the specified LogicalOperator - definition. + Dict containing details of the specified IntegrationManager. Raises: APIError: If the API request fails. """ - return _get_integration_logical_operator( + return _get_integration_manager( self, integration_name, - logical_operator_id, - expand=expand, + manager_id, api_version=api_version, ) - def delete_integration_logical_operator( + def delete_integration_manager( self, integration_name: str, - logical_operator_id: str, - api_version: APIVersion | None = APIVersion.V1ALPHA, + manager_id: str, + api_version: APIVersion | None = APIVersion.V1BETA, ) -> None: - """Delete a custom logical operator definition from a given integration. + """Delete a specific custom manager from a given integration. - Use this method to permanently remove an obsolete logical operator - from an integration. + Note that deleting a manager may break components (actions, + jobs) that depend on its code. Args: - integration_name: Name of the integration the logical operator + integration_name: Name of the integration the manager belongs to. - logical_operator_id: ID of the logical operator to delete. + manager_id: ID of the manager to delete. api_version: API version to use for the request. Default is - V1ALPHA. + V1BETA. Returns: None @@ -5702,264 +1329,237 @@ def delete_integration_logical_operator( Raises: APIError: If the API request fails. """ - return _delete_integration_logical_operator( + return _delete_integration_manager( self, integration_name, - logical_operator_id, + manager_id, api_version=api_version, ) - def create_integration_logical_operator( + def create_integration_manager( self, integration_name: str, display_name: str, script: str, - script_timeout: str, - enabled: bool, description: str | None = None, - parameters: list[dict[str, Any]] | None = None, - api_version: APIVersion | None = APIVersion.V1ALPHA, + api_version: APIVersion | None = APIVersion.V1BETA, ) -> dict[str, Any]: - """Create a new logical operator definition for a given integration. + """Create a new custom manager for a given integration. - Use this method to define a logical operator, specifying its - functional Python script and necessary input parameters for - conditional evaluations. + Use this method to add a new shared code utility. Each manager + must have a unique display name and a script containing valid + Python logic for reuse across actions, jobs, and connectors. Args: integration_name: Name of the integration to create the - logical operator for. - display_name: Logical operator's display name. Maximum 150 + manager for. + display_name: Manager's display name. Maximum 150 characters. Required. - script: Logical operator's Python script. Required. - script_timeout: Timeout in seconds for a single script run. - Default is 60. Required. - enabled: Whether the logical operator is enabled or disabled. - Required. - description: Logical operator's description. Maximum 2050 - characters. Optional. - parameters: List of logical operator parameter dicts. Optional. + script: Manager's Python script. Maximum 5MB. Required. + description: Manager's description. Maximum 400 characters. + Optional. api_version: API version to use for the request. Default is - V1ALPHA. + V1BETA. Returns: - Dict containing the newly created LogicalOperator resource. + Dict containing the newly created IntegrationManager + resource. Raises: APIError: If the API request fails. """ - return _create_integration_logical_operator( + return _create_integration_manager( self, integration_name, display_name, script, - script_timeout, - enabled, description=description, - parameters=parameters, api_version=api_version, ) - def update_integration_logical_operator( + def update_integration_manager( self, integration_name: str, - logical_operator_id: str, + manager_id: str, display_name: str | None = None, script: str | None = None, - script_timeout: str | None = None, - enabled: bool | None = None, description: str | None = None, - parameters: list[dict[str, Any]] | None = None, update_mask: str | None = None, - api_version: APIVersion | None = APIVersion.V1ALPHA, + api_version: APIVersion | None = APIVersion.V1BETA, ) -> dict[str, Any]: - """Update an existing logical operator definition for a given - integration. + """Update an existing custom manager for a given integration. - Use this method to modify a logical operator's Python script, - adjust its description, or refine its parameter definitions. + Use this method to modify the shared code, adjust its + description, or refine its logic across all components that + import it. Args: - integration_name: Name of the integration the logical operator + integration_name: Name of the integration the manager belongs to. - logical_operator_id: ID of the logical operator to update. - display_name: Logical operator's display name. Maximum 150 - characters. - script: Logical operator's Python script. - script_timeout: Timeout in seconds for a single script run. - enabled: Whether the logical operator is enabled or disabled. - description: Logical operator's description. Maximum 2050 + manager_id: ID of the manager to update. + display_name: Manager's display name. Maximum 150 characters. - parameters: List of logical operator parameter dicts. When - updating existing parameters, id must be provided in each - parameter. + script: Manager's Python script. Maximum 5MB. + description: Manager's description. Maximum 400 characters. update_mask: Comma-separated list of fields to update. If - omitted, the mask is auto-generated from whichever fields - are provided. Example: "displayName,script". + omitted, the mask is auto-generated from whichever + fields are provided. Example: "displayName,script". api_version: API version to use for the request. Default is - V1ALPHA. + V1BETA. Returns: - Dict containing the updated LogicalOperator resource. + Dict containing the updated IntegrationManager resource. Raises: APIError: If the API request fails. """ - return _update_integration_logical_operator( + return _update_integration_manager( self, integration_name, - logical_operator_id, + manager_id, display_name=display_name, script=script, - script_timeout=script_timeout, - enabled=enabled, description=description, - parameters=parameters, update_mask=update_mask, api_version=api_version, ) - def execute_integration_logical_operator_test( + def get_integration_manager_template( self, integration_name: str, - logical_operator: dict[str, Any], - api_version: APIVersion | None = APIVersion.V1ALPHA, + api_version: APIVersion | None = APIVersion.V1BETA, ) -> dict[str, Any]: - """Execute a test run of a logical operator's Python script. + """Retrieve a default Python script template for a new + integration manager. - Use this method to verify logical operator evaluation logic and - ensure conditions are being assessed correctly before saving or - deploying the operator. The full logical operator object is - required as the test can be run without saving the operator first. + Use this method to quickly start developing new managers. Args: - integration_name: Name of the integration the logical operator - belongs to. - logical_operator: Dict containing the LogicalOperator - definition to test. + integration_name: Name of the integration to fetch the + template for. api_version: API version to use for the request. Default is - V1ALPHA. + V1BETA. Returns: - Dict containing the test execution results with the following - fields: - - outputMessage: Human-readable output message set by the - script. - - debugOutputMessage: The script debug output. - - resultValue: The script result value (True/False). + Dict containing the IntegrationManager template. Raises: APIError: If the API request fails. """ - return _execute_integration_logical_operator_test( + return _get_integration_manager_template( self, integration_name, - logical_operator, api_version=api_version, ) - def get_integration_logical_operator_template( + # ------------------------------------------------------------------------- + # Integration Manager Revisions methods + # ------------------------------------------------------------------------- + + def list_integration_manager_revisions( self, integration_name: str, - api_version: APIVersion | None = APIVersion.V1ALPHA, - ) -> dict[str, Any]: - """Retrieve a default Python script template for a new logical operator. + manager_id: str, + page_size: int | None = None, + page_token: str | None = None, + filter_string: str | None = None, + order_by: str | None = None, + api_version: APIVersion | None = APIVersion.V1BETA, + as_list: bool = False, + ) -> dict[str, Any] | list[dict[str, Any]]: + """List all revisions for a specific integration manager. - Use this method to jumpstart the development of a custom - conditional logic by providing boilerplate code. + Use this method to browse the version history and identify + previous functional states of a manager. Args: - integration_name: Name of the integration to fetch the template - for. + integration_name: Name of the integration the manager + belongs to. + manager_id: ID of the manager to list revisions for. + page_size: Maximum number of revisions to return. + page_token: Page token from a previous call to retrieve the + next page. + filter_string: Filter expression to filter revisions. + order_by: Field to sort the revisions by. api_version: API version to use for the request. Default is - V1ALPHA. + V1BETA. + as_list: If True, return a list of revisions instead of a + dict with revisions list and nextPageToken. Returns: - Dict containing the LogicalOperator template. + If as_list is True: List of revisions. + If as_list is False: Dict with revisions list and + nextPageToken. Raises: APIError: If the API request fails. """ - return _get_integration_logical_operator_template( + return _list_integration_manager_revisions( self, integration_name, + manager_id, + page_size=page_size, + page_token=page_token, + filter_string=filter_string, + order_by=order_by, api_version=api_version, + as_list=as_list, ) - # -- Integration Logical Operator Revisions methods -- - - def list_integration_logical_operator_revisions( + def get_integration_manager_revision( self, integration_name: str, - logical_operator_id: str, - page_size: int | None = None, - page_token: str | None = None, - filter_string: str | None = None, - order_by: str | None = None, - api_version: APIVersion | None = APIVersion.V1ALPHA, - as_list: bool = False, - ) -> dict[str, Any] | list[dict[str, Any]]: - """List all revisions for a specific logical operator. + manager_id: str, + revision_id: str, + api_version: APIVersion | None = APIVersion.V1BETA, + ) -> dict[str, Any]: + """Get a single revision for a specific integration manager. - Use this method to view the revision history of a logical operator, - enabling you to track changes and potentially rollback to previous - versions. + Use this method to retrieve a specific snapshot of an + IntegrationManagerRevision for comparison or review. Args: - integration_name: Name of the integration the logical operator + integration_name: Name of the integration the manager belongs to. - logical_operator_id: ID of the logical operator to list - revisions for. - page_size: Maximum number of revisions to return. Defaults to - 100, maximum is 200. - page_token: Page token from a previous call to retrieve the - next page. - filter_string: Filter expression to filter revisions. - order_by: Field to sort the revisions by. + manager_id: ID of the manager the revision belongs to. + revision_id: ID of the revision to retrieve. api_version: API version to use for the request. Default is - V1ALPHA. - as_list: If True, automatically fetches all pages and returns - a list of revisions. If False, returns dict with revisions - and nextPageToken. + V1BETA. Returns: - If as_list is True: List of logical operator revisions. - If as_list is False: Dict with revisions list and nextPageToken. + Dict containing details of the specified + IntegrationManagerRevision. Raises: APIError: If the API request fails. """ - return _list_integration_logical_operator_revisions( + return _get_integration_manager_revision( self, integration_name, - logical_operator_id, - page_size=page_size, - page_token=page_token, - filter_string=filter_string, - order_by=order_by, + manager_id, + revision_id, api_version=api_version, - as_list=as_list, ) - def delete_integration_logical_operator_revision( + def delete_integration_manager_revision( self, integration_name: str, - logical_operator_id: str, + manager_id: str, revision_id: str, - api_version: APIVersion | None = APIVersion.V1ALPHA, + api_version: APIVersion | None = APIVersion.V1BETA, ) -> None: - """Delete a specific logical operator revision. + """Delete a specific revision for a given integration manager. - Use this method to remove obsolete or incorrect revisions from - a logical operator's history. + Use this method to clean up obsolete snapshots and manage the + historical record of managers. Args: - integration_name: Name of the integration the logical operator + integration_name: Name of the integration the manager belongs to. - logical_operator_id: ID of the logical operator. + manager_id: ID of the manager the revision belongs to. revision_id: ID of the revision to delete. api_version: API version to use for the request. Default is - V1ALPHA. + V1BETA. Returns: None @@ -5967,85 +1567,87 @@ def delete_integration_logical_operator_revision( Raises: APIError: If the API request fails. """ - return _delete_integration_logical_operator_revision( + return _delete_integration_manager_revision( self, integration_name, - logical_operator_id, + manager_id, revision_id, api_version=api_version, ) - def create_integration_logical_operator_revision( + def create_integration_manager_revision( self, integration_name: str, - logical_operator_id: str, - logical_operator: dict[str, Any], + manager_id: str, + manager: dict[str, Any], comment: str | None = None, - api_version: APIVersion | None = APIVersion.V1ALPHA, + api_version: APIVersion | None = APIVersion.V1BETA, ) -> dict[str, Any]: - """Create a new revision for a logical operator. + """Create a new revision snapshot of the current integration + manager. - Use this method to create a snapshot of the logical operator's - current state before making changes, enabling you to rollback if - needed. + Use this method to establish a recovery point before making + significant updates to a manager. Args: - integration_name: Name of the integration the logical operator + integration_name: Name of the integration the manager belongs to. - logical_operator_id: ID of the logical operator to create a - revision for. - logical_operator: Dict containing the LogicalOperator - definition to save as a revision. - comment: Optional comment describing the revision or changes. + manager_id: ID of the manager to create a revision for. + manager: Dict containing the IntegrationManager to snapshot. + comment: Comment describing the revision. Maximum 400 + characters. Optional. api_version: API version to use for the request. Default is - V1ALPHA. + V1BETA. Returns: - Dict containing the newly created LogicalOperatorRevision - resource. + Dict containing the newly created + IntegrationManagerRevision resource. Raises: APIError: If the API request fails. """ - return _create_integration_logical_operator_revision( + return _create_integration_manager_revision( self, integration_name, - logical_operator_id, - logical_operator, + manager_id, + manager, comment=comment, api_version=api_version, ) - def rollback_integration_logical_operator_revision( + def rollback_integration_manager_revision( self, integration_name: str, - logical_operator_id: str, + manager_id: str, revision_id: str, - api_version: APIVersion | None = APIVersion.V1ALPHA, + api_version: APIVersion | None = APIVersion.V1BETA, ) -> dict[str, Any]: - """Rollback a logical operator to a previous revision. + """Revert the current manager definition to a previously saved + revision. - Use this method to restore a logical operator to a previous - working state by rolling back to a specific revision. + Use this method to rapidly recover a functional state for + common code if an update causes operational issues in dependent + actions or jobs. Args: - integration_name: Name of the integration the logical operator + integration_name: Name of the integration the manager belongs to. - logical_operator_id: ID of the logical operator to rollback. + manager_id: ID of the manager to rollback. revision_id: ID of the revision to rollback to. api_version: API version to use for the request. Default is - V1ALPHA. + V1BETA. Returns: - Dict containing the updated LogicalOperator resource. + Dict containing the IntegrationManagerRevision rolled back + to. Raises: APIError: If the API request fails. """ - return _rollback_integration_logical_operator_revision( + return _rollback_integration_manager_revision( self, integration_name, - logical_operator_id, + manager_id, revision_id, api_version=api_version, ) diff --git a/src/secops/chronicle/integration/connector_context_properties.py b/src/secops/chronicle/integration/connector_context_properties.py deleted file mode 100644 index 24e59f66..00000000 --- a/src/secops/chronicle/integration/connector_context_properties.py +++ /dev/null @@ -1,299 +0,0 @@ -# Copyright 2025 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. -# -"""Integration connector context properties functionality for Chronicle.""" - -from typing import Any, TYPE_CHECKING - -from secops.chronicle.models import APIVersion -from secops.chronicle.utils.format_utils import ( - format_resource_id, - build_patch_body, -) -from secops.chronicle.utils.request_utils import ( - chronicle_paginated_request, - chronicle_request, -) - -if TYPE_CHECKING: - from secops.chronicle.client import ChronicleClient - - -def list_connector_context_properties( - client: "ChronicleClient", - integration_name: str, - connector_id: str, - page_size: int | None = None, - page_token: str | None = None, - filter_string: str | None = None, - order_by: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - as_list: bool = False, -) -> dict[str, Any] | list[dict[str, Any]]: - """List all context properties for a specific integration connector. - - Use this method to discover all custom data points associated with a - connector. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the connector belongs to. - connector_id: ID of the connector to list context properties for. - page_size: Maximum number of context properties to return. - page_token: Page token from a previous call to retrieve the next page. - filter_string: Filter expression to filter context properties. - order_by: Field to sort the context properties by. - api_version: API version to use for the request. Default is V1BETA. - as_list: If True, return a list of context properties instead of a - dict with context properties list and nextPageToken. - - Returns: - If as_list is True: List of context properties. - If as_list is False: Dict with context properties list and - nextPageToken. - - Raises: - APIError: If the API request fails. - """ - extra_params = { - "filter": filter_string, - "orderBy": order_by, - } - - # Remove keys with None values - extra_params = {k: v for k, v in extra_params.items() if v is not None} - - return chronicle_paginated_request( - client, - api_version=api_version, - path=( - f"integrations/{format_resource_id(integration_name)}/" - f"connectors/{connector_id}/contextProperties" - ), - items_key="contextProperties", - page_size=page_size, - page_token=page_token, - extra_params=extra_params, - as_list=as_list, - ) - - -def get_connector_context_property( - client: "ChronicleClient", - integration_name: str, - connector_id: str, - context_property_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> dict[str, Any]: - """Get a single context property for a specific integration connector. - - Use this method to retrieve the value of a specific key within a - connector's context. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the connector belongs to. - connector_id: ID of the connector the context property belongs to. - context_property_id: ID of the context property to retrieve. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing details of the specified ContextProperty. - - Raises: - APIError: If the API request fails. - """ - return chronicle_request( - client, - method="GET", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"connectors/{connector_id}/contextProperties/{context_property_id}" - ), - api_version=api_version, - ) - - -def delete_connector_context_property( - client: "ChronicleClient", - integration_name: str, - connector_id: str, - context_property_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> None: - """Delete a specific context property for a given integration connector. - - Use this method to remove a custom data point that is no longer relevant - to the connector's context. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the connector belongs to. - connector_id: ID of the connector the context property belongs to. - context_property_id: ID of the context property to delete. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - None - - Raises: - APIError: If the API request fails. - """ - chronicle_request( - client, - method="DELETE", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"connectors/{connector_id}/contextProperties/{context_property_id}" - ), - api_version=api_version, - ) - - -def create_connector_context_property( - client: "ChronicleClient", - integration_name: str, - connector_id: str, - value: str, - key: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> dict[str, Any]: - """Create a new context property for a specific integration connector. - - Use this method to attach custom data to a connector's context. Property - keys must be unique within their context. Key values must be 4-63 - characters and match /[a-z][0-9]-/. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the connector belongs to. - connector_id: ID of the connector to create the context property for. - value: The property value. Required. - key: The context property ID to use. Must be 4-63 characters and - match /[a-z][0-9]-/. Optional. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing the newly created ContextProperty resource. - - Raises: - APIError: If the API request fails. - """ - body = {"value": value} - - if key is not None: - body["key"] = key - - return chronicle_request( - client, - method="POST", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"connectors/{connector_id}/contextProperties" - ), - api_version=api_version, - json=body, - ) - - -def update_connector_context_property( - client: "ChronicleClient", - integration_name: str, - connector_id: str, - context_property_id: str, - value: str, - update_mask: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> dict[str, Any]: - """Update an existing context property for a given integration connector. - - Use this method to modify the value of a previously saved key. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the connector belongs to. - connector_id: ID of the connector the context property belongs to. - context_property_id: ID of the context property to update. - value: The new property value. Required. - update_mask: Comma-separated list of fields to update. Only "value" - is supported. If omitted, defaults to "value". - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing the updated ContextProperty resource. - - Raises: - APIError: If the API request fails. - """ - body, params = build_patch_body( - field_map=[ - ("value", "value", value), - ], - update_mask=update_mask, - ) - - return chronicle_request( - client, - method="PATCH", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"connectors/{connector_id}/contextProperties/{context_property_id}" - ), - api_version=api_version, - json=body, - params=params, - ) - - -def delete_all_connector_context_properties( - client: "ChronicleClient", - integration_name: str, - connector_id: str, - context_id: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> None: - """Delete all context properties for a specific integration connector. - - Use this method to quickly clear all supplemental data from a connector's - context. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the connector belongs to. - connector_id: ID of the connector to clear context properties from. - context_id: The context ID to remove context properties from. Must be - 4-63 characters and match /[a-z][0-9]-/. Optional. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - None - - Raises: - APIError: If the API request fails. - """ - body = {} - - if context_id is not None: - body["contextId"] = context_id - - chronicle_request( - client, - method="POST", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"connectors/{connector_id}/contextProperties:clearAll" - ), - api_version=api_version, - json=body, - ) diff --git a/src/secops/chronicle/integration/connector_instance_logs.py b/src/secops/chronicle/integration/connector_instance_logs.py deleted file mode 100644 index 0be7bd25..00000000 --- a/src/secops/chronicle/integration/connector_instance_logs.py +++ /dev/null @@ -1,130 +0,0 @@ -# Copyright 2025 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. -# -"""Integration connector instance logs functionality for Chronicle.""" - -from typing import Any, TYPE_CHECKING - -from secops.chronicle.models import APIVersion -from secops.chronicle.utils.format_utils import format_resource_id -from secops.chronicle.utils.request_utils import ( - chronicle_paginated_request, - chronicle_request, -) - -if TYPE_CHECKING: - from secops.chronicle.client import ChronicleClient - - -def list_connector_instance_logs( - client: "ChronicleClient", - integration_name: str, - connector_id: str, - connector_instance_id: str, - page_size: int | None = None, - page_token: str | None = None, - filter_string: str | None = None, - order_by: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - as_list: bool = False, -) -> dict[str, Any] | list[dict[str, Any]]: - """List all logs for a specific connector instance. - - Use this method to browse the execution history and diagnostic output of - a connector. Supports filtering and pagination to efficiently navigate - large volumes of log data. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the connector belongs to. - connector_id: ID of the connector the instance belongs to. - connector_instance_id: ID of the connector instance to list logs for. - page_size: Maximum number of logs to return. - page_token: Page token from a previous call to retrieve the next page. - filter_string: Filter expression to filter logs. - order_by: Field to sort the logs by. - api_version: API version to use for the request. Default is V1BETA. - as_list: If True, return a list of logs instead of a dict with logs - list and nextPageToken. - - Returns: - If as_list is True: List of logs. - If as_list is False: Dict with logs list and nextPageToken. - - Raises: - APIError: If the API request fails. - """ - extra_params = { - "filter": filter_string, - "orderBy": order_by, - } - - # Remove keys with None values - extra_params = {k: v for k, v in extra_params.items() if v is not None} - - return chronicle_paginated_request( - client, - api_version=api_version, - path=( - f"integrations/{format_resource_id(integration_name)}/" - f"connectors/{connector_id}/connectorInstances/" - f"{connector_instance_id}/logs" - ), - items_key="logs", - page_size=page_size, - page_token=page_token, - extra_params=extra_params, - as_list=as_list, - ) - - -def get_connector_instance_log( - client: "ChronicleClient", - integration_name: str, - connector_id: str, - connector_instance_id: str, - log_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> dict[str, Any]: - """Get a single log entry for a specific connector instance. - - Use this method to retrieve a specific log entry from a connector - instance's execution, including its message, timestamp, and severity - level. Useful for auditing and detailed troubleshooting of a specific - connector run. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the connector belongs to. - connector_id: ID of the connector the instance belongs to. - connector_instance_id: ID of the connector instance the log belongs to. - log_id: ID of the log entry to retrieve. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing details of the specified ConnectorLog. - - Raises: - APIError: If the API request fails. - """ - return chronicle_request( - client, - method="GET", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"connectors/{connector_id}/connectorInstances/" - f"{connector_instance_id}/logs/{log_id}" - ), - api_version=api_version, - ) diff --git a/src/secops/chronicle/integration/connector_instances.py b/src/secops/chronicle/integration/connector_instances.py deleted file mode 100644 index c6b563cc..00000000 --- a/src/secops/chronicle/integration/connector_instances.py +++ /dev/null @@ -1,489 +0,0 @@ -# Copyright 2025 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. -# -"""Integration connector instances functionality for Chronicle.""" - -from typing import Any, TYPE_CHECKING - -from secops.chronicle.models import ( - APIVersion, - ConnectorInstanceParameter, -) -from secops.chronicle.utils.format_utils import ( - format_resource_id, - build_patch_body, -) -from secops.chronicle.utils.request_utils import ( - chronicle_paginated_request, - chronicle_request, -) - -if TYPE_CHECKING: - from secops.chronicle.client import ChronicleClient - - -def list_connector_instances( - client: "ChronicleClient", - integration_name: str, - connector_id: str, - page_size: int | None = None, - page_token: str | None = None, - filter_string: str | None = None, - order_by: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - as_list: bool = False, -) -> dict[str, Any] | list[dict[str, Any]]: - """List all instances for a specific integration connector. - - Use this method to discover all configured instances of a connector. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the connector belongs to. - connector_id: ID of the connector to list instances for. - page_size: Maximum number of connector instances to return. - page_token: Page token from a previous call to retrieve the next page. - filter_string: Filter expression to filter connector instances. - order_by: Field to sort the connector instances by. - api_version: API version to use for the request. Default is V1BETA. - as_list: If True, return a list of connector instances instead of a - dict with connector instances list and nextPageToken. - - Returns: - If as_list is True: List of connector instances. - If as_list is False: Dict with connector instances list and - nextPageToken. - - Raises: - APIError: If the API request fails. - """ - extra_params = { - "filter": filter_string, - "orderBy": order_by, - } - - # Remove keys with None values - extra_params = {k: v for k, v in extra_params.items() if v is not None} - - return chronicle_paginated_request( - client, - api_version=api_version, - path=( - f"integrations/{format_resource_id(integration_name)}/" - f"connectors/{connector_id}/connectorInstances" - ), - items_key="connectorInstances", - page_size=page_size, - page_token=page_token, - extra_params=extra_params, - as_list=as_list, - ) - - -def get_connector_instance( - client: "ChronicleClient", - integration_name: str, - connector_id: str, - connector_instance_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> dict[str, Any]: - """Get a single instance for a specific integration connector. - - Use this method to retrieve the configuration and status of a specific - connector instance. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the connector belongs to. - connector_id: ID of the connector the instance belongs to. - connector_instance_id: ID of the connector instance to retrieve. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing details of the specified ConnectorInstance. - - Raises: - APIError: If the API request fails. - """ - return chronicle_request( - client, - method="GET", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"connectors/{connector_id}/connectorInstances/" - f"{connector_instance_id}" - ), - api_version=api_version, - ) - - -def delete_connector_instance( - client: "ChronicleClient", - integration_name: str, - connector_id: str, - connector_instance_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> None: - """Delete a specific connector instance. - - Use this method to permanently remove a data ingestion stream. For remote - connectors, the associated agent must be live and have no pending packages. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the connector belongs to. - connector_id: ID of the connector the instance belongs to. - connector_instance_id: ID of the connector instance to delete. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - None - - Raises: - APIError: If the API request fails. - """ - chronicle_request( - client, - method="DELETE", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"connectors/{connector_id}/connectorInstances/" - f"{connector_instance_id}" - ), - api_version=api_version, - ) - - -def create_connector_instance( - client: "ChronicleClient", - integration_name: str, - connector_id: str, - environment: str, - display_name: str, - interval_seconds: int, - timeout_seconds: int, - description: str | None = None, - agent: str | None = None, - allow_list: list[str] | None = None, - product_field_name: str | None = None, - event_field_name: str | None = None, - integration_version: str | None = None, - version: str | None = None, - logging_enabled_until_unix_ms: str | None = None, - parameters: list[dict[str, Any] | ConnectorInstanceParameter] | None = None, - connector_instance_id: str | None = None, - enabled: bool | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> dict[str, Any]: - """Create a new connector instance for a specific integration connector. - - Use this method to establish a new data ingestion stream from a security - product. Note that agent and remote cannot be patched after creation. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the connector belongs to. - connector_id: ID of the connector to create an instance for. - environment: Connector instance environment. Cannot be patched for - remote connectors. Required. - display_name: Connector instance display name. Required. - interval_seconds: Connector instance execution interval in seconds. - Required. - timeout_seconds: Timeout of a single Python script run. Required. - description: Connector instance description. Optional. - agent: Agent identifier for a remote connector instance. Cannot be - patched after creation. Optional. - allow_list: Connector instance allow list. Optional. - product_field_name: Connector's device product field. Optional. - event_field_name: Connector's event name field. Optional. - integration_version: The integration version. Optional. - version: The connector instance version. Optional. - logging_enabled_until_unix_ms: Timeout when log collecting will be - disabled. Optional. - parameters: List of ConnectorInstanceParameter instances or dicts. - Optional. - connector_instance_id: The connector instance id. Optional. - enabled: Whether the connector instance is enabled. Optional. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing the newly created ConnectorInstance resource. - - Raises: - APIError: If the API request fails. - """ - resolved_parameters = ( - [ - p.to_dict() if isinstance(p, ConnectorInstanceParameter) else p - for p in parameters - ] - if parameters is not None - else None - ) - - body = { - "environment": environment, - "displayName": display_name, - "intervalSeconds": interval_seconds, - "timeoutSeconds": timeout_seconds, - "description": description, - "agent": agent, - "allowList": allow_list, - "productFieldName": product_field_name, - "eventFieldName": event_field_name, - "integrationVersion": integration_version, - "version": version, - "loggingEnabledUntilUnixMs": logging_enabled_until_unix_ms, - "parameters": resolved_parameters, - "id": connector_instance_id, - "enabled": enabled, - } - - # Remove keys with None values - body = {k: v for k, v in body.items() if v is not None} - - return chronicle_request( - client, - method="POST", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"connectors/{connector_id}/connectorInstances" - ), - api_version=api_version, - json=body, - ) - - -def update_connector_instance( - client: "ChronicleClient", - integration_name: str, - connector_id: str, - connector_instance_id: str, - display_name: str | None = None, - description: str | None = None, - interval_seconds: int | None = None, - timeout_seconds: int | None = None, - allow_list: list[str] | None = None, - product_field_name: str | None = None, - event_field_name: str | None = None, - integration_version: str | None = None, - version: str | None = None, - logging_enabled_until_unix_ms: str | None = None, - parameters: list[dict[str, Any] | ConnectorInstanceParameter] | None = None, - enabled: bool | None = None, - update_mask: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> dict[str, Any]: - """Update an existing connector instance. - - Use this method to enable or disable a connector, change its display - name, or adjust its ingestion parameters. Note that agent, remote, and - environment cannot be patched after creation. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the connector belongs to. - connector_id: ID of the connector the instance belongs to. - connector_instance_id: ID of the connector instance to update. - display_name: Connector instance display name. - description: Connector instance description. - interval_seconds: Connector instance execution interval in seconds. - timeout_seconds: Timeout of a single Python script run. - allow_list: Connector instance allow list. - product_field_name: Connector's device product field. - event_field_name: Connector's event name field. - integration_version: The integration version. Required on patch if - provided. - version: The connector instance version. - logging_enabled_until_unix_ms: Timeout when log collecting will be - disabled. - parameters: List of ConnectorInstanceParameter instances or dicts. - enabled: Whether the connector instance is enabled. - update_mask: Comma-separated list of fields to update. If omitted, - the mask is auto-generated from whichever fields are provided. - Example: "displayName,intervalSeconds". - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing the updated ConnectorInstance resource. - - Raises: - APIError: If the API request fails. - """ - resolved_parameters = ( - [ - p.to_dict() if isinstance(p, ConnectorInstanceParameter) else p - for p in parameters - ] - if parameters is not None - else None - ) - - body, params = build_patch_body( - field_map=[ - ("displayName", "displayName", display_name), - ("description", "description", description), - ("intervalSeconds", "intervalSeconds", interval_seconds), - ("timeoutSeconds", "timeoutSeconds", timeout_seconds), - ("allowList", "allowList", allow_list), - ("productFieldName", "productFieldName", product_field_name), - ("eventFieldName", "eventFieldName", event_field_name), - ("integrationVersion", "integrationVersion", integration_version), - ("version", "version", version), - ( - "loggingEnabledUntilUnixMs", - "loggingEnabledUntilUnixMs", - logging_enabled_until_unix_ms, - ), - ("parameters", "parameters", resolved_parameters), - ("id", "id", connector_instance_id), - ("enabled", "enabled", enabled), - ], - update_mask=update_mask, - ) - - return chronicle_request( - client, - method="PATCH", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"connectors/{connector_id}/connectorInstances/" - f"{connector_instance_id}" - ), - api_version=api_version, - json=body, - params=params, - ) - - -def get_connector_instance_latest_definition( - client: "ChronicleClient", - integration_name: str, - connector_id: str, - connector_instance_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> dict[str, Any]: - """Refresh a connector instance with the latest definition. - - Use this method to discover new parameters or updated scripts for an - existing connector instance. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the connector belongs to. - connector_id: ID of the connector the instance belongs to. - connector_instance_id: ID of the connector instance to refresh. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing the refreshed ConnectorInstance resource. - - Raises: - APIError: If the API request fails. - """ - return chronicle_request( - client, - method="GET", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"connectors/{connector_id}/connectorInstances/" - f"{connector_instance_id}:fetchLatestDefinition" - ), - api_version=api_version, - ) - - -def set_connector_instance_logs_collection( - client: "ChronicleClient", - integration_name: str, - connector_id: str, - connector_instance_id: str, - enabled: bool, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> dict[str, Any]: - """Enable or disable debug log collection for a connector instance. - - When enabled is set to True, existing logs are cleared and a new - collection period is started. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the connector belongs to. - connector_id: ID of the connector the instance belongs to. - connector_instance_id: ID of the connector instance to configure. - enabled: Whether logs collection is enabled for the connector - instance. Required. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing the log enable expiration time in unix ms. - - Raises: - APIError: If the API request fails. - """ - return chronicle_request( - client, - method="POST", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"connectors/{connector_id}/connectorInstances/" - f"{connector_instance_id}:setLogsCollection" - ), - api_version=api_version, - json={"enabled": enabled}, - ) - - -def run_connector_instance_on_demand( - client: "ChronicleClient", - integration_name: str, - connector_id: str, - connector_instance_id: str, - connector_instance: dict[str, Any], - api_version: APIVersion | None = APIVersion.V1BETA, -) -> dict[str, Any]: - """Trigger an immediate, single execution of a connector instance. - - Use this method for testing configuration changes or manually - force-starting a data ingestion cycle. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the connector belongs to. - connector_id: ID of the connector the instance belongs to. - connector_instance_id: ID of the connector instance to run. - connector_instance: Dict containing the ConnectorInstance with - values to use for the run. Required. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing the run results with the following fields: - - debugOutput: The execution debug output message. - - success: True if the execution was successful. - - sampleCases: List of alerts produced by the connector run. - - Raises: - APIError: If the API request fails. - """ - return chronicle_request( - client, - method="POST", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"connectors/{connector_id}/connectorInstances/" - f"{connector_instance_id}:runOnDemand" - ), - api_version=api_version, - json={"connectorInstance": connector_instance}, - ) diff --git a/src/secops/chronicle/integration/connector_revisions.py b/src/secops/chronicle/integration/connector_revisions.py deleted file mode 100644 index a5908864..00000000 --- a/src/secops/chronicle/integration/connector_revisions.py +++ /dev/null @@ -1,202 +0,0 @@ -# Copyright 2025 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. -# -"""Integration connector revisions functionality for Chronicle.""" - -from typing import Any, TYPE_CHECKING - -from secops.chronicle.models import APIVersion -from secops.chronicle.utils.format_utils import format_resource_id -from secops.chronicle.utils.request_utils import ( - chronicle_paginated_request, - chronicle_request, -) - -if TYPE_CHECKING: - from secops.chronicle.client import ChronicleClient - - -def list_integration_connector_revisions( - client: "ChronicleClient", - integration_name: str, - connector_id: str, - page_size: int | None = None, - page_token: str | None = None, - filter_string: str | None = None, - order_by: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - as_list: bool = False, -) -> dict[str, Any] | list[dict[str, Any]]: - """List all revisions for a specific integration connector. - - Use this method to browse the version history and identify potential - rollback targets. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the connector belongs to. - connector_id: ID of the connector to list revisions for. - page_size: Maximum number of revisions to return. - page_token: Page token from a previous call to retrieve the next page. - filter_string: Filter expression to filter revisions. - order_by: Field to sort the revisions by. - api_version: API version to use for the request. Default is V1BETA. - as_list: If True, return a list of revisions instead of a dict with - revisions list and nextPageToken. - - Returns: - If as_list is True: List of revisions. - If as_list is False: Dict with revisions list and nextPageToken. - - Raises: - APIError: If the API request fails. - """ - extra_params = { - "filter": filter_string, - "orderBy": order_by, - } - - # Remove keys with None values - extra_params = {k: v for k, v in extra_params.items() if v is not None} - - return chronicle_paginated_request( - client, - api_version=api_version, - path=( - f"integrations/{format_resource_id(integration_name)}/" - f"connectors/{connector_id}/revisions" - ), - items_key="revisions", - page_size=page_size, - page_token=page_token, - extra_params=extra_params, - as_list=as_list, - ) - - -def delete_integration_connector_revision( - client: "ChronicleClient", - integration_name: str, - connector_id: str, - revision_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> None: - """Delete a specific revision for a given integration connector. - - Use this method to clean up old or incorrect snapshots from the version - history. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the connector belongs to. - connector_id: ID of the connector the revision belongs to. - revision_id: ID of the revision to delete. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - None - - Raises: - APIError: If the API request fails. - """ - chronicle_request( - client, - method="DELETE", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"connectors/{connector_id}/revisions/{revision_id}" - ), - api_version=api_version, - ) - - -def create_integration_connector_revision( - client: "ChronicleClient", - integration_name: str, - connector_id: str, - connector: dict[str, Any], - comment: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> dict[str, Any]: - """Create a new revision snapshot of the current integration connector. - - Use this method to save a stable configuration before making experimental - changes. Only custom connectors can be versioned. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the connector belongs to. - connector_id: ID of the connector to create a revision for. - connector: Dict containing the IntegrationConnector to snapshot. - comment: Comment describing the revision. Maximum 400 characters. - Optional. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing the newly created ConnectorRevision resource. - - Raises: - APIError: If the API request fails. - """ - body = {"connector": connector} - - if comment is not None: - body["comment"] = comment - - return chronicle_request( - client, - method="POST", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"connectors/{connector_id}/revisions" - ), - api_version=api_version, - json=body, - ) - - -def rollback_integration_connector_revision( - client: "ChronicleClient", - integration_name: str, - connector_id: str, - revision_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> dict[str, Any]: - """Revert the current connector definition to a previously saved revision. - - Use this method to quickly revert to a known good configuration if an - investigation or update is unsuccessful. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the connector belongs to. - connector_id: ID of the connector to rollback. - revision_id: ID of the revision to rollback to. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing the ConnectorRevision rolled back to. - - Raises: - APIError: If the API request fails. - """ - return chronicle_request( - client, - method="POST", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"connectors/{connector_id}/revisions/{revision_id}:rollback" - ), - api_version=api_version, - ) diff --git a/src/secops/chronicle/integration/connectors.py b/src/secops/chronicle/integration/connectors.py deleted file mode 100644 index b2c0ccd1..00000000 --- a/src/secops/chronicle/integration/connectors.py +++ /dev/null @@ -1,405 +0,0 @@ -# Copyright 2025 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. -# -"""Integration connectors functionality for Chronicle.""" - -from typing import Any, TYPE_CHECKING - -from secops.chronicle.models import ( - APIVersion, - ConnectorParameter, - ConnectorRule, -) -from secops.chronicle.utils.format_utils import ( - format_resource_id, - build_patch_body, -) -from secops.chronicle.utils.request_utils import ( - chronicle_paginated_request, - chronicle_request, -) - -if TYPE_CHECKING: - from secops.chronicle.client import ChronicleClient - - -def list_integration_connectors( - client: "ChronicleClient", - integration_name: str, - page_size: int | None = None, - page_token: str | None = None, - filter_string: str | None = None, - order_by: str | None = None, - exclude_staging: bool | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - as_list: bool = False, -) -> dict[str, Any] | list[dict[str, Any]]: - """List all connectors defined for a specific integration. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration to list connectors for. - page_size: Maximum number of connectors to return. Defaults to 50, - maximum is 1000. - page_token: Page token from a previous call to retrieve the next page. - filter_string: Filter expression to filter connectors. - order_by: Field to sort the connectors by. - exclude_staging: Whether to exclude staging connectors from the - response. By default, staging connectors are included. - api_version: API version to use for the request. Default is V1BETA. - as_list: If True, return a list of connectors instead of a dict with - connectors list and nextPageToken. - - Returns: - If as_list is True: List of connectors. - If as_list is False: Dict with connectors list and nextPageToken. - - Raises: - APIError: If the API request fails. - """ - extra_params = { - "filter": filter_string, - "orderBy": order_by, - "excludeStaging": exclude_staging, - } - - # Remove keys with None values - extra_params = {k: v for k, v in extra_params.items() if v is not None} - - return chronicle_paginated_request( - client, - api_version=api_version, - path=f"integrations/{format_resource_id(integration_name)}/connectors", - items_key="connectors", - page_size=page_size, - page_token=page_token, - extra_params=extra_params, - as_list=as_list, - ) - - -def get_integration_connector( - client: "ChronicleClient", - integration_name: str, - connector_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> dict[str, Any]: - """Get a single connector for a given integration. - - Use this method to retrieve the Python script, configuration parameters, - and field mapping logic for a specific connector. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the connector belongs to. - connector_id: ID of the connector to retrieve. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing details of the specified IntegrationConnector. - - Raises: - APIError: If the API request fails. - """ - return chronicle_request( - client, - method="GET", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"connectors/{connector_id}" - ), - api_version=api_version, - ) - - -def delete_integration_connector( - client: "ChronicleClient", - integration_name: str, - connector_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> None: - """Delete a specific custom connector from a given integration. - - Only custom connectors can be deleted; commercial connectors are - immutable. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the connector belongs to. - connector_id: ID of the connector to delete. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - None - - Raises: - APIError: If the API request fails. - """ - chronicle_request( - client, - method="DELETE", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"connectors/{connector_id}" - ), - api_version=api_version, - ) - - -def create_integration_connector( - client: "ChronicleClient", - integration_name: str, - display_name: str, - script: str, - timeout_seconds: int, - enabled: bool, - product_field_name: str, - event_field_name: str, - description: str | None = None, - parameters: list[dict[str, Any] | ConnectorParameter] | None = None, - rules: list[dict[str, Any] | ConnectorRule] | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> dict[str, Any]: - """Create a new custom connector for a given integration. - - Use this method to define how to fetch and parse alerts from a unique or - unofficial data source. Each connector must have a unique display name - and a functional Python script. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration to create the connector for. - display_name: Connector's display name. Required. - script: Connector's Python script. Required. - timeout_seconds: Timeout in seconds for a single script run. Required. - enabled: Whether the connector is enabled or disabled. Required. - product_field_name: Field name used to determine the device product. - Required. - event_field_name: Field name used to determine the event name - (sub-type). Required. - description: Connector's description. Optional. - parameters: List of ConnectorParameter instances or dicts. Optional. - rules: List of ConnectorRule instances or dicts. Optional. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing the newly created IntegrationConnector resource. - - Raises: - APIError: If the API request fails. - """ - resolved_parameters = ( - [ - p.to_dict() if isinstance(p, ConnectorParameter) else p - for p in parameters - ] - if parameters is not None - else None - ) - resolved_rules = ( - [r.to_dict() if isinstance(r, ConnectorRule) else r for r in rules] - if rules is not None - else None - ) - - body = { - "displayName": display_name, - "script": script, - "timeoutSeconds": timeout_seconds, - "enabled": enabled, - "productFieldName": product_field_name, - "eventFieldName": event_field_name, - "description": description, - "parameters": resolved_parameters, - "rules": resolved_rules, - } - - # Remove keys with None values - body = {k: v for k, v in body.items() if v is not None} - - return chronicle_request( - client, - method="POST", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"connectors" - ), - api_version=api_version, - json=body, - ) - - -def update_integration_connector( - client: "ChronicleClient", - integration_name: str, - connector_id: str, - display_name: str | None = None, - script: str | None = None, - timeout_seconds: int | None = None, - enabled: bool | None = None, - product_field_name: str | None = None, - event_field_name: str | None = None, - description: str | None = None, - parameters: list[dict[str, Any] | ConnectorParameter] | None = None, - rules: list[dict[str, Any] | ConnectorRule] | None = None, - update_mask: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> dict[str, Any]: - """Update an existing custom connector for a given integration. - - Only custom connectors can be updated; commercial connectors are - immutable. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the connector belongs to. - connector_id: ID of the connector to update. - display_name: Connector's display name. - script: Connector's Python script. - timeout_seconds: Timeout in seconds for a single script run. - enabled: Whether the connector is enabled or disabled. - product_field_name: Field name used to determine the device product. - event_field_name: Field name used to determine the event name - (sub-type). - description: Connector's description. - parameters: List of ConnectorParameter instances or dicts. - rules: List of ConnectorRule instances or dicts. - update_mask: Comma-separated list of fields to update. If omitted, - the mask is auto-generated from whichever fields are provided. - Example: "displayName,script". - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing the updated IntegrationConnector resource. - - Raises: - APIError: If the API request fails. - """ - resolved_parameters = ( - [ - p.to_dict() if isinstance(p, ConnectorParameter) else p - for p in parameters - ] - if parameters is not None - else None - ) - resolved_rules = ( - [r.to_dict() if isinstance(r, ConnectorRule) else r for r in rules] - if rules is not None - else None - ) - - body, params = build_patch_body( - field_map=[ - ("displayName", "displayName", display_name), - ("script", "script", script), - ("timeoutSeconds", "timeoutSeconds", timeout_seconds), - ("enabled", "enabled", enabled), - ("productFieldName", "productFieldName", product_field_name), - ("eventFieldName", "eventFieldName", event_field_name), - ("description", "description", description), - ("parameters", "parameters", resolved_parameters), - ("rules", "rules", resolved_rules), - ], - update_mask=update_mask, - ) - - return chronicle_request( - client, - method="PATCH", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"connectors/{connector_id}" - ), - api_version=api_version, - json=body, - params=params, - ) - - -def execute_integration_connector_test( - client: "ChronicleClient", - integration_name: str, - connector: dict[str, Any], - agent_identifier: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> dict[str, Any]: - """Execute a test run of a connector's Python script. - - Use this method to verify data fetching logic, authentication, and parsing - logic before enabling the connector for production ingestion. The full - connector object is required as the test can be run without saving the - connector first. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the connector belongs to. - connector: Dict containing the IntegrationConnector to test. - agent_identifier: Agent identifier for remote testing. Optional. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing the test execution results with the following fields: - - outputMessage: Human-readable output message set by the script. - - debugOutputMessage: The script debug output. - - resultJson: The result JSON if it exists (optional). - - Raises: - APIError: If the API request fails. - """ - body = {"connector": connector} - - if agent_identifier is not None: - body["agentIdentifier"] = agent_identifier - - return chronicle_request( - client, - method="POST", - endpoint_path=f"integrations/{format_resource_id(integration_name)}" - f"/connectors:executeTest", - api_version=api_version, - json=body, - ) - - -def get_integration_connector_template( - client: "ChronicleClient", - integration_name: str, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> dict[str, Any]: - """Retrieve a default Python script template for a - new integration connector. - - Use this method to rapidly initialize the development of a new connector. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration to fetch the template for. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing the IntegrationConnector template. - - Raises: - APIError: If the API request fails. - """ - return chronicle_request( - client, - method="GET", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"connectors:fetchTemplate" - ), - api_version=api_version, - ) diff --git a/src/secops/chronicle/integration/integration_instances.py b/src/secops/chronicle/integration/integration_instances.py deleted file mode 100644 index c7e88dd7..00000000 --- a/src/secops/chronicle/integration/integration_instances.py +++ /dev/null @@ -1,403 +0,0 @@ -# Copyright 2025 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. -# -"""Integration instances functionality for Chronicle.""" - -from typing import Any, TYPE_CHECKING - -from secops.chronicle.models import APIVersion, IntegrationInstanceParameter -from secops.chronicle.utils.format_utils import ( - format_resource_id, - build_patch_body, -) -from secops.chronicle.utils.request_utils import ( - chronicle_paginated_request, - chronicle_request, -) - -if TYPE_CHECKING: - from secops.chronicle.client import ChronicleClient - - -def list_integration_instances( - client: "ChronicleClient", - integration_name: str, - page_size: int | None = None, - page_token: str | None = None, - filter_string: str | None = None, - order_by: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - as_list: bool = False, -) -> dict[str, Any] | list[dict[str, Any]]: - """List all instances for a specific integration. - - Use this method to browse the configured integration instances available - for a custom or third-party product across different environments. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration to list instances for. - page_size: Maximum number of integration instances to return. - page_token: Page token from a previous call to retrieve the next page. - filter_string: Filter expression to filter integration instances. - order_by: Field to sort the integration instances by. - api_version: API version to use for the request. Default is V1BETA. - as_list: If True, return a list of integration instances instead of a - dict with integration instances list and nextPageToken. - - Returns: - If as_list is True: List of integration instances. - If as_list is False: Dict with integration instances list and - nextPageToken. - - Raises: - APIError: If the API request fails. - """ - extra_params = { - "filter": filter_string, - "orderBy": order_by, - } - - # Remove keys with None values - extra_params = {k: v for k, v in extra_params.items() if v is not None} - - return chronicle_paginated_request( - client, - api_version=api_version, - path=( - f"integrations/{format_resource_id(integration_name)}/" - f"integrationInstances" - ), - items_key="integrationInstances", - page_size=page_size, - page_token=page_token, - extra_params=extra_params, - as_list=as_list, - ) - - -def get_integration_instance( - client: "ChronicleClient", - integration_name: str, - integration_instance_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> dict[str, Any]: - """Get a single instance for a specific integration. - - Use this method to retrieve the specific configuration, connection status, - and environment mapping for an active integration. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the instance belongs to. - integration_instance_id: ID of the integration instance to retrieve. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing details of the specified IntegrationInstance. - - Raises: - APIError: If the API request fails. - """ - return chronicle_request( - client, - method="GET", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"integrationInstances/{integration_instance_id}" - ), - api_version=api_version, - ) - - -def delete_integration_instance( - client: "ChronicleClient", - integration_name: str, - integration_instance_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> None: - """Delete a specific integration instance. - - Use this method to permanently remove an integration instance and stop all - associated automated tasks (connectors or jobs) using this instance. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the instance belongs to. - integration_instance_id: ID of the integration instance to delete. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - None - - Raises: - APIError: If the API request fails. - """ - chronicle_request( - client, - method="DELETE", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"integrationInstances/{integration_instance_id}" - ), - api_version=api_version, - ) - - -def create_integration_instance( - client: "ChronicleClient", - integration_name: str, - environment: str, - display_name: str | None = None, - description: str | None = None, - parameters: ( - list[dict[str, Any] | IntegrationInstanceParameter] | None - ) = None, - agent: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> dict[str, Any]: - """Create a new integration instance for a specific integration. - - Use this method to establish a new integration instance to a custom or - third-party security product for a specific environment. All mandatory - parameters required by the integration definition must be provided. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration to create the instance for. - environment: The integration instance environment. Required. - display_name: The display name of the integration instance. - Automatically generated if not provided. Maximum 110 characters. - description: The integration instance description. Maximum 1500 - characters. - parameters: List of IntegrationInstanceParameter instances or dicts. - agent: Agent identifier for a remote integration instance. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing the newly created IntegrationInstance resource. - - Raises: - APIError: If the API request fails. - """ - resolved_parameters = ( - [ - p.to_dict() if isinstance(p, IntegrationInstanceParameter) else p - for p in parameters - ] - if parameters is not None - else None - ) - - body = { - "environment": environment, - "displayName": display_name, - "description": description, - "parameters": resolved_parameters, - "agent": agent, - } - - # Remove keys with None values - body = {k: v for k, v in body.items() if v is not None} - - return chronicle_request( - client, - method="POST", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"integrationInstances" - ), - api_version=api_version, - json=body, - ) - - -def update_integration_instance( - client: "ChronicleClient", - integration_name: str, - integration_instance_id: str, - environment: str | None = None, - display_name: str | None = None, - description: str | None = None, - parameters: ( - list[dict[str, Any] | IntegrationInstanceParameter] | None - ) = None, - agent: str | None = None, - update_mask: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> dict[str, Any]: - """Update an existing integration instance. - - Use this method to modify connection parameters (e.g., rotate an API - key), change the display name, or update the description of a configured - integration instance. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the instance belongs to. - integration_instance_id: ID of the integration instance to update. - environment: The integration instance environment. - display_name: The display name of the integration instance. Maximum - 110 characters. - description: The integration instance description. Maximum 1500 - characters. - parameters: List of IntegrationInstanceParameter instances or dicts. - agent: Agent identifier for a remote integration instance. - update_mask: Comma-separated list of fields to update. If omitted, - the mask is auto-generated from whichever fields are provided. - Example: "displayName,description". - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing the updated IntegrationInstance resource. - - Raises: - APIError: If the API request fails. - """ - resolved_parameters = ( - [ - p.to_dict() if isinstance(p, IntegrationInstanceParameter) else p - for p in parameters - ] - if parameters is not None - else None - ) - - body, params = build_patch_body( - field_map=[ - ("environment", "environment", environment), - ("displayName", "displayName", display_name), - ("description", "description", description), - ("parameters", "parameters", resolved_parameters), - ("agent", "agent", agent), - ], - update_mask=update_mask, - ) - - return chronicle_request( - client, - method="PATCH", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"integrationInstances/{integration_instance_id}" - ), - api_version=api_version, - json=body, - params=params, - ) - - -def execute_integration_instance_test( - client: "ChronicleClient", - integration_name: str, - integration_instance_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> dict[str, Any]: - """Execute a connectivity test for a specific integration instance. - - Use this method to verify that SecOps can successfully communicate with - the third-party security product using the provided credentials. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the instance belongs to. - integration_instance_id: ID of the integration instance to test. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing the test results with the following fields: - - successful: Indicates if the test was successful. - - message: Test result message (optional). - - Raises: - APIError: If the API request fails. - """ - return chronicle_request( - client, - method="POST", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"integrationInstances/{integration_instance_id}:executeTest" - ), - api_version=api_version, - ) - - -def get_integration_instance_affected_items( - client: "ChronicleClient", - integration_name: str, - integration_instance_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> dict[str, Any]: - """List all playbooks that depend on a specific integration instance. - - Use this method to perform impact analysis before deleting or - significantly changing a connection configuration. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the instance belongs to. - integration_instance_id: ID of the integration instance to fetch - affected items for. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing a list of AffectedPlaybookResponse objects that - depend on the specified integration instance. - - Raises: - APIError: If the API request fails. - """ - return chronicle_request( - client, - method="GET", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"integrationInstances/{integration_instance_id}:fetchAffectedItems" - ), - api_version=api_version, - ) - - -def get_default_integration_instance( - client: "ChronicleClient", - integration_name: str, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> dict[str, Any]: - """Get the system default configuration for a specific integration. - - Use this method to retrieve the baseline integration instance details - provided for a commercial product. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration to fetch the default - instance for. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing the default IntegrationInstance resource. - - Raises: - APIError: If the API request fails. - """ - return chronicle_request( - client, - method="GET", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"integrationInstances:fetchDefaultInstance" - ), - api_version=api_version, - ) diff --git a/src/secops/chronicle/integration/integrations.py b/src/secops/chronicle/integration/integrations.py deleted file mode 100644 index 4f72f5ea..00000000 --- a/src/secops/chronicle/integration/integrations.py +++ /dev/null @@ -1,686 +0,0 @@ -# Copyright 2025 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. -# -"""Integrations functionality for Chronicle.""" - -from typing import Any, TYPE_CHECKING - -from secops.chronicle.models import ( - APIVersion, - DiffType, - IntegrationParam, - TargetMode, - PythonVersion, - IntegrationType, -) - -from secops.chronicle.utils.format_utils import build_patch_body -from secops.chronicle.utils.request_utils import ( - chronicle_paginated_request, - chronicle_request_bytes, - chronicle_request, -) - -if TYPE_CHECKING: - from secops.chronicle.client import ChronicleClient - - -def list_integrations( - client: "ChronicleClient", - page_size: int | None = None, - page_token: str | None = None, - filter_string: str | None = None, - order_by: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - as_list: bool = False, -) -> dict[str, Any] | list[dict[str, Any]]: - """Get a list of integrations. - - Args: - client: ChronicleClient instance - page_size: Number of results to return per page - page_token: Token for the page to retrieve - filter_string: Filter expression to filter integrations - order_by: Field to sort the integrations by - api_version: API version to use for the request. Default is V1BETA. - as_list: If True, return a list of integrations instead - of a dict with integrations list and nextPageToken. - - Returns: - If as_list is True: List of integrations. - If as_list is False: Dict with integrations list and - nextPageToken. - - Raises: - APIError: If the API request fails - """ - param_fields = { - "filter": filter_string, - "orderBy": order_by, - } - - # Remove keys with None values - param_fields = {k: v for k, v in param_fields.items() if v is not None} - - return chronicle_paginated_request( - client, - api_version=api_version, - path="integrations", - items_key="integrations", - page_size=page_size, - page_token=page_token, - extra_params=param_fields, - as_list=as_list, - ) - - -def get_integration( - client: "ChronicleClient", - integration_name: str, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> dict[str, Any]: - """Get details of a specific integration. - - Args: - client: ChronicleClient instance - integration_name: name of the integration to retrieve - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing details of the specified integration - - Raises: - APIError: If the API request fails - """ - return chronicle_request( - client, - method="GET", - endpoint_path=f"integrations/{integration_name}", - api_version=api_version, - ) - - -def delete_integration( - client: "ChronicleClient", - integration_name: str, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> None: - """Deletes a specific custom Integration. Commercial integrations cannot - be deleted via this method. - - Args: - client: ChronicleClient instance - integration_name: name of the integration to delete - api_version: API version to use for the request. Default is V1BETA. - - Raises: - APIError: If the API request fails - """ - chronicle_request( - client, - method="DELETE", - endpoint_path=f"integrations/{integration_name}", - api_version=api_version, - ) - - -def create_integration( - client: "ChronicleClient", - display_name: str, - staging: bool, - description: str | None = None, - image_base64: str | None = None, - svg_icon: str | None = None, - python_version: PythonVersion | None = None, - parameters: list[IntegrationParam | dict[str, Any]] | None = None, - categories: list[str] | None = None, - integration_type: IntegrationType | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> dict[str, Any]: - """Creates a new custom SOAR Integration. - - Args: - client: ChronicleClient instance - display_name: Required. The display name of the integration - (max 150 characters) - staging: Required. True if the integration is in staging mode - description: Optional. The integration's description - (max 1,500 characters) - image_base64: Optional. The integration's image encoded as - a base64 string (max 5 MB) - svg_icon: Optional. The integration's SVG icon (max 1 MB) - python_version: Optional. The integration's Python version - parameters: Optional. Integration parameters (max 50). Each entry may - be an IntegrationParam dataclass instance or a plain dict with - keys: id, defaultValue, displayName, propertyName, type, - description, mandatory. - categories: Optional. Integration categories (max 50) - integration_type: Optional. The integration's type (response/extension) - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing the details of the newly created integration - - Raises: - APIError: If the API request fails - """ - serialised_params: list[dict[str, Any]] | None = None - if parameters is not None: - serialised_params = [ - p.to_dict() if isinstance(p, IntegrationParam) else p - for p in parameters - ] - - body_fields = { - "displayName": display_name, - "staging": staging, - "description": description, - "imageBase64": image_base64, - "svgIcon": svg_icon, - "pythonVersion": python_version, - "parameters": serialised_params, - "categories": categories, - "type": integration_type, - } - - # Remove keys with None values - body_fields = {k: v for k, v in body_fields.items() if v is not None} - - return chronicle_request( - client, - method="POST", - endpoint_path="integrations", - json=body_fields, - api_version=api_version, - ) - - -def download_integration( - client: "ChronicleClient", - integration_name: str, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> bytes: - """Exports the entire integration package as a ZIP file. Includes all - scripts, definitions, and the manifest file. Use this method for backup - or sharing. - - Args: - client: ChronicleClient instance - integration_name: name of the integration to download - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Bytes of the ZIP file containing the integration package - - Raises: - APIError: If the API request fails - """ - return chronicle_request_bytes( - client, - method="GET", - endpoint_path=f"integrations/{integration_name}:export", - api_version=api_version, - params={"alt": "media"}, - headers={"Accept": "application/zip"}, - ) - - -def download_integration_dependency( - client: "ChronicleClient", - integration_name: str, - dependency_name: str, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> dict[str, Any]: - """Initiates the download of a Python dependency (e.g., a library from - PyPI) for a custom integration. - - Args: - client: ChronicleClient instance - integration_name: name of the integration whose dependency to download - dependency_name: The dependency name to download. It can contain the - version or the repository. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Empty dict if the download was successful, or a dict containing error - details if the download failed - - Raises: - APIError: If the API request fails - """ - return chronicle_request( - client, - method="POST", - endpoint_path=f"integrations/{integration_name}:downloadDependency", - json={"dependency": dependency_name}, - api_version=api_version, - ) - - -def export_integration_items( - client: "ChronicleClient", - integration_name: str, - actions: list[str] | None = None, - jobs: list[str] | None = None, - connectors: list[str] | None = None, - managers: list[str] | None = None, - transformers: list[str] | None = None, - logical_operators: list[str] | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> bytes: - """Exports specific items from an integration into a ZIP folder. Use - this method to extract only a subset of capabilities (e.g., just the - connectors) for reuse. - - Args: - client: ChronicleClient instance - integration_name: name of the integration to export items from - actions: Optional. A list the ids of the actions to export. Format: - [1,2,3] - jobs: Optional. A list the ids of the jobs to export. Format: - [1,2,3] - connectors: Optional. A list the ids of the connectors to export. - Format: [1,2,3] - managers: Optional. A list the ids of the managers to export. Format: - [1,2,3] - transformers: Optional. A list the ids of the transformers to export. - Format: [1,2,3] - logical_operators: Optional. A list the ids of the logical - operators to export. Format: [1,2,3] - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Bytes of the ZIP file containing the exported integration items - - Raises: - APIError: If the API request fails - """ - export_items = { - "actions": ",".join(actions) if actions else None, - "jobs": jobs, - "connectors": connectors, - "managers": managers, - "transformers": transformers, - "logicalOperators": logical_operators, - "alt": "media", - } - - # Remove keys with None values - export_items = {k: v for k, v in export_items.items() if v is not None} - - return chronicle_request_bytes( - client, - method="GET", - endpoint_path=f"integrations/{integration_name}:exportItems", - params=export_items, - api_version=api_version, - headers={"Accept": "application/zip"}, - ) - - -def get_integration_affected_items( - client: "ChronicleClient", - integration_name: str, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> dict[str, Any]: - """Identifies all system items (e.g., connector instances, job instances, - playbooks) that would be affected by a change to or deletion of this - integration. Use this method to conduct impact analysis before making - breaking changes. - - Args: - client: ChronicleClient instance - integration_name: name of the integration to check for affected items - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing the list of items affected by changes to the specified - integration - - Raises: - APIError: If the API request fails - """ - return chronicle_request( - client, - method="GET", - endpoint_path=f"integrations/{integration_name}:fetchAffectedItems", - api_version=api_version, - ) - - -def get_agent_integrations( - client: "ChronicleClient", - agent_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> dict[str, Any]: - """Returns the set of integrations currently installed and configured on - a specific agent. - - Args: - client: ChronicleClient instance - agent_id: The agent identifier - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing the list of agent-based integrations - - Raises: - APIError: If the API request fails - """ - return chronicle_request( - client, - method="GET", - endpoint_path="integrations:fetchAgentIntegrations", - params={"agentId": agent_id}, - api_version=api_version, - ) - - -def get_integration_dependencies( - client: "ChronicleClient", - integration_name: str, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> dict[str, Any]: - """Returns the complete list of Python dependencies currently associated - with a custom integration. - - Args: - client: ChronicleClient instance - integration_name: name of the integration to check for dependencies - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing the list of dependencies for the specified integration - - Raises: - APIError: If the API request fails - """ - return chronicle_request( - client, - method="GET", - endpoint_path=f"integrations/{integration_name}:fetchDependencies", - api_version=api_version, - ) - - -def get_integration_restricted_agents( - client: "ChronicleClient", - integration_name: str, - required_python_version: PythonVersion, - push_request: bool = False, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> dict[str, Any]: - """Identifies remote agents that would be restricted from running an - updated version of the integration, typically due to environment - incompatibilities like unsupported Python versions. - - Args: - client: ChronicleClient instance - integration_name: name of the integration to check for restricted agents - required_python_version: Python version required for the updated - integration. - push_request: Optional. Indicates whether the integration is - pushed to a different mode (production/staging). False by default. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing the list of agents that would be restricted from running - - Raises: - APIError: If the API request fails - """ - params_fields = { - "requiredPythonVersion": required_python_version.value, - "pushRequest": push_request, - } - - # Remove keys with None values - params_fields = {k: v for k, v in params_fields.items() if v is not None} - - return chronicle_request( - client, - method="GET", - endpoint_path=f"integrations/{integration_name}:fetchRestrictedAgents", - params=params_fields, - api_version=api_version, - ) - - -def get_integration_diff( - client: "ChronicleClient", - integration_name: str, - diff_type: DiffType = DiffType.COMMERCIAL, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> dict[str, Any]: - """Get the configuration diff of a specific integration. - - Args: - client: ChronicleClient instance - integration_name: ID of the integration to retrieve the diff for - diff_type: Type of diff to retrieve - (Commercial, Production, or Staging). Default is Commercial. - COMMERCIAL: Diff between the commercial version of the - integration and the current version in the environment. - PRODUCTION: Returns the difference between the staging - integration and its matching production version. - STAGING: Returns the difference between the production - integration and its corresponding staging version. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing the configuration diff of the specified integration - - Raises: - APIError: If the API request fails - """ - return chronicle_request( - client, - method="GET", - endpoint_path=f"integrations/{integration_name}" - f":fetch{diff_type.value}Diff", - api_version=api_version, - ) - - -def transition_integration( - client: "ChronicleClient", - integration_name: str, - target_mode: TargetMode, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> dict[str, Any]: - """Transition an integration to a different environment - (e.g. staging to production). - - Args: - client: ChronicleClient instance - integration_name: ID of the integration to transition - target_mode: Target mode to transition the integration to: - PRODUCTION: Transition the integration to production environment. - STAGING: Transition the integration to staging environment. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing the details of the transitioned integration - - Raises: - APIError: If the API request fails - """ - return chronicle_request( - client, - method="POST", - endpoint_path=f"integrations/{integration_name}" - f":pushTo{target_mode.value}", - api_version=api_version, - ) - - -def update_integration( - client: "ChronicleClient", - integration_name: str, - display_name: str | None = None, - description: str | None = None, - image_base64: str | None = None, - svg_icon: str | None = None, - python_version: PythonVersion | None = None, - parameters: list[dict[str, Any]] | None = None, - categories: list[str] | None = None, - integration_type: IntegrationType | None = None, - staging: bool | None = None, - dependencies_to_remove: list[str] | None = None, - update_mask: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> dict[str, Any]: - """Update an existing integration. - - Args: - client: ChronicleClient instance - integration_name: ID of the integration to update - display_name: Optional. The display name of the integration - (max 150 characters) - description: Optional. The integration's description - (max 1,500 characters) - image_base64: Optional. The integration's image encoded as a - base64 string (max 5 MB) - svg_icon: Optional. The integration's SVG icon (max 1 MB) - python_version: Optional. The integration's Python version - parameters: Optional. Integration parameters (max 50) - categories: Optional. Integration categories (max 50) - integration_type: Optional. The integration's type (response/extension) - staging: Optional. True if the integration is in staging mode - dependencies_to_remove: Optional. List of dependencies to - remove from the integration. - update_mask: Optional. Comma-separated list of fields to update. - If not provided, all non-None fields will be updated. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing the details of the updated integration - - Raises: - APIError: If the API request fails - """ - body, params = build_patch_body( - field_map=[ - ("displayName", "display_name", display_name), - ("description", "description", description), - ("imageBase64", "image_base64", image_base64), - ("svgIcon", "svg_icon", svg_icon), - ("pythonVersion", "python_version", python_version), - ("parameters", "parameters", parameters), - ("categories", "categories", categories), - ("integrationType", "integration_type", integration_type), - ("staging", "staging", staging), - ], - update_mask=update_mask, - ) - - if dependencies_to_remove is not None: - params = params or {} - params["dependenciesToRemove"] = ",".join(dependencies_to_remove) - - return chronicle_request( - client, - method="PATCH", - endpoint_path=f"integrations/{integration_name}", - json=body, - params=params, - api_version=api_version, - ) - - -def update_custom_integration( - client: "ChronicleClient", - integration_name: str, - display_name: str | None = None, - description: str | None = None, - image_base64: str | None = None, - svg_icon: str | None = None, - python_version: PythonVersion | None = None, - parameters: list[dict[str, Any]] | None = None, - categories: list[str] | None = None, - integration_type: IntegrationType | None = None, - staging: bool | None = None, - dependencies_to_remove: list[str] | None = None, - update_mask: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> dict[str, Any]: - """Updates a custom integration definition, including its parameters and - dependencies. Use this method to refine the operational behavior of a - locally developed integration. - - Args: - client: ChronicleClient instance - integration_name: Name of the integration to update - display_name: Optional. The display name of the integration - (max 150 characters) - description: Optional. The integration's description - (max 1,500 characters) - image_base64: Optional. The integration's image encoded as a - base64 string (max 5 MB) - svg_icon: Optional. The integration's SVG icon (max 1 MB) - python_version: Optional. The integration's Python version - parameters: Optional. Integration parameters (max 50) - categories: Optional. Integration categories (max 50) - integration_type: Optional. The integration's type (response/extension) - staging: Optional. True if the integration is in staging mode - dependencies_to_remove: Optional. List of dependencies to remove from - the integration - update_mask: Optional. Comma-separated list of fields to update. - If not provided, all non-None fields will be updated. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing: - - successful: Whether the integration was updated successfully - - integration: The updated integration (populated if successful) - - dependencies: Dependency installation statuses - (populated if failed) - - Raises: - APIError: If the API request fails - """ - integration_fields = { - "name": integration_name, - "displayName": display_name, - "description": description, - "imageBase64": image_base64, - "svgIcon": svg_icon, - "pythonVersion": python_version, - "parameters": parameters, - "categories": categories, - "type": integration_type, - "staging": staging, - } - - # Remove keys with None values - integration_fields = { - k: v for k, v in integration_fields.items() if v is not None - } - - body = {"integration": integration_fields} - - if dependencies_to_remove is not None: - body["dependenciesToRemove"] = dependencies_to_remove - - params = {"updateMask": update_mask} if update_mask else None - - return chronicle_request( - client, - method="POST", - endpoint_path=f"integrations/" - f"{integration_name}:updateCustomIntegration", - json=body, - params=params, - api_version=api_version, - ) diff --git a/src/secops/chronicle/integration/job_context_properties.py b/src/secops/chronicle/integration/job_context_properties.py deleted file mode 100644 index de40a6f8..00000000 --- a/src/secops/chronicle/integration/job_context_properties.py +++ /dev/null @@ -1,298 +0,0 @@ -# Copyright 2025 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. -# -"""Integration job context property functionality for Chronicle.""" - -from typing import Any, TYPE_CHECKING - -from secops.chronicle.models import APIVersion -from secops.chronicle.utils.format_utils import ( - format_resource_id, - build_patch_body, -) -from secops.chronicle.utils.request_utils import ( - chronicle_paginated_request, - chronicle_request, -) - -if TYPE_CHECKING: - from secops.chronicle.client import ChronicleClient - - -def list_job_context_properties( - client: "ChronicleClient", - integration_name: str, - job_id: str, - page_size: int | None = None, - page_token: str | None = None, - filter_string: str | None = None, - order_by: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - as_list: bool = False, -) -> dict[str, Any] | list[dict[str, Any]]: - """List all context properties for a specific integration job. - - Use this method to discover all custom data points associated with a job. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the job belongs to. - job_id: ID of the job to list context properties for. - page_size: Maximum number of context properties to return. - page_token: Page token from a previous call to retrieve the next page. - filter_string: Filter expression to filter context properties. - order_by: Field to sort the context properties by. - api_version: API version to use for the request. Default is V1BETA. - as_list: If True, return a list of context properties instead of a - dict with context properties list and nextPageToken. - - Returns: - If as_list is True: List of context properties. - If as_list is False: Dict with context properties list and - nextPageToken. - - Raises: - APIError: If the API request fails. - """ - extra_params = { - "filter": filter_string, - "orderBy": order_by, - } - - # Remove keys with None values - extra_params = {k: v for k, v in extra_params.items() if v is not None} - - return chronicle_paginated_request( - client, - api_version=api_version, - path=( - f"integrations/{format_resource_id(integration_name)}/" - f"jobs/{job_id}/contextProperties" - ), - items_key="contextProperties", - page_size=page_size, - page_token=page_token, - extra_params=extra_params, - as_list=as_list, - ) - - -def get_job_context_property( - client: "ChronicleClient", - integration_name: str, - job_id: str, - context_property_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> dict[str, Any]: - """Get a single context property for a specific integration job. - - Use this method to retrieve the value of a specific key within a job's - context. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the job belongs to. - job_id: ID of the job the context property belongs to. - context_property_id: ID of the context property to retrieve. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing details of the specified ContextProperty. - - Raises: - APIError: If the API request fails. - """ - return chronicle_request( - client, - method="GET", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"jobs/{job_id}/contextProperties/{context_property_id}" - ), - api_version=api_version, - ) - - -def delete_job_context_property( - client: "ChronicleClient", - integration_name: str, - job_id: str, - context_property_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> None: - """Delete a specific context property for a given integration job. - - Use this method to remove a custom data point that is no longer relevant - to the job's context. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the job belongs to. - job_id: ID of the job the context property belongs to. - context_property_id: ID of the context property to delete. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - None - - Raises: - APIError: If the API request fails. - """ - chronicle_request( - client, - method="DELETE", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"jobs/{job_id}/contextProperties/{context_property_id}" - ), - api_version=api_version, - ) - - -def create_job_context_property( - client: "ChronicleClient", - integration_name: str, - job_id: str, - value: str, - key: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> dict[str, Any]: - """Create a new context property for a specific integration job. - - Use this method to attach custom data to a job's context. Property keys - must be unique within their context. Key values must be 4-63 characters - and match /[a-z][0-9]-/. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the job belongs to. - job_id: ID of the job to create the context property for. - value: The property value. Required. - key: The context property ID to use. Must be 4-63 characters and - match /[a-z][0-9]-/. Optional. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing the newly created ContextProperty resource. - - Raises: - APIError: If the API request fails. - """ - body = {"value": value} - - if key is not None: - body["key"] = key - - return chronicle_request( - client, - method="POST", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"jobs/{job_id}/contextProperties" - ), - api_version=api_version, - json=body, - ) - - -def update_job_context_property( - client: "ChronicleClient", - integration_name: str, - job_id: str, - context_property_id: str, - value: str, - update_mask: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> dict[str, Any]: - """Update an existing context property for a given integration job. - - Use this method to modify the value of a previously saved key. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the job belongs to. - job_id: ID of the job the context property belongs to. - context_property_id: ID of the context property to update. - value: The new property value. Required. - update_mask: Comma-separated list of fields to update. Only "value" - is supported. If omitted, defaults to "value". - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing the updated ContextProperty resource. - - Raises: - APIError: If the API request fails. - """ - body, params = build_patch_body( - field_map=[ - ("value", "value", value), - ], - update_mask=update_mask, - ) - - return chronicle_request( - client, - method="PATCH", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"jobs/{job_id}/contextProperties/{context_property_id}" - ), - api_version=api_version, - json=body, - params=params, - ) - - -def delete_all_job_context_properties( - client: "ChronicleClient", - integration_name: str, - job_id: str, - context_id: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> None: - """Delete all context properties for a specific integration job. - - Use this method to quickly clear all supplemental data from a job's - context. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the job belongs to. - job_id: ID of the job to clear context properties from. - context_id: The context ID to remove context properties from. Must be - 4-63 characters and match /[a-z][0-9]-/. Optional. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - None - - Raises: - APIError: If the API request fails. - """ - body = {} - - if context_id is not None: - body["contextId"] = context_id - - chronicle_request( - client, - method="POST", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"jobs/{job_id}/contextProperties:clearAll" - ), - api_version=api_version, - json=body, - ) diff --git a/src/secops/chronicle/integration/job_instance_logs.py b/src/secops/chronicle/integration/job_instance_logs.py deleted file mode 100644 index f58d568f..00000000 --- a/src/secops/chronicle/integration/job_instance_logs.py +++ /dev/null @@ -1,125 +0,0 @@ -# Copyright 2025 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. -# -"""Integration job instances functionality for Chronicle.""" - -from typing import Any, TYPE_CHECKING - -from secops.chronicle.models import APIVersion -from secops.chronicle.utils.format_utils import format_resource_id -from secops.chronicle.utils.request_utils import ( - chronicle_paginated_request, - chronicle_request, -) - -if TYPE_CHECKING: - from secops.chronicle.client import ChronicleClient - - -def list_job_instance_logs( - client: "ChronicleClient", - integration_name: str, - job_id: str, - job_instance_id: str, - page_size: int | None = None, - page_token: str | None = None, - filter_string: str | None = None, - order_by: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - as_list: bool = False, -) -> dict[str, Any] | list[dict[str, Any]]: - """List all execution logs for a specific job instance. - - Use this method to browse the historical performance and reliability of a - background automation schedule. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the job belongs to. - job_id: ID of the job the instance belongs to. - job_instance_id: ID of the job instance to list logs for. - page_size: Maximum number of logs to return. - page_token: Page token from a previous call to retrieve the next page. - filter_string: Filter expression to filter logs. - order_by: Field to sort the logs by. - api_version: API version to use for the request. Default is V1BETA. - as_list: If True, return a list of logs instead of a dict with logs - list and nextPageToken. - - Returns: - If as_list is True: List of logs. - If as_list is False: Dict with logs list and nextPageToken. - - Raises: - APIError: If the API request fails. - """ - extra_params = { - "filter": filter_string, - "orderBy": order_by, - } - - # Remove keys with None values - extra_params = {k: v for k, v in extra_params.items() if v is not None} - - return chronicle_paginated_request( - client, - api_version=api_version, - path=( - f"integrations/{format_resource_id(integration_name)}/" - f"jobs/{job_id}/jobInstances/{job_instance_id}/logs" - ), - items_key="logs", - page_size=page_size, - page_token=page_token, - extra_params=extra_params, - as_list=as_list, - ) - - -def get_job_instance_log( - client: "ChronicleClient", - integration_name: str, - job_id: str, - job_instance_id: str, - log_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> dict[str, Any]: - """Get a single log entry for a specific job instance. - - Use this method to retrieve the detailed output message, start/end times, - and final status of a specific background task execution. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the job belongs to. - job_id: ID of the job the instance belongs to. - job_instance_id: ID of the job instance the log belongs to. - log_id: ID of the log entry to retrieve. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing details of the specified JobInstanceLog. - - Raises: - APIError: If the API request fails. - """ - return chronicle_request( - client, - method="GET", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"jobs/{job_id}/jobInstances/{job_instance_id}/logs/{log_id}" - ), - api_version=api_version, - ) diff --git a/src/secops/chronicle/integration/job_instances.py b/src/secops/chronicle/integration/job_instances.py deleted file mode 100644 index c64705ee..00000000 --- a/src/secops/chronicle/integration/job_instances.py +++ /dev/null @@ -1,399 +0,0 @@ -# Copyright 2025 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. -# -"""Integration job instances functionality for Chronicle.""" - -from typing import Any, TYPE_CHECKING - -from secops.chronicle.models import ( - APIVersion, - AdvancedConfig, - IntegrationJobInstanceParameter, -) -from secops.chronicle.utils.format_utils import ( - format_resource_id, - build_patch_body, -) -from secops.chronicle.utils.request_utils import ( - chronicle_paginated_request, - chronicle_request, -) - -if TYPE_CHECKING: - from secops.chronicle.client import ChronicleClient - - -def list_integration_job_instances( - client: "ChronicleClient", - integration_name: str, - job_id: str, - page_size: int | None = None, - page_token: str | None = None, - filter_string: str | None = None, - order_by: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - as_list: bool = False, -) -> dict[str, Any] | list[dict[str, Any]]: - """List all job instances for a specific integration job. - - Use this method to browse the active job instances and their last - execution status. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the job belongs to. - job_id: ID of the job to list instances for. - page_size: Maximum number of job instances to return. - page_token: Page token from a previous call to retrieve the next page. - filter_string: Filter expression to filter job instances. - order_by: Field to sort the job instances by. - api_version: API version to use for the request. Default is V1BETA. - as_list: If True, return a list of job instances instead of a dict - with job instances list and nextPageToken. - - Returns: - If as_list is True: List of job instances. - If as_list is False: Dict with job instances list and nextPageToken. - - Raises: - APIError: If the API request fails. - """ - extra_params = { - "filter": filter_string, - "orderBy": order_by, - } - - # Remove keys with None values - extra_params = {k: v for k, v in extra_params.items() if v is not None} - - return chronicle_paginated_request( - client, - api_version=api_version, - path=( - f"integrations/{format_resource_id(integration_name)}/jobs/" - f"{job_id}/jobInstances" - ), - items_key="jobInstances", - page_size=page_size, - page_token=page_token, - extra_params=extra_params, - as_list=as_list, - ) - - -def get_integration_job_instance( - client: "ChronicleClient", - integration_name: str, - job_id: str, - job_instance_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> dict[str, Any]: - """Get a single job instance for a specific integration job. - - Use this method to retrieve the execution status, last run time, and - active schedule for a specific background task. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the job belongs to. - job_id: ID of the job the instance belongs to. - job_instance_id: ID of the job instance to retrieve. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing details of the specified IntegrationJobInstance. - - Raises: - APIError: If the API request fails. - """ - return chronicle_request( - client, - method="GET", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/jobs/" - f"{job_id}/jobInstances/{job_instance_id}" - ), - api_version=api_version, - ) - - -def delete_integration_job_instance( - client: "ChronicleClient", - integration_name: str, - job_id: str, - job_instance_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> None: - """Delete a specific job instance for a given integration job. - - Use this method to permanently stop and remove a scheduled background task. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the job belongs to. - job_id: ID of the job the instance belongs to. - job_instance_id: ID of the job instance to delete. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - None - - Raises: - APIError: If the API request fails. - """ - chronicle_request( - client, - method="DELETE", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/jobs/" - f"{job_id}/jobInstances/{job_instance_id}" - ), - api_version=api_version, - ) - - -# pylint: disable=line-too-long -def create_integration_job_instance( - client: "ChronicleClient", - integration_name: str, - job_id: str, - display_name: str, - interval_seconds: int, - enabled: bool, - advanced: bool, - description: str | None = None, - parameters: ( - list[dict[str, Any] | IntegrationJobInstanceParameter] | None - ) = None, - advanced_config: dict[str, Any] | AdvancedConfig | None = None, - agent: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> dict[str, Any]: - # pylint: enable=line-too-long - """Create a new job instance for a specific integration job. - - Use this method to schedule a new recurring background job. You must - provide a valid execution interval and any required script parameters. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the job belongs to. - job_id: ID of the job to create an instance for. - display_name: Job instance display name. Required. - interval_seconds: Job execution interval in seconds. Minimum 60. - Required. - enabled: Whether the job instance is enabled. Required. - advanced: Whether the job instance uses advanced scheduling. Required. - description: Job instance description. Optional. - parameters: List of IntegrationJobInstanceParameter instances or - dicts. Optional. - advanced_config: Advanced scheduling configuration. Accepts an - AdvancedConfig instance or a raw dict. Optional. - agent: Agent identifier for remote job execution. Cannot be patched - after creation. Optional. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing the newly created IntegrationJobInstance resource. - - Raises: - APIError: If the API request fails. - """ - resolved_parameters = ( - [ - p.to_dict() if isinstance(p, IntegrationJobInstanceParameter) else p - for p in parameters - ] - if parameters is not None - else None - ) - resolved_advanced_config = ( - advanced_config.to_dict() - if isinstance(advanced_config, AdvancedConfig) - else advanced_config - ) - - body = { - "displayName": display_name, - "intervalSeconds": interval_seconds, - "enabled": enabled, - "advanced": advanced, - "description": description, - "parameters": resolved_parameters, - "advancedConfig": resolved_advanced_config, - "agent": agent, - } - - # Remove keys with None values - body = {k: v for k, v in body.items() if v is not None} - - return chronicle_request( - client, - method="POST", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}" - f"/jobs/{job_id}/jobInstances" - ), - api_version=api_version, - json=body, - ) - - -# pylint: disable=line-too-long -def update_integration_job_instance( - client: "ChronicleClient", - integration_name: str, - job_id: str, - job_instance_id: str, - display_name: str | None = None, - interval_seconds: int | None = None, - enabled: bool | None = None, - advanced: bool | None = None, - description: str | None = None, - parameters: ( - list[dict[str, Any] | IntegrationJobInstanceParameter] | None - ) = None, - advanced_config: dict[str, Any] | AdvancedConfig | None = None, - update_mask: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> dict[str, Any]: - # pylint: enable=line-too-long - """Update an existing job instance for a given integration job. - - Use this method to modify the execution interval, enable/disable the job - instance, or adjust the parameters passed to the background script. - - Note: The agent field cannot be updated after creation. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the job belongs to. - job_id: ID of the job the instance belongs to. - job_instance_id: ID of the job instance to update. - display_name: Job instance display name. - interval_seconds: Job execution interval in seconds. Minimum 60. - enabled: Whether the job instance is enabled. - advanced: Whether the job instance uses advanced scheduling. - description: Job instance description. - parameters: List of IntegrationJobInstanceParameter instances or - dicts. - advanced_config: Advanced scheduling configuration. Accepts an - AdvancedConfig instance or a raw dict. - update_mask: Comma-separated list of fields to update. If omitted, - the mask is auto-generated from whichever fields are provided. - Example: "displayName,intervalSeconds". - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing the updated IntegrationJobInstance resource. - - Raises: - APIError: If the API request fails. - """ - resolved_parameters = ( - [ - p.to_dict() if isinstance(p, IntegrationJobInstanceParameter) else p - for p in parameters - ] - if parameters is not None - else None - ) - resolved_advanced_config = ( - advanced_config.to_dict() - if isinstance(advanced_config, AdvancedConfig) - else advanced_config - ) - - body, params = build_patch_body( - field_map=[ - ("displayName", "displayName", display_name), - ("intervalSeconds", "intervalSeconds", interval_seconds), - ("enabled", "enabled", enabled), - ("advanced", "advanced", advanced), - ("description", "description", description), - ("parameters", "parameters", resolved_parameters), - ("advancedConfig", "advancedConfig", resolved_advanced_config), - ], - update_mask=update_mask, - ) - - return chronicle_request( - client, - method="PATCH", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"jobs/{job_id}/jobInstances/{job_instance_id}" - ), - api_version=api_version, - json=body, - params=params, - ) - - -# pylint: disable=line-too-long -def run_integration_job_instance_on_demand( - client: "ChronicleClient", - integration_name: str, - job_id: str, - job_instance_id: str, - parameters: ( - list[dict[str, Any] | IntegrationJobInstanceParameter] | None - ) = None, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> dict[str, Any]: - # pylint: enable=line-too-long - """Execute a job instance immediately, bypassing its normal schedule. - - Use this method to trigger an on-demand run of a job for synchronization - or troubleshooting purposes. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the job belongs to. - job_id: ID of the job the instance belongs to. - job_instance_id: ID of the job instance to run on demand. - parameters: List of IntegrationJobInstanceParameter instances or - dicts. Optional. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing a success boolean indicating whether the job run - completed successfully. - - Raises: - APIError: If the API request fails. - """ - resolved_parameters = ( - [ - p.to_dict() if isinstance(p, IntegrationJobInstanceParameter) else p - for p in parameters - ] - if parameters is not None - else None - ) - - body = {} - if resolved_parameters is not None: - body["parameters"] = resolved_parameters - - return chronicle_request( - client, - method="POST", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}" - f"/jobs/{job_id}/jobInstances/{job_instance_id}:runOnDemand" - ), - api_version=api_version, - json=body, - ) diff --git a/src/secops/chronicle/integration/job_revisions.py b/src/secops/chronicle/integration/job_revisions.py deleted file mode 100644 index 391daacb..00000000 --- a/src/secops/chronicle/integration/job_revisions.py +++ /dev/null @@ -1,204 +0,0 @@ -# Copyright 2025 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. -# -"""Integration job revisions functionality for Chronicle.""" - -from typing import Any, TYPE_CHECKING - -from secops.chronicle.models import APIVersion -from secops.chronicle.utils.format_utils import ( - format_resource_id, -) -from secops.chronicle.utils.request_utils import ( - chronicle_paginated_request, - chronicle_request, -) - -if TYPE_CHECKING: - from secops.chronicle.client import ChronicleClient - - -def list_integration_job_revisions( - client: "ChronicleClient", - integration_name: str, - job_id: str, - page_size: int | None = None, - page_token: str | None = None, - filter_string: str | None = None, - order_by: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - as_list: bool = False, -) -> dict[str, Any] | list[dict[str, Any]]: - """List all revisions for a specific integration job. - - Use this method to browse the version history and identify previous - configurations of a recurring job. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the job belongs to. - job_id: ID of the job to list revisions for. - page_size: Maximum number of revisions to return. - page_token: Page token from a previous call to retrieve the next page. - filter_string: Filter expression to filter revisions. - order_by: Field to sort the revisions by. - api_version: API version to use for the request. Default is V1BETA. - as_list: If True, return a list of revisions instead of a dict with - revisions list and nextPageToken. - - Returns: - If as_list is True: List of revisions. - If as_list is False: Dict with revisions list and nextPageToken. - - Raises: - APIError: If the API request fails. - """ - extra_params = { - "filter": filter_string, - "orderBy": order_by, - } - - # Remove keys with None values - extra_params = {k: v for k, v in extra_params.items() if v is not None} - - return chronicle_paginated_request( - client, - api_version=api_version, - path=( - f"integrations/{format_resource_id(integration_name)}/" - f"jobs/{job_id}/revisions" - ), - items_key="revisions", - page_size=page_size, - page_token=page_token, - extra_params=extra_params, - as_list=as_list, - ) - - -def delete_integration_job_revision( - client: "ChronicleClient", - integration_name: str, - job_id: str, - revision_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> None: - """Delete a specific revision for a given integration job. - - Use this method to clean up obsolete snapshots and manage the historical - record of background automation tasks. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the job belongs to. - job_id: ID of the job the revision belongs to. - revision_id: ID of the revision to delete. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - None - - Raises: - APIError: If the API request fails. - """ - chronicle_request( - client, - method="DELETE", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"jobs/{job_id}/revisions/{revision_id}" - ), - api_version=api_version, - ) - - -def create_integration_job_revision( - client: "ChronicleClient", - integration_name: str, - job_id: str, - job: dict[str, Any], - comment: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> dict[str, Any]: - """Create a new revision snapshot of the current integration job. - - Use this method to establish a recovery point before making significant - changes to a background job's script or parameters. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the job belongs to. - job_id: ID of the job to create a revision for. - job: Dict containing the IntegrationJob to snapshot. - comment: Comment describing the revision. Maximum 400 characters. - Optional. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing the newly created IntegrationJobRevision resource. - - Raises: - APIError: If the API request fails. - """ - body = {"job": job} - - if comment is not None: - body["comment"] = comment - - return chronicle_request( - client, - method="POST", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"jobs/{job_id}/revisions" - ), - api_version=api_version, - json=body, - ) - - -def rollback_integration_job_revision( - client: "ChronicleClient", - integration_name: str, - job_id: str, - revision_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> dict[str, Any]: - """Revert the current job definition to a previously saved revision. - - Use this method to rapidly recover a functional automation state if an - update causes operational issues. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the job belongs to. - job_id: ID of the job to rollback. - revision_id: ID of the revision to rollback to. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing the IntegrationJobRevision rolled back to. - - Raises: - APIError: If the API request fails. - """ - return chronicle_request( - client, - method="POST", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"jobs/{job_id}/revisions/{revision_id}:rollback" - ), - api_version=api_version, - ) diff --git a/src/secops/chronicle/integration/jobs.py b/src/secops/chronicle/integration/jobs.py deleted file mode 100644 index b7600a76..00000000 --- a/src/secops/chronicle/integration/jobs.py +++ /dev/null @@ -1,371 +0,0 @@ -# Copyright 2025 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. -# -"""Integration jobs functionality for Chronicle.""" - -from typing import Any, TYPE_CHECKING - -from secops.chronicle.models import APIVersion, JobParameter -from secops.chronicle.utils.format_utils import ( - format_resource_id, - build_patch_body, -) -from secops.chronicle.utils.request_utils import ( - chronicle_paginated_request, - chronicle_request, -) - -if TYPE_CHECKING: - from secops.chronicle.client import ChronicleClient - - -def list_integration_jobs( - client: "ChronicleClient", - integration_name: str, - page_size: int | None = None, - page_token: str | None = None, - filter_string: str | None = None, - order_by: str | None = None, - exclude_staging: bool | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - as_list: bool = False, -) -> dict[str, Any] | list[dict[str, Any]]: - """List all jobs defined for a specific integration. - - Use this method to browse the available background and scheduled automation - capabilities provided by a third-party connection. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration to list jobs for. - page_size: Maximum number of jobs to return. - page_token: Page token from a previous call to retrieve the next page. - filter_string: Filter expression to filter jobs. Allowed filters are: - id, custom, system, author, version, integration. - order_by: Field to sort the jobs by. - exclude_staging: Whether to exclude staging jobs from the response. - By default, staging jobs are included. - api_version: API version to use for the request. Default is V1BETA. - as_list: If True, return a list of jobs instead of a dict with jobs - list and nextPageToken. - - Returns: - If as_list is True: List of jobs. - If as_list is False: Dict with jobs list and nextPageToken. - - Raises: - APIError: If the API request fails. - """ - extra_params = { - "filter": filter_string, - "orderBy": order_by, - "excludeStaging": exclude_staging, - } - - # Remove keys with None values - extra_params = {k: v for k, v in extra_params.items() if v is not None} - - return chronicle_paginated_request( - client, - api_version=api_version, - path=f"integrations/{format_resource_id(integration_name)}/jobs", - items_key="jobs", - page_size=page_size, - page_token=page_token, - extra_params=extra_params, - as_list=as_list, - ) - - -def get_integration_job( - client: "ChronicleClient", - integration_name: str, - job_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> dict[str, Any]: - """Get a single job for a given integration. - - Use this method to retrieve the Python script, execution parameters, and - versioning information for a background automation task. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the job belongs to. - job_id: ID of the job to retrieve. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing details of the specified IntegrationJob. - - Raises: - APIError: If the API request fails. - """ - return chronicle_request( - client, - method="GET", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"jobs/{job_id}" - ), - api_version=api_version, - ) - - -def delete_integration_job( - client: "ChronicleClient", - integration_name: str, - job_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> None: - """Delete a specific custom job from a given integration. - - Only custom jobs can be deleted; commercial and system jobs are immutable. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the job belongs to. - job_id: ID of the job to delete. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - None - - Raises: - APIError: If the API request fails. - """ - chronicle_request( - client, - method="DELETE", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"jobs/{job_id}" - ), - api_version=api_version, - ) - - -def create_integration_job( - client: "ChronicleClient", - integration_name: str, - display_name: str, - script: str, - version: int, - enabled: bool, - custom: bool, - description: str | None = None, - parameters: list[dict[str, Any] | JobParameter] | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> dict[str, Any]: - """Create a new custom job for a given integration. - - Each job must have a unique display name and a functional Python script - for its background execution. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration to create the job for. - display_name: Job's display name. Maximum 400 characters. Required. - script: Job's Python script. Required. - version: Job's version. Required. - enabled: Whether the job is enabled. Required. - custom: Whether the job is custom or commercial. Required. - description: Job's description. Optional. - parameters: List of JobParameter instances or dicts. Optional. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing the newly created IntegrationJob resource. - - Raises: - APIError: If the API request fails. - """ - resolved_parameters = ( - [p.to_dict() if isinstance(p, JobParameter) else p for p in parameters] - if parameters is not None - else None - ) - - body = { - "displayName": display_name, - "script": script, - "version": version, - "enabled": enabled, - "custom": custom, - "description": description, - "parameters": resolved_parameters, - } - - # Remove keys with None values - body = {k: v for k, v in body.items() if v is not None} - - return chronicle_request( - client, - method="POST", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/jobs" - ), - api_version=api_version, - json=body, - ) - - -def update_integration_job( - client: "ChronicleClient", - integration_name: str, - job_id: str, - display_name: str | None = None, - script: str | None = None, - version: int | None = None, - enabled: bool | None = None, - custom: bool | None = None, - description: str | None = None, - parameters: list[dict[str, Any] | JobParameter] | None = None, - update_mask: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> dict[str, Any]: - """Update an existing custom job for a given integration. - - Use this method to modify the Python script or adjust the parameter - definitions for a job. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the job belongs to. - job_id: ID of the job to update. - display_name: Job's display name. Maximum 400 characters. - script: Job's Python script. - version: Job's version. - enabled: Whether the job is enabled. - custom: Whether the job is custom or commercial. - description: Job's description. - parameters: List of JobParameter instances or dicts. - update_mask: Comma-separated list of fields to update. If omitted, - the mask is auto-generated from whichever fields are provided. - Example: "displayName,script". - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing the updated IntegrationJob resource. - - Raises: - APIError: If the API request fails. - """ - resolved_parameters = ( - [p.to_dict() if isinstance(p, JobParameter) else p for p in parameters] - if parameters is not None - else None - ) - - body, params = build_patch_body( - field_map=[ - ("displayName", "displayName", display_name), - ("script", "script", script), - ("version", "version", version), - ("enabled", "enabled", enabled), - ("custom", "custom", custom), - ("description", "description", description), - ("parameters", "parameters", resolved_parameters), - ], - update_mask=update_mask, - ) - - return chronicle_request( - client, - method="PATCH", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"jobs/{job_id}" - ), - api_version=api_version, - json=body, - params=params, - ) - - -def execute_integration_job_test( - client: "ChronicleClient", - integration_name: str, - job: dict[str, Any], - agent_identifier: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> dict[str, Any]: - """Execute a test run of an integration job's Python script. - - Use this method to verify background automation logic and connectivity - before deploying the job to an instance for recurring execution. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the job belongs to. - job: Dict containing the IntegrationJob to test. - agent_identifier: Agent identifier for remote testing. Optional. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing the test execution results with the following fields: - - output: The script output. - - debugOutput: The script debug output. - - resultObjectJson: The result JSON if it exists (optional). - - resultName: The script result name (optional). - - resultValue: The script result value (optional). - - Raises: - APIError: If the API request fails. - """ - body = {"job": job} - - if agent_identifier is not None: - body["agentIdentifier"] = agent_identifier - - return chronicle_request( - client, - method="POST", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"jobs:executeTest" - ), - api_version=api_version, - json=body, - ) - - -def get_integration_job_template( - client: "ChronicleClient", - integration_name: str, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> dict[str, Any]: - """Retrieve a default Python script template for a new integration job. - - Use this method to rapidly initialize the development of a new job. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration to fetch the template for. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing the IntegrationJob template. - - Raises: - APIError: If the API request fails. - """ - return chronicle_request( - client, - method="GET", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"jobs:fetchTemplate" - ), - api_version=api_version, - ) diff --git a/src/secops/chronicle/integration/logical_operator_revisions.py b/src/secops/chronicle/integration/logical_operator_revisions.py deleted file mode 100644 index f7f00cee..00000000 --- a/src/secops/chronicle/integration/logical_operator_revisions.py +++ /dev/null @@ -1,212 +0,0 @@ -# Copyright 2025 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. -# -"""Integration logical operator revisions functionality for Chronicle.""" - -from typing import Any, TYPE_CHECKING - -from secops.chronicle.models import APIVersion -from secops.chronicle.utils.format_utils import format_resource_id -from secops.chronicle.utils.request_utils import ( - chronicle_paginated_request, - chronicle_request, -) - -if TYPE_CHECKING: - from secops.chronicle.client import ChronicleClient - - -def list_integration_logical_operator_revisions( - client: "ChronicleClient", - integration_name: str, - logical_operator_id: str, - page_size: int | None = None, - page_token: str | None = None, - filter_string: str | None = None, - order_by: str | None = None, - api_version: APIVersion | None = APIVersion.V1ALPHA, - as_list: bool = False, -) -> dict[str, Any] | list[dict[str, Any]]: - """List all revisions for a specific integration logical operator. - - Use this method to browse through the version history of a custom logical - operator definition. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the logical operator - belongs to. - logical_operator_id: ID of the logical operator to list revisions for. - page_size: Maximum number of revisions to return. - page_token: Page token from a previous call to retrieve the next page. - filter_string: Filter expression to filter revisions. - order_by: Field to sort the revisions by. - api_version: API version to use for the request. Default is V1ALPHA. - as_list: If True, return a list of revisions instead of a dict with - revisions list and nextPageToken. - - Returns: - If as_list is True: List of revisions. - If as_list is False: Dict with revisions list and nextPageToken. - - Raises: - APIError: If the API request fails. - """ - extra_params = { - "filter": filter_string, - "orderBy": order_by, - } - - # Remove keys with None values - extra_params = {k: v for k, v in extra_params.items() if v is not None} - - return chronicle_paginated_request( - client, - api_version=api_version, - path=( - f"integrations/{format_resource_id(integration_name)}/" - f"logicalOperators/{logical_operator_id}/revisions" - ), - items_key="revisions", - page_size=page_size, - page_token=page_token, - extra_params=extra_params, - as_list=as_list, - ) - - -def delete_integration_logical_operator_revision( - client: "ChronicleClient", - integration_name: str, - logical_operator_id: str, - revision_id: str, - api_version: APIVersion | None = APIVersion.V1ALPHA, -) -> None: - """Delete a specific revision for a given integration logical operator. - - Permanently removes the versioned snapshot from the logical operator's - history. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the logical operator - belongs to. - logical_operator_id: ID of the logical operator the revision belongs - to. - revision_id: ID of the revision to delete. - api_version: API version to use for the request. Default is V1ALPHA. - - Returns: - None - - Raises: - APIError: If the API request fails. - """ - chronicle_request( - client, - method="DELETE", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"logicalOperators/{logical_operator_id}/revisions/{revision_id}" - ), - api_version=api_version, - ) - - -def create_integration_logical_operator_revision( - client: "ChronicleClient", - integration_name: str, - logical_operator_id: str, - logical_operator: dict[str, Any], - comment: str | None = None, - api_version: APIVersion | None = APIVersion.V1ALPHA, -) -> dict[str, Any]: - """Create a new revision snapshot of the current integration - logical operator. - - Use this method to save the current state of a logical operator - definition. Revisions can only be created for custom logical operators. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the logical operator - belongs to. - logical_operator_id: ID of the logical operator to create a revision - for. - logical_operator: Dict containing the IntegrationLogicalOperator to - snapshot. - comment: Comment describing the revision. Maximum 400 characters. - Optional. - api_version: API version to use for the request. Default is V1ALPHA. - - Returns: - Dict containing the newly created IntegrationLogicalOperatorRevision - resource. - - Raises: - APIError: If the API request fails. - """ - body = {"logicalOperator": logical_operator} - - if comment is not None: - body["comment"] = comment - - return chronicle_request( - client, - method="POST", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"logicalOperators/{logical_operator_id}/revisions" - ), - api_version=api_version, - json=body, - ) - - -def rollback_integration_logical_operator_revision( - client: "ChronicleClient", - integration_name: str, - logical_operator_id: str, - revision_id: str, - api_version: APIVersion | None = APIVersion.V1ALPHA, -) -> dict[str, Any]: - """Roll back the current logical operator to a previously saved revision. - - This updates the active logical operator definition with the configuration - stored in the specified revision. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the logical operator - belongs to. - logical_operator_id: ID of the logical operator to rollback. - revision_id: ID of the revision to rollback to. - api_version: API version to use for the request. Default is V1ALPHA. - - Returns: - Dict containing the IntegrationLogicalOperatorRevision rolled back to. - - Raises: - APIError: If the API request fails. - """ - return chronicle_request( - client, - method="POST", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"logicalOperators/{logical_operator_id}/revisions/" - f"{revision_id}:rollback" - ), - api_version=api_version, - ) diff --git a/src/secops/chronicle/integration/logical_operators.py b/src/secops/chronicle/integration/logical_operators.py deleted file mode 100644 index fe5da103..00000000 --- a/src/secops/chronicle/integration/logical_operators.py +++ /dev/null @@ -1,411 +0,0 @@ -# Copyright 2025 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. -# -"""Integration logical operators functionality for Chronicle.""" - -from typing import Any, TYPE_CHECKING - -from secops.chronicle.models import ( - APIVersion, - IntegrationLogicalOperatorParameter, -) -from secops.chronicle.utils.format_utils import ( - format_resource_id, - build_patch_body, -) -from secops.chronicle.utils.request_utils import ( - chronicle_paginated_request, - chronicle_request, -) - -if TYPE_CHECKING: - from secops.chronicle.client import ChronicleClient - - -def list_integration_logical_operators( - client: "ChronicleClient", - integration_name: str, - page_size: int | None = None, - page_token: str | None = None, - filter_string: str | None = None, - order_by: str | None = None, - exclude_staging: bool | None = None, - expand: str | None = None, - api_version: APIVersion | None = APIVersion.V1ALPHA, - as_list: bool = False, -) -> dict[str, Any] | list[dict[str, Any]]: - """List all logical operator definitions for a specific integration. - - Use this method to discover the custom logic operators available for use - within playbook decision steps. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration to list logical operators - for. - page_size: Maximum number of logical operators to return. Defaults - to 100, maximum is 200. - page_token: Page token from a previous call to retrieve the next page. - filter_string: Filter expression to filter logical operators. - order_by: Field to sort the logical operators by. - exclude_staging: Whether to exclude staging logical operators from - the response. By default, staging logical operators are included. - expand: Expand the response with the full logical operator details. - api_version: API version to use for the request. Default is V1ALPHA. - as_list: If True, return a list of logical operators instead of a - dict with logical operators list and nextPageToken. - - Returns: - If as_list is True: List of logical operators. - If as_list is False: Dict with logical operators list and - nextPageToken. - - Raises: - APIError: If the API request fails. - """ - extra_params = { - "filter": filter_string, - "orderBy": order_by, - "excludeStaging": exclude_staging, - "expand": expand, - } - - # Remove keys with None values - extra_params = {k: v for k, v in extra_params.items() if v is not None} - - return chronicle_paginated_request( - client, - api_version=api_version, - path=( - f"integrations/{format_resource_id(integration_name)}/" - f"logicalOperators" - ), - items_key="logicalOperators", - page_size=page_size, - page_token=page_token, - extra_params=extra_params, - as_list=as_list, - ) - - -def get_integration_logical_operator( - client: "ChronicleClient", - integration_name: str, - logical_operator_id: str, - expand: str | None = None, - api_version: APIVersion | None = APIVersion.V1ALPHA, -) -> dict[str, Any]: - """Get a single logical operator definition for a specific integration. - - Use this method to retrieve the Python script, evaluation parameters, - and description for a custom logical operator. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the logical operator - belongs to. - logical_operator_id: ID of the logical operator to retrieve. - expand: Expand the response with the full logical operator details. - Optional. - api_version: API version to use for the request. Default is V1ALPHA. - - Returns: - Dict containing details of the specified IntegrationLogicalOperator. - - Raises: - APIError: If the API request fails. - """ - params = {} - if expand is not None: - params["expand"] = expand - - return chronicle_request( - client, - method="GET", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"logicalOperators/{logical_operator_id}" - ), - api_version=api_version, - params=params if params else None, - ) - - -def delete_integration_logical_operator( - client: "ChronicleClient", - integration_name: str, - logical_operator_id: str, - api_version: APIVersion | None = APIVersion.V1ALPHA, -) -> None: - """Delete a specific custom logical operator from a given integration. - - Only custom logical operators can be deleted; predefined built-in - operators are immutable. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the logical operator - belongs to. - logical_operator_id: ID of the logical operator to delete. - api_version: API version to use for the request. Default is V1ALPHA. - - Returns: - None - - Raises: - APIError: If the API request fails. - """ - chronicle_request( - client, - method="DELETE", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"logicalOperators/{logical_operator_id}" - ), - api_version=api_version, - ) - - -def create_integration_logical_operator( - client: "ChronicleClient", - integration_name: str, - display_name: str, - script: str, - script_timeout: str, - enabled: bool, - description: str | None = None, - parameters: ( - list[dict[str, Any] | IntegrationLogicalOperatorParameter] | None - ) = None, - api_version: APIVersion | None = APIVersion.V1ALPHA, -) -> dict[str, Any]: - """Create a new custom logical operator for a given integration. - - Each operator must have a unique display name and a functional Python - script that returns a boolean result. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration to create the logical - operator for. - display_name: Logical operator's display name. Maximum 150 - characters. Required. - script: Logical operator's Python script. Required. - script_timeout: Timeout in seconds for a single script run. Default - is 60. Required. - enabled: Whether the logical operator is enabled or disabled. - Required. - description: Logical operator's description. Maximum 2050 characters. - Optional. - parameters: List of IntegrationLogicalOperatorParameter instances or - dicts. Optional. - api_version: API version to use for the request. Default is V1ALPHA. - - Returns: - Dict containing the newly created IntegrationLogicalOperator resource. - - Raises: - APIError: If the API request fails. - """ - resolved_parameters = ( - [ - ( - p.to_dict() - if isinstance(p, IntegrationLogicalOperatorParameter) - else p - ) - for p in parameters - ] - if parameters is not None - else None - ) - - body = { - "displayName": display_name, - "script": script, - "scriptTimeout": script_timeout, - "enabled": enabled, - "description": description, - "parameters": resolved_parameters, - } - - # Remove keys with None values - body = {k: v for k, v in body.items() if v is not None} - - return chronicle_request( - client, - method="POST", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"logicalOperators" - ), - api_version=api_version, - json=body, - ) - - -def update_integration_logical_operator( - client: "ChronicleClient", - integration_name: str, - logical_operator_id: str, - display_name: str | None = None, - script: str | None = None, - script_timeout: str | None = None, - enabled: bool | None = None, - description: str | None = None, - parameters: ( - list[dict[str, Any] | IntegrationLogicalOperatorParameter] | None - ) = None, - update_mask: str | None = None, - api_version: APIVersion | None = APIVersion.V1ALPHA, -) -> dict[str, Any]: - """Update an existing custom logical operator for a given integration. - - Use this method to modify the logical operator script, refine parameter - descriptions, or adjust the timeout for a logical operator. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the logical operator - belongs to. - logical_operator_id: ID of the logical operator to update. - display_name: Logical operator's display name. Maximum 150 characters. - script: Logical operator's Python script. - script_timeout: Timeout in seconds for a single script run. - enabled: Whether the logical operator is enabled or disabled. - description: Logical operator's description. Maximum 2050 characters. - parameters: List of IntegrationLogicalOperatorParameter instances or - dicts. When updating existing parameters, id must be provided - in each IntegrationLogicalOperatorParameter. - update_mask: Comma-separated list of fields to update. If omitted, - the mask is auto-generated from whichever fields are provided. - Example: "displayName,script". - api_version: API version to use for the request. Default is V1ALPHA. - - Returns: - Dict containing the updated IntegrationLogicalOperator resource. - - Raises: - APIError: If the API request fails. - """ - resolved_parameters = ( - [ - ( - p.to_dict() - if isinstance(p, IntegrationLogicalOperatorParameter) - else p - ) - for p in parameters - ] - if parameters is not None - else None - ) - - body, params = build_patch_body( - field_map=[ - ("displayName", "displayName", display_name), - ("script", "script", script), - ("scriptTimeout", "scriptTimeout", script_timeout), - ("enabled", "enabled", enabled), - ("description", "description", description), - ("parameters", "parameters", resolved_parameters), - ], - update_mask=update_mask, - ) - - return chronicle_request( - client, - method="PATCH", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"logicalOperators/{logical_operator_id}" - ), - api_version=api_version, - json=body, - params=params, - ) - - -def execute_integration_logical_operator_test( - client: "ChronicleClient", - integration_name: str, - logical_operator: dict[str, Any], - api_version: APIVersion | None = APIVersion.V1ALPHA, -) -> dict[str, Any]: - """Execute a test run of a logical operator's evaluation script. - - Use this method to verify decision logic and ensure it correctly handles - various input data before deployment in a playbook. The full logical - operator object is required as the test can be run without saving the - logical operator first. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the logical operator - belongs to. - logical_operator: Dict containing the IntegrationLogicalOperator to - test. - api_version: API version to use for the request. Default is V1ALPHA. - - Returns: - Dict containing the test execution results with the following fields: - - outputMessage: Human-readable output message set by the script. - - debugOutputMessage: The script debug output. - - resultValue: The script result value. - - Raises: - APIError: If the API request fails. - """ - return chronicle_request( - client, - method="POST", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"logicalOperators:executeTest" - ), - api_version=api_version, - json={"logicalOperator": logical_operator}, - ) - - -def get_integration_logical_operator_template( - client: "ChronicleClient", - integration_name: str, - api_version: APIVersion | None = APIVersion.V1ALPHA, -) -> dict[str, Any]: - """Retrieve a default Python script template for a new logical operator. - - Use this method to rapidly initialize the development of a new logical - operator. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration to fetch the template for. - api_version: API version to use for the request. Default is V1ALPHA. - - Returns: - Dict containing the IntegrationLogicalOperator template. - - Raises: - APIError: If the API request fails. - """ - return chronicle_request( - client, - method="GET", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"logicalOperators:fetchTemplate" - ), - api_version=api_version, - ) diff --git a/src/secops/chronicle/integration/marketplace_integrations.py b/src/secops/chronicle/integration/marketplace_integrations.py deleted file mode 100644 index fb9006cc..00000000 --- a/src/secops/chronicle/integration/marketplace_integrations.py +++ /dev/null @@ -1,199 +0,0 @@ -# Copyright 2025 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. -# -"""Integrations functionality for Chronicle.""" - -from typing import Any, TYPE_CHECKING - -from secops.chronicle.models import APIVersion -from secops.chronicle.utils.request_utils import ( - chronicle_paginated_request, - chronicle_request, -) - -if TYPE_CHECKING: - from secops.chronicle.client import ChronicleClient - - -def list_marketplace_integrations( - client: "ChronicleClient", - page_size: int | None = None, - page_token: str | None = None, - filter_string: str | None = None, - order_by: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - as_list: bool = False, -) -> dict[str, Any] | list[dict[str, Any]]: - """Get a list of marketplace integrations. - - Args: - client: ChronicleClient instance - page_size: Number of results to return per page - page_token: Token for the page to retrieve - filter_string: Filter expression to filter marketplace integrations - order_by: Field to sort the marketplace integrations by - api_version: API version to use for the request. Default is V1BETA. - as_list: If True, return a list of marketplace integrations instead - of a dict with marketplace integrations list and nextPageToken. - - Returns: - If as_list is True: List of marketplace integrations. - If as_list is False: Dict with marketplace integrations list and - nextPageToken. - - Raises: - APIError: If the API request fails - """ - field_map = { - "filter": filter_string, - "orderBy": order_by, - } - - return chronicle_paginated_request( - client, - api_version=api_version, - path="marketplaceIntegrations", - items_key="marketplaceIntegrations", - page_size=page_size, - page_token=page_token, - extra_params={k: v for k, v in field_map.items() if v is not None}, - as_list=as_list, - ) - - -def get_marketplace_integration( - client: "ChronicleClient", - integration_name: str, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> dict[str, Any]: - """Get a marketplace integration by integration name - - Args: - client: ChronicleClient instance - integration_name: Name of the marketplace integration to retrieve - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Marketplace integration details - - Raises: - APIError: If the API request fails - """ - return chronicle_request( - client, - method="GET", - endpoint_path=f"marketplaceIntegrations/{integration_name}", - api_version=api_version, - ) - - -def get_marketplace_integration_diff( - client: "ChronicleClient", - integration_name: str, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> dict[str, Any]: - """Get the differences between the currently installed version of - an integration and the commercial version available in the marketplace. - - Args: - client: ChronicleClient instance - integration_name: Name of the marketplace integration to compare - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Marketplace integration diff details - - Raises: - APIError: If the API request fails - """ - return chronicle_request( - client, - method="GET", - endpoint_path=f"marketplaceIntegrations/{integration_name}" - f":fetchCommercialDiff", - api_version=api_version, - ) - - -def install_marketplace_integration( - client: "ChronicleClient", - integration_name: str, - override_mapping: bool | None = None, - staging: bool | None = None, - version: str | None = None, - restore_from_snapshot: bool | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> dict[str, Any]: - """Install a marketplace integration by integration name - - Args: - client: ChronicleClient instance - integration_name: Name of the marketplace integration to install - override_mapping: Optional. Determines if the integration should - override the ontology if already installed, if not provided, set to - false by default. - staging: Optional. Determines if the integration should be installed - as staging or production, if not provided, installed as production. - version: Optional. Determines which version of the integration - should be installed. - restore_from_snapshot: Optional. Determines if the integration - should be installed from existing integration snapshot. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Installed marketplace integration details - - Raises: - APIError: If the API request fails - """ - field_map = { - "overrideMapping": override_mapping, - "staging": staging, - "version": version, - "restoreFromSnapshot": restore_from_snapshot, - } - - return chronicle_request( - client, - method="POST", - endpoint_path=f"marketplaceIntegrations/{integration_name}:install", - json={k: v for k, v in field_map.items() if v is not None}, - api_version=api_version, - ) - - -def uninstall_marketplace_integration( - client: "ChronicleClient", - integration_name: str, - api_version: APIVersion | None = APIVersion.V1BETA, -) -> dict[str, Any]: - """Uninstall a marketplace integration by integration name - - Args: - client: ChronicleClient instance - integration_name: Name of the marketplace integration to uninstall - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Empty dictionary if uninstallation is successful - - Raises: - APIError: If the API request fails - """ - return chronicle_request( - client, - method="POST", - endpoint_path=f"marketplaceIntegrations/{integration_name}:uninstall", - api_version=api_version, - ) diff --git a/src/secops/chronicle/integration/transformer_revisions.py b/src/secops/chronicle/integration/transformer_revisions.py deleted file mode 100644 index 397d3fbf..00000000 --- a/src/secops/chronicle/integration/transformer_revisions.py +++ /dev/null @@ -1,202 +0,0 @@ -# Copyright 2025 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. -# -"""Integration transformer revisions functionality for Chronicle.""" - -from typing import Any, TYPE_CHECKING - -from secops.chronicle.models import APIVersion -from secops.chronicle.utils.format_utils import format_resource_id -from secops.chronicle.utils.request_utils import ( - chronicle_paginated_request, - chronicle_request, -) - -if TYPE_CHECKING: - from secops.chronicle.client import ChronicleClient - - -def list_integration_transformer_revisions( - client: "ChronicleClient", - integration_name: str, - transformer_id: str, - page_size: int | None = None, - page_token: str | None = None, - filter_string: str | None = None, - order_by: str | None = None, - api_version: APIVersion | None = APIVersion.V1ALPHA, - as_list: bool = False, -) -> dict[str, Any] | list[dict[str, Any]]: - """List all revisions for a specific integration transformer. - - Use this method to browse through the version history of a custom - transformer definition. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the transformer belongs to. - transformer_id: ID of the transformer to list revisions for. - page_size: Maximum number of revisions to return. - page_token: Page token from a previous call to retrieve the next page. - filter_string: Filter expression to filter revisions. - order_by: Field to sort the revisions by. - api_version: API version to use for the request. Default is V1ALPHA. - as_list: If True, return a list of revisions instead of a dict with - revisions list and nextPageToken. - - Returns: - If as_list is True: List of revisions. - If as_list is False: Dict with revisions list and nextPageToken. - - Raises: - APIError: If the API request fails. - """ - extra_params = { - "filter": filter_string, - "orderBy": order_by, - } - - # Remove keys with None values - extra_params = {k: v for k, v in extra_params.items() if v is not None} - - return chronicle_paginated_request( - client, - api_version=api_version, - path=( - f"integrations/{format_resource_id(integration_name)}/" - f"transformers/{transformer_id}/revisions" - ), - items_key="revisions", - page_size=page_size, - page_token=page_token, - extra_params=extra_params, - as_list=as_list, - ) - - -def delete_integration_transformer_revision( - client: "ChronicleClient", - integration_name: str, - transformer_id: str, - revision_id: str, - api_version: APIVersion | None = APIVersion.V1ALPHA, -) -> None: - """Delete a specific revision for a given integration transformer. - - Permanently removes the versioned snapshot from the transformer's history. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the transformer belongs to. - transformer_id: ID of the transformer the revision belongs to. - revision_id: ID of the revision to delete. - api_version: API version to use for the request. Default is V1ALPHA. - - Returns: - None - - Raises: - APIError: If the API request fails. - """ - chronicle_request( - client, - method="DELETE", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"transformers/{transformer_id}/revisions/{revision_id}" - ), - api_version=api_version, - ) - - -def create_integration_transformer_revision( - client: "ChronicleClient", - integration_name: str, - transformer_id: str, - transformer: dict[str, Any], - comment: str | None = None, - api_version: APIVersion | None = APIVersion.V1ALPHA, -) -> dict[str, Any]: - """Create a new revision snapshot of the current integration transformer. - - Use this method to save the current state of a transformer definition. - Revisions can only be created for custom transformers. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the transformer belongs to. - transformer_id: ID of the transformer to create a revision for. - transformer: Dict containing the TransformerDefinition to snapshot. - comment: Comment describing the revision. Maximum 400 characters. - Optional. - api_version: API version to use for the request. Default is V1ALPHA. - - Returns: - Dict containing the newly created TransformerRevision resource. - - Raises: - APIError: If the API request fails. - """ - body = {"transformer": transformer} - - if comment is not None: - body["comment"] = comment - - return chronicle_request( - client, - method="POST", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"transformers/{transformer_id}/revisions" - ), - api_version=api_version, - json=body, - ) - - -def rollback_integration_transformer_revision( - client: "ChronicleClient", - integration_name: str, - transformer_id: str, - revision_id: str, - api_version: APIVersion | None = APIVersion.V1ALPHA, -) -> dict[str, Any]: - """Roll back the current transformer definition to - a previously saved revision. - - This updates the active transformer definition with the configuration - stored in the specified revision. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the transformer belongs to. - transformer_id: ID of the transformer to rollback. - revision_id: ID of the revision to rollback to. - api_version: API version to use for the request. Default is V1ALPHA. - - Returns: - Dict containing the TransformerRevision rolled back to. - - Raises: - APIError: If the API request fails. - """ - return chronicle_request( - client, - method="POST", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"transformers/{transformer_id}/revisions/{revision_id}:rollback" - ), - api_version=api_version, - ) diff --git a/src/secops/chronicle/integration/transformers.py b/src/secops/chronicle/integration/transformers.py deleted file mode 100644 index a2a0b817..00000000 --- a/src/secops/chronicle/integration/transformers.py +++ /dev/null @@ -1,406 +0,0 @@ -# Copyright 2025 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. -# -"""Integration transformers functionality for Chronicle.""" - -from typing import Any, TYPE_CHECKING - -from secops.chronicle.models import APIVersion, TransformerDefinitionParameter -from secops.chronicle.utils.format_utils import ( - format_resource_id, - build_patch_body, -) -from secops.chronicle.utils.request_utils import ( - chronicle_paginated_request, - chronicle_request, -) - -if TYPE_CHECKING: - from secops.chronicle.client import ChronicleClient - - -def list_integration_transformers( - client: "ChronicleClient", - integration_name: str, - page_size: int | None = None, - page_token: str | None = None, - filter_string: str | None = None, - order_by: str | None = None, - exclude_staging: bool | None = None, - expand: str | None = None, - api_version: APIVersion | None = APIVersion.V1ALPHA, -) -> dict[str, Any] | list[dict[str, Any]]: - """List all transformer definitions for a specific integration. - - Use this method to browse the available transformers. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration to list transformers for. - page_size: Maximum number of transformers to return. Defaults to 100, - maximum is 200. - page_token: Page token from a previous call to retrieve the next page. - filter_string: Filter expression to filter transformers. - order_by: Field to sort the transformers by. - exclude_staging: Whether to exclude staging transformers from the - response. By default, staging transformers are included. - expand: Expand the response with the full transformer details. - api_version: API version to use for the request. Default is V1ALPHA. - - Returns: - If as_list is True: List of transformers. - If as_list is False: Dict with transformers list and nextPageToken. - - Raises: - APIError: If the API request fails. - """ - extra_params = { - "filter": filter_string, - "orderBy": order_by, - "excludeStaging": exclude_staging, - "expand": expand, - } - - # Remove keys with None values - extra_params = {k: v for k, v in extra_params.items() if v is not None} - - return chronicle_paginated_request( - client, - api_version=api_version, - path=( - f"integrations/{format_resource_id(integration_name)}/" - f"transformers" - ), - items_key="transformers", - page_size=page_size, - page_token=page_token, - extra_params=extra_params, - as_list=False, - ) - - -def get_integration_transformer( - client: "ChronicleClient", - integration_name: str, - transformer_id: str, - expand: str | None = None, - api_version: APIVersion | None = APIVersion.V1ALPHA, -) -> dict[str, Any]: - """Get a single transformer definition for a specific integration. - - Use this method to retrieve the Python script, input parameters, and - expected input, output and usage example schema for a specific data - transformation logic within an integration. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the transformer belongs to. - transformer_id: ID of the transformer to retrieve. - expand: Expand the response with the full transformer details. - Optional. - api_version: API version to use for the request. Default is V1ALPHA. - - Returns: - Dict containing details of the specified TransformerDefinition. - - Raises: - APIError: If the API request fails. - """ - params = {} - if expand is not None: - params["expand"] = expand - - return chronicle_request( - client, - method="GET", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"transformers/{transformer_id}" - ), - api_version=api_version, - params=params if params else None, - ) - - -def delete_integration_transformer( - client: "ChronicleClient", - integration_name: str, - transformer_id: str, - api_version: APIVersion | None = APIVersion.V1ALPHA, -) -> None: - """Delete a custom transformer definition from a given integration. - - Use this method to permanently remove an obsolete transformer from an - integration. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the transformer belongs to. - transformer_id: ID of the transformer to delete. - api_version: API version to use for the request. Default is V1ALPHA. - - Returns: - None - - Raises: - APIError: If the API request fails. - """ - chronicle_request( - client, - method="DELETE", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"transformers/{transformer_id}" - ), - api_version=api_version, - ) - - -def create_integration_transformer( - client: "ChronicleClient", - integration_name: str, - display_name: str, - script: str, - script_timeout: str, - enabled: bool, - description: str | None = None, - parameters: ( - list[dict[str, Any] | TransformerDefinitionParameter] | None - ) = None, - usage_example: str | None = None, - expected_output: str | None = None, - expected_input: str | None = None, - api_version: APIVersion | None = APIVersion.V1ALPHA, -) -> dict[str, Any]: - """Create a new transformer definition for a given integration. - - Use this method to define a transformer, specifying its functional Python - script and necessary input parameters. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration to create the transformer - for. - display_name: Transformer's display name. Maximum 150 characters. - Required. - script: Transformer's Python script. Required. - script_timeout: Timeout in seconds for a single script run. Default - is 60. Required. - enabled: Whether the transformer is enabled or disabled. Required. - description: Transformer's description. Maximum 2050 characters. - Optional. - parameters: List of TransformerDefinitionParameter instances or - dicts. Optional. - usage_example: Transformer's usage example. Optional. - expected_output: Transformer's expected output. Optional. - expected_input: Transformer's expected input. Optional. - api_version: API version to use for the request. Default is V1ALPHA. - - Returns: - Dict containing the newly created TransformerDefinition resource. - - Raises: - APIError: If the API request fails. - """ - resolved_parameters = ( - [ - p.to_dict() if isinstance(p, TransformerDefinitionParameter) else p - for p in parameters - ] - if parameters is not None - else None - ) - - body = { - "displayName": display_name, - "script": script, - "scriptTimeout": script_timeout, - "enabled": enabled, - "description": description, - "parameters": resolved_parameters, - "usageExample": usage_example, - "expectedOutput": expected_output, - "expectedInput": expected_input, - } - - # Remove keys with None values - body = {k: v for k, v in body.items() if v is not None} - - return chronicle_request( - client, - method="POST", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/transformers" - ), - api_version=api_version, - json=body, - ) - - -def update_integration_transformer( - client: "ChronicleClient", - integration_name: str, - transformer_id: str, - display_name: str | None = None, - script: str | None = None, - script_timeout: str | None = None, - enabled: bool | None = None, - description: str | None = None, - parameters: ( - list[dict[str, Any] | TransformerDefinitionParameter] | None - ) = None, - usage_example: str | None = None, - expected_output: str | None = None, - expected_input: str | None = None, - update_mask: str | None = None, - api_version: APIVersion | None = APIVersion.V1ALPHA, -) -> dict[str, Any]: - """Update an existing transformer definition for a given integration. - - Use this method to modify a transformation's Python script, adjust its - description, or refine its parameter definitions. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the transformer belongs to. - transformer_id: ID of the transformer to update. - display_name: Transformer's display name. Maximum 150 characters. - script: Transformer's Python script. - script_timeout: Timeout in seconds for a single script run. - enabled: Whether the transformer is enabled or disabled. - description: Transformer's description. Maximum 2050 characters. - parameters: List of TransformerDefinitionParameter instances or - dicts. When updating existing parameters, id must be provided - in each TransformerDefinitionParameter. - usage_example: Transformer's usage example. - expected_output: Transformer's expected output. - expected_input: Transformer's expected input. - update_mask: Comma-separated list of fields to update. If omitted, - the mask is auto-generated from whichever fields are provided. - Example: "displayName,script". - api_version: API version to use for the request. Default is V1ALPHA. - - Returns: - Dict containing the updated TransformerDefinition resource. - - Raises: - APIError: If the API request fails. - """ - resolved_parameters = ( - [ - p.to_dict() if isinstance(p, TransformerDefinitionParameter) else p - for p in parameters - ] - if parameters is not None - else None - ) - - body, params = build_patch_body( - field_map=[ - ("displayName", "displayName", display_name), - ("script", "script", script), - ("scriptTimeout", "scriptTimeout", script_timeout), - ("enabled", "enabled", enabled), - ("description", "description", description), - ("parameters", "parameters", resolved_parameters), - ("usageExample", "usageExample", usage_example), - ("expectedOutput", "expectedOutput", expected_output), - ("expectedInput", "expectedInput", expected_input), - ], - update_mask=update_mask, - ) - - return chronicle_request( - client, - method="PATCH", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"transformers/{transformer_id}" - ), - api_version=api_version, - json=body, - params=params, - ) - - -def execute_integration_transformer_test( - client: "ChronicleClient", - integration_name: str, - transformer: dict[str, Any], - api_version: APIVersion | None = APIVersion.V1ALPHA, -) -> dict[str, Any]: - """Execute a test run of a transformer's Python script. - - Use this method to verify transformation logic and ensure data is being - parsed and formatted correctly before saving or deploying the transformer. - The full transformer object is required as the test can be run without - saving the transformer first. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration the transformer belongs to. - transformer: Dict containing the TransformerDefinition to test. - api_version: API version to use for the request. Default is V1ALPHA. - - Returns: - Dict containing the test execution results with the following fields: - - outputMessage: Human-readable output message set by the script. - - debugOutputMessage: The script debug output. - - resultValue: The script result value. - - Raises: - APIError: If the API request fails. - """ - return chronicle_request( - client, - method="POST", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"transformers:executeTest" - ), - api_version=api_version, - json={"transformer": transformer}, - ) - - -def get_integration_transformer_template( - client: "ChronicleClient", - integration_name: str, - api_version: APIVersion | None = APIVersion.V1ALPHA, -) -> dict[str, Any]: - """Retrieve a default Python script template for a new transformer. - - Use this method to jumpstart the development of a custom data - transformation logic by providing boilerplate code. - - Args: - client: ChronicleClient instance. - integration_name: Name of the integration to fetch the template for. - api_version: API version to use for the request. Default is V1ALPHA. - - Returns: - Dict containing the TransformerDefinition template. - - Raises: - APIError: If the API request fails. - """ - return chronicle_request( - client, - method="GET", - endpoint_path=( - f"integrations/{format_resource_id(integration_name)}/" - f"transformers:fetchTemplate" - ), - api_version=api_version, - ) diff --git a/src/secops/cli/commands/integration/connector_context_properties.py b/src/secops/cli/commands/integration/connector_context_properties.py deleted file mode 100644 index 46b2d936..00000000 --- a/src/secops/cli/commands/integration/connector_context_properties.py +++ /dev/null @@ -1,375 +0,0 @@ -# Copyright 2025 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. -# -"""Google SecOps CLI connector context properties commands""" - -import sys - -from secops.cli.utils.formatters import output_formatter -from secops.cli.utils.common_args import ( - add_pagination_args, - add_as_list_arg, -) - - -def setup_connector_context_properties_command(subparsers): - """Setup connector context properties command""" - properties_parser = subparsers.add_parser( - "connector-context-properties", - help="Manage connector context properties", - ) - lvl1 = properties_parser.add_subparsers( - dest="connector_context_properties_command", - help="Connector context properties command", - ) - - # list command - list_parser = lvl1.add_parser( - "list", help="List connector context properties" - ) - list_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - list_parser.add_argument( - "--connector-id", - type=str, - help="ID of the connector", - dest="connector_id", - required=True, - ) - list_parser.add_argument( - "--context-id", - type=str, - help="Context ID to filter properties", - dest="context_id", - ) - add_pagination_args(list_parser) - add_as_list_arg(list_parser) - list_parser.add_argument( - "--filter-string", - type=str, - help="Filter string for listing properties", - dest="filter_string", - ) - list_parser.add_argument( - "--order-by", - type=str, - help="Order by string for listing properties", - dest="order_by", - ) - list_parser.set_defaults( - func=handle_connector_context_properties_list_command, - ) - - # get command - get_parser = lvl1.add_parser( - "get", help="Get a specific connector context property" - ) - get_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - get_parser.add_argument( - "--connector-id", - type=str, - help="ID of the connector", - dest="connector_id", - required=True, - ) - get_parser.add_argument( - "--context-id", - type=str, - help="Context ID of the property", - dest="context_id", - required=True, - ) - get_parser.add_argument( - "--property-id", - type=str, - help="ID of the property to get", - dest="property_id", - required=True, - ) - get_parser.set_defaults( - func=handle_connector_context_properties_get_command - ) - - # delete command - delete_parser = lvl1.add_parser( - "delete", help="Delete a connector context property" - ) - delete_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - delete_parser.add_argument( - "--connector-id", - type=str, - help="ID of the connector", - dest="connector_id", - required=True, - ) - delete_parser.add_argument( - "--context-id", - type=str, - help="Context ID of the property", - dest="context_id", - required=True, - ) - delete_parser.add_argument( - "--property-id", - type=str, - help="ID of the property to delete", - dest="property_id", - required=True, - ) - delete_parser.set_defaults( - func=handle_connector_context_properties_delete_command - ) - - # create command - create_parser = lvl1.add_parser( - "create", help="Create a new connector context property" - ) - create_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - create_parser.add_argument( - "--connector-id", - type=str, - help="ID of the connector", - dest="connector_id", - required=True, - ) - create_parser.add_argument( - "--context-id", - type=str, - help="Context ID for the property", - dest="context_id", - required=True, - ) - create_parser.add_argument( - "--key", - type=str, - help="Key for the property", - dest="key", - required=True, - ) - create_parser.add_argument( - "--value", - type=str, - help="Value for the property", - dest="value", - required=True, - ) - create_parser.set_defaults( - func=handle_connector_context_properties_create_command - ) - - # update command - update_parser = lvl1.add_parser( - "update", help="Update a connector context property" - ) - update_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - update_parser.add_argument( - "--connector-id", - type=str, - help="ID of the connector", - dest="connector_id", - required=True, - ) - update_parser.add_argument( - "--context-id", - type=str, - help="Context ID of the property", - dest="context_id", - required=True, - ) - update_parser.add_argument( - "--property-id", - type=str, - help="ID of the property to update", - dest="property_id", - required=True, - ) - update_parser.add_argument( - "--value", - type=str, - help="New value for the property", - dest="value", - required=True, - ) - update_parser.set_defaults( - func=handle_connector_context_properties_update_command - ) - - # clear-all command - clear_parser = lvl1.add_parser( - "clear-all", help="Delete all connector context properties" - ) - clear_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - clear_parser.add_argument( - "--connector-id", - type=str, - help="ID of the connector", - dest="connector_id", - required=True, - ) - clear_parser.add_argument( - "--context-id", - type=str, - help="Context ID to clear all properties for", - dest="context_id", - required=True, - ) - clear_parser.set_defaults( - func=handle_connector_context_properties_clear_command - ) - - -def handle_connector_context_properties_list_command(args, chronicle): - """Handle connector context properties list command""" - try: - out = chronicle.list_connector_context_properties( - integration_name=args.integration_name, - connector_id=args.connector_id, - context_id=args.context_id, - page_size=args.page_size, - page_token=args.page_token, - filter_string=args.filter_string, - order_by=args.order_by, - as_list=args.as_list, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print( - f"Error listing connector context properties: {e}", file=sys.stderr - ) - sys.exit(1) - - -def handle_connector_context_properties_get_command(args, chronicle): - """Handle connector context property get command""" - try: - out = chronicle.get_connector_context_property( - integration_name=args.integration_name, - connector_id=args.connector_id, - context_id=args.context_id, - context_property_id=args.property_id, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error getting connector context property: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_connector_context_properties_delete_command(args, chronicle): - """Handle connector context property delete command""" - try: - chronicle.delete_connector_context_property( - integration_name=args.integration_name, - connector_id=args.connector_id, - context_id=args.context_id, - context_property_id=args.property_id, - ) - print( - f"Connector context property " - f"{args.property_id} deleted successfully" - ) - except Exception as e: # pylint: disable=broad-exception-caught - print( - f"Error deleting connector context property: {e}", file=sys.stderr - ) - sys.exit(1) - - -def handle_connector_context_properties_create_command(args, chronicle): - """Handle connector context property create command""" - try: - out = chronicle.create_connector_context_property( - integration_name=args.integration_name, - connector_id=args.connector_id, - context_id=args.context_id, - key=args.key, - value=args.value, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print( - f"Error creating connector context property: {e}", file=sys.stderr - ) - sys.exit(1) - - -def handle_connector_context_properties_update_command(args, chronicle): - """Handle connector context property update command""" - try: - out = chronicle.update_connector_context_property( - integration_name=args.integration_name, - connector_id=args.connector_id, - context_id=args.context_id, - context_property_id=args.property_id, - value=args.value, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print( - f"Error updating connector context property: {e}", file=sys.stderr - ) - sys.exit(1) - - -def handle_connector_context_properties_clear_command(args, chronicle): - """Handle clear all connector context properties command""" - try: - chronicle.delete_all_connector_context_properties( - integration_name=args.integration_name, - connector_id=args.connector_id, - context_id=args.context_id, - ) - print( - f"All connector context properties for context " - f"{args.context_id} cleared successfully" - ) - except Exception as e: # pylint: disable=broad-exception-caught - print( - f"Error clearing connector context properties: {e}", file=sys.stderr - ) - sys.exit(1) diff --git a/src/secops/cli/commands/integration/connector_instance_logs.py b/src/secops/cli/commands/integration/connector_instance_logs.py deleted file mode 100644 index b67e35f2..00000000 --- a/src/secops/cli/commands/integration/connector_instance_logs.py +++ /dev/null @@ -1,142 +0,0 @@ -# Copyright 2025 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. -# -"""Google SecOps CLI connector instance logs commands""" - -import sys - -from secops.cli.utils.formatters import output_formatter -from secops.cli.utils.common_args import ( - add_pagination_args, - add_as_list_arg, -) - - -def setup_connector_instance_logs_command(subparsers): - """Setup connector instance logs command""" - logs_parser = subparsers.add_parser( - "connector-instance-logs", - help="View connector instance logs", - ) - lvl1 = logs_parser.add_subparsers( - dest="connector_instance_logs_command", - help="Connector instance logs command", - ) - - # list command - list_parser = lvl1.add_parser("list", help="List connector instance logs") - list_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - list_parser.add_argument( - "--connector-id", - type=str, - help="ID of the connector", - dest="connector_id", - required=True, - ) - list_parser.add_argument( - "--connector-instance-id", - type=str, - help="ID of the connector instance", - dest="connector_instance_id", - required=True, - ) - add_pagination_args(list_parser) - add_as_list_arg(list_parser) - list_parser.add_argument( - "--filter-string", - type=str, - help="Filter string for listing logs", - dest="filter_string", - ) - list_parser.add_argument( - "--order-by", - type=str, - help="Order by string for listing logs", - dest="order_by", - ) - list_parser.set_defaults(func=handle_connector_instance_logs_list_command) - - # get command - get_parser = lvl1.add_parser( - "get", help="Get a specific connector instance log" - ) - get_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - get_parser.add_argument( - "--connector-id", - type=str, - help="ID of the connector", - dest="connector_id", - required=True, - ) - get_parser.add_argument( - "--connector-instance-id", - type=str, - help="ID of the connector instance", - dest="connector_instance_id", - required=True, - ) - get_parser.add_argument( - "--log-id", - type=str, - help="ID of the log to get", - dest="log_id", - required=True, - ) - get_parser.set_defaults(func=handle_connector_instance_logs_get_command) - - -def handle_connector_instance_logs_list_command(args, chronicle): - """Handle connector instance logs list command""" - try: - out = chronicle.list_connector_instance_logs( - integration_name=args.integration_name, - connector_id=args.connector_id, - connector_instance_id=args.connector_instance_id, - page_size=args.page_size, - page_token=args.page_token, - filter_string=args.filter_string, - order_by=args.order_by, - as_list=args.as_list, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error listing connector instance logs: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_connector_instance_logs_get_command(args, chronicle): - """Handle connector instance log get command""" - try: - out = chronicle.get_connector_instance_log( - integration_name=args.integration_name, - connector_id=args.connector_id, - connector_instance_id=args.connector_instance_id, - connector_instance_log_id=args.log_id, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error getting connector instance log: {e}", file=sys.stderr) - sys.exit(1) diff --git a/src/secops/cli/commands/integration/connector_instances.py b/src/secops/cli/commands/integration/connector_instances.py deleted file mode 100644 index df68bfde..00000000 --- a/src/secops/cli/commands/integration/connector_instances.py +++ /dev/null @@ -1,473 +0,0 @@ -# Copyright 2025 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. -# -"""Google SecOps CLI connector instances commands""" - -import sys - -from secops.cli.utils.formatters import output_formatter -from secops.cli.utils.common_args import ( - add_pagination_args, - add_as_list_arg, -) - - -def setup_connector_instances_command(subparsers): - """Setup connector instances command""" - instances_parser = subparsers.add_parser( - "connector-instances", - help="Manage connector instances", - ) - lvl1 = instances_parser.add_subparsers( - dest="connector_instances_command", - help="Connector instances command", - ) - - # list command - list_parser = lvl1.add_parser("list", help="List connector instances") - list_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - list_parser.add_argument( - "--connector-id", - type=str, - help="ID of the connector", - dest="connector_id", - required=True, - ) - add_pagination_args(list_parser) - add_as_list_arg(list_parser) - list_parser.add_argument( - "--filter-string", - type=str, - help="Filter string for listing instances", - dest="filter_string", - ) - list_parser.add_argument( - "--order-by", - type=str, - help="Order by string for listing instances", - dest="order_by", - ) - list_parser.set_defaults(func=handle_connector_instances_list_command) - - # get command - get_parser = lvl1.add_parser( - "get", help="Get a specific connector instance" - ) - get_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - get_parser.add_argument( - "--connector-id", - type=str, - help="ID of the connector", - dest="connector_id", - required=True, - ) - get_parser.add_argument( - "--connector-instance-id", - type=str, - help="ID of the connector instance to get", - dest="connector_instance_id", - required=True, - ) - get_parser.set_defaults(func=handle_connector_instances_get_command) - - # delete command - delete_parser = lvl1.add_parser( - "delete", help="Delete a connector instance" - ) - delete_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - delete_parser.add_argument( - "--connector-id", - type=str, - help="ID of the connector", - dest="connector_id", - required=True, - ) - delete_parser.add_argument( - "--connector-instance-id", - type=str, - help="ID of the connector instance to delete", - dest="connector_instance_id", - required=True, - ) - delete_parser.set_defaults(func=handle_connector_instances_delete_command) - - # create command - create_parser = lvl1.add_parser( - "create", help="Create a new connector instance" - ) - create_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - create_parser.add_argument( - "--connector-id", - type=str, - help="ID of the connector", - dest="connector_id", - required=True, - ) - create_parser.add_argument( - "--environment", - type=str, - help="Environment for the connector instance", - dest="environment", - required=True, - ) - create_parser.add_argument( - "--display-name", - type=str, - help="Display name for the connector instance", - dest="display_name", - required=True, - ) - create_parser.add_argument( - "--interval-seconds", - type=int, - help="Interval in seconds for connector execution", - dest="interval_seconds", - ) - create_parser.add_argument( - "--timeout-seconds", - type=int, - help="Timeout in seconds for connector execution", - dest="timeout_seconds", - ) - create_parser.add_argument( - "--enabled", - action="store_true", - help="Enable the connector instance", - dest="enabled", - ) - create_parser.set_defaults(func=handle_connector_instances_create_command) - - # update command - update_parser = lvl1.add_parser( - "update", help="Update a connector instance" - ) - update_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - update_parser.add_argument( - "--connector-id", - type=str, - help="ID of the connector", - dest="connector_id", - required=True, - ) - update_parser.add_argument( - "--connector-instance-id", - type=str, - help="ID of the connector instance to update", - dest="connector_instance_id", - required=True, - ) - update_parser.add_argument( - "--display-name", - type=str, - help="New display name for the connector instance", - dest="display_name", - ) - update_parser.add_argument( - "--interval-seconds", - type=int, - help="New interval in seconds for connector execution", - dest="interval_seconds", - ) - update_parser.add_argument( - "--timeout-seconds", - type=int, - help="New timeout in seconds for connector execution", - dest="timeout_seconds", - ) - update_parser.add_argument( - "--enabled", - type=str, - choices=["true", "false"], - help="Enable or disable the connector instance", - dest="enabled", - ) - update_parser.add_argument( - "--update-mask", - type=str, - help="Comma-separated list of fields to update", - dest="update_mask", - ) - update_parser.set_defaults(func=handle_connector_instances_update_command) - - # fetch-latest command - fetch_parser = lvl1.add_parser( - "fetch-latest", - help="Get the latest definition of a connector instance", - ) - fetch_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - fetch_parser.add_argument( - "--connector-id", - type=str, - help="ID of the connector", - dest="connector_id", - required=True, - ) - fetch_parser.add_argument( - "--connector-instance-id", - type=str, - help="ID of the connector instance", - dest="connector_instance_id", - required=True, - ) - fetch_parser.set_defaults( - func=handle_connector_instances_fetch_latest_command - ) - - # set-logs command - logs_parser = lvl1.add_parser( - "set-logs", - help="Enable or disable log collection for a connector instance", - ) - logs_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - logs_parser.add_argument( - "--connector-id", - type=str, - help="ID of the connector", - dest="connector_id", - required=True, - ) - logs_parser.add_argument( - "--connector-instance-id", - type=str, - help="ID of the connector instance", - dest="connector_instance_id", - required=True, - ) - logs_parser.add_argument( - "--enabled", - type=str, - choices=["true", "false"], - help="Enable or disable log collection", - dest="enabled", - required=True, - ) - logs_parser.set_defaults(func=handle_connector_instances_set_logs_command) - - # run-ondemand command - run_parser = lvl1.add_parser( - "run-ondemand", - help="Run a connector instance on demand", - ) - run_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - run_parser.add_argument( - "--connector-id", - type=str, - help="ID of the connector", - dest="connector_id", - required=True, - ) - run_parser.add_argument( - "--connector-instance-id", - type=str, - help="ID of the connector instance to run", - dest="connector_instance_id", - required=True, - ) - run_parser.set_defaults( - func=handle_connector_instances_run_ondemand_command - ) - - -def handle_connector_instances_list_command(args, chronicle): - """Handle connector instances list command""" - try: - out = chronicle.list_connector_instances( - integration_name=args.integration_name, - connector_id=args.connector_id, - page_size=args.page_size, - page_token=args.page_token, - filter_string=args.filter_string, - order_by=args.order_by, - as_list=args.as_list, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error listing connector instances: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_connector_instances_get_command(args, chronicle): - """Handle connector instance get command""" - try: - out = chronicle.get_connector_instance( - integration_name=args.integration_name, - connector_id=args.connector_id, - connector_instance_id=args.connector_instance_id, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error getting connector instance: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_connector_instances_delete_command(args, chronicle): - """Handle connector instance delete command""" - try: - chronicle.delete_connector_instance( - integration_name=args.integration_name, - connector_id=args.connector_id, - connector_instance_id=args.connector_instance_id, - ) - print( - f"Connector instance {args.connector_instance_id}" - f" deleted successfully" - ) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error deleting connector instance: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_connector_instances_create_command(args, chronicle): - """Handle connector instance create command""" - try: - out = chronicle.create_connector_instance( - integration_name=args.integration_name, - connector_id=args.connector_id, - environment=args.environment, - display_name=args.display_name, - interval_seconds=args.interval_seconds, - timeout_seconds=args.timeout_seconds, - enabled=args.enabled, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error creating connector instance: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_connector_instances_update_command(args, chronicle): - """Handle connector instance update command""" - try: - # Convert enabled string to boolean if provided - enabled = None - if args.enabled: - enabled = args.enabled.lower() == "true" - - out = chronicle.update_connector_instance( - integration_name=args.integration_name, - connector_id=args.connector_id, - connector_instance_id=args.connector_instance_id, - display_name=args.display_name, - interval_seconds=args.interval_seconds, - timeout_seconds=args.timeout_seconds, - enabled=enabled, - update_mask=args.update_mask, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error updating connector instance: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_connector_instances_fetch_latest_command(args, chronicle): - """Handle fetch latest connector instance definition command""" - try: - out = chronicle.get_connector_instance_latest_definition( - integration_name=args.integration_name, - connector_id=args.connector_id, - connector_instance_id=args.connector_instance_id, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error fetching latest connector instance: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_connector_instances_set_logs_command(args, chronicle): - """Handle set connector instance logs collection command""" - try: - enabled = args.enabled.lower() == "true" - out = chronicle.set_connector_instance_logs_collection( - integration_name=args.integration_name, - connector_id=args.connector_id, - connector_instance_id=args.connector_instance_id, - enabled=enabled, - ) - status = "enabled" if enabled else "disabled" - print(f"Log collection {status} for connector instance successfully") - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error setting connector instance logs: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_connector_instances_run_ondemand_command(args, chronicle): - """Handle run connector instance on demand command""" - try: - # Get the connector instance first - connector_instance = chronicle.get_connector_instance( - integration_name=args.integration_name, - connector_id=args.connector_id, - connector_instance_id=args.connector_instance_id, - ) - out = chronicle.run_connector_instance_on_demand( - integration_name=args.integration_name, - connector_id=args.connector_id, - connector_instance_id=args.connector_instance_id, - connector_instance=connector_instance, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print( - f"Error running connector instance on demand: {e}", file=sys.stderr - ) - sys.exit(1) diff --git a/src/secops/cli/commands/integration/connector_revisions.py b/src/secops/cli/commands/integration/connector_revisions.py deleted file mode 100644 index 779888c9..00000000 --- a/src/secops/cli/commands/integration/connector_revisions.py +++ /dev/null @@ -1,217 +0,0 @@ -# Copyright 2025 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. -# -"""Google SecOps CLI integration connector revisions commands""" - -import sys - -from secops.cli.utils.formatters import output_formatter -from secops.cli.utils.common_args import ( - add_pagination_args, - add_as_list_arg, -) - - -def setup_connector_revisions_command(subparsers): - """Setup integration connector revisions command""" - revisions_parser = subparsers.add_parser( - "connector-revisions", - help="Manage integration connector revisions", - ) - lvl1 = revisions_parser.add_subparsers( - dest="connector_revisions_command", - help="Integration connector revisions command", - ) - - # list command - list_parser = lvl1.add_parser( - "list", help="List integration connector revisions" - ) - list_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - list_parser.add_argument( - "--connector-id", - type=str, - help="ID of the connector", - dest="connector_id", - required=True, - ) - add_pagination_args(list_parser) - add_as_list_arg(list_parser) - list_parser.add_argument( - "--filter-string", - type=str, - help="Filter string for listing revisions", - dest="filter_string", - ) - list_parser.add_argument( - "--order-by", - type=str, - help="Order by string for listing revisions", - dest="order_by", - ) - list_parser.set_defaults(func=handle_connector_revisions_list_command) - - # delete command - delete_parser = lvl1.add_parser( - "delete", help="Delete an integration connector revision" - ) - delete_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - delete_parser.add_argument( - "--connector-id", - type=str, - help="ID of the connector", - dest="connector_id", - required=True, - ) - delete_parser.add_argument( - "--revision-id", - type=str, - help="ID of the revision to delete", - dest="revision_id", - required=True, - ) - delete_parser.set_defaults(func=handle_connector_revisions_delete_command) - - # create command - create_parser = lvl1.add_parser( - "create", help="Create a new integration connector revision" - ) - create_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - create_parser.add_argument( - "--connector-id", - type=str, - help="ID of the connector", - dest="connector_id", - required=True, - ) - create_parser.add_argument( - "--comment", - type=str, - help="Comment describing the revision", - dest="comment", - ) - create_parser.set_defaults(func=handle_connector_revisions_create_command) - - # rollback command - rollback_parser = lvl1.add_parser( - "rollback", help="Rollback connector to a previous revision" - ) - rollback_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - rollback_parser.add_argument( - "--connector-id", - type=str, - help="ID of the connector", - dest="connector_id", - required=True, - ) - rollback_parser.add_argument( - "--revision-id", - type=str, - help="ID of the revision to rollback to", - dest="revision_id", - required=True, - ) - rollback_parser.set_defaults( - func=handle_connector_revisions_rollback_command, - ) - - -def handle_connector_revisions_list_command(args, chronicle): - """Handle integration connector revisions list command""" - try: - out = chronicle.list_integration_connector_revisions( - integration_name=args.integration_name, - connector_id=args.connector_id, - page_size=args.page_size, - page_token=args.page_token, - filter_string=args.filter_string, - order_by=args.order_by, - as_list=args.as_list, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error listing connector revisions: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_connector_revisions_delete_command(args, chronicle): - """Handle integration connector revision delete command""" - try: - chronicle.delete_integration_connector_revision( - integration_name=args.integration_name, - connector_id=args.connector_id, - revision_id=args.revision_id, - ) - print(f"Connector revision {args.revision_id} deleted successfully") - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error deleting connector revision: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_connector_revisions_create_command(args, chronicle): - """Handle integration connector revision create command""" - try: - # Get the current connector to create a revision - connector = chronicle.get_integration_connector( - integration_name=args.integration_name, - connector_id=args.connector_id, - ) - out = chronicle.create_integration_connector_revision( - integration_name=args.integration_name, - connector_id=args.connector_id, - connector=connector, - comment=args.comment, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error creating connector revision: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_connector_revisions_rollback_command(args, chronicle): - """Handle integration connector revision rollback command""" - try: - out = chronicle.rollback_integration_connector_revision( - integration_name=args.integration_name, - connector_id=args.connector_id, - revision_id=args.revision_id, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error rolling back connector revision: {e}", file=sys.stderr) - sys.exit(1) diff --git a/src/secops/cli/commands/integration/connectors.py b/src/secops/cli/commands/integration/connectors.py deleted file mode 100644 index fe8e03ef..00000000 --- a/src/secops/cli/commands/integration/connectors.py +++ /dev/null @@ -1,325 +0,0 @@ -# Copyright 2025 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. -# -"""Google SecOps CLI integration connectors commands""" - -import sys - -from secops.cli.utils.formatters import output_formatter -from secops.cli.utils.common_args import ( - add_pagination_args, - add_as_list_arg, -) - - -def setup_connectors_command(subparsers): - """Setup integration connectors command""" - connectors_parser = subparsers.add_parser( - "connectors", - help="Manage integration connectors", - ) - lvl1 = connectors_parser.add_subparsers( - dest="connectors_command", help="Integration connectors command" - ) - - # list command - list_parser = lvl1.add_parser("list", help="List integration connectors") - list_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - add_pagination_args(list_parser) - add_as_list_arg(list_parser) - list_parser.add_argument( - "--filter-string", - type=str, - help="Filter string for listing connectors", - dest="filter_string", - ) - list_parser.add_argument( - "--order-by", - type=str, - help="Order by string for listing connectors", - dest="order_by", - ) - list_parser.set_defaults( - func=handle_connectors_list_command, - ) - - # get command - get_parser = lvl1.add_parser( - "get", help="Get integration connector details" - ) - get_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - get_parser.add_argument( - "--connector-id", - type=str, - help="ID of the connector to get", - dest="connector_id", - required=True, - ) - get_parser.set_defaults(func=handle_connectors_get_command) - - # delete command - delete_parser = lvl1.add_parser( - "delete", help="Delete an integration connector" - ) - delete_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - delete_parser.add_argument( - "--connector-id", - type=str, - help="ID of the connector to delete", - dest="connector_id", - required=True, - ) - delete_parser.set_defaults(func=handle_connectors_delete_command) - - # create command - create_parser = lvl1.add_parser( - "create", help="Create a new integration connector" - ) - create_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - create_parser.add_argument( - "--display-name", - type=str, - help="Display name for the connector", - dest="display_name", - required=True, - ) - create_parser.add_argument( - "--code", - type=str, - help="Python code for the connector", - dest="code", - required=True, - ) - create_parser.add_argument( - "--description", - type=str, - help="Description of the connector", - dest="description", - ) - create_parser.add_argument( - "--connector-id", - type=str, - help="Custom ID for the connector", - dest="connector_id", - ) - create_parser.set_defaults(func=handle_connectors_create_command) - - # update command - update_parser = lvl1.add_parser( - "update", help="Update an integration connector" - ) - update_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - update_parser.add_argument( - "--connector-id", - type=str, - help="ID of the connector to update", - dest="connector_id", - required=True, - ) - update_parser.add_argument( - "--display-name", - type=str, - help="New display name for the connector", - dest="display_name", - ) - update_parser.add_argument( - "--code", - type=str, - help="New Python code for the connector", - dest="code", - ) - update_parser.add_argument( - "--description", - type=str, - help="New description for the connector", - dest="description", - ) - update_parser.add_argument( - "--update-mask", - type=str, - help="Comma-separated list of fields to update", - dest="update_mask", - ) - update_parser.set_defaults(func=handle_connectors_update_command) - - # test command - test_parser = lvl1.add_parser( - "test", help="Execute an integration connector test" - ) - test_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - test_parser.add_argument( - "--connector-id", - type=str, - help="ID of the connector to test", - dest="connector_id", - required=True, - ) - test_parser.set_defaults(func=handle_connectors_test_command) - - # template command - template_parser = lvl1.add_parser( - "template", - help="Get a template for creating a connector", - ) - template_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - template_parser.set_defaults(func=handle_connectors_template_command) - - -def handle_connectors_list_command(args, chronicle): - """Handle integration connectors list command""" - try: - out = chronicle.list_integration_connectors( - integration_name=args.integration_name, - page_size=args.page_size, - page_token=args.page_token, - filter_string=args.filter_string, - order_by=args.order_by, - as_list=args.as_list, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error listing integration connectors: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_connectors_get_command(args, chronicle): - """Handle integration connector get command""" - try: - out = chronicle.get_integration_connector( - integration_name=args.integration_name, - connector_id=args.connector_id, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error getting integration connector: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_connectors_delete_command(args, chronicle): - """Handle integration connector delete command""" - try: - chronicle.delete_integration_connector( - integration_name=args.integration_name, - connector_id=args.connector_id, - ) - print(f"Connector {args.connector_id} deleted successfully") - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error deleting integration connector: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_connectors_create_command(args, chronicle): - """Handle integration connector create command""" - try: - out = chronicle.create_integration_connector( - integration_name=args.integration_name, - display_name=args.display_name, - code=args.code, - description=args.description, - connector_id=args.connector_id, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error creating integration connector: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_connectors_update_command(args, chronicle): - """Handle integration connector update command""" - try: - out = chronicle.update_integration_connector( - integration_name=args.integration_name, - connector_id=args.connector_id, - display_name=args.display_name, - code=args.code, - description=args.description, - update_mask=args.update_mask, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error updating integration connector: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_connectors_test_command(args, chronicle): - """Handle integration connector test command""" - try: - # First get the connector to test - connector = chronicle.get_integration_connector( - integration_name=args.integration_name, - connector_id=args.connector_id, - ) - out = chronicle.execute_integration_connector_test( - integration_name=args.integration_name, - connector_id=args.connector_id, - connector=connector, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error testing integration connector: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_connectors_template_command(args, chronicle): - """Handle get connector template command""" - try: - out = chronicle.get_integration_connector_template( - integration_name=args.integration_name, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error getting connector template: {e}", file=sys.stderr) - sys.exit(1) diff --git a/src/secops/cli/commands/integration/integration.py b/src/secops/cli/commands/integration/integration.py deleted file mode 100644 index dd73a600..00000000 --- a/src/secops/cli/commands/integration/integration.py +++ /dev/null @@ -1,775 +0,0 @@ -# Copyright 2025 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. -# -"""Google SecOps CLI integration commands""" - -import sys - -from secops.chronicle.models import ( - DiffType, - IntegrationType, - PythonVersion, - TargetMode, -) -from secops.cli.utils.formatters import output_formatter -from secops.cli.utils.common_args import ( - add_pagination_args, - add_as_list_arg, -) - - -def setup_integrations_command(subparsers): - """Setup integrations command""" - integrations_parser = subparsers.add_parser( - "integrations", help="Manage SecOps integrations" - ) - lvl1 = integrations_parser.add_subparsers( - dest="integrations_command", help="Integrations command" - ) - - # list command - list_parser = lvl1.add_parser("list", help="List integrations") - add_pagination_args(list_parser) - add_as_list_arg(list_parser) - list_parser.add_argument( - "--filter-string", - type=str, - help="Filter string for listing integrations", - dest="filter_string", - ) - list_parser.add_argument( - "--order-by", - type=str, - help="Order by string for listing integrations", - dest="order_by", - ) - list_parser.set_defaults(func=handle_integration_list_command) - - # get command - get_parser = lvl1.add_parser("get", help="Get integration details") - get_parser.add_argument( - "--integration-id", - type=str, - help="ID of the integration to get details for", - dest="integration_id", - required=True, - ) - get_parser.set_defaults(func=handle_integration_get_command) - - # delete command - delete_parser = lvl1.add_parser("delete", help="Delete an integration") - delete_parser.add_argument( - "--integration-id", - type=str, - help="ID of the integration to delete", - dest="integration_id", - required=True, - ) - delete_parser.set_defaults(func=handle_integration_delete_command) - - # create command - create_parser = lvl1.add_parser( - "create", help="Create a new custom integration" - ) - create_parser.add_argument( - "--display-name", - type=str, - help="Display name for the integration (max 150 characters)", - dest="display_name", - required=True, - ) - create_parser.add_argument( - "--staging", - action="store_true", - help="Create the integration in staging mode", - dest="staging", - ) - create_parser.add_argument( - "--description", - type=str, - help="Description of the integration (max 1,500 characters)", - dest="description", - ) - create_parser.add_argument( - "--image-base64", - type=str, - help="Integration image encoded as a base64 string (max 5 MB)", - dest="image_base64", - ) - create_parser.add_argument( - "--svg-icon", - type=str, - help="Integration SVG icon string (max 1 MB)", - dest="svg_icon", - ) - create_parser.add_argument( - "--python-version", - type=str, - choices=[v.value for v in PythonVersion], - help="Python version for the integration", - dest="python_version", - ) - create_parser.add_argument( - "--integration-type", - type=str, - choices=[t.value for t in IntegrationType], - help="Integration type", - dest="integration_type", - ) - create_parser.set_defaults(func=handle_integration_create_command) - - # download command - download_parser = lvl1.add_parser( - "download", - help="Download an integration package as a ZIP file", - ) - download_parser.add_argument( - "--integration-id", - type=str, - help="ID of the integration to download", - dest="integration_id", - required=True, - ) - download_parser.add_argument( - "--output-file", - type=str, - help="Path to write the downloaded ZIP file to", - dest="output_file", - required=True, - ) - download_parser.set_defaults(func=handle_integration_download_command) - - # download-dependency command - download_dep_parser = lvl1.add_parser( - "download-dependency", - help="Download a Python dependency for a custom integration", - ) - download_dep_parser.add_argument( - "--integration-id", - type=str, - help="ID of the integration", - dest="integration_id", - required=True, - ) - download_dep_parser.add_argument( - "--dependency-name", - type=str, - help=( - "Dependency name to download. Can include version or " - "repository, e.g. 'requests==2.31.0'" - ), - dest="dependency_name", - required=True, - ) - download_dep_parser.set_defaults( - func=handle_download_integration_dependency_command - ) - - # export-items command - export_items_parser = lvl1.add_parser( - "export-items", - help="Export specific items from an integration as a ZIP file", - ) - export_items_parser.add_argument( - "--integration-id", - type=str, - help="ID of the integration to export items from", - dest="integration_id", - required=True, - ) - export_items_parser.add_argument( - "--output-file", - type=str, - help="Path to write the exported ZIP file to", - dest="output_file", - required=True, - ) - export_items_parser.add_argument( - "--actions", - type=str, - nargs="+", - help="IDs of actions to export", - dest="actions", - ) - export_items_parser.add_argument( - "--jobs", - type=str, - nargs="+", - help="IDs of jobs to export", - dest="jobs", - ) - export_items_parser.add_argument( - "--connectors", - type=str, - nargs="+", - help="IDs of connectors to export", - dest="connectors", - ) - export_items_parser.add_argument( - "--managers", - type=str, - nargs="+", - help="IDs of managers to export", - dest="managers", - ) - export_items_parser.add_argument( - "--transformers", - type=str, - nargs="+", - help="IDs of transformers to export", - dest="transformers", - ) - export_items_parser.add_argument( - "--logical-operators", - type=str, - nargs="+", - help="IDs of logical operators to export", - dest="logical_operators", - ) - export_items_parser.set_defaults( - func=handle_export_integration_items_command - ) - - # affected-items command - affected_parser = lvl1.add_parser( - "affected-items", - help="Get items affected by changes to an integration", - ) - affected_parser.add_argument( - "--integration-id", - type=str, - help="ID of the integration to check", - dest="integration_id", - required=True, - ) - affected_parser.set_defaults( - func=handle_get_integration_affected_items_command - ) - - # agent-integrations command - agent_parser = lvl1.add_parser( - "agent-integrations", - help="Get integrations installed on a specific agent", - ) - agent_parser.add_argument( - "--agent-id", - type=str, - help="Identifier of the agent", - dest="agent_id", - required=True, - ) - agent_parser.set_defaults(func=handle_get_agent_integrations_command) - - # dependencies command - deps_parser = lvl1.add_parser( - "dependencies", - help="Get Python dependencies for a custom integration", - ) - deps_parser.add_argument( - "--integration-id", - type=str, - help="ID of the integration", - dest="integration_id", - required=True, - ) - deps_parser.set_defaults(func=handle_get_integration_dependencies_command) - - # restricted-agents command - restricted_parser = lvl1.add_parser( - "restricted-agents", - help="Get agents restricted from running an updated integration", - ) - restricted_parser.add_argument( - "--integration-id", - type=str, - help="ID of the integration", - dest="integration_id", - required=True, - ) - restricted_parser.add_argument( - "--required-python-version", - type=str, - choices=[v.value for v in PythonVersion], - help="Python version required for the updated integration", - dest="required_python_version", - required=True, - ) - restricted_parser.add_argument( - "--push-request", - action="store_true", - help="Indicates the integration is being pushed to a different mode", - dest="push_request", - ) - restricted_parser.set_defaults( - func=handle_get_integration_restricted_agents_command - ) - - # diff command - diff_parser = lvl1.add_parser( - "diff", help="Get the configuration diff for an integration" - ) - diff_parser.add_argument( - "--integration-id", - type=str, - help="ID of the integration", - dest="integration_id", - required=True, - ) - diff_parser.add_argument( - "--diff-type", - type=str, - choices=[d.value for d in DiffType], - help=( - "Type of diff to retrieve. " - "COMMERCIAL: diff against the marketplace version. " - "PRODUCTION: diff between staging and production. " - "STAGING: diff between production and staging." - ), - dest="diff_type", - default=DiffType.COMMERCIAL.value, - ) - diff_parser.set_defaults(func=handle_get_integration_diff_command) - - # transition command - transition_parser = lvl1.add_parser( - "transition", - help="Transition an integration to production or staging", - ) - transition_parser.add_argument( - "--integration-id", - type=str, - help="ID of the integration to transition", - dest="integration_id", - required=True, - ) - transition_parser.add_argument( - "--target-mode", - type=str, - choices=[t.value for t in TargetMode], - help="Target mode to transition the integration to", - dest="target_mode", - required=True, - ) - transition_parser.set_defaults(func=handle_transition_integration_command) - - # update command - update_parser = lvl1.add_parser( - "update", help="Update an existing integration's metadata" - ) - update_parser.add_argument( - "--integration-id", - type=str, - help="ID of the integration to update", - dest="integration_id", - required=True, - ) - update_parser.add_argument( - "--display-name", - type=str, - help="New display name for the integration (max 150 characters)", - dest="display_name", - ) - update_parser.add_argument( - "--description", - type=str, - help="New description for the integration (max 1,500 characters)", - dest="description", - ) - update_parser.add_argument( - "--image-base64", - type=str, - help="New integration image encoded as a base64 string (max 5 MB)", - dest="image_base64", - ) - update_parser.add_argument( - "--svg-icon", - type=str, - help="New integration SVG icon string (max 1 MB)", - dest="svg_icon", - ) - update_parser.add_argument( - "--python-version", - type=str, - choices=[v.value for v in PythonVersion], - help="Python version for the integration", - dest="python_version", - ) - update_parser.add_argument( - "--integration-type", - type=str, - choices=[t.value for t in IntegrationType], - help="Integration type", - dest="integration_type", - ) - update_parser.add_argument( - "--staging", - action="store_true", - help="Set the integration to staging mode", - dest="staging", - ) - update_parser.add_argument( - "--dependencies-to-remove", - type=str, - nargs="+", - help="List of dependency names to remove from the integration", - dest="dependencies_to_remove", - ) - update_parser.add_argument( - "--update-mask", - type=str, - help=( - "Comma-separated list of fields to update. " - "If not provided, all supplied fields are updated." - ), - dest="update_mask", - ) - update_parser.set_defaults(func=handle_update_integration_command) - - # update-custom command - update_custom_parser = lvl1.add_parser( - "update-custom", - help=( - "Update a custom integration definition including " - "parameters and dependencies" - ), - ) - update_custom_parser.add_argument( - "--integration-id", - type=str, - help="ID of the integration to update", - dest="integration_id", - required=True, - ) - update_custom_parser.add_argument( - "--display-name", - type=str, - help="New display name for the integration (max 150 characters)", - dest="display_name", - ) - update_custom_parser.add_argument( - "--description", - type=str, - help="New description for the integration (max 1,500 characters)", - dest="description", - ) - update_custom_parser.add_argument( - "--image-base64", - type=str, - help="New integration image encoded as a base64 string (max 5 MB)", - dest="image_base64", - ) - update_custom_parser.add_argument( - "--svg-icon", - type=str, - help="New integration SVG icon string (max 1 MB)", - dest="svg_icon", - ) - update_custom_parser.add_argument( - "--python-version", - type=str, - choices=[v.value for v in PythonVersion], - help="Python version for the integration", - dest="python_version", - ) - update_custom_parser.add_argument( - "--integration-type", - type=str, - choices=[t.value for t in IntegrationType], - help="Integration type", - dest="integration_type", - ) - update_custom_parser.add_argument( - "--staging", - action="store_true", - help="Set the integration to staging mode", - dest="staging", - ) - update_custom_parser.add_argument( - "--dependencies-to-remove", - type=str, - nargs="+", - help="List of dependency names to remove from the integration", - dest="dependencies_to_remove", - ) - update_custom_parser.add_argument( - "--update-mask", - type=str, - help=( - "Comma-separated list of fields to update. " - "If not provided, all supplied fields are updated." - ), - dest="update_mask", - ) - update_custom_parser.set_defaults( - func=handle_updated_custom_integration_command - ) - - -# --------------------------------------------------------------------------- -# Handlers -# --------------------------------------------------------------------------- - - -def handle_integration_list_command(args, chronicle): - """Handle list integrations command""" - try: - out = chronicle.list_integrations( - page_size=args.page_size, - page_token=args.page_token, - filter_string=args.filter_string, - order_by=args.order_by, - as_list=args.as_list, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error listing integrations: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_integration_get_command(args, chronicle): - """Handle get integration command""" - try: - out = chronicle.get_integration( - integration_name=args.integration_id, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error getting integration: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_integration_delete_command(args, chronicle): - """Handle delete integration command""" - try: - chronicle.delete_integration( - integration_name=args.integration_id, - ) - print(f"Integration {args.integration_id} deleted successfully.") - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error deleting integration: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_integration_create_command(args, chronicle): - """Handle create integration command""" - try: - out = chronicle.create_integration( - display_name=args.display_name, - staging=args.staging, - description=args.description, - image_base64=args.image_base64, - svg_icon=args.svg_icon, - python_version=( - PythonVersion(args.python_version) - if args.python_version - else None - ), - integration_type=( - IntegrationType(args.integration_type) - if args.integration_type - else None - ), - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error creating integration: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_integration_download_command(args, chronicle): - """Handle download integration command""" - try: - zip_bytes = chronicle.download_integration( - integration_name=args.integration_id, - ) - with open(args.output_file, "wb") as f: - f.write(zip_bytes) - print( - f"Integration {args.integration_id} downloaded to " - f"{args.output_file}." - ) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error downloading integration: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_download_integration_dependency_command(args, chronicle): - """Handle download integration dependencies command""" - try: - out = chronicle.download_integration_dependency( - integration_name=args.integration_id, - dependency_name=args.dependency_name, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print( - f"Error downloading integration dependencies: {e}", file=sys.stderr - ) - sys.exit(1) - - -def handle_export_integration_items_command(args, chronicle): - """Handle export integration items command""" - try: - zip_bytes = chronicle.export_integration_items( - integration_name=args.integration_id, - actions=args.actions, - jobs=args.jobs, - connectors=args.connectors, - managers=args.managers, - transformers=args.transformers, - logical_operators=args.logical_operators, - ) - with open(args.output_file, "wb") as f: - f.write(zip_bytes) - print(f"Integration items exported to {args.output_file}.") - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error exporting integration items: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_get_integration_affected_items_command(args, chronicle): - """Handle get integration affected items command""" - try: - out = chronicle.get_integration_affected_items( - integration_name=args.integration_id, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error getting integration affected items: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_get_agent_integrations_command(args, chronicle): - """Handle get agent integration command""" - try: - out = chronicle.get_agent_integrations( - agent_id=args.agent_id, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error getting agent integration: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_get_integration_dependencies_command(args, chronicle): - """Handle get integration dependencies command""" - try: - out = chronicle.get_integration_dependencies( - integration_name=args.integration_id, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error getting integration dependencies: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_get_integration_restricted_agents_command(args, chronicle): - """Handle get integration restricted agent command""" - try: - out = chronicle.get_integration_restricted_agents( - integration_name=args.integration_id, - required_python_version=PythonVersion(args.required_python_version), - push_request=args.push_request, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print( - f"Error getting integration restricted agent: {e}", file=sys.stderr - ) - sys.exit(1) - - -def handle_get_integration_diff_command(args, chronicle): - """Handle get integration diff command""" - try: - out = chronicle.get_integration_diff( - integration_name=args.integration_id, - diff_type=DiffType(args.diff_type), - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error getting integration diff: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_transition_integration_command(args, chronicle): - """Handle transition integration command""" - try: - out = chronicle.transition_integration( - integration_name=args.integration_id, - target_mode=TargetMode(args.target_mode), - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error transitioning integration: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_update_integration_command(args, chronicle): - """Handle update integration command""" - try: - out = chronicle.update_integration( - integration_name=args.integration_id, - display_name=args.display_name, - description=args.description, - image_base64=args.image_base64, - svg_icon=args.svg_icon, - python_version=( - PythonVersion(args.python_version) - if args.python_version - else None - ), - integration_type=( - IntegrationType(args.integration_type) - if args.integration_type - else None - ), - staging=args.staging or None, - dependencies_to_remove=args.dependencies_to_remove, - update_mask=args.update_mask, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error updating integration: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_updated_custom_integration_command(args, chronicle): - """Handle update custom integration command""" - try: - out = chronicle.update_custom_integration( - integration_name=args.integration_id, - display_name=args.display_name, - description=args.description, - image_base64=args.image_base64, - svg_icon=args.svg_icon, - python_version=( - PythonVersion(args.python_version) - if args.python_version - else None - ), - integration_type=( - IntegrationType(args.integration_type) - if args.integration_type - else None - ), - staging=args.staging or None, - dependencies_to_remove=args.dependencies_to_remove, - update_mask=args.update_mask, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error updating custom integration: {e}", file=sys.stderr) - sys.exit(1) diff --git a/src/secops/cli/commands/integration/integration_client.py b/src/secops/cli/commands/integration/integration_client.py index d84bd383..581bfb29 100644 --- a/src/secops/cli/commands/integration/integration_client.py +++ b/src/secops/cli/commands/integration/integration_client.py @@ -15,27 +15,10 @@ """Top level arguments for integration commands""" from secops.cli.commands.integration import ( - marketplace_integration, - integration, actions, action_revisions, - connectors, - connector_revisions, - connector_context_properties, - connector_instance_logs, - connector_instances, - jobs, - job_revisions, - job_context_properties, - job_instance_logs, - job_instances, managers, manager_revisions, - integration_instances, - transformers, - transformer_revisions, - logical_operators, - logical_operator_revisions, ) @@ -49,26 +32,7 @@ def setup_integrations_command(subparsers): ) # Setup all subcommands under `integration` - integration.setup_integrations_command(lvl1) - integration_instances.setup_integration_instances_command(lvl1) - transformers.setup_transformers_command(lvl1) - transformer_revisions.setup_transformer_revisions_command(lvl1) - logical_operators.setup_logical_operators_command(lvl1) - logical_operator_revisions.setup_logical_operator_revisions_command(lvl1) actions.setup_actions_command(lvl1) action_revisions.setup_action_revisions_command(lvl1) - connectors.setup_connectors_command(lvl1) - connector_revisions.setup_connector_revisions_command(lvl1) - connector_context_properties.setup_connector_context_properties_command( - lvl1 - ) - connector_instance_logs.setup_connector_instance_logs_command(lvl1) - connector_instances.setup_connector_instances_command(lvl1) - jobs.setup_jobs_command(lvl1) - job_revisions.setup_job_revisions_command(lvl1) - job_context_properties.setup_job_context_properties_command(lvl1) - job_instance_logs.setup_job_instance_logs_command(lvl1) - job_instances.setup_job_instances_command(lvl1) managers.setup_managers_command(lvl1) manager_revisions.setup_manager_revisions_command(lvl1) - marketplace_integration.setup_marketplace_integrations_command(lvl1) diff --git a/src/secops/cli/commands/integration/integration_instances.py b/src/secops/cli/commands/integration/integration_instances.py deleted file mode 100644 index 2d375346..00000000 --- a/src/secops/cli/commands/integration/integration_instances.py +++ /dev/null @@ -1,392 +0,0 @@ -# Copyright 2025 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. -# -"""Google SecOps CLI integration instances commands""" - -import json -import sys - -from secops.cli.utils.formatters import output_formatter -from secops.cli.utils.common_args import ( - add_pagination_args, - add_as_list_arg, -) - - -def setup_integration_instances_command(subparsers): - """Setup integration instances command""" - instances_parser = subparsers.add_parser( - "instances", - help="Manage integration instances", - ) - lvl1 = instances_parser.add_subparsers( - dest="integration_instances_command", - help="Integration instances command", - ) - - # list command - list_parser = lvl1.add_parser("list", help="List integration instances") - list_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - add_pagination_args(list_parser) - add_as_list_arg(list_parser) - list_parser.add_argument( - "--filter-string", - type=str, - help="Filter string for listing instances", - dest="filter_string", - ) - list_parser.add_argument( - "--order-by", - type=str, - help="Order by string for listing instances", - dest="order_by", - ) - list_parser.set_defaults(func=handle_integration_instances_list_command) - - # get command - get_parser = lvl1.add_parser("get", help="Get integration instance details") - get_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - get_parser.add_argument( - "--instance-id", - type=str, - help="ID of the instance to get", - dest="instance_id", - required=True, - ) - get_parser.set_defaults(func=handle_integration_instances_get_command) - - # delete command - delete_parser = lvl1.add_parser( - "delete", help="Delete an integration instance" - ) - delete_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - delete_parser.add_argument( - "--instance-id", - type=str, - help="ID of the instance to delete", - dest="instance_id", - required=True, - ) - delete_parser.set_defaults(func=handle_integration_instances_delete_command) - - # create command - create_parser = lvl1.add_parser( - "create", help="Create a new integration instance" - ) - create_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - create_parser.add_argument( - "--display-name", - type=str, - help="Display name for the instance", - dest="display_name", - required=True, - ) - create_parser.add_argument( - "--environment", - type=str, - help="Environment name for the instance", - dest="environment", - required=True, - ) - create_parser.add_argument( - "--description", - type=str, - help="Description of the instance", - dest="description", - ) - create_parser.add_argument( - "--instance-id", - type=str, - help="Custom ID for the instance", - dest="instance_id", - ) - create_parser.add_argument( - "--config", - type=str, - help="JSON string of instance configuration", - dest="config", - ) - create_parser.set_defaults(func=handle_integration_instances_create_command) - - # update command - update_parser = lvl1.add_parser( - "update", help="Update an integration instance" - ) - update_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - update_parser.add_argument( - "--instance-id", - type=str, - help="ID of the instance to update", - dest="instance_id", - required=True, - ) - update_parser.add_argument( - "--display-name", - type=str, - help="New display name for the instance", - dest="display_name", - ) - update_parser.add_argument( - "--description", - type=str, - help="New description for the instance", - dest="description", - ) - update_parser.add_argument( - "--config", - type=str, - help="JSON string of new instance configuration", - dest="config", - ) - update_parser.add_argument( - "--update-mask", - type=str, - help="Comma-separated list of fields to update", - dest="update_mask", - ) - update_parser.set_defaults(func=handle_integration_instances_update_command) - - # test command - test_parser = lvl1.add_parser( - "test", help="Execute an integration instance test" - ) - test_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - test_parser.add_argument( - "--instance-id", - type=str, - help="ID of the instance to test", - dest="instance_id", - required=True, - ) - test_parser.set_defaults(func=handle_integration_instances_test_command) - - # get-affected-items command - affected_parser = lvl1.add_parser( - "get-affected-items", - help="Get items affected by an integration instance", - ) - affected_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - affected_parser.add_argument( - "--instance-id", - type=str, - help="ID of the instance", - dest="instance_id", - required=True, - ) - affected_parser.set_defaults( - func=handle_integration_instances_get_affected_items_command - ) - - # get-default command - default_parser = lvl1.add_parser( - "get-default", - help="Get the default integration instance", - ) - default_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - default_parser.set_defaults( - func=handle_integration_instances_get_default_command - ) - - -def handle_integration_instances_list_command(args, chronicle): - """Handle integration instances list command""" - try: - out = chronicle.list_integration_instances( - integration_name=args.integration_name, - page_size=args.page_size, - page_token=args.page_token, - filter_string=args.filter_string, - order_by=args.order_by, - as_list=args.as_list, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error listing integration instances: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_integration_instances_get_command(args, chronicle): - """Handle integration instance get command""" - try: - out = chronicle.get_integration_instance( - integration_name=args.integration_name, - integration_instance_id=args.instance_id, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error getting integration instance: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_integration_instances_delete_command(args, chronicle): - """Handle integration instance delete command""" - try: - chronicle.delete_integration_instance( - integration_name=args.integration_name, - integration_instance_id=args.instance_id, - ) - print(f"Integration instance {args.instance_id} deleted successfully") - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error deleting integration instance: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_integration_instances_create_command(args, chronicle): - """Handle integration instance create command""" - try: - # Parse config if provided - - config = None - if args.config: - config = json.loads(args.config) - - out = chronicle.create_integration_instance( - integration_name=args.integration_name, - display_name=args.display_name, - environment=args.environment, - description=args.description, - integration_instance_id=args.instance_id, - config=config, - ) - output_formatter(out, getattr(args, "output", "json")) - except json.JSONDecodeError as e: - print(f"Error parsing config JSON: {e}", file=sys.stderr) - sys.exit(1) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error creating integration instance: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_integration_instances_update_command(args, chronicle): - """Handle integration instance update command""" - try: - # Parse config if provided - - config = None - if args.config: - config = json.loads(args.config) - - out = chronicle.update_integration_instance( - integration_name=args.integration_name, - integration_instance_id=args.instance_id, - display_name=args.display_name, - description=args.description, - config=config, - update_mask=args.update_mask, - ) - output_formatter(out, getattr(args, "output", "json")) - except json.JSONDecodeError as e: - print(f"Error parsing config JSON: {e}", file=sys.stderr) - sys.exit(1) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error updating integration instance: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_integration_instances_test_command(args, chronicle): - """Handle integration instance test command""" - try: - # Get the instance first - instance = chronicle.get_integration_instance( - integration_name=args.integration_name, - integration_instance_id=args.instance_id, - ) - - out = chronicle.execute_integration_instance_test( - integration_name=args.integration_name, - integration_instance_id=args.instance_id, - integration_instance=instance, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error testing integration instance: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_integration_instances_get_affected_items_command(args, chronicle): - """Handle get integration instance affected items command""" - try: - out = chronicle.get_integration_instance_affected_items( - integration_name=args.integration_name, - integration_instance_id=args.instance_id, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print( - f"Error getting integration instance affected items: {e}", - file=sys.stderr, - ) - sys.exit(1) - - -def handle_integration_instances_get_default_command(args, chronicle): - """Handle get default integration instance command""" - try: - out = chronicle.get_default_integration_instance( - integration_name=args.integration_name, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print( - f"Error getting default integration instance: {e}", file=sys.stderr - ) - sys.exit(1) diff --git a/src/secops/cli/commands/integration/job_context_properties.py b/src/secops/cli/commands/integration/job_context_properties.py deleted file mode 100644 index 5da5cdb3..00000000 --- a/src/secops/cli/commands/integration/job_context_properties.py +++ /dev/null @@ -1,354 +0,0 @@ -# Copyright 2025 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. -# -"""Google SecOps CLI job context properties commands""" - -import sys - -from secops.cli.utils.formatters import output_formatter -from secops.cli.utils.common_args import ( - add_pagination_args, - add_as_list_arg, -) - - -def setup_job_context_properties_command(subparsers): - """Setup job context properties command""" - properties_parser = subparsers.add_parser( - "job-context-properties", - help="Manage job context properties", - ) - lvl1 = properties_parser.add_subparsers( - dest="job_context_properties_command", - help="Job context properties command", - ) - - # list command - list_parser = lvl1.add_parser("list", help="List job context properties") - list_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - list_parser.add_argument( - "--job-id", - type=str, - help="ID of the job", - dest="job_id", - required=True, - ) - list_parser.add_argument( - "--context-id", - type=str, - help="Context ID to filter properties", - dest="context_id", - ) - add_pagination_args(list_parser) - add_as_list_arg(list_parser) - list_parser.add_argument( - "--filter-string", - type=str, - help="Filter string for listing properties", - dest="filter_string", - ) - list_parser.add_argument( - "--order-by", - type=str, - help="Order by string for listing properties", - dest="order_by", - ) - list_parser.set_defaults(func=handle_job_context_properties_list_command) - - # get command - get_parser = lvl1.add_parser( - "get", help="Get a specific job context property" - ) - get_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - get_parser.add_argument( - "--job-id", - type=str, - help="ID of the job", - dest="job_id", - required=True, - ) - get_parser.add_argument( - "--context-id", - type=str, - help="Context ID of the property", - dest="context_id", - required=True, - ) - get_parser.add_argument( - "--property-id", - type=str, - help="ID of the property to get", - dest="property_id", - required=True, - ) - get_parser.set_defaults(func=handle_job_context_properties_get_command) - - # delete command - delete_parser = lvl1.add_parser( - "delete", help="Delete a job context property" - ) - delete_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - delete_parser.add_argument( - "--job-id", - type=str, - help="ID of the job", - dest="job_id", - required=True, - ) - delete_parser.add_argument( - "--context-id", - type=str, - help="Context ID of the property", - dest="context_id", - required=True, - ) - delete_parser.add_argument( - "--property-id", - type=str, - help="ID of the property to delete", - dest="property_id", - required=True, - ) - delete_parser.set_defaults( - func=handle_job_context_properties_delete_command - ) - - # create command - create_parser = lvl1.add_parser( - "create", help="Create a new job context property" - ) - create_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - create_parser.add_argument( - "--job-id", - type=str, - help="ID of the job", - dest="job_id", - required=True, - ) - create_parser.add_argument( - "--context-id", - type=str, - help="Context ID for the property", - dest="context_id", - required=True, - ) - create_parser.add_argument( - "--key", - type=str, - help="Key for the property", - dest="key", - required=True, - ) - create_parser.add_argument( - "--value", - type=str, - help="Value for the property", - dest="value", - required=True, - ) - create_parser.set_defaults( - func=handle_job_context_properties_create_command - ) - - # update command - update_parser = lvl1.add_parser( - "update", help="Update a job context property" - ) - update_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - update_parser.add_argument( - "--job-id", - type=str, - help="ID of the job", - dest="job_id", - required=True, - ) - update_parser.add_argument( - "--context-id", - type=str, - help="Context ID of the property", - dest="context_id", - required=True, - ) - update_parser.add_argument( - "--property-id", - type=str, - help="ID of the property to update", - dest="property_id", - required=True, - ) - update_parser.add_argument( - "--value", - type=str, - help="New value for the property", - dest="value", - required=True, - ) - update_parser.set_defaults( - func=handle_job_context_properties_update_command - ) - - # clear-all command - clear_parser = lvl1.add_parser( - "clear-all", help="Delete all job context properties" - ) - clear_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - clear_parser.add_argument( - "--job-id", - type=str, - help="ID of the job", - dest="job_id", - required=True, - ) - clear_parser.add_argument( - "--context-id", - type=str, - help="Context ID to clear all properties for", - dest="context_id", - required=True, - ) - clear_parser.set_defaults(func=handle_job_context_properties_clear_command) - - -def handle_job_context_properties_list_command(args, chronicle): - """Handle job context properties list command""" - try: - out = chronicle.list_job_context_properties( - integration_name=args.integration_name, - job_id=args.job_id, - context_id=args.context_id, - page_size=args.page_size, - page_token=args.page_token, - filter_string=args.filter_string, - order_by=args.order_by, - as_list=args.as_list, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error listing job context properties: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_job_context_properties_get_command(args, chronicle): - """Handle job context property get command""" - try: - out = chronicle.get_job_context_property( - integration_name=args.integration_name, - job_id=args.job_id, - context_id=args.context_id, - context_property_id=args.property_id, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error getting job context property: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_job_context_properties_delete_command(args, chronicle): - """Handle job context property delete command""" - try: - chronicle.delete_job_context_property( - integration_name=args.integration_name, - job_id=args.job_id, - context_id=args.context_id, - context_property_id=args.property_id, - ) - print(f"Job context property {args.property_id} deleted successfully") - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error deleting job context property: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_job_context_properties_create_command(args, chronicle): - """Handle job context property create command""" - try: - out = chronicle.create_job_context_property( - integration_name=args.integration_name, - job_id=args.job_id, - context_id=args.context_id, - key=args.key, - value=args.value, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error creating job context property: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_job_context_properties_update_command(args, chronicle): - """Handle job context property update command""" - try: - out = chronicle.update_job_context_property( - integration_name=args.integration_name, - job_id=args.job_id, - context_id=args.context_id, - context_property_id=args.property_id, - value=args.value, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error updating job context property: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_job_context_properties_clear_command(args, chronicle): - """Handle clear all job context properties command""" - try: - chronicle.delete_all_job_context_properties( - integration_name=args.integration_name, - job_id=args.job_id, - context_id=args.context_id, - ) - print( - f"All job context properties for context " - f"{args.context_id} cleared successfully" - ) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error clearing job context properties: {e}", file=sys.stderr) - sys.exit(1) diff --git a/src/secops/cli/commands/integration/job_instance_logs.py b/src/secops/cli/commands/integration/job_instance_logs.py deleted file mode 100644 index d18e2ad4..00000000 --- a/src/secops/cli/commands/integration/job_instance_logs.py +++ /dev/null @@ -1,140 +0,0 @@ -# Copyright 2025 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. -# -"""Google SecOps CLI job instance logs commands""" - -import sys - -from secops.cli.utils.formatters import output_formatter -from secops.cli.utils.common_args import ( - add_pagination_args, - add_as_list_arg, -) - - -def setup_job_instance_logs_command(subparsers): - """Setup job instance logs command""" - logs_parser = subparsers.add_parser( - "job-instance-logs", - help="View job instance logs", - ) - lvl1 = logs_parser.add_subparsers( - dest="job_instance_logs_command", - help="Job instance logs command", - ) - - # list command - list_parser = lvl1.add_parser("list", help="List job instance logs") - list_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - list_parser.add_argument( - "--job-id", - type=str, - help="ID of the job", - dest="job_id", - required=True, - ) - list_parser.add_argument( - "--job-instance-id", - type=str, - help="ID of the job instance", - dest="job_instance_id", - required=True, - ) - add_pagination_args(list_parser) - add_as_list_arg(list_parser) - list_parser.add_argument( - "--filter-string", - type=str, - help="Filter string for listing logs", - dest="filter_string", - ) - list_parser.add_argument( - "--order-by", - type=str, - help="Order by string for listing logs", - dest="order_by", - ) - list_parser.set_defaults(func=handle_job_instance_logs_list_command) - - # get command - get_parser = lvl1.add_parser("get", help="Get a specific job instance log") - get_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - get_parser.add_argument( - "--job-id", - type=str, - help="ID of the job", - dest="job_id", - required=True, - ) - get_parser.add_argument( - "--job-instance-id", - type=str, - help="ID of the job instance", - dest="job_instance_id", - required=True, - ) - get_parser.add_argument( - "--log-id", - type=str, - help="ID of the log to get", - dest="log_id", - required=True, - ) - get_parser.set_defaults(func=handle_job_instance_logs_get_command) - - -def handle_job_instance_logs_list_command(args, chronicle): - """Handle job instance logs list command""" - try: - out = chronicle.list_job_instance_logs( - integration_name=args.integration_name, - job_id=args.job_id, - job_instance_id=args.job_instance_id, - page_size=args.page_size, - page_token=args.page_token, - filter_string=args.filter_string, - order_by=args.order_by, - as_list=args.as_list, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error listing job instance logs: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_job_instance_logs_get_command(args, chronicle): - """Handle job instance log get command""" - try: - out = chronicle.get_job_instance_log( - integration_name=args.integration_name, - job_id=args.job_id, - job_instance_id=args.job_instance_id, - job_instance_log_id=args.log_id, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error getting job instance log: {e}", file=sys.stderr) - sys.exit(1) diff --git a/src/secops/cli/commands/integration/job_instances.py b/src/secops/cli/commands/integration/job_instances.py deleted file mode 100644 index 53c9a202..00000000 --- a/src/secops/cli/commands/integration/job_instances.py +++ /dev/null @@ -1,407 +0,0 @@ -# Copyright 2025 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. -# -"""Google SecOps CLI integration job instances commands""" - -import json -import sys - -from secops.cli.utils.formatters import output_formatter -from secops.cli.utils.common_args import ( - add_pagination_args, - add_as_list_arg, -) - - -def setup_job_instances_command(subparsers): - """Setup integration job instances command""" - instances_parser = subparsers.add_parser( - "job-instances", - help="Manage job instances", - ) - lvl1 = instances_parser.add_subparsers( - dest="job_instances_command", - help="Job instances command", - ) - - # list command - list_parser = lvl1.add_parser("list", help="List job instances") - list_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - list_parser.add_argument( - "--job-id", - type=str, - help="ID of the job", - dest="job_id", - required=True, - ) - add_pagination_args(list_parser) - add_as_list_arg(list_parser) - list_parser.add_argument( - "--filter-string", - type=str, - help="Filter string for listing instances", - dest="filter_string", - ) - list_parser.add_argument( - "--order-by", - type=str, - help="Order by string for listing instances", - dest="order_by", - ) - list_parser.set_defaults(func=handle_job_instances_list_command) - - # get command - get_parser = lvl1.add_parser("get", help="Get a specific job instance") - get_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - get_parser.add_argument( - "--job-id", - type=str, - help="ID of the job", - dest="job_id", - required=True, - ) - get_parser.add_argument( - "--job-instance-id", - type=str, - help="ID of the job instance to get", - dest="job_instance_id", - required=True, - ) - get_parser.set_defaults(func=handle_job_instances_get_command) - - # delete command - delete_parser = lvl1.add_parser("delete", help="Delete a job instance") - delete_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - delete_parser.add_argument( - "--job-id", - type=str, - help="ID of the job", - dest="job_id", - required=True, - ) - delete_parser.add_argument( - "--job-instance-id", - type=str, - help="ID of the job instance to delete", - dest="job_instance_id", - required=True, - ) - delete_parser.set_defaults(func=handle_job_instances_delete_command) - - # create command - create_parser = lvl1.add_parser("create", help="Create a new job instance") - create_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - create_parser.add_argument( - "--job-id", - type=str, - help="ID of the job", - dest="job_id", - required=True, - ) - create_parser.add_argument( - "--environment", - type=str, - help="Environment for the job instance", - dest="environment", - required=True, - ) - create_parser.add_argument( - "--display-name", - type=str, - help="Display name for the job instance", - dest="display_name", - required=True, - ) - create_parser.add_argument( - "--schedule", - type=str, - help="Cron schedule for the job instance", - dest="schedule", - ) - create_parser.add_argument( - "--timeout-seconds", - type=int, - help="Timeout in seconds for job execution", - dest="timeout_seconds", - ) - create_parser.add_argument( - "--enabled", - action="store_true", - help="Enable the job instance", - dest="enabled", - ) - create_parser.add_argument( - "--parameters", - type=str, - help="JSON string of job parameters", - dest="parameters", - ) - create_parser.set_defaults(func=handle_job_instances_create_command) - - # update command - update_parser = lvl1.add_parser("update", help="Update a job instance") - update_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - update_parser.add_argument( - "--job-id", - type=str, - help="ID of the job", - dest="job_id", - required=True, - ) - update_parser.add_argument( - "--job-instance-id", - type=str, - help="ID of the job instance to update", - dest="job_instance_id", - required=True, - ) - update_parser.add_argument( - "--display-name", - type=str, - help="New display name for the job instance", - dest="display_name", - ) - update_parser.add_argument( - "--schedule", - type=str, - help="New cron schedule for the job instance", - dest="schedule", - ) - update_parser.add_argument( - "--timeout-seconds", - type=int, - help="New timeout in seconds for job execution", - dest="timeout_seconds", - ) - update_parser.add_argument( - "--enabled", - type=str, - choices=["true", "false"], - help="Enable or disable the job instance", - dest="enabled", - ) - update_parser.add_argument( - "--parameters", - type=str, - help="JSON string of new job parameters", - dest="parameters", - ) - update_parser.add_argument( - "--update-mask", - type=str, - help="Comma-separated list of fields to update", - dest="update_mask", - ) - update_parser.set_defaults(func=handle_job_instances_update_command) - - # run-ondemand command - run_parser = lvl1.add_parser( - "run-ondemand", - help="Run a job instance on demand", - ) - run_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - run_parser.add_argument( - "--job-id", - type=str, - help="ID of the job", - dest="job_id", - required=True, - ) - run_parser.add_argument( - "--job-instance-id", - type=str, - help="ID of the job instance to run", - dest="job_instance_id", - required=True, - ) - run_parser.add_argument( - "--parameters", - type=str, - help="JSON string of parameters for this run", - dest="parameters", - ) - run_parser.set_defaults(func=handle_job_instances_run_ondemand_command) - - -def handle_job_instances_list_command(args, chronicle): - """Handle job instances list command""" - try: - out = chronicle.list_integration_job_instances( - integration_name=args.integration_name, - job_id=args.job_id, - page_size=args.page_size, - page_token=args.page_token, - filter_string=args.filter_string, - order_by=args.order_by, - as_list=args.as_list, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error listing job instances: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_job_instances_get_command(args, chronicle): - """Handle job instance get command""" - try: - out = chronicle.get_integration_job_instance( - integration_name=args.integration_name, - job_id=args.job_id, - job_instance_id=args.job_instance_id, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error getting job instance: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_job_instances_delete_command(args, chronicle): - """Handle job instance delete command""" - try: - chronicle.delete_integration_job_instance( - integration_name=args.integration_name, - job_id=args.job_id, - job_instance_id=args.job_instance_id, - ) - print(f"Job instance {args.job_instance_id} deleted successfully") - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error deleting job instance: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_job_instances_create_command(args, chronicle): - """Handle job instance create command""" - try: - # Parse parameters if provided - parameters = None - if args.parameters: - parameters = json.loads(args.parameters) - - out = chronicle.create_integration_job_instance( - integration_name=args.integration_name, - job_id=args.job_id, - environment=args.environment, - display_name=args.display_name, - schedule=args.schedule, - timeout_seconds=args.timeout_seconds, - enabled=args.enabled, - parameters=parameters, - ) - output_formatter(out, getattr(args, "output", "json")) - except json.JSONDecodeError as e: - print(f"Error parsing parameters JSON: {e}", file=sys.stderr) - sys.exit(1) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error creating job instance: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_job_instances_update_command(args, chronicle): - """Handle job instance update command""" - try: - # Parse parameters if provided - parameters = None - if args.parameters: - parameters = json.loads(args.parameters) - - # Convert enabled string to boolean if provided - enabled = None - if args.enabled: - enabled = args.enabled.lower() == "true" - - out = chronicle.update_integration_job_instance( - integration_name=args.integration_name, - job_id=args.job_id, - job_instance_id=args.job_instance_id, - display_name=args.display_name, - schedule=args.schedule, - timeout_seconds=args.timeout_seconds, - enabled=enabled, - parameters=parameters, - update_mask=args.update_mask, - ) - output_formatter(out, getattr(args, "output", "json")) - except json.JSONDecodeError as e: - print(f"Error parsing parameters JSON: {e}", file=sys.stderr) - sys.exit(1) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error updating job instance: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_job_instances_run_ondemand_command(args, chronicle): - """Handle run job instance on demand command""" - try: - # Parse parameters if provided - parameters = None - if args.parameters: - parameters = json.loads(args.parameters) - - # Get the job instance first - job_instance = chronicle.get_integration_job_instance( - integration_name=args.integration_name, - job_id=args.job_id, - job_instance_id=args.job_instance_id, - ) - - out = chronicle.run_integration_job_instance_on_demand( - integration_name=args.integration_name, - job_id=args.job_id, - job_instance_id=args.job_instance_id, - job_instance=job_instance, - parameters=parameters, - ) - output_formatter(out, getattr(args, "output", "json")) - except json.JSONDecodeError as e: - print(f"Error parsing parameters JSON: {e}", file=sys.stderr) - sys.exit(1) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error running job instance on demand: {e}", file=sys.stderr) - sys.exit(1) diff --git a/src/secops/cli/commands/integration/job_revisions.py b/src/secops/cli/commands/integration/job_revisions.py deleted file mode 100644 index 36b24850..00000000 --- a/src/secops/cli/commands/integration/job_revisions.py +++ /dev/null @@ -1,213 +0,0 @@ -# Copyright 2025 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. -# -"""Google SecOps CLI integration job revisions commands""" - -import sys - -from secops.cli.utils.formatters import output_formatter -from secops.cli.utils.common_args import ( - add_pagination_args, - add_as_list_arg, -) - - -def setup_job_revisions_command(subparsers): - """Setup integration job revisions command""" - revisions_parser = subparsers.add_parser( - "job-revisions", - help="Manage integration job revisions", - ) - lvl1 = revisions_parser.add_subparsers( - dest="job_revisions_command", - help="Integration job revisions command", - ) - - # list command - list_parser = lvl1.add_parser("list", help="List integration job revisions") - list_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - list_parser.add_argument( - "--job-id", - type=str, - help="ID of the job", - dest="job_id", - required=True, - ) - add_pagination_args(list_parser) - add_as_list_arg(list_parser) - list_parser.add_argument( - "--filter-string", - type=str, - help="Filter string for listing revisions", - dest="filter_string", - ) - list_parser.add_argument( - "--order-by", - type=str, - help="Order by string for listing revisions", - dest="order_by", - ) - list_parser.set_defaults(func=handle_job_revisions_list_command) - - # delete command - delete_parser = lvl1.add_parser( - "delete", help="Delete an integration job revision" - ) - delete_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - delete_parser.add_argument( - "--job-id", - type=str, - help="ID of the job", - dest="job_id", - required=True, - ) - delete_parser.add_argument( - "--revision-id", - type=str, - help="ID of the revision to delete", - dest="revision_id", - required=True, - ) - delete_parser.set_defaults(func=handle_job_revisions_delete_command) - - # create command - create_parser = lvl1.add_parser( - "create", help="Create a new integration job revision" - ) - create_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - create_parser.add_argument( - "--job-id", - type=str, - help="ID of the job", - dest="job_id", - required=True, - ) - create_parser.add_argument( - "--comment", - type=str, - help="Comment describing the revision", - dest="comment", - ) - create_parser.set_defaults(func=handle_job_revisions_create_command) - - # rollback command - rollback_parser = lvl1.add_parser( - "rollback", help="Rollback job to a previous revision" - ) - rollback_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - rollback_parser.add_argument( - "--job-id", - type=str, - help="ID of the job", - dest="job_id", - required=True, - ) - rollback_parser.add_argument( - "--revision-id", - type=str, - help="ID of the revision to rollback to", - dest="revision_id", - required=True, - ) - rollback_parser.set_defaults(func=handle_job_revisions_rollback_command) - - -def handle_job_revisions_list_command(args, chronicle): - """Handle integration job revisions list command""" - try: - out = chronicle.list_integration_job_revisions( - integration_name=args.integration_name, - job_id=args.job_id, - page_size=args.page_size, - page_token=args.page_token, - filter_string=args.filter_string, - order_by=args.order_by, - as_list=args.as_list, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error listing job revisions: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_job_revisions_delete_command(args, chronicle): - """Handle integration job revision delete command""" - try: - chronicle.delete_integration_job_revision( - integration_name=args.integration_name, - job_id=args.job_id, - revision_id=args.revision_id, - ) - print(f"Job revision {args.revision_id} deleted successfully") - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error deleting job revision: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_job_revisions_create_command(args, chronicle): - """Handle integration job revision create command""" - try: - # Get the current job to create a revision - job = chronicle.get_integration_job( - integration_name=args.integration_name, - job_id=args.job_id, - ) - out = chronicle.create_integration_job_revision( - integration_name=args.integration_name, - job_id=args.job_id, - job=job, - comment=args.comment, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error creating job revision: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_job_revisions_rollback_command(args, chronicle): - """Handle integration job revision rollback command""" - try: - out = chronicle.rollback_integration_job_revision( - integration_name=args.integration_name, - job_id=args.job_id, - revision_id=args.revision_id, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error rolling back job revision: {e}", file=sys.stderr) - sys.exit(1) diff --git a/src/secops/cli/commands/integration/jobs.py b/src/secops/cli/commands/integration/jobs.py deleted file mode 100644 index 4cd04e8c..00000000 --- a/src/secops/cli/commands/integration/jobs.py +++ /dev/null @@ -1,356 +0,0 @@ -# Copyright 2025 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. -# -"""Google SecOps CLI integration jobs commands""" - -import json -import sys - -from secops.cli.utils.formatters import output_formatter -from secops.cli.utils.common_args import ( - add_pagination_args, - add_as_list_arg, -) - - -def setup_jobs_command(subparsers): - """Setup integration jobs command""" - jobs_parser = subparsers.add_parser( - "jobs", - help="Manage integration jobs", - ) - lvl1 = jobs_parser.add_subparsers( - dest="jobs_command", help="Integration jobs command" - ) - - # list command - list_parser = lvl1.add_parser("list", help="List integration jobs") - list_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - add_pagination_args(list_parser) - add_as_list_arg(list_parser) - list_parser.add_argument( - "--filter-string", - type=str, - help="Filter string for listing jobs", - dest="filter_string", - ) - list_parser.add_argument( - "--order-by", - type=str, - help="Order by string for listing jobs", - dest="order_by", - ) - list_parser.add_argument( - "--exclude-staging", - action="store_true", - help="Exclude staging jobs from the list", - dest="exclude_staging", - ) - list_parser.set_defaults(func=handle_jobs_list_command) - - # get command - get_parser = lvl1.add_parser("get", help="Get integration job details") - get_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - get_parser.add_argument( - "--job-id", - type=str, - help="ID of the job to get", - dest="job_id", - required=True, - ) - get_parser.set_defaults(func=handle_jobs_get_command) - - # delete command - delete_parser = lvl1.add_parser("delete", help="Delete an integration job") - delete_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - delete_parser.add_argument( - "--job-id", - type=str, - help="ID of the job to delete", - dest="job_id", - required=True, - ) - delete_parser.set_defaults(func=handle_jobs_delete_command) - - # create command - create_parser = lvl1.add_parser( - "create", - help="Create a new integration job", - ) - create_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - create_parser.add_argument( - "--display-name", - type=str, - help="Display name for the job", - dest="display_name", - required=True, - ) - create_parser.add_argument( - "--code", - type=str, - help="Python code for the job", - dest="code", - required=True, - ) - create_parser.add_argument( - "--description", - type=str, - help="Description of the job", - dest="description", - ) - create_parser.add_argument( - "--job-id", - type=str, - help="Custom ID for the job", - dest="job_id", - ) - create_parser.add_argument( - "--parameters", - type=str, - help="JSON string of job parameters", - dest="parameters", - ) - create_parser.set_defaults(func=handle_jobs_create_command) - - # update command - update_parser = lvl1.add_parser("update", help="Update an integration job") - update_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - update_parser.add_argument( - "--job-id", - type=str, - help="ID of the job to update", - dest="job_id", - required=True, - ) - update_parser.add_argument( - "--display-name", - type=str, - help="New display name for the job", - dest="display_name", - ) - update_parser.add_argument( - "--code", - type=str, - help="New Python code for the job", - dest="code", - ) - update_parser.add_argument( - "--description", - type=str, - help="New description for the job", - dest="description", - ) - update_parser.add_argument( - "--parameters", - type=str, - help="JSON string of new job parameters", - dest="parameters", - ) - update_parser.add_argument( - "--update-mask", - type=str, - help="Comma-separated list of fields to update", - dest="update_mask", - ) - update_parser.set_defaults(func=handle_jobs_update_command) - - # test command - test_parser = lvl1.add_parser( - "test", help="Execute an integration job test" - ) - test_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - test_parser.add_argument( - "--job-id", - type=str, - help="ID of the job to test", - dest="job_id", - required=True, - ) - test_parser.set_defaults(func=handle_jobs_test_command) - - # template command - template_parser = lvl1.add_parser( - "template", - help="Get a template for creating a job", - ) - template_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - template_parser.set_defaults(func=handle_jobs_template_command) - - -def handle_jobs_list_command(args, chronicle): - """Handle integration jobs list command""" - try: - out = chronicle.list_integration_jobs( - integration_name=args.integration_name, - page_size=args.page_size, - page_token=args.page_token, - filter_string=args.filter_string, - order_by=args.order_by, - exclude_staging=args.exclude_staging, - as_list=args.as_list, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error listing integration jobs: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_jobs_get_command(args, chronicle): - """Handle integration job get command""" - try: - out = chronicle.get_integration_job( - integration_name=args.integration_name, - job_id=args.job_id, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error getting integration job: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_jobs_delete_command(args, chronicle): - """Handle integration job delete command""" - try: - chronicle.delete_integration_job( - integration_name=args.integration_name, - job_id=args.job_id, - ) - print(f"Job {args.job_id} deleted successfully") - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error deleting integration job: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_jobs_create_command(args, chronicle): - """Handle integration job create command""" - try: - # Parse parameters if provided - parameters = None - if args.parameters: - parameters = json.loads(args.parameters) - - out = chronicle.create_integration_job( - integration_name=args.integration_name, - display_name=args.display_name, - code=args.code, - description=args.description, - job_id=args.job_id, - parameters=parameters, - ) - output_formatter(out, getattr(args, "output", "json")) - except json.JSONDecodeError as e: - print(f"Error parsing parameters JSON: {e}", file=sys.stderr) - sys.exit(1) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error creating integration job: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_jobs_update_command(args, chronicle): - """Handle integration job update command""" - try: - # Parse parameters if provided - parameters = None - if args.parameters: - parameters = json.loads(args.parameters) - - out = chronicle.update_integration_job( - integration_name=args.integration_name, - job_id=args.job_id, - display_name=args.display_name, - code=args.code, - description=args.description, - parameters=parameters, - update_mask=args.update_mask, - ) - output_formatter(out, getattr(args, "output", "json")) - except json.JSONDecodeError as e: - print(f"Error parsing parameters JSON: {e}", file=sys.stderr) - sys.exit(1) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error updating integration job: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_jobs_test_command(args, chronicle): - """Handle integration job test command""" - try: - # First get the job to test - job = chronicle.get_integration_job( - integration_name=args.integration_name, - job_id=args.job_id, - ) - out = chronicle.execute_integration_job_test( - integration_name=args.integration_name, - job_id=args.job_id, - job=job, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error testing integration job: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_jobs_template_command(args, chronicle): - """Handle get job template command""" - try: - out = chronicle.get_integration_job_template( - integration_name=args.integration_name, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error getting job template: {e}", file=sys.stderr) - sys.exit(1) diff --git a/src/secops/cli/commands/integration/logical_operator_revisions.py b/src/secops/cli/commands/integration/logical_operator_revisions.py deleted file mode 100644 index d09b9d70..00000000 --- a/src/secops/cli/commands/integration/logical_operator_revisions.py +++ /dev/null @@ -1,239 +0,0 @@ -# Copyright 2025 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. -# -"""Google SecOps CLI integration logical operator revisions commands""" - -import sys - -from secops.cli.utils.formatters import output_formatter -from secops.cli.utils.common_args import ( - add_pagination_args, - add_as_list_arg, -) - - -def setup_logical_operator_revisions_command(subparsers): - """Setup integration logical operator revisions command""" - revisions_parser = subparsers.add_parser( - "logical-operator-revisions", - help="Manage integration logical operator revisions", - ) - lvl1 = revisions_parser.add_subparsers( - dest="logical_operator_revisions_command", - help="Integration logical operator revisions command", - ) - - # list command - list_parser = lvl1.add_parser( - "list", - help="List integration logical operator revisions", - ) - list_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - list_parser.add_argument( - "--logical-operator-id", - type=str, - help="ID of the logical operator", - dest="logical_operator_id", - required=True, - ) - add_pagination_args(list_parser) - add_as_list_arg(list_parser) - list_parser.add_argument( - "--filter-string", - type=str, - help="Filter string for listing revisions", - dest="filter_string", - ) - list_parser.add_argument( - "--order-by", - type=str, - help="Order by string for listing revisions", - dest="order_by", - ) - list_parser.set_defaults( - func=handle_logical_operator_revisions_list_command, - ) - - # delete command - delete_parser = lvl1.add_parser( - "delete", - help="Delete an integration logical operator revision", - ) - delete_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - delete_parser.add_argument( - "--logical-operator-id", - type=str, - help="ID of the logical operator", - dest="logical_operator_id", - required=True, - ) - delete_parser.add_argument( - "--revision-id", - type=str, - help="ID of the revision to delete", - dest="revision_id", - required=True, - ) - delete_parser.set_defaults( - func=handle_logical_operator_revisions_delete_command, - ) - - # create command - create_parser = lvl1.add_parser( - "create", - help="Create a new integration logical operator revision", - ) - create_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - create_parser.add_argument( - "--logical-operator-id", - type=str, - help="ID of the logical operator", - dest="logical_operator_id", - required=True, - ) - create_parser.add_argument( - "--comment", - type=str, - help="Comment describing the revision", - dest="comment", - ) - create_parser.set_defaults( - func=handle_logical_operator_revisions_create_command, - ) - - # rollback command - rollback_parser = lvl1.add_parser( - "rollback", - help="Rollback logical operator to a previous revision", - ) - rollback_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - rollback_parser.add_argument( - "--logical-operator-id", - type=str, - help="ID of the logical operator", - dest="logical_operator_id", - required=True, - ) - rollback_parser.add_argument( - "--revision-id", - type=str, - help="ID of the revision to rollback to", - dest="revision_id", - required=True, - ) - rollback_parser.set_defaults( - func=handle_logical_operator_revisions_rollback_command, - ) - - -def handle_logical_operator_revisions_list_command(args, chronicle): - """Handle integration logical operator revisions list command""" - try: - out = chronicle.list_integration_logical_operator_revisions( - integration_name=args.integration_name, - logical_operator_id=args.logical_operator_id, - page_size=args.page_size, - page_token=args.page_token, - filter_string=args.filter_string, - order_by=args.order_by, - as_list=args.as_list, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error listing logical operator revisions: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_logical_operator_revisions_delete_command(args, chronicle): - """Handle integration logical operator revision delete command""" - try: - chronicle.delete_integration_logical_operator_revision( - integration_name=args.integration_name, - logical_operator_id=args.logical_operator_id, - revision_id=args.revision_id, - ) - print( - f"Logical operator revision {args.revision_id} deleted successfully" - ) - except Exception as e: # pylint: disable=broad-exception-caught - print( - f"Error deleting logical operator revision: {e}", - file=sys.stderr, - ) - sys.exit(1) - - -def handle_logical_operator_revisions_create_command(args, chronicle): - """Handle integration logical operator revision create command""" - try: - # Get the current logical operator to create a revision - logical_operator = chronicle.get_integration_logical_operator( - integration_name=args.integration_name, - logical_operator_id=args.logical_operator_id, - ) - out = chronicle.create_integration_logical_operator_revision( - integration_name=args.integration_name, - logical_operator_id=args.logical_operator_id, - logical_operator=logical_operator, - comment=args.comment, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print( - f"Error creating logical operator revision: {e}", - file=sys.stderr, - ) - sys.exit(1) - - -def handle_logical_operator_revisions_rollback_command(args, chronicle): - """Handle integration logical operator revision rollback command""" - try: - out = chronicle.rollback_integration_logical_operator_revision( - integration_name=args.integration_name, - logical_operator_id=args.logical_operator_id, - revision_id=args.revision_id, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print( - f"Error rolling back logical operator revision: {e}", - file=sys.stderr, - ) - sys.exit(1) - diff --git a/src/secops/cli/commands/integration/logical_operators.py b/src/secops/cli/commands/integration/logical_operators.py deleted file mode 100644 index 0bf65725..00000000 --- a/src/secops/cli/commands/integration/logical_operators.py +++ /dev/null @@ -1,395 +0,0 @@ -# Copyright 2025 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. -# -"""Google SecOps CLI integration logical operators commands""" - -import sys - -from secops.cli.utils.formatters import output_formatter -from secops.cli.utils.common_args import ( - add_pagination_args, - add_as_list_arg, -) - - -def setup_logical_operators_command(subparsers): - """Setup integration logical operators command""" - operators_parser = subparsers.add_parser( - "logical-operators", - help="Manage integration logical operators", - ) - lvl1 = operators_parser.add_subparsers( - dest="logical_operators_command", - help="Integration logical operators command", - ) - - # list command - list_parser = lvl1.add_parser( - "list", - help="List integration logical operators", - ) - list_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - add_pagination_args(list_parser) - add_as_list_arg(list_parser) - list_parser.add_argument( - "--filter-string", - type=str, - help="Filter string for listing logical operators", - dest="filter_string", - ) - list_parser.add_argument( - "--order-by", - type=str, - help="Order by string for listing logical operators", - dest="order_by", - ) - list_parser.add_argument( - "--exclude-staging", - action="store_true", - help="Exclude staging logical operators from the response", - dest="exclude_staging", - ) - list_parser.add_argument( - "--expand", - type=str, - help="Expand the response with full logical operator details", - dest="expand", - ) - list_parser.set_defaults(func=handle_logical_operators_list_command) - - # get command - get_parser = lvl1.add_parser( - "get", - help="Get integration logical operator details", - ) - get_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - get_parser.add_argument( - "--logical-operator-id", - type=str, - help="ID of the logical operator to get", - dest="logical_operator_id", - required=True, - ) - get_parser.add_argument( - "--expand", - type=str, - help="Expand the response with full logical operator details", - dest="expand", - ) - get_parser.set_defaults(func=handle_logical_operators_get_command) - - # delete command - delete_parser = lvl1.add_parser( - "delete", - help="Delete an integration logical operator", - ) - delete_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - delete_parser.add_argument( - "--logical-operator-id", - type=str, - help="ID of the logical operator to delete", - dest="logical_operator_id", - required=True, - ) - delete_parser.set_defaults(func=handle_logical_operators_delete_command) - - # create command - create_parser = lvl1.add_parser( - "create", - help="Create a new integration logical operator", - ) - create_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - create_parser.add_argument( - "--display-name", - type=str, - help="Display name for the logical operator", - dest="display_name", - required=True, - ) - create_parser.add_argument( - "--script", - type=str, - help="Python script for the logical operator", - dest="script", - required=True, - ) - create_parser.add_argument( - "--script-timeout", - type=str, - help="Timeout for script execution (e.g., '60s')", - dest="script_timeout", - required=True, - ) - create_parser.add_argument( - "--enabled", - action="store_true", - help="Enable the logical operator (default: disabled)", - dest="enabled", - ) - create_parser.add_argument( - "--description", - type=str, - help="Description of the logical operator", - dest="description", - ) - create_parser.set_defaults(func=handle_logical_operators_create_command) - - # update command - update_parser = lvl1.add_parser( - "update", - help="Update an integration logical operator", - ) - update_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - update_parser.add_argument( - "--logical-operator-id", - type=str, - help="ID of the logical operator to update", - dest="logical_operator_id", - required=True, - ) - update_parser.add_argument( - "--display-name", - type=str, - help="New display name for the logical operator", - dest="display_name", - ) - update_parser.add_argument( - "--script", - type=str, - help="New Python script for the logical operator", - dest="script", - ) - update_parser.add_argument( - "--script-timeout", - type=str, - help="New timeout for script execution", - dest="script_timeout", - ) - update_parser.add_argument( - "--enabled", - type=lambda x: x.lower() == "true", - help="Enable or disable the logical operator (true/false)", - dest="enabled", - ) - update_parser.add_argument( - "--description", - type=str, - help="New description for the logical operator", - dest="description", - ) - update_parser.add_argument( - "--update-mask", - type=str, - help="Comma-separated list of fields to update", - dest="update_mask", - ) - update_parser.set_defaults(func=handle_logical_operators_update_command) - - # test command - test_parser = lvl1.add_parser( - "test", - help="Execute an integration logical operator test", - ) - test_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - test_parser.add_argument( - "--logical-operator-id", - type=str, - help="ID of the logical operator to test", - dest="logical_operator_id", - required=True, - ) - test_parser.set_defaults(func=handle_logical_operators_test_command) - - # template command - template_parser = lvl1.add_parser( - "template", - help="Get logical operator template", - ) - template_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - template_parser.set_defaults(func=handle_logical_operators_template_command) - - -def handle_logical_operators_list_command(args, chronicle): - """Handle integration logical operators list command""" - try: - out = chronicle.list_integration_logical_operators( - integration_name=args.integration_name, - page_size=args.page_size, - page_token=args.page_token, - filter_string=args.filter_string, - order_by=args.order_by, - exclude_staging=args.exclude_staging, - expand=args.expand, - as_list=args.as_list, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print( - f"Error listing integration logical operators: {e}", file=sys.stderr - ) - sys.exit(1) - - -def handle_logical_operators_get_command(args, chronicle): - """Handle integration logical operator get command""" - try: - out = chronicle.get_integration_logical_operator( - integration_name=args.integration_name, - logical_operator_id=args.logical_operator_id, - expand=args.expand, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print( - f"Error getting integration logical operator: {e}", file=sys.stderr - ) - sys.exit(1) - - -def handle_logical_operators_delete_command(args, chronicle): - """Handle integration logical operator delete command""" - try: - chronicle.delete_integration_logical_operator( - integration_name=args.integration_name, - logical_operator_id=args.logical_operator_id, - ) - print( - f"Logical operator {args.logical_operator_id} deleted successfully" - ) - except Exception as e: # pylint: disable=broad-exception-caught - print( - f"Error deleting integration logical operator: {e}", file=sys.stderr - ) - sys.exit(1) - - -def handle_logical_operators_create_command(args, chronicle): - """Handle integration logical operator create command""" - try: - out = chronicle.create_integration_logical_operator( - integration_name=args.integration_name, - display_name=args.display_name, - script=args.script, - script_timeout=args.script_timeout, - enabled=args.enabled, - description=args.description, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print( - f"Error creating integration logical operator: {e}", - file=sys.stderr, - ) - sys.exit(1) - - -def handle_logical_operators_update_command(args, chronicle): - """Handle integration logical operator update command""" - try: - out = chronicle.update_integration_logical_operator( - integration_name=args.integration_name, - logical_operator_id=args.logical_operator_id, - display_name=args.display_name, - script=args.script, - script_timeout=args.script_timeout, - enabled=args.enabled, - description=args.description, - update_mask=args.update_mask, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print( - f"Error updating integration logical operator: {e}", - file=sys.stderr, - ) - sys.exit(1) - - -def handle_logical_operators_test_command(args, chronicle): - """Handle integration logical operator test command""" - try: - # Get the logical operator first - logical_operator = chronicle.get_integration_logical_operator( - integration_name=args.integration_name, - logical_operator_id=args.logical_operator_id, - ) - - out = chronicle.execute_integration_logical_operator_test( - integration_name=args.integration_name, - logical_operator=logical_operator, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print( - f"Error testing integration logical operator: {e}", - file=sys.stderr, - ) - sys.exit(1) - - -def handle_logical_operators_template_command(args, chronicle): - """Handle integration logical operator template command""" - try: - out = chronicle.get_integration_logical_operator_template( - integration_name=args.integration_name, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print( - f"Error getting logical operator template: {e}", - file=sys.stderr, - ) - sys.exit(1) diff --git a/src/secops/cli/commands/integration/marketplace_integration.py b/src/secops/cli/commands/integration/marketplace_integration.py deleted file mode 100644 index f8b87aa2..00000000 --- a/src/secops/cli/commands/integration/marketplace_integration.py +++ /dev/null @@ -1,204 +0,0 @@ -# Copyright 2025 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. -# -"""Google SecOps CLI marketplace integration commands""" - -import sys - -from secops.cli.utils.formatters import output_formatter -from secops.cli.utils.common_args import ( - add_pagination_args, - add_as_list_arg, -) - - -def setup_marketplace_integrations_command(subparsers): - """Setup marketplace integration command""" - mp_parser = subparsers.add_parser( - "marketplace", - help="Manage Chronicle marketplace integration", - ) - lvl1 = mp_parser.add_subparsers( - dest="mp_command", help="Marketplace integration command" - ) - - # list command - list_parser = lvl1.add_parser("list", help="List marketplace integrations") - add_pagination_args(list_parser) - add_as_list_arg(list_parser) - list_parser.add_argument( - "--filter-string", - type=str, - help="Filter string for listing marketplace integrations", - dest="filter_string", - ) - list_parser.add_argument( - "--order-by", - type=str, - help="Order by string for listing marketplace integrations", - dest="order_by", - ) - list_parser.set_defaults(func=handle_mp_integration_list_command) - - # get command - get_parser = lvl1.add_parser( - "get", help="Get marketplace integration details" - ) - get_parser.add_argument( - "--integration-name", - type=str, - help="Name of the marketplace integration to get", - dest="integration_name", - required=True, - ) - get_parser.set_defaults(func=handle_mp_integration_get_command) - - # diff command - diff_parser = lvl1.add_parser( - "diff", - help="Get marketplace integration diff between " - "installed and latest version", - ) - diff_parser.add_argument( - "--integration-name", - type=str, - help="Name of the marketplace integration to diff", - dest="integration_name", - required=True, - ) - diff_parser.set_defaults(func=handle_mp_integration_diff_command) - - # install command - install_parser = lvl1.add_parser( - "install", help="Install or update a marketplace integration" - ) - install_parser.add_argument( - "--integration-name", - type=str, - help="Name of the marketplace integration to install or update", - dest="integration_name", - required=True, - ) - install_parser.add_argument( - "--override-mapping", - action="store_true", - help="Override existing mapping", - dest="override_mapping", - ) - install_parser.add_argument( - "--staging", - action="store_true", - help="Whether to install the integration in " - "staging environment (true/false)", - dest="staging", - ) - install_parser.add_argument( - "--version", - type=str, - help="Version of the marketplace integration to install", - dest="version", - ) - install_parser.add_argument( - "--restore-from-snapshot", - action="store_true", - help="Whether to restore the integration from existing snapshot " - "(true/false)", - dest="restore_from_snapshot", - ) - install_parser.set_defaults(func=handle_mp_integration_install_command) - - # uninstall command - uninstall_parser = lvl1.add_parser( - "uninstall", help="Uninstall a marketplace integration" - ) - uninstall_parser.add_argument( - "--integration-name", - type=str, - help="Name of the marketplace integration to uninstall", - dest="integration_name", - required=True, - ) - uninstall_parser.set_defaults(func=handle_mp_integration_uninstall_command) - - -def handle_mp_integration_list_command(args, chronicle): - """Handle marketplace integration list command""" - try: - out = chronicle.list_marketplace_integrations( - page_size=args.page_size, - page_token=args.page_token, - filter_string=args.filter_string, - order_by=args.order_by, - as_list=args.as_list, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error listing marketplace integrations: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_mp_integration_get_command(args, chronicle): - """Handle marketplace integration get command""" - try: - out = chronicle.get_marketplace_integration( - integration_name=args.integration_name, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error getting marketplace integration: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_mp_integration_diff_command(args, chronicle): - """Handle marketplace integration diff command""" - try: - out = chronicle.get_marketplace_integration_diff( - integration_name=args.integration_name, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print( - f"Error getting marketplace integration diff: {e}", file=sys.stderr - ) - sys.exit(1) - - -def handle_mp_integration_install_command(args, chronicle): - """Handle marketplace integration install command""" - try: - out = chronicle.install_marketplace_integration( - integration_name=args.integration_name, - override_mapping=args.override_mapping, - staging=args.staging, - version=args.version, - restore_from_snapshot=args.restore_from_snapshot, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error installing marketplace integration: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_mp_integration_uninstall_command(args, chronicle): - """Handle marketplace integration uninstall command""" - try: - out = chronicle.uninstall_marketplace_integration( - integration_name=args.integration_name, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print( - f"Error uninstalling marketplace integration: {e}", file=sys.stderr - ) - sys.exit(1) diff --git a/src/secops/cli/commands/integration/transformer_revisions.py b/src/secops/cli/commands/integration/transformer_revisions.py deleted file mode 100644 index 1075a696..00000000 --- a/src/secops/cli/commands/integration/transformer_revisions.py +++ /dev/null @@ -1,236 +0,0 @@ -# Copyright 2025 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. -# -"""Google SecOps CLI integration transformer revisions commands""" - -import sys - -from secops.cli.utils.formatters import output_formatter -from secops.cli.utils.common_args import ( - add_pagination_args, - add_as_list_arg, -) - - -def setup_transformer_revisions_command(subparsers): - """Setup integration transformer revisions command""" - revisions_parser = subparsers.add_parser( - "transformer-revisions", - help="Manage integration transformer revisions", - ) - lvl1 = revisions_parser.add_subparsers( - dest="transformer_revisions_command", - help="Integration transformer revisions command", - ) - - # list command - list_parser = lvl1.add_parser( - "list", - help="List integration transformer revisions", - ) - list_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - list_parser.add_argument( - "--transformer-id", - type=str, - help="ID of the transformer", - dest="transformer_id", - required=True, - ) - add_pagination_args(list_parser) - add_as_list_arg(list_parser) - list_parser.add_argument( - "--filter-string", - type=str, - help="Filter string for listing revisions", - dest="filter_string", - ) - list_parser.add_argument( - "--order-by", - type=str, - help="Order by string for listing revisions", - dest="order_by", - ) - list_parser.set_defaults( - func=handle_transformer_revisions_list_command, - ) - - # delete command - delete_parser = lvl1.add_parser( - "delete", - help="Delete an integration transformer revision", - ) - delete_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - delete_parser.add_argument( - "--transformer-id", - type=str, - help="ID of the transformer", - dest="transformer_id", - required=True, - ) - delete_parser.add_argument( - "--revision-id", - type=str, - help="ID of the revision to delete", - dest="revision_id", - required=True, - ) - delete_parser.set_defaults( - func=handle_transformer_revisions_delete_command, - ) - - # create command - create_parser = lvl1.add_parser( - "create", - help="Create a new integration transformer revision", - ) - create_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - create_parser.add_argument( - "--transformer-id", - type=str, - help="ID of the transformer", - dest="transformer_id", - required=True, - ) - create_parser.add_argument( - "--comment", - type=str, - help="Comment describing the revision", - dest="comment", - ) - create_parser.set_defaults( - func=handle_transformer_revisions_create_command, - ) - - # rollback command - rollback_parser = lvl1.add_parser( - "rollback", - help="Rollback transformer to a previous revision", - ) - rollback_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - rollback_parser.add_argument( - "--transformer-id", - type=str, - help="ID of the transformer", - dest="transformer_id", - required=True, - ) - rollback_parser.add_argument( - "--revision-id", - type=str, - help="ID of the revision to rollback to", - dest="revision_id", - required=True, - ) - rollback_parser.set_defaults( - func=handle_transformer_revisions_rollback_command, - ) - - -def handle_transformer_revisions_list_command(args, chronicle): - """Handle integration transformer revisions list command""" - try: - out = chronicle.list_integration_transformer_revisions( - integration_name=args.integration_name, - transformer_id=args.transformer_id, - page_size=args.page_size, - page_token=args.page_token, - filter_string=args.filter_string, - order_by=args.order_by, - as_list=args.as_list, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error listing transformer revisions: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_transformer_revisions_delete_command(args, chronicle): - """Handle integration transformer revision delete command""" - try: - chronicle.delete_integration_transformer_revision( - integration_name=args.integration_name, - transformer_id=args.transformer_id, - revision_id=args.revision_id, - ) - print(f"Transformer revision {args.revision_id} deleted successfully") - except Exception as e: # pylint: disable=broad-exception-caught - print( - f"Error deleting transformer revision: {e}", - file=sys.stderr, - ) - sys.exit(1) - - -def handle_transformer_revisions_create_command(args, chronicle): - """Handle integration transformer revision create command""" - try: - # Get the current transformer to create a revision - transformer = chronicle.get_integration_transformer( - integration_name=args.integration_name, - transformer_id=args.transformer_id, - ) - out = chronicle.create_integration_transformer_revision( - integration_name=args.integration_name, - transformer_id=args.transformer_id, - transformer=transformer, - comment=args.comment, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print( - f"Error creating transformer revision: {e}", - file=sys.stderr, - ) - sys.exit(1) - - -def handle_transformer_revisions_rollback_command(args, chronicle): - """Handle integration transformer revision rollback command""" - try: - out = chronicle.rollback_integration_transformer_revision( - integration_name=args.integration_name, - transformer_id=args.transformer_id, - revision_id=args.revision_id, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print( - f"Error rolling back transformer revision: {e}", - file=sys.stderr, - ) - sys.exit(1) diff --git a/src/secops/cli/commands/integration/transformers.py b/src/secops/cli/commands/integration/transformers.py deleted file mode 100644 index 65dcd32d..00000000 --- a/src/secops/cli/commands/integration/transformers.py +++ /dev/null @@ -1,387 +0,0 @@ -# Copyright 2025 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. -# -"""Google SecOps CLI integration transformers commands""" - -import sys - -from secops.cli.utils.formatters import output_formatter -from secops.cli.utils.common_args import ( - add_pagination_args, - add_as_list_arg, -) - - -def setup_transformers_command(subparsers): - """Setup integration transformers command""" - transformers_parser = subparsers.add_parser( - "transformers", - help="Manage integration transformers", - ) - lvl1 = transformers_parser.add_subparsers( - dest="transformers_command", - help="Integration transformers command", - ) - - # list command - list_parser = lvl1.add_parser( - "list", - help="List integration transformers", - ) - list_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - add_pagination_args(list_parser) - add_as_list_arg(list_parser) - list_parser.add_argument( - "--filter-string", - type=str, - help="Filter string for listing transformers", - dest="filter_string", - ) - list_parser.add_argument( - "--order-by", - type=str, - help="Order by string for listing transformers", - dest="order_by", - ) - list_parser.add_argument( - "--exclude-staging", - action="store_true", - help="Exclude staging transformers from the response", - dest="exclude_staging", - ) - list_parser.add_argument( - "--expand", - type=str, - help="Expand the response with full transformer details", - dest="expand", - ) - list_parser.set_defaults(func=handle_transformers_list_command) - - # get command - get_parser = lvl1.add_parser( - "get", - help="Get integration transformer details", - ) - get_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - get_parser.add_argument( - "--transformer-id", - type=str, - help="ID of the transformer to get", - dest="transformer_id", - required=True, - ) - get_parser.add_argument( - "--expand", - type=str, - help="Expand the response with full transformer details", - dest="expand", - ) - get_parser.set_defaults(func=handle_transformers_get_command) - - # delete command - delete_parser = lvl1.add_parser( - "delete", - help="Delete an integration transformer", - ) - delete_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - delete_parser.add_argument( - "--transformer-id", - type=str, - help="ID of the transformer to delete", - dest="transformer_id", - required=True, - ) - delete_parser.set_defaults(func=handle_transformers_delete_command) - - # create command - create_parser = lvl1.add_parser( - "create", - help="Create a new integration transformer", - ) - create_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - create_parser.add_argument( - "--display-name", - type=str, - help="Display name for the transformer", - dest="display_name", - required=True, - ) - create_parser.add_argument( - "--script", - type=str, - help="Python script for the transformer", - dest="script", - required=True, - ) - create_parser.add_argument( - "--script-timeout", - type=str, - help="Timeout for script execution (e.g., '60s')", - dest="script_timeout", - required=True, - ) - create_parser.add_argument( - "--enabled", - action="store_true", - help="Enable the transformer (default: disabled)", - dest="enabled", - ) - create_parser.add_argument( - "--description", - type=str, - help="Description of the transformer", - dest="description", - ) - create_parser.set_defaults(func=handle_transformers_create_command) - - # update command - update_parser = lvl1.add_parser( - "update", - help="Update an integration transformer", - ) - update_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - update_parser.add_argument( - "--transformer-id", - type=str, - help="ID of the transformer to update", - dest="transformer_id", - required=True, - ) - update_parser.add_argument( - "--display-name", - type=str, - help="New display name for the transformer", - dest="display_name", - ) - update_parser.add_argument( - "--script", - type=str, - help="New Python script for the transformer", - dest="script", - ) - update_parser.add_argument( - "--script-timeout", - type=str, - help="New timeout for script execution", - dest="script_timeout", - ) - update_parser.add_argument( - "--enabled", - type=lambda x: x.lower() == "true", - help="Enable or disable the transformer (true/false)", - dest="enabled", - ) - update_parser.add_argument( - "--description", - type=str, - help="New description for the transformer", - dest="description", - ) - update_parser.add_argument( - "--update-mask", - type=str, - help="Comma-separated list of fields to update", - dest="update_mask", - ) - update_parser.set_defaults(func=handle_transformers_update_command) - - # test command - test_parser = lvl1.add_parser( - "test", - help="Execute an integration transformer test", - ) - test_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - test_parser.add_argument( - "--transformer-id", - type=str, - help="ID of the transformer to test", - dest="transformer_id", - required=True, - ) - test_parser.set_defaults(func=handle_transformers_test_command) - - # template command - template_parser = lvl1.add_parser( - "template", - help="Get transformer template", - ) - template_parser.add_argument( - "--integration-name", - type=str, - help="Name of the integration", - dest="integration_name", - required=True, - ) - template_parser.set_defaults(func=handle_transformers_template_command) - - -def handle_transformers_list_command(args, chronicle): - """Handle integration transformers list command""" - try: - out = chronicle.list_integration_transformers( - integration_name=args.integration_name, - page_size=args.page_size, - page_token=args.page_token, - filter_string=args.filter_string, - order_by=args.order_by, - exclude_staging=args.exclude_staging, - expand=args.expand, - as_list=args.as_list, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error listing integration transformers: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_transformers_get_command(args, chronicle): - """Handle integration transformer get command""" - try: - out = chronicle.get_integration_transformer( - integration_name=args.integration_name, - transformer_id=args.transformer_id, - expand=args.expand, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error getting integration transformer: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_transformers_delete_command(args, chronicle): - """Handle integration transformer delete command""" - try: - chronicle.delete_integration_transformer( - integration_name=args.integration_name, - transformer_id=args.transformer_id, - ) - print(f"Transformer {args.transformer_id} deleted successfully") - except Exception as e: # pylint: disable=broad-exception-caught - print(f"Error deleting integration transformer: {e}", file=sys.stderr) - sys.exit(1) - - -def handle_transformers_create_command(args, chronicle): - """Handle integration transformer create command""" - try: - out = chronicle.create_integration_transformer( - integration_name=args.integration_name, - display_name=args.display_name, - script=args.script, - script_timeout=args.script_timeout, - enabled=args.enabled, - description=args.description, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print( - f"Error creating integration transformer: {e}", - file=sys.stderr, - ) - sys.exit(1) - - -def handle_transformers_update_command(args, chronicle): - """Handle integration transformer update command""" - try: - out = chronicle.update_integration_transformer( - integration_name=args.integration_name, - transformer_id=args.transformer_id, - display_name=args.display_name, - script=args.script, - script_timeout=args.script_timeout, - enabled=args.enabled, - description=args.description, - update_mask=args.update_mask, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print( - f"Error updating integration transformer: {e}", - file=sys.stderr, - ) - sys.exit(1) - - -def handle_transformers_test_command(args, chronicle): - """Handle integration transformer test command""" - try: - # Get the transformer first - transformer = chronicle.get_integration_transformer( - integration_name=args.integration_name, - transformer_id=args.transformer_id, - ) - - out = chronicle.execute_integration_transformer_test( - integration_name=args.integration_name, - transformer=transformer, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print( - f"Error testing integration transformer: {e}", - file=sys.stderr, - ) - sys.exit(1) - - -def handle_transformers_template_command(args, chronicle): - """Handle integration transformer template command""" - try: - out = chronicle.get_integration_transformer_template( - integration_name=args.integration_name, - ) - output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught - print( - f"Error getting transformer template: {e}", - file=sys.stderr, - ) - sys.exit(1) diff --git a/tests/chronicle/integration/test_connector_context_properties.py b/tests/chronicle/integration/test_connector_context_properties.py deleted file mode 100644 index 33941087..00000000 --- a/tests/chronicle/integration/test_connector_context_properties.py +++ /dev/null @@ -1,561 +0,0 @@ -# Copyright 2025 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. -# -"""Tests for Chronicle integration connector context properties functions.""" - -from unittest.mock import Mock, patch - -import pytest - -from secops.chronicle.client import ChronicleClient -from secops.chronicle.models import APIVersion -from secops.chronicle.integration.connector_context_properties import ( - list_connector_context_properties, - get_connector_context_property, - delete_connector_context_property, - create_connector_context_property, - update_connector_context_property, - delete_all_connector_context_properties, -) -from secops.exceptions import APIError - - -@pytest.fixture -def chronicle_client(): - """Create a Chronicle client for testing.""" - with patch("secops.auth.SecOpsAuth") as mock_auth: - mock_session = Mock() - mock_session.headers = {} - mock_auth.return_value.session = mock_session - return ChronicleClient( - customer_id="test-customer", - project_id="test-project", - default_api_version=APIVersion.V1BETA, - ) - - -# -- list_connector_context_properties tests -- - - -def test_list_connector_context_properties_success(chronicle_client): - """Test list_connector_context_properties delegates to paginated request.""" - expected = { - "contextProperties": [{"key": "prop1"}, {"key": "prop2"}], - "nextPageToken": "t", - } - - with patch( - "secops.chronicle.integration.connector_context_properties.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated, patch( - "secops.chronicle.integration.connector_context_properties.format_resource_id", - return_value="My Integration", - ): - result = list_connector_context_properties( - chronicle_client, - integration_name="My Integration", - connector_id="c1", - page_size=10, - page_token="next-token", - ) - - assert result == expected - - _, kwargs = mock_paginated.call_args - assert "connectors/c1/contextProperties" in kwargs["path"] - assert kwargs["items_key"] == "contextProperties" - assert kwargs["page_size"] == 10 - assert kwargs["page_token"] == "next-token" - - -def test_list_connector_context_properties_default_args(chronicle_client): - """Test list_connector_context_properties with default args.""" - expected = {"contextProperties": []} - - with patch( - "secops.chronicle.integration.connector_context_properties.chronicle_paginated_request", - return_value=expected, - ): - result = list_connector_context_properties( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - ) - - assert result == expected - - -def test_list_connector_context_properties_with_filters(chronicle_client): - """Test list_connector_context_properties with filter and order_by.""" - expected = {"contextProperties": [{"key": "prop1"}]} - - with patch( - "secops.chronicle.integration.connector_context_properties.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated: - result = list_connector_context_properties( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - filter_string='key = "prop1"', - order_by="key", - ) - - assert result == expected - - _, kwargs = mock_paginated.call_args - assert kwargs["extra_params"] == { - "filter": 'key = "prop1"', - "orderBy": "key", - } - - -def test_list_connector_context_properties_as_list(chronicle_client): - """Test list_connector_context_properties returns list when as_list=True.""" - expected = [{"key": "prop1"}, {"key": "prop2"}] - - with patch( - "secops.chronicle.integration.connector_context_properties.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated: - result = list_connector_context_properties( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - as_list=True, - ) - - assert result == expected - - _, kwargs = mock_paginated.call_args - assert kwargs["as_list"] is True - - -def test_list_connector_context_properties_error(chronicle_client): - """Test list_connector_context_properties raises APIError on failure.""" - with patch( - "secops.chronicle.integration.connector_context_properties.chronicle_paginated_request", - side_effect=APIError("Failed to list context properties"), - ): - with pytest.raises(APIError) as exc_info: - list_connector_context_properties( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - ) - assert "Failed to list context properties" in str(exc_info.value) - - -# -- get_connector_context_property tests -- - - -def test_get_connector_context_property_success(chronicle_client): - """Test get_connector_context_property issues GET request.""" - expected = { - "name": "contextProperties/prop1", - "key": "prop1", - "value": "test-value", - } - - with patch( - "secops.chronicle.integration.connector_context_properties.chronicle_request", - return_value=expected, - ) as mock_request: - result = get_connector_context_property( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - context_property_id="prop1", - ) - - assert result == expected - - _, kwargs = mock_request.call_args - assert kwargs["method"] == "GET" - assert "connectors/c1/contextProperties/prop1" in kwargs["endpoint_path"] - assert kwargs["api_version"] == APIVersion.V1BETA - - -def test_get_connector_context_property_error(chronicle_client): - """Test get_connector_context_property raises APIError on failure.""" - with patch( - "secops.chronicle.integration.connector_context_properties.chronicle_request", - side_effect=APIError("Failed to get context property"), - ): - with pytest.raises(APIError) as exc_info: - get_connector_context_property( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - context_property_id="prop1", - ) - assert "Failed to get context property" in str(exc_info.value) - - -# -- delete_connector_context_property tests -- - - -def test_delete_connector_context_property_success(chronicle_client): - """Test delete_connector_context_property issues DELETE request.""" - with patch( - "secops.chronicle.integration.connector_context_properties.chronicle_request", - return_value=None, - ) as mock_request: - delete_connector_context_property( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - context_property_id="prop1", - ) - - _, kwargs = mock_request.call_args - assert kwargs["method"] == "DELETE" - assert "connectors/c1/contextProperties/prop1" in kwargs["endpoint_path"] - assert kwargs["api_version"] == APIVersion.V1BETA - - -def test_delete_connector_context_property_error(chronicle_client): - """Test delete_connector_context_property raises APIError on failure.""" - with patch( - "secops.chronicle.integration.connector_context_properties.chronicle_request", - side_effect=APIError("Failed to delete context property"), - ): - with pytest.raises(APIError) as exc_info: - delete_connector_context_property( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - context_property_id="prop1", - ) - assert "Failed to delete context property" in str(exc_info.value) - - -# -- create_connector_context_property tests -- - - -def test_create_connector_context_property_required_fields_only(chronicle_client): - """Test create_connector_context_property with required fields only.""" - expected = {"name": "contextProperties/new", "value": "test-value"} - - with patch( - "secops.chronicle.integration.connector_context_properties.chronicle_request", - return_value=expected, - ) as mock_request: - result = create_connector_context_property( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - value="test-value", - ) - - assert result == expected - - mock_request.assert_called_once_with( - chronicle_client, - method="POST", - endpoint_path="integrations/test-integration/connectors/c1/contextProperties", - api_version=APIVersion.V1BETA, - json={"value": "test-value"}, - ) - - -def test_create_connector_context_property_with_key(chronicle_client): - """Test create_connector_context_property includes key when provided.""" - expected = {"name": "contextProperties/custom-key", "value": "test-value"} - - with patch( - "secops.chronicle.integration.connector_context_properties.chronicle_request", - return_value=expected, - ) as mock_request: - result = create_connector_context_property( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - value="test-value", - key="custom-key", - ) - - assert result == expected - - _, kwargs = mock_request.call_args - assert kwargs["json"]["value"] == "test-value" - assert kwargs["json"]["key"] == "custom-key" - - -def test_create_connector_context_property_error(chronicle_client): - """Test create_connector_context_property raises APIError on failure.""" - with patch( - "secops.chronicle.integration.connector_context_properties.chronicle_request", - side_effect=APIError("Failed to create context property"), - ): - with pytest.raises(APIError) as exc_info: - create_connector_context_property( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - value="test-value", - ) - assert "Failed to create context property" in str(exc_info.value) - - -# -- update_connector_context_property tests -- - - -def test_update_connector_context_property_success(chronicle_client): - """Test update_connector_context_property updates value.""" - expected = { - "name": "contextProperties/prop1", - "value": "updated-value", - } - - with patch( - "secops.chronicle.integration.connector_context_properties.chronicle_request", - return_value=expected, - ) as mock_request: - result = update_connector_context_property( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - context_property_id="prop1", - value="updated-value", - ) - - assert result == expected - - _, kwargs = mock_request.call_args - assert kwargs["method"] == "PATCH" - assert "connectors/c1/contextProperties/prop1" in kwargs["endpoint_path"] - assert kwargs["json"]["value"] == "updated-value" - assert kwargs["params"]["updateMask"] == "value" - - -def test_update_connector_context_property_with_custom_mask(chronicle_client): - """Test update_connector_context_property with custom update_mask.""" - expected = {"name": "contextProperties/prop1"} - - with patch( - "secops.chronicle.integration.connector_context_properties.chronicle_request", - return_value=expected, - ) as mock_request: - result = update_connector_context_property( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - context_property_id="prop1", - value="updated-value", - update_mask="value", - ) - - assert result == expected - - _, kwargs = mock_request.call_args - assert kwargs["params"]["updateMask"] == "value" - - -def test_update_connector_context_property_error(chronicle_client): - """Test update_connector_context_property raises APIError on failure.""" - with patch( - "secops.chronicle.integration.connector_context_properties.chronicle_request", - side_effect=APIError("Failed to update context property"), - ): - with pytest.raises(APIError) as exc_info: - update_connector_context_property( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - context_property_id="prop1", - value="updated-value", - ) - assert "Failed to update context property" in str(exc_info.value) - - -# -- delete_all_connector_context_properties tests -- - - -def test_delete_all_connector_context_properties_success(chronicle_client): - """Test delete_all_connector_context_properties issues POST request.""" - with patch( - "secops.chronicle.integration.connector_context_properties.chronicle_request", - return_value=None, - ) as mock_request: - delete_all_connector_context_properties( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - ) - - _, kwargs = mock_request.call_args - assert kwargs["method"] == "POST" - assert "connectors/c1/contextProperties:clearAll" in kwargs["endpoint_path"] - assert kwargs["api_version"] == APIVersion.V1BETA - assert kwargs["json"] == {} - - -def test_delete_all_connector_context_properties_with_context_id(chronicle_client): - """Test delete_all_connector_context_properties with context_id.""" - with patch( - "secops.chronicle.integration.connector_context_properties.chronicle_request", - return_value=None, - ) as mock_request: - delete_all_connector_context_properties( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - context_id="my-context", - ) - - _, kwargs = mock_request.call_args - assert kwargs["json"]["contextId"] == "my-context" - - -def test_delete_all_connector_context_properties_error(chronicle_client): - """Test delete_all_connector_context_properties raises APIError on failure.""" - with patch( - "secops.chronicle.integration.connector_context_properties.chronicle_request", - side_effect=APIError("Failed to clear context properties"), - ): - with pytest.raises(APIError) as exc_info: - delete_all_connector_context_properties( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - ) - assert "Failed to clear context properties" in str(exc_info.value) - - -# -- API version tests -- - - -def test_list_connector_context_properties_custom_api_version(chronicle_client): - """Test list_connector_context_properties with custom API version.""" - expected = {"contextProperties": []} - - with patch( - "secops.chronicle.integration.connector_context_properties.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated: - result = list_connector_context_properties( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - api_version=APIVersion.V1ALPHA, - ) - - assert result == expected - - _, kwargs = mock_paginated.call_args - assert kwargs["api_version"] == APIVersion.V1ALPHA - - -def test_get_connector_context_property_custom_api_version(chronicle_client): - """Test get_connector_context_property with custom API version.""" - expected = {"name": "contextProperties/prop1"} - - with patch( - "secops.chronicle.integration.connector_context_properties.chronicle_request", - return_value=expected, - ) as mock_request: - result = get_connector_context_property( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - context_property_id="prop1", - api_version=APIVersion.V1ALPHA, - ) - - assert result == expected - - _, kwargs = mock_request.call_args - assert kwargs["api_version"] == APIVersion.V1ALPHA - - -def test_delete_connector_context_property_custom_api_version(chronicle_client): - """Test delete_connector_context_property with custom API version.""" - with patch( - "secops.chronicle.integration.connector_context_properties.chronicle_request", - return_value=None, - ) as mock_request: - delete_connector_context_property( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - context_property_id="prop1", - api_version=APIVersion.V1ALPHA, - ) - - _, kwargs = mock_request.call_args - assert kwargs["api_version"] == APIVersion.V1ALPHA - - -def test_create_connector_context_property_custom_api_version(chronicle_client): - """Test create_connector_context_property with custom API version.""" - expected = {"name": "contextProperties/new"} - - with patch( - "secops.chronicle.integration.connector_context_properties.chronicle_request", - return_value=expected, - ) as mock_request: - result = create_connector_context_property( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - value="test-value", - api_version=APIVersion.V1ALPHA, - ) - - assert result == expected - - _, kwargs = mock_request.call_args - assert kwargs["api_version"] == APIVersion.V1ALPHA - - -def test_update_connector_context_property_custom_api_version(chronicle_client): - """Test update_connector_context_property with custom API version.""" - expected = {"name": "contextProperties/prop1"} - - with patch( - "secops.chronicle.integration.connector_context_properties.chronicle_request", - return_value=expected, - ) as mock_request: - result = update_connector_context_property( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - context_property_id="prop1", - value="updated-value", - api_version=APIVersion.V1ALPHA, - ) - - assert result == expected - - _, kwargs = mock_request.call_args - assert kwargs["api_version"] == APIVersion.V1ALPHA - - -def test_delete_all_connector_context_properties_custom_api_version(chronicle_client): - """Test delete_all_connector_context_properties with custom API version.""" - with patch( - "secops.chronicle.integration.connector_context_properties.chronicle_request", - return_value=None, - ) as mock_request: - delete_all_connector_context_properties( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - api_version=APIVersion.V1ALPHA, - ) - - _, kwargs = mock_request.call_args - assert kwargs["api_version"] == APIVersion.V1ALPHA - diff --git a/tests/chronicle/integration/test_connector_instance_logs.py b/tests/chronicle/integration/test_connector_instance_logs.py deleted file mode 100644 index 873264fc..00000000 --- a/tests/chronicle/integration/test_connector_instance_logs.py +++ /dev/null @@ -1,256 +0,0 @@ -# Copyright 2025 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. -# -"""Tests for Chronicle integration connector instance logs functions.""" - -from unittest.mock import Mock, patch - -import pytest - -from secops.chronicle.client import ChronicleClient -from secops.chronicle.models import APIVersion -from secops.chronicle.integration.connector_instance_logs import ( - list_connector_instance_logs, - get_connector_instance_log, -) -from secops.exceptions import APIError - - -@pytest.fixture -def chronicle_client(): - """Create a Chronicle client for testing.""" - with patch("secops.auth.SecOpsAuth") as mock_auth: - mock_session = Mock() - mock_session.headers = {} - mock_auth.return_value.session = mock_session - return ChronicleClient( - customer_id="test-customer", - project_id="test-project", - default_api_version=APIVersion.V1BETA, - ) - - -# -- list_connector_instance_logs tests -- - - -def test_list_connector_instance_logs_success(chronicle_client): - """Test list_connector_instance_logs delegates to paginated request.""" - expected = { - "logs": [{"name": "log1"}, {"name": "log2"}], - "nextPageToken": "t", - } - - with patch( - "secops.chronicle.integration.connector_instance_logs.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated, patch( - "secops.chronicle.integration.connector_instance_logs.format_resource_id", - return_value="My Integration", - ): - result = list_connector_instance_logs( - chronicle_client, - integration_name="My Integration", - connector_id="c1", - connector_instance_id="ci1", - page_size=10, - page_token="next-token", - ) - - assert result == expected - - _, kwargs = mock_paginated.call_args - assert "connectors/c1/connectorInstances/ci1/logs" in kwargs["path"] - assert kwargs["items_key"] == "logs" - assert kwargs["page_size"] == 10 - assert kwargs["page_token"] == "next-token" - - -def test_list_connector_instance_logs_default_args(chronicle_client): - """Test list_connector_instance_logs with default args.""" - expected = {"logs": []} - - with patch( - "secops.chronicle.integration.connector_instance_logs.chronicle_paginated_request", - return_value=expected, - ): - result = list_connector_instance_logs( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - connector_instance_id="ci1", - ) - - assert result == expected - - -def test_list_connector_instance_logs_with_filters(chronicle_client): - """Test list_connector_instance_logs with filter and order_by.""" - expected = {"logs": [{"name": "log1"}]} - - with patch( - "secops.chronicle.integration.connector_instance_logs.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated: - result = list_connector_instance_logs( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - connector_instance_id="ci1", - filter_string='severity = "ERROR"', - order_by="timestamp desc", - ) - - assert result == expected - - _, kwargs = mock_paginated.call_args - assert kwargs["extra_params"] == { - "filter": 'severity = "ERROR"', - "orderBy": "timestamp desc", - } - - -def test_list_connector_instance_logs_as_list(chronicle_client): - """Test list_connector_instance_logs returns list when as_list=True.""" - expected = [{"name": "log1"}, {"name": "log2"}] - - with patch( - "secops.chronicle.integration.connector_instance_logs.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated: - result = list_connector_instance_logs( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - connector_instance_id="ci1", - as_list=True, - ) - - assert result == expected - - _, kwargs = mock_paginated.call_args - assert kwargs["as_list"] is True - - -def test_list_connector_instance_logs_error(chronicle_client): - """Test list_connector_instance_logs raises APIError on failure.""" - with patch( - "secops.chronicle.integration.connector_instance_logs.chronicle_paginated_request", - side_effect=APIError("Failed to list connector instance logs"), - ): - with pytest.raises(APIError) as exc_info: - list_connector_instance_logs( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - connector_instance_id="ci1", - ) - assert "Failed to list connector instance logs" in str(exc_info.value) - - -# -- get_connector_instance_log tests -- - - -def test_get_connector_instance_log_success(chronicle_client): - """Test get_connector_instance_log issues GET request.""" - expected = { - "name": "logs/log1", - "message": "Test log message", - "severity": "INFO", - "timestamp": "2026-03-09T10:00:00Z", - } - - with patch( - "secops.chronicle.integration.connector_instance_logs.chronicle_request", - return_value=expected, - ) as mock_request: - result = get_connector_instance_log( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - connector_instance_id="ci1", - log_id="log1", - ) - - assert result == expected - - _, kwargs = mock_request.call_args - assert kwargs["method"] == "GET" - assert "connectors/c1/connectorInstances/ci1/logs/log1" in kwargs["endpoint_path"] - assert kwargs["api_version"] == APIVersion.V1BETA - - -def test_get_connector_instance_log_error(chronicle_client): - """Test get_connector_instance_log raises APIError on failure.""" - with patch( - "secops.chronicle.integration.connector_instance_logs.chronicle_request", - side_effect=APIError("Failed to get connector instance log"), - ): - with pytest.raises(APIError) as exc_info: - get_connector_instance_log( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - connector_instance_id="ci1", - log_id="log1", - ) - assert "Failed to get connector instance log" in str(exc_info.value) - - -# -- API version tests -- - - -def test_list_connector_instance_logs_custom_api_version(chronicle_client): - """Test list_connector_instance_logs with custom API version.""" - expected = {"logs": []} - - with patch( - "secops.chronicle.integration.connector_instance_logs.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated: - result = list_connector_instance_logs( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - connector_instance_id="ci1", - api_version=APIVersion.V1ALPHA, - ) - - assert result == expected - - _, kwargs = mock_paginated.call_args - assert kwargs["api_version"] == APIVersion.V1ALPHA - - -def test_get_connector_instance_log_custom_api_version(chronicle_client): - """Test get_connector_instance_log with custom API version.""" - expected = {"name": "logs/log1"} - - with patch( - "secops.chronicle.integration.connector_instance_logs.chronicle_request", - return_value=expected, - ) as mock_request: - result = get_connector_instance_log( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - connector_instance_id="ci1", - log_id="log1", - api_version=APIVersion.V1ALPHA, - ) - - assert result == expected - - _, kwargs = mock_request.call_args - assert kwargs["api_version"] == APIVersion.V1ALPHA - diff --git a/tests/chronicle/integration/test_connector_instances.py b/tests/chronicle/integration/test_connector_instances.py deleted file mode 100644 index 25bf3abe..00000000 --- a/tests/chronicle/integration/test_connector_instances.py +++ /dev/null @@ -1,845 +0,0 @@ -# Copyright 2025 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. -# -"""Tests for Chronicle integration connector instances functions.""" - -from unittest.mock import Mock, patch - -import pytest - -from secops.chronicle.client import ChronicleClient -from secops.chronicle.models import ( - APIVersion, - ConnectorInstanceParameter, -) -from secops.chronicle.integration.connector_instances import ( - list_connector_instances, - get_connector_instance, - delete_connector_instance, - create_connector_instance, - update_connector_instance, - get_connector_instance_latest_definition, - set_connector_instance_logs_collection, - run_connector_instance_on_demand, -) -from secops.exceptions import APIError - - -@pytest.fixture -def chronicle_client(): - """Create a Chronicle client for testing.""" - with patch("secops.auth.SecOpsAuth") as mock_auth: - mock_session = Mock() - mock_session.headers = {} - mock_auth.return_value.session = mock_session - return ChronicleClient( - customer_id="test-customer", - project_id="test-project", - default_api_version=APIVersion.V1BETA, - ) - - -# -- list_connector_instances tests -- - - -def test_list_connector_instances_success(chronicle_client): - """Test list_connector_instances delegates to chronicle_paginated_request.""" - expected = { - "connectorInstances": [{"name": "ci1"}, {"name": "ci2"}], - "nextPageToken": "t", - } - - with patch( - "secops.chronicle.integration.connector_instances.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated, patch( - "secops.chronicle.integration.connector_instances.format_resource_id", - return_value="My Integration", - ): - result = list_connector_instances( - chronicle_client, - integration_name="My Integration", - connector_id="c1", - page_size=10, - page_token="next-token", - ) - - assert result == expected - - _, kwargs = mock_paginated.call_args - assert "connectors/c1/connectorInstances" in kwargs["path"] - assert kwargs["items_key"] == "connectorInstances" - assert kwargs["page_size"] == 10 - assert kwargs["page_token"] == "next-token" - - -def test_list_connector_instances_default_args(chronicle_client): - """Test list_connector_instances with default args.""" - expected = {"connectorInstances": []} - - with patch( - "secops.chronicle.integration.connector_instances.chronicle_paginated_request", - return_value=expected, - ): - result = list_connector_instances( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - ) - - assert result == expected - - -def test_list_connector_instances_with_filters(chronicle_client): - """Test list_connector_instances with filter and order_by.""" - expected = {"connectorInstances": [{"name": "ci1"}]} - - with patch( - "secops.chronicle.integration.connector_instances.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated: - result = list_connector_instances( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - filter_string='enabled = true', - order_by="displayName", - ) - - assert result == expected - - _, kwargs = mock_paginated.call_args - assert kwargs["extra_params"] == { - "filter": 'enabled = true', - "orderBy": "displayName", - } - - -def test_list_connector_instances_as_list(chronicle_client): - """Test list_connector_instances returns list when as_list=True.""" - expected = [{"name": "ci1"}, {"name": "ci2"}] - - with patch( - "secops.chronicle.integration.connector_instances.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated: - result = list_connector_instances( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - as_list=True, - ) - - assert result == expected - - _, kwargs = mock_paginated.call_args - assert kwargs["as_list"] is True - - -def test_list_connector_instances_error(chronicle_client): - """Test list_connector_instances raises APIError on failure.""" - with patch( - "secops.chronicle.integration.connector_instances.chronicle_paginated_request", - side_effect=APIError("Failed to list connector instances"), - ): - with pytest.raises(APIError) as exc_info: - list_connector_instances( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - ) - assert "Failed to list connector instances" in str(exc_info.value) - - -# -- get_connector_instance tests -- - - -def test_get_connector_instance_success(chronicle_client): - """Test get_connector_instance issues GET request.""" - expected = { - "name": "connectorInstances/ci1", - "displayName": "Test Instance", - "enabled": True, - } - - with patch( - "secops.chronicle.integration.connector_instances.chronicle_request", - return_value=expected, - ) as mock_request: - result = get_connector_instance( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - connector_instance_id="ci1", - ) - - assert result == expected - - _, kwargs = mock_request.call_args - assert kwargs["method"] == "GET" - assert "connectors/c1/connectorInstances/ci1" in kwargs["endpoint_path"] - assert kwargs["api_version"] == APIVersion.V1BETA - - -def test_get_connector_instance_error(chronicle_client): - """Test get_connector_instance raises APIError on failure.""" - with patch( - "secops.chronicle.integration.connector_instances.chronicle_request", - side_effect=APIError("Failed to get connector instance"), - ): - with pytest.raises(APIError) as exc_info: - get_connector_instance( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - connector_instance_id="ci1", - ) - assert "Failed to get connector instance" in str(exc_info.value) - - -# -- delete_connector_instance tests -- - - -def test_delete_connector_instance_success(chronicle_client): - """Test delete_connector_instance issues DELETE request.""" - with patch( - "secops.chronicle.integration.connector_instances.chronicle_request", - return_value=None, - ) as mock_request: - delete_connector_instance( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - connector_instance_id="ci1", - ) - - _, kwargs = mock_request.call_args - assert kwargs["method"] == "DELETE" - assert "connectors/c1/connectorInstances/ci1" in kwargs["endpoint_path"] - assert kwargs["api_version"] == APIVersion.V1BETA - - -def test_delete_connector_instance_error(chronicle_client): - """Test delete_connector_instance raises APIError on failure.""" - with patch( - "secops.chronicle.integration.connector_instances.chronicle_request", - side_effect=APIError("Failed to delete connector instance"), - ): - with pytest.raises(APIError) as exc_info: - delete_connector_instance( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - connector_instance_id="ci1", - ) - assert "Failed to delete connector instance" in str(exc_info.value) - - -# -- create_connector_instance tests -- - - -def test_create_connector_instance_required_fields_only(chronicle_client): - """Test create_connector_instance with required fields only.""" - expected = {"name": "connectorInstances/new", "displayName": "New Instance"} - - with patch( - "secops.chronicle.integration.connector_instances.chronicle_request", - return_value=expected, - ) as mock_request: - result = create_connector_instance( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - environment="production", - display_name="New Instance", - interval_seconds=3600, - timeout_seconds=300, - ) - - assert result == expected - - mock_request.assert_called_once() - _, kwargs = mock_request.call_args - assert kwargs["method"] == "POST" - assert "connectors/c1/connectorInstances" in kwargs["endpoint_path"] - assert kwargs["json"]["environment"] == "production" - assert kwargs["json"]["displayName"] == "New Instance" - assert kwargs["json"]["intervalSeconds"] == 3600 - assert kwargs["json"]["timeoutSeconds"] == 300 - - -def test_create_connector_instance_with_optional_fields(chronicle_client): - """Test create_connector_instance includes optional fields when provided.""" - expected = {"name": "connectorInstances/new"} - - with patch( - "secops.chronicle.integration.connector_instances.chronicle_request", - return_value=expected, - ) as mock_request: - result = create_connector_instance( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - environment="production", - display_name="New Instance", - interval_seconds=3600, - timeout_seconds=300, - description="Test description", - agent="agent-123", - allow_list=["192.168.1.0/24"], - product_field_name="product", - event_field_name="event", - integration_version="1.0.0", - version="2.0.0", - logging_enabled_until_unix_ms="1234567890000", - connector_instance_id="custom-id", - enabled=True, - ) - - assert result == expected - - _, kwargs = mock_request.call_args - assert kwargs["json"]["description"] == "Test description" - assert kwargs["json"]["agent"] == "agent-123" - assert kwargs["json"]["allowList"] == ["192.168.1.0/24"] - assert kwargs["json"]["productFieldName"] == "product" - assert kwargs["json"]["eventFieldName"] == "event" - assert kwargs["json"]["integrationVersion"] == "1.0.0" - assert kwargs["json"]["version"] == "2.0.0" - assert kwargs["json"]["loggingEnabledUntilUnixMs"] == "1234567890000" - assert kwargs["json"]["id"] == "custom-id" - assert kwargs["json"]["enabled"] is True - - -def test_create_connector_instance_with_parameters(chronicle_client): - """Test create_connector_instance with ConnectorInstanceParameter objects.""" - expected = {"name": "connectorInstances/new"} - - param = ConnectorInstanceParameter() - param.value = "secret-key" - - with patch( - "secops.chronicle.integration.connector_instances.chronicle_request", - return_value=expected, - ) as mock_request: - result = create_connector_instance( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - environment="production", - display_name="New Instance", - interval_seconds=3600, - timeout_seconds=300, - parameters=[param], - ) - - assert result == expected - - _, kwargs = mock_request.call_args - assert len(kwargs["json"]["parameters"]) == 1 - assert kwargs["json"]["parameters"][0]["value"] == "secret-key" - - -def test_create_connector_instance_with_dict_parameters(chronicle_client): - """Test create_connector_instance with dict parameters.""" - expected = {"name": "connectorInstances/new"} - - with patch( - "secops.chronicle.integration.connector_instances.chronicle_request", - return_value=expected, - ) as mock_request: - result = create_connector_instance( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - environment="production", - display_name="New Instance", - interval_seconds=3600, - timeout_seconds=300, - parameters=[{"displayName": "API Key", "value": "secret-key"}], - ) - - assert result == expected - - _, kwargs = mock_request.call_args - assert kwargs["json"]["parameters"][0]["displayName"] == "API Key" - - -def test_create_connector_instance_error(chronicle_client): - """Test create_connector_instance raises APIError on failure.""" - with patch( - "secops.chronicle.integration.connector_instances.chronicle_request", - side_effect=APIError("Failed to create connector instance"), - ): - with pytest.raises(APIError) as exc_info: - create_connector_instance( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - environment="production", - display_name="New Instance", - interval_seconds=3600, - timeout_seconds=300, - ) - assert "Failed to create connector instance" in str(exc_info.value) - - -# -- update_connector_instance tests -- - - -def test_update_connector_instance_success(chronicle_client): - """Test update_connector_instance updates fields.""" - expected = {"name": "connectorInstances/ci1", "displayName": "Updated"} - - with patch( - "secops.chronicle.integration.connector_instances.chronicle_request", - return_value=expected, - ) as mock_request: - result = update_connector_instance( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - connector_instance_id="ci1", - display_name="Updated", - enabled=True, - ) - - assert result == expected - - _, kwargs = mock_request.call_args - assert kwargs["method"] == "PATCH" - assert "connectors/c1/connectorInstances/ci1" in kwargs["endpoint_path"] - assert kwargs["json"]["displayName"] == "Updated" - assert kwargs["json"]["enabled"] is True - # Check that update mask contains the expected fields - assert "displayName" in kwargs["params"]["updateMask"] - assert "enabled" in kwargs["params"]["updateMask"] - - -def test_update_connector_instance_with_custom_mask(chronicle_client): - """Test update_connector_instance with custom update_mask.""" - expected = {"name": "connectorInstances/ci1"} - - with patch( - "secops.chronicle.integration.connector_instances.chronicle_request", - return_value=expected, - ) as mock_request: - result = update_connector_instance( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - connector_instance_id="ci1", - display_name="Updated", - update_mask="displayName", - ) - - assert result == expected - - _, kwargs = mock_request.call_args - assert kwargs["params"]["updateMask"] == "displayName" - - -def test_update_connector_instance_with_parameters(chronicle_client): - """Test update_connector_instance with parameters.""" - expected = {"name": "connectorInstances/ci1"} - - param = ConnectorInstanceParameter() - param.value = "new-key" - - with patch( - "secops.chronicle.integration.connector_instances.chronicle_request", - return_value=expected, - ) as mock_request: - result = update_connector_instance( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - connector_instance_id="ci1", - parameters=[param], - ) - - assert result == expected - - _, kwargs = mock_request.call_args - assert len(kwargs["json"]["parameters"]) == 1 - assert kwargs["json"]["parameters"][0]["value"] == "new-key" - - -def test_update_connector_instance_error(chronicle_client): - """Test update_connector_instance raises APIError on failure.""" - with patch( - "secops.chronicle.integration.connector_instances.chronicle_request", - side_effect=APIError("Failed to update connector instance"), - ): - with pytest.raises(APIError) as exc_info: - update_connector_instance( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - connector_instance_id="ci1", - display_name="Updated", - ) - assert "Failed to update connector instance" in str(exc_info.value) - - -# -- get_connector_instance_latest_definition tests -- - - -def test_get_connector_instance_latest_definition_success(chronicle_client): - """Test get_connector_instance_latest_definition issues GET request.""" - expected = { - "name": "connectorInstances/ci1", - "displayName": "Refreshed Instance", - } - - with patch( - "secops.chronicle.integration.connector_instances.chronicle_request", - return_value=expected, - ) as mock_request: - result = get_connector_instance_latest_definition( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - connector_instance_id="ci1", - ) - - assert result == expected - - _, kwargs = mock_request.call_args - assert kwargs["method"] == "GET" - assert "connectorInstances/ci1:fetchLatestDefinition" in kwargs["endpoint_path"] - assert kwargs["api_version"] == APIVersion.V1BETA - - -def test_get_connector_instance_latest_definition_error(chronicle_client): - """Test get_connector_instance_latest_definition raises APIError on failure.""" - with patch( - "secops.chronicle.integration.connector_instances.chronicle_request", - side_effect=APIError("Failed to fetch latest definition"), - ): - with pytest.raises(APIError) as exc_info: - get_connector_instance_latest_definition( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - connector_instance_id="ci1", - ) - assert "Failed to fetch latest definition" in str(exc_info.value) - - -# -- set_connector_instance_logs_collection tests -- - - -def test_set_connector_instance_logs_collection_enable(chronicle_client): - """Test set_connector_instance_logs_collection enables logs.""" - expected = {"loggingEnabledUntilUnixMs": "1234567890000"} - - with patch( - "secops.chronicle.integration.connector_instances.chronicle_request", - return_value=expected, - ) as mock_request: - result = set_connector_instance_logs_collection( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - connector_instance_id="ci1", - enabled=True, - ) - - assert result == expected - - _, kwargs = mock_request.call_args - assert kwargs["method"] == "POST" - assert "connectorInstances/ci1:setLogsCollection" in kwargs["endpoint_path"] - assert kwargs["json"]["enabled"] is True - - -def test_set_connector_instance_logs_collection_disable(chronicle_client): - """Test set_connector_instance_logs_collection disables logs.""" - expected = {} - - with patch( - "secops.chronicle.integration.connector_instances.chronicle_request", - return_value=expected, - ) as mock_request: - result = set_connector_instance_logs_collection( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - connector_instance_id="ci1", - enabled=False, - ) - - assert result == expected - - _, kwargs = mock_request.call_args - assert kwargs["json"]["enabled"] is False - - -def test_set_connector_instance_logs_collection_error(chronicle_client): - """Test set_connector_instance_logs_collection raises APIError on failure.""" - with patch( - "secops.chronicle.integration.connector_instances.chronicle_request", - side_effect=APIError("Failed to set logs collection"), - ): - with pytest.raises(APIError) as exc_info: - set_connector_instance_logs_collection( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - connector_instance_id="ci1", - enabled=True, - ) - assert "Failed to set logs collection" in str(exc_info.value) - - -# -- run_connector_instance_on_demand tests -- - - -def test_run_connector_instance_on_demand_success(chronicle_client): - """Test run_connector_instance_on_demand triggers execution.""" - expected = { - "debugOutput": "Execution completed", - "success": True, - "sampleCases": [], - } - - connector_instance = { - "name": "connectorInstances/ci1", - "displayName": "Test Instance", - "parameters": [{"displayName": "param1", "value": "value1"}], - } - - with patch( - "secops.chronicle.integration.connector_instances.chronicle_request", - return_value=expected, - ) as mock_request: - result = run_connector_instance_on_demand( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - connector_instance_id="ci1", - connector_instance=connector_instance, - ) - - assert result == expected - - _, kwargs = mock_request.call_args - assert kwargs["method"] == "POST" - assert "connectorInstances/ci1:runOnDemand" in kwargs["endpoint_path"] - assert kwargs["json"]["connectorInstance"] == connector_instance - - -def test_run_connector_instance_on_demand_error(chronicle_client): - """Test run_connector_instance_on_demand raises APIError on failure.""" - connector_instance = {"name": "connectorInstances/ci1"} - - with patch( - "secops.chronicle.integration.connector_instances.chronicle_request", - side_effect=APIError("Failed to run connector instance"), - ): - with pytest.raises(APIError) as exc_info: - run_connector_instance_on_demand( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - connector_instance_id="ci1", - connector_instance=connector_instance, - ) - assert "Failed to run connector instance" in str(exc_info.value) - - -# -- API version tests -- - - -def test_list_connector_instances_custom_api_version(chronicle_client): - """Test list_connector_instances with custom API version.""" - expected = {"connectorInstances": []} - - with patch( - "secops.chronicle.integration.connector_instances.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated: - result = list_connector_instances( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - api_version=APIVersion.V1ALPHA, - ) - - assert result == expected - - _, kwargs = mock_paginated.call_args - assert kwargs["api_version"] == APIVersion.V1ALPHA - - -def test_get_connector_instance_custom_api_version(chronicle_client): - """Test get_connector_instance with custom API version.""" - expected = {"name": "connectorInstances/ci1"} - - with patch( - "secops.chronicle.integration.connector_instances.chronicle_request", - return_value=expected, - ) as mock_request: - result = get_connector_instance( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - connector_instance_id="ci1", - api_version=APIVersion.V1ALPHA, - ) - - assert result == expected - - _, kwargs = mock_request.call_args - assert kwargs["api_version"] == APIVersion.V1ALPHA - - -def test_delete_connector_instance_custom_api_version(chronicle_client): - """Test delete_connector_instance with custom API version.""" - with patch( - "secops.chronicle.integration.connector_instances.chronicle_request", - return_value=None, - ) as mock_request: - delete_connector_instance( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - connector_instance_id="ci1", - api_version=APIVersion.V1ALPHA, - ) - - _, kwargs = mock_request.call_args - assert kwargs["api_version"] == APIVersion.V1ALPHA - - -def test_create_connector_instance_custom_api_version(chronicle_client): - """Test create_connector_instance with custom API version.""" - expected = {"name": "connectorInstances/new"} - - with patch( - "secops.chronicle.integration.connector_instances.chronicle_request", - return_value=expected, - ) as mock_request: - result = create_connector_instance( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - environment="production", - display_name="New Instance", - interval_seconds=3600, - timeout_seconds=300, - api_version=APIVersion.V1ALPHA, - ) - - assert result == expected - - _, kwargs = mock_request.call_args - assert kwargs["api_version"] == APIVersion.V1ALPHA - - -def test_update_connector_instance_custom_api_version(chronicle_client): - """Test update_connector_instance with custom API version.""" - expected = {"name": "connectorInstances/ci1"} - - with patch( - "secops.chronicle.integration.connector_instances.chronicle_request", - return_value=expected, - ) as mock_request: - result = update_connector_instance( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - connector_instance_id="ci1", - display_name="Updated", - api_version=APIVersion.V1ALPHA, - ) - - assert result == expected - - _, kwargs = mock_request.call_args - assert kwargs["api_version"] == APIVersion.V1ALPHA - - -def test_get_connector_instance_latest_definition_custom_api_version(chronicle_client): - """Test get_connector_instance_latest_definition with custom API version.""" - expected = {"name": "connectorInstances/ci1"} - - with patch( - "secops.chronicle.integration.connector_instances.chronicle_request", - return_value=expected, - ) as mock_request: - result = get_connector_instance_latest_definition( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - connector_instance_id="ci1", - api_version=APIVersion.V1ALPHA, - ) - - assert result == expected - - _, kwargs = mock_request.call_args - assert kwargs["api_version"] == APIVersion.V1ALPHA - - -def test_set_connector_instance_logs_collection_custom_api_version(chronicle_client): - """Test set_connector_instance_logs_collection with custom API version.""" - expected = {} - - with patch( - "secops.chronicle.integration.connector_instances.chronicle_request", - return_value=expected, - ) as mock_request: - result = set_connector_instance_logs_collection( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - connector_instance_id="ci1", - enabled=True, - api_version=APIVersion.V1ALPHA, - ) - - assert result == expected - - _, kwargs = mock_request.call_args - assert kwargs["api_version"] == APIVersion.V1ALPHA - - -def test_run_connector_instance_on_demand_custom_api_version(chronicle_client): - """Test run_connector_instance_on_demand with custom API version.""" - expected = {"success": True} - connector_instance = {"name": "connectorInstances/ci1"} - - with patch( - "secops.chronicle.integration.connector_instances.chronicle_request", - return_value=expected, - ) as mock_request: - result = run_connector_instance_on_demand( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - connector_instance_id="ci1", - connector_instance=connector_instance, - api_version=APIVersion.V1ALPHA, - ) - - assert result == expected - - _, kwargs = mock_request.call_args - assert kwargs["api_version"] == APIVersion.V1ALPHA - - - - diff --git a/tests/chronicle/integration/test_connector_revisions.py b/tests/chronicle/integration/test_connector_revisions.py deleted file mode 100644 index 7b214bcb..00000000 --- a/tests/chronicle/integration/test_connector_revisions.py +++ /dev/null @@ -1,385 +0,0 @@ -# Copyright 2025 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. -# -"""Tests for Chronicle marketplace integration connector revisions functions.""" - -from unittest.mock import Mock, patch - -import pytest - -from secops.chronicle.client import ChronicleClient -from secops.chronicle.models import APIVersion -from secops.chronicle.integration.connector_revisions import ( - list_integration_connector_revisions, - delete_integration_connector_revision, - create_integration_connector_revision, - rollback_integration_connector_revision, -) -from secops.exceptions import APIError - - -@pytest.fixture -def chronicle_client(): - """Create a Chronicle client for testing.""" - with patch("secops.auth.SecOpsAuth") as mock_auth: - mock_session = Mock() - mock_session.headers = {} - mock_auth.return_value.session = mock_session - return ChronicleClient( - customer_id="test-customer", - project_id="test-project", - default_api_version=APIVersion.V1BETA, - ) - - -# -- list_integration_connector_revisions tests -- - - -def test_list_integration_connector_revisions_success(chronicle_client): - """Test list_integration_connector_revisions delegates to chronicle_paginated_request.""" - expected = { - "revisions": [{"name": "r1"}, {"name": "r2"}], - "nextPageToken": "t", - } - - with patch( - "secops.chronicle.integration.connector_revisions.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated, patch( - "secops.chronicle.integration.connector_revisions.format_resource_id", - return_value="My Integration", - ): - result = list_integration_connector_revisions( - chronicle_client, - integration_name="My Integration", - connector_id="c1", - page_size=10, - page_token="next-token", - ) - - assert result == expected - - _, kwargs = mock_paginated.call_args - assert "connectors/c1/revisions" in kwargs["path"] - assert kwargs["items_key"] == "revisions" - assert kwargs["page_size"] == 10 - assert kwargs["page_token"] == "next-token" - - -def test_list_integration_connector_revisions_default_args(chronicle_client): - """Test list_integration_connector_revisions with default args.""" - expected = {"revisions": []} - - with patch( - "secops.chronicle.integration.connector_revisions.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated: - result = list_integration_connector_revisions( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - ) - - assert result == expected - - -def test_list_integration_connector_revisions_with_filters(chronicle_client): - """Test list_integration_connector_revisions with filter and order_by.""" - expected = {"revisions": [{"name": "r1"}]} - - with patch( - "secops.chronicle.integration.connector_revisions.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated: - result = list_integration_connector_revisions( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - filter_string='version = "1.0"', - order_by="createTime", - ) - - assert result == expected - - _, kwargs = mock_paginated.call_args - assert kwargs["extra_params"] == { - "filter": 'version = "1.0"', - "orderBy": "createTime", - } - - -def test_list_integration_connector_revisions_as_list(chronicle_client): - """Test list_integration_connector_revisions returns list when as_list=True.""" - expected = [{"name": "r1"}, {"name": "r2"}] - - with patch( - "secops.chronicle.integration.connector_revisions.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated: - result = list_integration_connector_revisions( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - as_list=True, - ) - - assert result == expected - - _, kwargs = mock_paginated.call_args - assert kwargs["as_list"] is True - - -def test_list_integration_connector_revisions_error(chronicle_client): - """Test list_integration_connector_revisions raises APIError on failure.""" - with patch( - "secops.chronicle.integration.connector_revisions.chronicle_paginated_request", - side_effect=APIError("Failed to list connector revisions"), - ): - with pytest.raises(APIError) as exc_info: - list_integration_connector_revisions( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - ) - assert "Failed to list connector revisions" in str(exc_info.value) - - -# -- delete_integration_connector_revision tests -- - - -def test_delete_integration_connector_revision_success(chronicle_client): - """Test delete_integration_connector_revision issues DELETE request.""" - with patch( - "secops.chronicle.integration.connector_revisions.chronicle_request", - return_value=None, - ) as mock_request: - delete_integration_connector_revision( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - revision_id="r1", - ) - - _, kwargs = mock_request.call_args - assert kwargs["method"] == "DELETE" - assert "connectors/c1/revisions/r1" in kwargs["endpoint_path"] - assert kwargs["api_version"] == APIVersion.V1BETA - - -def test_delete_integration_connector_revision_error(chronicle_client): - """Test delete_integration_connector_revision raises APIError on failure.""" - with patch( - "secops.chronicle.integration.connector_revisions.chronicle_request", - side_effect=APIError("Failed to delete connector revision"), - ): - with pytest.raises(APIError) as exc_info: - delete_integration_connector_revision( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - revision_id="r1", - ) - assert "Failed to delete connector revision" in str(exc_info.value) - - -# -- create_integration_connector_revision tests -- - - -def test_create_integration_connector_revision_required_fields_only( - chronicle_client, -): - """Test create_integration_connector_revision with required fields only.""" - expected = { - "name": "revisions/new", - "connector": {"displayName": "My Connector"}, - } - connector_dict = { - "displayName": "My Connector", - "script": "print('hello')", - "version": 1, - "enabled": True, - "custom": True, - } - - with patch( - "secops.chronicle.integration.connector_revisions.chronicle_request", - return_value=expected, - ) as mock_request: - result = create_integration_connector_revision( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - connector=connector_dict, - ) - - assert result == expected - - mock_request.assert_called_once_with( - chronicle_client, - method="POST", - endpoint_path=( - "integrations/test-integration/connectors/c1/revisions" - ), - api_version=APIVersion.V1BETA, - json={"connector": connector_dict}, - ) - - -def test_create_integration_connector_revision_with_comment(chronicle_client): - """Test create_integration_connector_revision includes comment when provided.""" - expected = {"name": "revisions/new"} - connector_dict = { - "displayName": "My Connector", - "script": "print('hello')", - "version": 1, - "enabled": True, - "custom": True, - } - - with patch( - "secops.chronicle.integration.connector_revisions.chronicle_request", - return_value=expected, - ) as mock_request: - result = create_integration_connector_revision( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - connector=connector_dict, - comment="Backup before major update", - ) - - assert result == expected - - _, kwargs = mock_request.call_args - assert kwargs["json"]["comment"] == "Backup before major update" - assert kwargs["json"]["connector"] == connector_dict - - -def test_create_integration_connector_revision_error(chronicle_client): - """Test create_integration_connector_revision raises APIError on failure.""" - connector_dict = { - "displayName": "My Connector", - "script": "print('hello')", - "version": 1, - "enabled": True, - "custom": True, - } - - with patch( - "secops.chronicle.integration.connector_revisions.chronicle_request", - side_effect=APIError("Failed to create connector revision"), - ): - with pytest.raises(APIError) as exc_info: - create_integration_connector_revision( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - connector=connector_dict, - ) - assert "Failed to create connector revision" in str(exc_info.value) - - -# -- rollback_integration_connector_revision tests -- - - -def test_rollback_integration_connector_revision_success(chronicle_client): - """Test rollback_integration_connector_revision issues POST request.""" - expected = { - "name": "revisions/r1", - "connector": { - "displayName": "My Connector", - "script": "print('hello')", - }, - } - - with patch( - "secops.chronicle.integration.connector_revisions.chronicle_request", - return_value=expected, - ) as mock_request: - result = rollback_integration_connector_revision( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - revision_id="r1", - ) - - assert result == expected - - _, kwargs = mock_request.call_args - assert kwargs["method"] == "POST" - assert "connectors/c1/revisions/r1:rollback" in kwargs["endpoint_path"] - assert kwargs["api_version"] == APIVersion.V1BETA - - -def test_rollback_integration_connector_revision_error(chronicle_client): - """Test rollback_integration_connector_revision raises APIError on failure.""" - with patch( - "secops.chronicle.integration.connector_revisions.chronicle_request", - side_effect=APIError("Failed to rollback connector revision"), - ): - with pytest.raises(APIError) as exc_info: - rollback_integration_connector_revision( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - revision_id="r1", - ) - assert "Failed to rollback connector revision" in str(exc_info.value) - - -# -- API version tests -- - - -def test_list_integration_connector_revisions_custom_api_version( - chronicle_client, -): - """Test list_integration_connector_revisions with custom API version.""" - expected = {"revisions": []} - - with patch( - "secops.chronicle.integration.connector_revisions.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated: - result = list_integration_connector_revisions( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - api_version=APIVersion.V1ALPHA, - ) - - assert result == expected - - _, kwargs = mock_paginated.call_args - assert kwargs["api_version"] == APIVersion.V1ALPHA - - -def test_delete_integration_connector_revision_custom_api_version( - chronicle_client, -): - """Test delete_integration_connector_revision with custom API version.""" - with patch( - "secops.chronicle.integration.connector_revisions.chronicle_request", - return_value=None, - ) as mock_request: - delete_integration_connector_revision( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - revision_id="r1", - api_version=APIVersion.V1ALPHA, - ) - - _, kwargs = mock_request.call_args - assert kwargs["api_version"] == APIVersion.V1ALPHA - diff --git a/tests/chronicle/integration/test_connectors.py b/tests/chronicle/integration/test_connectors.py deleted file mode 100644 index 3aca859a..00000000 --- a/tests/chronicle/integration/test_connectors.py +++ /dev/null @@ -1,665 +0,0 @@ -# Copyright 2025 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. -# -"""Tests for Chronicle marketplace integration connectors functions.""" - -from unittest.mock import Mock, patch - -import pytest - -from secops.chronicle.client import ChronicleClient -from secops.chronicle.models import ( - APIVersion, - ConnectorParameter, - ParamType, - ConnectorParamMode, - ConnectorRule, - ConnectorRuleType, -) -from secops.chronicle.integration.connectors import ( - list_integration_connectors, - get_integration_connector, - delete_integration_connector, - create_integration_connector, - update_integration_connector, - execute_integration_connector_test, - get_integration_connector_template, -) -from secops.exceptions import APIError - - -@pytest.fixture -def chronicle_client(): - """Create a Chronicle client for testing.""" - with patch("secops.auth.SecOpsAuth") as mock_auth: - mock_session = Mock() - mock_session.headers = {} - mock_auth.return_value.session = mock_session - return ChronicleClient( - customer_id="test-customer", - project_id="test-project", - default_api_version=APIVersion.V1BETA, - ) - - -# -- list_integration_connectors tests -- - - -def test_list_integration_connectors_success(chronicle_client): - """Test list_integration_connectors delegates to chronicle_paginated_request.""" - expected = {"connectors": [{"name": "c1"}, {"name": "c2"}], "nextPageToken": "t"} - - with patch( - "secops.chronicle.integration.connectors.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated, patch( - "secops.chronicle.integration.connectors.format_resource_id", - return_value="My Integration", - ): - result = list_integration_connectors( - chronicle_client, - integration_name="My Integration", - page_size=10, - page_token="next-token", - ) - - assert result == expected - - mock_paginated.assert_called_once_with( - chronicle_client, - api_version=APIVersion.V1BETA, - path="integrations/My Integration/connectors", - items_key="connectors", - page_size=10, - page_token="next-token", - extra_params={}, - as_list=False, - ) - - -def test_list_integration_connectors_default_args(chronicle_client): - """Test list_integration_connectors with default args.""" - expected = {"connectors": []} - - with patch( - "secops.chronicle.integration.connectors.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated: - result = list_integration_connectors( - chronicle_client, - integration_name="test-integration", - ) - - assert result == expected - - -def test_list_integration_connectors_with_filters(chronicle_client): - """Test list_integration_connectors with filter and order_by.""" - expected = {"connectors": [{"name": "c1"}]} - - with patch( - "secops.chronicle.integration.connectors.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated: - result = list_integration_connectors( - chronicle_client, - integration_name="test-integration", - filter_string="enabled=true", - order_by="displayName", - exclude_staging=True, - ) - - assert result == expected - - _, kwargs = mock_paginated.call_args - assert kwargs["extra_params"] == { - "filter": "enabled=true", - "orderBy": "displayName", - "excludeStaging": True, - } - - -def test_list_integration_connectors_as_list(chronicle_client): - """Test list_integration_connectors returns list when as_list=True.""" - expected = [{"name": "c1"}, {"name": "c2"}] - - with patch( - "secops.chronicle.integration.connectors.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated: - result = list_integration_connectors( - chronicle_client, - integration_name="test-integration", - as_list=True, - ) - - assert result == expected - - _, kwargs = mock_paginated.call_args - assert kwargs["as_list"] is True - - -def test_list_integration_connectors_error(chronicle_client): - """Test list_integration_connectors raises APIError on failure.""" - with patch( - "secops.chronicle.integration.connectors.chronicle_paginated_request", - side_effect=APIError("Failed to list integration connectors"), - ): - with pytest.raises(APIError) as exc_info: - list_integration_connectors( - chronicle_client, - integration_name="test-integration", - ) - assert "Failed to list integration connectors" in str(exc_info.value) - - -# -- get_integration_connector tests -- - - -def test_get_integration_connector_success(chronicle_client): - """Test get_integration_connector issues GET request.""" - expected = { - "name": "connectors/c1", - "displayName": "My Connector", - "script": "print('hello')", - } - - with patch( - "secops.chronicle.integration.connectors.chronicle_request", - return_value=expected, - ) as mock_request: - result = get_integration_connector( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - ) - - assert result == expected - - mock_request.assert_called_once_with( - chronicle_client, - method="GET", - endpoint_path="integrations/test-integration/connectors/c1", - api_version=APIVersion.V1BETA, - ) - - -def test_get_integration_connector_error(chronicle_client): - """Test get_integration_connector raises APIError on failure.""" - with patch( - "secops.chronicle.integration.connectors.chronicle_request", - side_effect=APIError("Failed to get integration connector"), - ): - with pytest.raises(APIError) as exc_info: - get_integration_connector( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - ) - assert "Failed to get integration connector" in str(exc_info.value) - - -# -- delete_integration_connector tests -- - - -def test_delete_integration_connector_success(chronicle_client): - """Test delete_integration_connector issues DELETE request.""" - with patch( - "secops.chronicle.integration.connectors.chronicle_request", - return_value=None, - ) as mock_request: - delete_integration_connector( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - ) - - mock_request.assert_called_once_with( - chronicle_client, - method="DELETE", - endpoint_path="integrations/test-integration/connectors/c1", - api_version=APIVersion.V1BETA, - ) - - -def test_delete_integration_connector_error(chronicle_client): - """Test delete_integration_connector raises APIError on failure.""" - with patch( - "secops.chronicle.integration.connectors.chronicle_request", - side_effect=APIError("Failed to delete integration connector"), - ): - with pytest.raises(APIError) as exc_info: - delete_integration_connector( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - ) - assert "Failed to delete integration connector" in str(exc_info.value) - - -# -- create_integration_connector tests -- - - -def test_create_integration_connector_required_fields_only(chronicle_client): - """Test create_integration_connector sends only required fields when optionals omitted.""" - expected = {"name": "connectors/new", "displayName": "My Connector"} - - with patch( - "secops.chronicle.integration.connectors.chronicle_request", - return_value=expected, - ) as mock_request: - result = create_integration_connector( - chronicle_client, - integration_name="test-integration", - display_name="My Connector", - script="print('hi')", - timeout_seconds=300, - enabled=True, - product_field_name="product", - event_field_name="event", - ) - - assert result == expected - - mock_request.assert_called_once_with( - chronicle_client, - method="POST", - endpoint_path="integrations/test-integration/connectors", - api_version=APIVersion.V1BETA, - json={ - "displayName": "My Connector", - "script": "print('hi')", - "timeoutSeconds": 300, - "enabled": True, - "productFieldName": "product", - "eventFieldName": "event", - }, - ) - - -def test_create_integration_connector_with_optional_fields(chronicle_client): - """Test create_integration_connector includes optional fields when provided.""" - expected = {"name": "connectors/new"} - - with patch( - "secops.chronicle.integration.connectors.chronicle_request", - return_value=expected, - ) as mock_request: - result = create_integration_connector( - chronicle_client, - integration_name="test-integration", - display_name="My Connector", - script="print('hi')", - timeout_seconds=300, - enabled=True, - product_field_name="product", - event_field_name="event", - description="Test connector", - parameters=[{"name": "p1", "type": "STRING"}], - rules=[{"name": "r1", "type": "MAPPING"}], - ) - - assert result == expected - - _, kwargs = mock_request.call_args - assert kwargs["json"]["description"] == "Test connector" - assert kwargs["json"]["parameters"] == [{"name": "p1", "type": "STRING"}] - assert kwargs["json"]["rules"] == [{"name": "r1", "type": "MAPPING"}] - - -def test_create_integration_connector_with_dataclass_parameters(chronicle_client): - """Test create_integration_connector converts ConnectorParameter dataclasses.""" - expected = {"name": "connectors/new"} - - param = ConnectorParameter( - display_name="API Key", - type=ParamType.STRING, - mode=ConnectorParamMode.REGULAR, - mandatory=True, - description="API key for authentication", - ) - - with patch( - "secops.chronicle.integration.connectors.chronicle_request", - return_value=expected, - ) as mock_request: - result = create_integration_connector( - chronicle_client, - integration_name="test-integration", - display_name="My Connector", - script="print('hi')", - timeout_seconds=300, - enabled=True, - product_field_name="product", - event_field_name="event", - parameters=[param], - ) - - assert result == expected - - _, kwargs = mock_request.call_args - params_sent = kwargs["json"]["parameters"] - assert len(params_sent) == 1 - assert params_sent[0]["displayName"] == "API Key" - assert params_sent[0]["type"] == "STRING" - - -def test_create_integration_connector_with_dataclass_rules(chronicle_client): - """Test create_integration_connector converts ConnectorRule dataclasses.""" - expected = {"name": "connectors/new"} - - rule = ConnectorRule( - display_name="Mapping Rule", - type=ConnectorRuleType.ALLOW_LIST, - ) - - with patch( - "secops.chronicle.integration.connectors.chronicle_request", - return_value=expected, - ) as mock_request: - result = create_integration_connector( - chronicle_client, - integration_name="test-integration", - display_name="My Connector", - script="print('hi')", - timeout_seconds=300, - enabled=True, - product_field_name="product", - event_field_name="event", - rules=[rule], - ) - - assert result == expected - - _, kwargs = mock_request.call_args - rules_sent = kwargs["json"]["rules"] - assert len(rules_sent) == 1 - assert rules_sent[0]["displayName"] == "Mapping Rule" - assert rules_sent[0]["type"] == "ALLOW_LIST" - - -def test_create_integration_connector_error(chronicle_client): - """Test create_integration_connector raises APIError on failure.""" - with patch( - "secops.chronicle.integration.connectors.chronicle_request", - side_effect=APIError("Failed to create integration connector"), - ): - with pytest.raises(APIError) as exc_info: - create_integration_connector( - chronicle_client, - integration_name="test-integration", - display_name="My Connector", - script="print('hi')", - timeout_seconds=300, - enabled=True, - product_field_name="product", - event_field_name="event", - ) - assert "Failed to create integration connector" in str(exc_info.value) - - -# -- update_integration_connector tests -- - - -def test_update_integration_connector_with_explicit_update_mask(chronicle_client): - """Test update_integration_connector passes through explicit update_mask.""" - expected = {"name": "connectors/c1", "displayName": "New Name"} - - with patch( - "secops.chronicle.integration.connectors.chronicle_request", - return_value=expected, - ) as mock_request: - result = update_integration_connector( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - display_name="New Name", - update_mask="displayName", - ) - - assert result == expected - - mock_request.assert_called_once_with( - chronicle_client, - method="PATCH", - endpoint_path="integrations/test-integration/connectors/c1", - api_version=APIVersion.V1BETA, - json={"displayName": "New Name"}, - params={"updateMask": "displayName"}, - ) - - -def test_update_integration_connector_auto_update_mask(chronicle_client): - """Test update_integration_connector auto-generates updateMask based on fields.""" - expected = {"name": "connectors/c1"} - - with patch( - "secops.chronicle.integration.connectors.chronicle_request", - return_value=expected, - ) as mock_request: - result = update_integration_connector( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - enabled=False, - timeout_seconds=600, - ) - - assert result == expected - - assert mock_request.call_count == 1 - _, kwargs = mock_request.call_args - - assert kwargs["method"] == "PATCH" - assert kwargs["endpoint_path"] == "integrations/test-integration/connectors/c1" - assert kwargs["api_version"] == APIVersion.V1BETA - - assert kwargs["json"] == {"enabled": False, "timeoutSeconds": 600} - - update_mask = kwargs["params"]["updateMask"] - assert set(update_mask.split(",")) == {"enabled", "timeoutSeconds"} - - -def test_update_integration_connector_with_parameters(chronicle_client): - """Test update_integration_connector with parameters field.""" - expected = {"name": "connectors/c1"} - - param = ConnectorParameter( - display_name="Auth Token", - type=ParamType.STRING, - mode=ConnectorParamMode.REGULAR, - mandatory=True, - ) - - with patch( - "secops.chronicle.integration.connectors.chronicle_request", - return_value=expected, - ) as mock_request: - result = update_integration_connector( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - parameters=[param], - ) - - assert result == expected - - _, kwargs = mock_request.call_args - params_sent = kwargs["json"]["parameters"] - assert len(params_sent) == 1 - assert params_sent[0]["displayName"] == "Auth Token" - - -def test_update_integration_connector_with_rules(chronicle_client): - """Test update_integration_connector with rules field.""" - expected = {"name": "connectors/c1"} - - rule = ConnectorRule( - display_name="Filter Rule", - type=ConnectorRuleType.BLOCK_LIST, - ) - - with patch( - "secops.chronicle.integration.connectors.chronicle_request", - return_value=expected, - ) as mock_request: - result = update_integration_connector( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - rules=[rule], - ) - - assert result == expected - - _, kwargs = mock_request.call_args - rules_sent = kwargs["json"]["rules"] - assert len(rules_sent) == 1 - assert rules_sent[0]["displayName"] == "Filter Rule" - - -def test_update_integration_connector_error(chronicle_client): - """Test update_integration_connector raises APIError on failure.""" - with patch( - "secops.chronicle.integration.connectors.chronicle_request", - side_effect=APIError("Failed to update integration connector"), - ): - with pytest.raises(APIError) as exc_info: - update_integration_connector( - chronicle_client, - integration_name="test-integration", - connector_id="c1", - display_name="New Name", - ) - assert "Failed to update integration connector" in str(exc_info.value) - - -# -- execute_integration_connector_test tests -- - - -def test_execute_integration_connector_test_success(chronicle_client): - """Test execute_integration_connector_test sends POST request with connector.""" - expected = { - "outputMessage": "Success", - "debugOutputMessage": "Debug info", - "resultJson": {"status": "ok"}, - } - - connector = { - "displayName": "Test Connector", - "script": "print('test')", - "enabled": True, - } - - with patch( - "secops.chronicle.integration.connectors.chronicle_request", - return_value=expected, - ) as mock_request: - result = execute_integration_connector_test( - chronicle_client, - integration_name="test-integration", - connector=connector, - ) - - assert result == expected - - mock_request.assert_called_once_with( - chronicle_client, - method="POST", - endpoint_path="integrations/test-integration/connectors:executeTest", - api_version=APIVersion.V1BETA, - json={"connector": connector}, - ) - - -def test_execute_integration_connector_test_with_agent_identifier(chronicle_client): - """Test execute_integration_connector_test includes agent_identifier when provided.""" - expected = {"outputMessage": "Success"} - - connector = {"displayName": "Test", "script": "print('test')"} - - with patch( - "secops.chronicle.integration.connectors.chronicle_request", - return_value=expected, - ) as mock_request: - result = execute_integration_connector_test( - chronicle_client, - integration_name="test-integration", - connector=connector, - agent_identifier="agent-123", - ) - - assert result == expected - - _, kwargs = mock_request.call_args - assert kwargs["json"]["agentIdentifier"] == "agent-123" - - -def test_execute_integration_connector_test_error(chronicle_client): - """Test execute_integration_connector_test raises APIError on failure.""" - with patch( - "secops.chronicle.integration.connectors.chronicle_request", - side_effect=APIError("Failed to execute connector test"), - ): - with pytest.raises(APIError) as exc_info: - execute_integration_connector_test( - chronicle_client, - integration_name="test-integration", - connector={"displayName": "Test"}, - ) - assert "Failed to execute connector test" in str(exc_info.value) - - -# -- get_integration_connector_template tests -- - - -def test_get_integration_connector_template_success(chronicle_client): - """Test get_integration_connector_template issues GET request.""" - expected = { - "script": "# Template script\nprint('hello')", - "displayName": "Template Connector", - } - - with patch( - "secops.chronicle.integration.connectors.chronicle_request", - return_value=expected, - ) as mock_request: - result = get_integration_connector_template( - chronicle_client, - integration_name="test-integration", - ) - - assert result == expected - - mock_request.assert_called_once_with( - chronicle_client, - method="GET", - endpoint_path="integrations/test-integration/connectors:fetchTemplate", - api_version=APIVersion.V1BETA, - ) - - -def test_get_integration_connector_template_error(chronicle_client): - """Test get_integration_connector_template raises APIError on failure.""" - with patch( - "secops.chronicle.integration.connectors.chronicle_request", - side_effect=APIError("Failed to get connector template"), - ): - with pytest.raises(APIError) as exc_info: - get_integration_connector_template( - chronicle_client, - integration_name="test-integration", - ) - assert "Failed to get connector template" in str(exc_info.value) - diff --git a/tests/chronicle/integration/test_integration_instances.py b/tests/chronicle/integration/test_integration_instances.py deleted file mode 100644 index 153390ad..00000000 --- a/tests/chronicle/integration/test_integration_instances.py +++ /dev/null @@ -1,623 +0,0 @@ -# Copyright 2025 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. -# -"""Tests for Chronicle marketplace integration instances functions.""" - -from unittest.mock import Mock, patch - -import pytest - -from secops.chronicle.client import ChronicleClient -from secops.chronicle.models import ( - APIVersion, - IntegrationInstanceParameter, -) -from secops.chronicle.integration.integration_instances import ( - list_integration_instances, - get_integration_instance, - delete_integration_instance, - create_integration_instance, - update_integration_instance, - execute_integration_instance_test, - get_integration_instance_affected_items, - get_default_integration_instance, -) -from secops.exceptions import APIError - - -@pytest.fixture -def chronicle_client(): - """Create a Chronicle client for testing.""" - with patch("secops.auth.SecOpsAuth") as mock_auth: - mock_session = Mock() - mock_session.headers = {} - mock_auth.return_value.session = mock_session - return ChronicleClient( - customer_id="test-customer", - project_id="test-project", - default_api_version=APIVersion.V1BETA, - ) - - -# -- list_integration_instances tests -- - - -def test_list_integration_instances_success(chronicle_client): - """Test list_integration_instances delegates to chronicle_paginated_request.""" - expected = { - "integrationInstances": [{"name": "ii1"}, {"name": "ii2"}], - "nextPageToken": "t", - } - - with patch( - "secops.chronicle.integration.integration_instances.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated, patch( - "secops.chronicle.integration.integration_instances.format_resource_id", - return_value="My Integration", - ): - result = list_integration_instances( - chronicle_client, - integration_name="My Integration", - page_size=10, - page_token="next-token", - ) - - assert result == expected - - _, kwargs = mock_paginated.call_args - assert "integrationInstances" in kwargs["path"] - assert kwargs["items_key"] == "integrationInstances" - assert kwargs["page_size"] == 10 - assert kwargs["page_token"] == "next-token" - - -def test_list_integration_instances_default_args(chronicle_client): - """Test list_integration_instances with default args.""" - expected = {"integrationInstances": []} - - with patch( - "secops.chronicle.integration.integration_instances.chronicle_paginated_request", - return_value=expected, - ): - result = list_integration_instances( - chronicle_client, - integration_name="test-integration", - ) - - assert result == expected - - -def test_list_integration_instances_with_filters(chronicle_client): - """Test list_integration_instances with filter and order_by.""" - expected = {"integrationInstances": [{"name": "ii1"}]} - - with patch( - "secops.chronicle.integration.integration_instances.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated: - result = list_integration_instances( - chronicle_client, - integration_name="test-integration", - filter_string="environment = 'prod'", - order_by="displayName", - ) - - assert result == expected - - _, kwargs = mock_paginated.call_args - assert kwargs["extra_params"] == { - "filter": "environment = 'prod'", - "orderBy": "displayName", - } - - -def test_list_integration_instances_as_list(chronicle_client): - """Test list_integration_instances returns list when as_list=True.""" - expected = [{"name": "ii1"}, {"name": "ii2"}] - - with patch( - "secops.chronicle.integration.integration_instances.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated: - result = list_integration_instances( - chronicle_client, - integration_name="test-integration", - as_list=True, - ) - - assert result == expected - - _, kwargs = mock_paginated.call_args - assert kwargs["as_list"] is True - - -def test_list_integration_instances_error(chronicle_client): - """Test list_integration_instances raises APIError on failure.""" - with patch( - "secops.chronicle.integration.integration_instances.chronicle_paginated_request", - side_effect=APIError("Failed to list integration instances"), - ): - with pytest.raises(APIError) as exc_info: - list_integration_instances( - chronicle_client, - integration_name="test-integration", - ) - assert "Failed to list integration instances" in str(exc_info.value) - - -# -- get_integration_instance tests -- - - -def test_get_integration_instance_success(chronicle_client): - """Test get_integration_instance issues GET request.""" - expected = { - "name": "integrationInstances/ii1", - "displayName": "My Instance", - "environment": "production", - } - - with patch( - "secops.chronicle.integration.integration_instances.chronicle_request", - return_value=expected, - ) as mock_request: - result = get_integration_instance( - chronicle_client, - integration_name="test-integration", - integration_instance_id="ii1", - ) - - assert result == expected - - _, kwargs = mock_request.call_args - assert kwargs["method"] == "GET" - assert "integrationInstances/ii1" in kwargs["endpoint_path"] - assert kwargs["api_version"] == APIVersion.V1BETA - - -def test_get_integration_instance_error(chronicle_client): - """Test get_integration_instance raises APIError on failure.""" - with patch( - "secops.chronicle.integration.integration_instances.chronicle_request", - side_effect=APIError("Failed to get integration instance"), - ): - with pytest.raises(APIError) as exc_info: - get_integration_instance( - chronicle_client, - integration_name="test-integration", - integration_instance_id="ii1", - ) - assert "Failed to get integration instance" in str(exc_info.value) - - -# -- delete_integration_instance tests -- - - -def test_delete_integration_instance_success(chronicle_client): - """Test delete_integration_instance issues DELETE request.""" - with patch( - "secops.chronicle.integration.integration_instances.chronicle_request", - return_value=None, - ) as mock_request: - delete_integration_instance( - chronicle_client, - integration_name="test-integration", - integration_instance_id="ii1", - ) - - _, kwargs = mock_request.call_args - assert kwargs["method"] == "DELETE" - assert "integrationInstances/ii1" in kwargs["endpoint_path"] - assert kwargs["api_version"] == APIVersion.V1BETA - - -def test_delete_integration_instance_error(chronicle_client): - """Test delete_integration_instance raises APIError on failure.""" - with patch( - "secops.chronicle.integration.integration_instances.chronicle_request", - side_effect=APIError("Failed to delete integration instance"), - ): - with pytest.raises(APIError) as exc_info: - delete_integration_instance( - chronicle_client, - integration_name="test-integration", - integration_instance_id="ii1", - ) - assert "Failed to delete integration instance" in str(exc_info.value) - - -# -- create_integration_instance tests -- - - -def test_create_integration_instance_required_fields_only(chronicle_client): - """Test create_integration_instance sends only required fields.""" - expected = {"name": "integrationInstances/new", "displayName": "My Instance"} - - with patch( - "secops.chronicle.integration.integration_instances.chronicle_request", - return_value=expected, - ) as mock_request: - result = create_integration_instance( - chronicle_client, - integration_name="test-integration", - environment="production", - ) - - assert result == expected - - mock_request.assert_called_once_with( - chronicle_client, - method="POST", - endpoint_path="integrations/test-integration/integrationInstances", - api_version=APIVersion.V1BETA, - json={ - "environment": "production", - }, - ) - - -def test_create_integration_instance_with_optional_fields(chronicle_client): - """Test create_integration_instance includes optional fields when provided.""" - expected = {"name": "integrationInstances/new"} - - with patch( - "secops.chronicle.integration.integration_instances.chronicle_request", - return_value=expected, - ) as mock_request: - result = create_integration_instance( - chronicle_client, - integration_name="test-integration", - environment="production", - display_name="My Instance", - description="Test instance", - parameters=[{"id": 1, "value": "test"}], - agent="agent-123", - ) - - assert result == expected - - _, kwargs = mock_request.call_args - assert kwargs["json"]["environment"] == "production" - assert kwargs["json"]["displayName"] == "My Instance" - assert kwargs["json"]["description"] == "Test instance" - assert kwargs["json"]["parameters"] == [{"id": 1, "value": "test"}] - assert kwargs["json"]["agent"] == "agent-123" - - -def test_create_integration_instance_with_dataclass_params(chronicle_client): - """Test create_integration_instance converts dataclass parameters.""" - expected = {"name": "integrationInstances/new"} - - param = IntegrationInstanceParameter(value="test-value") - - with patch( - "secops.chronicle.integration.integration_instances.chronicle_request", - return_value=expected, - ) as mock_request: - result = create_integration_instance( - chronicle_client, - integration_name="test-integration", - environment="production", - parameters=[param], - ) - - assert result == expected - - _, kwargs = mock_request.call_args - params_sent = kwargs["json"]["parameters"] - assert len(params_sent) == 1 - assert params_sent[0]["value"] == "test-value" - - -def test_create_integration_instance_error(chronicle_client): - """Test create_integration_instance raises APIError on failure.""" - with patch( - "secops.chronicle.integration.integration_instances.chronicle_request", - side_effect=APIError("Failed to create integration instance"), - ): - with pytest.raises(APIError) as exc_info: - create_integration_instance( - chronicle_client, - integration_name="test-integration", - environment="production", - ) - assert "Failed to create integration instance" in str(exc_info.value) - - -# -- update_integration_instance tests -- - - -def test_update_integration_instance_with_single_field(chronicle_client): - """Test update_integration_instance with single field updates updateMask.""" - expected = {"name": "integrationInstances/ii1", "displayName": "Updated"} - - with patch( - "secops.chronicle.integration.integration_instances.chronicle_request", - return_value=expected, - ) as mock_request: - result = update_integration_instance( - chronicle_client, - integration_name="test-integration", - integration_instance_id="ii1", - display_name="Updated", - ) - - assert result == expected - - _, kwargs = mock_request.call_args - assert kwargs["method"] == "PATCH" - assert "integrationInstances/ii1" in kwargs["endpoint_path"] - assert kwargs["json"]["displayName"] == "Updated" - assert kwargs["params"]["updateMask"] == "displayName" - - -def test_update_integration_instance_with_multiple_fields(chronicle_client): - """Test update_integration_instance with multiple fields.""" - expected = {"name": "integrationInstances/ii1"} - - with patch( - "secops.chronicle.integration.integration_instances.chronicle_request", - return_value=expected, - ) as mock_request: - result = update_integration_instance( - chronicle_client, - integration_name="test-integration", - integration_instance_id="ii1", - display_name="Updated", - description="New description", - environment="staging", - ) - - assert result == expected - - _, kwargs = mock_request.call_args - assert kwargs["json"]["displayName"] == "Updated" - assert kwargs["json"]["description"] == "New description" - assert kwargs["json"]["environment"] == "staging" - assert "displayName" in kwargs["params"]["updateMask"] - assert "description" in kwargs["params"]["updateMask"] - assert "environment" in kwargs["params"]["updateMask"] - - -def test_update_integration_instance_with_custom_update_mask(chronicle_client): - """Test update_integration_instance with explicitly provided update_mask.""" - expected = {"name": "integrationInstances/ii1"} - - with patch( - "secops.chronicle.integration.integration_instances.chronicle_request", - return_value=expected, - ) as mock_request: - result = update_integration_instance( - chronicle_client, - integration_name="test-integration", - integration_instance_id="ii1", - display_name="Updated", - update_mask="displayName,environment", - ) - - assert result == expected - - _, kwargs = mock_request.call_args - assert kwargs["params"]["updateMask"] == "displayName,environment" - - -def test_update_integration_instance_with_dataclass_params(chronicle_client): - """Test update_integration_instance converts dataclass parameters.""" - expected = {"name": "integrationInstances/ii1"} - - param = IntegrationInstanceParameter(value="test-value") - - with patch( - "secops.chronicle.integration.integration_instances.chronicle_request", - return_value=expected, - ) as mock_request: - result = update_integration_instance( - chronicle_client, - integration_name="test-integration", - integration_instance_id="ii1", - parameters=[param], - ) - - assert result == expected - - _, kwargs = mock_request.call_args - params_sent = kwargs["json"]["parameters"] - assert len(params_sent) == 1 - assert params_sent[0]["value"] == "test-value" - - -def test_update_integration_instance_error(chronicle_client): - """Test update_integration_instance raises APIError on failure.""" - with patch( - "secops.chronicle.integration.integration_instances.chronicle_request", - side_effect=APIError("Failed to update integration instance"), - ): - with pytest.raises(APIError) as exc_info: - update_integration_instance( - chronicle_client, - integration_name="test-integration", - integration_instance_id="ii1", - display_name="Updated", - ) - assert "Failed to update integration instance" in str(exc_info.value) - - -# -- execute_integration_instance_test tests -- - - -def test_execute_integration_instance_test_success(chronicle_client): - """Test execute_integration_instance_test issues POST request.""" - expected = { - "successful": True, - "message": "Test successful", - } - - with patch( - "secops.chronicle.integration.integration_instances.chronicle_request", - return_value=expected, - ) as mock_request: - result = execute_integration_instance_test( - chronicle_client, - integration_name="test-integration", - integration_instance_id="ii1", - ) - - assert result == expected - - _, kwargs = mock_request.call_args - assert kwargs["method"] == "POST" - assert "integrationInstances/ii1:executeTest" in kwargs["endpoint_path"] - assert kwargs["api_version"] == APIVersion.V1BETA - - -def test_execute_integration_instance_test_failure(chronicle_client): - """Test execute_integration_instance_test when test fails.""" - expected = { - "successful": False, - "message": "Connection failed", - } - - with patch( - "secops.chronicle.integration.integration_instances.chronicle_request", - return_value=expected, - ): - result = execute_integration_instance_test( - chronicle_client, - integration_name="test-integration", - integration_instance_id="ii1", - ) - - assert result == expected - assert result["successful"] is False - - -def test_execute_integration_instance_test_error(chronicle_client): - """Test execute_integration_instance_test raises APIError on failure.""" - with patch( - "secops.chronicle.integration.integration_instances.chronicle_request", - side_effect=APIError("Failed to execute test"), - ): - with pytest.raises(APIError) as exc_info: - execute_integration_instance_test( - chronicle_client, - integration_name="test-integration", - integration_instance_id="ii1", - ) - assert "Failed to execute test" in str(exc_info.value) - - -# -- get_integration_instance_affected_items tests -- - - -def test_get_integration_instance_affected_items_success(chronicle_client): - """Test get_integration_instance_affected_items issues GET request.""" - expected = { - "affectedPlaybooks": [ - {"name": "playbook1", "displayName": "Playbook 1"}, - {"name": "playbook2", "displayName": "Playbook 2"}, - ] - } - - with patch( - "secops.chronicle.integration.integration_instances.chronicle_request", - return_value=expected, - ) as mock_request: - result = get_integration_instance_affected_items( - chronicle_client, - integration_name="test-integration", - integration_instance_id="ii1", - ) - - assert result == expected - - _, kwargs = mock_request.call_args - assert kwargs["method"] == "GET" - assert "integrationInstances/ii1:fetchAffectedItems" in kwargs["endpoint_path"] - assert kwargs["api_version"] == APIVersion.V1BETA - - -def test_get_integration_instance_affected_items_empty(chronicle_client): - """Test get_integration_instance_affected_items with no affected items.""" - expected = {"affectedPlaybooks": []} - - with patch( - "secops.chronicle.integration.integration_instances.chronicle_request", - return_value=expected, - ): - result = get_integration_instance_affected_items( - chronicle_client, - integration_name="test-integration", - integration_instance_id="ii1", - ) - - assert result == expected - assert len(result["affectedPlaybooks"]) == 0 - - -def test_get_integration_instance_affected_items_error(chronicle_client): - """Test get_integration_instance_affected_items raises APIError on failure.""" - with patch( - "secops.chronicle.integration.integration_instances.chronicle_request", - side_effect=APIError("Failed to fetch affected items"), - ): - with pytest.raises(APIError) as exc_info: - get_integration_instance_affected_items( - chronicle_client, - integration_name="test-integration", - integration_instance_id="ii1", - ) - assert "Failed to fetch affected items" in str(exc_info.value) - - -# -- get_default_integration_instance tests -- - - -def test_get_default_integration_instance_success(chronicle_client): - """Test get_default_integration_instance issues GET request.""" - expected = { - "name": "integrationInstances/default", - "displayName": "Default Instance", - "environment": "default", - } - - with patch( - "secops.chronicle.integration.integration_instances.chronicle_request", - return_value=expected, - ) as mock_request: - result = get_default_integration_instance( - chronicle_client, - integration_name="test-integration", - ) - - assert result == expected - - _, kwargs = mock_request.call_args - assert kwargs["method"] == "GET" - assert "integrationInstances:fetchDefaultInstance" in kwargs["endpoint_path"] - assert kwargs["api_version"] == APIVersion.V1BETA - - -def test_get_default_integration_instance_error(chronicle_client): - """Test get_default_integration_instance raises APIError on failure.""" - with patch( - "secops.chronicle.integration.integration_instances.chronicle_request", - side_effect=APIError("Failed to get default instance"), - ): - with pytest.raises(APIError) as exc_info: - get_default_integration_instance( - chronicle_client, - integration_name="test-integration", - ) - assert "Failed to get default instance" in str(exc_info.value) - diff --git a/tests/chronicle/integration/test_integrations.py b/tests/chronicle/integration/test_integrations.py deleted file mode 100644 index 811ab052..00000000 --- a/tests/chronicle/integration/test_integrations.py +++ /dev/null @@ -1,909 +0,0 @@ -# Copyright 2025 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. -# -"""Tests for Chronicle integration functions.""" - -from unittest.mock import Mock, patch - -import pytest - -from secops.chronicle.client import ChronicleClient -from secops.chronicle.models import ( - APIVersion, - DiffType, - TargetMode, - PythonVersion, -) -from secops.chronicle.integration.integrations import ( - list_integrations, - get_integration, - delete_integration, - create_integration, - download_integration, - download_integration_dependency, - export_integration_items, - get_integration_affected_items, - get_agent_integrations, - get_integration_dependencies, - get_integration_restricted_agents, - get_integration_diff, - transition_integration, - update_integration, - update_custom_integration, -) -from secops.exceptions import APIError - - -@pytest.fixture -def chronicle_client(): - """Create a Chronicle client for testing.""" - with patch("secops.auth.SecOpsAuth") as mock_auth: - mock_session = Mock() - mock_session.headers = {} - mock_auth.return_value.session = mock_session - return ChronicleClient( - customer_id="test-customer", - project_id="test-project", - default_api_version=APIVersion.V1BETA, - ) - - -@pytest.fixture -def mock_response() -> Mock: - """Create a mock API response object.""" - mock = Mock() - mock.status_code = 200 - mock.json.return_value = {} - return mock - - -@pytest.fixture -def mock_error_response() -> Mock: - """Create a mock error API response object.""" - mock = Mock() - mock.status_code = 400 - mock.text = "Error message" - mock.raise_for_status.side_effect = Exception("API Error") - return mock - - -# -- list_integrations tests -- - - -def test_list_integrations_success(chronicle_client): - """Test list_integrations delegates to chronicle_paginated_request.""" - expected = {"integrations": [{"name": "i1"}, {"name": "i2"}]} - - with patch( - "secops.chronicle.integration.integrations.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated: - result = list_integrations( - chronicle_client, - page_size=10, - page_token="next-token", - ) - - assert result == expected - - mock_paginated.assert_called_once_with( - chronicle_client, - api_version=APIVersion.V1BETA, - path="integrations", - items_key="integrations", - page_size=10, - page_token="next-token", - extra_params={}, - as_list=False, - ) - - -def test_list_integrations_with_filter_and_order_by(chronicle_client): - """Test list_integrations passes filter_string and order_by in extra_params.""" - expected = {"integrations": []} - - with patch( - "secops.chronicle.integration.integrations.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated: - result = list_integrations( - chronicle_client, - filter_string='displayName = "My Integration"', - order_by="displayName", - as_list=True, - ) - - assert result == expected - - mock_paginated.assert_called_once_with( - chronicle_client, - api_version=APIVersion.V1BETA, - path="integrations", - items_key="integrations", - page_size=None, - page_token=None, - extra_params={ - "filter": 'displayName = "My Integration"', - "orderBy": "displayName", - }, - as_list=True, - ) - - -def test_list_integrations_error(chronicle_client): - """Test list_integrations propagates APIError from helper.""" - with patch( - "secops.chronicle.integration.integrations.chronicle_paginated_request", - side_effect=APIError("Failed to list integrations"), - ): - with pytest.raises(APIError) as exc_info: - list_integrations(chronicle_client) - - assert "Failed to list integrations" in str(exc_info.value) - - -# -- get_integration tests -- - - -def test_get_integration_success(chronicle_client): - """Test get_integration returns expected result.""" - expected = {"name": "integrations/test-integration", "displayName": "Test"} - - with patch( - "secops.chronicle.integration.integrations.chronicle_request", - return_value=expected, - ) as mock_request: - result = get_integration(chronicle_client, "test-integration") - - assert result == expected - - mock_request.assert_called_once_with( - chronicle_client, - method="GET", - endpoint_path="integrations/test-integration", - api_version=APIVersion.V1BETA, - ) - - -def test_get_integration_error(chronicle_client): - """Test get_integration raises APIError on failure.""" - with patch( - "secops.chronicle.integration.integrations.chronicle_request", - side_effect=APIError("Failed to get integration"), - ): - with pytest.raises(APIError) as exc_info: - get_integration(chronicle_client, "test-integration") - - assert "Failed to get integration" in str(exc_info.value) - - -# -- delete_integration tests -- - - -def test_delete_integration_success(chronicle_client): - """Test delete_integration delegates to chronicle_request.""" - with patch("secops.chronicle.integration.integrations.chronicle_request") as mock_request: - delete_integration(chronicle_client, "test-integration") - - mock_request.assert_called_once_with( - chronicle_client, - method="DELETE", - endpoint_path="integrations/test-integration", - api_version=APIVersion.V1BETA, - ) - - -def test_delete_integration_error(chronicle_client): - """Test delete_integration propagates APIError on failure.""" - with patch( - "secops.chronicle.integration.integrations.chronicle_request", - side_effect=APIError("Failed to delete integration"), - ): - with pytest.raises(APIError) as exc_info: - delete_integration(chronicle_client, "test-integration") - - assert "Failed to delete integration" in str(exc_info.value) - - -# -- create_integration tests -- - - -def test_create_integration_required_fields_only(chronicle_client): - """Test create_integration with required fields only.""" - expected = {"name": "integrations/test", "displayName": "Test"} - - with patch( - "secops.chronicle.integration.integrations.chronicle_request", - return_value=expected, - ) as mock_request: - result = create_integration( - chronicle_client, - display_name="Test", - staging=True, - ) - - assert result == expected - - mock_request.assert_called_once_with( - chronicle_client, - method="POST", - endpoint_path="integrations", - json={"displayName": "Test", "staging": True}, - api_version=APIVersion.V1BETA, - ) - - -def test_create_integration_all_optional_fields(chronicle_client): - """Test create_integration with all optional fields.""" - expected = {"name": "integrations/test"} - - python_version = list(PythonVersion)[0] - integration_type = Mock(name="integration_type") - - with patch( - "secops.chronicle.integration.integrations.chronicle_request", - return_value=expected, - ) as mock_request: - result = create_integration( - chronicle_client, - display_name="Test", - staging=False, - description="desc", - image_base64="b64", - svg_icon="", - python_version=python_version, - parameters=[{"id": "p1"}], - categories=["cat"], - integration_type=integration_type, - ) - - assert result == expected - - mock_request.assert_called_once_with( - chronicle_client, - method="POST", - endpoint_path="integrations", - json={ - "displayName": "Test", - "staging": False, - "description": "desc", - "imageBase64": "b64", - "svgIcon": "", - "pythonVersion": python_version, - "parameters": [{"id": "p1"}], - "categories": ["cat"], - "type": integration_type, - }, - api_version=APIVersion.V1BETA, - ) - - -def test_create_integration_none_fields_excluded(chronicle_client): - """Test that None optional fields are excluded from create_integration body.""" - with patch( - "secops.chronicle.integration.integrations.chronicle_request", - return_value={"name": "integrations/test"}, - ) as mock_request: - create_integration( - chronicle_client, - display_name="Test", - staging=True, - description=None, - image_base64=None, - svg_icon=None, - python_version=None, - parameters=None, - categories=None, - integration_type=None, - ) - - mock_request.assert_called_once_with( - chronicle_client, - method="POST", - endpoint_path="integrations", - json={"displayName": "Test", "staging": True}, - api_version=APIVersion.V1BETA, - ) - - -def test_create_integration_error(chronicle_client): - """Test create_integration raises APIError on failure.""" - with patch( - "secops.chronicle.integration.integrations.chronicle_request", - side_effect=APIError("Failed to create integration"), - ): - with pytest.raises(APIError) as exc_info: - create_integration(chronicle_client, display_name="Test", staging=True) - - assert "Failed to create integration" in str(exc_info.value) - - -# -- download_integration tests -- - - -def test_download_integration_success(chronicle_client): - """Test download_integration uses chronicle_request_bytes with alt=media and zip accept.""" - expected = b"ZIPBYTES" - - with patch( - "secops.chronicle.integration.integrations.chronicle_request_bytes", - return_value=expected, - ) as mock_bytes: - result = download_integration(chronicle_client, "test-integration") - - assert result == expected - - mock_bytes.assert_called_once_with( - chronicle_client, - method="GET", - endpoint_path="integrations/test-integration:export", - api_version=APIVersion.V1BETA, - params={"alt": "media"}, - headers={"Accept": "application/zip"}, - ) - - -def test_download_integration_error(chronicle_client): - """Test download_integration propagates APIError on failure.""" - with patch( - "secops.chronicle.integration.integrations.chronicle_request_bytes", - side_effect=APIError("Failed to download integration"), - ): - with pytest.raises(APIError) as exc_info: - download_integration(chronicle_client, "test-integration") - - assert "Failed to download integration" in str(exc_info.value) - - -# -- download_integration_dependency tests -- - - -def test_download_integration_dependency_success(chronicle_client): - """Test download_integration_dependency posts dependency name.""" - expected = {"dependency": "requests"} - - with patch( - "secops.chronicle.integration.integrations.chronicle_request", - return_value=expected, - ) as mock_request: - result = download_integration_dependency( - chronicle_client, - integration_name="test-integration", - dependency_name="requests==2.32.0", - ) - - assert result == expected - - mock_request.assert_called_once_with( - chronicle_client, - method="POST", - endpoint_path="integrations/test-integration:downloadDependency", - json={"dependency": "requests==2.32.0"}, - api_version=APIVersion.V1BETA, - ) - - -def test_download_integration_dependency_error(chronicle_client): - """Test download_integration_dependency raises APIError on failure.""" - with patch( - "secops.chronicle.integration.integrations.chronicle_request", - side_effect=APIError("Failed to download dependency"), - ): - with pytest.raises(APIError) as exc_info: - download_integration_dependency( - chronicle_client, - integration_name="test-integration", - dependency_name="requests", - ) - - assert "Failed to download dependency" in str(exc_info.value) - - -# -- export_integration_items tests -- - - -def test_export_integration_items_success_some_fields(chronicle_client): - """Test export_integration_items builds params correctly and uses chronicle_request_bytes.""" - expected = b"ZIPBYTES" - - with patch( - "secops.chronicle.integration.integrations.chronicle_request_bytes", - return_value=expected, - ) as mock_bytes: - result = export_integration_items( - chronicle_client, - integration_name="test-integration", - actions=["1", "2"], - connectors=["10"], - logical_operators=["7"], - ) - - assert result == expected - - mock_bytes.assert_called_once_with( - chronicle_client, - method="GET", - endpoint_path="integrations/test-integration:exportItems", - params={ - "actions": "1,2", - "connectors": ["10"], - "logicalOperators": ["7"], - "alt": "media", - }, - api_version=APIVersion.V1BETA, - headers={"Accept": "application/zip"}, - ) - - -def test_export_integration_items_no_fields(chronicle_client): - """Test export_integration_items always includes alt=media.""" - expected = b"ZIPBYTES" - - with patch( - "secops.chronicle.integration.integrations.chronicle_request_bytes", - return_value=expected, - ) as mock_bytes: - result = export_integration_items( - chronicle_client, - integration_name="test-integration", - ) - - assert result == expected - - mock_bytes.assert_called_once_with( - chronicle_client, - method="GET", - endpoint_path="integrations/test-integration:exportItems", - params={"alt": "media"}, - api_version=APIVersion.V1BETA, - headers={"Accept": "application/zip"}, - ) - - -def test_export_integration_items_error(chronicle_client): - """Test export_integration_items propagates APIError on failure.""" - with patch( - "secops.chronicle.integration.integrations.chronicle_request_bytes", - side_effect=APIError("Failed to export integration items"), - ): - with pytest.raises(APIError) as exc_info: - export_integration_items(chronicle_client, "test-integration") - - assert "Failed to export integration items" in str(exc_info.value) - - -# -- get_integration_affected_items tests -- - - -def test_get_integration_affected_items_success(chronicle_client): - """Test get_integration_affected_items delegates to chronicle_request.""" - expected = {"affectedItems": []} - - with patch( - "secops.chronicle.integration.integrations.chronicle_request", - return_value=expected, - ) as mock_request: - result = get_integration_affected_items(chronicle_client, "test-integration") - - assert result == expected - - mock_request.assert_called_once_with( - chronicle_client, - method="GET", - endpoint_path="integrations/test-integration:fetchAffectedItems", - api_version=APIVersion.V1BETA, - ) - - -def test_get_integration_affected_items_error(chronicle_client): - """Test get_integration_affected_items raises APIError on failure.""" - with patch( - "secops.chronicle.integration.integrations.chronicle_request", - side_effect=APIError("Failed to fetch affected items"), - ): - with pytest.raises(APIError) as exc_info: - get_integration_affected_items(chronicle_client, "test-integration") - - assert "Failed to fetch affected items" in str(exc_info.value) - - -# -- get_agent_integrations tests -- - - -def test_get_agent_integrations_success(chronicle_client): - """Test get_agent_integrations passes agentId parameter.""" - expected = {"integrations": []} - - with patch( - "secops.chronicle.integration.integrations.chronicle_request", - return_value=expected, - ) as mock_request: - result = get_agent_integrations(chronicle_client, agent_id="agent-123") - - assert result == expected - - mock_request.assert_called_once_with( - chronicle_client, - method="GET", - endpoint_path="integrations:fetchAgentIntegrations", - params={"agentId": "agent-123"}, - api_version=APIVersion.V1BETA, - ) - - -def test_get_agent_integrations_error(chronicle_client): - """Test get_agent_integrations raises APIError on failure.""" - with patch( - "secops.chronicle.integration.integrations.chronicle_request", - side_effect=APIError("Failed to fetch agent integrations"), - ): - with pytest.raises(APIError) as exc_info: - get_agent_integrations(chronicle_client, agent_id="agent-123") - - assert "Failed to fetch agent integrations" in str(exc_info.value) - - -# -- get_integration_dependencies tests -- - - -def test_get_integration_dependencies_success(chronicle_client): - """Test get_integration_dependencies delegates to chronicle_request.""" - expected = {"dependencies": []} - - with patch( - "secops.chronicle.integration.integrations.chronicle_request", - return_value=expected, - ) as mock_request: - result = get_integration_dependencies(chronicle_client, "test-integration") - - assert result == expected - - mock_request.assert_called_once_with( - chronicle_client, - method="GET", - endpoint_path="integrations/test-integration:fetchDependencies", - api_version=APIVersion.V1BETA, - ) - - -def test_get_integration_dependencies_error(chronicle_client): - """Test get_integration_dependencies raises APIError on failure.""" - with patch( - "secops.chronicle.integration.integrations.chronicle_request", - side_effect=APIError("Failed to fetch dependencies"), - ): - with pytest.raises(APIError) as exc_info: - get_integration_dependencies(chronicle_client, "test-integration") - - assert "Failed to fetch dependencies" in str(exc_info.value) - - -# -- get_integration_restricted_agents tests -- - - -def test_get_integration_restricted_agents_success(chronicle_client): - """Test get_integration_restricted_agents passes required python version and pushRequest.""" - expected = {"restrictedAgents": []} - - with patch( - "secops.chronicle.integration.integrations.chronicle_request", - return_value=expected, - ) as mock_request: - result = get_integration_restricted_agents( - chronicle_client, - integration_name="test-integration", - required_python_version=PythonVersion.PYTHON_3_11, - push_request=True, - ) - - assert result == expected - - mock_request.assert_called_once_with( - chronicle_client, - method="GET", - endpoint_path="integrations/test-integration:fetchRestrictedAgents", - params={ - "requiredPythonVersion": PythonVersion.PYTHON_3_11.value, - "pushRequest": True, - }, - api_version=APIVersion.V1BETA, - ) - - -def test_get_integration_restricted_agents_default_push_request(chronicle_client): - """Test get_integration_restricted_agents default push_request=False is sent.""" - expected = {"restrictedAgents": []} - - with patch( - "secops.chronicle.integration.integrations.chronicle_request", - return_value=expected, - ) as mock_request: - get_integration_restricted_agents( - chronicle_client, - integration_name="test-integration", - required_python_version=PythonVersion.PYTHON_3_11, - ) - - mock_request.assert_called_once_with( - chronicle_client, - method="GET", - endpoint_path="integrations/test-integration:fetchRestrictedAgents", - params={ - "requiredPythonVersion": PythonVersion.PYTHON_3_11.value, - "pushRequest": False, - }, - api_version=APIVersion.V1BETA, - ) - - -def test_get_integration_restricted_agents_error(chronicle_client): - """Test get_integration_restricted_agents raises APIError on failure.""" - with patch( - "secops.chronicle.integration.integrations.chronicle_request", - side_effect=APIError("Failed to fetch restricted agents"), - ): - with pytest.raises(APIError) as exc_info: - get_integration_restricted_agents( - chronicle_client, - integration_name="test-integration", - required_python_version=PythonVersion.PYTHON_3_11, - ) - - assert "Failed to fetch restricted agents" in str(exc_info.value) - - -# -- get_integration_diff tests -- - - -def test_get_integration_diff_success(chronicle_client): - """Test get_integration_diff builds endpoint with diff type.""" - expected = {"diff": {}} - - with patch( - "secops.chronicle.integration.integrations.chronicle_request", - return_value=expected, - ) as mock_request: - result = get_integration_diff( - chronicle_client, - integration_name="test-integration", - diff_type=DiffType.PRODUCTION, - ) - - assert result == expected - - mock_request.assert_called_once_with( - chronicle_client, - method="GET", - endpoint_path="integrations/test-integration:fetchProductionDiff", - api_version=APIVersion.V1BETA, - ) - - -def test_get_integration_diff_error(chronicle_client): - """Test get_integration_diff raises APIError on failure.""" - with patch( - "secops.chronicle.integration.integrations.chronicle_request", - side_effect=APIError("Failed to fetch diff"), - ): - with pytest.raises(APIError) as exc_info: - get_integration_diff(chronicle_client, "test-integration") - - assert "Failed to fetch diff" in str(exc_info.value) - - -# -- transition_integration tests -- - - -def test_transition_integration_success(chronicle_client): - """Test transition_integration posts to pushTo{TargetMode}.""" - expected = {"name": "integrations/test"} - - with patch( - "secops.chronicle.integration.integrations.chronicle_request", - return_value=expected, - ) as mock_request: - result = transition_integration( - chronicle_client, - integration_name="test-integration", - target_mode=TargetMode.PRODUCTION, - ) - - assert result == expected - - mock_request.assert_called_once_with( - chronicle_client, - method="POST", - endpoint_path="integrations/test-integration:pushToProduction", - api_version=APIVersion.V1BETA, - ) - - -def test_transition_integration_error(chronicle_client): - """Test transition_integration raises APIError on failure.""" - with patch( - "secops.chronicle.integration.integrations.chronicle_request", - side_effect=APIError("Failed to transition integration"), - ): - with pytest.raises(APIError) as exc_info: - transition_integration( - chronicle_client, - integration_name="test-integration", - target_mode=TargetMode.STAGING, - ) - - assert "Failed to transition integration" in str(exc_info.value) - - -# -- update_integration tests -- - - -def test_update_integration_uses_build_patch_body_and_passes_dependencies_to_remove( - chronicle_client, -): - """Test update_integration uses build_patch_body and adds dependenciesToRemove.""" - body = {"displayName": "New"} - params = {"updateMask": "displayName"} - - with patch( - "secops.chronicle.integration.integrations.build_patch_body", - return_value=(body, params), - ) as mock_build_patch, patch( - "secops.chronicle.integration.integrations.chronicle_request", - return_value={"name": "integrations/test"}, - ) as mock_request: - result = update_integration( - chronicle_client, - integration_name="test-integration", - display_name="New", - dependencies_to_remove=["dep1", "dep2"], - update_mask="displayName", - ) - - assert result == {"name": "integrations/test"} - - mock_build_patch.assert_called_once() - mock_request.assert_called_once_with( - chronicle_client, - method="PATCH", - endpoint_path="integrations/test-integration", - json=body, - params={"updateMask": "displayName", "dependenciesToRemove": "dep1,dep2"}, - api_version=APIVersion.V1BETA, - ) - - -def test_update_integration_when_build_patch_body_returns_no_params(chronicle_client): - """Test update_integration handles params=None from build_patch_body.""" - body = {"description": "New"} - - with patch( - "secops.chronicle.integration.integrations.build_patch_body", - return_value=(body, None), - ), patch( - "secops.chronicle.integration.integrations.chronicle_request", - return_value={"name": "integrations/test"}, - ) as mock_request: - update_integration( - chronicle_client, - integration_name="test-integration", - description="New", - dependencies_to_remove=["dep1"], - ) - - mock_request.assert_called_once_with( - chronicle_client, - method="PATCH", - endpoint_path="integrations/test-integration", - json=body, - params={"dependenciesToRemove": "dep1"}, - api_version=APIVersion.V1BETA, - ) - - -def test_update_integration_error(chronicle_client): - """Test update_integration raises APIError on failure.""" - with patch( - "secops.chronicle.integration.integrations.build_patch_body", - return_value=({}, None), - ), patch( - "secops.chronicle.integration.integrations.chronicle_request", - side_effect=APIError("Failed to update integration"), - ): - with pytest.raises(APIError) as exc_info: - update_integration(chronicle_client, "test-integration") - - assert "Failed to update integration" in str(exc_info.value) - - -# -- update_custom_integration tests -- - - -def test_update_custom_integration_builds_body_and_params(chronicle_client): - """Test update_custom_integration builds nested integration body and updateMask param.""" - expected = {"successful": True, "integration": {"name": "integrations/test"}} - - with patch( - "secops.chronicle.integration.integrations.chronicle_request", - return_value=expected, - ) as mock_request: - result = update_custom_integration( - chronicle_client, - integration_name="test-integration", - display_name="New", - staging=False, - dependencies_to_remove=["dep1"], - update_mask="displayName,staging", - ) - - assert result == expected - - mock_request.assert_called_once_with( - chronicle_client, - method="POST", - endpoint_path="integrations/test-integration:updateCustomIntegration", - json={ - "integration": { - "name": "test-integration", - "displayName": "New", - "staging": False, - }, - "dependenciesToRemove": ["dep1"], - }, - params={"updateMask": "displayName,staging"}, - api_version=APIVersion.V1BETA, - ) - - -def test_update_custom_integration_excludes_none_fields(chronicle_client): - """Test update_custom_integration excludes None fields from integration object.""" - with patch( - "secops.chronicle.integration.integrations.chronicle_request", - return_value={"successful": True}, - ) as mock_request: - update_custom_integration( - chronicle_client, - integration_name="test-integration", - display_name=None, - description=None, - image_base64=None, - svg_icon=None, - python_version=None, - parameters=None, - categories=None, - integration_type=None, - staging=None, - dependencies_to_remove=None, - update_mask=None, - ) - - mock_request.assert_called_once_with( - chronicle_client, - method="POST", - endpoint_path="integrations/test-integration:updateCustomIntegration", - json={"integration": {"name": "test-integration"}}, - params=None, - api_version=APIVersion.V1BETA, - ) - - -def test_update_custom_integration_error(chronicle_client): - """Test update_custom_integration raises APIError on failure.""" - with patch( - "secops.chronicle.integration.integrations.chronicle_request", - side_effect=APIError("Failed to update custom integration"), - ): - with pytest.raises(APIError) as exc_info: - update_custom_integration(chronicle_client, "test-integration") - - assert "Failed to update custom integration" in str(exc_info.value) diff --git a/tests/chronicle/integration/test_job_context_properties.py b/tests/chronicle/integration/test_job_context_properties.py deleted file mode 100644 index 5fdce61c..00000000 --- a/tests/chronicle/integration/test_job_context_properties.py +++ /dev/null @@ -1,506 +0,0 @@ -# Copyright 2025 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. -# -"""Tests for Chronicle integration job context properties functions.""" - -from unittest.mock import Mock, patch - -import pytest - -from secops.chronicle.client import ChronicleClient -from secops.chronicle.models import APIVersion -from secops.chronicle.integration.job_context_properties import ( - list_job_context_properties, - get_job_context_property, - delete_job_context_property, - create_job_context_property, - update_job_context_property, - delete_all_job_context_properties, -) -from secops.exceptions import APIError - - -@pytest.fixture -def chronicle_client(): - """Create a Chronicle client for testing.""" - with patch("secops.auth.SecOpsAuth") as mock_auth: - mock_session = Mock() - mock_session.headers = {} - mock_auth.return_value.session = mock_session - return ChronicleClient( - customer_id="test-customer", - project_id="test-project", - default_api_version=APIVersion.V1BETA, - ) - - -# -- list_job_context_properties tests -- - - -def test_list_job_context_properties_success(chronicle_client): - """Test list_job_context_properties delegates to paginated request.""" - expected = { - "contextProperties": [{"key": "prop1"}, {"key": "prop2"}], - "nextPageToken": "t", - } - - with patch( - "secops.chronicle.integration.job_context_properties.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated, patch( - "secops.chronicle.integration.job_context_properties.format_resource_id", - return_value="My Integration", - ): - result = list_job_context_properties( - chronicle_client, - integration_name="My Integration", - job_id="j1", - page_size=10, - page_token="next-token", - ) - - assert result == expected - - _, kwargs = mock_paginated.call_args - assert "jobs/j1/contextProperties" in kwargs["path"] - assert kwargs["items_key"] == "contextProperties" - assert kwargs["page_size"] == 10 - assert kwargs["page_token"] == "next-token" - - -def test_list_job_context_properties_default_args(chronicle_client): - """Test list_job_context_properties with default args.""" - expected = {"contextProperties": []} - - with patch( - "secops.chronicle.integration.job_context_properties.chronicle_paginated_request", - return_value=expected, - ): - result = list_job_context_properties( - chronicle_client, - integration_name="test-integration", - job_id="j1", - ) - - assert result == expected - - -def test_list_job_context_properties_with_filters(chronicle_client): - """Test list_job_context_properties with filter and order_by.""" - expected = {"contextProperties": [{"key": "prop1"}]} - - with patch( - "secops.chronicle.integration.job_context_properties.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated: - result = list_job_context_properties( - chronicle_client, - integration_name="test-integration", - job_id="j1", - filter_string='key = "prop1"', - order_by="key", - ) - - assert result == expected - - _, kwargs = mock_paginated.call_args - assert kwargs["extra_params"] == { - "filter": 'key = "prop1"', - "orderBy": "key", - } - - -def test_list_job_context_properties_as_list(chronicle_client): - """Test list_job_context_properties returns list when as_list=True.""" - expected = [{"key": "prop1"}, {"key": "prop2"}] - - with patch( - "secops.chronicle.integration.job_context_properties.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated: - result = list_job_context_properties( - chronicle_client, - integration_name="test-integration", - job_id="j1", - as_list=True, - ) - - assert result == expected - - _, kwargs = mock_paginated.call_args - assert kwargs["as_list"] is True - - -def test_list_job_context_properties_error(chronicle_client): - """Test list_job_context_properties raises APIError on failure.""" - with patch( - "secops.chronicle.integration.job_context_properties.chronicle_paginated_request", - side_effect=APIError("Failed to list context properties"), - ): - with pytest.raises(APIError) as exc_info: - list_job_context_properties( - chronicle_client, - integration_name="test-integration", - job_id="j1", - ) - assert "Failed to list context properties" in str(exc_info.value) - - -# -- get_job_context_property tests -- - - -def test_get_job_context_property_success(chronicle_client): - """Test get_job_context_property issues GET request.""" - expected = { - "name": "contextProperties/prop1", - "key": "prop1", - "value": "test-value", - } - - with patch( - "secops.chronicle.integration.job_context_properties.chronicle_request", - return_value=expected, - ) as mock_request: - result = get_job_context_property( - chronicle_client, - integration_name="test-integration", - job_id="j1", - context_property_id="prop1", - ) - - assert result == expected - - _, kwargs = mock_request.call_args - assert kwargs["method"] == "GET" - assert "jobs/j1/contextProperties/prop1" in kwargs["endpoint_path"] - assert kwargs["api_version"] == APIVersion.V1BETA - - -def test_get_job_context_property_error(chronicle_client): - """Test get_job_context_property raises APIError on failure.""" - with patch( - "secops.chronicle.integration.job_context_properties.chronicle_request", - side_effect=APIError("Failed to get context property"), - ): - with pytest.raises(APIError) as exc_info: - get_job_context_property( - chronicle_client, - integration_name="test-integration", - job_id="j1", - context_property_id="prop1", - ) - assert "Failed to get context property" in str(exc_info.value) - - -# -- delete_job_context_property tests -- - - -def test_delete_job_context_property_success(chronicle_client): - """Test delete_job_context_property issues DELETE request.""" - with patch( - "secops.chronicle.integration.job_context_properties.chronicle_request", - return_value=None, - ) as mock_request: - delete_job_context_property( - chronicle_client, - integration_name="test-integration", - job_id="j1", - context_property_id="prop1", - ) - - _, kwargs = mock_request.call_args - assert kwargs["method"] == "DELETE" - assert "jobs/j1/contextProperties/prop1" in kwargs["endpoint_path"] - assert kwargs["api_version"] == APIVersion.V1BETA - - -def test_delete_job_context_property_error(chronicle_client): - """Test delete_job_context_property raises APIError on failure.""" - with patch( - "secops.chronicle.integration.job_context_properties.chronicle_request", - side_effect=APIError("Failed to delete context property"), - ): - with pytest.raises(APIError) as exc_info: - delete_job_context_property( - chronicle_client, - integration_name="test-integration", - job_id="j1", - context_property_id="prop1", - ) - assert "Failed to delete context property" in str(exc_info.value) - - -# -- create_job_context_property tests -- - - -def test_create_job_context_property_value_only(chronicle_client): - """Test create_job_context_property with value only.""" - expected = {"name": "contextProperties/new", "value": "test-value"} - - with patch( - "secops.chronicle.integration.job_context_properties.chronicle_request", - return_value=expected, - ) as mock_request: - result = create_job_context_property( - chronicle_client, - integration_name="test-integration", - job_id="j1", - value="test-value", - ) - - assert result == expected - - mock_request.assert_called_once_with( - chronicle_client, - method="POST", - endpoint_path=( - "integrations/test-integration/jobs/j1/contextProperties" - ), - api_version=APIVersion.V1BETA, - json={"value": "test-value"}, - ) - - -def test_create_job_context_property_with_key(chronicle_client): - """Test create_job_context_property with key specified.""" - expected = {"name": "contextProperties/mykey", "value": "test-value"} - - with patch( - "secops.chronicle.integration.job_context_properties.chronicle_request", - return_value=expected, - ) as mock_request: - result = create_job_context_property( - chronicle_client, - integration_name="test-integration", - job_id="j1", - value="test-value", - key="mykey", - ) - - assert result == expected - - _, kwargs = mock_request.call_args - assert kwargs["json"]["value"] == "test-value" - assert kwargs["json"]["key"] == "mykey" - - -def test_create_job_context_property_error(chronicle_client): - """Test create_job_context_property raises APIError on failure.""" - with patch( - "secops.chronicle.integration.job_context_properties.chronicle_request", - side_effect=APIError("Failed to create context property"), - ): - with pytest.raises(APIError) as exc_info: - create_job_context_property( - chronicle_client, - integration_name="test-integration", - job_id="j1", - value="test-value", - ) - assert "Failed to create context property" in str(exc_info.value) - - -# -- update_job_context_property tests -- - - -def test_update_job_context_property_success(chronicle_client): - """Test update_job_context_property issues PATCH request.""" - expected = {"name": "contextProperties/prop1", "value": "updated-value"} - - with patch( - "secops.chronicle.integration.job_context_properties.chronicle_request", - return_value=expected, - ) as mock_request, patch( - "secops.chronicle.integration.job_context_properties.build_patch_body", - return_value=( - {"value": "updated-value"}, - {"updateMask": "value"}, - ), - ): - result = update_job_context_property( - chronicle_client, - integration_name="test-integration", - job_id="j1", - context_property_id="prop1", - value="updated-value", - ) - - assert result == expected - - mock_request.assert_called_once_with( - chronicle_client, - method="PATCH", - endpoint_path=( - "integrations/test-integration/jobs/j1/contextProperties/prop1" - ), - api_version=APIVersion.V1BETA, - json={"value": "updated-value"}, - params={"updateMask": "value"}, - ) - - -def test_update_job_context_property_with_update_mask(chronicle_client): - """Test update_job_context_property with explicit update_mask.""" - expected = {"name": "contextProperties/prop1", "value": "updated-value"} - - with patch( - "secops.chronicle.integration.job_context_properties.chronicle_request", - return_value=expected, - ) as mock_request, patch( - "secops.chronicle.integration.job_context_properties.build_patch_body", - return_value=( - {"value": "updated-value"}, - {"updateMask": "value"}, - ), - ): - result = update_job_context_property( - chronicle_client, - integration_name="test-integration", - job_id="j1", - context_property_id="prop1", - value="updated-value", - update_mask="value", - ) - - assert result == expected - - -def test_update_job_context_property_error(chronicle_client): - """Test update_job_context_property raises APIError on failure.""" - with patch( - "secops.chronicle.integration.job_context_properties.chronicle_request", - side_effect=APIError("Failed to update context property"), - ), patch( - "secops.chronicle.integration.job_context_properties.build_patch_body", - return_value=({"value": "updated"}, {"updateMask": "value"}), - ): - with pytest.raises(APIError) as exc_info: - update_job_context_property( - chronicle_client, - integration_name="test-integration", - job_id="j1", - context_property_id="prop1", - value="updated", - ) - assert "Failed to update context property" in str(exc_info.value) - - -# -- delete_all_job_context_properties tests -- - - -def test_delete_all_job_context_properties_success(chronicle_client): - """Test delete_all_job_context_properties issues POST request.""" - with patch( - "secops.chronicle.integration.job_context_properties.chronicle_request", - return_value=None, - ) as mock_request: - delete_all_job_context_properties( - chronicle_client, - integration_name="test-integration", - job_id="j1", - ) - - mock_request.assert_called_once_with( - chronicle_client, - method="POST", - endpoint_path=( - "integrations/test-integration/" - "jobs/j1/contextProperties:clearAll" - ), - api_version=APIVersion.V1BETA, - json={}, - ) - - -def test_delete_all_job_context_properties_with_context_id(chronicle_client): - """Test delete_all_job_context_properties with context_id specified.""" - with patch( - "secops.chronicle.integration.job_context_properties.chronicle_request", - return_value=None, - ) as mock_request: - delete_all_job_context_properties( - chronicle_client, - integration_name="test-integration", - job_id="j1", - context_id="mycontext", - ) - - _, kwargs = mock_request.call_args - assert kwargs["method"] == "POST" - assert "contextProperties:clearAll" in kwargs["endpoint_path"] - assert kwargs["json"]["contextId"] == "mycontext" - - -def test_delete_all_job_context_properties_error(chronicle_client): - """Test delete_all_job_context_properties raises APIError on failure.""" - with patch( - "secops.chronicle.integration.job_context_properties.chronicle_request", - side_effect=APIError("Failed to delete all context properties"), - ): - with pytest.raises(APIError) as exc_info: - delete_all_job_context_properties( - chronicle_client, - integration_name="test-integration", - job_id="j1", - ) - assert "Failed to delete all context properties" in str( - exc_info.value - ) - - -# -- API version tests -- - - -def test_list_job_context_properties_custom_api_version(chronicle_client): - """Test list_job_context_properties with custom API version.""" - expected = {"contextProperties": []} - - with patch( - "secops.chronicle.integration.job_context_properties.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated: - result = list_job_context_properties( - chronicle_client, - integration_name="test-integration", - job_id="j1", - api_version=APIVersion.V1ALPHA, - ) - - assert result == expected - - _, kwargs = mock_paginated.call_args - assert kwargs["api_version"] == APIVersion.V1ALPHA - - -def test_get_job_context_property_custom_api_version(chronicle_client): - """Test get_job_context_property with custom API version.""" - expected = {"name": "contextProperties/prop1"} - - with patch( - "secops.chronicle.integration.job_context_properties.chronicle_request", - return_value=expected, - ) as mock_request: - result = get_job_context_property( - chronicle_client, - integration_name="test-integration", - job_id="j1", - context_property_id="prop1", - api_version=APIVersion.V1ALPHA, - ) - - assert result == expected - - _, kwargs = mock_request.call_args - assert kwargs["api_version"] == APIVersion.V1ALPHA - diff --git a/tests/chronicle/integration/test_job_instance_logs.py b/tests/chronicle/integration/test_job_instance_logs.py deleted file mode 100644 index ad456e79..00000000 --- a/tests/chronicle/integration/test_job_instance_logs.py +++ /dev/null @@ -1,256 +0,0 @@ -# Copyright 2025 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. -# -"""Tests for Chronicle integration job instance logs functions.""" - -from unittest.mock import Mock, patch - -import pytest - -from secops.chronicle.client import ChronicleClient -from secops.chronicle.models import APIVersion -from secops.chronicle.integration.job_instance_logs import ( - list_job_instance_logs, - get_job_instance_log, -) -from secops.exceptions import APIError - - -@pytest.fixture -def chronicle_client(): - """Create a Chronicle client for testing.""" - with patch("secops.auth.SecOpsAuth") as mock_auth: - mock_session = Mock() - mock_session.headers = {} - mock_auth.return_value.session = mock_session - return ChronicleClient( - customer_id="test-customer", - project_id="test-project", - default_api_version=APIVersion.V1BETA, - ) - - -# -- list_job_instance_logs tests -- - - -def test_list_job_instance_logs_success(chronicle_client): - """Test list_job_instance_logs delegates to paginated request.""" - expected = { - "logs": [{"name": "log1"}, {"name": "log2"}], - "nextPageToken": "t", - } - - with patch( - "secops.chronicle.integration.job_instance_logs.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated, patch( - "secops.chronicle.integration.job_instance_logs.format_resource_id", - return_value="My Integration", - ): - result = list_job_instance_logs( - chronicle_client, - integration_name="My Integration", - job_id="j1", - job_instance_id="ji1", - page_size=10, - page_token="next-token", - ) - - assert result == expected - - _, kwargs = mock_paginated.call_args - assert "jobs/j1/jobInstances/ji1/logs" in kwargs["path"] - assert kwargs["items_key"] == "logs" - assert kwargs["page_size"] == 10 - assert kwargs["page_token"] == "next-token" - - -def test_list_job_instance_logs_default_args(chronicle_client): - """Test list_job_instance_logs with default args.""" - expected = {"logs": []} - - with patch( - "secops.chronicle.integration.job_instance_logs.chronicle_paginated_request", - return_value=expected, - ): - result = list_job_instance_logs( - chronicle_client, - integration_name="test-integration", - job_id="j1", - job_instance_id="ji1", - ) - - assert result == expected - - -def test_list_job_instance_logs_with_filters(chronicle_client): - """Test list_job_instance_logs with filter and order_by.""" - expected = {"logs": [{"name": "log1"}]} - - with patch( - "secops.chronicle.integration.job_instance_logs.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated: - result = list_job_instance_logs( - chronicle_client, - integration_name="test-integration", - job_id="j1", - job_instance_id="ji1", - filter_string="status = SUCCESS", - order_by="startTime desc", - ) - - assert result == expected - - _, kwargs = mock_paginated.call_args - assert kwargs["extra_params"] == { - "filter": "status = SUCCESS", - "orderBy": "startTime desc", - } - - -def test_list_job_instance_logs_as_list(chronicle_client): - """Test list_job_instance_logs returns list when as_list=True.""" - expected = [{"name": "log1"}, {"name": "log2"}] - - with patch( - "secops.chronicle.integration.job_instance_logs.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated: - result = list_job_instance_logs( - chronicle_client, - integration_name="test-integration", - job_id="j1", - job_instance_id="ji1", - as_list=True, - ) - - assert result == expected - - _, kwargs = mock_paginated.call_args - assert kwargs["as_list"] is True - - -def test_list_job_instance_logs_error(chronicle_client): - """Test list_job_instance_logs raises APIError on failure.""" - with patch( - "secops.chronicle.integration.job_instance_logs.chronicle_paginated_request", - side_effect=APIError("Failed to list job instance logs"), - ): - with pytest.raises(APIError) as exc_info: - list_job_instance_logs( - chronicle_client, - integration_name="test-integration", - job_id="j1", - job_instance_id="ji1", - ) - assert "Failed to list job instance logs" in str(exc_info.value) - - -# -- get_job_instance_log tests -- - - -def test_get_job_instance_log_success(chronicle_client): - """Test get_job_instance_log issues GET request.""" - expected = { - "name": "logs/log1", - "status": "SUCCESS", - "startTime": "2026-03-08T10:00:00Z", - "endTime": "2026-03-08T10:05:00Z", - } - - with patch( - "secops.chronicle.integration.job_instance_logs.chronicle_request", - return_value=expected, - ) as mock_request: - result = get_job_instance_log( - chronicle_client, - integration_name="test-integration", - job_id="j1", - job_instance_id="ji1", - log_id="log1", - ) - - assert result == expected - - _, kwargs = mock_request.call_args - assert kwargs["method"] == "GET" - assert "jobs/j1/jobInstances/ji1/logs/log1" in kwargs["endpoint_path"] - assert kwargs["api_version"] == APIVersion.V1BETA - - -def test_get_job_instance_log_error(chronicle_client): - """Test get_job_instance_log raises APIError on failure.""" - with patch( - "secops.chronicle.integration.job_instance_logs.chronicle_request", - side_effect=APIError("Failed to get job instance log"), - ): - with pytest.raises(APIError) as exc_info: - get_job_instance_log( - chronicle_client, - integration_name="test-integration", - job_id="j1", - job_instance_id="ji1", - log_id="log1", - ) - assert "Failed to get job instance log" in str(exc_info.value) - - -# -- API version tests -- - - -def test_list_job_instance_logs_custom_api_version(chronicle_client): - """Test list_job_instance_logs with custom API version.""" - expected = {"logs": []} - - with patch( - "secops.chronicle.integration.job_instance_logs.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated: - result = list_job_instance_logs( - chronicle_client, - integration_name="test-integration", - job_id="j1", - job_instance_id="ji1", - api_version=APIVersion.V1ALPHA, - ) - - assert result == expected - - _, kwargs = mock_paginated.call_args - assert kwargs["api_version"] == APIVersion.V1ALPHA - - -def test_get_job_instance_log_custom_api_version(chronicle_client): - """Test get_job_instance_log with custom API version.""" - expected = {"name": "logs/log1"} - - with patch( - "secops.chronicle.integration.job_instance_logs.chronicle_request", - return_value=expected, - ) as mock_request: - result = get_job_instance_log( - chronicle_client, - integration_name="test-integration", - job_id="j1", - job_instance_id="ji1", - log_id="log1", - api_version=APIVersion.V1ALPHA, - ) - - assert result == expected - - _, kwargs = mock_request.call_args - assert kwargs["api_version"] == APIVersion.V1ALPHA - diff --git a/tests/chronicle/integration/test_job_instances.py b/tests/chronicle/integration/test_job_instances.py deleted file mode 100644 index 3e8ca386..00000000 --- a/tests/chronicle/integration/test_job_instances.py +++ /dev/null @@ -1,733 +0,0 @@ -# Copyright 2025 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. -# -"""Tests for Chronicle marketplace integration job instances functions.""" - -from unittest.mock import Mock, patch - -import pytest - -from secops.chronicle.client import ChronicleClient -from secops.chronicle.models import ( - APIVersion, - IntegrationJobInstanceParameter, - AdvancedConfig, - ScheduleType, - DailyScheduleDetails, - Date, - TimeOfDay, -) -from secops.chronicle.integration.job_instances import ( - list_integration_job_instances, - get_integration_job_instance, - delete_integration_job_instance, - create_integration_job_instance, - update_integration_job_instance, - run_integration_job_instance_on_demand, -) -from secops.exceptions import APIError - - -@pytest.fixture -def chronicle_client(): - """Create a Chronicle client for testing.""" - with patch("secops.auth.SecOpsAuth") as mock_auth: - mock_session = Mock() - mock_session.headers = {} - mock_auth.return_value.session = mock_session - return ChronicleClient( - customer_id="test-customer", - project_id="test-project", - default_api_version=APIVersion.V1BETA, - ) - - -# -- list_integration_job_instances tests -- - - -def test_list_integration_job_instances_success(chronicle_client): - """Test list_integration_job_instances delegates to chronicle_paginated_request.""" - expected = { - "jobInstances": [{"name": "ji1"}, {"name": "ji2"}], - "nextPageToken": "t", - } - - with patch( - "secops.chronicle.integration.job_instances.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated, patch( - "secops.chronicle.integration.job_instances.format_resource_id", - return_value="My Integration", - ): - result = list_integration_job_instances( - chronicle_client, - integration_name="My Integration", - job_id="j1", - page_size=10, - page_token="next-token", - ) - - assert result == expected - - _, kwargs = mock_paginated.call_args - assert "jobs/j1/jobInstances" in kwargs["path"] - assert kwargs["items_key"] == "jobInstances" - assert kwargs["page_size"] == 10 - assert kwargs["page_token"] == "next-token" - - -def test_list_integration_job_instances_default_args(chronicle_client): - """Test list_integration_job_instances with default args.""" - expected = {"jobInstances": []} - - with patch( - "secops.chronicle.integration.job_instances.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated: - result = list_integration_job_instances( - chronicle_client, - integration_name="test-integration", - job_id="j1", - ) - - assert result == expected - - -def test_list_integration_job_instances_with_filters(chronicle_client): - """Test list_integration_job_instances with filter and order_by.""" - expected = {"jobInstances": [{"name": "ji1"}]} - - with patch( - "secops.chronicle.integration.job_instances.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated: - result = list_integration_job_instances( - chronicle_client, - integration_name="test-integration", - job_id="j1", - filter_string="enabled = true", - order_by="displayName", - ) - - assert result == expected - - _, kwargs = mock_paginated.call_args - assert kwargs["extra_params"] == { - "filter": "enabled = true", - "orderBy": "displayName", - } - - -def test_list_integration_job_instances_as_list(chronicle_client): - """Test list_integration_job_instances returns list when as_list=True.""" - expected = [{"name": "ji1"}, {"name": "ji2"}] - - with patch( - "secops.chronicle.integration.job_instances.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated: - result = list_integration_job_instances( - chronicle_client, - integration_name="test-integration", - job_id="j1", - as_list=True, - ) - - assert result == expected - - _, kwargs = mock_paginated.call_args - assert kwargs["as_list"] is True - - -def test_list_integration_job_instances_error(chronicle_client): - """Test list_integration_job_instances raises APIError on failure.""" - with patch( - "secops.chronicle.integration.job_instances.chronicle_paginated_request", - side_effect=APIError("Failed to list job instances"), - ): - with pytest.raises(APIError) as exc_info: - list_integration_job_instances( - chronicle_client, - integration_name="test-integration", - job_id="j1", - ) - assert "Failed to list job instances" in str(exc_info.value) - - -# -- get_integration_job_instance tests -- - - -def test_get_integration_job_instance_success(chronicle_client): - """Test get_integration_job_instance issues GET request.""" - expected = { - "name": "jobInstances/ji1", - "displayName": "My Job Instance", - "intervalSeconds": 300, - "enabled": True, - } - - with patch( - "secops.chronicle.integration.job_instances.chronicle_request", - return_value=expected, - ) as mock_request: - result = get_integration_job_instance( - chronicle_client, - integration_name="test-integration", - job_id="j1", - job_instance_id="ji1", - ) - - assert result == expected - - _, kwargs = mock_request.call_args - assert kwargs["method"] == "GET" - assert "jobs/j1/jobInstances/ji1" in kwargs["endpoint_path"] - assert kwargs["api_version"] == APIVersion.V1BETA - - -def test_get_integration_job_instance_error(chronicle_client): - """Test get_integration_job_instance raises APIError on failure.""" - with patch( - "secops.chronicle.integration.job_instances.chronicle_request", - side_effect=APIError("Failed to get job instance"), - ): - with pytest.raises(APIError) as exc_info: - get_integration_job_instance( - chronicle_client, - integration_name="test-integration", - job_id="j1", - job_instance_id="ji1", - ) - assert "Failed to get job instance" in str(exc_info.value) - - -# -- delete_integration_job_instance tests -- - - -def test_delete_integration_job_instance_success(chronicle_client): - """Test delete_integration_job_instance issues DELETE request.""" - with patch( - "secops.chronicle.integration.job_instances.chronicle_request", - return_value=None, - ) as mock_request: - delete_integration_job_instance( - chronicle_client, - integration_name="test-integration", - job_id="j1", - job_instance_id="ji1", - ) - - _, kwargs = mock_request.call_args - assert kwargs["method"] == "DELETE" - assert "jobs/j1/jobInstances/ji1" in kwargs["endpoint_path"] - assert kwargs["api_version"] == APIVersion.V1BETA - - -def test_delete_integration_job_instance_error(chronicle_client): - """Test delete_integration_job_instance raises APIError on failure.""" - with patch( - "secops.chronicle.integration.job_instances.chronicle_request", - side_effect=APIError("Failed to delete job instance"), - ): - with pytest.raises(APIError) as exc_info: - delete_integration_job_instance( - chronicle_client, - integration_name="test-integration", - job_id="j1", - job_instance_id="ji1", - ) - assert "Failed to delete job instance" in str(exc_info.value) - - -# -- create_integration_job_instance tests -- - - -def test_create_integration_job_instance_required_fields_only(chronicle_client): - """Test create_integration_job_instance sends only required fields.""" - expected = {"name": "jobInstances/new", "displayName": "My Job Instance"} - - with patch( - "secops.chronicle.integration.job_instances.chronicle_request", - return_value=expected, - ) as mock_request: - result = create_integration_job_instance( - chronicle_client, - integration_name="test-integration", - job_id="j1", - display_name="My Job Instance", - interval_seconds=300, - enabled=True, - advanced=False, - ) - - assert result == expected - - mock_request.assert_called_once_with( - chronicle_client, - method="POST", - endpoint_path="integrations/test-integration/jobs/j1/jobInstances", - api_version=APIVersion.V1BETA, - json={ - "displayName": "My Job Instance", - "intervalSeconds": 300, - "enabled": True, - "advanced": False, - }, - ) - - -def test_create_integration_job_instance_with_optional_fields(chronicle_client): - """Test create_integration_job_instance includes optional fields when provided.""" - expected = {"name": "jobInstances/new"} - - with patch( - "secops.chronicle.integration.job_instances.chronicle_request", - return_value=expected, - ) as mock_request: - result = create_integration_job_instance( - chronicle_client, - integration_name="test-integration", - job_id="j1", - display_name="My Job Instance", - interval_seconds=300, - enabled=True, - advanced=False, - description="Test job instance", - parameters=[{"id": 1, "value": "test"}], - agent="agent-123", - ) - - assert result == expected - - _, kwargs = mock_request.call_args - assert kwargs["json"]["description"] == "Test job instance" - assert kwargs["json"]["parameters"] == [{"id": 1, "value": "test"}] - assert kwargs["json"]["agent"] == "agent-123" - - -def test_create_integration_job_instance_with_dataclass_params(chronicle_client): - """Test create_integration_job_instance converts dataclass parameters.""" - expected = {"name": "jobInstances/new"} - - param = IntegrationJobInstanceParameter(value="test-value") - - with patch( - "secops.chronicle.integration.job_instances.chronicle_request", - return_value=expected, - ) as mock_request: - result = create_integration_job_instance( - chronicle_client, - integration_name="test-integration", - job_id="j1", - display_name="My Job Instance", - interval_seconds=300, - enabled=True, - advanced=False, - parameters=[param], - ) - - assert result == expected - - _, kwargs = mock_request.call_args - params_sent = kwargs["json"]["parameters"] - assert len(params_sent) == 1 - assert params_sent[0]["value"] == "test-value" - - -def test_create_integration_job_instance_with_advanced_config(chronicle_client): - """Test create_integration_job_instance with AdvancedConfig dataclass.""" - expected = {"name": "jobInstances/new"} - - advanced_config = AdvancedConfig( - time_zone="America/New_York", - schedule_type=ScheduleType.DAILY, - daily_schedule=DailyScheduleDetails( - start_date=Date(year=2026, month=3, day=8), - time=TimeOfDay(hours=2, minutes=0), - interval=1 - ) - ) - - with patch( - "secops.chronicle.integration.job_instances.chronicle_request", - return_value=expected, - ) as mock_request: - result = create_integration_job_instance( - chronicle_client, - integration_name="test-integration", - job_id="j1", - display_name="My Job Instance", - interval_seconds=300, - enabled=True, - advanced=True, - advanced_config=advanced_config, - ) - - assert result == expected - - _, kwargs = mock_request.call_args - config_sent = kwargs["json"]["advancedConfig"] - assert config_sent["timeZone"] == "America/New_York" - assert config_sent["scheduleType"] == "DAILY" - assert "dailySchedule" in config_sent - - -def test_create_integration_job_instance_error(chronicle_client): - """Test create_integration_job_instance raises APIError on failure.""" - with patch( - "secops.chronicle.integration.job_instances.chronicle_request", - side_effect=APIError("Failed to create job instance"), - ): - with pytest.raises(APIError) as exc_info: - create_integration_job_instance( - chronicle_client, - integration_name="test-integration", - job_id="j1", - display_name="My Job Instance", - interval_seconds=300, - enabled=True, - advanced=False, - ) - assert "Failed to create job instance" in str(exc_info.value) - - -# -- update_integration_job_instance tests -- - - -def test_update_integration_job_instance_single_field(chronicle_client): - """Test update_integration_job_instance updates a single field.""" - expected = {"name": "jobInstances/ji1", "displayName": "Updated Instance"} - - with patch( - "secops.chronicle.integration.job_instances.chronicle_request", - return_value=expected, - ) as mock_request, patch( - "secops.chronicle.integration.job_instances.build_patch_body", - return_value=( - {"displayName": "Updated Instance"}, - {"updateMask": "displayName"}, - ), - ) as mock_build_patch: - result = update_integration_job_instance( - chronicle_client, - integration_name="test-integration", - job_id="j1", - job_instance_id="ji1", - display_name="Updated Instance", - ) - - assert result == expected - - mock_build_patch.assert_called_once() - mock_request.assert_called_once_with( - chronicle_client, - method="PATCH", - endpoint_path=( - "integrations/test-integration/jobs/j1/jobInstances/ji1" - ), - api_version=APIVersion.V1BETA, - json={"displayName": "Updated Instance"}, - params={"updateMask": "displayName"}, - ) - - -def test_update_integration_job_instance_multiple_fields(chronicle_client): - """Test update_integration_job_instance updates multiple fields.""" - expected = {"name": "jobInstances/ji1"} - - with patch( - "secops.chronicle.integration.job_instances.chronicle_request", - return_value=expected, - ) as mock_request, patch( - "secops.chronicle.integration.job_instances.build_patch_body", - return_value=( - { - "displayName": "Updated", - "intervalSeconds": 600, - "enabled": False, - }, - {"updateMask": "displayName,intervalSeconds,enabled"}, - ), - ): - result = update_integration_job_instance( - chronicle_client, - integration_name="test-integration", - job_id="j1", - job_instance_id="ji1", - display_name="Updated", - interval_seconds=600, - enabled=False, - ) - - assert result == expected - - -def test_update_integration_job_instance_with_dataclass_params(chronicle_client): - """Test update_integration_job_instance converts dataclass parameters.""" - expected = {"name": "jobInstances/ji1"} - - param = IntegrationJobInstanceParameter(value="updated-value") - - with patch( - "secops.chronicle.integration.job_instances.chronicle_request", - return_value=expected, - ) as mock_request, patch( - "secops.chronicle.integration.job_instances.build_patch_body", - return_value=( - {"parameters": [{"value": "updated-value"}]}, - {"updateMask": "parameters"}, - ), - ): - result = update_integration_job_instance( - chronicle_client, - integration_name="test-integration", - job_id="j1", - job_instance_id="ji1", - parameters=[param], - ) - - assert result == expected - - -def test_update_integration_job_instance_with_advanced_config(chronicle_client): - """Test update_integration_job_instance with AdvancedConfig dataclass.""" - expected = {"name": "jobInstances/ji1"} - - advanced_config = AdvancedConfig( - time_zone="UTC", - schedule_type=ScheduleType.DAILY, - daily_schedule=DailyScheduleDetails( - start_date=Date(year=2026, month=3, day=8), - time=TimeOfDay(hours=0, minutes=0), - interval=1 - ) - ) - - with patch( - "secops.chronicle.integration.job_instances.chronicle_request", - return_value=expected, - ) as mock_request, patch( - "secops.chronicle.integration.job_instances.build_patch_body", - return_value=( - { - "advancedConfig": { - "timeZone": "UTC", - "scheduleType": "DAILY", - "dailySchedule": { - "startDate": {"year": 2026, "month": 3, "day": 8}, - "time": {"hours": 0, "minutes": 0}, - "interval": 1 - } - } - }, - {"updateMask": "advancedConfig"}, - ), - ): - result = update_integration_job_instance( - chronicle_client, - integration_name="test-integration", - job_id="j1", - job_instance_id="ji1", - advanced_config=advanced_config, - ) - - assert result == expected - - -def test_update_integration_job_instance_with_update_mask(chronicle_client): - """Test update_integration_job_instance respects explicit update_mask.""" - expected = {"name": "jobInstances/ji1"} - - with patch( - "secops.chronicle.integration.job_instances.chronicle_request", - return_value=expected, - ) as mock_request, patch( - "secops.chronicle.integration.job_instances.build_patch_body", - return_value=( - {"displayName": "Updated"}, - {"updateMask": "displayName"}, - ), - ): - result = update_integration_job_instance( - chronicle_client, - integration_name="test-integration", - job_id="j1", - job_instance_id="ji1", - display_name="Updated", - update_mask="displayName", - ) - - assert result == expected - - -def test_update_integration_job_instance_error(chronicle_client): - """Test update_integration_job_instance raises APIError on failure.""" - with patch( - "secops.chronicle.integration.job_instances.chronicle_request", - side_effect=APIError("Failed to update job instance"), - ), patch( - "secops.chronicle.integration.job_instances.build_patch_body", - return_value=({"enabled": False}, {"updateMask": "enabled"}), - ): - with pytest.raises(APIError) as exc_info: - update_integration_job_instance( - chronicle_client, - integration_name="test-integration", - job_id="j1", - job_instance_id="ji1", - enabled=False, - ) - assert "Failed to update job instance" in str(exc_info.value) - - -# -- run_integration_job_instance_on_demand tests -- - - -def test_run_integration_job_instance_on_demand_success(chronicle_client): - """Test run_integration_job_instance_on_demand issues POST request.""" - expected = {"success": True} - - with patch( - "secops.chronicle.integration.job_instances.chronicle_request", - return_value=expected, - ) as mock_request: - result = run_integration_job_instance_on_demand( - chronicle_client, - integration_name="test-integration", - job_id="j1", - job_instance_id="ji1", - ) - - assert result == expected - - mock_request.assert_called_once_with( - chronicle_client, - method="POST", - endpoint_path=( - "integrations/test-integration/jobs/j1/jobInstances/ji1:runOnDemand" - ), - api_version=APIVersion.V1BETA, - json={}, - ) - - -def test_run_integration_job_instance_on_demand_with_params(chronicle_client): - """Test run_integration_job_instance_on_demand with parameters.""" - expected = {"success": True} - - with patch( - "secops.chronicle.integration.job_instances.chronicle_request", - return_value=expected, - ) as mock_request: - result = run_integration_job_instance_on_demand( - chronicle_client, - integration_name="test-integration", - job_id="j1", - job_instance_id="ji1", - parameters=[{"id": 1, "value": "override"}], - ) - - assert result == expected - - _, kwargs = mock_request.call_args - assert kwargs["json"]["parameters"] == [{"id": 1, "value": "override"}] - - -def test_run_integration_job_instance_on_demand_with_dataclass(chronicle_client): - """Test run_integration_job_instance_on_demand converts dataclass parameters.""" - expected = {"success": True} - - param = IntegrationJobInstanceParameter(value="test") - - with patch( - "secops.chronicle.integration.job_instances.chronicle_request", - return_value=expected, - ) as mock_request: - result = run_integration_job_instance_on_demand( - chronicle_client, - integration_name="test-integration", - job_id="j1", - job_instance_id="ji1", - parameters=[param], - ) - - assert result == expected - - _, kwargs = mock_request.call_args - params_sent = kwargs["json"]["parameters"] - assert len(params_sent) == 1 - assert params_sent[0]["value"] == "test" - - -def test_run_integration_job_instance_on_demand_error(chronicle_client): - """Test run_integration_job_instance_on_demand raises APIError on failure.""" - with patch( - "secops.chronicle.integration.job_instances.chronicle_request", - side_effect=APIError("Failed to run job instance on demand"), - ): - with pytest.raises(APIError) as exc_info: - run_integration_job_instance_on_demand( - chronicle_client, - integration_name="test-integration", - job_id="j1", - job_instance_id="ji1", - ) - assert "Failed to run job instance on demand" in str(exc_info.value) - - -# -- API version tests -- - - -def test_list_integration_job_instances_custom_api_version(chronicle_client): - """Test list_integration_job_instances with custom API version.""" - expected = {"jobInstances": []} - - with patch( - "secops.chronicle.integration.job_instances.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated: - result = list_integration_job_instances( - chronicle_client, - integration_name="test-integration", - job_id="j1", - api_version=APIVersion.V1ALPHA, - ) - - assert result == expected - - _, kwargs = mock_paginated.call_args - assert kwargs["api_version"] == APIVersion.V1ALPHA - - -def test_get_integration_job_instance_custom_api_version(chronicle_client): - """Test get_integration_job_instance with custom API version.""" - expected = {"name": "jobInstances/ji1"} - - with patch( - "secops.chronicle.integration.job_instances.chronicle_request", - return_value=expected, - ) as mock_request: - result = get_integration_job_instance( - chronicle_client, - integration_name="test-integration", - job_id="j1", - job_instance_id="ji1", - api_version=APIVersion.V1ALPHA, - ) - - assert result == expected - - _, kwargs = mock_request.call_args - assert kwargs["api_version"] == APIVersion.V1ALPHA - diff --git a/tests/chronicle/integration/test_job_revisions.py b/tests/chronicle/integration/test_job_revisions.py deleted file mode 100644 index 3a81682c..00000000 --- a/tests/chronicle/integration/test_job_revisions.py +++ /dev/null @@ -1,378 +0,0 @@ -# Copyright 2025 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. -# -"""Tests for Chronicle marketplace integration job revisions functions.""" - -from unittest.mock import Mock, patch - -import pytest - -from secops.chronicle.client import ChronicleClient -from secops.chronicle.models import APIVersion -from secops.chronicle.integration.job_revisions import ( - list_integration_job_revisions, - delete_integration_job_revision, - create_integration_job_revision, - rollback_integration_job_revision, -) -from secops.exceptions import APIError - - -@pytest.fixture -def chronicle_client(): - """Create a Chronicle client for testing.""" - with patch("secops.auth.SecOpsAuth") as mock_auth: - mock_session = Mock() - mock_session.headers = {} - mock_auth.return_value.session = mock_session - return ChronicleClient( - customer_id="test-customer", - project_id="test-project", - default_api_version=APIVersion.V1BETA, - ) - - -# -- list_integration_job_revisions tests -- - - -def test_list_integration_job_revisions_success(chronicle_client): - """Test list_integration_job_revisions delegates to chronicle_paginated_request.""" - expected = { - "revisions": [{"name": "r1"}, {"name": "r2"}], - "nextPageToken": "t", - } - - with patch( - "secops.chronicle.integration.job_revisions.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated, patch( - "secops.chronicle.integration.job_revisions.format_resource_id", - return_value="My Integration", - ): - result = list_integration_job_revisions( - chronicle_client, - integration_name="My Integration", - job_id="j1", - page_size=10, - page_token="next-token", - ) - - assert result == expected - - _, kwargs = mock_paginated.call_args - assert "jobs/j1/revisions" in kwargs["path"] - assert kwargs["items_key"] == "revisions" - assert kwargs["page_size"] == 10 - assert kwargs["page_token"] == "next-token" - - -def test_list_integration_job_revisions_default_args(chronicle_client): - """Test list_integration_job_revisions with default args.""" - expected = {"revisions": []} - - with patch( - "secops.chronicle.integration.job_revisions.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated: - result = list_integration_job_revisions( - chronicle_client, - integration_name="test-integration", - job_id="j1", - ) - - assert result == expected - - -def test_list_integration_job_revisions_with_filters(chronicle_client): - """Test list_integration_job_revisions with filter and order_by.""" - expected = {"revisions": [{"name": "r1"}]} - - with patch( - "secops.chronicle.integration.job_revisions.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated: - result = list_integration_job_revisions( - chronicle_client, - integration_name="test-integration", - job_id="j1", - filter_string='version = "1.0"', - order_by="createTime", - ) - - assert result == expected - - _, kwargs = mock_paginated.call_args - assert kwargs["extra_params"] == { - "filter": 'version = "1.0"', - "orderBy": "createTime", - } - - -def test_list_integration_job_revisions_as_list(chronicle_client): - """Test list_integration_job_revisions returns list when as_list=True.""" - expected = [{"name": "r1"}, {"name": "r2"}] - - with patch( - "secops.chronicle.integration.job_revisions.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated: - result = list_integration_job_revisions( - chronicle_client, - integration_name="test-integration", - job_id="j1", - as_list=True, - ) - - assert result == expected - - _, kwargs = mock_paginated.call_args - assert kwargs["as_list"] is True - - -def test_list_integration_job_revisions_error(chronicle_client): - """Test list_integration_job_revisions raises APIError on failure.""" - with patch( - "secops.chronicle.integration.job_revisions.chronicle_paginated_request", - side_effect=APIError("Failed to list job revisions"), - ): - with pytest.raises(APIError) as exc_info: - list_integration_job_revisions( - chronicle_client, - integration_name="test-integration", - job_id="j1", - ) - assert "Failed to list job revisions" in str(exc_info.value) - - -# -- delete_integration_job_revision tests -- - - -def test_delete_integration_job_revision_success(chronicle_client): - """Test delete_integration_job_revision issues DELETE request.""" - with patch( - "secops.chronicle.integration.job_revisions.chronicle_request", - return_value=None, - ) as mock_request: - delete_integration_job_revision( - chronicle_client, - integration_name="test-integration", - job_id="j1", - revision_id="r1", - ) - - _, kwargs = mock_request.call_args - assert kwargs["method"] == "DELETE" - assert "jobs/j1/revisions/r1" in kwargs["endpoint_path"] - assert kwargs["api_version"] == APIVersion.V1BETA - - -def test_delete_integration_job_revision_error(chronicle_client): - """Test delete_integration_job_revision raises APIError on failure.""" - with patch( - "secops.chronicle.integration.job_revisions.chronicle_request", - side_effect=APIError("Failed to delete job revision"), - ): - with pytest.raises(APIError) as exc_info: - delete_integration_job_revision( - chronicle_client, - integration_name="test-integration", - job_id="j1", - revision_id="r1", - ) - assert "Failed to delete job revision" in str(exc_info.value) - - -# -- create_integration_job_revision tests -- - - -def test_create_integration_job_revision_required_fields_only( - chronicle_client, -): - """Test create_integration_job_revision with required fields only.""" - expected = {"name": "revisions/new", "job": {"displayName": "My Job"}} - job_dict = { - "displayName": "My Job", - "script": "print('hello')", - "version": 1, - "enabled": True, - "custom": True, - } - - with patch( - "secops.chronicle.integration.job_revisions.chronicle_request", - return_value=expected, - ) as mock_request: - result = create_integration_job_revision( - chronicle_client, - integration_name="test-integration", - job_id="j1", - job=job_dict, - ) - - assert result == expected - - mock_request.assert_called_once_with( - chronicle_client, - method="POST", - endpoint_path=( - "integrations/test-integration/jobs/j1/revisions" - ), - api_version=APIVersion.V1BETA, - json={"job": job_dict}, - ) - - -def test_create_integration_job_revision_with_comment(chronicle_client): - """Test create_integration_job_revision includes comment when provided.""" - expected = {"name": "revisions/new"} - job_dict = { - "displayName": "My Job", - "script": "print('hello')", - "version": 1, - "enabled": True, - "custom": True, - } - - with patch( - "secops.chronicle.integration.job_revisions.chronicle_request", - return_value=expected, - ) as mock_request: - result = create_integration_job_revision( - chronicle_client, - integration_name="test-integration", - job_id="j1", - job=job_dict, - comment="Backup before major update", - ) - - assert result == expected - - _, kwargs = mock_request.call_args - assert kwargs["json"]["comment"] == "Backup before major update" - assert kwargs["json"]["job"] == job_dict - - -def test_create_integration_job_revision_error(chronicle_client): - """Test create_integration_job_revision raises APIError on failure.""" - job_dict = { - "displayName": "My Job", - "script": "print('hello')", - "version": 1, - "enabled": True, - "custom": True, - } - - with patch( - "secops.chronicle.integration.job_revisions.chronicle_request", - side_effect=APIError("Failed to create job revision"), - ): - with pytest.raises(APIError) as exc_info: - create_integration_job_revision( - chronicle_client, - integration_name="test-integration", - job_id="j1", - job=job_dict, - ) - assert "Failed to create job revision" in str(exc_info.value) - - -# -- rollback_integration_job_revision tests -- - - -def test_rollback_integration_job_revision_success(chronicle_client): - """Test rollback_integration_job_revision issues POST request.""" - expected = { - "name": "revisions/r1", - "job": { - "displayName": "My Job", - "script": "print('hello')", - }, - } - - with patch( - "secops.chronicle.integration.job_revisions.chronicle_request", - return_value=expected, - ) as mock_request: - result = rollback_integration_job_revision( - chronicle_client, - integration_name="test-integration", - job_id="j1", - revision_id="r1", - ) - - assert result == expected - - _, kwargs = mock_request.call_args - assert kwargs["method"] == "POST" - assert "jobs/j1/revisions/r1:rollback" in kwargs["endpoint_path"] - assert kwargs["api_version"] == APIVersion.V1BETA - - -def test_rollback_integration_job_revision_error(chronicle_client): - """Test rollback_integration_job_revision raises APIError on failure.""" - with patch( - "secops.chronicle.integration.job_revisions.chronicle_request", - side_effect=APIError("Failed to rollback job revision"), - ): - with pytest.raises(APIError) as exc_info: - rollback_integration_job_revision( - chronicle_client, - integration_name="test-integration", - job_id="j1", - revision_id="r1", - ) - assert "Failed to rollback job revision" in str(exc_info.value) - - -# -- API version tests -- - - -def test_list_integration_job_revisions_custom_api_version(chronicle_client): - """Test list_integration_job_revisions with custom API version.""" - expected = {"revisions": []} - - with patch( - "secops.chronicle.integration.job_revisions.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated: - result = list_integration_job_revisions( - chronicle_client, - integration_name="test-integration", - job_id="j1", - api_version=APIVersion.V1ALPHA, - ) - - assert result == expected - - _, kwargs = mock_paginated.call_args - assert kwargs["api_version"] == APIVersion.V1ALPHA - - -def test_delete_integration_job_revision_custom_api_version(chronicle_client): - """Test delete_integration_job_revision with custom API version.""" - with patch( - "secops.chronicle.integration.job_revisions.chronicle_request", - return_value=None, - ) as mock_request: - delete_integration_job_revision( - chronicle_client, - integration_name="test-integration", - job_id="j1", - revision_id="r1", - api_version=APIVersion.V1ALPHA, - ) - - _, kwargs = mock_request.call_args - assert kwargs["api_version"] == APIVersion.V1ALPHA - diff --git a/tests/chronicle/integration/test_jobs.py b/tests/chronicle/integration/test_jobs.py deleted file mode 100644 index a318a890..00000000 --- a/tests/chronicle/integration/test_jobs.py +++ /dev/null @@ -1,594 +0,0 @@ -# Copyright 2025 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. -# -"""Tests for Chronicle marketplace integration jobs functions.""" - -from unittest.mock import Mock, patch - -import pytest - -from secops.chronicle.client import ChronicleClient -from secops.chronicle.models import APIVersion, JobParameter, ParamType -from secops.chronicle.integration.jobs import ( - list_integration_jobs, - get_integration_job, - delete_integration_job, - create_integration_job, - update_integration_job, - execute_integration_job_test, - get_integration_job_template, -) -from secops.exceptions import APIError - - -@pytest.fixture -def chronicle_client(): - """Create a Chronicle client for testing.""" - with patch("secops.auth.SecOpsAuth") as mock_auth: - mock_session = Mock() - mock_session.headers = {} - mock_auth.return_value.session = mock_session - return ChronicleClient( - customer_id="test-customer", - project_id="test-project", - default_api_version=APIVersion.V1BETA, - ) - - -# -- list_integration_jobs tests -- - - -def test_list_integration_jobs_success(chronicle_client): - """Test list_integration_jobs delegates to chronicle_paginated_request.""" - expected = {"jobs": [{"name": "j1"}, {"name": "j2"}], "nextPageToken": "t"} - - with patch( - "secops.chronicle.integration.jobs.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated, patch( - "secops.chronicle.integration.jobs.format_resource_id", - return_value="My Integration", - ): - result = list_integration_jobs( - chronicle_client, - integration_name="My Integration", - page_size=10, - page_token="next-token", - ) - - assert result == expected - - mock_paginated.assert_called_once_with( - chronicle_client, - api_version=APIVersion.V1BETA, - path="integrations/My Integration/jobs", - items_key="jobs", - page_size=10, - page_token="next-token", - extra_params={}, - as_list=False, - ) - - -def test_list_integration_jobs_default_args(chronicle_client): - """Test list_integration_jobs with default args.""" - expected = {"jobs": []} - - with patch( - "secops.chronicle.integration.jobs.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated: - result = list_integration_jobs( - chronicle_client, - integration_name="test-integration", - ) - - assert result == expected - - -def test_list_integration_jobs_with_filters(chronicle_client): - """Test list_integration_jobs with filter and order_by.""" - expected = {"jobs": [{"name": "j1"}]} - - with patch( - "secops.chronicle.integration.jobs.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated: - result = list_integration_jobs( - chronicle_client, - integration_name="test-integration", - filter_string="custom=true", - order_by="displayName", - exclude_staging=True, - ) - - assert result == expected - - _, kwargs = mock_paginated.call_args - assert kwargs["extra_params"] == { - "filter": "custom=true", - "orderBy": "displayName", - "excludeStaging": True, - } - - -def test_list_integration_jobs_as_list(chronicle_client): - """Test list_integration_jobs returns list when as_list=True.""" - expected = [{"name": "j1"}, {"name": "j2"}] - - with patch( - "secops.chronicle.integration.jobs.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated: - result = list_integration_jobs( - chronicle_client, - integration_name="test-integration", - as_list=True, - ) - - assert result == expected - - _, kwargs = mock_paginated.call_args - assert kwargs["as_list"] is True - - -def test_list_integration_jobs_error(chronicle_client): - """Test list_integration_jobs raises APIError on failure.""" - with patch( - "secops.chronicle.integration.jobs.chronicle_paginated_request", - side_effect=APIError("Failed to list integration jobs"), - ): - with pytest.raises(APIError) as exc_info: - list_integration_jobs( - chronicle_client, - integration_name="test-integration", - ) - assert "Failed to list integration jobs" in str(exc_info.value) - - -# -- get_integration_job tests -- - - -def test_get_integration_job_success(chronicle_client): - """Test get_integration_job issues GET request.""" - expected = { - "name": "jobs/j1", - "displayName": "My Job", - "script": "print('hello')", - } - - with patch( - "secops.chronicle.integration.jobs.chronicle_request", - return_value=expected, - ) as mock_request: - result = get_integration_job( - chronicle_client, - integration_name="test-integration", - job_id="j1", - ) - - assert result == expected - - mock_request.assert_called_once_with( - chronicle_client, - method="GET", - endpoint_path="integrations/test-integration/jobs/j1", - api_version=APIVersion.V1BETA, - ) - - -def test_get_integration_job_error(chronicle_client): - """Test get_integration_job raises APIError on failure.""" - with patch( - "secops.chronicle.integration.jobs.chronicle_request", - side_effect=APIError("Failed to get integration job"), - ): - with pytest.raises(APIError) as exc_info: - get_integration_job( - chronicle_client, - integration_name="test-integration", - job_id="j1", - ) - assert "Failed to get integration job" in str(exc_info.value) - - -# -- delete_integration_job tests -- - - -def test_delete_integration_job_success(chronicle_client): - """Test delete_integration_job issues DELETE request.""" - with patch( - "secops.chronicle.integration.jobs.chronicle_request", - return_value=None, - ) as mock_request: - delete_integration_job( - chronicle_client, - integration_name="test-integration", - job_id="j1", - ) - - mock_request.assert_called_once_with( - chronicle_client, - method="DELETE", - endpoint_path="integrations/test-integration/jobs/j1", - api_version=APIVersion.V1BETA, - ) - - -def test_delete_integration_job_error(chronicle_client): - """Test delete_integration_job raises APIError on failure.""" - with patch( - "secops.chronicle.integration.jobs.chronicle_request", - side_effect=APIError("Failed to delete integration job"), - ): - with pytest.raises(APIError) as exc_info: - delete_integration_job( - chronicle_client, - integration_name="test-integration", - job_id="j1", - ) - assert "Failed to delete integration job" in str(exc_info.value) - - -# -- create_integration_job tests -- - - -def test_create_integration_job_required_fields_only(chronicle_client): - """Test create_integration_job sends only required fields when optionals omitted.""" - expected = {"name": "jobs/new", "displayName": "My Job"} - - with patch( - "secops.chronicle.integration.jobs.chronicle_request", - return_value=expected, - ) as mock_request: - result = create_integration_job( - chronicle_client, - integration_name="test-integration", - display_name="My Job", - script="print('hi')", - version=1, - enabled=True, - custom=True, - ) - - assert result == expected - - mock_request.assert_called_once_with( - chronicle_client, - method="POST", - endpoint_path="integrations/test-integration/jobs", - api_version=APIVersion.V1BETA, - json={ - "displayName": "My Job", - "script": "print('hi')", - "version": 1, - "enabled": True, - "custom": True, - }, - ) - - -def test_create_integration_job_with_optional_fields(chronicle_client): - """Test create_integration_job includes optional fields when provided.""" - expected = {"name": "jobs/new"} - - with patch( - "secops.chronicle.integration.jobs.chronicle_request", - return_value=expected, - ) as mock_request: - result = create_integration_job( - chronicle_client, - integration_name="test-integration", - display_name="My Job", - script="print('hi')", - version=1, - enabled=True, - custom=True, - description="Test job", - parameters=[{"id": 1, "displayName": "p1", "type": "STRING"}], - ) - - assert result == expected - - _, kwargs = mock_request.call_args - assert kwargs["json"]["description"] == "Test job" - assert kwargs["json"]["parameters"] == [ - {"id": 1, "displayName": "p1", "type": "STRING"} - ] - - -def test_create_integration_job_with_dataclass_parameters(chronicle_client): - """Test create_integration_job converts JobParameter dataclasses.""" - expected = {"name": "jobs/new"} - - param = JobParameter( - id=1, - display_name="API Key", - description="API key for authentication", - type=ParamType.STRING, - mandatory=True, - ) - - with patch( - "secops.chronicle.integration.jobs.chronicle_request", - return_value=expected, - ) as mock_request: - result = create_integration_job( - chronicle_client, - integration_name="test-integration", - display_name="My Job", - script="print('hi')", - version=1, - enabled=True, - custom=True, - parameters=[param], - ) - - assert result == expected - - _, kwargs = mock_request.call_args - params_sent = kwargs["json"]["parameters"] - assert len(params_sent) == 1 - assert params_sent[0]["id"] == 1 - assert params_sent[0]["displayName"] == "API Key" - assert params_sent[0]["type"] == "STRING" - - -def test_create_integration_job_error(chronicle_client): - """Test create_integration_job raises APIError on failure.""" - with patch( - "secops.chronicle.integration.jobs.chronicle_request", - side_effect=APIError("Failed to create integration job"), - ): - with pytest.raises(APIError) as exc_info: - create_integration_job( - chronicle_client, - integration_name="test-integration", - display_name="My Job", - script="print('hi')", - version=1, - enabled=True, - custom=True, - ) - assert "Failed to create integration job" in str(exc_info.value) - - -# -- update_integration_job tests -- - - -def test_update_integration_job_with_explicit_update_mask(chronicle_client): - """Test update_integration_job passes through explicit update_mask.""" - expected = {"name": "jobs/j1", "displayName": "New Name"} - - with patch( - "secops.chronicle.integration.jobs.chronicle_request", - return_value=expected, - ) as mock_request: - result = update_integration_job( - chronicle_client, - integration_name="test-integration", - job_id="j1", - display_name="New Name", - update_mask="displayName", - ) - - assert result == expected - - mock_request.assert_called_once_with( - chronicle_client, - method="PATCH", - endpoint_path="integrations/test-integration/jobs/j1", - api_version=APIVersion.V1BETA, - json={"displayName": "New Name"}, - params={"updateMask": "displayName"}, - ) - - -def test_update_integration_job_auto_update_mask(chronicle_client): - """Test update_integration_job auto-generates updateMask based on fields.""" - expected = {"name": "jobs/j1"} - - with patch( - "secops.chronicle.integration.jobs.chronicle_request", - return_value=expected, - ) as mock_request: - result = update_integration_job( - chronicle_client, - integration_name="test-integration", - job_id="j1", - enabled=False, - version=2, - ) - - assert result == expected - - assert mock_request.call_count == 1 - _, kwargs = mock_request.call_args - - assert kwargs["method"] == "PATCH" - assert kwargs["endpoint_path"] == "integrations/test-integration/jobs/j1" - assert kwargs["api_version"] == APIVersion.V1BETA - - assert kwargs["json"] == {"enabled": False, "version": 2} - - update_mask = kwargs["params"]["updateMask"] - assert set(update_mask.split(",")) == {"enabled", "version"} - - -def test_update_integration_job_with_parameters(chronicle_client): - """Test update_integration_job with parameters field.""" - expected = {"name": "jobs/j1"} - - param = JobParameter( - id=2, - display_name="Auth Token", - description="Authentication token", - type=ParamType.PASSWORD, - mandatory=True, - ) - - with patch( - "secops.chronicle.integration.jobs.chronicle_request", - return_value=expected, - ) as mock_request: - result = update_integration_job( - chronicle_client, - integration_name="test-integration", - job_id="j1", - parameters=[param], - ) - - assert result == expected - - _, kwargs = mock_request.call_args - params_sent = kwargs["json"]["parameters"] - assert len(params_sent) == 1 - assert params_sent[0]["id"] == 2 - assert params_sent[0]["displayName"] == "Auth Token" - - -def test_update_integration_job_error(chronicle_client): - """Test update_integration_job raises APIError on failure.""" - with patch( - "secops.chronicle.integration.jobs.chronicle_request", - side_effect=APIError("Failed to update integration job"), - ): - with pytest.raises(APIError) as exc_info: - update_integration_job( - chronicle_client, - integration_name="test-integration", - job_id="j1", - display_name="New Name", - ) - assert "Failed to update integration job" in str(exc_info.value) - - -# -- execute_integration_job_test tests -- - - -def test_execute_integration_job_test_success(chronicle_client): - """Test execute_integration_job_test sends POST request with job.""" - expected = { - "output": "Success", - "debugOutput": "Debug info", - "resultObjectJson": {"status": "ok"}, - } - - job = { - "displayName": "Test Job", - "script": "print('test')", - "enabled": True, - } - - with patch( - "secops.chronicle.integration.jobs.chronicle_request", - return_value=expected, - ) as mock_request: - result = execute_integration_job_test( - chronicle_client, - integration_name="test-integration", - job=job, - ) - - assert result == expected - - mock_request.assert_called_once_with( - chronicle_client, - method="POST", - endpoint_path="integrations/test-integration/jobs:executeTest", - api_version=APIVersion.V1BETA, - json={"job": job}, - ) - - -def test_execute_integration_job_test_with_agent_identifier(chronicle_client): - """Test execute_integration_job_test includes agent_identifier when provided.""" - expected = {"output": "Success"} - - job = {"displayName": "Test", "script": "print('test')"} - - with patch( - "secops.chronicle.integration.jobs.chronicle_request", - return_value=expected, - ) as mock_request: - result = execute_integration_job_test( - chronicle_client, - integration_name="test-integration", - job=job, - agent_identifier="agent-123", - ) - - assert result == expected - - _, kwargs = mock_request.call_args - assert kwargs["json"]["agentIdentifier"] == "agent-123" - - -def test_execute_integration_job_test_error(chronicle_client): - """Test execute_integration_job_test raises APIError on failure.""" - with patch( - "secops.chronicle.integration.jobs.chronicle_request", - side_effect=APIError("Failed to execute job test"), - ): - with pytest.raises(APIError) as exc_info: - execute_integration_job_test( - chronicle_client, - integration_name="test-integration", - job={"displayName": "Test"}, - ) - assert "Failed to execute job test" in str(exc_info.value) - - -# -- get_integration_job_template tests -- - - -def test_get_integration_job_template_success(chronicle_client): - """Test get_integration_job_template issues GET request.""" - expected = { - "script": "# Template script\nprint('hello')", - "displayName": "Template Job", - } - - with patch( - "secops.chronicle.integration.jobs.chronicle_request", - return_value=expected, - ) as mock_request: - result = get_integration_job_template( - chronicle_client, - integration_name="test-integration", - ) - - assert result == expected - - mock_request.assert_called_once_with( - chronicle_client, - method="GET", - endpoint_path="integrations/test-integration/jobs:fetchTemplate", - api_version=APIVersion.V1BETA, - ) - - -def test_get_integration_job_template_error(chronicle_client): - """Test get_integration_job_template raises APIError on failure.""" - with patch( - "secops.chronicle.integration.jobs.chronicle_request", - side_effect=APIError("Failed to get job template"), - ): - with pytest.raises(APIError) as exc_info: - get_integration_job_template( - chronicle_client, - integration_name="test-integration", - ) - assert "Failed to get job template" in str(exc_info.value) - diff --git a/tests/chronicle/integration/test_logical_operator_revisions.py b/tests/chronicle/integration/test_logical_operator_revisions.py deleted file mode 100644 index 29e912e6..00000000 --- a/tests/chronicle/integration/test_logical_operator_revisions.py +++ /dev/null @@ -1,367 +0,0 @@ -# Copyright 2025 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. -# -"""Tests for Chronicle integration logical operator revisions functions.""" - -from unittest.mock import Mock, patch - -import pytest - -from secops.chronicle.client import ChronicleClient -from secops.chronicle.models import APIVersion -from secops.chronicle.integration.logical_operator_revisions import ( - list_integration_logical_operator_revisions, - delete_integration_logical_operator_revision, - create_integration_logical_operator_revision, - rollback_integration_logical_operator_revision, -) -from secops.exceptions import APIError - - -@pytest.fixture -def chronicle_client(): - """Create a Chronicle client for testing.""" - with patch("secops.auth.SecOpsAuth") as mock_auth: - mock_session = Mock() - mock_session.headers = {} - mock_auth.return_value.session = mock_session - return ChronicleClient( - customer_id="test-customer", - project_id="test-project", - default_api_version=APIVersion.V1ALPHA, - ) - - -# -- list_integration_logical_operator_revisions tests -- - - -def test_list_integration_logical_operator_revisions_success(chronicle_client): - """Test list_integration_logical_operator_revisions delegates to paginated request.""" - expected = { - "revisions": [{"name": "r1"}, {"name": "r2"}], - "nextPageToken": "token", - } - - with patch( - "secops.chronicle.integration.logical_operator_revisions.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated, patch( - "secops.chronicle.integration.logical_operator_revisions.format_resource_id", - return_value="My Integration", - ): - result = list_integration_logical_operator_revisions( - chronicle_client, - integration_name="My Integration", - logical_operator_id="lo1", - page_size=10, - page_token="next-token", - ) - - assert result == expected - - mock_paginated.assert_called_once_with( - chronicle_client, - api_version=APIVersion.V1ALPHA, - path="integrations/My Integration/logicalOperators/lo1/revisions", - items_key="revisions", - page_size=10, - page_token="next-token", - extra_params={}, - as_list=False, - ) - - -def test_list_integration_logical_operator_revisions_default_args(chronicle_client): - """Test list_integration_logical_operator_revisions with default args.""" - expected = {"revisions": []} - - with patch( - "secops.chronicle.integration.logical_operator_revisions.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated: - result = list_integration_logical_operator_revisions( - chronicle_client, - integration_name="test-integration", - logical_operator_id="lo1", - ) - - assert result == expected - - mock_paginated.assert_called_once_with( - chronicle_client, - api_version=APIVersion.V1ALPHA, - path="integrations/test-integration/logicalOperators/lo1/revisions", - items_key="revisions", - page_size=None, - page_token=None, - extra_params={}, - as_list=False, - ) - - -def test_list_integration_logical_operator_revisions_with_filter_order( - chronicle_client, -): - """Test list passes filter/orderBy in extra_params.""" - expected = {"revisions": [{"name": "r1"}]} - - with patch( - "secops.chronicle.integration.logical_operator_revisions.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated: - result = list_integration_logical_operator_revisions( - chronicle_client, - integration_name="test-integration", - logical_operator_id="lo1", - filter_string='version = "1.0"', - order_by="createTime desc", - ) - - assert result == expected - - mock_paginated.assert_called_once_with( - chronicle_client, - api_version=APIVersion.V1ALPHA, - path="integrations/test-integration/logicalOperators/lo1/revisions", - items_key="revisions", - page_size=None, - page_token=None, - extra_params={ - "filter": 'version = "1.0"', - "orderBy": "createTime desc", - }, - as_list=False, - ) - - -def test_list_integration_logical_operator_revisions_as_list(chronicle_client): - """Test list_integration_logical_operator_revisions with as_list=True.""" - expected = [{"name": "r1"}, {"name": "r2"}] - - with patch( - "secops.chronicle.integration.logical_operator_revisions.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated: - result = list_integration_logical_operator_revisions( - chronicle_client, - integration_name="test-integration", - logical_operator_id="lo1", - as_list=True, - ) - - assert result == expected - - mock_paginated.assert_called_once_with( - chronicle_client, - api_version=APIVersion.V1ALPHA, - path="integrations/test-integration/logicalOperators/lo1/revisions", - items_key="revisions", - page_size=None, - page_token=None, - extra_params={}, - as_list=True, - ) - - -# -- delete_integration_logical_operator_revision tests -- - - -def test_delete_integration_logical_operator_revision_success(chronicle_client): - """Test delete_integration_logical_operator_revision delegates to chronicle_request.""" - with patch( - "secops.chronicle.integration.logical_operator_revisions.chronicle_request", - return_value=None, - ) as mock_request, patch( - "secops.chronicle.integration.logical_operator_revisions.format_resource_id", - return_value="test-integration", - ): - delete_integration_logical_operator_revision( - chronicle_client, - integration_name="test-integration", - logical_operator_id="lo1", - revision_id="rev1", - ) - - mock_request.assert_called_once_with( - chronicle_client, - method="DELETE", - endpoint_path=( - "integrations/test-integration/logicalOperators/lo1/revisions/rev1" - ), - api_version=APIVersion.V1ALPHA, - ) - - -# -- create_integration_logical_operator_revision tests -- - - -def test_create_integration_logical_operator_revision_minimal(chronicle_client): - """Test create_integration_logical_operator_revision with minimal fields.""" - logical_operator = { - "displayName": "Test Operator", - "script": "def evaluate(a, b): return a == b", - } - expected = {"name": "rev1", "comment": ""} - - with patch( - "secops.chronicle.integration.logical_operator_revisions.chronicle_request", - return_value=expected, - ) as mock_request, patch( - "secops.chronicle.integration.logical_operator_revisions.format_resource_id", - return_value="test-integration", - ): - result = create_integration_logical_operator_revision( - chronicle_client, - integration_name="test-integration", - logical_operator_id="lo1", - logical_operator=logical_operator, - ) - - assert result == expected - - mock_request.assert_called_once_with( - chronicle_client, - method="POST", - endpoint_path=( - "integrations/test-integration/logicalOperators/lo1/revisions" - ), - api_version=APIVersion.V1ALPHA, - json={"logicalOperator": logical_operator}, - ) - - -def test_create_integration_logical_operator_revision_with_comment(chronicle_client): - """Test create_integration_logical_operator_revision with comment.""" - logical_operator = { - "displayName": "Test Operator", - "script": "def evaluate(a, b): return a == b", - } - expected = {"name": "rev1", "comment": "Version 2.0"} - - with patch( - "secops.chronicle.integration.logical_operator_revisions.chronicle_request", - return_value=expected, - ) as mock_request: - result = create_integration_logical_operator_revision( - chronicle_client, - integration_name="test-integration", - logical_operator_id="lo1", - logical_operator=logical_operator, - comment="Version 2.0", - ) - - assert result == expected - - call_kwargs = mock_request.call_args[1] - assert call_kwargs["json"]["logicalOperator"] == logical_operator - assert call_kwargs["json"]["comment"] == "Version 2.0" - - -# -- rollback_integration_logical_operator_revision tests -- - - -def test_rollback_integration_logical_operator_revision_success(chronicle_client): - """Test rollback_integration_logical_operator_revision delegates to chronicle_request.""" - expected = {"name": "rev1", "comment": "Rolled back"} - - with patch( - "secops.chronicle.integration.logical_operator_revisions.chronicle_request", - return_value=expected, - ) as mock_request, patch( - "secops.chronicle.integration.logical_operator_revisions.format_resource_id", - return_value="test-integration", - ): - result = rollback_integration_logical_operator_revision( - chronicle_client, - integration_name="test-integration", - logical_operator_id="lo1", - revision_id="rev1", - ) - - assert result == expected - - mock_request.assert_called_once_with( - chronicle_client, - method="POST", - endpoint_path=( - "integrations/test-integration/logicalOperators/lo1/" - "revisions/rev1:rollback" - ), - api_version=APIVersion.V1ALPHA, - ) - - -# -- Error handling tests -- - - -def test_list_integration_logical_operator_revisions_api_error(chronicle_client): - """Test list_integration_logical_operator_revisions handles API errors.""" - with patch( - "secops.chronicle.integration.logical_operator_revisions.chronicle_paginated_request", - side_effect=APIError("API Error"), - ): - with pytest.raises(APIError, match="API Error"): - list_integration_logical_operator_revisions( - chronicle_client, - integration_name="test-integration", - logical_operator_id="lo1", - ) - - -def test_delete_integration_logical_operator_revision_api_error(chronicle_client): - """Test delete_integration_logical_operator_revision handles API errors.""" - with patch( - "secops.chronicle.integration.logical_operator_revisions.chronicle_request", - side_effect=APIError("Delete failed"), - ): - with pytest.raises(APIError, match="Delete failed"): - delete_integration_logical_operator_revision( - chronicle_client, - integration_name="test-integration", - logical_operator_id="lo1", - revision_id="rev1", - ) - - -def test_create_integration_logical_operator_revision_api_error(chronicle_client): - """Test create_integration_logical_operator_revision handles API errors.""" - logical_operator = {"displayName": "Test"} - - with patch( - "secops.chronicle.integration.logical_operator_revisions.chronicle_request", - side_effect=APIError("Creation failed"), - ): - with pytest.raises(APIError, match="Creation failed"): - create_integration_logical_operator_revision( - chronicle_client, - integration_name="test-integration", - logical_operator_id="lo1", - logical_operator=logical_operator, - ) - - -def test_rollback_integration_logical_operator_revision_api_error(chronicle_client): - """Test rollback_integration_logical_operator_revision handles API errors.""" - with patch( - "secops.chronicle.integration.logical_operator_revisions.chronicle_request", - side_effect=APIError("Rollback failed"), - ): - with pytest.raises(APIError, match="Rollback failed"): - rollback_integration_logical_operator_revision( - chronicle_client, - integration_name="test-integration", - logical_operator_id="lo1", - revision_id="rev1", - ) - diff --git a/tests/chronicle/integration/test_logical_operators.py b/tests/chronicle/integration/test_logical_operators.py deleted file mode 100644 index df495750..00000000 --- a/tests/chronicle/integration/test_logical_operators.py +++ /dev/null @@ -1,547 +0,0 @@ -# Copyright 2025 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. -# -"""Tests for Chronicle integration logical operators functions.""" - -from unittest.mock import Mock, patch - -import pytest - -from secops.chronicle.client import ChronicleClient -from secops.chronicle.models import APIVersion -from secops.chronicle.integration.logical_operators import ( - list_integration_logical_operators, - get_integration_logical_operator, - delete_integration_logical_operator, - create_integration_logical_operator, - update_integration_logical_operator, - execute_integration_logical_operator_test, - get_integration_logical_operator_template, -) -from secops.exceptions import APIError - - -@pytest.fixture -def chronicle_client(): - """Create a Chronicle client for testing.""" - with patch("secops.auth.SecOpsAuth") as mock_auth: - mock_session = Mock() - mock_session.headers = {} - mock_auth.return_value.session = mock_session - return ChronicleClient( - customer_id="test-customer", - project_id="test-project", - default_api_version=APIVersion.V1ALPHA, - ) - - -# -- list_integration_logical_operators tests -- - - -def test_list_integration_logical_operators_success(chronicle_client): - """Test list_integration_logical_operators delegates to paginated request.""" - expected = { - "logicalOperators": [{"name": "lo1"}, {"name": "lo2"}], - "nextPageToken": "token", - } - - with patch( - "secops.chronicle.integration.logical_operators.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated, patch( - "secops.chronicle.integration.logical_operators.format_resource_id", - return_value="My Integration", - ): - result = list_integration_logical_operators( - chronicle_client, - integration_name="My Integration", - page_size=10, - page_token="next-token", - ) - - assert result == expected - - mock_paginated.assert_called_once_with( - chronicle_client, - api_version=APIVersion.V1ALPHA, - path="integrations/My Integration/logicalOperators", - items_key="logicalOperators", - page_size=10, - page_token="next-token", - extra_params={}, - as_list=False, - ) - - -def test_list_integration_logical_operators_default_args(chronicle_client): - """Test list_integration_logical_operators with default args.""" - expected = {"logicalOperators": []} - - with patch( - "secops.chronicle.integration.logical_operators.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated: - result = list_integration_logical_operators( - chronicle_client, - integration_name="test-integration", - ) - - assert result == expected - - mock_paginated.assert_called_once_with( - chronicle_client, - api_version=APIVersion.V1ALPHA, - path="integrations/test-integration/logicalOperators", - items_key="logicalOperators", - page_size=None, - page_token=None, - extra_params={}, - as_list=False, - ) - - -def test_list_integration_logical_operators_with_filter_order_expand( - chronicle_client, -): - """Test list passes filter/orderBy/excludeStaging/expand in extra_params.""" - expected = {"logicalOperators": [{"name": "lo1"}]} - - with patch( - "secops.chronicle.integration.logical_operators.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated: - result = list_integration_logical_operators( - chronicle_client, - integration_name="test-integration", - filter_string='displayName = "My Operator"', - order_by="displayName", - exclude_staging=True, - expand="parameters", - ) - - assert result == expected - - mock_paginated.assert_called_once_with( - chronicle_client, - api_version=APIVersion.V1ALPHA, - path="integrations/test-integration/logicalOperators", - items_key="logicalOperators", - page_size=None, - page_token=None, - extra_params={ - "filter": 'displayName = "My Operator"', - "orderBy": "displayName", - "excludeStaging": True, - "expand": "parameters", - }, - as_list=False, - ) - - -# -- get_integration_logical_operator tests -- - - -def test_get_integration_logical_operator_success(chronicle_client): - """Test get_integration_logical_operator delegates to chronicle_request.""" - expected = {"name": "lo1", "displayName": "My Operator"} - - with patch( - "secops.chronicle.integration.logical_operators.chronicle_request", - return_value=expected, - ) as mock_request, patch( - "secops.chronicle.integration.logical_operators.format_resource_id", - return_value="test-integration", - ): - result = get_integration_logical_operator( - chronicle_client, - integration_name="test-integration", - logical_operator_id="lo1", - ) - - assert result == expected - - mock_request.assert_called_once_with( - chronicle_client, - method="GET", - endpoint_path="integrations/test-integration/logicalOperators/lo1", - api_version=APIVersion.V1ALPHA, - params=None, - ) - - -def test_get_integration_logical_operator_with_expand(chronicle_client): - """Test get_integration_logical_operator with expand parameter.""" - expected = {"name": "lo1"} - - with patch( - "secops.chronicle.integration.logical_operators.chronicle_request", - return_value=expected, - ) as mock_request: - result = get_integration_logical_operator( - chronicle_client, - integration_name="test-integration", - logical_operator_id="lo1", - expand="parameters", - ) - - assert result == expected - - mock_request.assert_called_once_with( - chronicle_client, - method="GET", - endpoint_path="integrations/test-integration/logicalOperators/lo1", - api_version=APIVersion.V1ALPHA, - params={"expand": "parameters"}, - ) - - -# -- delete_integration_logical_operator tests -- - - -def test_delete_integration_logical_operator_success(chronicle_client): - """Test delete_integration_logical_operator delegates to chronicle_request.""" - with patch( - "secops.chronicle.integration.logical_operators.chronicle_request", - return_value=None, - ) as mock_request, patch( - "secops.chronicle.integration.logical_operators.format_resource_id", - return_value="test-integration", - ): - delete_integration_logical_operator( - chronicle_client, - integration_name="test-integration", - logical_operator_id="lo1", - ) - - mock_request.assert_called_once_with( - chronicle_client, - method="DELETE", - endpoint_path="integrations/test-integration/logicalOperators/lo1", - api_version=APIVersion.V1ALPHA, - ) - - -# -- create_integration_logical_operator tests -- - - -def test_create_integration_logical_operator_minimal(chronicle_client): - """Test create_integration_logical_operator with minimal required fields.""" - expected = {"name": "lo1", "displayName": "New Operator"} - - with patch( - "secops.chronicle.integration.logical_operators.chronicle_request", - return_value=expected, - ) as mock_request, patch( - "secops.chronicle.integration.logical_operators.format_resource_id", - return_value="test-integration", - ): - result = create_integration_logical_operator( - chronicle_client, - integration_name="test-integration", - display_name="New Operator", - script="def evaluate(a, b): return a == b", - script_timeout="60s", - enabled=True, - ) - - assert result == expected - - mock_request.assert_called_once() - call_kwargs = mock_request.call_args[1] - assert call_kwargs["method"] == "POST" - assert ( - call_kwargs["endpoint_path"] - == "integrations/test-integration/logicalOperators" - ) - assert call_kwargs["api_version"] == APIVersion.V1ALPHA - assert call_kwargs["json"]["displayName"] == "New Operator" - assert call_kwargs["json"]["script"] == "def evaluate(a, b): return a == b" - assert call_kwargs["json"]["scriptTimeout"] == "60s" - assert call_kwargs["json"]["enabled"] is True - - -def test_create_integration_logical_operator_with_all_fields(chronicle_client): - """Test create_integration_logical_operator with all optional fields.""" - expected = {"name": "lo1"} - - with patch( - "secops.chronicle.integration.logical_operators.chronicle_request", - return_value=expected, - ) as mock_request: - result = create_integration_logical_operator( - chronicle_client, - integration_name="test-integration", - display_name="Full Operator", - script="def evaluate(a, b): return a > b", - script_timeout="120s", - enabled=False, - description="Test logical operator description", - parameters=[{"name": "param1", "type": "STRING"}], - ) - - assert result == expected - - call_kwargs = mock_request.call_args[1] - body = call_kwargs["json"] - assert body["displayName"] == "Full Operator" - assert body["description"] == "Test logical operator description" - assert body["parameters"] == [{"name": "param1", "type": "STRING"}] - - -# -- update_integration_logical_operator tests -- - - -def test_update_integration_logical_operator_display_name(chronicle_client): - """Test update_integration_logical_operator updates display name.""" - expected = {"name": "lo1", "displayName": "Updated Name"} - - with patch( - "secops.chronicle.integration.logical_operators.chronicle_request", - return_value=expected, - ) as mock_request, patch( - "secops.chronicle.integration.logical_operators.build_patch_body", - return_value=({"displayName": "Updated Name"}, {"updateMask": "displayName"}), - ) as mock_build: - result = update_integration_logical_operator( - chronicle_client, - integration_name="test-integration", - logical_operator_id="lo1", - display_name="Updated Name", - ) - - assert result == expected - - mock_build.assert_called_once() - mock_request.assert_called_once() - call_kwargs = mock_request.call_args[1] - assert call_kwargs["method"] == "PATCH" - assert ( - call_kwargs["endpoint_path"] - == "integrations/test-integration/logicalOperators/lo1" - ) - - -def test_update_integration_logical_operator_with_update_mask(chronicle_client): - """Test update_integration_logical_operator with explicit update mask.""" - expected = {"name": "lo1"} - - with patch( - "secops.chronicle.integration.logical_operators.chronicle_request", - return_value=expected, - ) as mock_request, patch( - "secops.chronicle.integration.logical_operators.build_patch_body", - return_value=( - {"displayName": "New Name", "enabled": True}, - {"updateMask": "displayName,enabled"}, - ), - ): - result = update_integration_logical_operator( - chronicle_client, - integration_name="test-integration", - logical_operator_id="lo1", - display_name="New Name", - enabled=True, - update_mask="displayName,enabled", - ) - - assert result == expected - - -def test_update_integration_logical_operator_all_fields(chronicle_client): - """Test update_integration_logical_operator with all fields.""" - expected = {"name": "lo1"} - - with patch( - "secops.chronicle.integration.logical_operators.chronicle_request", - return_value=expected, - ) as mock_request, patch( - "secops.chronicle.integration.logical_operators.build_patch_body", - return_value=( - { - "displayName": "Updated", - "script": "new script", - "scriptTimeout": "90s", - "enabled": False, - "description": "Updated description", - "parameters": [{"name": "p1"}], - }, - {"updateMask": "displayName,script,scriptTimeout,enabled,description"}, - ), - ): - result = update_integration_logical_operator( - chronicle_client, - integration_name="test-integration", - logical_operator_id="lo1", - display_name="Updated", - script="new script", - script_timeout="90s", - enabled=False, - description="Updated description", - parameters=[{"name": "p1"}], - ) - - assert result == expected - - -# -- execute_integration_logical_operator_test tests -- - - -def test_execute_integration_logical_operator_test_success(chronicle_client): - """Test execute_integration_logical_operator_test delegates to chronicle_request.""" - logical_operator = { - "displayName": "Test Operator", - "script": "def evaluate(a, b): return a == b", - } - expected = { - "outputMessage": "Success", - "debugOutputMessage": "Debug info", - "resultValue": True, - } - - with patch( - "secops.chronicle.integration.logical_operators.chronicle_request", - return_value=expected, - ) as mock_request, patch( - "secops.chronicle.integration.logical_operators.format_resource_id", - return_value="test-integration", - ): - result = execute_integration_logical_operator_test( - chronicle_client, - integration_name="test-integration", - logical_operator=logical_operator, - ) - - assert result == expected - - mock_request.assert_called_once_with( - chronicle_client, - method="POST", - endpoint_path="integrations/test-integration/logicalOperators:executeTest", - api_version=APIVersion.V1ALPHA, - json={"logicalOperator": logical_operator}, - ) - - -# -- get_integration_logical_operator_template tests -- - - -def test_get_integration_logical_operator_template_success(chronicle_client): - """Test get_integration_logical_operator_template delegates to chronicle_request.""" - expected = { - "script": "def evaluate(a, b):\n # Template code\n return True", - "displayName": "Template Operator", - } - - with patch( - "secops.chronicle.integration.logical_operators.chronicle_request", - return_value=expected, - ) as mock_request, patch( - "secops.chronicle.integration.logical_operators.format_resource_id", - return_value="test-integration", - ): - result = get_integration_logical_operator_template( - chronicle_client, - integration_name="test-integration", - ) - - assert result == expected - - mock_request.assert_called_once_with( - chronicle_client, - method="GET", - endpoint_path=( - "integrations/test-integration/logicalOperators:fetchTemplate" - ), - api_version=APIVersion.V1ALPHA, - ) - - -# -- Error handling tests -- - - -def test_list_integration_logical_operators_api_error(chronicle_client): - """Test list_integration_logical_operators handles API errors.""" - with patch( - "secops.chronicle.integration.logical_operators.chronicle_paginated_request", - side_effect=APIError("API Error"), - ): - with pytest.raises(APIError, match="API Error"): - list_integration_logical_operators( - chronicle_client, - integration_name="test-integration", - ) - - -def test_get_integration_logical_operator_api_error(chronicle_client): - """Test get_integration_logical_operator handles API errors.""" - with patch( - "secops.chronicle.integration.logical_operators.chronicle_request", - side_effect=APIError("Not found"), - ): - with pytest.raises(APIError, match="Not found"): - get_integration_logical_operator( - chronicle_client, - integration_name="test-integration", - logical_operator_id="nonexistent", - ) - - -def test_create_integration_logical_operator_api_error(chronicle_client): - """Test create_integration_logical_operator handles API errors.""" - with patch( - "secops.chronicle.integration.logical_operators.chronicle_request", - side_effect=APIError("Creation failed"), - ): - with pytest.raises(APIError, match="Creation failed"): - create_integration_logical_operator( - chronicle_client, - integration_name="test-integration", - display_name="New Operator", - script="def evaluate(a, b): return a == b", - script_timeout="60s", - enabled=True, - ) - - -def test_update_integration_logical_operator_api_error(chronicle_client): - """Test update_integration_logical_operator handles API errors.""" - with patch( - "secops.chronicle.integration.logical_operators.chronicle_request", - side_effect=APIError("Update failed"), - ), patch( - "secops.chronicle.integration.logical_operators.build_patch_body", - return_value=({"displayName": "Updated"}, {"updateMask": "displayName"}), - ): - with pytest.raises(APIError, match="Update failed"): - update_integration_logical_operator( - chronicle_client, - integration_name="test-integration", - logical_operator_id="lo1", - display_name="Updated", - ) - - -def test_delete_integration_logical_operator_api_error(chronicle_client): - """Test delete_integration_logical_operator handles API errors.""" - with patch( - "secops.chronicle.integration.logical_operators.chronicle_request", - side_effect=APIError("Delete failed"), - ): - with pytest.raises(APIError, match="Delete failed"): - delete_integration_logical_operator( - chronicle_client, - integration_name="test-integration", - logical_operator_id="lo1", - ) - diff --git a/tests/chronicle/integration/test_marketplace_integrations.py b/tests/chronicle/integration/test_marketplace_integrations.py deleted file mode 100644 index 15216fd9..00000000 --- a/tests/chronicle/integration/test_marketplace_integrations.py +++ /dev/null @@ -1,522 +0,0 @@ -# Copyright 2025 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. -# -"""Tests for Chronicle marketplace integration functions.""" - -from unittest.mock import Mock, patch - -import pytest - -from secops.chronicle.client import ChronicleClient -from secops.chronicle.models import APIVersion -from secops.chronicle.integration.marketplace_integrations import ( - list_marketplace_integrations, - get_marketplace_integration, - get_marketplace_integration_diff, - install_marketplace_integration, - uninstall_marketplace_integration, -) -from secops.exceptions import APIError - - -@pytest.fixture -def chronicle_client(): - """Create a Chronicle client for testing.""" - with patch("secops.auth.SecOpsAuth") as mock_auth: - mock_session = Mock() - mock_session.headers = {} - mock_auth.return_value.session = mock_session - return ChronicleClient( - customer_id="test-customer", - project_id="test-project", - default_api_version=APIVersion.V1BETA, - ) - - -@pytest.fixture -def mock_response() -> Mock: - """Create a mock API response object.""" - mock = Mock() - mock.status_code = 200 - mock.json.return_value = {} - return mock - - -@pytest.fixture -def mock_error_response() -> Mock: - """Create a mock error API response object.""" - mock = Mock() - mock.status_code = 400 - mock.text = "Error message" - mock.raise_for_status.side_effect = Exception("API Error") - return mock - - -# -- list_marketplace_integrations tests -- - - -def test_list_marketplace_integrations_success(chronicle_client): - """Test list_marketplace_integrations delegates to chronicle_paginated_request.""" - expected = { - "marketplaceIntegrations": [ - {"name": "integration1"}, - {"name": "integration2"}, - ] - } - - with patch( - "secops.chronicle.integration.marketplace_integrations.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated: - result = list_marketplace_integrations( - chronicle_client, - page_size=10, - page_token="next-token", - ) - - assert result == expected - - mock_paginated.assert_called_once_with( - chronicle_client, - api_version=APIVersion.V1BETA, - path="marketplaceIntegrations", - items_key="marketplaceIntegrations", - page_size=10, - page_token="next-token", - extra_params={}, - as_list=False, - ) - - -def test_list_marketplace_integrations_default_args(chronicle_client): - """Test list_marketplace_integrations with default args.""" - expected = {"marketplaceIntegrations": []} - - with patch( - "secops.chronicle.integration.marketplace_integrations.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated: - result = list_marketplace_integrations(chronicle_client) - - assert result == expected - - mock_paginated.assert_called_once_with( - chronicle_client, - api_version=APIVersion.V1BETA, - path="marketplaceIntegrations", - items_key="marketplaceIntegrations", - page_size=None, - page_token=None, - extra_params={}, - as_list=False, - ) - - -def test_list_marketplace_integrations_with_filter(chronicle_client): - """Test list_marketplace_integrations passes filter_string in extra_params.""" - expected = {"marketplaceIntegrations": [{"name": "integration1"}]} - - with patch( - "secops.chronicle.integration.marketplace_integrations.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated: - result = list_marketplace_integrations( - chronicle_client, - filter_string='displayName = "My Integration"', - ) - - assert result == expected - - mock_paginated.assert_called_once_with( - chronicle_client, - api_version=APIVersion.V1BETA, - path="marketplaceIntegrations", - items_key="marketplaceIntegrations", - page_size=None, - page_token=None, - extra_params={"filter": 'displayName = "My Integration"'}, - as_list=False, - ) - - -def test_list_marketplace_integrations_with_order_by(chronicle_client): - """Test list_marketplace_integrations passes order_by in extra_params.""" - expected = {"marketplaceIntegrations": []} - - with patch( - "secops.chronicle.integration.marketplace_integrations.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated: - result = list_marketplace_integrations( - chronicle_client, - order_by="displayName", - ) - - assert result == expected - - mock_paginated.assert_called_once_with( - chronicle_client, - api_version=APIVersion.V1BETA, - path="marketplaceIntegrations", - items_key="marketplaceIntegrations", - page_size=None, - page_token=None, - extra_params={"orderBy": "displayName"}, - as_list=False, - ) - - -def test_list_marketplace_integrations_with_filter_and_order_by(chronicle_client): - """Test list_marketplace_integrations with both filter_string and order_by.""" - expected = {"marketplaceIntegrations": []} - - with patch( - "secops.chronicle.integration.marketplace_integrations.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated: - result = list_marketplace_integrations( - chronicle_client, - filter_string='displayName = "My Integration"', - order_by="displayName", - ) - - assert result == expected - - mock_paginated.assert_called_once_with( - chronicle_client, - api_version=APIVersion.V1BETA, - path="marketplaceIntegrations", - items_key="marketplaceIntegrations", - page_size=None, - page_token=None, - extra_params={ - "filter": 'displayName = "My Integration"', - "orderBy": "displayName", - }, - as_list=False, - ) - - -def test_list_marketplace_integrations_as_list(chronicle_client): - """Test list_marketplace_integrations with as_list=True.""" - expected = [{"name": "integration1"}, {"name": "integration2"}] - - with patch( - "secops.chronicle.integration.marketplace_integrations.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated: - result = list_marketplace_integrations(chronicle_client, as_list=True) - - assert result == expected - - mock_paginated.assert_called_once_with( - chronicle_client, - api_version=APIVersion.V1BETA, - path="marketplaceIntegrations", - items_key="marketplaceIntegrations", - page_size=None, - page_token=None, - extra_params={}, - as_list=True, - ) - - -def test_list_marketplace_integrations_error(chronicle_client): - """Test list_marketplace_integrations propagates APIError from helper.""" - with patch( - "secops.chronicle.integration.marketplace_integrations.chronicle_paginated_request", - side_effect=APIError("Failed to list marketplace integrations"), - ): - with pytest.raises(APIError) as exc_info: - list_marketplace_integrations(chronicle_client) - - assert "Failed to list marketplace integrations" in str(exc_info.value) - - -# -- get_marketplace_integration tests -- - - -def test_get_marketplace_integration_success(chronicle_client): - """Test get_marketplace_integration returns expected result.""" - expected = { - "name": "test-integration", - "displayName": "Test Integration", - "version": "1.0.0", - } - - with patch( - "secops.chronicle.integration.marketplace_integrations.chronicle_request", - return_value=expected, - ) as mock_request: - result = get_marketplace_integration(chronicle_client, "test-integration") - - assert result == expected - - mock_request.assert_called_once_with( - chronicle_client, - method="GET", - endpoint_path="marketplaceIntegrations/test-integration", - api_version=APIVersion.V1BETA, - ) - - -def test_get_marketplace_integration_error(chronicle_client): - """Test get_marketplace_integration raises APIError on failure.""" - with patch( - "secops.chronicle.integration.marketplace_integrations.chronicle_request", - side_effect=APIError("Failed to get marketplace integration test-integration"), - ): - with pytest.raises(APIError) as exc_info: - get_marketplace_integration(chronicle_client, "test-integration") - - assert "Failed to get marketplace integration" in str(exc_info.value) - - -# -- get_marketplace_integration_diff tests -- - - -def test_get_marketplace_integration_diff_success(chronicle_client): - """Test get_marketplace_integration_diff returns expected result.""" - expected = { - "name": "test-integration", - "diff": {"added": [], "removed": [], "modified": []}, - } - - with patch( - "secops.chronicle.integration.marketplace_integrations.chronicle_request", - return_value=expected, - ) as mock_request: - result = get_marketplace_integration_diff(chronicle_client, "test-integration") - - assert result == expected - - mock_request.assert_called_once_with( - chronicle_client, - method="GET", - endpoint_path=( - "marketplaceIntegrations/test-integration" - ":fetchCommercialDiff" - ), - api_version=APIVersion.V1BETA, - ) - - -def test_get_marketplace_integration_diff_error(chronicle_client): - """Test get_marketplace_integration_diff raises APIError on failure.""" - with patch( - "secops.chronicle.integration.marketplace_integrations.chronicle_request", - side_effect=APIError("Failed to get marketplace integration diff"), - ): - with pytest.raises(APIError) as exc_info: - get_marketplace_integration_diff(chronicle_client, "test-integration") - - assert "Failed to get marketplace integration diff" in str(exc_info.value) - - -# -- install_marketplace_integration tests -- - - -def test_install_marketplace_integration_no_optional_fields(chronicle_client): - """Test install_marketplace_integration with no optional fields sends empty body.""" - expected = { - "name": "test-integration", - "displayName": "Test Integration", - "installedVersion": "1.0.0", - } - - with patch( - "secops.chronicle.integration.marketplace_integrations.chronicle_request", - return_value=expected, - ) as mock_request: - result = install_marketplace_integration( - chronicle_client, - integration_name="test-integration", - ) - - assert result == expected - - mock_request.assert_called_once_with( - chronicle_client, - method="POST", - endpoint_path="marketplaceIntegrations/test-integration:install", - json={}, - api_version=APIVersion.V1BETA, - ) - - -def test_install_marketplace_integration_all_fields(chronicle_client): - """Test install_marketplace_integration with all optional fields.""" - expected = { - "name": "test-integration", - "displayName": "Test Integration", - "installedVersion": "2.0.0", - } - - with patch( - "secops.chronicle.integration.marketplace_integrations.chronicle_request", - return_value=expected, - ) as mock_request: - result = install_marketplace_integration( - chronicle_client, - integration_name="test-integration", - override_mapping=True, - staging=False, - version="2.0.0", - restore_from_snapshot=True, - ) - - assert result == expected - - mock_request.assert_called_once_with( - chronicle_client, - method="POST", - endpoint_path="marketplaceIntegrations/test-integration:install", - json={ - "overrideMapping": True, - "staging": False, - "version": "2.0.0", - "restoreFromSnapshot": True, - }, - api_version=APIVersion.V1BETA, - ) - - -def test_install_marketplace_integration_override_mapping_only(chronicle_client): - """Test install_marketplace_integration with only override_mapping set.""" - expected = {"name": "test-integration"} - - with patch( - "secops.chronicle.integration.marketplace_integrations.chronicle_request", - return_value=expected, - ) as mock_request: - result = install_marketplace_integration( - chronicle_client, - integration_name="test-integration", - override_mapping=True, - ) - - assert result == expected - - mock_request.assert_called_once_with( - chronicle_client, - method="POST", - endpoint_path="marketplaceIntegrations/test-integration:install", - json={"overrideMapping": True}, - api_version=APIVersion.V1BETA, - ) - - -def test_install_marketplace_integration_version_only(chronicle_client): - """Test install_marketplace_integration with only version set.""" - expected = {"name": "test-integration"} - - with patch( - "secops.chronicle.integration.marketplace_integrations.chronicle_request", - return_value=expected, - ) as mock_request: - result = install_marketplace_integration( - chronicle_client, - integration_name="test-integration", - version="1.2.3", - ) - - assert result == expected - - mock_request.assert_called_once_with( - chronicle_client, - method="POST", - endpoint_path="marketplaceIntegrations/test-integration:install", - json={"version": "1.2.3"}, - api_version=APIVersion.V1BETA, - ) - - -def test_install_marketplace_integration_none_fields_excluded(chronicle_client): - """Test that None optional fields are not included in the request body.""" - with patch( - "secops.chronicle.integration.marketplace_integrations.chronicle_request", - return_value={"name": "test-integration"}, - ) as mock_request: - install_marketplace_integration( - chronicle_client, - integration_name="test-integration", - override_mapping=None, - staging=None, - version=None, - restore_from_snapshot=None, - ) - - mock_request.assert_called_once_with( - chronicle_client, - method="POST", - endpoint_path="marketplaceIntegrations/test-integration:install", - json={}, - api_version=APIVersion.V1BETA, - ) - - -def test_install_marketplace_integration_error(chronicle_client): - """Test install_marketplace_integration raises APIError on failure.""" - with patch( - "secops.chronicle.integration.marketplace_integrations.chronicle_request", - side_effect=APIError("Failed to install marketplace integration"), - ): - with pytest.raises(APIError) as exc_info: - install_marketplace_integration( - chronicle_client, - integration_name="test-integration", - ) - - assert "Failed to install marketplace integration" in str(exc_info.value) - - -# -- uninstall_marketplace_integration tests -- - - -def test_uninstall_marketplace_integration_success(chronicle_client): - """Test uninstall_marketplace_integration returns expected result.""" - expected = {} - - with patch( - "secops.chronicle.integration.marketplace_integrations.chronicle_request", - return_value=expected, - ) as mock_request: - result = uninstall_marketplace_integration( - chronicle_client, - integration_name="test-integration", - ) - - assert result == expected - - mock_request.assert_called_once_with( - chronicle_client, - method="POST", - endpoint_path="marketplaceIntegrations/test-integration:uninstall", - api_version=APIVersion.V1BETA, - ) - - -def test_uninstall_marketplace_integration_error(chronicle_client): - """Test uninstall_marketplace_integration raises APIError on failure.""" - with patch( - "secops.chronicle.integration.marketplace_integrations.chronicle_request", - side_effect=APIError("Failed to uninstall marketplace integration"), - ): - with pytest.raises(APIError) as exc_info: - uninstall_marketplace_integration( - chronicle_client, - integration_name="test-integration", - ) - - assert "Failed to uninstall marketplace integration" in str(exc_info.value) \ No newline at end of file diff --git a/tests/chronicle/integration/test_transformer_revisions.py b/tests/chronicle/integration/test_transformer_revisions.py deleted file mode 100644 index 8107891e..00000000 --- a/tests/chronicle/integration/test_transformer_revisions.py +++ /dev/null @@ -1,366 +0,0 @@ -# Copyright 2025 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. -# -"""Tests for Chronicle integration transformer revisions functions.""" - -from unittest.mock import Mock, patch - -import pytest - -from secops.chronicle.client import ChronicleClient -from secops.chronicle.models import APIVersion -from secops.chronicle.integration.transformer_revisions import ( - list_integration_transformer_revisions, - delete_integration_transformer_revision, - create_integration_transformer_revision, - rollback_integration_transformer_revision, -) -from secops.exceptions import APIError - - -@pytest.fixture -def chronicle_client(): - """Create a Chronicle client for testing.""" - with patch("secops.auth.SecOpsAuth") as mock_auth: - mock_session = Mock() - mock_session.headers = {} - mock_auth.return_value.session = mock_session - return ChronicleClient( - customer_id="test-customer", - project_id="test-project", - default_api_version=APIVersion.V1ALPHA, - ) - - -# -- list_integration_transformer_revisions tests -- - - -def test_list_integration_transformer_revisions_success(chronicle_client): - """Test list_integration_transformer_revisions delegates to paginated request.""" - expected = { - "revisions": [{"name": "r1"}, {"name": "r2"}], - "nextPageToken": "token", - } - - with patch( - "secops.chronicle.integration.transformer_revisions.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated, patch( - "secops.chronicle.integration.transformer_revisions.format_resource_id", - return_value="My Integration", - ): - result = list_integration_transformer_revisions( - chronicle_client, - integration_name="My Integration", - transformer_id="t1", - page_size=10, - page_token="next-token", - ) - - assert result == expected - - mock_paginated.assert_called_once_with( - chronicle_client, - api_version=APIVersion.V1ALPHA, - path="integrations/My Integration/transformers/t1/revisions", - items_key="revisions", - page_size=10, - page_token="next-token", - extra_params={}, - as_list=False, - ) - - -def test_list_integration_transformer_revisions_default_args(chronicle_client): - """Test list_integration_transformer_revisions with default args.""" - expected = {"revisions": []} - - with patch( - "secops.chronicle.integration.transformer_revisions.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated: - result = list_integration_transformer_revisions( - chronicle_client, - integration_name="test-integration", - transformer_id="t1", - ) - - assert result == expected - - mock_paginated.assert_called_once_with( - chronicle_client, - api_version=APIVersion.V1ALPHA, - path="integrations/test-integration/transformers/t1/revisions", - items_key="revisions", - page_size=None, - page_token=None, - extra_params={}, - as_list=False, - ) - - -def test_list_integration_transformer_revisions_with_filter_order( - chronicle_client, -): - """Test list passes filter/orderBy in extra_params.""" - expected = {"revisions": [{"name": "r1"}]} - - with patch( - "secops.chronicle.integration.transformer_revisions.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated: - result = list_integration_transformer_revisions( - chronicle_client, - integration_name="test-integration", - transformer_id="t1", - filter_string='version = "1.0"', - order_by="createTime desc", - ) - - assert result == expected - - mock_paginated.assert_called_once_with( - chronicle_client, - api_version=APIVersion.V1ALPHA, - path="integrations/test-integration/transformers/t1/revisions", - items_key="revisions", - page_size=None, - page_token=None, - extra_params={ - "filter": 'version = "1.0"', - "orderBy": "createTime desc", - }, - as_list=False, - ) - - -def test_list_integration_transformer_revisions_as_list(chronicle_client): - """Test list_integration_transformer_revisions with as_list=True.""" - expected = [{"name": "r1"}, {"name": "r2"}] - - with patch( - "secops.chronicle.integration.transformer_revisions.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated: - result = list_integration_transformer_revisions( - chronicle_client, - integration_name="test-integration", - transformer_id="t1", - as_list=True, - ) - - assert result == expected - - mock_paginated.assert_called_once_with( - chronicle_client, - api_version=APIVersion.V1ALPHA, - path="integrations/test-integration/transformers/t1/revisions", - items_key="revisions", - page_size=None, - page_token=None, - extra_params={}, - as_list=True, - ) - - -# -- delete_integration_transformer_revision tests -- - - -def test_delete_integration_transformer_revision_success(chronicle_client): - """Test delete_integration_transformer_revision delegates to chronicle_request.""" - with patch( - "secops.chronicle.integration.transformer_revisions.chronicle_request", - return_value=None, - ) as mock_request, patch( - "secops.chronicle.integration.transformer_revisions.format_resource_id", - return_value="test-integration", - ): - delete_integration_transformer_revision( - chronicle_client, - integration_name="test-integration", - transformer_id="t1", - revision_id="rev1", - ) - - mock_request.assert_called_once_with( - chronicle_client, - method="DELETE", - endpoint_path=( - "integrations/test-integration/transformers/t1/revisions/rev1" - ), - api_version=APIVersion.V1ALPHA, - ) - - -# -- create_integration_transformer_revision tests -- - - -def test_create_integration_transformer_revision_minimal(chronicle_client): - """Test create_integration_transformer_revision with minimal fields.""" - transformer = { - "displayName": "Test Transformer", - "script": "def transform(data): return data", - } - expected = {"name": "rev1", "comment": ""} - - with patch( - "secops.chronicle.integration.transformer_revisions.chronicle_request", - return_value=expected, - ) as mock_request, patch( - "secops.chronicle.integration.transformer_revisions.format_resource_id", - return_value="test-integration", - ): - result = create_integration_transformer_revision( - chronicle_client, - integration_name="test-integration", - transformer_id="t1", - transformer=transformer, - ) - - assert result == expected - - mock_request.assert_called_once_with( - chronicle_client, - method="POST", - endpoint_path=( - "integrations/test-integration/transformers/t1/revisions" - ), - api_version=APIVersion.V1ALPHA, - json={"transformer": transformer}, - ) - - -def test_create_integration_transformer_revision_with_comment(chronicle_client): - """Test create_integration_transformer_revision with comment.""" - transformer = { - "displayName": "Test Transformer", - "script": "def transform(data): return data", - } - expected = {"name": "rev1", "comment": "Version 2.0"} - - with patch( - "secops.chronicle.integration.transformer_revisions.chronicle_request", - return_value=expected, - ) as mock_request: - result = create_integration_transformer_revision( - chronicle_client, - integration_name="test-integration", - transformer_id="t1", - transformer=transformer, - comment="Version 2.0", - ) - - assert result == expected - - call_kwargs = mock_request.call_args[1] - assert call_kwargs["json"]["transformer"] == transformer - assert call_kwargs["json"]["comment"] == "Version 2.0" - - -# -- rollback_integration_transformer_revision tests -- - - -def test_rollback_integration_transformer_revision_success(chronicle_client): - """Test rollback_integration_transformer_revision delegates to chronicle_request.""" - expected = {"name": "rev1", "comment": "Rolled back"} - - with patch( - "secops.chronicle.integration.transformer_revisions.chronicle_request", - return_value=expected, - ) as mock_request, patch( - "secops.chronicle.integration.transformer_revisions.format_resource_id", - return_value="test-integration", - ): - result = rollback_integration_transformer_revision( - chronicle_client, - integration_name="test-integration", - transformer_id="t1", - revision_id="rev1", - ) - - assert result == expected - - mock_request.assert_called_once_with( - chronicle_client, - method="POST", - endpoint_path=( - "integrations/test-integration/transformers/t1/revisions/rev1:rollback" - ), - api_version=APIVersion.V1ALPHA, - ) - - -# -- Error handling tests -- - - -def test_list_integration_transformer_revisions_api_error(chronicle_client): - """Test list_integration_transformer_revisions handles API errors.""" - with patch( - "secops.chronicle.integration.transformer_revisions.chronicle_paginated_request", - side_effect=APIError("API Error"), - ): - with pytest.raises(APIError, match="API Error"): - list_integration_transformer_revisions( - chronicle_client, - integration_name="test-integration", - transformer_id="t1", - ) - - -def test_delete_integration_transformer_revision_api_error(chronicle_client): - """Test delete_integration_transformer_revision handles API errors.""" - with patch( - "secops.chronicle.integration.transformer_revisions.chronicle_request", - side_effect=APIError("Delete failed"), - ): - with pytest.raises(APIError, match="Delete failed"): - delete_integration_transformer_revision( - chronicle_client, - integration_name="test-integration", - transformer_id="t1", - revision_id="rev1", - ) - - -def test_create_integration_transformer_revision_api_error(chronicle_client): - """Test create_integration_transformer_revision handles API errors.""" - transformer = {"displayName": "Test"} - - with patch( - "secops.chronicle.integration.transformer_revisions.chronicle_request", - side_effect=APIError("Creation failed"), - ): - with pytest.raises(APIError, match="Creation failed"): - create_integration_transformer_revision( - chronicle_client, - integration_name="test-integration", - transformer_id="t1", - transformer=transformer, - ) - - -def test_rollback_integration_transformer_revision_api_error(chronicle_client): - """Test rollback_integration_transformer_revision handles API errors.""" - with patch( - "secops.chronicle.integration.transformer_revisions.chronicle_request", - side_effect=APIError("Rollback failed"), - ): - with pytest.raises(APIError, match="Rollback failed"): - rollback_integration_transformer_revision( - chronicle_client, - integration_name="test-integration", - transformer_id="t1", - revision_id="rev1", - ) - diff --git a/tests/chronicle/integration/test_transformers.py b/tests/chronicle/integration/test_transformers.py deleted file mode 100644 index 43d8687e..00000000 --- a/tests/chronicle/integration/test_transformers.py +++ /dev/null @@ -1,555 +0,0 @@ -# Copyright 2025 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. -# -"""Tests for Chronicle integration transformers functions.""" - -from unittest.mock import Mock, patch - -import pytest - -from secops.chronicle.client import ChronicleClient -from secops.chronicle.models import APIVersion -from secops.chronicle.integration.transformers import ( - list_integration_transformers, - get_integration_transformer, - delete_integration_transformer, - create_integration_transformer, - update_integration_transformer, - execute_integration_transformer_test, - get_integration_transformer_template, -) -from secops.exceptions import APIError - - -@pytest.fixture -def chronicle_client(): - """Create a Chronicle client for testing.""" - with patch("secops.auth.SecOpsAuth") as mock_auth: - mock_session = Mock() - mock_session.headers = {} - mock_auth.return_value.session = mock_session - return ChronicleClient( - customer_id="test-customer", - project_id="test-project", - default_api_version=APIVersion.V1ALPHA, - ) - - -# -- list_integration_transformers tests -- - - -def test_list_integration_transformers_success(chronicle_client): - """Test list_integration_transformers delegates to chronicle_paginated_request.""" - expected = { - "transformers": [{"name": "t1"}, {"name": "t2"}], - "nextPageToken": "token", - } - - with patch( - "secops.chronicle.integration.transformers.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated, patch( - "secops.chronicle.integration.transformers.format_resource_id", - return_value="My Integration", - ): - result = list_integration_transformers( - chronicle_client, - integration_name="My Integration", - page_size=10, - page_token="next-token", - ) - - assert result == expected - - mock_paginated.assert_called_once_with( - chronicle_client, - api_version=APIVersion.V1ALPHA, - path="integrations/My Integration/transformers", - items_key="transformers", - page_size=10, - page_token="next-token", - extra_params={}, - as_list=False, - ) - - -def test_list_integration_transformers_default_args(chronicle_client): - """Test list_integration_transformers with default args.""" - expected = {"transformers": []} - - with patch( - "secops.chronicle.integration.transformers.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated: - result = list_integration_transformers( - chronicle_client, - integration_name="test-integration", - ) - - assert result == expected - - mock_paginated.assert_called_once_with( - chronicle_client, - api_version=APIVersion.V1ALPHA, - path="integrations/test-integration/transformers", - items_key="transformers", - page_size=None, - page_token=None, - extra_params={}, - as_list=False, - ) - - -def test_list_integration_transformers_with_filter_order_expand(chronicle_client): - """Test list passes filter/orderBy/excludeStaging/expand in extra_params.""" - expected = {"transformers": [{"name": "t1"}]} - - with patch( - "secops.chronicle.integration.transformers.chronicle_paginated_request", - return_value=expected, - ) as mock_paginated: - result = list_integration_transformers( - chronicle_client, - integration_name="test-integration", - filter_string='displayName = "My Transformer"', - order_by="displayName", - exclude_staging=True, - expand="parameters", - ) - - assert result == expected - - mock_paginated.assert_called_once_with( - chronicle_client, - api_version=APIVersion.V1ALPHA, - path="integrations/test-integration/transformers", - items_key="transformers", - page_size=None, - page_token=None, - extra_params={ - "filter": 'displayName = "My Transformer"', - "orderBy": "displayName", - "excludeStaging": True, - "expand": "parameters", - }, - as_list=False, - ) - - -# -- get_integration_transformer tests -- - - -def test_get_integration_transformer_success(chronicle_client): - """Test get_integration_transformer delegates to chronicle_request.""" - expected = {"name": "transformer1", "displayName": "My Transformer"} - - with patch( - "secops.chronicle.integration.transformers.chronicle_request", - return_value=expected, - ) as mock_request, patch( - "secops.chronicle.integration.transformers.format_resource_id", - return_value="test-integration", - ): - result = get_integration_transformer( - chronicle_client, - integration_name="test-integration", - transformer_id="transformer1", - ) - - assert result == expected - - mock_request.assert_called_once_with( - chronicle_client, - method="GET", - endpoint_path="integrations/test-integration/transformers/transformer1", - api_version=APIVersion.V1ALPHA, - params=None, - ) - - -def test_get_integration_transformer_with_expand(chronicle_client): - """Test get_integration_transformer with expand parameter.""" - expected = {"name": "transformer1"} - - with patch( - "secops.chronicle.integration.transformers.chronicle_request", - return_value=expected, - ) as mock_request: - result = get_integration_transformer( - chronicle_client, - integration_name="test-integration", - transformer_id="transformer1", - expand="parameters", - ) - - assert result == expected - - mock_request.assert_called_once_with( - chronicle_client, - method="GET", - endpoint_path="integrations/test-integration/transformers/transformer1", - api_version=APIVersion.V1ALPHA, - params={"expand": "parameters"}, - ) - - -# -- delete_integration_transformer tests -- - - -def test_delete_integration_transformer_success(chronicle_client): - """Test delete_integration_transformer delegates to chronicle_request.""" - with patch( - "secops.chronicle.integration.transformers.chronicle_request", - return_value=None, - ) as mock_request, patch( - "secops.chronicle.integration.transformers.format_resource_id", - return_value="test-integration", - ): - delete_integration_transformer( - chronicle_client, - integration_name="test-integration", - transformer_id="transformer1", - ) - - mock_request.assert_called_once_with( - chronicle_client, - method="DELETE", - endpoint_path="integrations/test-integration/transformers/transformer1", - api_version=APIVersion.V1ALPHA, - ) - - -# -- create_integration_transformer tests -- - - -def test_create_integration_transformer_minimal(chronicle_client): - """Test create_integration_transformer with minimal required fields.""" - expected = {"name": "transformer1", "displayName": "New Transformer"} - - with patch( - "secops.chronicle.integration.transformers.chronicle_request", - return_value=expected, - ) as mock_request, patch( - "secops.chronicle.integration.transformers.format_resource_id", - return_value="test-integration", - ): - result = create_integration_transformer( - chronicle_client, - integration_name="test-integration", - display_name="New Transformer", - script="def transform(data): return data", - script_timeout="60s", - enabled=True, - ) - - assert result == expected - - mock_request.assert_called_once() - call_kwargs = mock_request.call_args[1] - assert call_kwargs["method"] == "POST" - assert ( - call_kwargs["endpoint_path"] - == "integrations/test-integration/transformers" - ) - assert call_kwargs["api_version"] == APIVersion.V1ALPHA - assert call_kwargs["json"]["displayName"] == "New Transformer" - assert call_kwargs["json"]["script"] == "def transform(data): return data" - assert call_kwargs["json"]["scriptTimeout"] == "60s" - assert call_kwargs["json"]["enabled"] is True - - -def test_create_integration_transformer_with_all_fields(chronicle_client): - """Test create_integration_transformer with all optional fields.""" - expected = {"name": "transformer1"} - - with patch( - "secops.chronicle.integration.transformers.chronicle_request", - return_value=expected, - ) as mock_request: - result = create_integration_transformer( - chronicle_client, - integration_name="test-integration", - display_name="Full Transformer", - script="def transform(data): return data", - script_timeout="120s", - enabled=False, - description="Test transformer description", - parameters=[{"name": "param1", "type": "STRING"}], - usage_example="Example usage", - expected_output="Output format", - expected_input="Input format", - ) - - assert result == expected - - call_kwargs = mock_request.call_args[1] - body = call_kwargs["json"] - assert body["displayName"] == "Full Transformer" - assert body["description"] == "Test transformer description" - assert body["parameters"] == [{"name": "param1", "type": "STRING"}] - assert body["usageExample"] == "Example usage" - assert body["expectedOutput"] == "Output format" - assert body["expectedInput"] == "Input format" - - -# -- update_integration_transformer tests -- - - -def test_update_integration_transformer_display_name(chronicle_client): - """Test update_integration_transformer updates display name.""" - expected = {"name": "transformer1", "displayName": "Updated Name"} - - with patch( - "secops.chronicle.integration.transformers.chronicle_request", - return_value=expected, - ) as mock_request, patch( - "secops.chronicle.integration.transformers.build_patch_body", - return_value=({"displayName": "Updated Name"}, {"updateMask": "displayName"}), - ) as mock_build: - result = update_integration_transformer( - chronicle_client, - integration_name="test-integration", - transformer_id="transformer1", - display_name="Updated Name", - ) - - assert result == expected - - mock_build.assert_called_once() - mock_request.assert_called_once() - call_kwargs = mock_request.call_args[1] - assert call_kwargs["method"] == "PATCH" - assert ( - call_kwargs["endpoint_path"] - == "integrations/test-integration/transformers/transformer1" - ) - - -def test_update_integration_transformer_with_update_mask(chronicle_client): - """Test update_integration_transformer with explicit update mask.""" - expected = {"name": "transformer1"} - - with patch( - "secops.chronicle.integration.transformers.chronicle_request", - return_value=expected, - ) as mock_request, patch( - "secops.chronicle.integration.transformers.build_patch_body", - return_value=( - {"displayName": "New Name", "enabled": True}, - {"updateMask": "displayName,enabled"}, - ), - ): - result = update_integration_transformer( - chronicle_client, - integration_name="test-integration", - transformer_id="transformer1", - display_name="New Name", - enabled=True, - update_mask="displayName,enabled", - ) - - assert result == expected - - -def test_update_integration_transformer_all_fields(chronicle_client): - """Test update_integration_transformer with all fields.""" - expected = {"name": "transformer1"} - - with patch( - "secops.chronicle.integration.transformers.chronicle_request", - return_value=expected, - ) as mock_request, patch( - "secops.chronicle.integration.transformers.build_patch_body", - return_value=( - { - "displayName": "Updated", - "script": "new script", - "scriptTimeout": "90s", - "enabled": False, - "description": "Updated description", - "parameters": [{"name": "p1"}], - "usageExample": "New example", - "expectedOutput": "New output", - "expectedInput": "New input", - }, - {"updateMask": "displayName,script,scriptTimeout,enabled,description"}, - ), - ): - result = update_integration_transformer( - chronicle_client, - integration_name="test-integration", - transformer_id="transformer1", - display_name="Updated", - script="new script", - script_timeout="90s", - enabled=False, - description="Updated description", - parameters=[{"name": "p1"}], - usage_example="New example", - expected_output="New output", - expected_input="New input", - ) - - assert result == expected - - -# -- execute_integration_transformer_test tests -- - - -def test_execute_integration_transformer_test_success(chronicle_client): - """Test execute_integration_transformer_test delegates to chronicle_request.""" - transformer = { - "displayName": "Test Transformer", - "script": "def transform(data): return data", - } - expected = { - "outputMessage": "Success", - "debugOutputMessage": "Debug info", - "resultValue": {"status": "ok"}, - } - - with patch( - "secops.chronicle.integration.transformers.chronicle_request", - return_value=expected, - ) as mock_request, patch( - "secops.chronicle.integration.transformers.format_resource_id", - return_value="test-integration", - ): - result = execute_integration_transformer_test( - chronicle_client, - integration_name="test-integration", - transformer=transformer, - ) - - assert result == expected - - mock_request.assert_called_once_with( - chronicle_client, - method="POST", - endpoint_path="integrations/test-integration/transformers:executeTest", - api_version=APIVersion.V1ALPHA, - json={"transformer": transformer}, - ) - - -# -- get_integration_transformer_template tests -- - - -def test_get_integration_transformer_template_success(chronicle_client): - """Test get_integration_transformer_template delegates to chronicle_request.""" - expected = { - "script": "def transform(data):\n # Template code\n return data", - "displayName": "Template Transformer", - } - - with patch( - "secops.chronicle.integration.transformers.chronicle_request", - return_value=expected, - ) as mock_request, patch( - "secops.chronicle.integration.transformers.format_resource_id", - return_value="test-integration", - ): - result = get_integration_transformer_template( - chronicle_client, - integration_name="test-integration", - ) - - assert result == expected - - mock_request.assert_called_once_with( - chronicle_client, - method="GET", - endpoint_path="integrations/test-integration/transformers:fetchTemplate", - api_version=APIVersion.V1ALPHA, - ) - - -# -- Error handling tests -- - - -def test_list_integration_transformers_api_error(chronicle_client): - """Test list_integration_transformers handles API errors.""" - with patch( - "secops.chronicle.integration.transformers.chronicle_paginated_request", - side_effect=APIError("API Error"), - ): - with pytest.raises(APIError, match="API Error"): - list_integration_transformers( - chronicle_client, - integration_name="test-integration", - ) - - -def test_get_integration_transformer_api_error(chronicle_client): - """Test get_integration_transformer handles API errors.""" - with patch( - "secops.chronicle.integration.transformers.chronicle_request", - side_effect=APIError("Not found"), - ): - with pytest.raises(APIError, match="Not found"): - get_integration_transformer( - chronicle_client, - integration_name="test-integration", - transformer_id="nonexistent", - ) - - -def test_create_integration_transformer_api_error(chronicle_client): - """Test create_integration_transformer handles API errors.""" - with patch( - "secops.chronicle.integration.transformers.chronicle_request", - side_effect=APIError("Creation failed"), - ): - with pytest.raises(APIError, match="Creation failed"): - create_integration_transformer( - chronicle_client, - integration_name="test-integration", - display_name="New Transformer", - script="def transform(data): return data", - script_timeout="60s", - enabled=True, - ) - - -def test_update_integration_transformer_api_error(chronicle_client): - """Test update_integration_transformer handles API errors.""" - with patch( - "secops.chronicle.integration.transformers.chronicle_request", - side_effect=APIError("Update failed"), - ), patch( - "secops.chronicle.integration.transformers.build_patch_body", - return_value=({"displayName": "Updated"}, {"updateMask": "displayName"}), - ): - with pytest.raises(APIError, match="Update failed"): - update_integration_transformer( - chronicle_client, - integration_name="test-integration", - transformer_id="transformer1", - display_name="Updated", - ) - - -def test_delete_integration_transformer_api_error(chronicle_client): - """Test delete_integration_transformer handles API errors.""" - with patch( - "secops.chronicle.integration.transformers.chronicle_request", - side_effect=APIError("Delete failed"), - ): - with pytest.raises(APIError, match="Delete failed"): - delete_integration_transformer( - chronicle_client, - integration_name="test-integration", - transformer_id="transformer1", - ) - From 3604a1842b3114cf03695cf2c20b0e0f8673e2e9 Mon Sep 17 00:00:00 2001 From: PaperMtn Date: Thu, 9 Apr 2026 20:56:43 +0100 Subject: [PATCH 3/8] feat: refactor to use SOAR service --- src/secops/chronicle/__init__.py | 58 -- src/secops/chronicle/client.py | 983 ------------------ src/secops/chronicle/soar/__init__.py | 58 ++ .../integration/action_revisions.py | 0 .../{ => soar}/integration/actions.py | 0 .../integration/manager_revisions.py | 0 .../{ => soar}/integration/managers.py | 0 src/secops/chronicle/soar/service.py | 977 +++++++++++++++++ tests/chronicle/soar/integration/__init__.py | 0 .../integration/test_action_revisions.py | 36 +- .../{ => soar}/integration/test_actions.py | 50 +- .../integration/test_manager_revisions.py | 36 +- .../{ => soar}/integration/test_managers.py | 48 +- 13 files changed, 1120 insertions(+), 1126 deletions(-) rename src/secops/chronicle/{ => soar}/integration/action_revisions.py (100%) rename src/secops/chronicle/{ => soar}/integration/actions.py (100%) rename src/secops/chronicle/{ => soar}/integration/manager_revisions.py (100%) rename src/secops/chronicle/{ => soar}/integration/managers.py (100%) create mode 100644 tests/chronicle/soar/integration/__init__.py rename tests/chronicle/{ => soar}/integration/test_action_revisions.py (89%) rename tests/chronicle/{ => soar}/integration/test_actions.py (92%) rename tests/chronicle/{ => soar}/integration/test_manager_revisions.py (89%) rename tests/chronicle/{ => soar}/integration/test_managers.py (88%) diff --git a/src/secops/chronicle/__init__.py b/src/secops/chronicle/__init__.py index 2ab3fe8c..76d4150f 100644 --- a/src/secops/chronicle/__init__.py +++ b/src/secops/chronicle/__init__.py @@ -227,37 +227,6 @@ create_watchlist, update_watchlist, ) -from secops.chronicle.integration.actions import ( - list_integration_actions, - get_integration_action, - delete_integration_action, - create_integration_action, - update_integration_action, - execute_integration_action_test, - get_integration_actions_by_environment, - get_integration_action_template, -) -from secops.chronicle.integration.action_revisions import ( - list_integration_action_revisions, - delete_integration_action_revision, - create_integration_action_revision, - rollback_integration_action_revision, -) -from secops.chronicle.integration.managers import ( - list_integration_managers, - get_integration_manager, - delete_integration_manager, - create_integration_manager, - update_integration_manager, - get_integration_manager_template, -) -from secops.chronicle.integration.manager_revisions import ( - list_integration_manager_revisions, - get_integration_manager_revision, - delete_integration_manager_revision, - create_integration_manager_revision, - rollback_integration_manager_revision, -) __all__ = [ # Client @@ -449,31 +418,4 @@ "delete_watchlist", "create_watchlist", "update_watchlist", - # Integration Actions - "list_integration_actions", - "get_integration_action", - "delete_integration_action", - "create_integration_action", - "update_integration_action", - "execute_integration_action_test", - "get_integration_actions_by_environment", - "get_integration_action_template", - # Integration Action Revisions - "list_integration_action_revisions", - "delete_integration_action_revision", - "create_integration_action_revision", - "rollback_integration_action_revision", - # Integration Managers - "list_integration_managers", - "get_integration_manager", - "delete_integration_manager", - "create_integration_manager", - "update_integration_manager", - "get_integration_manager_template", - # Integration Manager Revisions - "list_integration_manager_revisions", - "get_integration_manager_revision", - "delete_integration_manager_revision", - "create_integration_manager_revision", - "rollback_integration_manager_revision", ] diff --git a/src/secops/chronicle/client.py b/src/secops/chronicle/client.py index e0478474..8b758c07 100644 --- a/src/secops/chronicle/client.py +++ b/src/secops/chronicle/client.py @@ -135,13 +135,6 @@ from secops.chronicle.log_ingest import ingest_udm as _ingest_udm from secops.chronicle.log_ingest import list_forwarders as _list_forwarders from secops.chronicle.log_ingest import update_forwarder as _update_forwarder -from secops.chronicle.log_types import classify_logs as _classify_logs -from secops.chronicle.log_types import get_all_log_types as _get_all_log_types -from secops.chronicle.log_types import ( - get_log_type_description as _get_log_type_description, -) -from secops.chronicle.log_types import is_valid_log_type as _is_valid_log_type -from secops.chronicle.log_types import search_log_types as _search_log_types from secops.chronicle.log_processing_pipelines import ( associate_streams as _associate_streams, ) @@ -176,37 +169,6 @@ is_valid_log_type as _is_valid_log_type, search_log_types as _search_log_types, ) -from secops.chronicle.integration.actions import ( - create_integration_action as _create_integration_action, - delete_integration_action as _delete_integration_action, - execute_integration_action_test as _execute_integration_action_test, - get_integration_action as _get_integration_action, - get_integration_action_template as _get_integration_action_template, - get_integration_actions_by_environment as _get_integration_actions_by_environment, - list_integration_actions as _list_integration_actions, - update_integration_action as _update_integration_action, -) -from secops.chronicle.integration.action_revisions import ( - create_integration_action_revision as _create_integration_action_revision, - delete_integration_action_revision as _delete_integration_action_revision, - list_integration_action_revisions as _list_integration_action_revisions, - rollback_integration_action_revision as _rollback_integration_action_revision, -) -from secops.chronicle.integration.managers import ( - create_integration_manager as _create_integration_manager, - delete_integration_manager as _delete_integration_manager, - get_integration_manager as _get_integration_manager, - get_integration_manager_template as _get_integration_manager_template, - list_integration_managers as _list_integration_managers, - update_integration_manager as _update_integration_manager, -) -from secops.chronicle.integration.manager_revisions import ( - create_integration_manager_revision as _create_integration_manager_revision, - delete_integration_manager_revision as _delete_integration_manager_revision, - get_integration_manager_revision as _get_integration_manager_revision, - list_integration_manager_revisions as _list_integration_manager_revisions, - rollback_integration_manager_revision as _rollback_integration_manager_revision, -) from secops.chronicle.log_processing_pipelines import ( test_pipeline as _test_pipeline, ) @@ -825,951 +787,6 @@ def update_watchlist( update_mask, ) - # ------------------------------------------------------------------------- - # Integration Action methods - # ------------------------------------------------------------------------- - - def list_integration_actions( - self, - integration_name: str, - page_size: int | None = None, - page_token: str | None = None, - filter_string: str | None = None, - order_by: str | None = None, - expand: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - as_list: bool = False, - ) -> dict[str, Any] | list[dict[str, Any]]: - """Get a list of actions for a given integration. - - Args: - integration_name: Name of the integration to get actions for - page_size: Number of results to return per page - page_token: Token for the page to retrieve - filter_string: Filter expression to filter actions - order_by: Field to sort the actions by - expand: Comma-separated list of fields to expand in the response - api_version: API version to use for the request. Default is V1BETA. - as_list: If True, return a list of actions instead of a dict with - actions list and nextPageToken. - - Returns: - If as_list is True: List of actions. - If as_list is False: Dict with actions list and nextPageToken. - - Raises: - APIError: If the API request fails - """ - return _list_integration_actions( - self, - integration_name, - page_size=page_size, - page_token=page_token, - filter_string=filter_string, - order_by=order_by, - expand=expand, - api_version=api_version, - as_list=as_list, - ) - - def get_integration_action( - self, - integration_name: str, - action_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Get details of a specific action for a given integration. - - Args: - integration_name: Name of the integration the action belongs to - action_id: ID of the action to retrieve - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing details of the specified action. - - Raises: - APIError: If the API request fails - """ - return _get_integration_action( - self, - integration_name, - action_id, - api_version=api_version, - ) - - def delete_integration_action( - self, - integration_name: str, - action_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> None: - """Delete a specific action from a given integration. - - Args: - integration_name: Name of the integration the action belongs to - action_id: ID of the action to delete - api_version: API version to use for the request. Default is V1BETA. - - Returns: - None - - Raises: - APIError: If the API request fails - """ - return _delete_integration_action( - self, - integration_name, - action_id, - api_version=api_version, - ) - - def create_integration_action( - self, - integration_name: str, - display_name: str, - script: str, - timeout_seconds: int, - enabled: bool, - script_result_name: str, - is_async: bool, - description: str | None = None, - default_result_value: str | None = None, - async_polling_interval_seconds: int | None = None, - async_total_timeout_seconds: int | None = None, - dynamic_results: list[dict[str, Any]] | None = None, - parameters: list[dict[str, Any]] | None = None, - ai_generated: bool | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Create a new custom action for a given integration. - - Args: - integration_name: Name of the integration to - create the action for. - display_name: Action's display name. - Maximum 150 characters. Required. - script: Action's Python script. Maximum size 5MB. Required. - timeout_seconds: Action timeout in seconds. Maximum 1200. Required. - enabled: Whether the action is enabled or disabled. Required. - script_result_name: Field name that holds the script result. - Maximum 100 characters. Required. - is_async: Whether the action is asynchronous. Required. - description: Action's description. Maximum 400 characters. Optional. - default_result_value: Action's default result value. - Maximum 1000 characters. Optional. - async_polling_interval_seconds: Polling interval - in seconds for async actions. - Cannot exceed total timeout. Optional. - async_total_timeout_seconds: Total async timeout in seconds. Maximum - 1209600 (14 days). Optional. - dynamic_results: List of dynamic result metadata dicts. - Max 50. Optional. - parameters: List of action parameter dicts. Max 50. Optional. - ai_generated: Whether the action was generated by AI. Optional. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing the newly created IntegrationAction resource. - - Raises: - APIError: If the API request fails. - """ - return _create_integration_action( - self, - integration_name, - display_name, - script, - timeout_seconds, - enabled, - script_result_name, - is_async, - description=description, - default_result_value=default_result_value, - async_polling_interval_seconds=async_polling_interval_seconds, - async_total_timeout_seconds=async_total_timeout_seconds, - dynamic_results=dynamic_results, - parameters=parameters, - ai_generated=ai_generated, - api_version=api_version, - ) - - def update_integration_action( - self, - integration_name: str, - action_id: str, - display_name: str | None = None, - script: str | None = None, - timeout_seconds: int | None = None, - enabled: bool | None = None, - script_result_name: str | None = None, - is_async: bool | None = None, - description: str | None = None, - default_result_value: str | None = None, - async_polling_interval_seconds: int | None = None, - async_total_timeout_seconds: int | None = None, - dynamic_results: list[dict[str, Any]] | None = None, - parameters: list[dict[str, Any]] | None = None, - ai_generated: bool | None = None, - update_mask: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Update an existing custom action for a given integration. - - Only custom actions can be updated; predefined commercial actions are - immutable. - - Args: - integration_name: Name of the integration the action belongs to. - action_id: ID of the action to update. - display_name: Action's display name. Maximum 150 characters. - script: Action's Python script. Maximum size 5MB. - timeout_seconds: Action timeout in seconds. Maximum 1200. - enabled: Whether the action is enabled or disabled. - script_result_name: Field name that holds the script result. - Maximum 100 characters. - is_async: Whether the action is asynchronous. - description: Action's description. Maximum 400 characters. - default_result_value: Action's default result value. - Maximum 1000 characters. - async_polling_interval_seconds: Polling interval - in seconds for async actions. Cannot exceed total timeout. - async_total_timeout_seconds: Total async timeout in seconds. Maximum - 1209600 (14 days). - dynamic_results: List of dynamic result metadata dicts. Max 50. - parameters: List of action parameter dicts. Max 50. - ai_generated: Whether the action was generated by AI. - update_mask: Comma-separated list of fields to update. If omitted, - the mask is auto-generated from whichever fields are provided. - Example: "displayName,script". - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing the updated IntegrationAction resource. - - Raises: - APIError: If the API request fails. - """ - return _update_integration_action( - self, - integration_name, - action_id, - display_name=display_name, - script=script, - timeout_seconds=timeout_seconds, - enabled=enabled, - script_result_name=script_result_name, - is_async=is_async, - description=description, - default_result_value=default_result_value, - async_polling_interval_seconds=async_polling_interval_seconds, - async_total_timeout_seconds=async_total_timeout_seconds, - dynamic_results=dynamic_results, - parameters=parameters, - ai_generated=ai_generated, - update_mask=update_mask, - api_version=api_version, - ) - - def execute_integration_action_test( - self, - integration_name: str, - test_case_id: int, - action: dict[str, Any], - scope: str, - integration_instance_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Execute a test run of an integration action's script. - - Use this method to verify custom action logic, connectivity, and data - parsing against a specified integration instance and test case before - making the action available in playbooks. - - Args: - integration_name: Name of the integration the action belongs to. - test_case_id: ID of the action test case. - action: Dict containing the IntegrationAction to test. - scope: The action test scope. - integration_instance_id: The integration instance ID to use. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict with the test execution results with the following fields: - - output: The script output. - - debugOutput: The script debug output. - - resultJson: The result JSON if it exists (optional). - - resultName: The script result name (optional). - - Raises: - APIError: If the API request fails. - """ - return _execute_integration_action_test( - self, - integration_name, - test_case_id, - action, - scope, - integration_instance_id, - api_version=api_version, - ) - - def get_integration_actions_by_environment( - self, - integration_name: str, - environments: list[str], - include_widgets: bool, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """List actions executable within specified environments. - - Use this method to discover which automated tasks have active - integration instances configured for a particular - network or organizational context. - - Args: - integration_name: Name of the integration to fetch actions for. - environments: List of environments to filter actions by. - include_widgets: Whether to include widget actions in the response. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing a list of IntegrationAction objects that have - integration instances in one of the given environments. - - Raises: - APIError: If the API request fails. - """ - return _get_integration_actions_by_environment( - self, - integration_name, - environments, - include_widgets, - api_version=api_version, - ) - - def get_integration_action_template( - self, - integration_name: str, - is_async: bool = False, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Retrieve a default Python script template for a new - integration action. - - Use this method to jumpstart the development of a custom automated task - by providing boilerplate code for either synchronous or asynchronous - operations. - - Args: - integration_name: Name of the integration to fetch the template for. - is_async: Whether to fetch a template for an async action. Default - is False. - api_version: API version to use for the request. Default is V1BETA. - - Returns: - Dict containing the IntegrationAction template. - - Raises: - APIError: If the API request fails. - """ - return _get_integration_action_template( - self, - integration_name, - is_async=is_async, - api_version=api_version, - ) - - # ------------------------------------------------------------------------- - # Integration Action Revisions methods - # ------------------------------------------------------------------------- - - def list_integration_action_revisions( - self, - integration_name: str, - action_id: str, - page_size: int | None = None, - page_token: str | None = None, - filter_string: str | None = None, - order_by: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - as_list: bool = False, - ) -> dict[str, Any] | list[dict[str, Any]]: - """List all revisions for a specific integration action. - - Use this method to view the history of changes to an action, - enabling version control and the ability to rollback to - previous configurations. - - Args: - integration_name: Name of the integration the action - belongs to. - action_id: ID of the action to list revisions for. - page_size: Maximum number of revisions to return. - page_token: Page token from a previous call to retrieve the - next page. - filter_string: Filter expression to filter revisions. - order_by: Field to sort the revisions by. - api_version: API version to use for the request. Default is - V1BETA. - as_list: If True, return a list of revisions instead of a - dict with revisions list and nextPageToken. - - Returns: - If as_list is True: List of action revisions. - If as_list is False: Dict with action revisions list and - nextPageToken. - - Raises: - APIError: If the API request fails. - """ - return _list_integration_action_revisions( - self, - integration_name, - action_id, - page_size=page_size, - page_token=page_token, - filter_string=filter_string, - order_by=order_by, - api_version=api_version, - as_list=as_list, - ) - - def delete_integration_action_revision( - self, - integration_name: str, - action_id: str, - revision_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> None: - """Delete a specific action revision. - - Use this method to permanently remove a revision from the - action's history. - - Args: - integration_name: Name of the integration the action - belongs to. - action_id: ID of the action the revision belongs to. - revision_id: ID of the revision to delete. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - None - - Raises: - APIError: If the API request fails. - """ - return _delete_integration_action_revision( - self, - integration_name, - action_id, - revision_id, - api_version=api_version, - ) - - def create_integration_action_revision( - self, - integration_name: str, - action_id: str, - action: dict[str, Any], - comment: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Create a new revision for an integration action. - - Use this method to save a snapshot of the current action - configuration before making changes, enabling easy rollback if - needed. - - Args: - integration_name: Name of the integration the action - belongs to. - action_id: ID of the action to create a revision for. - action: The action object to save as a revision. - comment: Optional comment describing the revision. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - Dict containing the newly created ActionRevision resource. - - Raises: - APIError: If the API request fails. - """ - return _create_integration_action_revision( - self, - integration_name, - action_id, - action, - comment=comment, - api_version=api_version, - ) - - def rollback_integration_action_revision( - self, - integration_name: str, - action_id: str, - revision_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Rollback an integration action to a previous revision. - - Use this method to restore an action to a previously saved - state, reverting any changes made since that revision. - - Args: - integration_name: Name of the integration the action - belongs to. - action_id: ID of the action to rollback. - revision_id: ID of the revision to rollback to. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - Dict containing the rolled back IntegrationAction resource. - - Raises: - APIError: If the API request fails. - """ - return _rollback_integration_action_revision( - self, - integration_name, - action_id, - revision_id, - api_version=api_version, - ) - - # ------------------------------------------------------------------------- - # Integration Manager methods - # ------------------------------------------------------------------------- - - def list_integration_managers( - self, - integration_name: str, - page_size: int | None = None, - page_token: str | None = None, - filter_string: str | None = None, - order_by: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - as_list: bool = False, - ) -> dict[str, Any] | list[dict[str, Any]]: - """List all managers defined for a specific integration. - - Use this method to discover the library of managers available - within a particular integration's scope. - - Args: - integration_name: Name of the integration to list managers - for. - page_size: Maximum number of managers to return. Defaults to - 100, maximum is 100. - page_token: Page token from a previous call to retrieve the - next page. - filter_string: Filter expression to filter managers. - order_by: Field to sort the managers by. - api_version: API version to use for the request. Default is - V1BETA. - as_list: If True, return a list of managers instead of a - dict with managers list and nextPageToken. - - Returns: - If as_list is True: List of managers. - If as_list is False: Dict with managers list and - nextPageToken. - - Raises: - APIError: If the API request fails. - """ - return _list_integration_managers( - self, - integration_name, - page_size=page_size, - page_token=page_token, - filter_string=filter_string, - order_by=order_by, - api_version=api_version, - as_list=as_list, - ) - - def get_integration_manager( - self, - integration_name: str, - manager_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Get a single manager for a given integration. - - Use this method to retrieve the manager script and its metadata - for review or reference. - - Args: - integration_name: Name of the integration the manager - belongs to. - manager_id: ID of the manager to retrieve. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - Dict containing details of the specified IntegrationManager. - - Raises: - APIError: If the API request fails. - """ - return _get_integration_manager( - self, - integration_name, - manager_id, - api_version=api_version, - ) - - def delete_integration_manager( - self, - integration_name: str, - manager_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> None: - """Delete a specific custom manager from a given integration. - - Note that deleting a manager may break components (actions, - jobs) that depend on its code. - - Args: - integration_name: Name of the integration the manager - belongs to. - manager_id: ID of the manager to delete. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - None - - Raises: - APIError: If the API request fails. - """ - return _delete_integration_manager( - self, - integration_name, - manager_id, - api_version=api_version, - ) - - def create_integration_manager( - self, - integration_name: str, - display_name: str, - script: str, - description: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Create a new custom manager for a given integration. - - Use this method to add a new shared code utility. Each manager - must have a unique display name and a script containing valid - Python logic for reuse across actions, jobs, and connectors. - - Args: - integration_name: Name of the integration to create the - manager for. - display_name: Manager's display name. Maximum 150 - characters. Required. - script: Manager's Python script. Maximum 5MB. Required. - description: Manager's description. Maximum 400 characters. - Optional. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - Dict containing the newly created IntegrationManager - resource. - - Raises: - APIError: If the API request fails. - """ - return _create_integration_manager( - self, - integration_name, - display_name, - script, - description=description, - api_version=api_version, - ) - - def update_integration_manager( - self, - integration_name: str, - manager_id: str, - display_name: str | None = None, - script: str | None = None, - description: str | None = None, - update_mask: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Update an existing custom manager for a given integration. - - Use this method to modify the shared code, adjust its - description, or refine its logic across all components that - import it. - - Args: - integration_name: Name of the integration the manager - belongs to. - manager_id: ID of the manager to update. - display_name: Manager's display name. Maximum 150 - characters. - script: Manager's Python script. Maximum 5MB. - description: Manager's description. Maximum 400 characters. - update_mask: Comma-separated list of fields to update. If - omitted, the mask is auto-generated from whichever - fields are provided. Example: "displayName,script". - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - Dict containing the updated IntegrationManager resource. - - Raises: - APIError: If the API request fails. - """ - return _update_integration_manager( - self, - integration_name, - manager_id, - display_name=display_name, - script=script, - description=description, - update_mask=update_mask, - api_version=api_version, - ) - - def get_integration_manager_template( - self, - integration_name: str, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Retrieve a default Python script template for a new - integration manager. - - Use this method to quickly start developing new managers. - - Args: - integration_name: Name of the integration to fetch the - template for. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - Dict containing the IntegrationManager template. - - Raises: - APIError: If the API request fails. - """ - return _get_integration_manager_template( - self, - integration_name, - api_version=api_version, - ) - - # ------------------------------------------------------------------------- - # Integration Manager Revisions methods - # ------------------------------------------------------------------------- - - def list_integration_manager_revisions( - self, - integration_name: str, - manager_id: str, - page_size: int | None = None, - page_token: str | None = None, - filter_string: str | None = None, - order_by: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - as_list: bool = False, - ) -> dict[str, Any] | list[dict[str, Any]]: - """List all revisions for a specific integration manager. - - Use this method to browse the version history and identify - previous functional states of a manager. - - Args: - integration_name: Name of the integration the manager - belongs to. - manager_id: ID of the manager to list revisions for. - page_size: Maximum number of revisions to return. - page_token: Page token from a previous call to retrieve the - next page. - filter_string: Filter expression to filter revisions. - order_by: Field to sort the revisions by. - api_version: API version to use for the request. Default is - V1BETA. - as_list: If True, return a list of revisions instead of a - dict with revisions list and nextPageToken. - - Returns: - If as_list is True: List of revisions. - If as_list is False: Dict with revisions list and - nextPageToken. - - Raises: - APIError: If the API request fails. - """ - return _list_integration_manager_revisions( - self, - integration_name, - manager_id, - page_size=page_size, - page_token=page_token, - filter_string=filter_string, - order_by=order_by, - api_version=api_version, - as_list=as_list, - ) - - def get_integration_manager_revision( - self, - integration_name: str, - manager_id: str, - revision_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Get a single revision for a specific integration manager. - - Use this method to retrieve a specific snapshot of an - IntegrationManagerRevision for comparison or review. - - Args: - integration_name: Name of the integration the manager - belongs to. - manager_id: ID of the manager the revision belongs to. - revision_id: ID of the revision to retrieve. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - Dict containing details of the specified - IntegrationManagerRevision. - - Raises: - APIError: If the API request fails. - """ - return _get_integration_manager_revision( - self, - integration_name, - manager_id, - revision_id, - api_version=api_version, - ) - - def delete_integration_manager_revision( - self, - integration_name: str, - manager_id: str, - revision_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> None: - """Delete a specific revision for a given integration manager. - - Use this method to clean up obsolete snapshots and manage the - historical record of managers. - - Args: - integration_name: Name of the integration the manager - belongs to. - manager_id: ID of the manager the revision belongs to. - revision_id: ID of the revision to delete. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - None - - Raises: - APIError: If the API request fails. - """ - return _delete_integration_manager_revision( - self, - integration_name, - manager_id, - revision_id, - api_version=api_version, - ) - - def create_integration_manager_revision( - self, - integration_name: str, - manager_id: str, - manager: dict[str, Any], - comment: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Create a new revision snapshot of the current integration - manager. - - Use this method to establish a recovery point before making - significant updates to a manager. - - Args: - integration_name: Name of the integration the manager - belongs to. - manager_id: ID of the manager to create a revision for. - manager: Dict containing the IntegrationManager to snapshot. - comment: Comment describing the revision. Maximum 400 - characters. Optional. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - Dict containing the newly created - IntegrationManagerRevision resource. - - Raises: - APIError: If the API request fails. - """ - return _create_integration_manager_revision( - self, - integration_name, - manager_id, - manager, - comment=comment, - api_version=api_version, - ) - - def rollback_integration_manager_revision( - self, - integration_name: str, - manager_id: str, - revision_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, - ) -> dict[str, Any]: - """Revert the current manager definition to a previously saved - revision. - - Use this method to rapidly recover a functional state for - common code if an update causes operational issues in dependent - actions or jobs. - - Args: - integration_name: Name of the integration the manager - belongs to. - manager_id: ID of the manager to rollback. - revision_id: ID of the revision to rollback to. - api_version: API version to use for the request. Default is - V1BETA. - - Returns: - Dict containing the IntegrationManagerRevision rolled back - to. - - Raises: - APIError: If the API request fails. - """ - return _rollback_integration_manager_revision( - self, - integration_name, - manager_id, - revision_id, - api_version=api_version, - ) def get_analysis_report( self, log_type: str, diff --git a/src/secops/chronicle/soar/__init__.py b/src/secops/chronicle/soar/__init__.py index 9f3847d1..074d5e40 100644 --- a/src/secops/chronicle/soar/__init__.py +++ b/src/secops/chronicle/soar/__init__.py @@ -43,6 +43,37 @@ install_marketplace_integration, uninstall_marketplace_integration, ) +from secops.chronicle.soar.integration.actions import ( + create_integration_action, + delete_integration_action, + execute_integration_action_test, + get_integration_action, + get_integration_action_template, + get_integration_actions_by_environment, + list_integration_actions, + update_integration_action, +) +from secops.chronicle.soar.integration.action_revisions import ( + create_integration_action_revision, + delete_integration_action_revision, + list_integration_action_revisions, + rollback_integration_action_revision, +) +from secops.chronicle.soar.integration.managers import ( + create_integration_manager, + delete_integration_manager, + get_integration_manager, + get_integration_manager_template, + list_integration_managers, + update_integration_manager, +) +from secops.chronicle.soar.integration.manager_revisions import ( + create_integration_manager_revision, + delete_integration_manager_revision, + get_integration_manager_revision, + list_integration_manager_revisions, + rollback_integration_manager_revision, +) __all__ = [ # client @@ -71,4 +102,31 @@ "delete_integration_instance", "create_integration_instance", "update_integration_instance", + # Integration Actions + "create_integration_action", + "delete_integration_action", + "execute_integration_action_test", + "get_integration_action", + "get_integration_action_template", + "get_integration_actions_by_environment", + "list_integration_actions", + "update_integration_action", + # Integration Action Revisions + "create_integration_action_revision", + "delete_integration_action_revision", + "list_integration_action_revisions", + "rollback_integration_action_revision", + # Integration Managers + "create_integration_manager", + "delete_integration_manager", + "get_integration_manager", + "get_integration_manager_template", + "list_integration_managers", + "update_integration_manager", + # Integration Manager Revisions + "create_integration_manager_revision", + "delete_integration_manager_revision", + "get_integration_manager_revision", + "list_integration_manager_revisions", + "rollback_integration_manager_revision", ] diff --git a/src/secops/chronicle/integration/action_revisions.py b/src/secops/chronicle/soar/integration/action_revisions.py similarity index 100% rename from src/secops/chronicle/integration/action_revisions.py rename to src/secops/chronicle/soar/integration/action_revisions.py diff --git a/src/secops/chronicle/integration/actions.py b/src/secops/chronicle/soar/integration/actions.py similarity index 100% rename from src/secops/chronicle/integration/actions.py rename to src/secops/chronicle/soar/integration/actions.py diff --git a/src/secops/chronicle/integration/manager_revisions.py b/src/secops/chronicle/soar/integration/manager_revisions.py similarity index 100% rename from src/secops/chronicle/integration/manager_revisions.py rename to src/secops/chronicle/soar/integration/manager_revisions.py diff --git a/src/secops/chronicle/integration/managers.py b/src/secops/chronicle/soar/integration/managers.py similarity index 100% rename from src/secops/chronicle/integration/managers.py rename to src/secops/chronicle/soar/integration/managers.py diff --git a/src/secops/chronicle/soar/service.py b/src/secops/chronicle/soar/service.py index 0f3d27a8..1d57ee59 100644 --- a/src/secops/chronicle/soar/service.py +++ b/src/secops/chronicle/soar/service.py @@ -60,6 +60,37 @@ list_integration_instances as _list_integration_instances, update_integration_instance as _update_integration_instance, ) +from secops.chronicle.soar.integration.actions import ( + create_integration_action as _create_integration_action, + delete_integration_action as _delete_integration_action, + execute_integration_action_test as _execute_integration_action_test, + get_integration_action as _get_integration_action, + get_integration_action_template as _get_integration_action_template, + get_integration_actions_by_environment as _get_integration_actions_by_environment, + list_integration_actions as _list_integration_actions, + update_integration_action as _update_integration_action, +) +from secops.chronicle.soar.integration.action_revisions import ( + create_integration_action_revision as _create_integration_action_revision, + delete_integration_action_revision as _delete_integration_action_revision, + list_integration_action_revisions as _list_integration_action_revisions, + rollback_integration_action_revision as _rollback_integration_action_revision, +) +from secops.chronicle.soar.integration.managers import ( + create_integration_manager as _create_integration_manager, + delete_integration_manager as _delete_integration_manager, + get_integration_manager as _get_integration_manager, + get_integration_manager_template as _get_integration_manager_template, + list_integration_managers as _list_integration_managers, + update_integration_manager as _update_integration_manager, +) +from secops.chronicle.soar.integration.manager_revisions import ( + create_integration_manager_revision as _create_integration_manager_revision, + delete_integration_manager_revision as _delete_integration_manager_revision, + get_integration_manager_revision as _get_integration_manager_revision, + list_integration_manager_revisions as _list_integration_manager_revisions, + rollback_integration_manager_revision as _rollback_integration_manager_revision, +) # pylint: enable=line-too-long @@ -1091,3 +1122,949 @@ def get_default_integration_instance( integration_name, api_version=api_version, ) + + # ------------------------------------------------------------------------- + # Integration Action methods + # ------------------------------------------------------------------------- + + def list_integration_actions( + self, + integration_name: str, + page_size: int | None = None, + page_token: str | None = None, + filter_string: str | None = None, + order_by: str | None = None, + expand: str | None = None, + api_version: APIVersion | None = APIVersion.V1BETA, + as_list: bool = False, + ) -> dict[str, Any] | list[dict[str, Any]]: + """Get a list of actions for a given integration. + + Args: + integration_name: Name of the integration to get actions for + page_size: Number of results to return per page + page_token: Token for the page to retrieve + filter_string: Filter expression to filter actions + order_by: Field to sort the actions by + expand: Comma-separated list of fields to expand in the response + api_version: API version to use for the request. Default is V1BETA. + as_list: If True, return a list of actions instead of a dict with + actions list and nextPageToken. + + Returns: + If as_list is True: List of actions. + If as_list is False: Dict with actions list and nextPageToken. + + Raises: + APIError: If the API request fails + """ + return _list_integration_actions( + self, + integration_name, + page_size=page_size, + page_token=page_token, + filter_string=filter_string, + order_by=order_by, + expand=expand, + api_version=api_version, + as_list=as_list, + ) + + def get_integration_action( + self, + integration_name: str, + action_id: str, + api_version: APIVersion | None = APIVersion.V1BETA, + ) -> dict[str, Any]: + """Get details of a specific action for a given integration. + + Args: + integration_name: Name of the integration the action belongs to + action_id: ID of the action to retrieve + api_version: API version to use for the request. Default is V1BETA. + + Returns: + Dict containing details of the specified action. + + Raises: + APIError: If the API request fails + """ + return _get_integration_action( + self, + integration_name, + action_id, + api_version=api_version, + ) + + def delete_integration_action( + self, + integration_name: str, + action_id: str, + api_version: APIVersion | None = APIVersion.V1BETA, + ) -> None: + """Delete a specific action from a given integration. + + Args: + integration_name: Name of the integration the action belongs to + action_id: ID of the action to delete + api_version: API version to use for the request. Default is V1BETA. + + Returns: + None + + Raises: + APIError: If the API request fails + """ + return _delete_integration_action( + self, + integration_name, + action_id, + api_version=api_version, + ) + + def create_integration_action( + self, + integration_name: str, + display_name: str, + script: str, + timeout_seconds: int, + enabled: bool, + script_result_name: str, + is_async: bool, + description: str | None = None, + default_result_value: str | None = None, + async_polling_interval_seconds: int | None = None, + async_total_timeout_seconds: int | None = None, + dynamic_results: list[dict[str, Any]] | None = None, + parameters: list[dict[str, Any]] | None = None, + ai_generated: bool | None = None, + api_version: APIVersion | None = APIVersion.V1BETA, + ) -> dict[str, Any]: + """Create a new custom action for a given integration. + + Args: + integration_name: Name of the integration to + create the action for. + display_name: Action's display name. + Maximum 150 characters. Required. + script: Action's Python script. Maximum size 5MB. Required. + timeout_seconds: Action timeout in seconds. Maximum 1200. Required. + enabled: Whether the action is enabled or disabled. Required. + script_result_name: Field name that holds the script result. + Maximum 100 characters. Required. + is_async: Whether the action is asynchronous. Required. + description: Action's description. Maximum 400 characters. Optional. + default_result_value: Action's default result value. + Maximum 1000 characters. Optional. + async_polling_interval_seconds: Polling interval + in seconds for async actions. + Cannot exceed total timeout. Optional. + async_total_timeout_seconds: Total async timeout in seconds. Maximum + 1209600 (14 days). Optional. + dynamic_results: List of dynamic result metadata dicts. + Max 50. Optional. + parameters: List of action parameter dicts. Max 50. Optional. + ai_generated: Whether the action was generated by AI. Optional. + api_version: API version to use for the request. Default is V1BETA. + + Returns: + Dict containing the newly created IntegrationAction resource. + + Raises: + APIError: If the API request fails. + """ + return _create_integration_action( + self, + integration_name, + display_name, + script, + timeout_seconds, + enabled, + script_result_name, + is_async, + description=description, + default_result_value=default_result_value, + async_polling_interval_seconds=async_polling_interval_seconds, + async_total_timeout_seconds=async_total_timeout_seconds, + dynamic_results=dynamic_results, + parameters=parameters, + ai_generated=ai_generated, + api_version=api_version, + ) + + def update_integration_action( + self, + integration_name: str, + action_id: str, + display_name: str | None = None, + script: str | None = None, + timeout_seconds: int | None = None, + enabled: bool | None = None, + script_result_name: str | None = None, + is_async: bool | None = None, + description: str | None = None, + default_result_value: str | None = None, + async_polling_interval_seconds: int | None = None, + async_total_timeout_seconds: int | None = None, + dynamic_results: list[dict[str, Any]] | None = None, + parameters: list[dict[str, Any]] | None = None, + ai_generated: bool | None = None, + update_mask: str | None = None, + api_version: APIVersion | None = APIVersion.V1BETA, + ) -> dict[str, Any]: + """Update an existing custom action for a given integration. + + Only custom actions can be updated; predefined commercial actions are + immutable. + + Args: + integration_name: Name of the integration the action belongs to. + action_id: ID of the action to update. + display_name: Action's display name. Maximum 150 characters. + script: Action's Python script. Maximum size 5MB. + timeout_seconds: Action timeout in seconds. Maximum 1200. + enabled: Whether the action is enabled or disabled. + script_result_name: Field name that holds the script result. + Maximum 100 characters. + is_async: Whether the action is asynchronous. + description: Action's description. Maximum 400 characters. + default_result_value: Action's default result value. + Maximum 1000 characters. + async_polling_interval_seconds: Polling interval + in seconds for async actions. Cannot exceed total timeout. + async_total_timeout_seconds: Total async timeout in seconds. Maximum + 1209600 (14 days). + dynamic_results: List of dynamic result metadata dicts. Max 50. + parameters: List of action parameter dicts. Max 50. + ai_generated: Whether the action was generated by AI. + update_mask: Comma-separated list of fields to update. If omitted, + the mask is auto-generated from whichever fields are provided. + Example: "displayName,script". + api_version: API version to use for the request. Default is V1BETA. + + Returns: + Dict containing the updated IntegrationAction resource. + + Raises: + APIError: If the API request fails. + """ + return _update_integration_action( + self, + integration_name, + action_id, + display_name=display_name, + script=script, + timeout_seconds=timeout_seconds, + enabled=enabled, + script_result_name=script_result_name, + is_async=is_async, + description=description, + default_result_value=default_result_value, + async_polling_interval_seconds=async_polling_interval_seconds, + async_total_timeout_seconds=async_total_timeout_seconds, + dynamic_results=dynamic_results, + parameters=parameters, + ai_generated=ai_generated, + update_mask=update_mask, + api_version=api_version, + ) + + def execute_integration_action_test( + self, + integration_name: str, + test_case_id: int, + action: dict[str, Any], + scope: str, + integration_instance_id: str, + api_version: APIVersion | None = APIVersion.V1BETA, + ) -> dict[str, Any]: + """Execute a test run of an integration action's script. + + Use this method to verify custom action logic, connectivity, and data + parsing against a specified integration instance and test case before + making the action available in playbooks. + + Args: + integration_name: Name of the integration the action belongs to. + test_case_id: ID of the action test case. + action: Dict containing the IntegrationAction to test. + scope: The action test scope. + integration_instance_id: The integration instance ID to use. + api_version: API version to use for the request. Default is V1BETA. + + Returns: + Dict with the test execution results with the following fields: + - output: The script output. + - debugOutput: The script debug output. + - resultJson: The result JSON if it exists (optional). + - resultName: The script result name (optional). + + Raises: + APIError: If the API request fails. + """ + return _execute_integration_action_test( + self, + integration_name, + test_case_id, + action, + scope, + integration_instance_id, + api_version=api_version, + ) + + def get_integration_actions_by_environment( + self, + integration_name: str, + environments: list[str], + include_widgets: bool, + api_version: APIVersion | None = APIVersion.V1BETA, + ) -> dict[str, Any]: + """List actions executable within specified environments. + + Use this method to discover which automated tasks have active + integration instances configured for a particular + network or organizational context. + + Args: + integration_name: Name of the integration to fetch actions for. + environments: List of environments to filter actions by. + include_widgets: Whether to include widget actions in the response. + api_version: API version to use for the request. Default is V1BETA. + + Returns: + Dict containing a list of IntegrationAction objects that have + integration instances in one of the given environments. + + Raises: + APIError: If the API request fails. + """ + return _get_integration_actions_by_environment( + self, + integration_name, + environments, + include_widgets, + api_version=api_version, + ) + + def get_integration_action_template( + self, + integration_name: str, + is_async: bool = False, + api_version: APIVersion | None = APIVersion.V1BETA, + ) -> dict[str, Any]: + """Retrieve a default Python script template for a new + integration action. + + Use this method to jumpstart the development of a custom automated task + by providing boilerplate code for either synchronous or asynchronous + operations. + + Args: + integration_name: Name of the integration to fetch the template for. + is_async: Whether to fetch a template for an async action. Default + is False. + api_version: API version to use for the request. Default is V1BETA. + + Returns: + Dict containing the IntegrationAction template. + + Raises: + APIError: If the API request fails. + """ + return _get_integration_action_template( + self, + integration_name, + is_async=is_async, + api_version=api_version, + ) + + # ------------------------------------------------------------------------- + # Integration Action Revisions methods + # ------------------------------------------------------------------------- + + def list_integration_action_revisions( + self, + integration_name: str, + action_id: str, + page_size: int | None = None, + page_token: str | None = None, + filter_string: str | None = None, + order_by: str | None = None, + api_version: APIVersion | None = APIVersion.V1BETA, + as_list: bool = False, + ) -> dict[str, Any] | list[dict[str, Any]]: + """List all revisions for a specific integration action. + + Use this method to view the history of changes to an action, + enabling version control and the ability to rollback to + previous configurations. + + Args: + integration_name: Name of the integration the action + belongs to. + action_id: ID of the action to list revisions for. + page_size: Maximum number of revisions to return. + page_token: Page token from a previous call to retrieve the + next page. + filter_string: Filter expression to filter revisions. + order_by: Field to sort the revisions by. + api_version: API version to use for the request. Default is + V1BETA. + as_list: If True, return a list of revisions instead of a + dict with revisions list and nextPageToken. + + Returns: + If as_list is True: List of action revisions. + If as_list is False: Dict with action revisions list and + nextPageToken. + + Raises: + APIError: If the API request fails. + """ + return _list_integration_action_revisions( + self, + integration_name, + action_id, + page_size=page_size, + page_token=page_token, + filter_string=filter_string, + order_by=order_by, + api_version=api_version, + as_list=as_list, + ) + + def delete_integration_action_revision( + self, + integration_name: str, + action_id: str, + revision_id: str, + api_version: APIVersion | None = APIVersion.V1BETA, + ) -> None: + """Delete a specific action revision. + + Use this method to permanently remove a revision from the + action's history. + + Args: + integration_name: Name of the integration the action + belongs to. + action_id: ID of the action the revision belongs to. + revision_id: ID of the revision to delete. + api_version: API version to use for the request. Default is + V1BETA. + + Returns: + None + + Raises: + APIError: If the API request fails. + """ + return _delete_integration_action_revision( + self, + integration_name, + action_id, + revision_id, + api_version=api_version, + ) + + def create_integration_action_revision( + self, + integration_name: str, + action_id: str, + action: dict[str, Any], + comment: str | None = None, + api_version: APIVersion | None = APIVersion.V1BETA, + ) -> dict[str, Any]: + """Create a new revision for an integration action. + + Use this method to save a snapshot of the current action + configuration before making changes, enabling easy rollback if + needed. + + Args: + integration_name: Name of the integration the action + belongs to. + action_id: ID of the action to create a revision for. + action: The action object to save as a revision. + comment: Optional comment describing the revision. + api_version: API version to use for the request. Default is + V1BETA. + + Returns: + Dict containing the newly created ActionRevision resource. + + Raises: + APIError: If the API request fails. + """ + return _create_integration_action_revision( + self, + integration_name, + action_id, + action, + comment=comment, + api_version=api_version, + ) + + def rollback_integration_action_revision( + self, + integration_name: str, + action_id: str, + revision_id: str, + api_version: APIVersion | None = APIVersion.V1BETA, + ) -> dict[str, Any]: + """Rollback an integration action to a previous revision. + + Use this method to restore an action to a previously saved + state, reverting any changes made since that revision. + + Args: + integration_name: Name of the integration the action + belongs to. + action_id: ID of the action to rollback. + revision_id: ID of the revision to rollback to. + api_version: API version to use for the request. Default is + V1BETA. + + Returns: + Dict containing the rolled back IntegrationAction resource. + + Raises: + APIError: If the API request fails. + """ + return _rollback_integration_action_revision( + self, + integration_name, + action_id, + revision_id, + api_version=api_version, + ) + + # ------------------------------------------------------------------------- + # Integration Manager methods + # ------------------------------------------------------------------------- + + def list_integration_managers( + self, + integration_name: str, + page_size: int | None = None, + page_token: str | None = None, + filter_string: str | None = None, + order_by: str | None = None, + api_version: APIVersion | None = APIVersion.V1BETA, + as_list: bool = False, + ) -> dict[str, Any] | list[dict[str, Any]]: + """List all managers defined for a specific integration. + + Use this method to discover the library of managers available + within a particular integration's scope. + + Args: + integration_name: Name of the integration to list managers + for. + page_size: Maximum number of managers to return. Defaults to + 100, maximum is 100. + page_token: Page token from a previous call to retrieve the + next page. + filter_string: Filter expression to filter managers. + order_by: Field to sort the managers by. + api_version: API version to use for the request. Default is + V1BETA. + as_list: If True, return a list of managers instead of a + dict with managers list and nextPageToken. + + Returns: + If as_list is True: List of managers. + If as_list is False: Dict with managers list and + nextPageToken. + + Raises: + APIError: If the API request fails. + """ + return _list_integration_managers( + self, + integration_name, + page_size=page_size, + page_token=page_token, + filter_string=filter_string, + order_by=order_by, + api_version=api_version, + as_list=as_list, + ) + + def get_integration_manager( + self, + integration_name: str, + manager_id: str, + api_version: APIVersion | None = APIVersion.V1BETA, + ) -> dict[str, Any]: + """Get a single manager for a given integration. + + Use this method to retrieve the manager script and its metadata + for review or reference. + + Args: + integration_name: Name of the integration the manager + belongs to. + manager_id: ID of the manager to retrieve. + api_version: API version to use for the request. Default is + V1BETA. + + Returns: + Dict containing details of the specified IntegrationManager. + + Raises: + APIError: If the API request fails. + """ + return _get_integration_manager( + self, + integration_name, + manager_id, + api_version=api_version, + ) + + def delete_integration_manager( + self, + integration_name: str, + manager_id: str, + api_version: APIVersion | None = APIVersion.V1BETA, + ) -> None: + """Delete a specific custom manager from a given integration. + + Note that deleting a manager may break components (actions, + jobs) that depend on its code. + + Args: + integration_name: Name of the integration the manager + belongs to. + manager_id: ID of the manager to delete. + api_version: API version to use for the request. Default is + V1BETA. + + Returns: + None + + Raises: + APIError: If the API request fails. + """ + return _delete_integration_manager( + self, + integration_name, + manager_id, + api_version=api_version, + ) + + def create_integration_manager( + self, + integration_name: str, + display_name: str, + script: str, + description: str | None = None, + api_version: APIVersion | None = APIVersion.V1BETA, + ) -> dict[str, Any]: + """Create a new custom manager for a given integration. + + Use this method to add a new shared code utility. Each manager + must have a unique display name and a script containing valid + Python logic for reuse across actions, jobs, and connectors. + + Args: + integration_name: Name of the integration to create the + manager for. + display_name: Manager's display name. Maximum 150 + characters. Required. + script: Manager's Python script. Maximum 5MB. Required. + description: Manager's description. Maximum 400 characters. + Optional. + api_version: API version to use for the request. Default is + V1BETA. + + Returns: + Dict containing the newly created IntegrationManager + resource. + + Raises: + APIError: If the API request fails. + """ + return _create_integration_manager( + self, + integration_name, + display_name, + script, + description=description, + api_version=api_version, + ) + + def update_integration_manager( + self, + integration_name: str, + manager_id: str, + display_name: str | None = None, + script: str | None = None, + description: str | None = None, + update_mask: str | None = None, + api_version: APIVersion | None = APIVersion.V1BETA, + ) -> dict[str, Any]: + """Update an existing custom manager for a given integration. + + Use this method to modify the shared code, adjust its + description, or refine its logic across all components that + import it. + + Args: + integration_name: Name of the integration the manager + belongs to. + manager_id: ID of the manager to update. + display_name: Manager's display name. Maximum 150 + characters. + script: Manager's Python script. Maximum 5MB. + description: Manager's description. Maximum 400 characters. + update_mask: Comma-separated list of fields to update. If + omitted, the mask is auto-generated from whichever + fields are provided. Example: "displayName,script". + api_version: API version to use for the request. Default is + V1BETA. + + Returns: + Dict containing the updated IntegrationManager resource. + + Raises: + APIError: If the API request fails. + """ + return _update_integration_manager( + self, + integration_name, + manager_id, + display_name=display_name, + script=script, + description=description, + update_mask=update_mask, + api_version=api_version, + ) + + def get_integration_manager_template( + self, + integration_name: str, + api_version: APIVersion | None = APIVersion.V1BETA, + ) -> dict[str, Any]: + """Retrieve a default Python script template for a new + integration manager. + + Use this method to quickly start developing new managers. + + Args: + integration_name: Name of the integration to fetch the + template for. + api_version: API version to use for the request. Default is + V1BETA. + + Returns: + Dict containing the IntegrationManager template. + + Raises: + APIError: If the API request fails. + """ + return _get_integration_manager_template( + self, + integration_name, + api_version=api_version, + ) + + # ------------------------------------------------------------------------- + # Integration Manager Revisions methods + # ------------------------------------------------------------------------- + + def list_integration_manager_revisions( + self, + integration_name: str, + manager_id: str, + page_size: int | None = None, + page_token: str | None = None, + filter_string: str | None = None, + order_by: str | None = None, + api_version: APIVersion | None = APIVersion.V1BETA, + as_list: bool = False, + ) -> dict[str, Any] | list[dict[str, Any]]: + """List all revisions for a specific integration manager. + + Use this method to browse the version history and identify + previous functional states of a manager. + + Args: + integration_name: Name of the integration the manager + belongs to. + manager_id: ID of the manager to list revisions for. + page_size: Maximum number of revisions to return. + page_token: Page token from a previous call to retrieve the + next page. + filter_string: Filter expression to filter revisions. + order_by: Field to sort the revisions by. + api_version: API version to use for the request. Default is + V1BETA. + as_list: If True, return a list of revisions instead of a + dict with revisions list and nextPageToken. + + Returns: + If as_list is True: List of revisions. + If as_list is False: Dict with revisions list and + nextPageToken. + + Raises: + APIError: If the API request fails. + """ + return _list_integration_manager_revisions( + self, + integration_name, + manager_id, + page_size=page_size, + page_token=page_token, + filter_string=filter_string, + order_by=order_by, + api_version=api_version, + as_list=as_list, + ) + + def get_integration_manager_revision( + self, + integration_name: str, + manager_id: str, + revision_id: str, + api_version: APIVersion | None = APIVersion.V1BETA, + ) -> dict[str, Any]: + """Get a single revision for a specific integration manager. + + Use this method to retrieve a specific snapshot of an + IntegrationManagerRevision for comparison or review. + + Args: + integration_name: Name of the integration the manager + belongs to. + manager_id: ID of the manager the revision belongs to. + revision_id: ID of the revision to retrieve. + api_version: API version to use for the request. Default is + V1BETA. + + Returns: + Dict containing details of the specified + IntegrationManagerRevision. + + Raises: + APIError: If the API request fails. + """ + return _get_integration_manager_revision( + self, + integration_name, + manager_id, + revision_id, + api_version=api_version, + ) + + def delete_integration_manager_revision( + self, + integration_name: str, + manager_id: str, + revision_id: str, + api_version: APIVersion | None = APIVersion.V1BETA, + ) -> None: + """Delete a specific revision for a given integration manager. + + Use this method to clean up obsolete snapshots and manage the + historical record of managers. + + Args: + integration_name: Name of the integration the manager + belongs to. + manager_id: ID of the manager the revision belongs to. + revision_id: ID of the revision to delete. + api_version: API version to use for the request. Default is + V1BETA. + + Returns: + None + + Raises: + APIError: If the API request fails. + """ + return _delete_integration_manager_revision( + self, + integration_name, + manager_id, + revision_id, + api_version=api_version, + ) + + def create_integration_manager_revision( + self, + integration_name: str, + manager_id: str, + manager: dict[str, Any], + comment: str | None = None, + api_version: APIVersion | None = APIVersion.V1BETA, + ) -> dict[str, Any]: + """Create a new revision snapshot of the current integration + manager. + + Use this method to establish a recovery point before making + significant updates to a manager. + + Args: + integration_name: Name of the integration the manager + belongs to. + manager_id: ID of the manager to create a revision for. + manager: Dict containing the IntegrationManager to snapshot. + comment: Comment describing the revision. Maximum 400 + characters. Optional. + api_version: API version to use for the request. Default is + V1BETA. + + Returns: + Dict containing the newly created + IntegrationManagerRevision resource. + + Raises: + APIError: If the API request fails. + """ + return _create_integration_manager_revision( + self, + integration_name, + manager_id, + manager, + comment=comment, + api_version=api_version, + ) + + def rollback_integration_manager_revision( + self, + integration_name: str, + manager_id: str, + revision_id: str, + api_version: APIVersion | None = APIVersion.V1BETA, + ) -> dict[str, Any]: + """Revert the current manager definition to a previously saved + revision. + + Use this method to rapidly recover a functional state for + common code if an update causes operational issues in dependent + actions or jobs. + + Args: + integration_name: Name of the integration the manager + belongs to. + manager_id: ID of the manager to rollback. + revision_id: ID of the revision to rollback to. + api_version: API version to use for the request. Default is + V1BETA. + + Returns: + Dict containing the IntegrationManagerRevision rolled back + to. + + Raises: + APIError: If the API request fails. + """ + return _rollback_integration_manager_revision( + self, + integration_name, + manager_id, + revision_id, + api_version=api_version, + ) diff --git a/tests/chronicle/soar/integration/__init__.py b/tests/chronicle/soar/integration/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/chronicle/integration/test_action_revisions.py b/tests/chronicle/soar/integration/test_action_revisions.py similarity index 89% rename from tests/chronicle/integration/test_action_revisions.py rename to tests/chronicle/soar/integration/test_action_revisions.py index f9abd9bc..8db23e3a 100644 --- a/tests/chronicle/integration/test_action_revisions.py +++ b/tests/chronicle/soar/integration/test_action_revisions.py @@ -20,7 +20,7 @@ from secops.chronicle.client import ChronicleClient from secops.chronicle.models import APIVersion -from secops.chronicle.integration.action_revisions import ( +from secops.chronicle.soar.integration.action_revisions import ( list_integration_action_revisions, delete_integration_action_revision, create_integration_action_revision, @@ -54,10 +54,10 @@ def test_list_integration_action_revisions_success(chronicle_client): } with patch( - "secops.chronicle.integration.action_revisions.chronicle_paginated_request", + "secops.chronicle.soar.integration.action_revisions.chronicle_paginated_request", return_value=expected, ) as mock_paginated, patch( - "secops.chronicle.integration.action_revisions.format_resource_id", + "secops.chronicle.soar.integration.action_revisions.format_resource_id", return_value="My Integration", ): result = list_integration_action_revisions( @@ -82,7 +82,7 @@ def test_list_integration_action_revisions_default_args(chronicle_client): expected = {"revisions": []} with patch( - "secops.chronicle.integration.action_revisions.chronicle_paginated_request", + "secops.chronicle.soar.integration.action_revisions.chronicle_paginated_request", return_value=expected, ) as mock_paginated: result = list_integration_action_revisions( @@ -99,7 +99,7 @@ def test_list_integration_action_revisions_with_filters(chronicle_client): expected = {"revisions": [{"name": "r1"}]} with patch( - "secops.chronicle.integration.action_revisions.chronicle_paginated_request", + "secops.chronicle.soar.integration.action_revisions.chronicle_paginated_request", return_value=expected, ) as mock_paginated: result = list_integration_action_revisions( @@ -124,7 +124,7 @@ def test_list_integration_action_revisions_as_list(chronicle_client): expected = [{"name": "r1"}, {"name": "r2"}] with patch( - "secops.chronicle.integration.action_revisions.chronicle_paginated_request", + "secops.chronicle.soar.integration.action_revisions.chronicle_paginated_request", return_value=expected, ) as mock_paginated: result = list_integration_action_revisions( @@ -143,7 +143,7 @@ def test_list_integration_action_revisions_as_list(chronicle_client): def test_list_integration_action_revisions_error(chronicle_client): """Test list_integration_action_revisions raises APIError on failure.""" with patch( - "secops.chronicle.integration.action_revisions.chronicle_paginated_request", + "secops.chronicle.soar.integration.action_revisions.chronicle_paginated_request", side_effect=APIError("Failed to list action revisions"), ): with pytest.raises(APIError) as exc_info: @@ -161,7 +161,7 @@ def test_list_integration_action_revisions_error(chronicle_client): def test_delete_integration_action_revision_success(chronicle_client): """Test delete_integration_action_revision issues DELETE request.""" with patch( - "secops.chronicle.integration.action_revisions.chronicle_request", + "secops.chronicle.soar.integration.action_revisions.chronicle_request", return_value=None, ) as mock_request: delete_integration_action_revision( @@ -180,7 +180,7 @@ def test_delete_integration_action_revision_success(chronicle_client): def test_delete_integration_action_revision_error(chronicle_client): """Test delete_integration_action_revision raises APIError on failure.""" with patch( - "secops.chronicle.integration.action_revisions.chronicle_request", + "secops.chronicle.soar.integration.action_revisions.chronicle_request", side_effect=APIError("Failed to delete action revision"), ): with pytest.raises(APIError) as exc_info: @@ -210,7 +210,7 @@ def test_create_integration_action_revision_success(chronicle_client): } with patch( - "secops.chronicle.integration.action_revisions.chronicle_request", + "secops.chronicle.soar.integration.action_revisions.chronicle_request", return_value=expected, ) as mock_request: result = create_integration_action_revision( @@ -241,7 +241,7 @@ def test_create_integration_action_revision_without_comment(chronicle_client): } with patch( - "secops.chronicle.integration.action_revisions.chronicle_request", + "secops.chronicle.soar.integration.action_revisions.chronicle_request", return_value=expected, ) as mock_request: result = create_integration_action_revision( @@ -263,7 +263,7 @@ def test_create_integration_action_revision_error(chronicle_client): action = {"name": "actions/a1"} with patch( - "secops.chronicle.integration.action_revisions.chronicle_request", + "secops.chronicle.soar.integration.action_revisions.chronicle_request", side_effect=APIError("Failed to create action revision"), ): with pytest.raises(APIError) as exc_info: @@ -287,7 +287,7 @@ def test_rollback_integration_action_revision_success(chronicle_client): } with patch( - "secops.chronicle.integration.action_revisions.chronicle_request", + "secops.chronicle.soar.integration.action_revisions.chronicle_request", return_value=expected, ) as mock_request: result = rollback_integration_action_revision( @@ -308,7 +308,7 @@ def test_rollback_integration_action_revision_success(chronicle_client): def test_rollback_integration_action_revision_error(chronicle_client): """Test rollback_integration_action_revision raises APIError on failure.""" with patch( - "secops.chronicle.integration.action_revisions.chronicle_request", + "secops.chronicle.soar.integration.action_revisions.chronicle_request", side_effect=APIError("Failed to rollback action revision"), ): with pytest.raises(APIError) as exc_info: @@ -329,7 +329,7 @@ def test_list_integration_action_revisions_custom_api_version(chronicle_client): expected = {"revisions": []} with patch( - "secops.chronicle.integration.action_revisions.chronicle_paginated_request", + "secops.chronicle.soar.integration.action_revisions.chronicle_paginated_request", return_value=expected, ) as mock_paginated: result = list_integration_action_revisions( @@ -348,7 +348,7 @@ def test_list_integration_action_revisions_custom_api_version(chronicle_client): def test_delete_integration_action_revision_custom_api_version(chronicle_client): """Test delete_integration_action_revision with custom API version.""" with patch( - "secops.chronicle.integration.action_revisions.chronicle_request", + "secops.chronicle.soar.integration.action_revisions.chronicle_request", return_value=None, ) as mock_request: delete_integration_action_revision( @@ -369,7 +369,7 @@ def test_create_integration_action_revision_custom_api_version(chronicle_client) action = {"name": "actions/a1"} with patch( - "secops.chronicle.integration.action_revisions.chronicle_request", + "secops.chronicle.soar.integration.action_revisions.chronicle_request", return_value=expected, ) as mock_request: result = create_integration_action_revision( @@ -391,7 +391,7 @@ def test_rollback_integration_action_revision_custom_api_version(chronicle_clien expected = {"name": "revisions/r1"} with patch( - "secops.chronicle.integration.action_revisions.chronicle_request", + "secops.chronicle.soar.integration.action_revisions.chronicle_request", return_value=expected, ) as mock_request: result = rollback_integration_action_revision( diff --git a/tests/chronicle/integration/test_actions.py b/tests/chronicle/soar/integration/test_actions.py similarity index 92% rename from tests/chronicle/integration/test_actions.py rename to tests/chronicle/soar/integration/test_actions.py index 6cd0a9ac..5bc57bd4 100644 --- a/tests/chronicle/integration/test_actions.py +++ b/tests/chronicle/soar/integration/test_actions.py @@ -20,7 +20,7 @@ from secops.chronicle.client import ChronicleClient from secops.chronicle.models import APIVersion -from secops.chronicle.integration.actions import ( +from secops.chronicle.soar.integration.actions import ( list_integration_actions, get_integration_action, delete_integration_action, @@ -55,11 +55,11 @@ def test_list_integration_actions_success(chronicle_client): expected = {"actions": [{"name": "a1"}, {"name": "a2"}], "nextPageToken": "t"} with patch( - "secops.chronicle.integration.actions.chronicle_paginated_request", + "secops.chronicle.soar.integration.actions.chronicle_paginated_request", return_value=expected, ) as mock_paginated, patch( # Avoid assuming how format_resource_id encodes/cases values - "secops.chronicle.integration.actions.format_resource_id", + "secops.chronicle.soar.integration.actions.format_resource_id", return_value="My Integration", ): result = list_integration_actions( @@ -88,7 +88,7 @@ def test_list_integration_actions_default_args(chronicle_client): expected = {"actions": []} with patch( - "secops.chronicle.integration.actions.chronicle_paginated_request", + "secops.chronicle.soar.integration.actions.chronicle_paginated_request", return_value=expected, ) as mock_paginated: result = list_integration_actions( @@ -115,7 +115,7 @@ def test_list_integration_actions_with_filter_order_expand(chronicle_client): expected = {"actions": [{"name": "a1"}]} with patch( - "secops.chronicle.integration.actions.chronicle_paginated_request", + "secops.chronicle.soar.integration.actions.chronicle_paginated_request", return_value=expected, ) as mock_paginated: result = list_integration_actions( @@ -149,7 +149,7 @@ def test_list_integration_actions_as_list(chronicle_client): expected = [{"name": "a1"}, {"name": "a2"}] with patch( - "secops.chronicle.integration.actions.chronicle_paginated_request", + "secops.chronicle.soar.integration.actions.chronicle_paginated_request", return_value=expected, ) as mock_paginated: result = list_integration_actions( @@ -175,7 +175,7 @@ def test_list_integration_actions_as_list(chronicle_client): def test_list_integration_actions_error(chronicle_client): """Test list_integration_actions propagates APIError from helper.""" with patch( - "secops.chronicle.integration.actions.chronicle_paginated_request", + "secops.chronicle.soar.integration.actions.chronicle_paginated_request", side_effect=APIError("Failed to list integration actions"), ): with pytest.raises(APIError) as exc_info: @@ -195,7 +195,7 @@ def test_get_integration_action_success(chronicle_client): expected = {"name": "actions/a1", "displayName": "Action 1"} with patch( - "secops.chronicle.integration.actions.chronicle_request", + "secops.chronicle.soar.integration.actions.chronicle_request", return_value=expected, ) as mock_request: result = get_integration_action( @@ -217,7 +217,7 @@ def test_get_integration_action_success(chronicle_client): def test_get_integration_action_error(chronicle_client): """Test get_integration_action raises APIError on failure.""" with patch( - "secops.chronicle.integration.actions.chronicle_request", + "secops.chronicle.soar.integration.actions.chronicle_request", side_effect=APIError("Failed to get integration action"), ): with pytest.raises(APIError) as exc_info: @@ -235,7 +235,7 @@ def test_get_integration_action_error(chronicle_client): def test_delete_integration_action_success(chronicle_client): """Test delete_integration_action issues DELETE request.""" with patch( - "secops.chronicle.integration.actions.chronicle_request", + "secops.chronicle.soar.integration.actions.chronicle_request", return_value=None, ) as mock_request: delete_integration_action( @@ -255,7 +255,7 @@ def test_delete_integration_action_success(chronicle_client): def test_delete_integration_action_error(chronicle_client): """Test delete_integration_action raises APIError on failure.""" with patch( - "secops.chronicle.integration.actions.chronicle_request", + "secops.chronicle.soar.integration.actions.chronicle_request", side_effect=APIError("Failed to delete integration action"), ): with pytest.raises(APIError) as exc_info: @@ -275,7 +275,7 @@ def test_create_integration_action_required_fields_only(chronicle_client): expected = {"name": "actions/new", "displayName": "My Action"} with patch( - "secops.chronicle.integration.actions.chronicle_request", + "secops.chronicle.soar.integration.actions.chronicle_request", return_value=expected, ) as mock_request: result = create_integration_action( @@ -312,7 +312,7 @@ def test_create_integration_action_all_fields(chronicle_client): expected = {"name": "actions/new"} with patch( - "secops.chronicle.integration.actions.chronicle_request", + "secops.chronicle.soar.integration.actions.chronicle_request", return_value=expected, ) as mock_request: result = create_integration_action( @@ -361,7 +361,7 @@ def test_create_integration_action_all_fields(chronicle_client): def test_create_integration_action_none_fields_excluded(chronicle_client): """Test that None optional fields are not included in request body.""" with patch( - "secops.chronicle.integration.actions.chronicle_request", + "secops.chronicle.soar.integration.actions.chronicle_request", return_value={"name": "actions/new"}, ) as mock_request: create_integration_action( @@ -401,7 +401,7 @@ def test_create_integration_action_none_fields_excluded(chronicle_client): def test_create_integration_action_error(chronicle_client): """Test create_integration_action raises APIError on failure.""" with patch( - "secops.chronicle.integration.actions.chronicle_request", + "secops.chronicle.soar.integration.actions.chronicle_request", side_effect=APIError("Failed to create integration action"), ): with pytest.raises(APIError) as exc_info: @@ -426,7 +426,7 @@ def test_update_integration_action_with_explicit_update_mask(chronicle_client): expected = {"name": "actions/a1", "displayName": "New Name"} with patch( - "secops.chronicle.integration.actions.chronicle_request", + "secops.chronicle.soar.integration.actions.chronicle_request", return_value=expected, ) as mock_request: result = update_integration_action( @@ -457,7 +457,7 @@ def test_update_integration_action_auto_update_mask(chronicle_client): expected = {"name": "actions/a1"} with patch( - "secops.chronicle.integration.actions.chronicle_request", + "secops.chronicle.soar.integration.actions.chronicle_request", return_value=expected, ) as mock_request: result = update_integration_action( @@ -487,7 +487,7 @@ def test_update_integration_action_auto_update_mask(chronicle_client): def test_update_integration_action_error(chronicle_client): """Test update_integration_action raises APIError on failure.""" with patch( - "secops.chronicle.integration.actions.chronicle_request", + "secops.chronicle.soar.integration.actions.chronicle_request", side_effect=APIError("Failed to update integration action"), ): with pytest.raises(APIError) as exc_info: @@ -508,7 +508,7 @@ def test_execute_test_integration_action_success(chronicle_client): expected = {"output": "ok", "debugOutput": ""} with patch( - "secops.chronicle.integration.actions.chronicle_request", + "secops.chronicle.soar.integration.actions.chronicle_request", return_value=expected, ) as mock_request: action = {"displayName": "My Action", "script": "print('hi')"} @@ -540,7 +540,7 @@ def test_execute_test_integration_action_success(chronicle_client): def test_execute_test_integration_action_error(chronicle_client): """Test test_integration_action raises APIError on failure.""" with patch( - "secops.chronicle.integration.actions.chronicle_request", + "secops.chronicle.soar.integration.actions.chronicle_request", side_effect=APIError("Failed to test integration action"), ): with pytest.raises(APIError) as exc_info: @@ -563,7 +563,7 @@ def test_get_integration_actions_by_environment_success(chronicle_client): expected = {"actions": [{"name": "a1"}]} with patch( - "secops.chronicle.integration.actions.chronicle_request", + "secops.chronicle.soar.integration.actions.chronicle_request", return_value=expected, ) as mock_request: result = get_integration_actions_by_environment( @@ -587,7 +587,7 @@ def test_get_integration_actions_by_environment_success(chronicle_client): def test_get_integration_actions_by_environment_error(chronicle_client): """Test get_integration_actions_by_environment raises APIError on failure.""" with patch( - "secops.chronicle.integration.actions.chronicle_request", + "secops.chronicle.soar.integration.actions.chronicle_request", side_effect=APIError("Failed to fetch actions by environment"), ): with pytest.raises(APIError) as exc_info: @@ -608,7 +608,7 @@ def test_get_integration_action_template_default_async_false(chronicle_client): expected = {"script": "# template"} with patch( - "secops.chronicle.integration.actions.chronicle_request", + "secops.chronicle.soar.integration.actions.chronicle_request", return_value=expected, ) as mock_request: result = get_integration_action_template( @@ -632,7 +632,7 @@ def test_get_integration_action_template_async_true(chronicle_client): expected = {"script": "# async template"} with patch( - "secops.chronicle.integration.actions.chronicle_request", + "secops.chronicle.soar.integration.actions.chronicle_request", return_value=expected, ) as mock_request: result = get_integration_action_template( @@ -655,7 +655,7 @@ def test_get_integration_action_template_async_true(chronicle_client): def test_get_integration_action_template_error(chronicle_client): """Test get_integration_action_template raises APIError on failure.""" with patch( - "secops.chronicle.integration.actions.chronicle_request", + "secops.chronicle.soar.integration.actions.chronicle_request", side_effect=APIError("Failed to fetch action template"), ): with pytest.raises(APIError) as exc_info: diff --git a/tests/chronicle/integration/test_manager_revisions.py b/tests/chronicle/soar/integration/test_manager_revisions.py similarity index 89% rename from tests/chronicle/integration/test_manager_revisions.py rename to tests/chronicle/soar/integration/test_manager_revisions.py index 7076bd54..0170a5a7 100644 --- a/tests/chronicle/integration/test_manager_revisions.py +++ b/tests/chronicle/soar/integration/test_manager_revisions.py @@ -20,7 +20,7 @@ from secops.chronicle.client import ChronicleClient from secops.chronicle.models import APIVersion -from secops.chronicle.integration.manager_revisions import ( +from secops.chronicle.soar.integration.manager_revisions import ( list_integration_manager_revisions, get_integration_manager_revision, delete_integration_manager_revision, @@ -55,10 +55,10 @@ def test_list_integration_manager_revisions_success(chronicle_client): } with patch( - "secops.chronicle.integration.manager_revisions.chronicle_paginated_request", + "secops.chronicle.soar.integration.manager_revisions.chronicle_paginated_request", return_value=expected, ) as mock_paginated, patch( - "secops.chronicle.integration.manager_revisions.format_resource_id", + "secops.chronicle.soar.integration.manager_revisions.format_resource_id", return_value="My Integration", ): result = list_integration_manager_revisions( @@ -83,7 +83,7 @@ def test_list_integration_manager_revisions_default_args(chronicle_client): expected = {"revisions": []} with patch( - "secops.chronicle.integration.manager_revisions.chronicle_paginated_request", + "secops.chronicle.soar.integration.manager_revisions.chronicle_paginated_request", return_value=expected, ) as mock_paginated: result = list_integration_manager_revisions( @@ -100,7 +100,7 @@ def test_list_integration_manager_revisions_with_filters(chronicle_client): expected = {"revisions": [{"name": "r1"}]} with patch( - "secops.chronicle.integration.manager_revisions.chronicle_paginated_request", + "secops.chronicle.soar.integration.manager_revisions.chronicle_paginated_request", return_value=expected, ) as mock_paginated: result = list_integration_manager_revisions( @@ -125,7 +125,7 @@ def test_list_integration_manager_revisions_as_list(chronicle_client): expected = [{"name": "r1"}, {"name": "r2"}] with patch( - "secops.chronicle.integration.manager_revisions.chronicle_paginated_request", + "secops.chronicle.soar.integration.manager_revisions.chronicle_paginated_request", return_value=expected, ) as mock_paginated: result = list_integration_manager_revisions( @@ -144,7 +144,7 @@ def test_list_integration_manager_revisions_as_list(chronicle_client): def test_list_integration_manager_revisions_error(chronicle_client): """Test list_integration_manager_revisions raises APIError on failure.""" with patch( - "secops.chronicle.integration.manager_revisions.chronicle_paginated_request", + "secops.chronicle.soar.integration.manager_revisions.chronicle_paginated_request", side_effect=APIError("Failed to list manager revisions"), ): with pytest.raises(APIError) as exc_info: @@ -171,7 +171,7 @@ def test_get_integration_manager_revision_success(chronicle_client): } with patch( - "secops.chronicle.integration.manager_revisions.chronicle_request", + "secops.chronicle.soar.integration.manager_revisions.chronicle_request", return_value=expected, ) as mock_request: result = get_integration_manager_revision( @@ -192,7 +192,7 @@ def test_get_integration_manager_revision_success(chronicle_client): def test_get_integration_manager_revision_error(chronicle_client): """Test get_integration_manager_revision raises APIError on failure.""" with patch( - "secops.chronicle.integration.manager_revisions.chronicle_request", + "secops.chronicle.soar.integration.manager_revisions.chronicle_request", side_effect=APIError("Failed to get manager revision"), ): with pytest.raises(APIError) as exc_info: @@ -211,7 +211,7 @@ def test_get_integration_manager_revision_error(chronicle_client): def test_delete_integration_manager_revision_success(chronicle_client): """Test delete_integration_manager_revision issues DELETE request.""" with patch( - "secops.chronicle.integration.manager_revisions.chronicle_request", + "secops.chronicle.soar.integration.manager_revisions.chronicle_request", return_value=None, ) as mock_request: delete_integration_manager_revision( @@ -230,7 +230,7 @@ def test_delete_integration_manager_revision_success(chronicle_client): def test_delete_integration_manager_revision_error(chronicle_client): """Test delete_integration_manager_revision raises APIError on failure.""" with patch( - "secops.chronicle.integration.manager_revisions.chronicle_request", + "secops.chronicle.soar.integration.manager_revisions.chronicle_request", side_effect=APIError("Failed to delete manager revision"), ): with pytest.raises(APIError) as exc_info: @@ -257,7 +257,7 @@ def test_create_integration_manager_revision_required_fields_only( } with patch( - "secops.chronicle.integration.manager_revisions.chronicle_request", + "secops.chronicle.soar.integration.manager_revisions.chronicle_request", return_value=expected, ) as mock_request: result = create_integration_manager_revision( @@ -286,7 +286,7 @@ def test_create_integration_manager_revision_with_comment(chronicle_client): manager_dict = {"displayName": "My Manager", "script": "def helper(): pass"} with patch( - "secops.chronicle.integration.manager_revisions.chronicle_request", + "secops.chronicle.soar.integration.manager_revisions.chronicle_request", return_value=expected, ) as mock_request: result = create_integration_manager_revision( @@ -309,7 +309,7 @@ def test_create_integration_manager_revision_error(chronicle_client): manager_dict = {"displayName": "My Manager", "script": "def helper(): pass"} with patch( - "secops.chronicle.integration.manager_revisions.chronicle_request", + "secops.chronicle.soar.integration.manager_revisions.chronicle_request", side_effect=APIError("Failed to create manager revision"), ): with pytest.raises(APIError) as exc_info: @@ -336,7 +336,7 @@ def test_rollback_integration_manager_revision_success(chronicle_client): } with patch( - "secops.chronicle.integration.manager_revisions.chronicle_request", + "secops.chronicle.soar.integration.manager_revisions.chronicle_request", return_value=expected, ) as mock_request: result = rollback_integration_manager_revision( @@ -357,7 +357,7 @@ def test_rollback_integration_manager_revision_success(chronicle_client): def test_rollback_integration_manager_revision_error(chronicle_client): """Test rollback_integration_manager_revision raises APIError on failure.""" with patch( - "secops.chronicle.integration.manager_revisions.chronicle_request", + "secops.chronicle.soar.integration.manager_revisions.chronicle_request", side_effect=APIError("Failed to rollback manager revision"), ): with pytest.raises(APIError) as exc_info: @@ -378,7 +378,7 @@ def test_list_integration_manager_revisions_custom_api_version(chronicle_client) expected = {"revisions": []} with patch( - "secops.chronicle.integration.manager_revisions.chronicle_paginated_request", + "secops.chronicle.soar.integration.manager_revisions.chronicle_paginated_request", return_value=expected, ) as mock_paginated: result = list_integration_manager_revisions( @@ -399,7 +399,7 @@ def test_get_integration_manager_revision_custom_api_version(chronicle_client): expected = {"name": "revisions/r1"} with patch( - "secops.chronicle.integration.manager_revisions.chronicle_request", + "secops.chronicle.soar.integration.manager_revisions.chronicle_request", return_value=expected, ) as mock_request: result = get_integration_manager_revision( diff --git a/tests/chronicle/integration/test_managers.py b/tests/chronicle/soar/integration/test_managers.py similarity index 88% rename from tests/chronicle/integration/test_managers.py rename to tests/chronicle/soar/integration/test_managers.py index c6bf5c4a..4ee5cea2 100644 --- a/tests/chronicle/integration/test_managers.py +++ b/tests/chronicle/soar/integration/test_managers.py @@ -20,7 +20,7 @@ from secops.chronicle.client import ChronicleClient from secops.chronicle.models import APIVersion -from secops.chronicle.integration.managers import ( +from secops.chronicle.soar.integration.managers import ( list_integration_managers, get_integration_manager, delete_integration_manager, @@ -53,10 +53,10 @@ def test_list_integration_managers_success(chronicle_client): expected = {"managers": [{"name": "m1"}, {"name": "m2"}], "nextPageToken": "t"} with patch( - "secops.chronicle.integration.managers.chronicle_paginated_request", + "secops.chronicle.soar.integration.managers.chronicle_paginated_request", return_value=expected, ) as mock_paginated, patch( - "secops.chronicle.integration.managers.format_resource_id", + "secops.chronicle.soar.integration.managers.format_resource_id", return_value="My Integration", ): result = list_integration_managers( @@ -85,7 +85,7 @@ def test_list_integration_managers_default_args(chronicle_client): expected = {"managers": []} with patch( - "secops.chronicle.integration.managers.chronicle_paginated_request", + "secops.chronicle.soar.integration.managers.chronicle_paginated_request", return_value=expected, ) as mock_paginated: result = list_integration_managers( @@ -101,7 +101,7 @@ def test_list_integration_managers_with_filters(chronicle_client): expected = {"managers": [{"name": "m1"}]} with patch( - "secops.chronicle.integration.managers.chronicle_paginated_request", + "secops.chronicle.soar.integration.managers.chronicle_paginated_request", return_value=expected, ) as mock_paginated: result = list_integration_managers( @@ -125,7 +125,7 @@ def test_list_integration_managers_as_list(chronicle_client): expected = [{"name": "m1"}, {"name": "m2"}] with patch( - "secops.chronicle.integration.managers.chronicle_paginated_request", + "secops.chronicle.soar.integration.managers.chronicle_paginated_request", return_value=expected, ) as mock_paginated: result = list_integration_managers( @@ -143,7 +143,7 @@ def test_list_integration_managers_as_list(chronicle_client): def test_list_integration_managers_error(chronicle_client): """Test list_integration_managers raises APIError on failure.""" with patch( - "secops.chronicle.integration.managers.chronicle_paginated_request", + "secops.chronicle.soar.integration.managers.chronicle_paginated_request", side_effect=APIError("Failed to list integration managers"), ): with pytest.raises(APIError) as exc_info: @@ -166,7 +166,7 @@ def test_get_integration_manager_success(chronicle_client): } with patch( - "secops.chronicle.integration.managers.chronicle_request", + "secops.chronicle.soar.integration.managers.chronicle_request", return_value=expected, ) as mock_request: result = get_integration_manager( @@ -188,7 +188,7 @@ def test_get_integration_manager_success(chronicle_client): def test_get_integration_manager_error(chronicle_client): """Test get_integration_manager raises APIError on failure.""" with patch( - "secops.chronicle.integration.managers.chronicle_request", + "secops.chronicle.soar.integration.managers.chronicle_request", side_effect=APIError("Failed to get integration manager"), ): with pytest.raises(APIError) as exc_info: @@ -206,7 +206,7 @@ def test_get_integration_manager_error(chronicle_client): def test_delete_integration_manager_success(chronicle_client): """Test delete_integration_manager issues DELETE request.""" with patch( - "secops.chronicle.integration.managers.chronicle_request", + "secops.chronicle.soar.integration.managers.chronicle_request", return_value=None, ) as mock_request: delete_integration_manager( @@ -226,7 +226,7 @@ def test_delete_integration_manager_success(chronicle_client): def test_delete_integration_manager_error(chronicle_client): """Test delete_integration_manager raises APIError on failure.""" with patch( - "secops.chronicle.integration.managers.chronicle_request", + "secops.chronicle.soar.integration.managers.chronicle_request", side_effect=APIError("Failed to delete integration manager"), ): with pytest.raises(APIError) as exc_info: @@ -246,7 +246,7 @@ def test_create_integration_manager_required_fields_only(chronicle_client): expected = {"name": "managers/new", "displayName": "My Manager"} with patch( - "secops.chronicle.integration.managers.chronicle_request", + "secops.chronicle.soar.integration.managers.chronicle_request", return_value=expected, ) as mock_request: result = create_integration_manager( @@ -275,7 +275,7 @@ def test_create_integration_manager_with_description(chronicle_client): expected = {"name": "managers/new", "displayName": "My Manager"} with patch( - "secops.chronicle.integration.managers.chronicle_request", + "secops.chronicle.soar.integration.managers.chronicle_request", return_value=expected, ) as mock_request: result = create_integration_manager( @@ -295,7 +295,7 @@ def test_create_integration_manager_with_description(chronicle_client): def test_create_integration_manager_error(chronicle_client): """Test create_integration_manager raises APIError on failure.""" with patch( - "secops.chronicle.integration.managers.chronicle_request", + "secops.chronicle.soar.integration.managers.chronicle_request", side_effect=APIError("Failed to create integration manager"), ): with pytest.raises(APIError) as exc_info: @@ -316,10 +316,10 @@ def test_update_integration_manager_single_field(chronicle_client): expected = {"name": "managers/m1", "displayName": "Updated Manager"} with patch( - "secops.chronicle.integration.managers.chronicle_request", + "secops.chronicle.soar.integration.managers.chronicle_request", return_value=expected, ) as mock_request, patch( - "secops.chronicle.integration.managers.build_patch_body", + "secops.chronicle.soar.integration.managers.build_patch_body", return_value=({"displayName": "Updated Manager"}, {"updateMask": "displayName"}), ) as mock_build_patch: result = update_integration_manager( @@ -347,10 +347,10 @@ def test_update_integration_manager_multiple_fields(chronicle_client): expected = {"name": "managers/m1", "displayName": "Updated Manager"} with patch( - "secops.chronicle.integration.managers.chronicle_request", + "secops.chronicle.soar.integration.managers.chronicle_request", return_value=expected, ) as mock_request, patch( - "secops.chronicle.integration.managers.build_patch_body", + "secops.chronicle.soar.integration.managers.build_patch_body", return_value=( { "displayName": "Updated Manager", @@ -377,10 +377,10 @@ def test_update_integration_manager_with_update_mask(chronicle_client): expected = {"name": "managers/m1", "displayName": "Updated Manager"} with patch( - "secops.chronicle.integration.managers.chronicle_request", + "secops.chronicle.soar.integration.managers.chronicle_request", return_value=expected, ) as mock_request, patch( - "secops.chronicle.integration.managers.build_patch_body", + "secops.chronicle.soar.integration.managers.build_patch_body", return_value=( {"displayName": "Updated Manager"}, {"updateMask": "displayName"}, @@ -400,10 +400,10 @@ def test_update_integration_manager_with_update_mask(chronicle_client): def test_update_integration_manager_error(chronicle_client): """Test update_integration_manager raises APIError on failure.""" with patch( - "secops.chronicle.integration.managers.chronicle_request", + "secops.chronicle.soar.integration.managers.chronicle_request", side_effect=APIError("Failed to update integration manager"), ), patch( - "secops.chronicle.integration.managers.build_patch_body", + "secops.chronicle.soar.integration.managers.build_patch_body", return_value=({"displayName": "Updated"}, {"updateMask": "displayName"}), ): with pytest.raises(APIError) as exc_info: @@ -427,7 +427,7 @@ def test_get_integration_manager_template_success(chronicle_client): } with patch( - "secops.chronicle.integration.managers.chronicle_request", + "secops.chronicle.soar.integration.managers.chronicle_request", return_value=expected, ) as mock_request: result = get_integration_manager_template( @@ -448,7 +448,7 @@ def test_get_integration_manager_template_success(chronicle_client): def test_get_integration_manager_template_error(chronicle_client): """Test get_integration_manager_template raises APIError on failure.""" with patch( - "secops.chronicle.integration.managers.chronicle_request", + "secops.chronicle.soar.integration.managers.chronicle_request", side_effect=APIError("Failed to get integration manager template"), ): with pytest.raises(APIError) as exc_info: From e641c5d712ea139e64470e55a1b2c0c9b45a9bc8 Mon Sep 17 00:00:00 2001 From: PaperMtn Date: Thu, 9 Apr 2026 21:11:00 +0100 Subject: [PATCH 4/8] feat: refactor to use SOAR service --- src/secops/chronicle/soar/service.py | 46 +++++++++---------- .../commands/integration/action_revisions.py | 6 +-- .../cli/commands/integration/actions.py | 14 +++--- .../integration/integration_client.py | 37 +++++++++++++++ .../commands/integration/manager_revisions.py | 8 ++-- .../cli/commands/integration/managers.py | 10 ++-- 6 files changed, 79 insertions(+), 42 deletions(-) diff --git a/src/secops/chronicle/soar/service.py b/src/secops/chronicle/soar/service.py index 1d57ee59..ea77526b 100644 --- a/src/secops/chronicle/soar/service.py +++ b/src/secops/chronicle/soar/service.py @@ -1159,7 +1159,7 @@ def list_integration_actions( APIError: If the API request fails """ return _list_integration_actions( - self, + self._client, integration_name, page_size=page_size, page_token=page_token, @@ -1190,7 +1190,7 @@ def get_integration_action( APIError: If the API request fails """ return _get_integration_action( - self, + self._client, integration_name, action_id, api_version=api_version, @@ -1216,7 +1216,7 @@ def delete_integration_action( APIError: If the API request fails """ return _delete_integration_action( - self, + self._client, integration_name, action_id, api_version=api_version, @@ -1274,7 +1274,7 @@ def create_integration_action( APIError: If the API request fails. """ return _create_integration_action( - self, + self._client, integration_name, display_name, script, @@ -1349,7 +1349,7 @@ def update_integration_action( APIError: If the API request fails. """ return _update_integration_action( - self, + self._client, integration_name, action_id, display_name=display_name, @@ -1403,7 +1403,7 @@ def execute_integration_action_test( APIError: If the API request fails. """ return _execute_integration_action_test( - self, + self._client, integration_name, test_case_id, action, @@ -1439,7 +1439,7 @@ def get_integration_actions_by_environment( APIError: If the API request fails. """ return _get_integration_actions_by_environment( - self, + self._client, integration_name, environments, include_widgets, @@ -1472,7 +1472,7 @@ def get_integration_action_template( APIError: If the API request fails. """ return _get_integration_action_template( - self, + self._client, integration_name, is_async=is_async, api_version=api_version, @@ -1522,7 +1522,7 @@ def list_integration_action_revisions( APIError: If the API request fails. """ return _list_integration_action_revisions( - self, + self._client, integration_name, action_id, page_size=page_size, @@ -1560,7 +1560,7 @@ def delete_integration_action_revision( APIError: If the API request fails. """ return _delete_integration_action_revision( - self, + self._client, integration_name, action_id, revision_id, @@ -1597,7 +1597,7 @@ def create_integration_action_revision( APIError: If the API request fails. """ return _create_integration_action_revision( - self, + self._client, integration_name, action_id, action, @@ -1632,7 +1632,7 @@ def rollback_integration_action_revision( APIError: If the API request fails. """ return _rollback_integration_action_revision( - self, + self._client, integration_name, action_id, revision_id, @@ -1681,7 +1681,7 @@ def list_integration_managers( APIError: If the API request fails. """ return _list_integration_managers( - self, + self._client, integration_name, page_size=page_size, page_token=page_token, @@ -1716,7 +1716,7 @@ def get_integration_manager( APIError: If the API request fails. """ return _get_integration_manager( - self, + self._client, integration_name, manager_id, api_version=api_version, @@ -1747,7 +1747,7 @@ def delete_integration_manager( APIError: If the API request fails. """ return _delete_integration_manager( - self, + self._client, integration_name, manager_id, api_version=api_version, @@ -1786,7 +1786,7 @@ def create_integration_manager( APIError: If the API request fails. """ return _create_integration_manager( - self, + self._client, integration_name, display_name, script, @@ -1831,7 +1831,7 @@ def update_integration_manager( APIError: If the API request fails. """ return _update_integration_manager( - self, + self._client, integration_name, manager_id, display_name=display_name, @@ -1864,7 +1864,7 @@ def get_integration_manager_template( APIError: If the API request fails. """ return _get_integration_manager_template( - self, + self._client, integration_name, api_version=api_version, ) @@ -1912,7 +1912,7 @@ def list_integration_manager_revisions( APIError: If the API request fails. """ return _list_integration_manager_revisions( - self, + self._client, integration_name, manager_id, page_size=page_size, @@ -1951,7 +1951,7 @@ def get_integration_manager_revision( APIError: If the API request fails. """ return _get_integration_manager_revision( - self, + self._client, integration_name, manager_id, revision_id, @@ -1985,7 +1985,7 @@ def delete_integration_manager_revision( APIError: If the API request fails. """ return _delete_integration_manager_revision( - self, + self._client, integration_name, manager_id, revision_id, @@ -2024,7 +2024,7 @@ def create_integration_manager_revision( APIError: If the API request fails. """ return _create_integration_manager_revision( - self, + self._client, integration_name, manager_id, manager, @@ -2062,7 +2062,7 @@ def rollback_integration_manager_revision( APIError: If the API request fails. """ return _rollback_integration_manager_revision( - self, + self._client, integration_name, manager_id, revision_id, diff --git a/src/secops/cli/commands/integration/action_revisions.py b/src/secops/cli/commands/integration/action_revisions.py index d6999bac..cafd82e7 100644 --- a/src/secops/cli/commands/integration/action_revisions.py +++ b/src/secops/cli/commands/integration/action_revisions.py @@ -152,7 +152,7 @@ def setup_action_revisions_command(subparsers): def handle_action_revisions_list_command(args, chronicle): """Handle integration action revisions list command""" try: - out = chronicle.list_integration_action_revisions( + out = chronicle.soar.list_integration_action_revisions( integration_name=args.integration_name, action_id=args.action_id, page_size=args.page_size, @@ -189,7 +189,7 @@ def handle_action_revisions_create_command(args, chronicle): integration_name=args.integration_name, action_id=args.action_id, ) - out = chronicle.create_integration_action_revision( + out = chronicle.soar.create_integration_action_revision( integration_name=args.integration_name, action_id=args.action_id, action=action, @@ -204,7 +204,7 @@ def handle_action_revisions_create_command(args, chronicle): def handle_action_revisions_rollback_command(args, chronicle): """Handle integration action revision rollback command""" try: - out = chronicle.rollback_integration_action_revision( + out = chronicle.soar.rollback_integration_action_revision( integration_name=args.integration_name, action_id=args.action_id, revision_id=args.revision_id, diff --git a/src/secops/cli/commands/integration/actions.py b/src/secops/cli/commands/integration/actions.py index a389c8aa..55776154 100644 --- a/src/secops/cli/commands/integration/actions.py +++ b/src/secops/cli/commands/integration/actions.py @@ -258,7 +258,7 @@ def setup_actions_command(subparsers): def handle_actions_list_command(args, chronicle): """Handle integration actions list command""" try: - out = chronicle.list_integration_actions( + out = chronicle.soar.list_integration_actions( integration_name=args.integration_name, page_size=args.page_size, page_token=args.page_token, @@ -275,7 +275,7 @@ def handle_actions_list_command(args, chronicle): def handle_actions_get_command(args, chronicle): """Handle integration action get command""" try: - out = chronicle.get_integration_action( + out = chronicle.soar.get_integration_action( integration_name=args.integration_name, action_id=args.action_id, ) @@ -301,7 +301,7 @@ def handle_actions_delete_command(args, chronicle): def handle_actions_create_command(args, chronicle): """Handle integration action create command""" try: - out = chronicle.create_integration_action( + out = chronicle.soar.create_integration_action( integration_name=args.integration_name, display_name=args.display_name, script=args.code, # CLI uses --code flag but API expects script @@ -320,7 +320,7 @@ def handle_actions_create_command(args, chronicle): def handle_actions_update_command(args, chronicle): """Handle integration action update command""" try: - out = chronicle.update_integration_action( + out = chronicle.soar.update_integration_action( integration_name=args.integration_name, action_id=args.action_id, display_name=args.display_name, @@ -344,7 +344,7 @@ def handle_actions_test_command(args, chronicle): integration_name=args.integration_name, action_id=args.action_id, ) - out = chronicle.execute_integration_action_test( + out = chronicle.soar.execute_integration_action_test( integration_name=args.integration_name, action_id=args.action_id, action=action, @@ -358,7 +358,7 @@ def handle_actions_test_command(args, chronicle): def handle_actions_by_environment_command(args, chronicle): """Handle get actions by environment command""" try: - out = chronicle.get_integration_actions_by_environment( + out = chronicle.soar.get_integration_actions_by_environment( integration_name=args.integration_name, environments=args.environments, include_widgets=args.include_widgets, @@ -372,7 +372,7 @@ def handle_actions_by_environment_command(args, chronicle): def handle_actions_template_command(args, chronicle): """Handle get action template command""" try: - out = chronicle.get_integration_action_template( + out = chronicle.soar.get_integration_action_template( integration_name=args.integration_name, is_async=args.is_async, ) diff --git a/src/secops/cli/commands/integration/integration_client.py b/src/secops/cli/commands/integration/integration_client.py index 581bfb29..4c22e111 100644 --- a/src/secops/cli/commands/integration/integration_client.py +++ b/src/secops/cli/commands/integration/integration_client.py @@ -15,10 +15,27 @@ """Top level arguments for integration commands""" from secops.cli.commands.integration import ( + marketplace_integration, + integration, actions, action_revisions, + # connectors, + # connector_revisions, + # connector_context_properties, + # connector_instance_logs, + # connector_instances, + # jobs, + # job_revisions, + # job_context_properties, + # job_instance_logs, + # job_instances, managers, manager_revisions, + integration_instances, + # transformers, + # transformer_revisions, + # logical_operators, + # logical_operator_revisions, ) @@ -32,7 +49,27 @@ def setup_integrations_command(subparsers): ) # Setup all subcommands under `integration` + integration.setup_integrations_command(lvl1) + integration_instances.setup_integration_instances_command(lvl1) + # transformers.setup_transformers_command(lvl1) + # transformer_revisions.setup_transformer_revisions_command(lvl1) + # logical_operators.setup_logical_operators_command(lvl1) + # logical_operator_revisions.setup_logical_operator_revisions_command(lvl1) actions.setup_actions_command(lvl1) action_revisions.setup_action_revisions_command(lvl1) + # connectors.setup_connectors_command(lvl1) + # connector_revisions.setup_connector_revisions_command(lvl1) + # connector_context_properties.setup_connector_context_properties_command( + # lvl1 + # ) + # connector_instance_logs.setup_connector_instance_logs_command(lvl1) + # connector_instances.setup_connector_instances_command(lvl1) + # jobs.setup_jobs_command(lvl1) + # job_revisions.setup_job_revisions_command(lvl1) + # job_context_properties.setup_job_context_properties_command(lvl1) + # job_instance_logs.setup_job_instance_logs_command(lvl1) + # job_instances.setup_job_instances_command(lvl1) managers.setup_managers_command(lvl1) manager_revisions.setup_manager_revisions_command(lvl1) + marketplace_integration.setup_marketplace_integrations_command(lvl1) + diff --git a/src/secops/cli/commands/integration/manager_revisions.py b/src/secops/cli/commands/integration/manager_revisions.py index 82116abe..4ee766c5 100644 --- a/src/secops/cli/commands/integration/manager_revisions.py +++ b/src/secops/cli/commands/integration/manager_revisions.py @@ -177,7 +177,7 @@ def setup_manager_revisions_command(subparsers): def handle_manager_revisions_list_command(args, chronicle): """Handle integration manager revisions list command""" try: - out = chronicle.list_integration_manager_revisions( + out = chronicle.soar.list_integration_manager_revisions( integration_name=args.integration_name, manager_id=args.manager_id, page_size=args.page_size, @@ -195,7 +195,7 @@ def handle_manager_revisions_list_command(args, chronicle): def handle_manager_revisions_get_command(args, chronicle): """Handle integration manager revision get command""" try: - out = chronicle.get_integration_manager_revision( + out = chronicle.soar.get_integration_manager_revision( integration_name=args.integration_name, manager_id=args.manager_id, revision_id=args.revision_id, @@ -228,7 +228,7 @@ def handle_manager_revisions_create_command(args, chronicle): integration_name=args.integration_name, manager_id=args.manager_id, ) - out = chronicle.create_integration_manager_revision( + out = chronicle.soar.create_integration_manager_revision( integration_name=args.integration_name, manager_id=args.manager_id, manager=manager, @@ -243,7 +243,7 @@ def handle_manager_revisions_create_command(args, chronicle): def handle_manager_revisions_rollback_command(args, chronicle): """Handle integration manager revision rollback command""" try: - out = chronicle.rollback_integration_manager_revision( + out = chronicle.soar.rollback_integration_manager_revision( integration_name=args.integration_name, manager_id=args.manager_id, revision_id=args.revision_id, diff --git a/src/secops/cli/commands/integration/managers.py b/src/secops/cli/commands/integration/managers.py index e5f202a0..37ee1d56 100644 --- a/src/secops/cli/commands/integration/managers.py +++ b/src/secops/cli/commands/integration/managers.py @@ -198,7 +198,7 @@ def setup_managers_command(subparsers): def handle_managers_list_command(args, chronicle): """Handle integration managers list command""" try: - out = chronicle.list_integration_managers( + out = chronicle.soar.list_integration_managers( integration_name=args.integration_name, page_size=args.page_size, page_token=args.page_token, @@ -215,7 +215,7 @@ def handle_managers_list_command(args, chronicle): def handle_managers_get_command(args, chronicle): """Handle integration manager get command""" try: - out = chronicle.get_integration_manager( + out = chronicle.soar.get_integration_manager( integration_name=args.integration_name, manager_id=args.manager_id, ) @@ -241,7 +241,7 @@ def handle_managers_delete_command(args, chronicle): def handle_managers_create_command(args, chronicle): """Handle integration manager create command""" try: - out = chronicle.create_integration_manager( + out = chronicle.soar.create_integration_manager( integration_name=args.integration_name, display_name=args.display_name, code=args.code, @@ -257,7 +257,7 @@ def handle_managers_create_command(args, chronicle): def handle_managers_update_command(args, chronicle): """Handle integration manager update command""" try: - out = chronicle.update_integration_manager( + out = chronicle.soar.update_integration_manager( integration_name=args.integration_name, manager_id=args.manager_id, display_name=args.display_name, @@ -274,7 +274,7 @@ def handle_managers_update_command(args, chronicle): def handle_managers_template_command(args, chronicle): """Handle get manager template command""" try: - out = chronicle.get_integration_manager_template( + out = chronicle.soar.get_integration_manager_template( integration_name=args.integration_name, ) output_formatter(out, getattr(args, "output", "json")) From 94f8816f94bd9c2941989262fbeb0366894c2794 Mon Sep 17 00:00:00 2001 From: PaperMtn Date: Fri, 10 Apr 2026 07:56:06 +0100 Subject: [PATCH 5/8] chore: implement helper functions --- .../soar/integration/action_revisions.py | 12 ++++----- .../chronicle/soar/integration/actions.py | 15 ++++------- .../soar/integration/integrations.py | 27 +++++++++---------- .../soar/integration/manager_revisions.py | 8 +++--- .../chronicle/soar/integration/managers.py | 8 +++--- 5 files changed, 29 insertions(+), 41 deletions(-) diff --git a/src/secops/chronicle/soar/integration/action_revisions.py b/src/secops/chronicle/soar/integration/action_revisions.py index b5229b3c..8b6d6bb9 100644 --- a/src/secops/chronicle/soar/integration/action_revisions.py +++ b/src/secops/chronicle/soar/integration/action_revisions.py @@ -17,7 +17,10 @@ from typing import Any, TYPE_CHECKING from secops.chronicle.models import APIVersion -from secops.chronicle.utils.format_utils import format_resource_id +from secops.chronicle.utils.format_utils import ( + format_resource_id, + remove_none_values, +) from secops.chronicle.utils.request_utils import ( chronicle_paginated_request, chronicle_request, @@ -62,13 +65,10 @@ def list_integration_action_revisions( Raises: APIError: If the API request fails. """ - extra_params = { + extra_params = remove_none_values({ "filter": filter_string, "orderBy": order_by, - } - - # Remove keys with None values - extra_params = {k: v for k, v in extra_params.items() if v is not None} + }) return chronicle_paginated_request( client, diff --git a/src/secops/chronicle/soar/integration/actions.py b/src/secops/chronicle/soar/integration/actions.py index d52ba28b..b613806c 100644 --- a/src/secops/chronicle/soar/integration/actions.py +++ b/src/secops/chronicle/soar/integration/actions.py @@ -20,6 +20,7 @@ from secops.chronicle.utils.format_utils import ( format_resource_id, build_patch_body, + remove_none_values, ) from secops.chronicle.utils.request_utils import ( chronicle_paginated_request, @@ -62,14 +63,11 @@ def list_integration_actions( Raises: APIError: If the API request fails """ - field_map = { + field_map = remove_none_values({ "filter": filter_string, "orderBy": order_by, "expand": expand, - } - - # Remove keys with None values - field_map = {k: v for k, v in field_map.items() if v is not None} + }) return chronicle_paginated_request( client, @@ -200,7 +198,7 @@ def create_integration_action( else None ) - body = { + body = remove_none_values({ "displayName": display_name, "script": script, "timeoutSeconds": timeout_seconds, @@ -214,10 +212,7 @@ def create_integration_action( "dynamicResults": dynamic_results, "parameters": resolved_parameters, "aiGenerated": ai_generated, - } - - # Remove keys with None values - body = {k: v for k, v in body.items() if v is not None} + }) return chronicle_request( client, diff --git a/src/secops/chronicle/soar/integration/integrations.py b/src/secops/chronicle/soar/integration/integrations.py index 54f659f1..46e6f19e 100644 --- a/src/secops/chronicle/soar/integration/integrations.py +++ b/src/secops/chronicle/soar/integration/integrations.py @@ -68,13 +68,10 @@ def list_integrations( Raises: APIError: If the API request fails """ - param_fields = { + param_fields = remove_none_values({ "filter": filter_string, "orderBy": order_by, - } - - # Remove keys with None values - param_fields = {k: v for k, v in param_fields.items() if v is not None} + }) return chronicle_paginated_request( client, @@ -290,16 +287,16 @@ def export_integration_items( integration_name: name of the integration to export items from actions: Optional. IDs of the actions to export as a list or comma-separated string. Format: [1,2,3] or "1,2,3" - jobs: Optional. IDs of the jobs to export as a list or - comma-separated string. - connectors: Optional. IDs of the connectors to export as a - list or comma-separated string. - managers: Optional. IDs of the managers to export as a list - or comma-separated string. - transformers: Optional. IDs of the transformers to export as - a list or comma-separated string. - logical_operators: Optional. IDs of the logical operators to - export as a list or comma-separated string. + jobs: Optional. IDs of the jobs to export as a list or + comma-separated string. + connectors: Optional. IDs of the connectors to export as a + list or comma-separated string. + managers: Optional. IDs of the managers to export as a list + or comma-separated string. + transformers: Optional. IDs of the transformers to export as + a list or comma-separated string. + logical_operators: Optional. IDs of the logical operators to + export as a list or comma-separated string. api_version: API version to use for the request. Default is V1BETA. Returns: diff --git a/src/secops/chronicle/soar/integration/manager_revisions.py b/src/secops/chronicle/soar/integration/manager_revisions.py index 644a8490..b7e9acee 100644 --- a/src/secops/chronicle/soar/integration/manager_revisions.py +++ b/src/secops/chronicle/soar/integration/manager_revisions.py @@ -19,6 +19,7 @@ from secops.chronicle.models import APIVersion from secops.chronicle.utils.format_utils import ( format_resource_id, + remove_none_values ) from secops.chronicle.utils.request_utils import ( chronicle_paginated_request, @@ -64,13 +65,10 @@ def list_integration_manager_revisions( Raises: APIError: If the API request fails. """ - extra_params = { + extra_params = remove_none_values({ "filter": filter_string, "orderBy": order_by, - } - - # Remove keys with None values - extra_params = {k: v for k, v in extra_params.items() if v is not None} + }) return chronicle_paginated_request( client, diff --git a/src/secops/chronicle/soar/integration/managers.py b/src/secops/chronicle/soar/integration/managers.py index ced5b199..acdd72a0 100644 --- a/src/secops/chronicle/soar/integration/managers.py +++ b/src/secops/chronicle/soar/integration/managers.py @@ -20,6 +20,7 @@ from secops.chronicle.utils.format_utils import ( format_resource_id, build_patch_body, + remove_none_values ) from secops.chronicle.utils.request_utils import ( chronicle_paginated_request, @@ -64,13 +65,10 @@ def list_integration_managers( Raises: APIError: If the API request fails. """ - extra_params = { + extra_params = remove_none_values({ "filter": filter_string, "orderBy": order_by, - } - - # Remove keys with None values - extra_params = {k: v for k, v in extra_params.items() if v is not None} + }) return chronicle_paginated_request( client, From c4dd091480d91634c601c3ade9e1c2eb3f5c45b7 Mon Sep 17 00:00:00 2001 From: PaperMtn Date: Fri, 10 Apr 2026 07:57:41 +0100 Subject: [PATCH 6/8] chore: black formatting --- .../soar/integration/action_revisions.py | 10 +- .../chronicle/soar/integration/actions.py | 44 +-- .../soar/integration/integrations.py | 10 +- .../soar/integration/manager_revisions.py | 12 +- .../chronicle/soar/integration/managers.py | 12 +- src/secops/chronicle/soar/service.py | 310 +++++++++--------- 6 files changed, 205 insertions(+), 193 deletions(-) diff --git a/src/secops/chronicle/soar/integration/action_revisions.py b/src/secops/chronicle/soar/integration/action_revisions.py index 8b6d6bb9..ac5878e0 100644 --- a/src/secops/chronicle/soar/integration/action_revisions.py +++ b/src/secops/chronicle/soar/integration/action_revisions.py @@ -65,10 +65,12 @@ def list_integration_action_revisions( Raises: APIError: If the API request fails. """ - extra_params = remove_none_values({ - "filter": filter_string, - "orderBy": order_by, - }) + extra_params = remove_none_values( + { + "filter": filter_string, + "orderBy": order_by, + } + ) return chronicle_paginated_request( client, diff --git a/src/secops/chronicle/soar/integration/actions.py b/src/secops/chronicle/soar/integration/actions.py index b613806c..810a5d04 100644 --- a/src/secops/chronicle/soar/integration/actions.py +++ b/src/secops/chronicle/soar/integration/actions.py @@ -63,11 +63,13 @@ def list_integration_actions( Raises: APIError: If the API request fails """ - field_map = remove_none_values({ - "filter": filter_string, - "orderBy": order_by, - "expand": expand, - }) + field_map = remove_none_values( + { + "filter": filter_string, + "orderBy": order_by, + "expand": expand, + } + ) return chronicle_paginated_request( client, @@ -198,21 +200,23 @@ def create_integration_action( else None ) - body = remove_none_values({ - "displayName": display_name, - "script": script, - "timeoutSeconds": timeout_seconds, - "enabled": enabled, - "scriptResultName": script_result_name, - "async": is_async, - "description": description, - "defaultResultValue": default_result_value, - "asyncPollingIntervalSeconds": async_polling_interval_seconds, - "asyncTotalTimeoutSeconds": async_total_timeout_seconds, - "dynamicResults": dynamic_results, - "parameters": resolved_parameters, - "aiGenerated": ai_generated, - }) + body = remove_none_values( + { + "displayName": display_name, + "script": script, + "timeoutSeconds": timeout_seconds, + "enabled": enabled, + "scriptResultName": script_result_name, + "async": is_async, + "description": description, + "defaultResultValue": default_result_value, + "asyncPollingIntervalSeconds": async_polling_interval_seconds, + "asyncTotalTimeoutSeconds": async_total_timeout_seconds, + "dynamicResults": dynamic_results, + "parameters": resolved_parameters, + "aiGenerated": ai_generated, + } + ) return chronicle_request( client, diff --git a/src/secops/chronicle/soar/integration/integrations.py b/src/secops/chronicle/soar/integration/integrations.py index 46e6f19e..a5b1e7a9 100644 --- a/src/secops/chronicle/soar/integration/integrations.py +++ b/src/secops/chronicle/soar/integration/integrations.py @@ -68,10 +68,12 @@ def list_integrations( Raises: APIError: If the API request fails """ - param_fields = remove_none_values({ - "filter": filter_string, - "orderBy": order_by, - }) + param_fields = remove_none_values( + { + "filter": filter_string, + "orderBy": order_by, + } + ) return chronicle_paginated_request( client, diff --git a/src/secops/chronicle/soar/integration/manager_revisions.py b/src/secops/chronicle/soar/integration/manager_revisions.py index b7e9acee..1da13a88 100644 --- a/src/secops/chronicle/soar/integration/manager_revisions.py +++ b/src/secops/chronicle/soar/integration/manager_revisions.py @@ -19,7 +19,7 @@ from secops.chronicle.models import APIVersion from secops.chronicle.utils.format_utils import ( format_resource_id, - remove_none_values + remove_none_values, ) from secops.chronicle.utils.request_utils import ( chronicle_paginated_request, @@ -65,10 +65,12 @@ def list_integration_manager_revisions( Raises: APIError: If the API request fails. """ - extra_params = remove_none_values({ - "filter": filter_string, - "orderBy": order_by, - }) + extra_params = remove_none_values( + { + "filter": filter_string, + "orderBy": order_by, + } + ) return chronicle_paginated_request( client, diff --git a/src/secops/chronicle/soar/integration/managers.py b/src/secops/chronicle/soar/integration/managers.py index acdd72a0..fe016fe8 100644 --- a/src/secops/chronicle/soar/integration/managers.py +++ b/src/secops/chronicle/soar/integration/managers.py @@ -20,7 +20,7 @@ from secops.chronicle.utils.format_utils import ( format_resource_id, build_patch_body, - remove_none_values + remove_none_values, ) from secops.chronicle.utils.request_utils import ( chronicle_paginated_request, @@ -65,10 +65,12 @@ def list_integration_managers( Raises: APIError: If the API request fails. """ - extra_params = remove_none_values({ - "filter": filter_string, - "orderBy": order_by, - }) + extra_params = remove_none_values( + { + "filter": filter_string, + "orderBy": order_by, + } + ) return chronicle_paginated_request( client, diff --git a/src/secops/chronicle/soar/service.py b/src/secops/chronicle/soar/service.py index ea77526b..ead75620 100644 --- a/src/secops/chronicle/soar/service.py +++ b/src/secops/chronicle/soar/service.py @@ -1128,15 +1128,15 @@ def get_default_integration_instance( # ------------------------------------------------------------------------- def list_integration_actions( - self, - integration_name: str, - page_size: int | None = None, - page_token: str | None = None, - filter_string: str | None = None, - order_by: str | None = None, - expand: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - as_list: bool = False, + self, + integration_name: str, + page_size: int | None = None, + page_token: str | None = None, + filter_string: str | None = None, + order_by: str | None = None, + expand: str | None = None, + api_version: APIVersion | None = APIVersion.V1BETA, + as_list: bool = False, ) -> dict[str, Any] | list[dict[str, Any]]: """Get a list of actions for a given integration. @@ -1171,10 +1171,10 @@ def list_integration_actions( ) def get_integration_action( - self, - integration_name: str, - action_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, + self, + integration_name: str, + action_id: str, + api_version: APIVersion | None = APIVersion.V1BETA, ) -> dict[str, Any]: """Get details of a specific action for a given integration. @@ -1197,10 +1197,10 @@ def get_integration_action( ) def delete_integration_action( - self, - integration_name: str, - action_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, + self, + integration_name: str, + action_id: str, + api_version: APIVersion | None = APIVersion.V1BETA, ) -> None: """Delete a specific action from a given integration. @@ -1223,22 +1223,22 @@ def delete_integration_action( ) def create_integration_action( - self, - integration_name: str, - display_name: str, - script: str, - timeout_seconds: int, - enabled: bool, - script_result_name: str, - is_async: bool, - description: str | None = None, - default_result_value: str | None = None, - async_polling_interval_seconds: int | None = None, - async_total_timeout_seconds: int | None = None, - dynamic_results: list[dict[str, Any]] | None = None, - parameters: list[dict[str, Any]] | None = None, - ai_generated: bool | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, + self, + integration_name: str, + display_name: str, + script: str, + timeout_seconds: int, + enabled: bool, + script_result_name: str, + is_async: bool, + description: str | None = None, + default_result_value: str | None = None, + async_polling_interval_seconds: int | None = None, + async_total_timeout_seconds: int | None = None, + dynamic_results: list[dict[str, Any]] | None = None, + parameters: list[dict[str, Any]] | None = None, + ai_generated: bool | None = None, + api_version: APIVersion | None = APIVersion.V1BETA, ) -> dict[str, Any]: """Create a new custom action for a given integration. @@ -1293,24 +1293,24 @@ def create_integration_action( ) def update_integration_action( - self, - integration_name: str, - action_id: str, - display_name: str | None = None, - script: str | None = None, - timeout_seconds: int | None = None, - enabled: bool | None = None, - script_result_name: str | None = None, - is_async: bool | None = None, - description: str | None = None, - default_result_value: str | None = None, - async_polling_interval_seconds: int | None = None, - async_total_timeout_seconds: int | None = None, - dynamic_results: list[dict[str, Any]] | None = None, - parameters: list[dict[str, Any]] | None = None, - ai_generated: bool | None = None, - update_mask: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, + self, + integration_name: str, + action_id: str, + display_name: str | None = None, + script: str | None = None, + timeout_seconds: int | None = None, + enabled: bool | None = None, + script_result_name: str | None = None, + is_async: bool | None = None, + description: str | None = None, + default_result_value: str | None = None, + async_polling_interval_seconds: int | None = None, + async_total_timeout_seconds: int | None = None, + dynamic_results: list[dict[str, Any]] | None = None, + parameters: list[dict[str, Any]] | None = None, + ai_generated: bool | None = None, + update_mask: str | None = None, + api_version: APIVersion | None = APIVersion.V1BETA, ) -> dict[str, Any]: """Update an existing custom action for a given integration. @@ -1370,13 +1370,13 @@ def update_integration_action( ) def execute_integration_action_test( - self, - integration_name: str, - test_case_id: int, - action: dict[str, Any], - scope: str, - integration_instance_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, + self, + integration_name: str, + test_case_id: int, + action: dict[str, Any], + scope: str, + integration_instance_id: str, + api_version: APIVersion | None = APIVersion.V1BETA, ) -> dict[str, Any]: """Execute a test run of an integration action's script. @@ -1413,11 +1413,11 @@ def execute_integration_action_test( ) def get_integration_actions_by_environment( - self, - integration_name: str, - environments: list[str], - include_widgets: bool, - api_version: APIVersion | None = APIVersion.V1BETA, + self, + integration_name: str, + environments: list[str], + include_widgets: bool, + api_version: APIVersion | None = APIVersion.V1BETA, ) -> dict[str, Any]: """List actions executable within specified environments. @@ -1447,10 +1447,10 @@ def get_integration_actions_by_environment( ) def get_integration_action_template( - self, - integration_name: str, - is_async: bool = False, - api_version: APIVersion | None = APIVersion.V1BETA, + self, + integration_name: str, + is_async: bool = False, + api_version: APIVersion | None = APIVersion.V1BETA, ) -> dict[str, Any]: """Retrieve a default Python script template for a new integration action. @@ -1483,15 +1483,15 @@ def get_integration_action_template( # ------------------------------------------------------------------------- def list_integration_action_revisions( - self, - integration_name: str, - action_id: str, - page_size: int | None = None, - page_token: str | None = None, - filter_string: str | None = None, - order_by: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - as_list: bool = False, + self, + integration_name: str, + action_id: str, + page_size: int | None = None, + page_token: str | None = None, + filter_string: str | None = None, + order_by: str | None = None, + api_version: APIVersion | None = APIVersion.V1BETA, + as_list: bool = False, ) -> dict[str, Any] | list[dict[str, Any]]: """List all revisions for a specific integration action. @@ -1534,11 +1534,11 @@ def list_integration_action_revisions( ) def delete_integration_action_revision( - self, - integration_name: str, - action_id: str, - revision_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, + self, + integration_name: str, + action_id: str, + revision_id: str, + api_version: APIVersion | None = APIVersion.V1BETA, ) -> None: """Delete a specific action revision. @@ -1568,12 +1568,12 @@ def delete_integration_action_revision( ) def create_integration_action_revision( - self, - integration_name: str, - action_id: str, - action: dict[str, Any], - comment: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, + self, + integration_name: str, + action_id: str, + action: dict[str, Any], + comment: str | None = None, + api_version: APIVersion | None = APIVersion.V1BETA, ) -> dict[str, Any]: """Create a new revision for an integration action. @@ -1606,11 +1606,11 @@ def create_integration_action_revision( ) def rollback_integration_action_revision( - self, - integration_name: str, - action_id: str, - revision_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, + self, + integration_name: str, + action_id: str, + revision_id: str, + api_version: APIVersion | None = APIVersion.V1BETA, ) -> dict[str, Any]: """Rollback an integration action to a previous revision. @@ -1644,14 +1644,14 @@ def rollback_integration_action_revision( # ------------------------------------------------------------------------- def list_integration_managers( - self, - integration_name: str, - page_size: int | None = None, - page_token: str | None = None, - filter_string: str | None = None, - order_by: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - as_list: bool = False, + self, + integration_name: str, + page_size: int | None = None, + page_token: str | None = None, + filter_string: str | None = None, + order_by: str | None = None, + api_version: APIVersion | None = APIVersion.V1BETA, + as_list: bool = False, ) -> dict[str, Any] | list[dict[str, Any]]: """List all managers defined for a specific integration. @@ -1692,10 +1692,10 @@ def list_integration_managers( ) def get_integration_manager( - self, - integration_name: str, - manager_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, + self, + integration_name: str, + manager_id: str, + api_version: APIVersion | None = APIVersion.V1BETA, ) -> dict[str, Any]: """Get a single manager for a given integration. @@ -1723,10 +1723,10 @@ def get_integration_manager( ) def delete_integration_manager( - self, - integration_name: str, - manager_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, + self, + integration_name: str, + manager_id: str, + api_version: APIVersion | None = APIVersion.V1BETA, ) -> None: """Delete a specific custom manager from a given integration. @@ -1754,12 +1754,12 @@ def delete_integration_manager( ) def create_integration_manager( - self, - integration_name: str, - display_name: str, - script: str, - description: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, + self, + integration_name: str, + display_name: str, + script: str, + description: str | None = None, + api_version: APIVersion | None = APIVersion.V1BETA, ) -> dict[str, Any]: """Create a new custom manager for a given integration. @@ -1795,14 +1795,14 @@ def create_integration_manager( ) def update_integration_manager( - self, - integration_name: str, - manager_id: str, - display_name: str | None = None, - script: str | None = None, - description: str | None = None, - update_mask: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, + self, + integration_name: str, + manager_id: str, + display_name: str | None = None, + script: str | None = None, + description: str | None = None, + update_mask: str | None = None, + api_version: APIVersion | None = APIVersion.V1BETA, ) -> dict[str, Any]: """Update an existing custom manager for a given integration. @@ -1842,9 +1842,9 @@ def update_integration_manager( ) def get_integration_manager_template( - self, - integration_name: str, - api_version: APIVersion | None = APIVersion.V1BETA, + self, + integration_name: str, + api_version: APIVersion | None = APIVersion.V1BETA, ) -> dict[str, Any]: """Retrieve a default Python script template for a new integration manager. @@ -1874,15 +1874,15 @@ def get_integration_manager_template( # ------------------------------------------------------------------------- def list_integration_manager_revisions( - self, - integration_name: str, - manager_id: str, - page_size: int | None = None, - page_token: str | None = None, - filter_string: str | None = None, - order_by: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, - as_list: bool = False, + self, + integration_name: str, + manager_id: str, + page_size: int | None = None, + page_token: str | None = None, + filter_string: str | None = None, + order_by: str | None = None, + api_version: APIVersion | None = APIVersion.V1BETA, + as_list: bool = False, ) -> dict[str, Any] | list[dict[str, Any]]: """List all revisions for a specific integration manager. @@ -1924,11 +1924,11 @@ def list_integration_manager_revisions( ) def get_integration_manager_revision( - self, - integration_name: str, - manager_id: str, - revision_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, + self, + integration_name: str, + manager_id: str, + revision_id: str, + api_version: APIVersion | None = APIVersion.V1BETA, ) -> dict[str, Any]: """Get a single revision for a specific integration manager. @@ -1959,11 +1959,11 @@ def get_integration_manager_revision( ) def delete_integration_manager_revision( - self, - integration_name: str, - manager_id: str, - revision_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, + self, + integration_name: str, + manager_id: str, + revision_id: str, + api_version: APIVersion | None = APIVersion.V1BETA, ) -> None: """Delete a specific revision for a given integration manager. @@ -1993,12 +1993,12 @@ def delete_integration_manager_revision( ) def create_integration_manager_revision( - self, - integration_name: str, - manager_id: str, - manager: dict[str, Any], - comment: str | None = None, - api_version: APIVersion | None = APIVersion.V1BETA, + self, + integration_name: str, + manager_id: str, + manager: dict[str, Any], + comment: str | None = None, + api_version: APIVersion | None = APIVersion.V1BETA, ) -> dict[str, Any]: """Create a new revision snapshot of the current integration manager. @@ -2033,11 +2033,11 @@ def create_integration_manager_revision( ) def rollback_integration_manager_revision( - self, - integration_name: str, - manager_id: str, - revision_id: str, - api_version: APIVersion | None = APIVersion.V1BETA, + self, + integration_name: str, + manager_id: str, + revision_id: str, + api_version: APIVersion | None = APIVersion.V1BETA, ) -> dict[str, Any]: """Revert the current manager definition to a previously saved revision. From ab3373870525849ff9c83dbdeac7dbdf22f766f5 Mon Sep 17 00:00:00 2001 From: PaperMtn Date: Fri, 10 Apr 2026 08:01:08 +0100 Subject: [PATCH 7/8] chore: fix incorrect return types --- src/secops/chronicle/soar/integration/integrations.py | 2 +- src/secops/chronicle/soar/service.py | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/secops/chronicle/soar/integration/integrations.py b/src/secops/chronicle/soar/integration/integrations.py index a5b1e7a9..88501380 100644 --- a/src/secops/chronicle/soar/integration/integrations.py +++ b/src/secops/chronicle/soar/integration/integrations.py @@ -486,7 +486,7 @@ def get_integration_restricted_agents( def get_integration_diff( client: "ChronicleClient", integration_name: str, - diff_type: DiffType = DiffType.COMMERCIAL, + diff_type: DiffType | None = DiffType.COMMERCIAL, api_version: APIVersion | None = APIVersion.V1BETA, ) -> dict[str, Any]: """Get the configuration diff of a specific integration. diff --git a/src/secops/chronicle/soar/service.py b/src/secops/chronicle/soar/service.py index ead75620..bd3fee7a 100644 --- a/src/secops/chronicle/soar/service.py +++ b/src/secops/chronicle/soar/service.py @@ -905,7 +905,7 @@ def delete_integration_instance( Raises: APIError: If the API request fails. """ - return _delete_integration_instance( + _delete_integration_instance( self._client, integration_name, integration_instance_id, @@ -1215,7 +1215,7 @@ def delete_integration_action( Raises: APIError: If the API request fails """ - return _delete_integration_action( + _delete_integration_action( self._client, integration_name, action_id, @@ -1559,7 +1559,7 @@ def delete_integration_action_revision( Raises: APIError: If the API request fails. """ - return _delete_integration_action_revision( + _delete_integration_action_revision( self._client, integration_name, action_id, @@ -1746,7 +1746,7 @@ def delete_integration_manager( Raises: APIError: If the API request fails. """ - return _delete_integration_manager( + _delete_integration_manager( self._client, integration_name, manager_id, @@ -1984,7 +1984,7 @@ def delete_integration_manager_revision( Raises: APIError: If the API request fails. """ - return _delete_integration_manager_revision( + _delete_integration_manager_revision( self._client, integration_name, manager_id, From 53f94a9efcfc0f2367537d83ad08dc560a5111b3 Mon Sep 17 00:00:00 2001 From: PaperMtn Date: Fri, 10 Apr 2026 11:04:38 +0100 Subject: [PATCH 8/8] fix: fix incorrect function path --- src/secops/cli/commands/integration/action_revisions.py | 4 ++-- src/secops/cli/commands/integration/actions.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/secops/cli/commands/integration/action_revisions.py b/src/secops/cli/commands/integration/action_revisions.py index cafd82e7..c53a044a 100644 --- a/src/secops/cli/commands/integration/action_revisions.py +++ b/src/secops/cli/commands/integration/action_revisions.py @@ -170,7 +170,7 @@ def handle_action_revisions_list_command(args, chronicle): def handle_action_revisions_delete_command(args, chronicle): """Handle integration action revision delete command""" try: - chronicle.delete_integration_action_revision( + chronicle.soar.delete_integration_action_revision( integration_name=args.integration_name, action_id=args.action_id, revision_id=args.revision_id, @@ -185,7 +185,7 @@ def handle_action_revisions_create_command(args, chronicle): """Handle integration action revision create command""" try: # Get the current action to create a revision - action = chronicle.get_integration_action( + action = chronicle.soar.get_integration_action( integration_name=args.integration_name, action_id=args.action_id, ) diff --git a/src/secops/cli/commands/integration/actions.py b/src/secops/cli/commands/integration/actions.py index 55776154..67aa9a45 100644 --- a/src/secops/cli/commands/integration/actions.py +++ b/src/secops/cli/commands/integration/actions.py @@ -288,7 +288,7 @@ def handle_actions_get_command(args, chronicle): def handle_actions_delete_command(args, chronicle): """Handle integration action delete command""" try: - chronicle.delete_integration_action( + chronicle.soar.delete_integration_action( integration_name=args.integration_name, action_id=args.action_id, ) @@ -340,7 +340,7 @@ def handle_actions_test_command(args, chronicle): """Handle integration action test command""" try: # First get the action to test - action = chronicle.get_integration_action( + action = chronicle.soar.get_integration_action( integration_name=args.integration_name, action_id=args.action_id, )