From 2fbc7b37bd87bc0ce5bfbab6d85245f8df0901dc Mon Sep 17 00:00:00 2001 From: PaperMtn Date: Thu, 23 Oct 2025 20:48:51 +0100 Subject: [PATCH 01/30] feat: add listing curated rule sets --- api_module_mapping.md | 744 +++++++++++++++---------------- src/secops/chronicle/__init__.py | 6 +- src/secops/chronicle/client.py | 20 + src/secops/chronicle/rule_set.py | 52 ++- 4 files changed, 447 insertions(+), 375 deletions(-) diff --git a/api_module_mapping.md b/api_module_mapping.md index ab89dfd9..958d2619 100644 --- a/api_module_mapping.md +++ b/api_module_mapping.md @@ -4,376 +4,376 @@ Following shows mapping between SecOps [REST Resource](https://cloud.google.com/ **Note:** All the REST resources mentioned have suffix `projects.locations.instances`. -|REST Resource |Version|secops-wrapper module |CLI Command | -|------------------------------------------------------------------------------|-------|------------------------------------------------------------|---------------------------------------| -|dataAccessLabels.create |v1 | | | -|dataAccessLabels.delete |v1 | | | -|dataAccessLabels.get |v1 | | | -|dataAccessLabels.list |v1 | | | -|dataAccessLabels.patch |v1 | | | -|dataAccessScopes.create |v1 | | | -|dataAccessScopes.delete |v1 | | | -|dataAccessScopes.get |v1 | | | -|dataAccessScopes.list |v1 | | | -|dataAccessScopes.patch |v1 | | | -|get |v1 | | | -|operations.cancel |v1 | | | -|operations.delete |v1 | | | -|operations.get |v1 | | | -|operations.list |v1 | | | -|referenceLists.create |v1 |chronicle.reference_list.create_reference_list |secops reference-list create | -|referenceLists.get |v1 |chronicle.reference_list.get_reference_list |secops reference-list get | -|referenceLists.list |v1 |chronicle.reference_list.list_reference_lists |secops reference-list list | -|referenceLists.patch |v1 |chronicle.reference_list.update_reference_list |secops reference-list update | -|rules.create |v1 |chronicle.rule.create_rule |secops rule create | -|rules.delete |v1 |chronicle.rule.delete_rule |secops rule delete | -|rules.deployments.list |v1 | | | -|rules.get |v1 |chronicle.rule.get_rule |secops rule get | -|rules.getDeployment |v1 | | | -|rules.list |v1 |chronicle.rule.list_rules |secops rule list | -|rules.listRevisions |v1 | | | -|rules.patch |v1 |chronicle.rule.update_rule |secops rule update | -|rules.retrohunts.create |v1 |chronicle.rule_retrohunt.create_retrohunt | | -|rules.retrohunts.get |v1 |chronicle.rule_retrohunt.get_retrohunt | | -|rules.retrohunts.list |v1 | | | -|rules.updateDeployment |v1 |chronicle.rule.enable_rule |secops rule enable | -|watchlists.create |v1 | | | -|watchlists.delete |v1 | | | -|watchlists.get |v1 | | | -|watchlists.list |v1 | | | -|watchlists.patch |v1 | | | -|dataAccessLabels.create |v1beta | | | -|dataAccessLabels.delete |v1beta | | | -|dataAccessLabels.get |v1beta | | | -|dataAccessLabels.list |v1beta | | | -|dataAccessLabels.patch |v1beta | | | -|dataAccessScopes.create |v1beta | | | -|dataAccessScopes.delete |v1beta | | | -|dataAccessScopes.get |v1beta | | | -|dataAccessScopes.list |v1beta | | | -|dataAccessScopes.patch |v1beta | | | -|get |v1beta | | | -|operations.cancel |v1beta | | | -|operations.delete |v1beta | | | -|operations.get |v1beta | | | -|operations.list |v1beta | | | -|referenceLists.create |v1beta | | | -|referenceLists.get |v1beta | | | -|referenceLists.list |v1beta | | | -|referenceLists.patch |v1beta | | | -|rules.create |v1beta | | | -|rules.delete |v1beta | | | -|rules.deployments.list |v1beta | | | -|rules.get |v1beta | | | -|rules.getDeployment |v1beta | | | -|rules.list |v1beta | | | -|rules.listRevisions |v1beta | | | -|rules.patch |v1beta | | | -|rules.retrohunts.create |v1beta | | | -|rules.retrohunts.get |v1beta | | | -|rules.retrohunts.list |v1beta | | | -|rules.updateDeployment |v1beta | | | -|watchlists.create |v1beta | | | -|watchlists.delete |v1beta | | | -|watchlists.get |v1beta | | | -|watchlists.list |v1beta | | | -|watchlists.patch |v1beta | | | -|analytics.entities.analyticValues.list |v1alpha| | | -|analytics.list |v1alpha| | | -|batchValidateWatchlistEntities |v1alpha| | | -|bigQueryAccess.provide |v1alpha| | | -|bigQueryExport.provision |v1alpha| | | -|cases.countPriorities |v1alpha| | | -|curatedRuleSetCategories.curatedRuleSets.curatedRuleSetDeployments.batchUpdate|v1alpha|chronicle.rule_set.batch_update_curated_rule_set_deployments| | -|curatedRuleSetCategories.curatedRuleSets.curatedRuleSetDeployments.patch |v1alpha| | | -|curatedRuleSetCategories.curatedRuleSets.get |v1alpha| | | -|curatedRuleSetCategories.curatedRuleSets.list |v1alpha| | | -|curatedRuleSetCategories.get |v1alpha| | | -|curatedRuleSetCategories.list |v1alpha| | | -|curatedRules.get |v1alpha| | | -|curatedRules.list |v1alpha| | | -|dashboardCharts.batchGet |v1alpha| | | -|dashboardCharts.get |v1alpha|chronicle.dashboard.get_chart |secops dashboard get-chart | -|dashboardQueries.execute |v1alpha|chronicle.dashboard_query.execute_query |secops dashboard-query execute | -|dashboardQueries.get |v1alpha|chronicle.dashboard_query.get_execute_query |secops dashboard-query get | -|dashboards.copy |v1alpha| | | -|dashboards.create |v1alpha| | | -|dashboards.delete |v1alpha| | | -|dashboards.get |v1alpha| | | -|dashboards.list |v1alpha| | | -|dataAccessLabels.create |v1alpha| | | -|dataAccessLabels.delete |v1alpha| | | -|dataAccessLabels.get |v1alpha| | | -|dataAccessLabels.list |v1alpha| | | -|dataAccessLabels.patch |v1alpha| | | -|dataAccessScopes.create |v1alpha| | | -|dataAccessScopes.delete |v1alpha| | | -|dataAccessScopes.get |v1alpha| | | -|dataAccessScopes.list |v1alpha| | | -|dataAccessScopes.patch |v1alpha| | | -|dataExports.cancel |v1alpha|chronicle.data_export.cancel_data_export |secops export cancel | -|dataExports.create |v1alpha|chronicle.data_export.create_data_export |secops export create | -|dataExports.fetchavailablelogtypes |v1alpha|chronicle.data_export.fetch_available_log_types |secops export log-types | -|dataExports.get |v1alpha|chronicle.data_export.get_data_export |secops export status | -|dataExports.list |v1alpha|chronicle.data_export.list_data_export |secops export list | -|dataExports.patch |v1alpha|chronicle.data_export.update_data_export |secops export update | -|dataTableOperationErrors.get |v1alpha| | | -|dataTables.create |v1alpha|chronicle.data_table.create_data_table |secops data-table create | -|dataTables.dataTableRows.bulkCreate |v1alpha|chronicle.data_table.create_data_table_rows |secops data-table add-rows | -|dataTables.dataTableRows.bulkCreateAsync |v1alpha| | | -|dataTables.dataTableRows.bulkGet |v1alpha| | | -|dataTables.dataTableRows.bulkReplace |v1alpha| | | -|dataTables.dataTableRows.bulkReplaceAsync |v1alpha| | | -|dataTables.dataTableRows.bulkUpdate |v1alpha| | | -|dataTables.dataTableRows.bulkUpdateAsync |v1alpha| | | -|dataTables.dataTableRows.create |v1alpha| | | -|dataTables.dataTableRows.delete |v1alpha|chronicle.data_table.delete_data_table_rows |secops data-table delete-rows | -|dataTables.dataTableRows.get |v1alpha| | | -|dataTables.dataTableRows.list |v1alpha|chronicle.data_table.list_data_table_rows |secops data-table list-rows | -|dataTables.dataTableRows.patch |v1alpha| | | -|dataTables.delete |v1alpha|chronicle.data_table.delete_data_table |secops data-table delete | -|dataTables.get |v1alpha|chronicle.data_table.get_data_table |secops data-table get | -|dataTables.list |v1alpha|chronicle.data_table.list_data_tables |secops data-table list | -|dataTables.patch |v1alpha| | | -|dataTables.upload |v1alpha| | | -|dataTaps.create |v1alpha| | | -|dataTaps.delete |v1alpha| | | -|dataTaps.get |v1alpha| | | -|dataTaps.list |v1alpha| | | -|dataTaps.patch |v1alpha| | | -|delete |v1alpha| | | -|enrichmentControls.create |v1alpha| | | -|enrichmentControls.delete |v1alpha| | | -|enrichmentControls.get |v1alpha| | | -|enrichmentControls.list |v1alpha| | | -|entities.get |v1alpha| | | -|entities.import |v1alpha| | | -|entities.modifyEntityRiskScore |v1alpha| | | -|entities.queryEntityRiskScoreModifications |v1alpha| | | -|entityRiskScores.query |v1alpha| | | -|errorNotificationConfigs.create |v1alpha| | | -|errorNotificationConfigs.delete |v1alpha| | | -|errorNotificationConfigs.get |v1alpha| | | -|errorNotificationConfigs.list |v1alpha| | | -|errorNotificationConfigs.patch |v1alpha| | | -|events.batchGet |v1alpha| | | -|events.get |v1alpha| | | -|events.import |v1alpha|chronicle.log_ingest.ingest_udm |secops log ingest-udm | -|extractSyslog |v1alpha| | | -|federationGroups.create |v1alpha| | | -|federationGroups.delete |v1alpha| | | -|federationGroups.get |v1alpha| | | -|federationGroups.list |v1alpha| | | -|federationGroups.patch |v1alpha| | | -|feedPacks.get |v1alpha| | | -|feedPacks.list |v1alpha| | | -|feedServiceAccounts.fetchServiceAccountForCustomer |v1alpha| | | -|feedSourceTypeSchemas.list |v1alpha| | | -|feedSourceTypeSchemas.logTypeSchemas.list |v1alpha| | | -|feeds.create |v1alpha|chronicle.feeds.create_feed |secops feed create | -|feeds.delete |v1alpha|chronicle.feeds.delete_feed |secops feed delete | -|feeds.disable |v1alpha|chronicle.feeds.disable_feed |secops feed disable | -|feeds.enable |v1alpha|chronicle.feeds.enable_feed |secops feed enable | -|feeds.generateSecret |v1alpha|chronicle.feeds.generate_secret |secops feed secret | -|feeds.get |v1alpha|chronicle.feeds.get_feed |secops feed get | -|feeds.importPushLogs |v1alpha| | | -|feeds.list |v1alpha|chronicle.feeds.list_feeds |secops feed list | -|feeds.patch |v1alpha|chronicle.feeds.update_feed |secops feed update | -|feeds.scheduleTransfer |v1alpha| | | -|fetchFederationAccess |v1alpha| | | -|findEntity |v1alpha| | | -|findEntityAlerts |v1alpha| | | -|findRelatedEntities |v1alpha| | | -|findUdmFieldValues |v1alpha| | | -|findingsGraph.exploreNode |v1alpha| | | -|findingsGraph.initializeGraph |v1alpha| | | -|findingsRefinements.computeFindingsRefinementActivity |v1alpha|chronicle.rule_exclusion.compute_rule_exclusion_activity |secops rule-exclusion compute-activity | -|findingsRefinements.create |v1alpha|chronicle.rule_exclusion.create_rule_exclusion |secops rule-exclusion create | -|findingsRefinements.get |v1alpha|chronicle.rule_exclusion.get_rule_exclusion |secops rule-exclusion get | -|findingsRefinements.getDeployment |v1alpha|chronicle.rule_exclusion.get_rule_exclusion_deployment |secops rule-exclusion get-deployment | -|findingsRefinements.list |v1alpha|chronicle.rule_exclusion.list_rule_exclusions |secops rule-exclusion list | -|findingsRefinements.patch |v1alpha|chronicle.rule_exclusion.patch_rule_exclusion |secops rule-exclusion update | -|findingsRefinements.updateDeployment |v1alpha|chronicle.rule_exclusion.update_rule_exclusion_deployment |secops rule-exclusion update-deployment| -|forwarders.collectors.create |v1alpha| | | -|forwarders.collectors.delete |v1alpha| | | -|forwarders.collectors.get |v1alpha| | | -|forwarders.collectors.list |v1alpha| | | -|forwarders.collectors.patch |v1alpha| | | -|forwarders.create |v1alpha|chronicle.log_ingest.create_forwarder |secops forwarder create | -|forwarders.delete |v1alpha|chronicle.log_ingest.delete_forwarder |secops forwarder delete | -|forwarders.generateForwarderFiles |v1alpha| | | -|forwarders.get |v1alpha|chronicle.log_ingest.get_forwarder |secops forwarder get | -|forwarders.importStatsEvents |v1alpha| | | -|forwarders.list |v1alpha|chronicle.log_ingest.list_forwarder |secops forwarder list | -|forwarders.patch |v1alpha|chronicle.log_ingest.update_forwarder |secops forwarder update | -|generateCollectionAgentAuth |v1alpha| | | -|generateSoarAuthJwt |v1alpha| | | -|generateUdmKeyValueMappings |v1alpha| | | -|generateWorkspaceConnectionToken |v1alpha| | | -|get |v1alpha| | | -|getBigQueryExport |v1alpha| | | -|getMultitenantDirectory |v1alpha| | | -|getRiskConfig |v1alpha| | | -|ingestionLogLabels.get |v1alpha| | | -|ingestionLogLabels.list |v1alpha| | | -|ingestionLogNamespaces.get |v1alpha| | | -|ingestionLogNamespaces.list |v1alpha| | | -|iocs.batchGet |v1alpha| | | -|iocs.findFirstAndLastSeen |v1alpha| | | -|iocs.get |v1alpha| | | -|iocs.getIocState |v1alpha| | | -|iocs.searchCuratedDetectionsForIoc |v1alpha| | | -|iocs.updateIocState |v1alpha| | | -|legacy.legacyBatchGetCases |v1alpha|chronicle.case.get_cases_from_list |secops case | -|legacy.legacyBatchGetCollections |v1alpha| | | -|legacy.legacyCreateOrUpdateCase |v1alpha| | | -|legacy.legacyCreateSoarAlert |v1alpha| | | -|legacy.legacyFetchAlertsView |v1alpha|chronicle.alert.get_alerts |secops alert | -|legacy.legacyFetchUdmSearchCsv |v1alpha|chronicle.udm_search.fetch_udm_search_csv |secops search --csv | -|legacy.legacyFetchUdmSearchView |v1alpha|chronicle.udm_search.fetch_udm_search_view |secops udm-search-view | -|legacy.legacyFindAssetEvents |v1alpha| | | -|legacy.legacyFindRawLogs |v1alpha| | | -|legacy.legacyFindUdmEvents |v1alpha| | | -|legacy.legacyGetAlert |v1alpha|chronicle.rule_alert.get_alert | | -|legacy.legacyGetCuratedRulesTrends |v1alpha| | | -|legacy.legacyGetDetection |v1alpha| | | -|legacy.legacyGetEventForDetection |v1alpha| | | -|legacy.legacyGetRuleCounts |v1alpha| | | -|legacy.legacyGetRulesTrends |v1alpha| | | -|legacy.legacyListCases |v1alpha|chronicle.case.get_cases |secops case --ids | -|legacy.legacyRunTestRule |v1alpha|chronicle.rule.run_rule_test |secops rule validate | -|legacy.legacySearchArtifactEvents |v1alpha| | | -|legacy.legacySearchArtifactIoCDetails |v1alpha| | | -|legacy.legacySearchAssetEvents |v1alpha| | | -|legacy.legacySearchCuratedDetections |v1alpha| | | -|legacy.legacySearchCustomerStats |v1alpha| | | -|legacy.legacySearchDetections |v1alpha|chronicle.rule_detection.list_detections | | -|legacy.legacySearchDomainsRecentlyRegistered |v1alpha| | | -|legacy.legacySearchDomainsTimingStats |v1alpha| | | -|legacy.legacySearchEnterpriseWideAlerts |v1alpha| | | -|legacy.legacySearchEnterpriseWideIoCs |v1alpha|chronicle.ioc.list_iocs |secops iocs | -|legacy.legacySearchFindings |v1alpha| | | -|legacy.legacySearchIngestionStats |v1alpha| | | -|legacy.legacySearchIoCInsights |v1alpha| | | -|legacy.legacySearchRawLogs |v1alpha| | | -|legacy.legacySearchRuleDetectionCountBuckets |v1alpha| | | -|legacy.legacySearchRuleDetectionEvents |v1alpha| | | -|legacy.legacySearchRuleResults |v1alpha| | | -|legacy.legacySearchRulesAlerts |v1alpha|chronicle.rule_alert.search_rule_alerts | | -|legacy.legacySearchUserEvents |v1alpha| | | -|legacy.legacyStreamDetectionAlerts |v1alpha| | | -|legacy.legacyTestRuleStreaming |v1alpha| | | -|legacy.legacyUpdateAlert |v1alpha|chronicle.rule_alert.update_alert | | -|listAllFindingsRefinementDeployments |v1alpha| | | -|logTypes.create |v1alpha| | | -|logTypes.generateEventTypesSuggestions |v1alpha| | | -|logTypes.get |v1alpha| | | -|logTypes.getLogTypeSetting |v1alpha| | | -|logTypes.legacySubmitParserExtension |v1alpha| | | -|logTypes.list |v1alpha| | | -|logTypes.logs.export |v1alpha| | | -|logTypes.logs.get |v1alpha| | | -|logTypes.logs.import |v1alpha|chronicle.log_ingest.ingest_log |secops log ingest | -|logTypes.logs.list |v1alpha| | | -|logTypes.parserExtensions.activate |v1alpha|chronicle.parser_extension.activate_parser_extension |secops parser-extension activate | -|logTypes.parserExtensions.create |v1alpha|chronicle.parser_extension.create_parser_extension |secops parser-extension create | -|logTypes.parserExtensions.delete |v1alpha|chronicle.parser_extension.delete_parser_extension |secops parser-extension delete | -|logTypes.parserExtensions.extensionValidationReports.get |v1alpha| | | -|logTypes.parserExtensions.extensionValidationReports.list |v1alpha| | | -|logTypes.parserExtensions.extensionValidationReports.validationErrors.list |v1alpha| | | -|logTypes.parserExtensions.get |v1alpha|chronicle.parser_extension.get_parser_extension |secops parser-extension get | -|logTypes.parserExtensions.list |v1alpha|chronicle.parser_extension.list_parser_extensions |secops parser-extension list | -|logTypes.parserExtensions.validationReports.get |v1alpha| | | -|logTypes.parserExtensions.validationReports.parsingErrors.list |v1alpha| | | -|logTypes.parsers.activate |v1alpha|chronicle.parser.activate_parser |secops parser activate | -|logTypes.parsers.activateReleaseCandidateParser |v1alpha|chronicle.parser.activate_release_candidate |secops parser activate-rc | -|logTypes.parsers.copy |v1alpha|chronicle.parser.copy_parser |secops parser copy | -|logTypes.parsers.create |v1alpha|chronicle.parser.create_parser |secops parser create | -|logTypes.parsers.deactivate |v1alpha|chronicle.parser.deactivate_parser |secops parser deactivate | -|logTypes.parsers.delete |v1alpha|chronicle.parser.delete_parser |secops parser delete | -|logTypes.parsers.get |v1alpha|chronicle.parser.get_parser |secops parser get | -|logTypes.parsers.list |v1alpha|chronicle.parser.list_parsers |secops parser list | -|logTypes.parsers.validationReports.get |v1alpha| | | -|logTypes.parsers.validationReports.parsingErrors.list |v1alpha| | | -|logTypes.patch |v1alpha| | | -|logTypes.runParser |v1alpha|chronicle.parser.run_parser |secops parser run | -|logTypes.updateLogTypeSetting |v1alpha| | | -|logs.classify |v1alpha| | | -| nativeDashboards.addChart | v1alpha |chronicle.dashboard.add_chart |secops dashboard add-chart | -| nativeDashboards.create | v1alpha |chronicle.dashboard.create_dashboard |secops dashboard create | -| nativeDashboards.delete | v1alpha |chronicle.dashboard.delete_dashboard |secops dashboard delete | -| nativeDashboards.duplicate | v1alpha |chronicle.dashboard.duplicate_dashboard |secops dashboard duplicate | +|REST Resource |Version| secops-wrapper module |CLI Command | +|------------------------------------------------------------------------------|-------|--------------------------------------------------------------|---------------------------------------| +|dataAccessLabels.create |v1 | | | +|dataAccessLabels.delete |v1 | | | +|dataAccessLabels.get |v1 | | | +|dataAccessLabels.list |v1 | | | +|dataAccessLabels.patch |v1 | | | +|dataAccessScopes.create |v1 | | | +|dataAccessScopes.delete |v1 | | | +|dataAccessScopes.get |v1 | | | +|dataAccessScopes.list |v1 | | | +|dataAccessScopes.patch |v1 | | | +|get |v1 | | | +|operations.cancel |v1 | | | +|operations.delete |v1 | | | +|operations.get |v1 | | | +|operations.list |v1 | | | +|referenceLists.create |v1 | chronicle.reference_list.create_reference_list |secops reference-list create | +|referenceLists.get |v1 | chronicle.reference_list.get_reference_list |secops reference-list get | +|referenceLists.list |v1 | chronicle.reference_list.list_reference_lists |secops reference-list list | +|referenceLists.patch |v1 | chronicle.reference_list.update_reference_list |secops reference-list update | +|rules.create |v1 | chronicle.rule.create_rule |secops rule create | +|rules.delete |v1 | chronicle.rule.delete_rule |secops rule delete | +|rules.deployments.list |v1 | | | +|rules.get |v1 | chronicle.rule.get_rule |secops rule get | +|rules.getDeployment |v1 | | | +|rules.list |v1 | chronicle.rule.list_rules |secops rule list | +|rules.listRevisions |v1 | | | +|rules.patch |v1 | chronicle.rule.update_rule |secops rule update | +|rules.retrohunts.create |v1 | chronicle.rule_retrohunt.create_retrohunt | | +|rules.retrohunts.get |v1 | chronicle.rule_retrohunt.get_retrohunt | | +|rules.retrohunts.list |v1 | | | +|rules.updateDeployment |v1 | chronicle.rule.enable_rule |secops rule enable | +|watchlists.create |v1 | | | +|watchlists.delete |v1 | | | +|watchlists.get |v1 | | | +|watchlists.list |v1 | | | +|watchlists.patch |v1 | | | +|dataAccessLabels.create |v1beta | | | +|dataAccessLabels.delete |v1beta | | | +|dataAccessLabels.get |v1beta | | | +|dataAccessLabels.list |v1beta | | | +|dataAccessLabels.patch |v1beta | | | +|dataAccessScopes.create |v1beta | | | +|dataAccessScopes.delete |v1beta | | | +|dataAccessScopes.get |v1beta | | | +|dataAccessScopes.list |v1beta | | | +|dataAccessScopes.patch |v1beta | | | +|get |v1beta | | | +|operations.cancel |v1beta | | | +|operations.delete |v1beta | | | +|operations.get |v1beta | | | +|operations.list |v1beta | | | +|referenceLists.create |v1beta | | | +|referenceLists.get |v1beta | | | +|referenceLists.list |v1beta | | | +|referenceLists.patch |v1beta | | | +|rules.create |v1beta | | | +|rules.delete |v1beta | | | +|rules.deployments.list |v1beta | | | +|rules.get |v1beta | | | +|rules.getDeployment |v1beta | | | +|rules.list |v1beta | | | +|rules.listRevisions |v1beta | | | +|rules.patch |v1beta | | | +|rules.retrohunts.create |v1beta | | | +|rules.retrohunts.get |v1beta | | | +|rules.retrohunts.list |v1beta | | | +|rules.updateDeployment |v1beta | | | +|watchlists.create |v1beta | | | +|watchlists.delete |v1beta | | | +|watchlists.get |v1beta | | | +|watchlists.list |v1beta | | | +|watchlists.patch |v1beta | | | +|analytics.entities.analyticValues.list |v1alpha| | | +|analytics.list |v1alpha| | | +|batchValidateWatchlistEntities |v1alpha| | | +|bigQueryAccess.provide |v1alpha| | | +|bigQueryExport.provision |v1alpha| | | +|cases.countPriorities |v1alpha| | | +|curatedRuleSetCategories.curatedRuleSets.curatedRuleSetDeployments.batchUpdate|v1alpha| chronicle.rule_set.batch_update_curated_rule_set_deployments | | +|curatedRuleSetCategories.curatedRuleSets.curatedRuleSetDeployments.patch |v1alpha| chronicle.rule_set.list_rule_sets | | +|curatedRuleSetCategories.curatedRuleSets.get |v1alpha| | | +|curatedRuleSetCategories.curatedRuleSets.list |v1alpha| | | +|curatedRuleSetCategories.get |v1alpha| | | +|curatedRuleSetCategories.list |v1alpha| | | +|curatedRules.get |v1alpha| | | +|curatedRules.list |v1alpha| | | +|dashboardCharts.batchGet |v1alpha| | | +|dashboardCharts.get |v1alpha| chronicle.dashboard.get_chart |secops dashboard get-chart | +|dashboardQueries.execute |v1alpha| chronicle.dashboard_query.execute_query |secops dashboard-query execute | +|dashboardQueries.get |v1alpha| chronicle.dashboard_query.get_execute_query |secops dashboard-query get | +|dashboards.copy |v1alpha| | | +|dashboards.create |v1alpha| | | +|dashboards.delete |v1alpha| | | +|dashboards.get |v1alpha| | | +|dashboards.list |v1alpha| | | +|dataAccessLabels.create |v1alpha| | | +|dataAccessLabels.delete |v1alpha| | | +|dataAccessLabels.get |v1alpha| | | +|dataAccessLabels.list |v1alpha| | | +|dataAccessLabels.patch |v1alpha| | | +|dataAccessScopes.create |v1alpha| | | +|dataAccessScopes.delete |v1alpha| | | +|dataAccessScopes.get |v1alpha| | | +|dataAccessScopes.list |v1alpha| | | +|dataAccessScopes.patch |v1alpha| | | +|dataExports.cancel |v1alpha| chronicle.data_export.cancel_data_export |secops export cancel | +|dataExports.create |v1alpha| chronicle.data_export.create_data_export |secops export create | +|dataExports.fetchavailablelogtypes |v1alpha| chronicle.data_export.fetch_available_log_types |secops export log-types | +|dataExports.get |v1alpha| chronicle.data_export.get_data_export |secops export status | +|dataExports.list |v1alpha| chronicle.data_export.list_data_export |secops export list | +|dataExports.patch |v1alpha| chronicle.data_export.update_data_export |secops export update | +|dataTableOperationErrors.get |v1alpha| | | +|dataTables.create |v1alpha| chronicle.data_table.create_data_table |secops data-table create | +|dataTables.dataTableRows.bulkCreate |v1alpha| chronicle.data_table.create_data_table_rows |secops data-table add-rows | +|dataTables.dataTableRows.bulkCreateAsync |v1alpha| | | +|dataTables.dataTableRows.bulkGet |v1alpha| | | +|dataTables.dataTableRows.bulkReplace |v1alpha| | | +|dataTables.dataTableRows.bulkReplaceAsync |v1alpha| | | +|dataTables.dataTableRows.bulkUpdate |v1alpha| | | +|dataTables.dataTableRows.bulkUpdateAsync |v1alpha| | | +|dataTables.dataTableRows.create |v1alpha| | | +|dataTables.dataTableRows.delete |v1alpha| chronicle.data_table.delete_data_table_rows |secops data-table delete-rows | +|dataTables.dataTableRows.get |v1alpha| | | +|dataTables.dataTableRows.list |v1alpha| chronicle.data_table.list_data_table_rows |secops data-table list-rows | +|dataTables.dataTableRows.patch |v1alpha| | | +|dataTables.delete |v1alpha| chronicle.data_table.delete_data_table |secops data-table delete | +|dataTables.get |v1alpha| chronicle.data_table.get_data_table |secops data-table get | +|dataTables.list |v1alpha| chronicle.data_table.list_data_tables |secops data-table list | +|dataTables.patch |v1alpha| | | +|dataTables.upload |v1alpha| | | +|dataTaps.create |v1alpha| | | +|dataTaps.delete |v1alpha| | | +|dataTaps.get |v1alpha| | | +|dataTaps.list |v1alpha| | | +|dataTaps.patch |v1alpha| | | +|delete |v1alpha| | | +|enrichmentControls.create |v1alpha| | | +|enrichmentControls.delete |v1alpha| | | +|enrichmentControls.get |v1alpha| | | +|enrichmentControls.list |v1alpha| | | +|entities.get |v1alpha| | | +|entities.import |v1alpha| | | +|entities.modifyEntityRiskScore |v1alpha| | | +|entities.queryEntityRiskScoreModifications |v1alpha| | | +|entityRiskScores.query |v1alpha| | | +|errorNotificationConfigs.create |v1alpha| | | +|errorNotificationConfigs.delete |v1alpha| | | +|errorNotificationConfigs.get |v1alpha| | | +|errorNotificationConfigs.list |v1alpha| | | +|errorNotificationConfigs.patch |v1alpha| | | +|events.batchGet |v1alpha| | | +|events.get |v1alpha| | | +|events.import |v1alpha| chronicle.log_ingest.ingest_udm |secops log ingest-udm | +|extractSyslog |v1alpha| | | +|federationGroups.create |v1alpha| | | +|federationGroups.delete |v1alpha| | | +|federationGroups.get |v1alpha| | | +|federationGroups.list |v1alpha| | | +|federationGroups.patch |v1alpha| | | +|feedPacks.get |v1alpha| | | +|feedPacks.list |v1alpha| | | +|feedServiceAccounts.fetchServiceAccountForCustomer |v1alpha| | | +|feedSourceTypeSchemas.list |v1alpha| | | +|feedSourceTypeSchemas.logTypeSchemas.list |v1alpha| | | +|feeds.create |v1alpha| chronicle.feeds.create_feed |secops feed create | +|feeds.delete |v1alpha| chronicle.feeds.delete_feed |secops feed delete | +|feeds.disable |v1alpha| chronicle.feeds.disable_feed |secops feed disable | +|feeds.enable |v1alpha| chronicle.feeds.enable_feed |secops feed enable | +|feeds.generateSecret |v1alpha| chronicle.feeds.generate_secret |secops feed secret | +|feeds.get |v1alpha| chronicle.feeds.get_feed |secops feed get | +|feeds.importPushLogs |v1alpha| | | +|feeds.list |v1alpha| chronicle.feeds.list_feeds |secops feed list | +|feeds.patch |v1alpha| chronicle.feeds.update_feed |secops feed update | +|feeds.scheduleTransfer |v1alpha| | | +|fetchFederationAccess |v1alpha| | | +|findEntity |v1alpha| | | +|findEntityAlerts |v1alpha| | | +|findRelatedEntities |v1alpha| | | +|findUdmFieldValues |v1alpha| | | +|findingsGraph.exploreNode |v1alpha| | | +|findingsGraph.initializeGraph |v1alpha| | | +|findingsRefinements.computeFindingsRefinementActivity |v1alpha| chronicle.rule_exclusion.compute_rule_exclusion_activity |secops rule-exclusion compute-activity | +|findingsRefinements.create |v1alpha| chronicle.rule_exclusion.create_rule_exclusion |secops rule-exclusion create | +|findingsRefinements.get |v1alpha| chronicle.rule_exclusion.get_rule_exclusion |secops rule-exclusion get | +|findingsRefinements.getDeployment |v1alpha| chronicle.rule_exclusion.get_rule_exclusion_deployment |secops rule-exclusion get-deployment | +|findingsRefinements.list |v1alpha| chronicle.rule_exclusion.list_rule_exclusions |secops rule-exclusion list | +|findingsRefinements.patch |v1alpha| chronicle.rule_exclusion.patch_rule_exclusion |secops rule-exclusion update | +|findingsRefinements.updateDeployment |v1alpha| chronicle.rule_exclusion.update_rule_exclusion_deployment |secops rule-exclusion update-deployment| +|forwarders.collectors.create |v1alpha| | | +|forwarders.collectors.delete |v1alpha| | | +|forwarders.collectors.get |v1alpha| | | +|forwarders.collectors.list |v1alpha| | | +|forwarders.collectors.patch |v1alpha| | | +|forwarders.create |v1alpha| chronicle.log_ingest.create_forwarder |secops forwarder create | +|forwarders.delete |v1alpha| chronicle.log_ingest.delete_forwarder |secops forwarder delete | +|forwarders.generateForwarderFiles |v1alpha| | | +|forwarders.get |v1alpha| chronicle.log_ingest.get_forwarder |secops forwarder get | +|forwarders.importStatsEvents |v1alpha| | | +|forwarders.list |v1alpha| chronicle.log_ingest.list_forwarder |secops forwarder list | +|forwarders.patch |v1alpha| chronicle.log_ingest.update_forwarder |secops forwarder update | +|generateCollectionAgentAuth |v1alpha| | | +|generateSoarAuthJwt |v1alpha| | | +|generateUdmKeyValueMappings |v1alpha| | | +|generateWorkspaceConnectionToken |v1alpha| | | +|get |v1alpha| | | +|getBigQueryExport |v1alpha| | | +|getMultitenantDirectory |v1alpha| | | +|getRiskConfig |v1alpha| | | +|ingestionLogLabels.get |v1alpha| | | +|ingestionLogLabels.list |v1alpha| | | +|ingestionLogNamespaces.get |v1alpha| | | +|ingestionLogNamespaces.list |v1alpha| | | +|iocs.batchGet |v1alpha| | | +|iocs.findFirstAndLastSeen |v1alpha| | | +|iocs.get |v1alpha| | | +|iocs.getIocState |v1alpha| | | +|iocs.searchCuratedDetectionsForIoc |v1alpha| | | +|iocs.updateIocState |v1alpha| | | +|legacy.legacyBatchGetCases |v1alpha| chronicle.case.get_cases_from_list |secops case | +|legacy.legacyBatchGetCollections |v1alpha| | | +|legacy.legacyCreateOrUpdateCase |v1alpha| | | +|legacy.legacyCreateSoarAlert |v1alpha| | | +|legacy.legacyFetchAlertsView |v1alpha| chronicle.alert.get_alerts |secops alert | +|legacy.legacyFetchUdmSearchCsv |v1alpha| chronicle.udm_search.fetch_udm_search_csv |secops search --csv | +|legacy.legacyFetchUdmSearchView |v1alpha| chronicle.udm_search.fetch_udm_search_view |secops udm-search-view | +|legacy.legacyFindAssetEvents |v1alpha| | | +|legacy.legacyFindRawLogs |v1alpha| | | +|legacy.legacyFindUdmEvents |v1alpha| | | +|legacy.legacyGetAlert |v1alpha| chronicle.rule_alert.get_alert | | +|legacy.legacyGetCuratedRulesTrends |v1alpha| | | +|legacy.legacyGetDetection |v1alpha| | | +|legacy.legacyGetEventForDetection |v1alpha| | | +|legacy.legacyGetRuleCounts |v1alpha| | | +|legacy.legacyGetRulesTrends |v1alpha| | | +|legacy.legacyListCases |v1alpha| chronicle.case.get_cases |secops case --ids | +|legacy.legacyRunTestRule |v1alpha| chronicle.rule.run_rule_test |secops rule validate | +|legacy.legacySearchArtifactEvents |v1alpha| | | +|legacy.legacySearchArtifactIoCDetails |v1alpha| | | +|legacy.legacySearchAssetEvents |v1alpha| | | +|legacy.legacySearchCuratedDetections |v1alpha| | | +|legacy.legacySearchCustomerStats |v1alpha| | | +|legacy.legacySearchDetections |v1alpha| chronicle.rule_detection.list_detections | | +|legacy.legacySearchDomainsRecentlyRegistered |v1alpha| | | +|legacy.legacySearchDomainsTimingStats |v1alpha| | | +|legacy.legacySearchEnterpriseWideAlerts |v1alpha| | | +|legacy.legacySearchEnterpriseWideIoCs |v1alpha| chronicle.ioc.list_iocs |secops iocs | +|legacy.legacySearchFindings |v1alpha| | | +|legacy.legacySearchIngestionStats |v1alpha| | | +|legacy.legacySearchIoCInsights |v1alpha| | | +|legacy.legacySearchRawLogs |v1alpha| | | +|legacy.legacySearchRuleDetectionCountBuckets |v1alpha| | | +|legacy.legacySearchRuleDetectionEvents |v1alpha| | | +|legacy.legacySearchRuleResults |v1alpha| | | +|legacy.legacySearchRulesAlerts |v1alpha| chronicle.rule_alert.search_rule_alerts | | +|legacy.legacySearchUserEvents |v1alpha| | | +|legacy.legacyStreamDetectionAlerts |v1alpha| | | +|legacy.legacyTestRuleStreaming |v1alpha| | | +|legacy.legacyUpdateAlert |v1alpha| chronicle.rule_alert.update_alert | | +|listAllFindingsRefinementDeployments |v1alpha| | | +|logTypes.create |v1alpha| | | +|logTypes.generateEventTypesSuggestions |v1alpha| | | +|logTypes.get |v1alpha| | | +|logTypes.getLogTypeSetting |v1alpha| | | +|logTypes.legacySubmitParserExtension |v1alpha| | | +|logTypes.list |v1alpha| | | +|logTypes.logs.export |v1alpha| | | +|logTypes.logs.get |v1alpha| | | +|logTypes.logs.import |v1alpha| chronicle.log_ingest.ingest_log |secops log ingest | +|logTypes.logs.list |v1alpha| | | +|logTypes.parserExtensions.activate |v1alpha| chronicle.parser_extension.activate_parser_extension |secops parser-extension activate | +|logTypes.parserExtensions.create |v1alpha| chronicle.parser_extension.create_parser_extension |secops parser-extension create | +|logTypes.parserExtensions.delete |v1alpha| chronicle.parser_extension.delete_parser_extension |secops parser-extension delete | +|logTypes.parserExtensions.extensionValidationReports.get |v1alpha| | | +|logTypes.parserExtensions.extensionValidationReports.list |v1alpha| | | +|logTypes.parserExtensions.extensionValidationReports.validationErrors.list |v1alpha| | | +|logTypes.parserExtensions.get |v1alpha| chronicle.parser_extension.get_parser_extension |secops parser-extension get | +|logTypes.parserExtensions.list |v1alpha| chronicle.parser_extension.list_parser_extensions |secops parser-extension list | +|logTypes.parserExtensions.validationReports.get |v1alpha| | | +|logTypes.parserExtensions.validationReports.parsingErrors.list |v1alpha| | | +|logTypes.parsers.activate |v1alpha| chronicle.parser.activate_parser |secops parser activate | +|logTypes.parsers.activateReleaseCandidateParser |v1alpha| chronicle.parser.activate_release_candidate |secops parser activate-rc | +|logTypes.parsers.copy |v1alpha| chronicle.parser.copy_parser |secops parser copy | +|logTypes.parsers.create |v1alpha| chronicle.parser.create_parser |secops parser create | +|logTypes.parsers.deactivate |v1alpha| chronicle.parser.deactivate_parser |secops parser deactivate | +|logTypes.parsers.delete |v1alpha| chronicle.parser.delete_parser |secops parser delete | +|logTypes.parsers.get |v1alpha| chronicle.parser.get_parser |secops parser get | +|logTypes.parsers.list |v1alpha| chronicle.parser.list_parsers |secops parser list | +|logTypes.parsers.validationReports.get |v1alpha| | | +|logTypes.parsers.validationReports.parsingErrors.list |v1alpha| | | +|logTypes.patch |v1alpha| | | +|logTypes.runParser |v1alpha| chronicle.parser.run_parser |secops parser run | +|logTypes.updateLogTypeSetting |v1alpha| | | +|logs.classify |v1alpha| | | +| nativeDashboards.addChart | v1alpha | chronicle.dashboard.add_chart |secops dashboard add-chart | +| nativeDashboards.create | v1alpha | chronicle.dashboard.create_dashboard |secops dashboard create | +| nativeDashboards.delete | v1alpha | chronicle.dashboard.delete_dashboard |secops dashboard delete | +| nativeDashboards.duplicate | v1alpha | chronicle.dashboard.duplicate_dashboard |secops dashboard duplicate | | nativeDashboards.duplicateChart | v1alpha | | | -| nativeDashboards.editChart | v1alpha |chronicle.dashboard.edit_chart |secops dashboard edit-chart | -| nativeDashboards.export | v1alpha |chronicle.dashboard.export_dashboard |secops dashboard export | -| nativeDashboards.get | v1alpha |chronicle.dashboard.get_dashboard |secops dashboard get | -| nativeDashboards.import | v1alpha |chronicle.dashboard.import_dashboard |secops dashboard import | -| nativeDashboards.list | v1alpha |chronicle.dashboard.list_dashboards |secops dashboard list | -| nativeDashboards.patch | v1alpha |chronicle.dashboard.update_dashboard |secops dashboard update | -| nativeDashboards.removeChart | v1alpha |chronicle.dashboard.remove_chart |secops dashboard remove-chart | -|operations.cancel |v1alpha| | | -|operations.delete |v1alpha| | | -|operations.get |v1alpha| | | -|operations.list |v1alpha| | | -|operations.streamSearch |v1alpha| | | -|queryProductSourceStats |v1alpha| | | -|referenceLists.create |v1alpha| | | -|referenceLists.get |v1alpha| | | -|referenceLists.list |v1alpha| | | -|referenceLists.patch |v1alpha| | | -|report |v1alpha| | | -|ruleExecutionErrors.list |v1alpha|chronicle.rule_detection.list_errors | | -|rules.create |v1alpha| | | -|rules.delete |v1alpha| | | -|rules.deployments.list |v1alpha| | | -|rules.get |v1alpha| | | -|rules.getDeployment |v1alpha| | | -|rules.list |v1alpha| | | -|rules.listRevisions |v1alpha| | | -|rules.patch |v1alpha| | | -|rules.retrohunts.create |v1alpha| | | -|rules.retrohunts.get |v1alpha| | | -|rules.retrohunts.list |v1alpha| | | -|rules.updateDeployment |v1alpha| | | -|searchEntities |v1alpha| | | -|searchRawLogs |v1alpha| | | -|summarizeEntitiesFromQuery |v1alpha|chronicle.entity.summarize_entity |secops entity | -|summarizeEntity |v1alpha|chronicle.entity.summarize_entity | | -|testFindingsRefinement |v1alpha| | | -|translateUdmQuery |v1alpha|chronicle.nl_search.translate_nl_to_udm | | -|translateYlRule |v1alpha| | | -|udmSearch |v1alpha|chronicle.search.search_udm |secops search | -|undelete |v1alpha| | | -|updateBigQueryExport |v1alpha| | | -|updateRiskConfig |v1alpha| | | -|users.clearConversationHistory |v1alpha| | | -|users.conversations.create |v1alpha|chronicle.gemini.create_conversation | | -|users.conversations.delete |v1alpha| | | -|users.conversations.get |v1alpha| | | -|users.conversations.list |v1alpha| | | -|users.conversations.messages.create |v1alpha|chronicle.gemini.query_gemini |secops gemini | -|users.conversations.messages.delete |v1alpha| | | -|users.conversations.messages.get |v1alpha| | | -|users.conversations.messages.list |v1alpha| | | -|users.conversations.messages.patch |v1alpha| | | -|users.conversations.patch |v1alpha| | | -|users.getPreferenceSet |v1alpha|chronicle.gemini.opt_in_to_gemini |secops gemini --opt-in | -|users.searchQueries.create |v1alpha| | | -|users.searchQueries.delete |v1alpha| | | -|users.searchQueries.get |v1alpha| | | -|users.searchQueries.list |v1alpha| | | -|users.searchQueries.patch |v1alpha| | | -|users.updatePreferenceSet |v1alpha| | | -|validateQuery |v1alpha|chronicle.validate.validate_query | | -|verifyReferenceList |v1alpha| | | -|verifyRuleText |v1alpha|chronicle.rule_validation.validate_rule |secops rule validate | -|watchlists.create |v1alpha| | | -|watchlists.delete |v1alpha| | | -|watchlists.entities.add |v1alpha| | | -|watchlists.entities.batchAdd |v1alpha| | | -|watchlists.entities.batchRemove |v1alpha| | | -|watchlists.entities.remove |v1alpha| | | -|watchlists.get |v1alpha| | | -|watchlists.list |v1alpha| | | -|watchlists.listEntities |v1alpha| | | -|watchlists.patch |v1alpha| | | +| nativeDashboards.editChart | v1alpha | chronicle.dashboard.edit_chart |secops dashboard edit-chart | +| nativeDashboards.export | v1alpha | chronicle.dashboard.export_dashboard |secops dashboard export | +| nativeDashboards.get | v1alpha | chronicle.dashboard.get_dashboard |secops dashboard get | +| nativeDashboards.import | v1alpha | chronicle.dashboard.import_dashboard |secops dashboard import | +| nativeDashboards.list | v1alpha | chronicle.dashboard.list_dashboards |secops dashboard list | +| nativeDashboards.patch | v1alpha | chronicle.dashboard.update_dashboard |secops dashboard update | +| nativeDashboards.removeChart | v1alpha | chronicle.dashboard.remove_chart |secops dashboard remove-chart | +|operations.cancel |v1alpha| | | +|operations.delete |v1alpha| | | +|operations.get |v1alpha| | | +|operations.list |v1alpha| | | +|operations.streamSearch |v1alpha| | | +|queryProductSourceStats |v1alpha| | | +|referenceLists.create |v1alpha| | | +|referenceLists.get |v1alpha| | | +|referenceLists.list |v1alpha| | | +|referenceLists.patch |v1alpha| | | +|report |v1alpha| | | +|ruleExecutionErrors.list |v1alpha| chronicle.rule_detection.list_errors | | +|rules.create |v1alpha| | | +|rules.delete |v1alpha| | | +|rules.deployments.list |v1alpha| | | +|rules.get |v1alpha| | | +|rules.getDeployment |v1alpha| | | +|rules.list |v1alpha| | | +|rules.listRevisions |v1alpha| | | +|rules.patch |v1alpha| | | +|rules.retrohunts.create |v1alpha| | | +|rules.retrohunts.get |v1alpha| | | +|rules.retrohunts.list |v1alpha| | | +|rules.updateDeployment |v1alpha| | | +|searchEntities |v1alpha| | | +|searchRawLogs |v1alpha| | | +|summarizeEntitiesFromQuery |v1alpha| chronicle.entity.summarize_entity |secops entity | +|summarizeEntity |v1alpha| chronicle.entity.summarize_entity | | +|testFindingsRefinement |v1alpha| | | +|translateUdmQuery |v1alpha| chronicle.nl_search.translate_nl_to_udm | | +|translateYlRule |v1alpha| | | +|udmSearch |v1alpha| chronicle.search.search_udm |secops search | +|undelete |v1alpha| | | +|updateBigQueryExport |v1alpha| | | +|updateRiskConfig |v1alpha| | | +|users.clearConversationHistory |v1alpha| | | +|users.conversations.create |v1alpha| chronicle.gemini.create_conversation | | +|users.conversations.delete |v1alpha| | | +|users.conversations.get |v1alpha| | | +|users.conversations.list |v1alpha| | | +|users.conversations.messages.create |v1alpha| chronicle.gemini.query_gemini |secops gemini | +|users.conversations.messages.delete |v1alpha| | | +|users.conversations.messages.get |v1alpha| | | +|users.conversations.messages.list |v1alpha| | | +|users.conversations.messages.patch |v1alpha| | | +|users.conversations.patch |v1alpha| | | +|users.getPreferenceSet |v1alpha| chronicle.gemini.opt_in_to_gemini |secops gemini --opt-in | +|users.searchQueries.create |v1alpha| | | +|users.searchQueries.delete |v1alpha| | | +|users.searchQueries.get |v1alpha| | | +|users.searchQueries.list |v1alpha| | | +|users.searchQueries.patch |v1alpha| | | +|users.updatePreferenceSet |v1alpha| | | +|validateQuery |v1alpha| chronicle.validate.validate_query | | +|verifyReferenceList |v1alpha| | | +|verifyRuleText |v1alpha| chronicle.rule_validation.validate_rule |secops rule validate | +|watchlists.create |v1alpha| | | +|watchlists.delete |v1alpha| | | +|watchlists.entities.add |v1alpha| | | +|watchlists.entities.batchAdd |v1alpha| | | +|watchlists.entities.batchRemove |v1alpha| | | +|watchlists.entities.remove |v1alpha| | | +|watchlists.get |v1alpha| | | +|watchlists.list |v1alpha| | | +|watchlists.listEntities |v1alpha| | | +|watchlists.patch |v1alpha| | | diff --git a/src/secops/chronicle/__init__.py b/src/secops/chronicle/__init__.py index 37f157f6..36d72801 100644 --- a/src/secops/chronicle/__init__.py +++ b/src/secops/chronicle/__init__.py @@ -132,7 +132,10 @@ update_rule_exclusion_deployment, ) from secops.chronicle.rule_retrohunt import create_retrohunt, get_retrohunt -from secops.chronicle.rule_set import batch_update_curated_rule_set_deployments +from secops.chronicle.rule_set import ( + batch_update_curated_rule_set_deployments, + list_rule_sets, +) from secops.chronicle.rule_validation import ValidationResult from secops.chronicle.search import search_udm from secops.chronicle.stats import get_stats @@ -228,6 +231,7 @@ "get_retrohunt", # Rule set operations "batch_update_curated_rule_set_deployments", + "list_rule_sets", # Native Dashboard "add_chart", "create_dashboard", diff --git a/src/secops/chronicle/client.py b/src/secops/chronicle/client.py index 35ef6254..49afcf81 100644 --- a/src/secops/chronicle/client.py +++ b/src/secops/chronicle/client.py @@ -222,6 +222,7 @@ from secops.chronicle.rule_retrohunt import get_retrohunt as _get_retrohunt from secops.chronicle.rule_set import ( batch_update_curated_rule_set_deployments as _batch_update_curated_rule_set_deployments, # pylint: disable=line-too-long + list_rule_sets as _list_rule_sets, ) from secops.chronicle.rule_validation import validate_rule as _validate_rule from secops.chronicle.search import search_udm as _search_udm @@ -1731,6 +1732,25 @@ def batch_update_curated_rule_set_deployments( """ return _batch_update_curated_rule_set_deployments(self, deployments) + def list_rule_sets( + self, + page_size: Optional[str] = None, + page_token: Optional[str] = None, + ) -> Dict[str, Any]: + """Get a list of all curated rule sets. + + Args: + page_size: Number of results to return per page + page_token: Token for the page to retrieve + + Returns: + Dictionary containing the list of curated rule sets + + Raises: + APIError: If the API request fails + """ + return _list_rule_sets(self, page_size, page_token) + def validate_rule(self, rule_text: str): """Validates a YARA-L2 rule against the Chronicle API. diff --git a/src/secops/chronicle/rule_set.py b/src/secops/chronicle/rule_set.py index a1e3ffc7..af16c8a4 100644 --- a/src/secops/chronicle/rule_set.py +++ b/src/secops/chronicle/rule_set.py @@ -12,12 +12,60 @@ # See the License for the specific language governing permissions and # limitations under the License. # -"""Rule set functionality for Chronicle.""" +"""Curated rule set functionality for Chronicle.""" -from typing import Dict, Any, List +from typing import Dict, Any, List, Optional from secops.exceptions import APIError +def list_rule_sets( + client, + page_size: Optional[str] = None, + page_token: Optional[str] = None, +) -> Dict[str, Any]: + """Get a list of all curated rule sets + + Args: + client: ChronicleClient instance + page_size: Number of results to return per page + page_token: Token for the page to retrieve + + Returns: + Dictionary containing the list of curated rule sets + + Raises: + APIError: If the API request fails + """ + + base_url = ( + f'{client.base_url}/{client.instance_id}/curatedRuleSetCategories/-/curatedRuleSets' + ) + + rule_sets = {"ruleSets": []} + + while True: + params = {"pageSize": 1000 if not page_size else page_size} + if page_token: + params["pageToken"] = page_token + + response = client.session.get(base_url, params=params) + if response.status_code != 200: + raise APIError(f"Failed to list rules: {response.text}") + + data = response.json() + if not data: + return rule_sets + + curated_sets = data.get("curatedRuleSets", []) + rule_sets["ruleSets"].extend(curated_sets) + + page_token = data.get("nextPageToken") + if not page_token: + break + + return rule_sets + + def batch_update_curated_rule_set_deployments( client, deployments: List[Dict[str, Any]] ) -> Dict[str, Any]: From 089549fd3a310e8ff879f402ba74c9fbfe9d053c Mon Sep 17 00:00:00 2001 From: PaperMtn Date: Thu, 23 Oct 2025 21:25:06 +0100 Subject: [PATCH 02/30] refactor: switch to returning list of dicts instead of a dict --- src/secops/chronicle/__init__.py | 4 ++-- src/secops/chronicle/client.py | 6 +++--- src/secops/chronicle/rule_set.py | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/secops/chronicle/__init__.py b/src/secops/chronicle/__init__.py index 36d72801..ca59aebb 100644 --- a/src/secops/chronicle/__init__.py +++ b/src/secops/chronicle/__init__.py @@ -134,7 +134,7 @@ from secops.chronicle.rule_retrohunt import create_retrohunt, get_retrohunt from secops.chronicle.rule_set import ( batch_update_curated_rule_set_deployments, - list_rule_sets, + list_curated_rule_sets, ) from secops.chronicle.rule_validation import ValidationResult from secops.chronicle.search import search_udm @@ -231,7 +231,7 @@ "get_retrohunt", # Rule set operations "batch_update_curated_rule_set_deployments", - "list_rule_sets", + "list_curated_rule_sets", # Native Dashboard "add_chart", "create_dashboard", diff --git a/src/secops/chronicle/client.py b/src/secops/chronicle/client.py index 49afcf81..1d8f7fae 100644 --- a/src/secops/chronicle/client.py +++ b/src/secops/chronicle/client.py @@ -222,7 +222,7 @@ from secops.chronicle.rule_retrohunt import get_retrohunt as _get_retrohunt from secops.chronicle.rule_set import ( batch_update_curated_rule_set_deployments as _batch_update_curated_rule_set_deployments, # pylint: disable=line-too-long - list_rule_sets as _list_rule_sets, + list_curated_rule_sets as _list_curated_rule_sets, ) from secops.chronicle.rule_validation import validate_rule as _validate_rule from secops.chronicle.search import search_udm as _search_udm @@ -1736,7 +1736,7 @@ def list_rule_sets( self, page_size: Optional[str] = None, page_token: Optional[str] = None, - ) -> Dict[str, Any]: + ) -> List[Dict[str, Any]]: """Get a list of all curated rule sets. Args: @@ -1749,7 +1749,7 @@ def list_rule_sets( Raises: APIError: If the API request fails """ - return _list_rule_sets(self, page_size, page_token) + return _list_curated_rule_sets(self, page_size, page_token) def validate_rule(self, rule_text: str): """Validates a YARA-L2 rule against the Chronicle API. diff --git a/src/secops/chronicle/rule_set.py b/src/secops/chronicle/rule_set.py index af16c8a4..2667fd11 100644 --- a/src/secops/chronicle/rule_set.py +++ b/src/secops/chronicle/rule_set.py @@ -18,11 +18,11 @@ from secops.exceptions import APIError -def list_rule_sets( +def list_curated_rule_sets( client, page_size: Optional[str] = None, page_token: Optional[str] = None, -) -> Dict[str, Any]: +) -> List[Dict[str, Any]]: """Get a list of all curated rule sets Args: @@ -41,7 +41,7 @@ def list_rule_sets( f'{client.base_url}/{client.instance_id}/curatedRuleSetCategories/-/curatedRuleSets' ) - rule_sets = {"ruleSets": []} + rule_sets = [] while True: params = {"pageSize": 1000 if not page_size else page_size} @@ -57,7 +57,7 @@ def list_rule_sets( return rule_sets curated_sets = data.get("curatedRuleSets", []) - rule_sets["ruleSets"].extend(curated_sets) + rule_sets.extend(curated_sets) page_token = data.get("nextPageToken") if not page_token: From 69fa5564b45f81eae0a10e51220ff16c37e0dfd5 Mon Sep 17 00:00:00 2001 From: PaperMtn Date: Fri, 24 Oct 2025 10:45:15 +0100 Subject: [PATCH 03/30] feat: added listing curated rule set categories --- api_module_mapping.md | 4 +-- src/secops/chronicle/__init__.py | 4 ++- src/secops/chronicle/client.py | 20 +++++++++++ src/secops/chronicle/rule_set.py | 61 +++++++++++++++++++++++++++++--- 4 files changed, 81 insertions(+), 8 deletions(-) diff --git a/api_module_mapping.md b/api_module_mapping.md index 958d2619..38c6b28e 100644 --- a/api_module_mapping.md +++ b/api_module_mapping.md @@ -85,9 +85,9 @@ Following shows mapping between SecOps [REST Resource](https://cloud.google.com/ |bigQueryExport.provision |v1alpha| | | |cases.countPriorities |v1alpha| | | |curatedRuleSetCategories.curatedRuleSets.curatedRuleSetDeployments.batchUpdate|v1alpha| chronicle.rule_set.batch_update_curated_rule_set_deployments | | -|curatedRuleSetCategories.curatedRuleSets.curatedRuleSetDeployments.patch |v1alpha| chronicle.rule_set.list_rule_sets | | +|curatedRuleSetCategories.curatedRuleSets.curatedRuleSetDeployments.patch |v1alpha| chronicle.rule_set.list_curated_rule_sets | | |curatedRuleSetCategories.curatedRuleSets.get |v1alpha| | | -|curatedRuleSetCategories.curatedRuleSets.list |v1alpha| | | +|curatedRuleSetCategories.curatedRuleSets.list |v1alpha| chronicle.rule_set.list_curated_rule_set_categories | | |curatedRuleSetCategories.get |v1alpha| | | |curatedRuleSetCategories.list |v1alpha| | | |curatedRules.get |v1alpha| | | diff --git a/src/secops/chronicle/__init__.py b/src/secops/chronicle/__init__.py index ca59aebb..548c480f 100644 --- a/src/secops/chronicle/__init__.py +++ b/src/secops/chronicle/__init__.py @@ -132,9 +132,10 @@ update_rule_exclusion_deployment, ) from secops.chronicle.rule_retrohunt import create_retrohunt, get_retrohunt -from secops.chronicle.rule_set import ( +from secops.chronicle.rule_set import ( batch_update_curated_rule_set_deployments, list_curated_rule_sets, + list_curated_rule_set_categories, ) from secops.chronicle.rule_validation import ValidationResult from secops.chronicle.search import search_udm @@ -232,6 +233,7 @@ # Rule set operations "batch_update_curated_rule_set_deployments", "list_curated_rule_sets", + "list_curated_rule_set_categories", # Native Dashboard "add_chart", "create_dashboard", diff --git a/src/secops/chronicle/client.py b/src/secops/chronicle/client.py index 1d8f7fae..ae0de8ad 100644 --- a/src/secops/chronicle/client.py +++ b/src/secops/chronicle/client.py @@ -223,6 +223,7 @@ from secops.chronicle.rule_set import ( batch_update_curated_rule_set_deployments as _batch_update_curated_rule_set_deployments, # pylint: disable=line-too-long list_curated_rule_sets as _list_curated_rule_sets, + list_curated_rule_set_categories as _list_curated_rule_set_categories, ) from secops.chronicle.rule_validation import validate_rule as _validate_rule from secops.chronicle.search import search_udm as _search_udm @@ -1751,6 +1752,25 @@ def list_rule_sets( """ return _list_curated_rule_sets(self, page_size, page_token) + def list_rule_set_categories( + self, + page_size: Optional[str] = None, + page_token: Optional[str] = None, + ) -> List[Dict[str, Any]]: + """Get a list of all curated rule set categories. + + Args: + page_size: Number of results to return per page + page_token: Token for the page to retrieve + + Returns: + Dictionary containing the list of curated rule set categories + + Raises: + APIError: If the API request fails + """ + return _list_curated_rule_set_categories(self, page_size, page_token) + def validate_rule(self, rule_text: str): """Validates a YARA-L2 rule against the Chronicle API. diff --git a/src/secops/chronicle/rule_set.py b/src/secops/chronicle/rule_set.py index 2667fd11..1511135b 100644 --- a/src/secops/chronicle/rule_set.py +++ b/src/secops/chronicle/rule_set.py @@ -19,9 +19,9 @@ def list_curated_rule_sets( - client, - page_size: Optional[str] = None, - page_token: Optional[str] = None, + client, + page_size: Optional[str] = None, + page_token: Optional[str] = None, ) -> List[Dict[str, Any]]: """Get a list of all curated rule sets @@ -38,7 +38,8 @@ def list_curated_rule_sets( """ base_url = ( - f'{client.base_url}/{client.instance_id}/curatedRuleSetCategories/-/curatedRuleSets' + f"{client.base_url}/{client.instance_id}/" + f"curatedRuleSetCategories/-/curatedRuleSets" ) rule_sets = [] @@ -50,7 +51,7 @@ def list_curated_rule_sets( response = client.session.get(base_url, params=params) if response.status_code != 200: - raise APIError(f"Failed to list rules: {response.text}") + raise APIError(f"Failed to list rule sets: {response.text}") data = response.json() if not data: @@ -66,6 +67,56 @@ def list_curated_rule_sets( return rule_sets +def list_curated_rule_set_categories( + client, + page_size: Optional[str] = None, + page_token: Optional[str] = None, +) -> List[Dict[str, Any]]: + """Get a list of all curated rule set categories + + Args: + client: ChronicleClient instance + page_size: Number of results to return per page + page_token: Token for the page to retrieve + + Returns: + Dictionary containing the list of curated rule set categories + + Raises: + APIError: If the API request fails + """ + + base_url = ( + f"{client.base_url}/{client.instance_id}/" f"curatedRuleSetCategories" + ) + + rule_set_categories = [] + + while True: + params = {"pageSize": 1000 if not page_size else page_size} + if page_token: + params["pageToken"] = page_token + + response = client.session.get(base_url, params=params) + if response.status_code != 200: + raise APIError( + f"Failed to list rule set " f"categories: {response.text}" + ) + + data = response.json() + if not data: + return rule_set_categories + + curated_sets = data.get("curatedRuleSetCategories", []) + rule_set_categories.extend(curated_sets) + + page_token = data.get("nextPageToken") + if not page_token: + break + + return rule_set_categories + + def batch_update_curated_rule_set_deployments( client, deployments: List[Dict[str, Any]] ) -> Dict[str, Any]: From 1b2ba98acba4c78e7769ec4c1ce940cdf1e1c18d Mon Sep 17 00:00:00 2001 From: PaperMtn Date: Fri, 24 Oct 2025 11:25:10 +0100 Subject: [PATCH 04/30] feat: added listing all curated rules --- api_module_mapping.md | 2 +- src/secops/chronicle/__init__.py | 2 ++ src/secops/chronicle/client.py | 20 +++++++++++++++ src/secops/chronicle/rule_set.py | 44 ++++++++++++++++++++++++++++++++ 4 files changed, 67 insertions(+), 1 deletion(-) diff --git a/api_module_mapping.md b/api_module_mapping.md index 38c6b28e..bd563d11 100644 --- a/api_module_mapping.md +++ b/api_module_mapping.md @@ -91,7 +91,7 @@ Following shows mapping between SecOps [REST Resource](https://cloud.google.com/ |curatedRuleSetCategories.get |v1alpha| | | |curatedRuleSetCategories.list |v1alpha| | | |curatedRules.get |v1alpha| | | -|curatedRules.list |v1alpha| | | +|curatedRules.list |v1alpha| chronicle.rule_set.list_curated_rules | | |dashboardCharts.batchGet |v1alpha| | | |dashboardCharts.get |v1alpha| chronicle.dashboard.get_chart |secops dashboard get-chart | |dashboardQueries.execute |v1alpha| chronicle.dashboard_query.execute_query |secops dashboard-query execute | diff --git a/src/secops/chronicle/__init__.py b/src/secops/chronicle/__init__.py index 548c480f..e5e2520f 100644 --- a/src/secops/chronicle/__init__.py +++ b/src/secops/chronicle/__init__.py @@ -136,6 +136,7 @@ batch_update_curated_rule_set_deployments, list_curated_rule_sets, list_curated_rule_set_categories, + list_curated_rules, ) from secops.chronicle.rule_validation import ValidationResult from secops.chronicle.search import search_udm @@ -234,6 +235,7 @@ "batch_update_curated_rule_set_deployments", "list_curated_rule_sets", "list_curated_rule_set_categories", + "list_curated_rules", # Native Dashboard "add_chart", "create_dashboard", diff --git a/src/secops/chronicle/client.py b/src/secops/chronicle/client.py index ae0de8ad..043f57e5 100644 --- a/src/secops/chronicle/client.py +++ b/src/secops/chronicle/client.py @@ -224,6 +224,7 @@ batch_update_curated_rule_set_deployments as _batch_update_curated_rule_set_deployments, # pylint: disable=line-too-long list_curated_rule_sets as _list_curated_rule_sets, list_curated_rule_set_categories as _list_curated_rule_set_categories, + list_curated_rules as _list_curated_rules, ) from secops.chronicle.rule_validation import validate_rule as _validate_rule from secops.chronicle.search import search_udm as _search_udm @@ -1771,6 +1772,25 @@ def list_rule_set_categories( """ return _list_curated_rule_set_categories(self, page_size, page_token) + def list_curated_rules( + self, + page_size: Optional[str] = None, + page_token: Optional[str] = None, + ) -> List[Dict[str, Any]]: + """Get a list of all curated rules. + + Args: + page_size: Number of results to return per page + page_token: Token for the page to retrieve + + Returns: + Dictionary containing the list of curated rules + + Raises: + APIError: If the API request fails + """ + return _list_curated_rules(self, page_size, page_token) + def validate_rule(self, rule_text: str): """Validates a YARA-L2 rule against the Chronicle API. diff --git a/src/secops/chronicle/rule_set.py b/src/secops/chronicle/rule_set.py index 1511135b..6db2634f 100644 --- a/src/secops/chronicle/rule_set.py +++ b/src/secops/chronicle/rule_set.py @@ -117,6 +117,50 @@ def list_curated_rule_set_categories( return rule_set_categories +def list_curated_rules( + client, + page_size: Optional[str] = None, + page_token: Optional[str] = None, +) -> List[Dict[str, Any]]: + """Get a list of all curated rules + + Args: + client: ChronicleClient instance + page_size: Number of results to return per page + page_token: Token for the page to retrieve + + Returns: + Dictionary containing the list of curated rules + + Raises: + APIError: If the API request fails + """ + base_url = f"{client.base_url}/{client.instance_id}/" f"curatedRules" + + curated_rules = [] + + while True: + params = {"pageSize": 1000 if not page_size else page_size} + if page_token: + params["pageToken"] = page_token + + response = client.session.get(base_url, params=params) + if response.status_code != 200: + raise APIError(f"Failed to list curated rules: {response.text}") + + data = response.json() + if not data: + return curated_rules + + curated_rules.extend(data.get("curatedRules", [])) + + page_token = data.get("nextPageToken") + if not page_token: + break + + return curated_rules + + def batch_update_curated_rule_set_deployments( client, deployments: List[Dict[str, Any]] ) -> Dict[str, Any]: From 738bfe77adafe44b198a69db95cdd185ec67d6e5 Mon Sep 17 00:00:00 2001 From: PaperMtn Date: Fri, 24 Oct 2025 13:38:50 +0100 Subject: [PATCH 05/30] feat: added getting a curated rule by ID --- api_module_mapping.md | 2 +- src/secops/chronicle/__init__.py | 2 ++ src/secops/chronicle/client.py | 15 +++++++++++++++ src/secops/chronicle/rule_set.py | 26 ++++++++++++++++++++++++++ 4 files changed, 44 insertions(+), 1 deletion(-) diff --git a/api_module_mapping.md b/api_module_mapping.md index bd563d11..e72087f7 100644 --- a/api_module_mapping.md +++ b/api_module_mapping.md @@ -90,7 +90,7 @@ Following shows mapping between SecOps [REST Resource](https://cloud.google.com/ |curatedRuleSetCategories.curatedRuleSets.list |v1alpha| chronicle.rule_set.list_curated_rule_set_categories | | |curatedRuleSetCategories.get |v1alpha| | | |curatedRuleSetCategories.list |v1alpha| | | -|curatedRules.get |v1alpha| | | +|curatedRules.get |v1alpha| chronicle.rule_set.get_curated_rule | | |curatedRules.list |v1alpha| chronicle.rule_set.list_curated_rules | | |dashboardCharts.batchGet |v1alpha| | | |dashboardCharts.get |v1alpha| chronicle.dashboard.get_chart |secops dashboard get-chart | diff --git a/src/secops/chronicle/__init__.py b/src/secops/chronicle/__init__.py index e5e2520f..bfe38c07 100644 --- a/src/secops/chronicle/__init__.py +++ b/src/secops/chronicle/__init__.py @@ -137,6 +137,7 @@ list_curated_rule_sets, list_curated_rule_set_categories, list_curated_rules, + get_curated_rule, ) from secops.chronicle.rule_validation import ValidationResult from secops.chronicle.search import search_udm @@ -236,6 +237,7 @@ "list_curated_rule_sets", "list_curated_rule_set_categories", "list_curated_rules", + "get_curated_rule", # Native Dashboard "add_chart", "create_dashboard", diff --git a/src/secops/chronicle/client.py b/src/secops/chronicle/client.py index 043f57e5..7b18bd06 100644 --- a/src/secops/chronicle/client.py +++ b/src/secops/chronicle/client.py @@ -225,6 +225,7 @@ list_curated_rule_sets as _list_curated_rule_sets, list_curated_rule_set_categories as _list_curated_rule_set_categories, list_curated_rules as _list_curated_rules, + get_curated_rule as _get_curated_rule, ) from secops.chronicle.rule_validation import validate_rule as _validate_rule from secops.chronicle.search import search_udm as _search_udm @@ -1791,6 +1792,20 @@ def list_curated_rules( """ return _list_curated_rules(self, page_size, page_token) + def get_curated_rule(self, rule_id: str) -> Dict[str, Any]: + """Get a curated rule by ID. + + Args: + rule_id: ID of the curated rule + + Returns: + Dictionary containing the curated rule + + Raises: + APIError: If the API request fails + """ + return _get_curated_rule(self, rule_id) + def validate_rule(self, rule_text: str): """Validates a YARA-L2 rule against the Chronicle API. diff --git a/src/secops/chronicle/rule_set.py b/src/secops/chronicle/rule_set.py index 6db2634f..9d54cf68 100644 --- a/src/secops/chronicle/rule_set.py +++ b/src/secops/chronicle/rule_set.py @@ -161,6 +161,32 @@ def list_curated_rules( return curated_rules +def get_curated_rule(client, rule_id: str) -> Dict[str, Any]: + """Get a curated rule by ID + + Args: + client: ChronicleClient instance + rule_id: Unique ID of the curated rule to retrieve ("ur_" + or "ur_). + Examples: + `ur_ffac5fa0-5b0b-463e-9f92-2443f8f1b6fd` + `ur_ttp_GCP_MassSecretDeletion` + + Returns: + Dictionary containing the curated rule + + Raises: + APIError: If the API request fails + """ + base_url = f"{client.base_url}/{client.instance_id}/" f"curatedRules/{rule_id}" + + response = client.session.get(base_url) + if response.status_code != 200: + raise APIError(f"Failed to get curated rule: {response.text}") + + return response.json() + + def batch_update_curated_rule_set_deployments( client, deployments: List[Dict[str, Any]] ) -> Dict[str, Any]: From 9920901b0cae8910e35329722c9e76149034fcf9 Mon Sep 17 00:00:00 2001 From: PaperMtn Date: Fri, 24 Oct 2025 13:57:17 +0100 Subject: [PATCH 06/30] feat: added getting a curated rule set category by ID --- api_module_mapping.md | 747 ++++++++++++++++--------------- src/secops/chronicle/__init__.py | 2 + src/secops/chronicle/client.py | 15 + src/secops/chronicle/rule_set.py | 27 ++ 4 files changed, 418 insertions(+), 373 deletions(-) diff --git a/api_module_mapping.md b/api_module_mapping.md index e72087f7..9a95c914 100644 --- a/api_module_mapping.md +++ b/api_module_mapping.md @@ -1,379 +1,380 @@ # SecOps API Endpoint and SDK Wrapper Module Mapping -Following shows mapping between SecOps [REST Resource](https://cloud.google.com/chronicle/docs/reference/rest) and SDK wrapper module and its respective CLI command (if available). +Following shows mapping between SecOps [REST Resource](https://cloud.google.com/chronicle/docs/reference/rest) and SDK +wrapper module and its respective CLI command (if available). **Note:** All the REST resources mentioned have suffix `projects.locations.instances`. -|REST Resource |Version| secops-wrapper module |CLI Command | -|------------------------------------------------------------------------------|-------|--------------------------------------------------------------|---------------------------------------| -|dataAccessLabels.create |v1 | | | -|dataAccessLabels.delete |v1 | | | -|dataAccessLabels.get |v1 | | | -|dataAccessLabels.list |v1 | | | -|dataAccessLabels.patch |v1 | | | -|dataAccessScopes.create |v1 | | | -|dataAccessScopes.delete |v1 | | | -|dataAccessScopes.get |v1 | | | -|dataAccessScopes.list |v1 | | | -|dataAccessScopes.patch |v1 | | | -|get |v1 | | | -|operations.cancel |v1 | | | -|operations.delete |v1 | | | -|operations.get |v1 | | | -|operations.list |v1 | | | -|referenceLists.create |v1 | chronicle.reference_list.create_reference_list |secops reference-list create | -|referenceLists.get |v1 | chronicle.reference_list.get_reference_list |secops reference-list get | -|referenceLists.list |v1 | chronicle.reference_list.list_reference_lists |secops reference-list list | -|referenceLists.patch |v1 | chronicle.reference_list.update_reference_list |secops reference-list update | -|rules.create |v1 | chronicle.rule.create_rule |secops rule create | -|rules.delete |v1 | chronicle.rule.delete_rule |secops rule delete | -|rules.deployments.list |v1 | | | -|rules.get |v1 | chronicle.rule.get_rule |secops rule get | -|rules.getDeployment |v1 | | | -|rules.list |v1 | chronicle.rule.list_rules |secops rule list | -|rules.listRevisions |v1 | | | -|rules.patch |v1 | chronicle.rule.update_rule |secops rule update | -|rules.retrohunts.create |v1 | chronicle.rule_retrohunt.create_retrohunt | | -|rules.retrohunts.get |v1 | chronicle.rule_retrohunt.get_retrohunt | | -|rules.retrohunts.list |v1 | | | -|rules.updateDeployment |v1 | chronicle.rule.enable_rule |secops rule enable | -|watchlists.create |v1 | | | -|watchlists.delete |v1 | | | -|watchlists.get |v1 | | | -|watchlists.list |v1 | | | -|watchlists.patch |v1 | | | -|dataAccessLabels.create |v1beta | | | -|dataAccessLabels.delete |v1beta | | | -|dataAccessLabels.get |v1beta | | | -|dataAccessLabels.list |v1beta | | | -|dataAccessLabels.patch |v1beta | | | -|dataAccessScopes.create |v1beta | | | -|dataAccessScopes.delete |v1beta | | | -|dataAccessScopes.get |v1beta | | | -|dataAccessScopes.list |v1beta | | | -|dataAccessScopes.patch |v1beta | | | -|get |v1beta | | | -|operations.cancel |v1beta | | | -|operations.delete |v1beta | | | -|operations.get |v1beta | | | -|operations.list |v1beta | | | -|referenceLists.create |v1beta | | | -|referenceLists.get |v1beta | | | -|referenceLists.list |v1beta | | | -|referenceLists.patch |v1beta | | | -|rules.create |v1beta | | | -|rules.delete |v1beta | | | -|rules.deployments.list |v1beta | | | -|rules.get |v1beta | | | -|rules.getDeployment |v1beta | | | -|rules.list |v1beta | | | -|rules.listRevisions |v1beta | | | -|rules.patch |v1beta | | | -|rules.retrohunts.create |v1beta | | | -|rules.retrohunts.get |v1beta | | | -|rules.retrohunts.list |v1beta | | | -|rules.updateDeployment |v1beta | | | -|watchlists.create |v1beta | | | -|watchlists.delete |v1beta | | | -|watchlists.get |v1beta | | | -|watchlists.list |v1beta | | | -|watchlists.patch |v1beta | | | -|analytics.entities.analyticValues.list |v1alpha| | | -|analytics.list |v1alpha| | | -|batchValidateWatchlistEntities |v1alpha| | | -|bigQueryAccess.provide |v1alpha| | | -|bigQueryExport.provision |v1alpha| | | -|cases.countPriorities |v1alpha| | | -|curatedRuleSetCategories.curatedRuleSets.curatedRuleSetDeployments.batchUpdate|v1alpha| chronicle.rule_set.batch_update_curated_rule_set_deployments | | -|curatedRuleSetCategories.curatedRuleSets.curatedRuleSetDeployments.patch |v1alpha| chronicle.rule_set.list_curated_rule_sets | | -|curatedRuleSetCategories.curatedRuleSets.get |v1alpha| | | -|curatedRuleSetCategories.curatedRuleSets.list |v1alpha| chronicle.rule_set.list_curated_rule_set_categories | | -|curatedRuleSetCategories.get |v1alpha| | | -|curatedRuleSetCategories.list |v1alpha| | | -|curatedRules.get |v1alpha| chronicle.rule_set.get_curated_rule | | -|curatedRules.list |v1alpha| chronicle.rule_set.list_curated_rules | | -|dashboardCharts.batchGet |v1alpha| | | -|dashboardCharts.get |v1alpha| chronicle.dashboard.get_chart |secops dashboard get-chart | -|dashboardQueries.execute |v1alpha| chronicle.dashboard_query.execute_query |secops dashboard-query execute | -|dashboardQueries.get |v1alpha| chronicle.dashboard_query.get_execute_query |secops dashboard-query get | -|dashboards.copy |v1alpha| | | -|dashboards.create |v1alpha| | | -|dashboards.delete |v1alpha| | | -|dashboards.get |v1alpha| | | -|dashboards.list |v1alpha| | | -|dataAccessLabels.create |v1alpha| | | -|dataAccessLabels.delete |v1alpha| | | -|dataAccessLabels.get |v1alpha| | | -|dataAccessLabels.list |v1alpha| | | -|dataAccessLabels.patch |v1alpha| | | -|dataAccessScopes.create |v1alpha| | | -|dataAccessScopes.delete |v1alpha| | | -|dataAccessScopes.get |v1alpha| | | -|dataAccessScopes.list |v1alpha| | | -|dataAccessScopes.patch |v1alpha| | | -|dataExports.cancel |v1alpha| chronicle.data_export.cancel_data_export |secops export cancel | -|dataExports.create |v1alpha| chronicle.data_export.create_data_export |secops export create | -|dataExports.fetchavailablelogtypes |v1alpha| chronicle.data_export.fetch_available_log_types |secops export log-types | -|dataExports.get |v1alpha| chronicle.data_export.get_data_export |secops export status | -|dataExports.list |v1alpha| chronicle.data_export.list_data_export |secops export list | -|dataExports.patch |v1alpha| chronicle.data_export.update_data_export |secops export update | -|dataTableOperationErrors.get |v1alpha| | | -|dataTables.create |v1alpha| chronicle.data_table.create_data_table |secops data-table create | -|dataTables.dataTableRows.bulkCreate |v1alpha| chronicle.data_table.create_data_table_rows |secops data-table add-rows | -|dataTables.dataTableRows.bulkCreateAsync |v1alpha| | | -|dataTables.dataTableRows.bulkGet |v1alpha| | | -|dataTables.dataTableRows.bulkReplace |v1alpha| | | -|dataTables.dataTableRows.bulkReplaceAsync |v1alpha| | | -|dataTables.dataTableRows.bulkUpdate |v1alpha| | | -|dataTables.dataTableRows.bulkUpdateAsync |v1alpha| | | -|dataTables.dataTableRows.create |v1alpha| | | -|dataTables.dataTableRows.delete |v1alpha| chronicle.data_table.delete_data_table_rows |secops data-table delete-rows | -|dataTables.dataTableRows.get |v1alpha| | | -|dataTables.dataTableRows.list |v1alpha| chronicle.data_table.list_data_table_rows |secops data-table list-rows | -|dataTables.dataTableRows.patch |v1alpha| | | -|dataTables.delete |v1alpha| chronicle.data_table.delete_data_table |secops data-table delete | -|dataTables.get |v1alpha| chronicle.data_table.get_data_table |secops data-table get | -|dataTables.list |v1alpha| chronicle.data_table.list_data_tables |secops data-table list | -|dataTables.patch |v1alpha| | | -|dataTables.upload |v1alpha| | | -|dataTaps.create |v1alpha| | | -|dataTaps.delete |v1alpha| | | -|dataTaps.get |v1alpha| | | -|dataTaps.list |v1alpha| | | -|dataTaps.patch |v1alpha| | | -|delete |v1alpha| | | -|enrichmentControls.create |v1alpha| | | -|enrichmentControls.delete |v1alpha| | | -|enrichmentControls.get |v1alpha| | | -|enrichmentControls.list |v1alpha| | | -|entities.get |v1alpha| | | -|entities.import |v1alpha| | | -|entities.modifyEntityRiskScore |v1alpha| | | -|entities.queryEntityRiskScoreModifications |v1alpha| | | -|entityRiskScores.query |v1alpha| | | -|errorNotificationConfigs.create |v1alpha| | | -|errorNotificationConfigs.delete |v1alpha| | | -|errorNotificationConfigs.get |v1alpha| | | -|errorNotificationConfigs.list |v1alpha| | | -|errorNotificationConfigs.patch |v1alpha| | | -|events.batchGet |v1alpha| | | -|events.get |v1alpha| | | -|events.import |v1alpha| chronicle.log_ingest.ingest_udm |secops log ingest-udm | -|extractSyslog |v1alpha| | | -|federationGroups.create |v1alpha| | | -|federationGroups.delete |v1alpha| | | -|federationGroups.get |v1alpha| | | -|federationGroups.list |v1alpha| | | -|federationGroups.patch |v1alpha| | | -|feedPacks.get |v1alpha| | | -|feedPacks.list |v1alpha| | | -|feedServiceAccounts.fetchServiceAccountForCustomer |v1alpha| | | -|feedSourceTypeSchemas.list |v1alpha| | | -|feedSourceTypeSchemas.logTypeSchemas.list |v1alpha| | | -|feeds.create |v1alpha| chronicle.feeds.create_feed |secops feed create | -|feeds.delete |v1alpha| chronicle.feeds.delete_feed |secops feed delete | -|feeds.disable |v1alpha| chronicle.feeds.disable_feed |secops feed disable | -|feeds.enable |v1alpha| chronicle.feeds.enable_feed |secops feed enable | -|feeds.generateSecret |v1alpha| chronicle.feeds.generate_secret |secops feed secret | -|feeds.get |v1alpha| chronicle.feeds.get_feed |secops feed get | -|feeds.importPushLogs |v1alpha| | | -|feeds.list |v1alpha| chronicle.feeds.list_feeds |secops feed list | -|feeds.patch |v1alpha| chronicle.feeds.update_feed |secops feed update | -|feeds.scheduleTransfer |v1alpha| | | -|fetchFederationAccess |v1alpha| | | -|findEntity |v1alpha| | | -|findEntityAlerts |v1alpha| | | -|findRelatedEntities |v1alpha| | | -|findUdmFieldValues |v1alpha| | | -|findingsGraph.exploreNode |v1alpha| | | -|findingsGraph.initializeGraph |v1alpha| | | -|findingsRefinements.computeFindingsRefinementActivity |v1alpha| chronicle.rule_exclusion.compute_rule_exclusion_activity |secops rule-exclusion compute-activity | -|findingsRefinements.create |v1alpha| chronicle.rule_exclusion.create_rule_exclusion |secops rule-exclusion create | -|findingsRefinements.get |v1alpha| chronicle.rule_exclusion.get_rule_exclusion |secops rule-exclusion get | -|findingsRefinements.getDeployment |v1alpha| chronicle.rule_exclusion.get_rule_exclusion_deployment |secops rule-exclusion get-deployment | -|findingsRefinements.list |v1alpha| chronicle.rule_exclusion.list_rule_exclusions |secops rule-exclusion list | -|findingsRefinements.patch |v1alpha| chronicle.rule_exclusion.patch_rule_exclusion |secops rule-exclusion update | -|findingsRefinements.updateDeployment |v1alpha| chronicle.rule_exclusion.update_rule_exclusion_deployment |secops rule-exclusion update-deployment| -|forwarders.collectors.create |v1alpha| | | -|forwarders.collectors.delete |v1alpha| | | -|forwarders.collectors.get |v1alpha| | | -|forwarders.collectors.list |v1alpha| | | -|forwarders.collectors.patch |v1alpha| | | -|forwarders.create |v1alpha| chronicle.log_ingest.create_forwarder |secops forwarder create | -|forwarders.delete |v1alpha| chronicle.log_ingest.delete_forwarder |secops forwarder delete | -|forwarders.generateForwarderFiles |v1alpha| | | -|forwarders.get |v1alpha| chronicle.log_ingest.get_forwarder |secops forwarder get | -|forwarders.importStatsEvents |v1alpha| | | -|forwarders.list |v1alpha| chronicle.log_ingest.list_forwarder |secops forwarder list | -|forwarders.patch |v1alpha| chronicle.log_ingest.update_forwarder |secops forwarder update | -|generateCollectionAgentAuth |v1alpha| | | -|generateSoarAuthJwt |v1alpha| | | -|generateUdmKeyValueMappings |v1alpha| | | -|generateWorkspaceConnectionToken |v1alpha| | | -|get |v1alpha| | | -|getBigQueryExport |v1alpha| | | -|getMultitenantDirectory |v1alpha| | | -|getRiskConfig |v1alpha| | | -|ingestionLogLabels.get |v1alpha| | | -|ingestionLogLabels.list |v1alpha| | | -|ingestionLogNamespaces.get |v1alpha| | | -|ingestionLogNamespaces.list |v1alpha| | | -|iocs.batchGet |v1alpha| | | -|iocs.findFirstAndLastSeen |v1alpha| | | -|iocs.get |v1alpha| | | -|iocs.getIocState |v1alpha| | | -|iocs.searchCuratedDetectionsForIoc |v1alpha| | | -|iocs.updateIocState |v1alpha| | | -|legacy.legacyBatchGetCases |v1alpha| chronicle.case.get_cases_from_list |secops case | -|legacy.legacyBatchGetCollections |v1alpha| | | -|legacy.legacyCreateOrUpdateCase |v1alpha| | | -|legacy.legacyCreateSoarAlert |v1alpha| | | -|legacy.legacyFetchAlertsView |v1alpha| chronicle.alert.get_alerts |secops alert | -|legacy.legacyFetchUdmSearchCsv |v1alpha| chronicle.udm_search.fetch_udm_search_csv |secops search --csv | -|legacy.legacyFetchUdmSearchView |v1alpha| chronicle.udm_search.fetch_udm_search_view |secops udm-search-view | -|legacy.legacyFindAssetEvents |v1alpha| | | -|legacy.legacyFindRawLogs |v1alpha| | | -|legacy.legacyFindUdmEvents |v1alpha| | | -|legacy.legacyGetAlert |v1alpha| chronicle.rule_alert.get_alert | | -|legacy.legacyGetCuratedRulesTrends |v1alpha| | | -|legacy.legacyGetDetection |v1alpha| | | -|legacy.legacyGetEventForDetection |v1alpha| | | -|legacy.legacyGetRuleCounts |v1alpha| | | -|legacy.legacyGetRulesTrends |v1alpha| | | -|legacy.legacyListCases |v1alpha| chronicle.case.get_cases |secops case --ids | -|legacy.legacyRunTestRule |v1alpha| chronicle.rule.run_rule_test |secops rule validate | -|legacy.legacySearchArtifactEvents |v1alpha| | | -|legacy.legacySearchArtifactIoCDetails |v1alpha| | | -|legacy.legacySearchAssetEvents |v1alpha| | | -|legacy.legacySearchCuratedDetections |v1alpha| | | -|legacy.legacySearchCustomerStats |v1alpha| | | -|legacy.legacySearchDetections |v1alpha| chronicle.rule_detection.list_detections | | -|legacy.legacySearchDomainsRecentlyRegistered |v1alpha| | | -|legacy.legacySearchDomainsTimingStats |v1alpha| | | -|legacy.legacySearchEnterpriseWideAlerts |v1alpha| | | -|legacy.legacySearchEnterpriseWideIoCs |v1alpha| chronicle.ioc.list_iocs |secops iocs | -|legacy.legacySearchFindings |v1alpha| | | -|legacy.legacySearchIngestionStats |v1alpha| | | -|legacy.legacySearchIoCInsights |v1alpha| | | -|legacy.legacySearchRawLogs |v1alpha| | | -|legacy.legacySearchRuleDetectionCountBuckets |v1alpha| | | -|legacy.legacySearchRuleDetectionEvents |v1alpha| | | -|legacy.legacySearchRuleResults |v1alpha| | | -|legacy.legacySearchRulesAlerts |v1alpha| chronicle.rule_alert.search_rule_alerts | | -|legacy.legacySearchUserEvents |v1alpha| | | -|legacy.legacyStreamDetectionAlerts |v1alpha| | | -|legacy.legacyTestRuleStreaming |v1alpha| | | -|legacy.legacyUpdateAlert |v1alpha| chronicle.rule_alert.update_alert | | -|listAllFindingsRefinementDeployments |v1alpha| | | -|logTypes.create |v1alpha| | | -|logTypes.generateEventTypesSuggestions |v1alpha| | | -|logTypes.get |v1alpha| | | -|logTypes.getLogTypeSetting |v1alpha| | | -|logTypes.legacySubmitParserExtension |v1alpha| | | -|logTypes.list |v1alpha| | | -|logTypes.logs.export |v1alpha| | | -|logTypes.logs.get |v1alpha| | | -|logTypes.logs.import |v1alpha| chronicle.log_ingest.ingest_log |secops log ingest | -|logTypes.logs.list |v1alpha| | | -|logTypes.parserExtensions.activate |v1alpha| chronicle.parser_extension.activate_parser_extension |secops parser-extension activate | -|logTypes.parserExtensions.create |v1alpha| chronicle.parser_extension.create_parser_extension |secops parser-extension create | -|logTypes.parserExtensions.delete |v1alpha| chronicle.parser_extension.delete_parser_extension |secops parser-extension delete | -|logTypes.parserExtensions.extensionValidationReports.get |v1alpha| | | -|logTypes.parserExtensions.extensionValidationReports.list |v1alpha| | | -|logTypes.parserExtensions.extensionValidationReports.validationErrors.list |v1alpha| | | -|logTypes.parserExtensions.get |v1alpha| chronicle.parser_extension.get_parser_extension |secops parser-extension get | -|logTypes.parserExtensions.list |v1alpha| chronicle.parser_extension.list_parser_extensions |secops parser-extension list | -|logTypes.parserExtensions.validationReports.get |v1alpha| | | -|logTypes.parserExtensions.validationReports.parsingErrors.list |v1alpha| | | -|logTypes.parsers.activate |v1alpha| chronicle.parser.activate_parser |secops parser activate | -|logTypes.parsers.activateReleaseCandidateParser |v1alpha| chronicle.parser.activate_release_candidate |secops parser activate-rc | -|logTypes.parsers.copy |v1alpha| chronicle.parser.copy_parser |secops parser copy | -|logTypes.parsers.create |v1alpha| chronicle.parser.create_parser |secops parser create | -|logTypes.parsers.deactivate |v1alpha| chronicle.parser.deactivate_parser |secops parser deactivate | -|logTypes.parsers.delete |v1alpha| chronicle.parser.delete_parser |secops parser delete | -|logTypes.parsers.get |v1alpha| chronicle.parser.get_parser |secops parser get | -|logTypes.parsers.list |v1alpha| chronicle.parser.list_parsers |secops parser list | -|logTypes.parsers.validationReports.get |v1alpha| | | -|logTypes.parsers.validationReports.parsingErrors.list |v1alpha| | | -|logTypes.patch |v1alpha| | | -|logTypes.runParser |v1alpha| chronicle.parser.run_parser |secops parser run | -|logTypes.updateLogTypeSetting |v1alpha| | | -|logs.classify |v1alpha| | | -| nativeDashboards.addChart | v1alpha | chronicle.dashboard.add_chart |secops dashboard add-chart | -| nativeDashboards.create | v1alpha | chronicle.dashboard.create_dashboard |secops dashboard create | -| nativeDashboards.delete | v1alpha | chronicle.dashboard.delete_dashboard |secops dashboard delete | -| nativeDashboards.duplicate | v1alpha | chronicle.dashboard.duplicate_dashboard |secops dashboard duplicate | +| REST Resource | Version | secops-wrapper module | CLI Command | +|--------------------------------------------------------------------------------|---------|--------------------------------------------------------------|-----------------------------------------| +| dataAccessLabels.create | v1 | | | +| dataAccessLabels.delete | v1 | | | +| dataAccessLabels.get | v1 | | | +| dataAccessLabels.list | v1 | | | +| dataAccessLabels.patch | v1 | | | +| dataAccessScopes.create | v1 | | | +| dataAccessScopes.delete | v1 | | | +| dataAccessScopes.get | v1 | | | +| dataAccessScopes.list | v1 | | | +| dataAccessScopes.patch | v1 | | | +| get | v1 | | | +| operations.cancel | v1 | | | +| operations.delete | v1 | | | +| operations.get | v1 | | | +| operations.list | v1 | | | +| referenceLists.create | v1 | chronicle.reference_list.create_reference_list | secops reference-list create | +| referenceLists.get | v1 | chronicle.reference_list.get_reference_list | secops reference-list get | +| referenceLists.list | v1 | chronicle.reference_list.list_reference_lists | secops reference-list list | +| referenceLists.patch | v1 | chronicle.reference_list.update_reference_list | secops reference-list update | +| rules.create | v1 | chronicle.rule.create_rule | secops rule create | +| rules.delete | v1 | chronicle.rule.delete_rule | secops rule delete | +| rules.deployments.list | v1 | | | +| rules.get | v1 | chronicle.rule.get_rule | secops rule get | +| rules.getDeployment | v1 | | | +| rules.list | v1 | chronicle.rule.list_rules | secops rule list | +| rules.listRevisions | v1 | | | +| rules.patch | v1 | chronicle.rule.update_rule | secops rule update | +| rules.retrohunts.create | v1 | chronicle.rule_retrohunt.create_retrohunt | | +| rules.retrohunts.get | v1 | chronicle.rule_retrohunt.get_retrohunt | | +| rules.retrohunts.list | v1 | | | +| rules.updateDeployment | v1 | chronicle.rule.enable_rule | secops rule enable | +| watchlists.create | v1 | | | +| watchlists.delete | v1 | | | +| watchlists.get | v1 | | | +| watchlists.list | v1 | | | +| watchlists.patch | v1 | | | +| dataAccessLabels.create | v1beta | | | +| dataAccessLabels.delete | v1beta | | | +| dataAccessLabels.get | v1beta | | | +| dataAccessLabels.list | v1beta | | | +| dataAccessLabels.patch | v1beta | | | +| dataAccessScopes.create | v1beta | | | +| dataAccessScopes.delete | v1beta | | | +| dataAccessScopes.get | v1beta | | | +| dataAccessScopes.list | v1beta | | | +| dataAccessScopes.patch | v1beta | | | +| get | v1beta | | | +| operations.cancel | v1beta | | | +| operations.delete | v1beta | | | +| operations.get | v1beta | | | +| operations.list | v1beta | | | +| referenceLists.create | v1beta | | | +| referenceLists.get | v1beta | | | +| referenceLists.list | v1beta | | | +| referenceLists.patch | v1beta | | | +| rules.create | v1beta | | | +| rules.delete | v1beta | | | +| rules.deployments.list | v1beta | | | +| rules.get | v1beta | | | +| rules.getDeployment | v1beta | | | +| rules.list | v1beta | | | +| rules.listRevisions | v1beta | | | +| rules.patch | v1beta | | | +| rules.retrohunts.create | v1beta | | | +| rules.retrohunts.get | v1beta | | | +| rules.retrohunts.list | v1beta | | | +| rules.updateDeployment | v1beta | | | +| watchlists.create | v1beta | | | +| watchlists.delete | v1beta | | | +| watchlists.get | v1beta | | | +| watchlists.list | v1beta | | | +| watchlists.patch | v1beta | | | +| analytics.entities.analyticValues.list | v1alpha | | | +| analytics.list | v1alpha | | | +| batchValidateWatchlistEntities | v1alpha | | | +| bigQueryAccess.provide | v1alpha | | | +| bigQueryExport.provision | v1alpha | | | +| cases.countPriorities | v1alpha | | | +| curatedRuleSetCategories.curatedRuleSets.curatedRuleSetDeployments.batchUpdate | v1alpha | chronicle.rule_set.batch_update_curated_rule_set_deployments | | +| curatedRuleSetCategories.curatedRuleSets.curatedRuleSetDeployments.patch | v1alpha | | | +| curatedRuleSetCategories.curatedRuleSets.get | v1alpha | | | +| curatedRuleSetCategories.curatedRuleSets.list | v1alpha | chronicle.rule_set.list_curated_rule_sets | | +| curatedRuleSetCategories.get | v1alpha | chronicle.rule_set.get_curated_rule_set_category | | +| curatedRuleSetCategories.list | v1alpha | chronicle.rule_set.list_curated_rule_set_categories | | +| curatedRules.get | v1alpha | chronicle.rule_set.get_curated_rule | | +| curatedRules.list | v1alpha | chronicle.rule_set.list_curated_rules | | +| dashboardCharts.batchGet | v1alpha | | | +| dashboardCharts.get | v1alpha | chronicle.dashboard.get_chart | secops dashboard get-chart | +| dashboardQueries.execute | v1alpha | chronicle.dashboard_query.execute_query | secops dashboard-query execute | +| dashboardQueries.get | v1alpha | chronicle.dashboard_query.get_execute_query | secops dashboard-query get | +| dashboards.copy | v1alpha | | | +| dashboards.create | v1alpha | | | +| dashboards.delete | v1alpha | | | +| dashboards.get | v1alpha | | | +| dashboards.list | v1alpha | | | +| dataAccessLabels.create | v1alpha | | | +| dataAccessLabels.delete | v1alpha | | | +| dataAccessLabels.get | v1alpha | | | +| dataAccessLabels.list | v1alpha | | | +| dataAccessLabels.patch | v1alpha | | | +| dataAccessScopes.create | v1alpha | | | +| dataAccessScopes.delete | v1alpha | | | +| dataAccessScopes.get | v1alpha | | | +| dataAccessScopes.list | v1alpha | | | +| dataAccessScopes.patch | v1alpha | | | +| dataExports.cancel | v1alpha | chronicle.data_export.cancel_data_export | secops export cancel | +| dataExports.create | v1alpha | chronicle.data_export.create_data_export | secops export create | +| dataExports.fetchavailablelogtypes | v1alpha | chronicle.data_export.fetch_available_log_types | secops export log-types | +| dataExports.get | v1alpha | chronicle.data_export.get_data_export | secops export status | +| dataExports.list | v1alpha | chronicle.data_export.list_data_export | secops export list | +| dataExports.patch | v1alpha | chronicle.data_export.update_data_export | secops export update | +| dataTableOperationErrors.get | v1alpha | | | +| dataTables.create | v1alpha | chronicle.data_table.create_data_table | secops data-table create | +| dataTables.dataTableRows.bulkCreate | v1alpha | chronicle.data_table.create_data_table_rows | secops data-table add-rows | +| dataTables.dataTableRows.bulkCreateAsync | v1alpha | | | +| dataTables.dataTableRows.bulkGet | v1alpha | | | +| dataTables.dataTableRows.bulkReplace | v1alpha | | | +| dataTables.dataTableRows.bulkReplaceAsync | v1alpha | | | +| dataTables.dataTableRows.bulkUpdate | v1alpha | | | +| dataTables.dataTableRows.bulkUpdateAsync | v1alpha | | | +| dataTables.dataTableRows.create | v1alpha | | | +| dataTables.dataTableRows.delete | v1alpha | chronicle.data_table.delete_data_table_rows | secops data-table delete-rows | +| dataTables.dataTableRows.get | v1alpha | | | +| dataTables.dataTableRows.list | v1alpha | chronicle.data_table.list_data_table_rows | secops data-table list-rows | +| dataTables.dataTableRows.patch | v1alpha | | | +| dataTables.delete | v1alpha | chronicle.data_table.delete_data_table | secops data-table delete | +| dataTables.get | v1alpha | chronicle.data_table.get_data_table | secops data-table get | +| dataTables.list | v1alpha | chronicle.data_table.list_data_tables | secops data-table list | +| dataTables.patch | v1alpha | | | +| dataTables.upload | v1alpha | | | +| dataTaps.create | v1alpha | | | +| dataTaps.delete | v1alpha | | | +| dataTaps.get | v1alpha | | | +| dataTaps.list | v1alpha | | | +| dataTaps.patch | v1alpha | | | +| delete | v1alpha | | | +| enrichmentControls.create | v1alpha | | | +| enrichmentControls.delete | v1alpha | | | +| enrichmentControls.get | v1alpha | | | +| enrichmentControls.list | v1alpha | | | +| entities.get | v1alpha | | | +| entities.import | v1alpha | | | +| entities.modifyEntityRiskScore | v1alpha | | | +| entities.queryEntityRiskScoreModifications | v1alpha | | | +| entityRiskScores.query | v1alpha | | | +| errorNotificationConfigs.create | v1alpha | | | +| errorNotificationConfigs.delete | v1alpha | | | +| errorNotificationConfigs.get | v1alpha | | | +| errorNotificationConfigs.list | v1alpha | | | +| errorNotificationConfigs.patch | v1alpha | | | +| events.batchGet | v1alpha | | | +| events.get | v1alpha | | | +| events.import | v1alpha | chronicle.log_ingest.ingest_udm | secops log ingest-udm | +| extractSyslog | v1alpha | | | +| federationGroups.create | v1alpha | | | +| federationGroups.delete | v1alpha | | | +| federationGroups.get | v1alpha | | | +| federationGroups.list | v1alpha | | | +| federationGroups.patch | v1alpha | | | +| feedPacks.get | v1alpha | | | +| feedPacks.list | v1alpha | | | +| feedServiceAccounts.fetchServiceAccountForCustomer | v1alpha | | | +| feedSourceTypeSchemas.list | v1alpha | | | +| feedSourceTypeSchemas.logTypeSchemas.list | v1alpha | | | +| feeds.create | v1alpha | chronicle.feeds.create_feed | secops feed create | +| feeds.delete | v1alpha | chronicle.feeds.delete_feed | secops feed delete | +| feeds.disable | v1alpha | chronicle.feeds.disable_feed | secops feed disable | +| feeds.enable | v1alpha | chronicle.feeds.enable_feed | secops feed enable | +| feeds.generateSecret | v1alpha | chronicle.feeds.generate_secret | secops feed secret | +| feeds.get | v1alpha | chronicle.feeds.get_feed | secops feed get | +| feeds.importPushLogs | v1alpha | | | +| feeds.list | v1alpha | chronicle.feeds.list_feeds | secops feed list | +| feeds.patch | v1alpha | chronicle.feeds.update_feed | secops feed update | +| feeds.scheduleTransfer | v1alpha | | | +| fetchFederationAccess | v1alpha | | | +| findEntity | v1alpha | | | +| findEntityAlerts | v1alpha | | | +| findRelatedEntities | v1alpha | | | +| findUdmFieldValues | v1alpha | | | +| findingsGraph.exploreNode | v1alpha | | | +| findingsGraph.initializeGraph | v1alpha | | | +| findingsRefinements.computeFindingsRefinementActivity | v1alpha | chronicle.rule_exclusion.compute_rule_exclusion_activity | secops rule-exclusion compute-activity | +| findingsRefinements.create | v1alpha | chronicle.rule_exclusion.create_rule_exclusion | secops rule-exclusion create | +| findingsRefinements.get | v1alpha | chronicle.rule_exclusion.get_rule_exclusion | secops rule-exclusion get | +| findingsRefinements.getDeployment | v1alpha | chronicle.rule_exclusion.get_rule_exclusion_deployment | secops rule-exclusion get-deployment | +| findingsRefinements.list | v1alpha | chronicle.rule_exclusion.list_rule_exclusions | secops rule-exclusion list | +| findingsRefinements.patch | v1alpha | chronicle.rule_exclusion.patch_rule_exclusion | secops rule-exclusion update | +| findingsRefinements.updateDeployment | v1alpha | chronicle.rule_exclusion.update_rule_exclusion_deployment | secops rule-exclusion update-deployment | +| forwarders.collectors.create | v1alpha | | | +| forwarders.collectors.delete | v1alpha | | | +| forwarders.collectors.get | v1alpha | | | +| forwarders.collectors.list | v1alpha | | | +| forwarders.collectors.patch | v1alpha | | | +| forwarders.create | v1alpha | chronicle.log_ingest.create_forwarder | secops forwarder create | +| forwarders.delete | v1alpha | chronicle.log_ingest.delete_forwarder | secops forwarder delete | +| forwarders.generateForwarderFiles | v1alpha | | | +| forwarders.get | v1alpha | chronicle.log_ingest.get_forwarder | secops forwarder get | +| forwarders.importStatsEvents | v1alpha | | | +| forwarders.list | v1alpha | chronicle.log_ingest.list_forwarder | secops forwarder list | +| forwarders.patch | v1alpha | chronicle.log_ingest.update_forwarder | secops forwarder update | +| generateCollectionAgentAuth | v1alpha | | | +| generateSoarAuthJwt | v1alpha | | | +| generateUdmKeyValueMappings | v1alpha | | | +| generateWorkspaceConnectionToken | v1alpha | | | +| get | v1alpha | | | +| getBigQueryExport | v1alpha | | | +| getMultitenantDirectory | v1alpha | | | +| getRiskConfig | v1alpha | | | +| ingestionLogLabels.get | v1alpha | | | +| ingestionLogLabels.list | v1alpha | | | +| ingestionLogNamespaces.get | v1alpha | | | +| ingestionLogNamespaces.list | v1alpha | | | +| iocs.batchGet | v1alpha | | | +| iocs.findFirstAndLastSeen | v1alpha | | | +| iocs.get | v1alpha | | | +| iocs.getIocState | v1alpha | | | +| iocs.searchCuratedDetectionsForIoc | v1alpha | | | +| iocs.updateIocState | v1alpha | | | +| legacy.legacyBatchGetCases | v1alpha | chronicle.case.get_cases_from_list | secops case | +| legacy.legacyBatchGetCollections | v1alpha | | | +| legacy.legacyCreateOrUpdateCase | v1alpha | | | +| legacy.legacyCreateSoarAlert | v1alpha | | | +| legacy.legacyFetchAlertsView | v1alpha | chronicle.alert.get_alerts | secops alert | +| legacy.legacyFetchUdmSearchCsv | v1alpha | chronicle.udm_search.fetch_udm_search_csv | secops search --csv | +| legacy.legacyFetchUdmSearchView | v1alpha | chronicle.udm_search.fetch_udm_search_view | secops udm-search-view | +| legacy.legacyFindAssetEvents | v1alpha | | | +| legacy.legacyFindRawLogs | v1alpha | | | +| legacy.legacyFindUdmEvents | v1alpha | | | +| legacy.legacyGetAlert | v1alpha | chronicle.rule_alert.get_alert | | +| legacy.legacyGetCuratedRulesTrends | v1alpha | | | +| legacy.legacyGetDetection | v1alpha | | | +| legacy.legacyGetEventForDetection | v1alpha | | | +| legacy.legacyGetRuleCounts | v1alpha | | | +| legacy.legacyGetRulesTrends | v1alpha | | | +| legacy.legacyListCases | v1alpha | chronicle.case.get_cases | secops case --ids | +| legacy.legacyRunTestRule | v1alpha | chronicle.rule.run_rule_test | secops rule validate | +| legacy.legacySearchArtifactEvents | v1alpha | | | +| legacy.legacySearchArtifactIoCDetails | v1alpha | | | +| legacy.legacySearchAssetEvents | v1alpha | | | +| legacy.legacySearchCuratedDetections | v1alpha | | | +| legacy.legacySearchCustomerStats | v1alpha | | | +| legacy.legacySearchDetections | v1alpha | chronicle.rule_detection.list_detections | | +| legacy.legacySearchDomainsRecentlyRegistered | v1alpha | | | +| legacy.legacySearchDomainsTimingStats | v1alpha | | | +| legacy.legacySearchEnterpriseWideAlerts | v1alpha | | | +| legacy.legacySearchEnterpriseWideIoCs | v1alpha | chronicle.ioc.list_iocs | secops iocs | +| legacy.legacySearchFindings | v1alpha | | | +| legacy.legacySearchIngestionStats | v1alpha | | | +| legacy.legacySearchIoCInsights | v1alpha | | | +| legacy.legacySearchRawLogs | v1alpha | | | +| legacy.legacySearchRuleDetectionCountBuckets | v1alpha | | | +| legacy.legacySearchRuleDetectionEvents | v1alpha | | | +| legacy.legacySearchRuleResults | v1alpha | | | +| legacy.legacySearchRulesAlerts | v1alpha | chronicle.rule_alert.search_rule_alerts | | +| legacy.legacySearchUserEvents | v1alpha | | | +| legacy.legacyStreamDetectionAlerts | v1alpha | | | +| legacy.legacyTestRuleStreaming | v1alpha | | | +| legacy.legacyUpdateAlert | v1alpha | chronicle.rule_alert.update_alert | | +| listAllFindingsRefinementDeployments | v1alpha | | | +| logTypes.create | v1alpha | | | +| logTypes.generateEventTypesSuggestions | v1alpha | | | +| logTypes.get | v1alpha | | | +| logTypes.getLogTypeSetting | v1alpha | | | +| logTypes.legacySubmitParserExtension | v1alpha | | | +| logTypes.list | v1alpha | | | +| logTypes.logs.export | v1alpha | | | +| logTypes.logs.get | v1alpha | | | +| logTypes.logs.import | v1alpha | chronicle.log_ingest.ingest_log | secops log ingest | +| logTypes.logs.list | v1alpha | | | +| logTypes.parserExtensions.activate | v1alpha | chronicle.parser_extension.activate_parser_extension | secops parser-extension activate | +| logTypes.parserExtensions.create | v1alpha | chronicle.parser_extension.create_parser_extension | secops parser-extension create | +| logTypes.parserExtensions.delete | v1alpha | chronicle.parser_extension.delete_parser_extension | secops parser-extension delete | +| logTypes.parserExtensions.extensionValidationReports.get | v1alpha | | | +| logTypes.parserExtensions.extensionValidationReports.list | v1alpha | | | +| logTypes.parserExtensions.extensionValidationReports.validationErrors.list | v1alpha | | | +| logTypes.parserExtensions.get | v1alpha | chronicle.parser_extension.get_parser_extension | secops parser-extension get | +| logTypes.parserExtensions.list | v1alpha | chronicle.parser_extension.list_parser_extensions | secops parser-extension list | +| logTypes.parserExtensions.validationReports.get | v1alpha | | | +| logTypes.parserExtensions.validationReports.parsingErrors.list | v1alpha | | | +| logTypes.parsers.activate | v1alpha | chronicle.parser.activate_parser | secops parser activate | +| logTypes.parsers.activateReleaseCandidateParser | v1alpha | chronicle.parser.activate_release_candidate | secops parser activate-rc | +| logTypes.parsers.copy | v1alpha | chronicle.parser.copy_parser | secops parser copy | +| logTypes.parsers.create | v1alpha | chronicle.parser.create_parser | secops parser create | +| logTypes.parsers.deactivate | v1alpha | chronicle.parser.deactivate_parser | secops parser deactivate | +| logTypes.parsers.delete | v1alpha | chronicle.parser.delete_parser | secops parser delete | +| logTypes.parsers.get | v1alpha | chronicle.parser.get_parser | secops parser get | +| logTypes.parsers.list | v1alpha | chronicle.parser.list_parsers | secops parser list | +| logTypes.parsers.validationReports.get | v1alpha | | | +| logTypes.parsers.validationReports.parsingErrors.list | v1alpha | | | +| logTypes.patch | v1alpha | | | +| logTypes.runParser | v1alpha | chronicle.parser.run_parser | secops parser run | +| logTypes.updateLogTypeSetting | v1alpha | | | +| logs.classify | v1alpha | | | +| nativeDashboards.addChart | v1alpha | chronicle.dashboard.add_chart | secops dashboard add-chart | +| nativeDashboards.create | v1alpha | chronicle.dashboard.create_dashboard | secops dashboard create | +| nativeDashboards.delete | v1alpha | chronicle.dashboard.delete_dashboard | secops dashboard delete | +| nativeDashboards.duplicate | v1alpha | chronicle.dashboard.duplicate_dashboard | secops dashboard duplicate | | nativeDashboards.duplicateChart | v1alpha | | | -| nativeDashboards.editChart | v1alpha | chronicle.dashboard.edit_chart |secops dashboard edit-chart | -| nativeDashboards.export | v1alpha | chronicle.dashboard.export_dashboard |secops dashboard export | -| nativeDashboards.get | v1alpha | chronicle.dashboard.get_dashboard |secops dashboard get | -| nativeDashboards.import | v1alpha | chronicle.dashboard.import_dashboard |secops dashboard import | -| nativeDashboards.list | v1alpha | chronicle.dashboard.list_dashboards |secops dashboard list | -| nativeDashboards.patch | v1alpha | chronicle.dashboard.update_dashboard |secops dashboard update | -| nativeDashboards.removeChart | v1alpha | chronicle.dashboard.remove_chart |secops dashboard remove-chart | -|operations.cancel |v1alpha| | | -|operations.delete |v1alpha| | | -|operations.get |v1alpha| | | -|operations.list |v1alpha| | | -|operations.streamSearch |v1alpha| | | -|queryProductSourceStats |v1alpha| | | -|referenceLists.create |v1alpha| | | -|referenceLists.get |v1alpha| | | -|referenceLists.list |v1alpha| | | -|referenceLists.patch |v1alpha| | | -|report |v1alpha| | | -|ruleExecutionErrors.list |v1alpha| chronicle.rule_detection.list_errors | | -|rules.create |v1alpha| | | -|rules.delete |v1alpha| | | -|rules.deployments.list |v1alpha| | | -|rules.get |v1alpha| | | -|rules.getDeployment |v1alpha| | | -|rules.list |v1alpha| | | -|rules.listRevisions |v1alpha| | | -|rules.patch |v1alpha| | | -|rules.retrohunts.create |v1alpha| | | -|rules.retrohunts.get |v1alpha| | | -|rules.retrohunts.list |v1alpha| | | -|rules.updateDeployment |v1alpha| | | -|searchEntities |v1alpha| | | -|searchRawLogs |v1alpha| | | -|summarizeEntitiesFromQuery |v1alpha| chronicle.entity.summarize_entity |secops entity | -|summarizeEntity |v1alpha| chronicle.entity.summarize_entity | | -|testFindingsRefinement |v1alpha| | | -|translateUdmQuery |v1alpha| chronicle.nl_search.translate_nl_to_udm | | -|translateYlRule |v1alpha| | | -|udmSearch |v1alpha| chronicle.search.search_udm |secops search | -|undelete |v1alpha| | | -|updateBigQueryExport |v1alpha| | | -|updateRiskConfig |v1alpha| | | -|users.clearConversationHistory |v1alpha| | | -|users.conversations.create |v1alpha| chronicle.gemini.create_conversation | | -|users.conversations.delete |v1alpha| | | -|users.conversations.get |v1alpha| | | -|users.conversations.list |v1alpha| | | -|users.conversations.messages.create |v1alpha| chronicle.gemini.query_gemini |secops gemini | -|users.conversations.messages.delete |v1alpha| | | -|users.conversations.messages.get |v1alpha| | | -|users.conversations.messages.list |v1alpha| | | -|users.conversations.messages.patch |v1alpha| | | -|users.conversations.patch |v1alpha| | | -|users.getPreferenceSet |v1alpha| chronicle.gemini.opt_in_to_gemini |secops gemini --opt-in | -|users.searchQueries.create |v1alpha| | | -|users.searchQueries.delete |v1alpha| | | -|users.searchQueries.get |v1alpha| | | -|users.searchQueries.list |v1alpha| | | -|users.searchQueries.patch |v1alpha| | | -|users.updatePreferenceSet |v1alpha| | | -|validateQuery |v1alpha| chronicle.validate.validate_query | | -|verifyReferenceList |v1alpha| | | -|verifyRuleText |v1alpha| chronicle.rule_validation.validate_rule |secops rule validate | -|watchlists.create |v1alpha| | | -|watchlists.delete |v1alpha| | | -|watchlists.entities.add |v1alpha| | | -|watchlists.entities.batchAdd |v1alpha| | | -|watchlists.entities.batchRemove |v1alpha| | | -|watchlists.entities.remove |v1alpha| | | -|watchlists.get |v1alpha| | | -|watchlists.list |v1alpha| | | -|watchlists.listEntities |v1alpha| | | -|watchlists.patch |v1alpha| | | +| nativeDashboards.editChart | v1alpha | chronicle.dashboard.edit_chart | secops dashboard edit-chart | +| nativeDashboards.export | v1alpha | chronicle.dashboard.export_dashboard | secops dashboard export | +| nativeDashboards.get | v1alpha | chronicle.dashboard.get_dashboard | secops dashboard get | +| nativeDashboards.import | v1alpha | chronicle.dashboard.import_dashboard | secops dashboard import | +| nativeDashboards.list | v1alpha | chronicle.dashboard.list_dashboards | secops dashboard list | +| nativeDashboards.patch | v1alpha | chronicle.dashboard.update_dashboard | secops dashboard update | +| nativeDashboards.removeChart | v1alpha | chronicle.dashboard.remove_chart | secops dashboard remove-chart | +| operations.cancel | v1alpha | | | +| operations.delete | v1alpha | | | +| operations.get | v1alpha | | | +| operations.list | v1alpha | | | +| operations.streamSearch | v1alpha | | | +| queryProductSourceStats | v1alpha | | | +| referenceLists.create | v1alpha | | | +| referenceLists.get | v1alpha | | | +| referenceLists.list | v1alpha | | | +| referenceLists.patch | v1alpha | | | +| report | v1alpha | | | +| ruleExecutionErrors.list | v1alpha | chronicle.rule_detection.list_errors | | +| rules.create | v1alpha | | | +| rules.delete | v1alpha | | | +| rules.deployments.list | v1alpha | | | +| rules.get | v1alpha | | | +| rules.getDeployment | v1alpha | | | +| rules.list | v1alpha | | | +| rules.listRevisions | v1alpha | | | +| rules.patch | v1alpha | | | +| rules.retrohunts.create | v1alpha | | | +| rules.retrohunts.get | v1alpha | | | +| rules.retrohunts.list | v1alpha | | | +| rules.updateDeployment | v1alpha | | | +| searchEntities | v1alpha | | | +| searchRawLogs | v1alpha | | | +| summarizeEntitiesFromQuery | v1alpha | chronicle.entity.summarize_entity | secops entity | +| summarizeEntity | v1alpha | chronicle.entity.summarize_entity | | +| testFindingsRefinement | v1alpha | | | +| translateUdmQuery | v1alpha | chronicle.nl_search.translate_nl_to_udm | | +| translateYlRule | v1alpha | | | +| udmSearch | v1alpha | chronicle.search.search_udm | secops search | +| undelete | v1alpha | | | +| updateBigQueryExport | v1alpha | | | +| updateRiskConfig | v1alpha | | | +| users.clearConversationHistory | v1alpha | | | +| users.conversations.create | v1alpha | chronicle.gemini.create_conversation | | +| users.conversations.delete | v1alpha | | | +| users.conversations.get | v1alpha | | | +| users.conversations.list | v1alpha | | | +| users.conversations.messages.create | v1alpha | chronicle.gemini.query_gemini | secops gemini | +| users.conversations.messages.delete | v1alpha | | | +| users.conversations.messages.get | v1alpha | | | +| users.conversations.messages.list | v1alpha | | | +| users.conversations.messages.patch | v1alpha | | | +| users.conversations.patch | v1alpha | | | +| users.getPreferenceSet | v1alpha | chronicle.gemini.opt_in_to_gemini | secops gemini --opt-in | +| users.searchQueries.create | v1alpha | | | +| users.searchQueries.delete | v1alpha | | | +| users.searchQueries.get | v1alpha | | | +| users.searchQueries.list | v1alpha | | | +| users.searchQueries.patch | v1alpha | | | +| users.updatePreferenceSet | v1alpha | | | +| validateQuery | v1alpha | chronicle.validate.validate_query | | +| verifyReferenceList | v1alpha | | | +| verifyRuleText | v1alpha | chronicle.rule_validation.validate_rule | secops rule validate | +| watchlists.create | v1alpha | | | +| watchlists.delete | v1alpha | | | +| watchlists.entities.add | v1alpha | | | +| watchlists.entities.batchAdd | v1alpha | | | +| watchlists.entities.batchRemove | v1alpha | | | +| watchlists.entities.remove | v1alpha | | | +| watchlists.get | v1alpha | | | +| watchlists.list | v1alpha | | | +| watchlists.listEntities | v1alpha | | | +| watchlists.patch | v1alpha | | | diff --git a/src/secops/chronicle/__init__.py b/src/secops/chronicle/__init__.py index bfe38c07..5a404f2f 100644 --- a/src/secops/chronicle/__init__.py +++ b/src/secops/chronicle/__init__.py @@ -138,6 +138,7 @@ list_curated_rule_set_categories, list_curated_rules, get_curated_rule, + get_curated_rule_set_category, ) from secops.chronicle.rule_validation import ValidationResult from secops.chronicle.search import search_udm @@ -238,6 +239,7 @@ "list_curated_rule_set_categories", "list_curated_rules", "get_curated_rule", + "get_curated_rule_set_category", # Native Dashboard "add_chart", "create_dashboard", diff --git a/src/secops/chronicle/client.py b/src/secops/chronicle/client.py index 7b18bd06..b1acd27b 100644 --- a/src/secops/chronicle/client.py +++ b/src/secops/chronicle/client.py @@ -226,6 +226,7 @@ list_curated_rule_set_categories as _list_curated_rule_set_categories, list_curated_rules as _list_curated_rules, get_curated_rule as _get_curated_rule, + get_curated_rule_set_category as _get_curated_rule_set_category, ) from secops.chronicle.rule_validation import validate_rule as _validate_rule from secops.chronicle.search import search_udm as _search_udm @@ -1806,6 +1807,20 @@ def get_curated_rule(self, rule_id: str) -> Dict[str, Any]: """ return _get_curated_rule(self, rule_id) + def get_curated_rule_set_category(self, category_id: str) -> Dict[str, Any]: + """Get a curated rule set category by ID. + + Args: + category_id: ID of the curated rule set category + + Returns: + Dictionary containing the curated rule set category + + Raises: + APIError: If the API request fails + """ + return _get_curated_rule_set_category(self, category_id) + def validate_rule(self, rule_text: str): """Validates a YARA-L2 rule against the Chronicle API. diff --git a/src/secops/chronicle/rule_set.py b/src/secops/chronicle/rule_set.py index 9d54cf68..e042995b 100644 --- a/src/secops/chronicle/rule_set.py +++ b/src/secops/chronicle/rule_set.py @@ -117,6 +117,33 @@ def list_curated_rule_set_categories( return rule_set_categories +def get_curated_rule_set_category(client, category_id: str) -> Dict[str, Any]: + """Get a curated rule set category by ID + + Args: + client: ChronicleClient instance + category_id: Unique ID of the curated rule set category + + Returns: + Dictionary containing the curated rule set category + + Raises: + APIError: If the API request fails + """ + base_url = ( + f"{client.base_url}/{client.instance_id}/" + f"curatedRuleSetCategories/{category_id}" + ) + + response = client.session.get(base_url) + if response.status_code != 200: + raise APIError( + f"Failed to get curated rule set category: {response.text}" + ) + + return response.json() + + def list_curated_rules( client, page_size: Optional[str] = None, From b5fcf3511cce78899f85529fb064f17e15ff8217 Mon Sep 17 00:00:00 2001 From: PaperMtn Date: Fri, 24 Oct 2025 14:15:47 +0100 Subject: [PATCH 07/30] feat: added getting a curated rule set by ID --- api_module_mapping.md | 2 +- src/secops/chronicle/__init__.py | 2 ++ src/secops/chronicle/client.py | 15 +++++++++++++++ src/secops/chronicle/rule_set.py | 25 +++++++++++++++++++++++++ 4 files changed, 43 insertions(+), 1 deletion(-) diff --git a/api_module_mapping.md b/api_module_mapping.md index 9a95c914..9679968b 100644 --- a/api_module_mapping.md +++ b/api_module_mapping.md @@ -87,7 +87,7 @@ wrapper module and its respective CLI command (if available). | cases.countPriorities | v1alpha | | | | curatedRuleSetCategories.curatedRuleSets.curatedRuleSetDeployments.batchUpdate | v1alpha | chronicle.rule_set.batch_update_curated_rule_set_deployments | | | curatedRuleSetCategories.curatedRuleSets.curatedRuleSetDeployments.patch | v1alpha | | | -| curatedRuleSetCategories.curatedRuleSets.get | v1alpha | | | +| curatedRuleSetCategories.curatedRuleSets.get | v1alpha | chronicle.rule_set.get_curated_rule_set | | | curatedRuleSetCategories.curatedRuleSets.list | v1alpha | chronicle.rule_set.list_curated_rule_sets | | | curatedRuleSetCategories.get | v1alpha | chronicle.rule_set.get_curated_rule_set_category | | | curatedRuleSetCategories.list | v1alpha | chronicle.rule_set.list_curated_rule_set_categories | | diff --git a/src/secops/chronicle/__init__.py b/src/secops/chronicle/__init__.py index 5a404f2f..088ac1c3 100644 --- a/src/secops/chronicle/__init__.py +++ b/src/secops/chronicle/__init__.py @@ -139,6 +139,7 @@ list_curated_rules, get_curated_rule, get_curated_rule_set_category, + get_curated_rule_set, ) from secops.chronicle.rule_validation import ValidationResult from secops.chronicle.search import search_udm @@ -240,6 +241,7 @@ "list_curated_rules", "get_curated_rule", "get_curated_rule_set_category", + "get_curated_rule_set", # Native Dashboard "add_chart", "create_dashboard", diff --git a/src/secops/chronicle/client.py b/src/secops/chronicle/client.py index b1acd27b..ff7454c7 100644 --- a/src/secops/chronicle/client.py +++ b/src/secops/chronicle/client.py @@ -227,6 +227,7 @@ list_curated_rules as _list_curated_rules, get_curated_rule as _get_curated_rule, get_curated_rule_set_category as _get_curated_rule_set_category, + get_curated_rule_set as _get_curated_rule_set, ) from secops.chronicle.rule_validation import validate_rule as _validate_rule from secops.chronicle.search import search_udm as _search_udm @@ -1821,6 +1822,20 @@ def get_curated_rule_set_category(self, category_id: str) -> Dict[str, Any]: """ return _get_curated_rule_set_category(self, category_id) + def get_curated_rule_set(self, rule_set_id: str) -> Dict[str, Any]: + """Get a curated rule set by ID. + + Args: + rule_set_id: ID of the curated rule set + + Returns: + Dictionary containing the curated rule set + + Raises: + APIError: If the API request fails + """ + return _get_curated_rule_set(self, rule_set_id) + def validate_rule(self, rule_text: str): """Validates a YARA-L2 rule against the Chronicle API. diff --git a/src/secops/chronicle/rule_set.py b/src/secops/chronicle/rule_set.py index e042995b..7d21c960 100644 --- a/src/secops/chronicle/rule_set.py +++ b/src/secops/chronicle/rule_set.py @@ -67,6 +67,31 @@ def list_curated_rule_sets( return rule_sets +def get_curated_rule_set(client, rule_set_id: str) -> Dict[str, Any]: + """Get a curated rule set by ID + + Args: + client: ChronicleClient instance + rule_set_id: Unique ID of the curated rule set + + Returns: + Dictionary containing the curated rule set + + Raises: + APIError: If the API request fails + """ + base_url = ( + f"{client.base_url}/{client.instance_id}/" + f"curatedRuleSetCategories/-/curatedRuleSets/{rule_set_id}" + ) + + response = client.session.get(base_url) + if response.status_code != 200: + raise APIError(f"Failed to get rule set: {response.text}") + + return response.json() + + def list_curated_rule_set_categories( client, page_size: Optional[str] = None, From b53a41d195463f6d93db53d0a93c701642d22724 Mon Sep 17 00:00:00 2001 From: PaperMtn Date: Fri, 24 Oct 2025 15:01:35 +0100 Subject: [PATCH 08/30] refactor: implement helper function for paginated requests --- src/secops/chronicle/rule_set.py | 148 +++++++++++++++---------------- 1 file changed, 72 insertions(+), 76 deletions(-) diff --git a/src/secops/chronicle/rule_set.py b/src/secops/chronicle/rule_set.py index 7d21c960..0fffc633 100644 --- a/src/secops/chronicle/rule_set.py +++ b/src/secops/chronicle/rule_set.py @@ -18,53 +18,87 @@ from secops.exceptions import APIError -def list_curated_rule_sets( +def _paginated_request( client, - page_size: Optional[str] = None, - page_token: Optional[str] = None, + path: str, + items_key: str, + *, + page_size: Optional[int] = None, + start_page_token: Optional[str] = None, + extra_params: Optional[Dict[str, Any]] = None, ) -> List[Dict[str, Any]]: - """Get a list of all curated rule sets + """ + Helper to get items from endpoints that use pagination. Args: client: ChronicleClient instance - page_size: Number of results to return per page - page_token: Token for the page to retrieve + path: URL path after {base_url}/{instance_id}/ + items_key: JSON key holding the array of items (e.g., 'curatedRules') + page_size: page size (defaults to API max) + start_page_token: if provided, start from this token + extra_params: extra query params to include on every request Returns: - Dictionary containing the list of curated rule sets + List of items from the paginated collection. Raises: - APIError: If the API request fails + APIError: If the HTTP request fails. """ + url = f"{client.base_url}/{client.instance_id}/{path}" + page_token = start_page_token - base_url = ( - f"{client.base_url}/{client.instance_id}/" - f"curatedRuleSetCategories/-/curatedRuleSets" - ) - - rule_sets = [] + results = [] while True: params = {"pageSize": 1000 if not page_size else page_size} if page_token: params["pageToken"] = page_token + if extra_params: + params.update(extra_params) - response = client.session.get(base_url, params=params) + response = client.session.get(url, params=params) if response.status_code != 200: - raise APIError(f"Failed to list rule sets: {response.text}") + raise APIError(f"Failed to list {items_key}: {response.text}") data = response.json() if not data: - return rule_sets + return results - curated_sets = data.get("curatedRuleSets", []) - rule_sets.extend(curated_sets) + curated_sets = data.get(items_key, []) + results.extend(curated_sets) page_token = data.get("nextPageToken") if not page_token: break - return rule_sets + return results + + +def list_curated_rule_sets( + client, + page_size: Optional[str] = None, + page_token: Optional[str] = None, +) -> List[Dict[str, Any]]: + """Get a list of all curated rule sets + + Args: + client: ChronicleClient instance + page_size: Number of results to return per page + page_token: Token for the page to retrieve + + Returns: + List of curated rule sets + + Raises: + APIError: If the API request fails + """ + return _paginated_request( + client, + path="curatedRuleSetCategories/-/curatedRuleSets", + items_key="curatedRuleSets", + page_size=page_size, + start_page_token=page_token, + ) def get_curated_rule_set(client, rule_set_id: str) -> Dict[str, Any]: @@ -105,42 +139,19 @@ def list_curated_rule_set_categories( page_token: Token for the page to retrieve Returns: - Dictionary containing the list of curated rule set categories + List of curated rule set categories Raises: APIError: If the API request fails """ - - base_url = ( - f"{client.base_url}/{client.instance_id}/" f"curatedRuleSetCategories" + return _paginated_request( + client, + path="curatedRuleSetCategories", + items_key="curatedRuleSetCategories", + page_size=page_size, + start_page_token=page_token, ) - rule_set_categories = [] - - while True: - params = {"pageSize": 1000 if not page_size else page_size} - if page_token: - params["pageToken"] = page_token - - response = client.session.get(base_url, params=params) - if response.status_code != 200: - raise APIError( - f"Failed to list rule set " f"categories: {response.text}" - ) - - data = response.json() - if not data: - return rule_set_categories - - curated_sets = data.get("curatedRuleSetCategories", []) - rule_set_categories.extend(curated_sets) - - page_token = data.get("nextPageToken") - if not page_token: - break - - return rule_set_categories - def get_curated_rule_set_category(client, category_id: str) -> Dict[str, Any]: """Get a curated rule set category by ID @@ -182,35 +193,18 @@ def list_curated_rules( page_token: Token for the page to retrieve Returns: - Dictionary containing the list of curated rules + List of curated rules Raises: APIError: If the API request fails """ - base_url = f"{client.base_url}/{client.instance_id}/" f"curatedRules" - - curated_rules = [] - - while True: - params = {"pageSize": 1000 if not page_size else page_size} - if page_token: - params["pageToken"] = page_token - - response = client.session.get(base_url, params=params) - if response.status_code != 200: - raise APIError(f"Failed to list curated rules: {response.text}") - - data = response.json() - if not data: - return curated_rules - - curated_rules.extend(data.get("curatedRules", [])) - - page_token = data.get("nextPageToken") - if not page_token: - break - - return curated_rules + return _paginated_request( + client, + path="curatedRules", + items_key="curatedRules", + page_size=page_size, + start_page_token=page_token, + ) def get_curated_rule(client, rule_id: str) -> Dict[str, Any]: @@ -230,7 +224,9 @@ def get_curated_rule(client, rule_id: str) -> Dict[str, Any]: Raises: APIError: If the API request fails """ - base_url = f"{client.base_url}/{client.instance_id}/" f"curatedRules/{rule_id}" + base_url = ( + f"{client.base_url}/{client.instance_id}/" f"curatedRules/{rule_id}" + ) response = client.session.get(base_url) if response.status_code != 200: From aa122e6900e56f0f0d5e9f7302993c5061bf1248 Mon Sep 17 00:00:00 2001 From: PaperMtn Date: Fri, 24 Oct 2025 15:39:31 +0100 Subject: [PATCH 09/30] feat: added listing all rule set deployments --- api_module_mapping.md | 1 + src/secops/chronicle/__init__.py | 2 ++ src/secops/chronicle/client.py | 24 ++++++++++++++++ src/secops/chronicle/rule_set.py | 49 ++++++++++++++++++++++++++++++++ 4 files changed, 76 insertions(+) diff --git a/api_module_mapping.md b/api_module_mapping.md index 9679968b..5efa608c 100644 --- a/api_module_mapping.md +++ b/api_module_mapping.md @@ -87,6 +87,7 @@ wrapper module and its respective CLI command (if available). | cases.countPriorities | v1alpha | | | | curatedRuleSetCategories.curatedRuleSets.curatedRuleSetDeployments.batchUpdate | v1alpha | chronicle.rule_set.batch_update_curated_rule_set_deployments | | | curatedRuleSetCategories.curatedRuleSets.curatedRuleSetDeployments.patch | v1alpha | | | +| curatedRuleSetCategories.curatedRuleSets.curatedRuleSetDeployments.list | v1alpha | chronicle.rule_set.list_curated_rule_set_deployments | | | curatedRuleSetCategories.curatedRuleSets.get | v1alpha | chronicle.rule_set.get_curated_rule_set | | | curatedRuleSetCategories.curatedRuleSets.list | v1alpha | chronicle.rule_set.list_curated_rule_sets | | | curatedRuleSetCategories.get | v1alpha | chronicle.rule_set.get_curated_rule_set_category | | diff --git a/src/secops/chronicle/__init__.py b/src/secops/chronicle/__init__.py index 088ac1c3..77968fa6 100644 --- a/src/secops/chronicle/__init__.py +++ b/src/secops/chronicle/__init__.py @@ -140,6 +140,7 @@ get_curated_rule, get_curated_rule_set_category, get_curated_rule_set, + list_curated_rule_set_deployments, ) from secops.chronicle.rule_validation import ValidationResult from secops.chronicle.search import search_udm @@ -242,6 +243,7 @@ "get_curated_rule", "get_curated_rule_set_category", "get_curated_rule_set", + "list_curated_rule_set_deployments", # Native Dashboard "add_chart", "create_dashboard", diff --git a/src/secops/chronicle/client.py b/src/secops/chronicle/client.py index ff7454c7..1a206846 100644 --- a/src/secops/chronicle/client.py +++ b/src/secops/chronicle/client.py @@ -228,6 +228,7 @@ get_curated_rule as _get_curated_rule, get_curated_rule_set_category as _get_curated_rule_set_category, get_curated_rule_set as _get_curated_rule_set, + list_curated_rule_set_deployments as _list_curated_rule_set_deployments, ) from secops.chronicle.rule_validation import validate_rule as _validate_rule from secops.chronicle.search import search_udm as _search_udm @@ -1775,6 +1776,29 @@ def list_rule_set_categories( """ return _list_curated_rule_set_categories(self, page_size, page_token) + def list_curated_rule_set_deployments( + self, + page_size: Optional[str] = None, + page_token: Optional[str] = None, + only_enabled: Optional[bool] = False, + only_alerting: Optional[bool] = False, + ) -> List[Dict[str, Any]]: + """Get a list of all curated rule set deployments. + + Args: + page_size: Number of results to return per page + page_token: Token for the page to retrieve + only_enabled: Only return enabled rule set deployments + only_alerting: Only return alerting rule set deployments + + Returns: + Dictionary containing the list of curated rule set deployments + + Raises: + APIError: If the API request fails + """ + return _list_curated_rule_set_deployments(self, page_size, page_token, only_enabled, only_alerting) + def list_curated_rules( self, page_size: Optional[str] = None, diff --git a/src/secops/chronicle/rule_set.py b/src/secops/chronicle/rule_set.py index 0fffc633..a4d681fe 100644 --- a/src/secops/chronicle/rule_set.py +++ b/src/secops/chronicle/rule_set.py @@ -235,6 +235,55 @@ def get_curated_rule(client, rule_id: str) -> Dict[str, Any]: return response.json() +def list_curated_rule_set_deployments( + client, + page_size: Optional[str] = None, + page_token: Optional[str] = None, + only_enabled: Optional[bool] = False, + only_alerting: Optional[bool] = False, +) -> List[Dict[str, Any]]: + """Get a list of all curated rule set deployments + + Args: + client: ChronicleClient instance + page_size: Number of results to return per page + page_token: Token for the page to retrieve + only_enabled: Only return enabled rule set deployments + only_alerting: Only return alerting rule set deployments + + Returns: + List of curated rule set deployments + + Raises: + APIError: If the API request fails + """ + rule_set_deployments = _paginated_request( + client, + path="curatedRuleSetCategories/-/curatedRuleSets/-/curatedRuleSetDeployments", + items_key="curatedRuleSetDeployments", + page_size=page_size, + start_page_token=page_token, + ) + + all_rule_sets = list_curated_rule_sets(client) + for deployment in rule_set_deployments: + rule_set_id = deployment.get("name", "").split("curatedRuleSetDeployment")[0].rstrip("/") + for rule_set in all_rule_sets: + if rule_set.get("name", "") == rule_set_id: + deployment["displayName"] = rule_set.get("displayName", "") + + if only_enabled: + rule_set_deployments = [ + deployment for deployment in rule_set_deployments if deployment.get("enabled", False) + ] + if only_alerting: + rule_set_deployments = [ + deployment for deployment in rule_set_deployments if deployment.get("alerting", False) + ] + + return rule_set_deployments + + def batch_update_curated_rule_set_deployments( client, deployments: List[Dict[str, Any]] ) -> Dict[str, Any]: From 3fd0d58b74ab7814c8465f2f1537fd33fa733e1b Mon Sep 17 00:00:00 2001 From: PaperMtn Date: Fri, 24 Oct 2025 17:11:18 +0100 Subject: [PATCH 10/30] feat: added getting rule set deployment by ID --- api_module_mapping.md | 1 + src/secops/chronicle/__init__.py | 2 + src/secops/chronicle/client.py | 24 +++++++++- src/secops/chronicle/rule_set.py | 75 +++++++++++++++++++++++++++++--- 4 files changed, 95 insertions(+), 7 deletions(-) diff --git a/api_module_mapping.md b/api_module_mapping.md index 5efa608c..4a5ca432 100644 --- a/api_module_mapping.md +++ b/api_module_mapping.md @@ -88,6 +88,7 @@ wrapper module and its respective CLI command (if available). | curatedRuleSetCategories.curatedRuleSets.curatedRuleSetDeployments.batchUpdate | v1alpha | chronicle.rule_set.batch_update_curated_rule_set_deployments | | | curatedRuleSetCategories.curatedRuleSets.curatedRuleSetDeployments.patch | v1alpha | | | | curatedRuleSetCategories.curatedRuleSets.curatedRuleSetDeployments.list | v1alpha | chronicle.rule_set.list_curated_rule_set_deployments | | +| curatedRuleSetCategories.curatedRuleSets.curatedRuleSetDeployments.get | v1alpha | chronicle.rule_set.get_curated_rule_set_deployment | | | curatedRuleSetCategories.curatedRuleSets.get | v1alpha | chronicle.rule_set.get_curated_rule_set | | | curatedRuleSetCategories.curatedRuleSets.list | v1alpha | chronicle.rule_set.list_curated_rule_sets | | | curatedRuleSetCategories.get | v1alpha | chronicle.rule_set.get_curated_rule_set_category | | diff --git a/src/secops/chronicle/__init__.py b/src/secops/chronicle/__init__.py index 77968fa6..5ae38fa9 100644 --- a/src/secops/chronicle/__init__.py +++ b/src/secops/chronicle/__init__.py @@ -141,6 +141,7 @@ get_curated_rule_set_category, get_curated_rule_set, list_curated_rule_set_deployments, + get_curated_rule_set_deployment, ) from secops.chronicle.rule_validation import ValidationResult from secops.chronicle.search import search_udm @@ -244,6 +245,7 @@ "get_curated_rule_set_category", "get_curated_rule_set", "list_curated_rule_set_deployments", + "get_curated_rule_set_deployment", # Native Dashboard "add_chart", "create_dashboard", diff --git a/src/secops/chronicle/client.py b/src/secops/chronicle/client.py index 1a206846..1bf30113 100644 --- a/src/secops/chronicle/client.py +++ b/src/secops/chronicle/client.py @@ -229,6 +229,7 @@ get_curated_rule_set_category as _get_curated_rule_set_category, get_curated_rule_set as _get_curated_rule_set, list_curated_rule_set_deployments as _list_curated_rule_set_deployments, + get_curated_rule_set_deployment as _get_curated_rule_set_deployment, ) from secops.chronicle.rule_validation import validate_rule as _validate_rule from secops.chronicle.search import search_udm as _search_udm @@ -1797,7 +1798,28 @@ def list_curated_rule_set_deployments( Raises: APIError: If the API request fails """ - return _list_curated_rule_set_deployments(self, page_size, page_token, only_enabled, only_alerting) + return _list_curated_rule_set_deployments( + self, page_size, page_token, only_enabled, only_alerting + ) + + def get_curated_rule_set_deployment( + self, + rule_set_id: str, + precision: str = "precise", + ) -> Dict[str, Any]: + """Get a curated rule set deployment by ID + + Args: + rule_set_id: Unique ID of the curated rule set + precision: Precision level ("precise" or "broad") + + Returns: + Dictionary containing the curated rule set deployment + + Raises: + APIError: If the API request fails + """ + return _get_curated_rule_set_deployment(self, rule_set_id, precision) def list_curated_rules( self, diff --git a/src/secops/chronicle/rule_set.py b/src/secops/chronicle/rule_set.py index a4d681fe..6c611382 100644 --- a/src/secops/chronicle/rule_set.py +++ b/src/secops/chronicle/rule_set.py @@ -15,7 +15,7 @@ """Curated rule set functionality for Chronicle.""" from typing import Dict, Any, List, Optional -from secops.exceptions import APIError +from secops.exceptions import APIError, SecOpsError def _paginated_request( @@ -242,7 +242,7 @@ def list_curated_rule_set_deployments( only_enabled: Optional[bool] = False, only_alerting: Optional[bool] = False, ) -> List[Dict[str, Any]]: - """Get a list of all curated rule set deployments + """Get a list of all curated rule set deployment statuses Args: client: ChronicleClient instance @@ -259,31 +259,94 @@ def list_curated_rule_set_deployments( """ rule_set_deployments = _paginated_request( client, - path="curatedRuleSetCategories/-/curatedRuleSets/-/curatedRuleSetDeployments", + path="curatedRuleSetCategories/-/curatedRuleSets/" + "-/curatedRuleSetDeployments", items_key="curatedRuleSetDeployments", page_size=page_size, start_page_token=page_token, ) + # Enrich the deployment data with the rule set displayName all_rule_sets = list_curated_rule_sets(client) for deployment in rule_set_deployments: - rule_set_id = deployment.get("name", "").split("curatedRuleSetDeployment")[0].rstrip("/") + rule_set_id = ( + deployment.get("name", "") + .split("curatedRuleSetDeployment")[0] + .rstrip("/") + ) for rule_set in all_rule_sets: if rule_set.get("name", "") == rule_set_id: deployment["displayName"] = rule_set.get("displayName", "") + # Apply filters for only enabled and/or alerting rule sets if only_enabled: rule_set_deployments = [ - deployment for deployment in rule_set_deployments if deployment.get("enabled", False) + deployment + for deployment in rule_set_deployments + if deployment.get("enabled", False) ] if only_alerting: rule_set_deployments = [ - deployment for deployment in rule_set_deployments if deployment.get("alerting", False) + deployment + for deployment in rule_set_deployments + if deployment.get("alerting", False) ] return rule_set_deployments +def get_curated_rule_set_deployment( + client, + rule_set_id: str, + precision: str = "precise", +) -> Dict[str, Any]: + """Get the deployment status of a curated rule set by ID + + Args: + client: ChronicleClient instance + rule_set_id: Unique ID of the curated rule set + precision: Precision level ("precise" or "broad") + + Returns: + Dictionary containing the curated rule set deployment + + Raises: + APIError: If the API request fails + SecOpsError: If the rule set is not found or precision is invalid + """ + if precision not in ["precise", "broad"]: + raise SecOpsError("Precision must be 'precise' or 'broad'") + + # Get the rule set by ID + rule_set = next( + ( + rs + for rs in list_curated_rule_sets(client) + if rule_set_id in rs.get("name", "") + ), + None, + ) + if rule_set is None: + raise SecOpsError(f"Rule set {rule_set_id} not found") + + url = ( + f"{client.base_url}/{rule_set.get("name", "")}/" + f"curatedRuleSetDeployments/{precision}" + ) + + response = client.session.get(url) + if response.status_code != 200: + raise APIError( + f"Failed to get curated rule set deployment: {response.text}" + ) + + # Enrich the deployment data with the rule set displayName + deployment = response.json() + deployment["displayName"] = rule_set.get("displayName", "") + + return deployment + + def batch_update_curated_rule_set_deployments( client, deployments: List[Dict[str, Any]] ) -> Dict[str, Any]: From 032173b02b17a968eee007f1cb306117c216798f Mon Sep 17 00:00:00 2001 From: PaperMtn Date: Fri, 24 Oct 2025 19:17:11 +0100 Subject: [PATCH 11/30] feat: added getting rule set deployment by display name --- api_module_mapping.md | 750 +++++++++++++++---------------- src/secops/chronicle/__init__.py | 2 + src/secops/chronicle/client.py | 21 + src/secops/chronicle/rule_set.py | 41 ++ 4 files changed, 439 insertions(+), 375 deletions(-) diff --git a/api_module_mapping.md b/api_module_mapping.md index 4a5ca432..b82d9c54 100644 --- a/api_module_mapping.md +++ b/api_module_mapping.md @@ -5,378 +5,378 @@ wrapper module and its respective CLI command (if available). **Note:** All the REST resources mentioned have suffix `projects.locations.instances`. -| REST Resource | Version | secops-wrapper module | CLI Command | -|--------------------------------------------------------------------------------|---------|--------------------------------------------------------------|-----------------------------------------| -| dataAccessLabels.create | v1 | | | -| dataAccessLabels.delete | v1 | | | -| dataAccessLabels.get | v1 | | | -| dataAccessLabels.list | v1 | | | -| dataAccessLabels.patch | v1 | | | -| dataAccessScopes.create | v1 | | | -| dataAccessScopes.delete | v1 | | | -| dataAccessScopes.get | v1 | | | -| dataAccessScopes.list | v1 | | | -| dataAccessScopes.patch | v1 | | | -| get | v1 | | | -| operations.cancel | v1 | | | -| operations.delete | v1 | | | -| operations.get | v1 | | | -| operations.list | v1 | | | -| referenceLists.create | v1 | chronicle.reference_list.create_reference_list | secops reference-list create | -| referenceLists.get | v1 | chronicle.reference_list.get_reference_list | secops reference-list get | -| referenceLists.list | v1 | chronicle.reference_list.list_reference_lists | secops reference-list list | -| referenceLists.patch | v1 | chronicle.reference_list.update_reference_list | secops reference-list update | -| rules.create | v1 | chronicle.rule.create_rule | secops rule create | -| rules.delete | v1 | chronicle.rule.delete_rule | secops rule delete | -| rules.deployments.list | v1 | | | -| rules.get | v1 | chronicle.rule.get_rule | secops rule get | -| rules.getDeployment | v1 | | | -| rules.list | v1 | chronicle.rule.list_rules | secops rule list | -| rules.listRevisions | v1 | | | -| rules.patch | v1 | chronicle.rule.update_rule | secops rule update | -| rules.retrohunts.create | v1 | chronicle.rule_retrohunt.create_retrohunt | | -| rules.retrohunts.get | v1 | chronicle.rule_retrohunt.get_retrohunt | | -| rules.retrohunts.list | v1 | | | -| rules.updateDeployment | v1 | chronicle.rule.enable_rule | secops rule enable | -| watchlists.create | v1 | | | -| watchlists.delete | v1 | | | -| watchlists.get | v1 | | | -| watchlists.list | v1 | | | -| watchlists.patch | v1 | | | -| dataAccessLabels.create | v1beta | | | -| dataAccessLabels.delete | v1beta | | | -| dataAccessLabels.get | v1beta | | | -| dataAccessLabels.list | v1beta | | | -| dataAccessLabels.patch | v1beta | | | -| dataAccessScopes.create | v1beta | | | -| dataAccessScopes.delete | v1beta | | | -| dataAccessScopes.get | v1beta | | | -| dataAccessScopes.list | v1beta | | | -| dataAccessScopes.patch | v1beta | | | -| get | v1beta | | | -| operations.cancel | v1beta | | | -| operations.delete | v1beta | | | -| operations.get | v1beta | | | -| operations.list | v1beta | | | -| referenceLists.create | v1beta | | | -| referenceLists.get | v1beta | | | -| referenceLists.list | v1beta | | | -| referenceLists.patch | v1beta | | | -| rules.create | v1beta | | | -| rules.delete | v1beta | | | -| rules.deployments.list | v1beta | | | -| rules.get | v1beta | | | -| rules.getDeployment | v1beta | | | -| rules.list | v1beta | | | -| rules.listRevisions | v1beta | | | -| rules.patch | v1beta | | | -| rules.retrohunts.create | v1beta | | | -| rules.retrohunts.get | v1beta | | | -| rules.retrohunts.list | v1beta | | | -| rules.updateDeployment | v1beta | | | -| watchlists.create | v1beta | | | -| watchlists.delete | v1beta | | | -| watchlists.get | v1beta | | | -| watchlists.list | v1beta | | | -| watchlists.patch | v1beta | | | -| analytics.entities.analyticValues.list | v1alpha | | | -| analytics.list | v1alpha | | | -| batchValidateWatchlistEntities | v1alpha | | | -| bigQueryAccess.provide | v1alpha | | | -| bigQueryExport.provision | v1alpha | | | -| cases.countPriorities | v1alpha | | | -| curatedRuleSetCategories.curatedRuleSets.curatedRuleSetDeployments.batchUpdate | v1alpha | chronicle.rule_set.batch_update_curated_rule_set_deployments | | -| curatedRuleSetCategories.curatedRuleSets.curatedRuleSetDeployments.patch | v1alpha | | | -| curatedRuleSetCategories.curatedRuleSets.curatedRuleSetDeployments.list | v1alpha | chronicle.rule_set.list_curated_rule_set_deployments | | -| curatedRuleSetCategories.curatedRuleSets.curatedRuleSetDeployments.get | v1alpha | chronicle.rule_set.get_curated_rule_set_deployment | | -| curatedRuleSetCategories.curatedRuleSets.get | v1alpha | chronicle.rule_set.get_curated_rule_set | | -| curatedRuleSetCategories.curatedRuleSets.list | v1alpha | chronicle.rule_set.list_curated_rule_sets | | -| curatedRuleSetCategories.get | v1alpha | chronicle.rule_set.get_curated_rule_set_category | | -| curatedRuleSetCategories.list | v1alpha | chronicle.rule_set.list_curated_rule_set_categories | | -| curatedRules.get | v1alpha | chronicle.rule_set.get_curated_rule | | -| curatedRules.list | v1alpha | chronicle.rule_set.list_curated_rules | | -| dashboardCharts.batchGet | v1alpha | | | -| dashboardCharts.get | v1alpha | chronicle.dashboard.get_chart | secops dashboard get-chart | -| dashboardQueries.execute | v1alpha | chronicle.dashboard_query.execute_query | secops dashboard-query execute | -| dashboardQueries.get | v1alpha | chronicle.dashboard_query.get_execute_query | secops dashboard-query get | -| dashboards.copy | v1alpha | | | -| dashboards.create | v1alpha | | | -| dashboards.delete | v1alpha | | | -| dashboards.get | v1alpha | | | -| dashboards.list | v1alpha | | | -| dataAccessLabels.create | v1alpha | | | -| dataAccessLabels.delete | v1alpha | | | -| dataAccessLabels.get | v1alpha | | | -| dataAccessLabels.list | v1alpha | | | -| dataAccessLabels.patch | v1alpha | | | -| dataAccessScopes.create | v1alpha | | | -| dataAccessScopes.delete | v1alpha | | | -| dataAccessScopes.get | v1alpha | | | -| dataAccessScopes.list | v1alpha | | | -| dataAccessScopes.patch | v1alpha | | | -| dataExports.cancel | v1alpha | chronicle.data_export.cancel_data_export | secops export cancel | -| dataExports.create | v1alpha | chronicle.data_export.create_data_export | secops export create | -| dataExports.fetchavailablelogtypes | v1alpha | chronicle.data_export.fetch_available_log_types | secops export log-types | -| dataExports.get | v1alpha | chronicle.data_export.get_data_export | secops export status | -| dataExports.list | v1alpha | chronicle.data_export.list_data_export | secops export list | -| dataExports.patch | v1alpha | chronicle.data_export.update_data_export | secops export update | -| dataTableOperationErrors.get | v1alpha | | | -| dataTables.create | v1alpha | chronicle.data_table.create_data_table | secops data-table create | -| dataTables.dataTableRows.bulkCreate | v1alpha | chronicle.data_table.create_data_table_rows | secops data-table add-rows | -| dataTables.dataTableRows.bulkCreateAsync | v1alpha | | | -| dataTables.dataTableRows.bulkGet | v1alpha | | | -| dataTables.dataTableRows.bulkReplace | v1alpha | | | -| dataTables.dataTableRows.bulkReplaceAsync | v1alpha | | | -| dataTables.dataTableRows.bulkUpdate | v1alpha | | | -| dataTables.dataTableRows.bulkUpdateAsync | v1alpha | | | -| dataTables.dataTableRows.create | v1alpha | | | -| dataTables.dataTableRows.delete | v1alpha | chronicle.data_table.delete_data_table_rows | secops data-table delete-rows | -| dataTables.dataTableRows.get | v1alpha | | | -| dataTables.dataTableRows.list | v1alpha | chronicle.data_table.list_data_table_rows | secops data-table list-rows | -| dataTables.dataTableRows.patch | v1alpha | | | -| dataTables.delete | v1alpha | chronicle.data_table.delete_data_table | secops data-table delete | -| dataTables.get | v1alpha | chronicle.data_table.get_data_table | secops data-table get | -| dataTables.list | v1alpha | chronicle.data_table.list_data_tables | secops data-table list | -| dataTables.patch | v1alpha | | | -| dataTables.upload | v1alpha | | | -| dataTaps.create | v1alpha | | | -| dataTaps.delete | v1alpha | | | -| dataTaps.get | v1alpha | | | -| dataTaps.list | v1alpha | | | -| dataTaps.patch | v1alpha | | | -| delete | v1alpha | | | -| enrichmentControls.create | v1alpha | | | -| enrichmentControls.delete | v1alpha | | | -| enrichmentControls.get | v1alpha | | | -| enrichmentControls.list | v1alpha | | | -| entities.get | v1alpha | | | -| entities.import | v1alpha | | | -| entities.modifyEntityRiskScore | v1alpha | | | -| entities.queryEntityRiskScoreModifications | v1alpha | | | -| entityRiskScores.query | v1alpha | | | -| errorNotificationConfigs.create | v1alpha | | | -| errorNotificationConfigs.delete | v1alpha | | | -| errorNotificationConfigs.get | v1alpha | | | -| errorNotificationConfigs.list | v1alpha | | | -| errorNotificationConfigs.patch | v1alpha | | | -| events.batchGet | v1alpha | | | -| events.get | v1alpha | | | -| events.import | v1alpha | chronicle.log_ingest.ingest_udm | secops log ingest-udm | -| extractSyslog | v1alpha | | | -| federationGroups.create | v1alpha | | | -| federationGroups.delete | v1alpha | | | -| federationGroups.get | v1alpha | | | -| federationGroups.list | v1alpha | | | -| federationGroups.patch | v1alpha | | | -| feedPacks.get | v1alpha | | | -| feedPacks.list | v1alpha | | | -| feedServiceAccounts.fetchServiceAccountForCustomer | v1alpha | | | -| feedSourceTypeSchemas.list | v1alpha | | | -| feedSourceTypeSchemas.logTypeSchemas.list | v1alpha | | | -| feeds.create | v1alpha | chronicle.feeds.create_feed | secops feed create | -| feeds.delete | v1alpha | chronicle.feeds.delete_feed | secops feed delete | -| feeds.disable | v1alpha | chronicle.feeds.disable_feed | secops feed disable | -| feeds.enable | v1alpha | chronicle.feeds.enable_feed | secops feed enable | -| feeds.generateSecret | v1alpha | chronicle.feeds.generate_secret | secops feed secret | -| feeds.get | v1alpha | chronicle.feeds.get_feed | secops feed get | -| feeds.importPushLogs | v1alpha | | | -| feeds.list | v1alpha | chronicle.feeds.list_feeds | secops feed list | -| feeds.patch | v1alpha | chronicle.feeds.update_feed | secops feed update | -| feeds.scheduleTransfer | v1alpha | | | -| fetchFederationAccess | v1alpha | | | -| findEntity | v1alpha | | | -| findEntityAlerts | v1alpha | | | -| findRelatedEntities | v1alpha | | | -| findUdmFieldValues | v1alpha | | | -| findingsGraph.exploreNode | v1alpha | | | -| findingsGraph.initializeGraph | v1alpha | | | -| findingsRefinements.computeFindingsRefinementActivity | v1alpha | chronicle.rule_exclusion.compute_rule_exclusion_activity | secops rule-exclusion compute-activity | -| findingsRefinements.create | v1alpha | chronicle.rule_exclusion.create_rule_exclusion | secops rule-exclusion create | -| findingsRefinements.get | v1alpha | chronicle.rule_exclusion.get_rule_exclusion | secops rule-exclusion get | -| findingsRefinements.getDeployment | v1alpha | chronicle.rule_exclusion.get_rule_exclusion_deployment | secops rule-exclusion get-deployment | -| findingsRefinements.list | v1alpha | chronicle.rule_exclusion.list_rule_exclusions | secops rule-exclusion list | -| findingsRefinements.patch | v1alpha | chronicle.rule_exclusion.patch_rule_exclusion | secops rule-exclusion update | -| findingsRefinements.updateDeployment | v1alpha | chronicle.rule_exclusion.update_rule_exclusion_deployment | secops rule-exclusion update-deployment | -| forwarders.collectors.create | v1alpha | | | -| forwarders.collectors.delete | v1alpha | | | -| forwarders.collectors.get | v1alpha | | | -| forwarders.collectors.list | v1alpha | | | -| forwarders.collectors.patch | v1alpha | | | -| forwarders.create | v1alpha | chronicle.log_ingest.create_forwarder | secops forwarder create | -| forwarders.delete | v1alpha | chronicle.log_ingest.delete_forwarder | secops forwarder delete | -| forwarders.generateForwarderFiles | v1alpha | | | -| forwarders.get | v1alpha | chronicle.log_ingest.get_forwarder | secops forwarder get | -| forwarders.importStatsEvents | v1alpha | | | -| forwarders.list | v1alpha | chronicle.log_ingest.list_forwarder | secops forwarder list | -| forwarders.patch | v1alpha | chronicle.log_ingest.update_forwarder | secops forwarder update | -| generateCollectionAgentAuth | v1alpha | | | -| generateSoarAuthJwt | v1alpha | | | -| generateUdmKeyValueMappings | v1alpha | | | -| generateWorkspaceConnectionToken | v1alpha | | | -| get | v1alpha | | | -| getBigQueryExport | v1alpha | | | -| getMultitenantDirectory | v1alpha | | | -| getRiskConfig | v1alpha | | | -| ingestionLogLabels.get | v1alpha | | | -| ingestionLogLabels.list | v1alpha | | | -| ingestionLogNamespaces.get | v1alpha | | | -| ingestionLogNamespaces.list | v1alpha | | | -| iocs.batchGet | v1alpha | | | -| iocs.findFirstAndLastSeen | v1alpha | | | -| iocs.get | v1alpha | | | -| iocs.getIocState | v1alpha | | | -| iocs.searchCuratedDetectionsForIoc | v1alpha | | | -| iocs.updateIocState | v1alpha | | | -| legacy.legacyBatchGetCases | v1alpha | chronicle.case.get_cases_from_list | secops case | -| legacy.legacyBatchGetCollections | v1alpha | | | -| legacy.legacyCreateOrUpdateCase | v1alpha | | | -| legacy.legacyCreateSoarAlert | v1alpha | | | -| legacy.legacyFetchAlertsView | v1alpha | chronicle.alert.get_alerts | secops alert | -| legacy.legacyFetchUdmSearchCsv | v1alpha | chronicle.udm_search.fetch_udm_search_csv | secops search --csv | -| legacy.legacyFetchUdmSearchView | v1alpha | chronicle.udm_search.fetch_udm_search_view | secops udm-search-view | -| legacy.legacyFindAssetEvents | v1alpha | | | -| legacy.legacyFindRawLogs | v1alpha | | | -| legacy.legacyFindUdmEvents | v1alpha | | | -| legacy.legacyGetAlert | v1alpha | chronicle.rule_alert.get_alert | | -| legacy.legacyGetCuratedRulesTrends | v1alpha | | | -| legacy.legacyGetDetection | v1alpha | | | -| legacy.legacyGetEventForDetection | v1alpha | | | -| legacy.legacyGetRuleCounts | v1alpha | | | -| legacy.legacyGetRulesTrends | v1alpha | | | -| legacy.legacyListCases | v1alpha | chronicle.case.get_cases | secops case --ids | -| legacy.legacyRunTestRule | v1alpha | chronicle.rule.run_rule_test | secops rule validate | -| legacy.legacySearchArtifactEvents | v1alpha | | | -| legacy.legacySearchArtifactIoCDetails | v1alpha | | | -| legacy.legacySearchAssetEvents | v1alpha | | | -| legacy.legacySearchCuratedDetections | v1alpha | | | -| legacy.legacySearchCustomerStats | v1alpha | | | -| legacy.legacySearchDetections | v1alpha | chronicle.rule_detection.list_detections | | -| legacy.legacySearchDomainsRecentlyRegistered | v1alpha | | | -| legacy.legacySearchDomainsTimingStats | v1alpha | | | -| legacy.legacySearchEnterpriseWideAlerts | v1alpha | | | -| legacy.legacySearchEnterpriseWideIoCs | v1alpha | chronicle.ioc.list_iocs | secops iocs | -| legacy.legacySearchFindings | v1alpha | | | -| legacy.legacySearchIngestionStats | v1alpha | | | -| legacy.legacySearchIoCInsights | v1alpha | | | -| legacy.legacySearchRawLogs | v1alpha | | | -| legacy.legacySearchRuleDetectionCountBuckets | v1alpha | | | -| legacy.legacySearchRuleDetectionEvents | v1alpha | | | -| legacy.legacySearchRuleResults | v1alpha | | | -| legacy.legacySearchRulesAlerts | v1alpha | chronicle.rule_alert.search_rule_alerts | | -| legacy.legacySearchUserEvents | v1alpha | | | -| legacy.legacyStreamDetectionAlerts | v1alpha | | | -| legacy.legacyTestRuleStreaming | v1alpha | | | -| legacy.legacyUpdateAlert | v1alpha | chronicle.rule_alert.update_alert | | -| listAllFindingsRefinementDeployments | v1alpha | | | -| logTypes.create | v1alpha | | | -| logTypes.generateEventTypesSuggestions | v1alpha | | | -| logTypes.get | v1alpha | | | -| logTypes.getLogTypeSetting | v1alpha | | | -| logTypes.legacySubmitParserExtension | v1alpha | | | -| logTypes.list | v1alpha | | | -| logTypes.logs.export | v1alpha | | | -| logTypes.logs.get | v1alpha | | | -| logTypes.logs.import | v1alpha | chronicle.log_ingest.ingest_log | secops log ingest | -| logTypes.logs.list | v1alpha | | | -| logTypes.parserExtensions.activate | v1alpha | chronicle.parser_extension.activate_parser_extension | secops parser-extension activate | -| logTypes.parserExtensions.create | v1alpha | chronicle.parser_extension.create_parser_extension | secops parser-extension create | -| logTypes.parserExtensions.delete | v1alpha | chronicle.parser_extension.delete_parser_extension | secops parser-extension delete | -| logTypes.parserExtensions.extensionValidationReports.get | v1alpha | | | -| logTypes.parserExtensions.extensionValidationReports.list | v1alpha | | | -| logTypes.parserExtensions.extensionValidationReports.validationErrors.list | v1alpha | | | -| logTypes.parserExtensions.get | v1alpha | chronicle.parser_extension.get_parser_extension | secops parser-extension get | -| logTypes.parserExtensions.list | v1alpha | chronicle.parser_extension.list_parser_extensions | secops parser-extension list | -| logTypes.parserExtensions.validationReports.get | v1alpha | | | -| logTypes.parserExtensions.validationReports.parsingErrors.list | v1alpha | | | -| logTypes.parsers.activate | v1alpha | chronicle.parser.activate_parser | secops parser activate | -| logTypes.parsers.activateReleaseCandidateParser | v1alpha | chronicle.parser.activate_release_candidate | secops parser activate-rc | -| logTypes.parsers.copy | v1alpha | chronicle.parser.copy_parser | secops parser copy | -| logTypes.parsers.create | v1alpha | chronicle.parser.create_parser | secops parser create | -| logTypes.parsers.deactivate | v1alpha | chronicle.parser.deactivate_parser | secops parser deactivate | -| logTypes.parsers.delete | v1alpha | chronicle.parser.delete_parser | secops parser delete | -| logTypes.parsers.get | v1alpha | chronicle.parser.get_parser | secops parser get | -| logTypes.parsers.list | v1alpha | chronicle.parser.list_parsers | secops parser list | -| logTypes.parsers.validationReports.get | v1alpha | | | -| logTypes.parsers.validationReports.parsingErrors.list | v1alpha | | | -| logTypes.patch | v1alpha | | | -| logTypes.runParser | v1alpha | chronicle.parser.run_parser | secops parser run | -| logTypes.updateLogTypeSetting | v1alpha | | | -| logs.classify | v1alpha | | | -| nativeDashboards.addChart | v1alpha | chronicle.dashboard.add_chart | secops dashboard add-chart | -| nativeDashboards.create | v1alpha | chronicle.dashboard.create_dashboard | secops dashboard create | -| nativeDashboards.delete | v1alpha | chronicle.dashboard.delete_dashboard | secops dashboard delete | -| nativeDashboards.duplicate | v1alpha | chronicle.dashboard.duplicate_dashboard | secops dashboard duplicate | -| nativeDashboards.duplicateChart | v1alpha | | | -| nativeDashboards.editChart | v1alpha | chronicle.dashboard.edit_chart | secops dashboard edit-chart | -| nativeDashboards.export | v1alpha | chronicle.dashboard.export_dashboard | secops dashboard export | -| nativeDashboards.get | v1alpha | chronicle.dashboard.get_dashboard | secops dashboard get | -| nativeDashboards.import | v1alpha | chronicle.dashboard.import_dashboard | secops dashboard import | -| nativeDashboards.list | v1alpha | chronicle.dashboard.list_dashboards | secops dashboard list | -| nativeDashboards.patch | v1alpha | chronicle.dashboard.update_dashboard | secops dashboard update | -| nativeDashboards.removeChart | v1alpha | chronicle.dashboard.remove_chart | secops dashboard remove-chart | -| operations.cancel | v1alpha | | | -| operations.delete | v1alpha | | | -| operations.get | v1alpha | | | -| operations.list | v1alpha | | | -| operations.streamSearch | v1alpha | | | -| queryProductSourceStats | v1alpha | | | -| referenceLists.create | v1alpha | | | -| referenceLists.get | v1alpha | | | -| referenceLists.list | v1alpha | | | -| referenceLists.patch | v1alpha | | | -| report | v1alpha | | | -| ruleExecutionErrors.list | v1alpha | chronicle.rule_detection.list_errors | | -| rules.create | v1alpha | | | -| rules.delete | v1alpha | | | -| rules.deployments.list | v1alpha | | | -| rules.get | v1alpha | | | -| rules.getDeployment | v1alpha | | | -| rules.list | v1alpha | | | -| rules.listRevisions | v1alpha | | | -| rules.patch | v1alpha | | | -| rules.retrohunts.create | v1alpha | | | -| rules.retrohunts.get | v1alpha | | | -| rules.retrohunts.list | v1alpha | | | -| rules.updateDeployment | v1alpha | | | -| searchEntities | v1alpha | | | -| searchRawLogs | v1alpha | | | -| summarizeEntitiesFromQuery | v1alpha | chronicle.entity.summarize_entity | secops entity | -| summarizeEntity | v1alpha | chronicle.entity.summarize_entity | | -| testFindingsRefinement | v1alpha | | | -| translateUdmQuery | v1alpha | chronicle.nl_search.translate_nl_to_udm | | -| translateYlRule | v1alpha | | | -| udmSearch | v1alpha | chronicle.search.search_udm | secops search | -| undelete | v1alpha | | | -| updateBigQueryExport | v1alpha | | | -| updateRiskConfig | v1alpha | | | -| users.clearConversationHistory | v1alpha | | | -| users.conversations.create | v1alpha | chronicle.gemini.create_conversation | | -| users.conversations.delete | v1alpha | | | -| users.conversations.get | v1alpha | | | -| users.conversations.list | v1alpha | | | -| users.conversations.messages.create | v1alpha | chronicle.gemini.query_gemini | secops gemini | -| users.conversations.messages.delete | v1alpha | | | -| users.conversations.messages.get | v1alpha | | | -| users.conversations.messages.list | v1alpha | | | -| users.conversations.messages.patch | v1alpha | | | -| users.conversations.patch | v1alpha | | | -| users.getPreferenceSet | v1alpha | chronicle.gemini.opt_in_to_gemini | secops gemini --opt-in | -| users.searchQueries.create | v1alpha | | | -| users.searchQueries.delete | v1alpha | | | -| users.searchQueries.get | v1alpha | | | -| users.searchQueries.list | v1alpha | | | -| users.searchQueries.patch | v1alpha | | | -| users.updatePreferenceSet | v1alpha | | | -| validateQuery | v1alpha | chronicle.validate.validate_query | | -| verifyReferenceList | v1alpha | | | -| verifyRuleText | v1alpha | chronicle.rule_validation.validate_rule | secops rule validate | -| watchlists.create | v1alpha | | | -| watchlists.delete | v1alpha | | | -| watchlists.entities.add | v1alpha | | | -| watchlists.entities.batchAdd | v1alpha | | | -| watchlists.entities.batchRemove | v1alpha | | | -| watchlists.entities.remove | v1alpha | | | -| watchlists.get | v1alpha | | | -| watchlists.list | v1alpha | | | -| watchlists.listEntities | v1alpha | | | -| watchlists.patch | v1alpha | | | +| REST Resource | Version | secops-wrapper module | CLI Command | +|--------------------------------------------------------------------------------|---------|-------------------------------------------------------------------------------------------------------------------|-----------------------------------------| +| dataAccessLabels.create | v1 | | | +| dataAccessLabels.delete | v1 | | | +| dataAccessLabels.get | v1 | | | +| dataAccessLabels.list | v1 | | | +| dataAccessLabels.patch | v1 | | | +| dataAccessScopes.create | v1 | | | +| dataAccessScopes.delete | v1 | | | +| dataAccessScopes.get | v1 | | | +| dataAccessScopes.list | v1 | | | +| dataAccessScopes.patch | v1 | | | +| get | v1 | | | +| operations.cancel | v1 | | | +| operations.delete | v1 | | | +| operations.get | v1 | | | +| operations.list | v1 | | | +| referenceLists.create | v1 | chronicle.reference_list.create_reference_list | secops reference-list create | +| referenceLists.get | v1 | chronicle.reference_list.get_reference_list | secops reference-list get | +| referenceLists.list | v1 | chronicle.reference_list.list_reference_lists | secops reference-list list | +| referenceLists.patch | v1 | chronicle.reference_list.update_reference_list | secops reference-list update | +| rules.create | v1 | chronicle.rule.create_rule | secops rule create | +| rules.delete | v1 | chronicle.rule.delete_rule | secops rule delete | +| rules.deployments.list | v1 | | | +| rules.get | v1 | chronicle.rule.get_rule | secops rule get | +| rules.getDeployment | v1 | | | +| rules.list | v1 | chronicle.rule.list_rules | secops rule list | +| rules.listRevisions | v1 | | | +| rules.patch | v1 | chronicle.rule.update_rule | secops rule update | +| rules.retrohunts.create | v1 | chronicle.rule_retrohunt.create_retrohunt | | +| rules.retrohunts.get | v1 | chronicle.rule_retrohunt.get_retrohunt | | +| rules.retrohunts.list | v1 | | | +| rules.updateDeployment | v1 | chronicle.rule.enable_rule | secops rule enable | +| watchlists.create | v1 | | | +| watchlists.delete | v1 | | | +| watchlists.get | v1 | | | +| watchlists.list | v1 | | | +| watchlists.patch | v1 | | | +| dataAccessLabels.create | v1beta | | | +| dataAccessLabels.delete | v1beta | | | +| dataAccessLabels.get | v1beta | | | +| dataAccessLabels.list | v1beta | | | +| dataAccessLabels.patch | v1beta | | | +| dataAccessScopes.create | v1beta | | | +| dataAccessScopes.delete | v1beta | | | +| dataAccessScopes.get | v1beta | | | +| dataAccessScopes.list | v1beta | | | +| dataAccessScopes.patch | v1beta | | | +| get | v1beta | | | +| operations.cancel | v1beta | | | +| operations.delete | v1beta | | | +| operations.get | v1beta | | | +| operations.list | v1beta | | | +| referenceLists.create | v1beta | | | +| referenceLists.get | v1beta | | | +| referenceLists.list | v1beta | | | +| referenceLists.patch | v1beta | | | +| rules.create | v1beta | | | +| rules.delete | v1beta | | | +| rules.deployments.list | v1beta | | | +| rules.get | v1beta | | | +| rules.getDeployment | v1beta | | | +| rules.list | v1beta | | | +| rules.listRevisions | v1beta | | | +| rules.patch | v1beta | | | +| rules.retrohunts.create | v1beta | | | +| rules.retrohunts.get | v1beta | | | +| rules.retrohunts.list | v1beta | | | +| rules.updateDeployment | v1beta | | | +| watchlists.create | v1beta | | | +| watchlists.delete | v1beta | | | +| watchlists.get | v1beta | | | +| watchlists.list | v1beta | | | +| watchlists.patch | v1beta | | | +| analytics.entities.analyticValues.list | v1alpha | | | +| analytics.list | v1alpha | | | +| batchValidateWatchlistEntities | v1alpha | | | +| bigQueryAccess.provide | v1alpha | | | +| bigQueryExport.provision | v1alpha | | | +| cases.countPriorities | v1alpha | | | +| curatedRuleSetCategories.curatedRuleSets.curatedRuleSetDeployments.batchUpdate | v1alpha | chronicle.rule_set.batch_update_curated_rule_set_deployments | | +| curatedRuleSetCategories.curatedRuleSets.curatedRuleSetDeployments.patch | v1alpha | | | +| curatedRuleSetCategories.curatedRuleSets.curatedRuleSetDeployments.list | v1alpha | chronicle.rule_set.list_curated_rule_set_deployments | | +| curatedRuleSetCategories.curatedRuleSets.curatedRuleSetDeployments.get | v1alpha | chronicle.rule_set.get_curated_rule_set_deployment
chronicle.rule_set.get_curated_rule_set_deployment_by_name | | +| curatedRuleSetCategories.curatedRuleSets.get | v1alpha | chronicle.rule_set.get_curated_rule_set | | +| curatedRuleSetCategories.curatedRuleSets.list | v1alpha | chronicle.rule_set.list_curated_rule_sets | | +| curatedRuleSetCategories.get | v1alpha | chronicle.rule_set.get_curated_rule_set_category | | +| curatedRuleSetCategories.list | v1alpha | chronicle.rule_set.list_curated_rule_set_categories | | +| curatedRules.get | v1alpha | chronicle.rule_set.get_curated_rule | | +| curatedRules.list | v1alpha | chronicle.rule_set.list_curated_rules | | +| dashboardCharts.batchGet | v1alpha | | | +| dashboardCharts.get | v1alpha | chronicle.dashboard.get_chart | secops dashboard get-chart | +| dashboardQueries.execute | v1alpha | chronicle.dashboard_query.execute_query | secops dashboard-query execute | +| dashboardQueries.get | v1alpha | chronicle.dashboard_query.get_execute_query | secops dashboard-query get | +| dashboards.copy | v1alpha | | | +| dashboards.create | v1alpha | | | +| dashboards.delete | v1alpha | | | +| dashboards.get | v1alpha | | | +| dashboards.list | v1alpha | | | +| dataAccessLabels.create | v1alpha | | | +| dataAccessLabels.delete | v1alpha | | | +| dataAccessLabels.get | v1alpha | | | +| dataAccessLabels.list | v1alpha | | | +| dataAccessLabels.patch | v1alpha | | | +| dataAccessScopes.create | v1alpha | | | +| dataAccessScopes.delete | v1alpha | | | +| dataAccessScopes.get | v1alpha | | | +| dataAccessScopes.list | v1alpha | | | +| dataAccessScopes.patch | v1alpha | | | +| dataExports.cancel | v1alpha | chronicle.data_export.cancel_data_export | secops export cancel | +| dataExports.create | v1alpha | chronicle.data_export.create_data_export | secops export create | +| dataExports.fetchavailablelogtypes | v1alpha | chronicle.data_export.fetch_available_log_types | secops export log-types | +| dataExports.get | v1alpha | chronicle.data_export.get_data_export | secops export status | +| dataExports.list | v1alpha | chronicle.data_export.list_data_export | secops export list | +| dataExports.patch | v1alpha | chronicle.data_export.update_data_export | secops export update | +| dataTableOperationErrors.get | v1alpha | | | +| dataTables.create | v1alpha | chronicle.data_table.create_data_table | secops data-table create | +| dataTables.dataTableRows.bulkCreate | v1alpha | chronicle.data_table.create_data_table_rows | secops data-table add-rows | +| dataTables.dataTableRows.bulkCreateAsync | v1alpha | | | +| dataTables.dataTableRows.bulkGet | v1alpha | | | +| dataTables.dataTableRows.bulkReplace | v1alpha | | | +| dataTables.dataTableRows.bulkReplaceAsync | v1alpha | | | +| dataTables.dataTableRows.bulkUpdate | v1alpha | | | +| dataTables.dataTableRows.bulkUpdateAsync | v1alpha | | | +| dataTables.dataTableRows.create | v1alpha | | | +| dataTables.dataTableRows.delete | v1alpha | chronicle.data_table.delete_data_table_rows | secops data-table delete-rows | +| dataTables.dataTableRows.get | v1alpha | | | +| dataTables.dataTableRows.list | v1alpha | chronicle.data_table.list_data_table_rows | secops data-table list-rows | +| dataTables.dataTableRows.patch | v1alpha | | | +| dataTables.delete | v1alpha | chronicle.data_table.delete_data_table | secops data-table delete | +| dataTables.get | v1alpha | chronicle.data_table.get_data_table | secops data-table get | +| dataTables.list | v1alpha | chronicle.data_table.list_data_tables | secops data-table list | +| dataTables.patch | v1alpha | | | +| dataTables.upload | v1alpha | | | +| dataTaps.create | v1alpha | | | +| dataTaps.delete | v1alpha | | | +| dataTaps.get | v1alpha | | | +| dataTaps.list | v1alpha | | | +| dataTaps.patch | v1alpha | | | +| delete | v1alpha | | | +| enrichmentControls.create | v1alpha | | | +| enrichmentControls.delete | v1alpha | | | +| enrichmentControls.get | v1alpha | | | +| enrichmentControls.list | v1alpha | | | +| entities.get | v1alpha | | | +| entities.import | v1alpha | | | +| entities.modifyEntityRiskScore | v1alpha | | | +| entities.queryEntityRiskScoreModifications | v1alpha | | | +| entityRiskScores.query | v1alpha | | | +| errorNotificationConfigs.create | v1alpha | | | +| errorNotificationConfigs.delete | v1alpha | | | +| errorNotificationConfigs.get | v1alpha | | | +| errorNotificationConfigs.list | v1alpha | | | +| errorNotificationConfigs.patch | v1alpha | | | +| events.batchGet | v1alpha | | | +| events.get | v1alpha | | | +| events.import | v1alpha | chronicle.log_ingest.ingest_udm | secops log ingest-udm | +| extractSyslog | v1alpha | | | +| federationGroups.create | v1alpha | | | +| federationGroups.delete | v1alpha | | | +| federationGroups.get | v1alpha | | | +| federationGroups.list | v1alpha | | | +| federationGroups.patch | v1alpha | | | +| feedPacks.get | v1alpha | | | +| feedPacks.list | v1alpha | | | +| feedServiceAccounts.fetchServiceAccountForCustomer | v1alpha | | | +| feedSourceTypeSchemas.list | v1alpha | | | +| feedSourceTypeSchemas.logTypeSchemas.list | v1alpha | | | +| feeds.create | v1alpha | chronicle.feeds.create_feed | secops feed create | +| feeds.delete | v1alpha | chronicle.feeds.delete_feed | secops feed delete | +| feeds.disable | v1alpha | chronicle.feeds.disable_feed | secops feed disable | +| feeds.enable | v1alpha | chronicle.feeds.enable_feed | secops feed enable | +| feeds.generateSecret | v1alpha | chronicle.feeds.generate_secret | secops feed secret | +| feeds.get | v1alpha | chronicle.feeds.get_feed | secops feed get | +| feeds.importPushLogs | v1alpha | | | +| feeds.list | v1alpha | chronicle.feeds.list_feeds | secops feed list | +| feeds.patch | v1alpha | chronicle.feeds.update_feed | secops feed update | +| feeds.scheduleTransfer | v1alpha | | | +| fetchFederationAccess | v1alpha | | | +| findEntity | v1alpha | | | +| findEntityAlerts | v1alpha | | | +| findRelatedEntities | v1alpha | | | +| findUdmFieldValues | v1alpha | | | +| findingsGraph.exploreNode | v1alpha | | | +| findingsGraph.initializeGraph | v1alpha | | | +| findingsRefinements.computeFindingsRefinementActivity | v1alpha | chronicle.rule_exclusion.compute_rule_exclusion_activity | secops rule-exclusion compute-activity | +| findingsRefinements.create | v1alpha | chronicle.rule_exclusion.create_rule_exclusion | secops rule-exclusion create | +| findingsRefinements.get | v1alpha | chronicle.rule_exclusion.get_rule_exclusion | secops rule-exclusion get | +| findingsRefinements.getDeployment | v1alpha | chronicle.rule_exclusion.get_rule_exclusion_deployment | secops rule-exclusion get-deployment | +| findingsRefinements.list | v1alpha | chronicle.rule_exclusion.list_rule_exclusions | secops rule-exclusion list | +| findingsRefinements.patch | v1alpha | chronicle.rule_exclusion.patch_rule_exclusion | secops rule-exclusion update | +| findingsRefinements.updateDeployment | v1alpha | chronicle.rule_exclusion.update_rule_exclusion_deployment | secops rule-exclusion update-deployment | +| forwarders.collectors.create | v1alpha | | | +| forwarders.collectors.delete | v1alpha | | | +| forwarders.collectors.get | v1alpha | | | +| forwarders.collectors.list | v1alpha | | | +| forwarders.collectors.patch | v1alpha | | | +| forwarders.create | v1alpha | chronicle.log_ingest.create_forwarder | secops forwarder create | +| forwarders.delete | v1alpha | chronicle.log_ingest.delete_forwarder | secops forwarder delete | +| forwarders.generateForwarderFiles | v1alpha | | | +| forwarders.get | v1alpha | chronicle.log_ingest.get_forwarder | secops forwarder get | +| forwarders.importStatsEvents | v1alpha | | | +| forwarders.list | v1alpha | chronicle.log_ingest.list_forwarder | secops forwarder list | +| forwarders.patch | v1alpha | chronicle.log_ingest.update_forwarder | secops forwarder update | +| generateCollectionAgentAuth | v1alpha | | | +| generateSoarAuthJwt | v1alpha | | | +| generateUdmKeyValueMappings | v1alpha | | | +| generateWorkspaceConnectionToken | v1alpha | | | +| get | v1alpha | | | +| getBigQueryExport | v1alpha | | | +| getMultitenantDirectory | v1alpha | | | +| getRiskConfig | v1alpha | | | +| ingestionLogLabels.get | v1alpha | | | +| ingestionLogLabels.list | v1alpha | | | +| ingestionLogNamespaces.get | v1alpha | | | +| ingestionLogNamespaces.list | v1alpha | | | +| iocs.batchGet | v1alpha | | | +| iocs.findFirstAndLastSeen | v1alpha | | | +| iocs.get | v1alpha | | | +| iocs.getIocState | v1alpha | | | +| iocs.searchCuratedDetectionsForIoc | v1alpha | | | +| iocs.updateIocState | v1alpha | | | +| legacy.legacyBatchGetCases | v1alpha | chronicle.case.get_cases_from_list | secops case | +| legacy.legacyBatchGetCollections | v1alpha | | | +| legacy.legacyCreateOrUpdateCase | v1alpha | | | +| legacy.legacyCreateSoarAlert | v1alpha | | | +| legacy.legacyFetchAlertsView | v1alpha | chronicle.alert.get_alerts | secops alert | +| legacy.legacyFetchUdmSearchCsv | v1alpha | chronicle.udm_search.fetch_udm_search_csv | secops search --csv | +| legacy.legacyFetchUdmSearchView | v1alpha | chronicle.udm_search.fetch_udm_search_view | secops udm-search-view | +| legacy.legacyFindAssetEvents | v1alpha | | | +| legacy.legacyFindRawLogs | v1alpha | | | +| legacy.legacyFindUdmEvents | v1alpha | | | +| legacy.legacyGetAlert | v1alpha | chronicle.rule_alert.get_alert | | +| legacy.legacyGetCuratedRulesTrends | v1alpha | | | +| legacy.legacyGetDetection | v1alpha | | | +| legacy.legacyGetEventForDetection | v1alpha | | | +| legacy.legacyGetRuleCounts | v1alpha | | | +| legacy.legacyGetRulesTrends | v1alpha | | | +| legacy.legacyListCases | v1alpha | chronicle.case.get_cases | secops case --ids | +| legacy.legacyRunTestRule | v1alpha | chronicle.rule.run_rule_test | secops rule validate | +| legacy.legacySearchArtifactEvents | v1alpha | | | +| legacy.legacySearchArtifactIoCDetails | v1alpha | | | +| legacy.legacySearchAssetEvents | v1alpha | | | +| legacy.legacySearchCuratedDetections | v1alpha | | | +| legacy.legacySearchCustomerStats | v1alpha | | | +| legacy.legacySearchDetections | v1alpha | chronicle.rule_detection.list_detections | | +| legacy.legacySearchDomainsRecentlyRegistered | v1alpha | | | +| legacy.legacySearchDomainsTimingStats | v1alpha | | | +| legacy.legacySearchEnterpriseWideAlerts | v1alpha | | | +| legacy.legacySearchEnterpriseWideIoCs | v1alpha | chronicle.ioc.list_iocs | secops iocs | +| legacy.legacySearchFindings | v1alpha | | | +| legacy.legacySearchIngestionStats | v1alpha | | | +| legacy.legacySearchIoCInsights | v1alpha | | | +| legacy.legacySearchRawLogs | v1alpha | | | +| legacy.legacySearchRuleDetectionCountBuckets | v1alpha | | | +| legacy.legacySearchRuleDetectionEvents | v1alpha | | | +| legacy.legacySearchRuleResults | v1alpha | | | +| legacy.legacySearchRulesAlerts | v1alpha | chronicle.rule_alert.search_rule_alerts | | +| legacy.legacySearchUserEvents | v1alpha | | | +| legacy.legacyStreamDetectionAlerts | v1alpha | | | +| legacy.legacyTestRuleStreaming | v1alpha | | | +| legacy.legacyUpdateAlert | v1alpha | chronicle.rule_alert.update_alert | | +| listAllFindingsRefinementDeployments | v1alpha | | | +| logTypes.create | v1alpha | | | +| logTypes.generateEventTypesSuggestions | v1alpha | | | +| logTypes.get | v1alpha | | | +| logTypes.getLogTypeSetting | v1alpha | | | +| logTypes.legacySubmitParserExtension | v1alpha | | | +| logTypes.list | v1alpha | | | +| logTypes.logs.export | v1alpha | | | +| logTypes.logs.get | v1alpha | | | +| logTypes.logs.import | v1alpha | chronicle.log_ingest.ingest_log | secops log ingest | +| logTypes.logs.list | v1alpha | | | +| logTypes.parserExtensions.activate | v1alpha | chronicle.parser_extension.activate_parser_extension | secops parser-extension activate | +| logTypes.parserExtensions.create | v1alpha | chronicle.parser_extension.create_parser_extension | secops parser-extension create | +| logTypes.parserExtensions.delete | v1alpha | chronicle.parser_extension.delete_parser_extension | secops parser-extension delete | +| logTypes.parserExtensions.extensionValidationReports.get | v1alpha | | | +| logTypes.parserExtensions.extensionValidationReports.list | v1alpha | | | +| logTypes.parserExtensions.extensionValidationReports.validationErrors.list | v1alpha | | | +| logTypes.parserExtensions.get | v1alpha | chronicle.parser_extension.get_parser_extension | secops parser-extension get | +| logTypes.parserExtensions.list | v1alpha | chronicle.parser_extension.list_parser_extensions | secops parser-extension list | +| logTypes.parserExtensions.validationReports.get | v1alpha | | | +| logTypes.parserExtensions.validationReports.parsingErrors.list | v1alpha | | | +| logTypes.parsers.activate | v1alpha | chronicle.parser.activate_parser | secops parser activate | +| logTypes.parsers.activateReleaseCandidateParser | v1alpha | chronicle.parser.activate_release_candidate | secops parser activate-rc | +| logTypes.parsers.copy | v1alpha | chronicle.parser.copy_parser | secops parser copy | +| logTypes.parsers.create | v1alpha | chronicle.parser.create_parser | secops parser create | +| logTypes.parsers.deactivate | v1alpha | chronicle.parser.deactivate_parser | secops parser deactivate | +| logTypes.parsers.delete | v1alpha | chronicle.parser.delete_parser | secops parser delete | +| logTypes.parsers.get | v1alpha | chronicle.parser.get_parser | secops parser get | +| logTypes.parsers.list | v1alpha | chronicle.parser.list_parsers | secops parser list | +| logTypes.parsers.validationReports.get | v1alpha | | | +| logTypes.parsers.validationReports.parsingErrors.list | v1alpha | | | +| logTypes.patch | v1alpha | | | +| logTypes.runParser | v1alpha | chronicle.parser.run_parser | secops parser run | +| logTypes.updateLogTypeSetting | v1alpha | | | +| logs.classify | v1alpha | | | +| nativeDashboards.addChart | v1alpha | chronicle.dashboard.add_chart | secops dashboard add-chart | +| nativeDashboards.create | v1alpha | chronicle.dashboard.create_dashboard | secops dashboard create | +| nativeDashboards.delete | v1alpha | chronicle.dashboard.delete_dashboard | secops dashboard delete | +| nativeDashboards.duplicate | v1alpha | chronicle.dashboard.duplicate_dashboard | secops dashboard duplicate | +| nativeDashboards.duplicateChart | v1alpha | | | +| nativeDashboards.editChart | v1alpha | chronicle.dashboard.edit_chart | secops dashboard edit-chart | +| nativeDashboards.export | v1alpha | chronicle.dashboard.export_dashboard | secops dashboard export | +| nativeDashboards.get | v1alpha | chronicle.dashboard.get_dashboard | secops dashboard get | +| nativeDashboards.import | v1alpha | chronicle.dashboard.import_dashboard | secops dashboard import | +| nativeDashboards.list | v1alpha | chronicle.dashboard.list_dashboards | secops dashboard list | +| nativeDashboards.patch | v1alpha | chronicle.dashboard.update_dashboard | secops dashboard update | +| nativeDashboards.removeChart | v1alpha | chronicle.dashboard.remove_chart | secops dashboard remove-chart | +| operations.cancel | v1alpha | | | +| operations.delete | v1alpha | | | +| operations.get | v1alpha | | | +| operations.list | v1alpha | | | +| operations.streamSearch | v1alpha | | | +| queryProductSourceStats | v1alpha | | | +| referenceLists.create | v1alpha | | | +| referenceLists.get | v1alpha | | | +| referenceLists.list | v1alpha | | | +| referenceLists.patch | v1alpha | | | +| report | v1alpha | | | +| ruleExecutionErrors.list | v1alpha | chronicle.rule_detection.list_errors | | +| rules.create | v1alpha | | | +| rules.delete | v1alpha | | | +| rules.deployments.list | v1alpha | | | +| rules.get | v1alpha | | | +| rules.getDeployment | v1alpha | | | +| rules.list | v1alpha | | | +| rules.listRevisions | v1alpha | | | +| rules.patch | v1alpha | | | +| rules.retrohunts.create | v1alpha | | | +| rules.retrohunts.get | v1alpha | | | +| rules.retrohunts.list | v1alpha | | | +| rules.updateDeployment | v1alpha | | | +| searchEntities | v1alpha | | | +| searchRawLogs | v1alpha | | | +| summarizeEntitiesFromQuery | v1alpha | chronicle.entity.summarize_entity | secops entity | +| summarizeEntity | v1alpha | chronicle.entity.summarize_entity | | +| testFindingsRefinement | v1alpha | | | +| translateUdmQuery | v1alpha | chronicle.nl_search.translate_nl_to_udm | | +| translateYlRule | v1alpha | | | +| udmSearch | v1alpha | chronicle.search.search_udm | secops search | +| undelete | v1alpha | | | +| updateBigQueryExport | v1alpha | | | +| updateRiskConfig | v1alpha | | | +| users.clearConversationHistory | v1alpha | | | +| users.conversations.create | v1alpha | chronicle.gemini.create_conversation | | +| users.conversations.delete | v1alpha | | | +| users.conversations.get | v1alpha | | | +| users.conversations.list | v1alpha | | | +| users.conversations.messages.create | v1alpha | chronicle.gemini.query_gemini | secops gemini | +| users.conversations.messages.delete | v1alpha | | | +| users.conversations.messages.get | v1alpha | | | +| users.conversations.messages.list | v1alpha | | | +| users.conversations.messages.patch | v1alpha | | | +| users.conversations.patch | v1alpha | | | +| users.getPreferenceSet | v1alpha | chronicle.gemini.opt_in_to_gemini | secops gemini --opt-in | +| users.searchQueries.create | v1alpha | | | +| users.searchQueries.delete | v1alpha | | | +| users.searchQueries.get | v1alpha | | | +| users.searchQueries.list | v1alpha | | | +| users.searchQueries.patch | v1alpha | | | +| users.updatePreferenceSet | v1alpha | | | +| validateQuery | v1alpha | chronicle.validate.validate_query | | +| verifyReferenceList | v1alpha | | | +| verifyRuleText | v1alpha | chronicle.rule_validation.validate_rule | secops rule validate | +| watchlists.create | v1alpha | | | +| watchlists.delete | v1alpha | | | +| watchlists.entities.add | v1alpha | | | +| watchlists.entities.batchAdd | v1alpha | | | +| watchlists.entities.batchRemove | v1alpha | | | +| watchlists.entities.remove | v1alpha | | | +| watchlists.get | v1alpha | | | +| watchlists.list | v1alpha | | | +| watchlists.listEntities | v1alpha | | | +| watchlists.patch | v1alpha | | | diff --git a/src/secops/chronicle/__init__.py b/src/secops/chronicle/__init__.py index 5ae38fa9..ab83bfcc 100644 --- a/src/secops/chronicle/__init__.py +++ b/src/secops/chronicle/__init__.py @@ -142,6 +142,7 @@ get_curated_rule_set, list_curated_rule_set_deployments, get_curated_rule_set_deployment, + get_curated_rule_set_deployment_by_name, ) from secops.chronicle.rule_validation import ValidationResult from secops.chronicle.search import search_udm @@ -246,6 +247,7 @@ "get_curated_rule_set", "list_curated_rule_set_deployments", "get_curated_rule_set_deployment", + "get_curated_rule_set_deployment_by_name", # Native Dashboard "add_chart", "create_dashboard", diff --git a/src/secops/chronicle/client.py b/src/secops/chronicle/client.py index 1bf30113..340cbc9a 100644 --- a/src/secops/chronicle/client.py +++ b/src/secops/chronicle/client.py @@ -230,6 +230,7 @@ get_curated_rule_set as _get_curated_rule_set, list_curated_rule_set_deployments as _list_curated_rule_set_deployments, get_curated_rule_set_deployment as _get_curated_rule_set_deployment, + get_curated_rule_set_deployment_by_name as _get_curated_rule_set_deployment_by_name, ) from secops.chronicle.rule_validation import validate_rule as _validate_rule from secops.chronicle.search import search_udm as _search_udm @@ -1821,6 +1822,26 @@ def get_curated_rule_set_deployment( """ return _get_curated_rule_set_deployment(self, rule_set_id, precision) + def get_curated_rule_set_deployment_by_name( + self, + rule_set_name: str, + precision: str = "precise", + ) -> Dict[str, Any]: + """Get a curated rule set deployment by human-readable display name + + Args: + rule_set_name: Display name of the curated rule set + precision: Precision level ("precise" or "broad") + + Returns: + Dictionary containing the curated rule set deployment + + Raises: + APIError: If the API request fails + SecOpsError: If the rule set is not found or precision is invalid + """ + return _get_curated_rule_set_deployment_by_name(self, rule_set_name, precision) + def list_curated_rules( self, page_size: Optional[str] = None, diff --git a/src/secops/chronicle/rule_set.py b/src/secops/chronicle/rule_set.py index 6c611382..bc7e38bb 100644 --- a/src/secops/chronicle/rule_set.py +++ b/src/secops/chronicle/rule_set.py @@ -347,6 +347,47 @@ def get_curated_rule_set_deployment( return deployment +def get_curated_rule_set_deployment_by_name( + client, + rule_set_name: str, + precision: str = "precise", +) -> Dict[str, Any]: + """Get the deployment status of a curated rule set by its display name + + Args: + client: ChronicleClient instance + rule_set_name: Display name of the curated rule set (case-insensitive) + precision: Precision level ("precise" or "broad") + + Returns: + Dictionary containing the curated rule set deployment + + Raises: + APIError: If the API request fails + SecOpsError: If the rule set is not found or precision is invalid + """ + if precision not in ["precise", "broad"]: + raise SecOpsError("Precision must be 'precise' or 'broad'") + + rule_set = None + for rs in list_curated_rule_sets(client): + # Names normalised as lowercase + current_name = rs.get("displayName", "").lower() + if current_name == rule_set_name.lower(): + rule_set = rs + break + + if not rule_set: + raise SecOpsError(f"Rule set with name '{rule_set_name}' not found") + + # Extract the rule set ID from the resource name + name_parts = rule_set["name"].split("/") + rule_set_id = name_parts[-1] + + # Get the deployment status using existing function + return get_curated_rule_set_deployment(client, rule_set_id, precision) + + def batch_update_curated_rule_set_deployments( client, deployments: List[Dict[str, Any]] ) -> Dict[str, Any]: From 3d3f7ec61c9fe81a36e6a62e6bbdb724b6c723d1 Mon Sep 17 00:00:00 2001 From: PaperMtn Date: Fri, 24 Oct 2025 20:15:16 +0100 Subject: [PATCH 12/30] feat: added getting rule by display name --- api_module_mapping.md | 2 +- src/secops/chronicle/__init__.py | 2 ++ src/secops/chronicle/client.py | 22 +++++++++++++++++--- src/secops/chronicle/rule_set.py | 35 +++++++++++++++++++++++++++----- 4 files changed, 52 insertions(+), 9 deletions(-) diff --git a/api_module_mapping.md b/api_module_mapping.md index b82d9c54..6b515749 100644 --- a/api_module_mapping.md +++ b/api_module_mapping.md @@ -93,7 +93,7 @@ wrapper module and its respective CLI command (if available). | curatedRuleSetCategories.curatedRuleSets.list | v1alpha | chronicle.rule_set.list_curated_rule_sets | | | curatedRuleSetCategories.get | v1alpha | chronicle.rule_set.get_curated_rule_set_category | | | curatedRuleSetCategories.list | v1alpha | chronicle.rule_set.list_curated_rule_set_categories | | -| curatedRules.get | v1alpha | chronicle.rule_set.get_curated_rule | | +| curatedRules.get | v1alpha | chronicle.rule_set.get_curated_rule
chronicle.rule_set.get_curated_rule_by_name | | | curatedRules.list | v1alpha | chronicle.rule_set.list_curated_rules | | | dashboardCharts.batchGet | v1alpha | | | | dashboardCharts.get | v1alpha | chronicle.dashboard.get_chart | secops dashboard get-chart | diff --git a/src/secops/chronicle/__init__.py b/src/secops/chronicle/__init__.py index ab83bfcc..e95fee47 100644 --- a/src/secops/chronicle/__init__.py +++ b/src/secops/chronicle/__init__.py @@ -143,6 +143,7 @@ list_curated_rule_set_deployments, get_curated_rule_set_deployment, get_curated_rule_set_deployment_by_name, + get_curated_rule_by_name, ) from secops.chronicle.rule_validation import ValidationResult from secops.chronicle.search import search_udm @@ -248,6 +249,7 @@ "list_curated_rule_set_deployments", "get_curated_rule_set_deployment", "get_curated_rule_set_deployment_by_name", + "get_curated_rule_by_name", # Native Dashboard "add_chart", "create_dashboard", diff --git a/src/secops/chronicle/client.py b/src/secops/chronicle/client.py index 340cbc9a..ffa36acb 100644 --- a/src/secops/chronicle/client.py +++ b/src/secops/chronicle/client.py @@ -231,6 +231,7 @@ list_curated_rule_set_deployments as _list_curated_rule_set_deployments, get_curated_rule_set_deployment as _get_curated_rule_set_deployment, get_curated_rule_set_deployment_by_name as _get_curated_rule_set_deployment_by_name, + get_curated_rule_by_name as _get_curated_rule_by_name, ) from secops.chronicle.rule_validation import validate_rule as _validate_rule from secops.chronicle.search import search_udm as _search_udm @@ -1824,13 +1825,13 @@ def get_curated_rule_set_deployment( def get_curated_rule_set_deployment_by_name( self, - rule_set_name: str, + display_name: str, precision: str = "precise", ) -> Dict[str, Any]: """Get a curated rule set deployment by human-readable display name Args: - rule_set_name: Display name of the curated rule set + display_name: Display name of the curated rule set precision: Precision level ("precise" or "broad") Returns: @@ -1840,7 +1841,7 @@ def get_curated_rule_set_deployment_by_name( APIError: If the API request fails SecOpsError: If the rule set is not found or precision is invalid """ - return _get_curated_rule_set_deployment_by_name(self, rule_set_name, precision) + return _get_curated_rule_set_deployment_by_name(self, display_name, precision) def list_curated_rules( self, @@ -1875,6 +1876,21 @@ def get_curated_rule(self, rule_id: str) -> Dict[str, Any]: """ return _get_curated_rule(self, rule_id) + def get_curated_rule_by_name(self, display_name: str) -> Dict[str, Any]: + """Get a curated rule by human-readable display name + + Args: + display_name: Display name of the curated rule + + Returns: + Dictionary containing the curated rule + + Raises: + APIError: If the API request fails + SecOpsError: If the rule is not found + """ + return _get_curated_rule_by_name(self, display_name) + def get_curated_rule_set_category(self, category_id: str) -> Dict[str, Any]: """Get a curated rule set category by ID. diff --git a/src/secops/chronicle/rule_set.py b/src/secops/chronicle/rule_set.py index bc7e38bb..3a9d4f57 100644 --- a/src/secops/chronicle/rule_set.py +++ b/src/secops/chronicle/rule_set.py @@ -235,6 +235,32 @@ def get_curated_rule(client, rule_id: str) -> Dict[str, Any]: return response.json() +def get_curated_rule_by_name( + client, display_name: str +) -> Dict[str, Any]: + """Get a curated rule by display name + + Args: + client: ChronicleClient instance + display_name: Display name of the curated rule + + Returns: + Dictionary containing the curated rule + + Raises: + APIError: If the API request fails + """ + rule = None + for r in list_curated_rules(client): + if r.get("displayName", "").lower() == display_name.lower(): + rule = r + break + if not rule: + raise SecOpsError(f"Rule with name '{display_name}' not found") + + return rule + + def list_curated_rule_set_deployments( client, page_size: Optional[str] = None, @@ -349,14 +375,14 @@ def get_curated_rule_set_deployment( def get_curated_rule_set_deployment_by_name( client, - rule_set_name: str, + display_name: str, precision: str = "precise", ) -> Dict[str, Any]: """Get the deployment status of a curated rule set by its display name Args: client: ChronicleClient instance - rule_set_name: Display name of the curated rule set (case-insensitive) + display_name: Display name of the curated rule set (case-insensitive) precision: Precision level ("precise" or "broad") Returns: @@ -372,13 +398,12 @@ def get_curated_rule_set_deployment_by_name( rule_set = None for rs in list_curated_rule_sets(client): # Names normalised as lowercase - current_name = rs.get("displayName", "").lower() - if current_name == rule_set_name.lower(): + if rs.get("displayName", "").lower() == display_name.lower(): rule_set = rs break if not rule_set: - raise SecOpsError(f"Rule set with name '{rule_set_name}' not found") + raise SecOpsError(f"Rule set with name '{display_name}' not found") # Extract the rule set ID from the resource name name_parts = rule_set["name"].split("/") From 837df6f0d3e879e7084f12396944bd88e72b864f Mon Sep 17 00:00:00 2001 From: PaperMtn Date: Fri, 24 Oct 2025 21:38:00 +0100 Subject: [PATCH 13/30] feat: added patching a rule set deployment --- api_module_mapping.md | 2 +- src/secops/chronicle/__init__.py | 2 + src/secops/chronicle/client.py | 28 ++++++++++++- src/secops/chronicle/rule_set.py | 68 ++++++++++++++++++++++++++++++-- 4 files changed, 95 insertions(+), 5 deletions(-) diff --git a/api_module_mapping.md b/api_module_mapping.md index 6b515749..cc8a3c5d 100644 --- a/api_module_mapping.md +++ b/api_module_mapping.md @@ -86,7 +86,7 @@ wrapper module and its respective CLI command (if available). | bigQueryExport.provision | v1alpha | | | | cases.countPriorities | v1alpha | | | | curatedRuleSetCategories.curatedRuleSets.curatedRuleSetDeployments.batchUpdate | v1alpha | chronicle.rule_set.batch_update_curated_rule_set_deployments | | -| curatedRuleSetCategories.curatedRuleSets.curatedRuleSetDeployments.patch | v1alpha | | | +| curatedRuleSetCategories.curatedRuleSets.curatedRuleSetDeployments.patch | v1alpha | chronicle.rule_set.patch_curated_rule_set_deployment | | | curatedRuleSetCategories.curatedRuleSets.curatedRuleSetDeployments.list | v1alpha | chronicle.rule_set.list_curated_rule_set_deployments | | | curatedRuleSetCategories.curatedRuleSets.curatedRuleSetDeployments.get | v1alpha | chronicle.rule_set.get_curated_rule_set_deployment
chronicle.rule_set.get_curated_rule_set_deployment_by_name | | | curatedRuleSetCategories.curatedRuleSets.get | v1alpha | chronicle.rule_set.get_curated_rule_set | | diff --git a/src/secops/chronicle/__init__.py b/src/secops/chronicle/__init__.py index e95fee47..e312e42b 100644 --- a/src/secops/chronicle/__init__.py +++ b/src/secops/chronicle/__init__.py @@ -144,6 +144,7 @@ get_curated_rule_set_deployment, get_curated_rule_set_deployment_by_name, get_curated_rule_by_name, + patch_curated_rule_set_deployment, ) from secops.chronicle.rule_validation import ValidationResult from secops.chronicle.search import search_udm @@ -250,6 +251,7 @@ "get_curated_rule_set_deployment", "get_curated_rule_set_deployment_by_name", "get_curated_rule_by_name", + "patch_curated_rule_set_deployment", # Native Dashboard "add_chart", "create_dashboard", diff --git a/src/secops/chronicle/client.py b/src/secops/chronicle/client.py index ffa36acb..2c884d15 100644 --- a/src/secops/chronicle/client.py +++ b/src/secops/chronicle/client.py @@ -232,6 +232,7 @@ get_curated_rule_set_deployment as _get_curated_rule_set_deployment, get_curated_rule_set_deployment_by_name as _get_curated_rule_set_deployment_by_name, get_curated_rule_by_name as _get_curated_rule_by_name, + patch_curated_rule_set_deployment as _patch_curated_rule_set_deployment, ) from secops.chronicle.rule_validation import validate_rule as _validate_rule from secops.chronicle.search import search_udm as _search_udm @@ -1841,7 +1842,9 @@ def get_curated_rule_set_deployment_by_name( APIError: If the API request fails SecOpsError: If the rule set is not found or precision is invalid """ - return _get_curated_rule_set_deployment_by_name(self, display_name, precision) + return _get_curated_rule_set_deployment_by_name( + self, display_name, precision + ) def list_curated_rules( self, @@ -1891,6 +1894,29 @@ def get_curated_rule_by_name(self, display_name: str) -> Dict[str, Any]: """ return _get_curated_rule_by_name(self, display_name) + def patch_curated_rule_set_deployment( + self, deployment: Dict[str, Any] + ) -> Dict[str, Any]: + """Update a curated rule set deployment to enable or disable + alerting or change precision. + + Args: + deployment: Dict of deployment configuration containing: + - category_id: UUID of the category + - rule_set_id: UUID of the rule set + - precision: Precision level either "broad" or "precise" + - enabled: Whether the rule set should be enabled + - alerting: Whether alerting should be enabled for the rule set + + Returns: + Dictionary containing the updated curated rule set deployment + + Raises: + APIError: If the API request fails + SecOpsError: If the rule set is not found or precision is invalid + """ + return _patch_curated_rule_set_deployment(self, deployment) + def get_curated_rule_set_category(self, category_id: str) -> Dict[str, Any]: """Get a curated rule set category by ID. diff --git a/src/secops/chronicle/rule_set.py b/src/secops/chronicle/rule_set.py index 3a9d4f57..94a200c1 100644 --- a/src/secops/chronicle/rule_set.py +++ b/src/secops/chronicle/rule_set.py @@ -235,9 +235,7 @@ def get_curated_rule(client, rule_id: str) -> Dict[str, Any]: return response.json() -def get_curated_rule_by_name( - client, display_name: str -) -> Dict[str, Any]: +def get_curated_rule_by_name(client, display_name: str) -> Dict[str, Any]: """Get a curated rule by display name Args: @@ -413,6 +411,70 @@ def get_curated_rule_set_deployment_by_name( return get_curated_rule_set_deployment(client, rule_set_id, precision) +def patch_curated_rule_set_deployment( + client, deployment: Dict[str, Any] +) -> Dict[str, Any]: + """Update a curated rule set deployment to enable or disable + alerting or change precision. + + Args: + client: ChronicleClient instance + deployment: Dict of deployment configuration containing: + - category_id: UUID of the category + - rule_set_id: UUID of the rule set + - precision: Precision level either "broad" or "precise" + - enabled: Whether the rule set should be enabled + - alerting: Whether alerting should be enabled for the rule set + + Returns: + Dictionary containing the updated curated rule set deployment + + Raises: + APIError: If the API request fails + SecOpsError: If the rule set is not found or precision is invalid + """ + # Check required fields + required_fields = ["category_id", "rule_set_id", "precision", "enabled"] + missing_fields = [ + field for field in required_fields if field not in deployment + ] + + if missing_fields: + raise ValueError( + f"Deployment missing required fields: {missing_fields}" + ) + + # Get deployment configuration + category_id = deployment["category_id"] + rule_set_id = deployment["rule_set_id"] + precision = deployment["precision"] + enabled = deployment["enabled"] + alerting = deployment.get("alerting", False) + + deployment_name = ( + f"{client.instance_id}/curatedRuleSetCategories/{category_id}" + f"/curatedRuleSets/{rule_set_id}" + f"/curatedRuleSetDeployments/{precision}" + ) + + deployment = { + "name": deployment_name, + "precision": precision, + "enabled": enabled, + "alerting": alerting, + } + + url = f"{client.base_url}/{deployment_name}" + + response = client.session.patch(url, json=deployment) + if response.status_code != 200: + raise APIError( + f"Failed to patch curated rule set deployment: {response.text}" + ) + + return response.json() + + def batch_update_curated_rule_set_deployments( client, deployments: List[Dict[str, Any]] ) -> Dict[str, Any]: From c7a86c81d175285b59bc88e7272d21148d1e4931 Mon Sep 17 00:00:00 2001 From: PaperMtn Date: Fri, 24 Oct 2025 21:41:49 +0100 Subject: [PATCH 14/30] refactor: make function names consistent --- src/secops/chronicle/client.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/secops/chronicle/client.py b/src/secops/chronicle/client.py index 2c884d15..0d7eeaf1 100644 --- a/src/secops/chronicle/client.py +++ b/src/secops/chronicle/client.py @@ -1742,7 +1742,7 @@ def batch_update_curated_rule_set_deployments( """ return _batch_update_curated_rule_set_deployments(self, deployments) - def list_rule_sets( + def list_curated_rule_sets( self, page_size: Optional[str] = None, page_token: Optional[str] = None, @@ -1761,7 +1761,7 @@ def list_rule_sets( """ return _list_curated_rule_sets(self, page_size, page_token) - def list_rule_set_categories( + def list_curated_rule_set_categories( self, page_size: Optional[str] = None, page_token: Optional[str] = None, From f119877d08d499eec32d467ee62363ad9423f049 Mon Sep 17 00:00:00 2001 From: PaperMtn Date: Fri, 24 Oct 2025 21:51:04 +0100 Subject: [PATCH 15/30] refactor: make function names consistent --- src/secops/chronicle/client.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/secops/chronicle/client.py b/src/secops/chronicle/client.py index 0d7eeaf1..d11b3cbd 100644 --- a/src/secops/chronicle/client.py +++ b/src/secops/chronicle/client.py @@ -232,7 +232,7 @@ get_curated_rule_set_deployment as _get_curated_rule_set_deployment, get_curated_rule_set_deployment_by_name as _get_curated_rule_set_deployment_by_name, get_curated_rule_by_name as _get_curated_rule_by_name, - patch_curated_rule_set_deployment as _patch_curated_rule_set_deployment, + update_curated_rule_set_deployment as _update_curated_rule_set_deployment, ) from secops.chronicle.rule_validation import validate_rule as _validate_rule from secops.chronicle.search import search_udm as _search_udm @@ -1915,7 +1915,7 @@ def patch_curated_rule_set_deployment( APIError: If the API request fails SecOpsError: If the rule set is not found or precision is invalid """ - return _patch_curated_rule_set_deployment(self, deployment) + return _update_curated_rule_set_deployment(self, deployment) def get_curated_rule_set_category(self, category_id: str) -> Dict[str, Any]: """Get a curated rule set category by ID. From 1be86c64a00842fea488306ad2184a0a215fe9e4 Mon Sep 17 00:00:00 2001 From: PaperMtn Date: Fri, 24 Oct 2025 21:51:36 +0100 Subject: [PATCH 16/30] refactor: make function names consistent --- api_module_mapping.md | 2 +- src/secops/chronicle/__init__.py | 4 ++-- src/secops/chronicle/rule_set.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/api_module_mapping.md b/api_module_mapping.md index cc8a3c5d..cac9ef97 100644 --- a/api_module_mapping.md +++ b/api_module_mapping.md @@ -86,7 +86,7 @@ wrapper module and its respective CLI command (if available). | bigQueryExport.provision | v1alpha | | | | cases.countPriorities | v1alpha | | | | curatedRuleSetCategories.curatedRuleSets.curatedRuleSetDeployments.batchUpdate | v1alpha | chronicle.rule_set.batch_update_curated_rule_set_deployments | | -| curatedRuleSetCategories.curatedRuleSets.curatedRuleSetDeployments.patch | v1alpha | chronicle.rule_set.patch_curated_rule_set_deployment | | +| curatedRuleSetCategories.curatedRuleSets.curatedRuleSetDeployments.patch | v1alpha | chronicle.rule_set.update_curated_rule_set_deployment | | | curatedRuleSetCategories.curatedRuleSets.curatedRuleSetDeployments.list | v1alpha | chronicle.rule_set.list_curated_rule_set_deployments | | | curatedRuleSetCategories.curatedRuleSets.curatedRuleSetDeployments.get | v1alpha | chronicle.rule_set.get_curated_rule_set_deployment
chronicle.rule_set.get_curated_rule_set_deployment_by_name | | | curatedRuleSetCategories.curatedRuleSets.get | v1alpha | chronicle.rule_set.get_curated_rule_set | | diff --git a/src/secops/chronicle/__init__.py b/src/secops/chronicle/__init__.py index e312e42b..caad032c 100644 --- a/src/secops/chronicle/__init__.py +++ b/src/secops/chronicle/__init__.py @@ -144,7 +144,7 @@ get_curated_rule_set_deployment, get_curated_rule_set_deployment_by_name, get_curated_rule_by_name, - patch_curated_rule_set_deployment, + update_curated_rule_set_deployment, ) from secops.chronicle.rule_validation import ValidationResult from secops.chronicle.search import search_udm @@ -251,7 +251,7 @@ "get_curated_rule_set_deployment", "get_curated_rule_set_deployment_by_name", "get_curated_rule_by_name", - "patch_curated_rule_set_deployment", + "update_curated_rule_set_deployment", # Native Dashboard "add_chart", "create_dashboard", diff --git a/src/secops/chronicle/rule_set.py b/src/secops/chronicle/rule_set.py index 94a200c1..80a68594 100644 --- a/src/secops/chronicle/rule_set.py +++ b/src/secops/chronicle/rule_set.py @@ -411,7 +411,7 @@ def get_curated_rule_set_deployment_by_name( return get_curated_rule_set_deployment(client, rule_set_id, precision) -def patch_curated_rule_set_deployment( +def update_curated_rule_set_deployment( client, deployment: Dict[str, Any] ) -> Dict[str, Any]: """Update a curated rule set deployment to enable or disable From 227cbed6beb3b6576cd76768819b069e3b39fcc7 Mon Sep 17 00:00:00 2001 From: PaperMtn Date: Sat, 25 Oct 2025 20:41:41 +0100 Subject: [PATCH 17/30] docs: update README with curated rule set actions --- README.md | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 83 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b0302910..aa0874ee 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +from docutils.nodes import description + # Google SecOps SDK for Python [![PyPI version](https://img.shields.io/pypi/v/secops.svg)](https://pypi.org/project/secops/) @@ -1671,11 +1673,80 @@ for rule_alert in alerts_response.get('ruleAlerts', []): If `tooManyAlerts` is True in the response, consider narrowing your search criteria using a smaller time window or more specific filters. -### Rule Sets +### Curated Rule Sets + +Query curated rules: + +```python +# List all curated rules +rules = chronicle.list_curated_rules() +for rule in rules: + rule_id = rule.get("name", "").split("/")[-1] + display_name = rule.get("description") + description = rule.get("description") + print(f"Rule: {display_name}, Description: {description}") + +# Get a curated rule +rule = chronicle.get_curated_rule("ur_ttp_lol_Atbroker") + +# Get a curated rule set by display name +rule_set = chronicle.get_curated_rule_by_name("Atbroker.exe Abuse") +``` + +Query curated rule sets: + +```python +# List all curated rule sets +rule_sets = chronicle.list_curated_rule_sets() +for rule_set in rule_sets: + rule_set_id = rule_set.get("name", "").split("/")[-1] + display_name = rule_set.get("displayName") + print(f"Rule Set: {display_name}, ID: {rule_set_id}") + +# Get a curated rule set by ID +rule_set = chronicle.get_curated_rule_set("00ad672e-ebb3-0dd1-2a4d-99bd7c5e5f93") +``` + +Query curated rule set categories: + +```python +# List all curated rule set categories +rule_set_categories = chronicle.list_curated_rule_set_categories() +for rule_set_category in rule_set_categories: + rule_set_category_id = rule_set_category.get("name", "").split("/")[-1] + display_name = rule_set_category.get("displayName") + print(f"Rule Set Category: {display_name}, ID: {rule_set_category_id}") -Manage curated rule sets: +# Get a curated rule set category by ID +rule_set_category = chronicle.get_curated_rule_set_category("110fa43d-7165-2355-1985-a63b7cdf90e8") +``` + +Manage curated rule set deployments (turn alerting on or off (either precise or broad) for curated rule sets): ```python +# List all curated rule set deployments +rule_set_deployments = chronicle.list_curated_rule_set_deployments() +for rs_deployment in rule_set_deployments: + rule_set_id = rs_deployment.get("name", "").split("/")[-3] + category_id = rs_deployment.get("name", "").split("/")[-5] + deployment_status = rs_deployment.get("name", "").split("/")[-1] + display_name = rs_deployment.get("displayName") + alerting = rs_deployment.get("alerting", False) + print( + f"Rule Set: {display_name}," + f"Rule Set ID: {rule_set_id}", + f"Category ID: {category_id}", + f"Precision: {deployment_status}", + f"Alerting: {alerting}", + ) + +# Get curated rule set deployment by ID +rule_set_deployment = chronicle.get_curated_rule_set_deployment("00ad672e-ebb3-0dd1-2a4d-99bd7c5e5f93") + +# Get curated rule set deployment by rule set display name +rule_set_deployment = chronicle.get_curated_rule_set_deployment_by_name("Azure - Network") + +# Update multiple curated rule set deployments # Define deployments for rule sets deployments = [ { @@ -1687,8 +1758,17 @@ deployments = [ } ] -# Update rule set deployments chronicle.batch_update_curated_rule_set_deployments(deployments) + +# Update a single curated rule set deployment +chronicle.update_curated_rule_set_deployment( + category_id="category-uuid", + rule_set_id="ruleset-uuid", + precision="broad", + enabled=True, + alerting=False +) + ``` ### Rule Validation From 6d41f8fa5f1808d65aa4c38a2b2c4777a7520e9a Mon Sep 17 00:00:00 2001 From: PaperMtn Date: Sun, 26 Oct 2025 19:46:36 +0000 Subject: [PATCH 18/30] feat: added tests for rule_set module --- tests/chronicle/test_rule_set.py | 596 +++++++++++++++++++++++++++++++ 1 file changed, 596 insertions(+) create mode 100644 tests/chronicle/test_rule_set.py diff --git a/tests/chronicle/test_rule_set.py b/tests/chronicle/test_rule_set.py new file mode 100644 index 00000000..36779c7a --- /dev/null +++ b/tests/chronicle/test_rule_set.py @@ -0,0 +1,596 @@ +# 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 curated rule set functions.""" + +import pytest +from unittest.mock import Mock, patch +from secops.chronicle.client import ChronicleClient +from secops.chronicle.rule_set import ( + _paginated_request, + get_curated_rule, + list_curated_rules, + get_curated_rule_by_name, + get_curated_rule_set, + get_curated_rule_set_category, + list_curated_rule_sets, + list_curated_rule_set_categories, + list_curated_rule_set_deployments, + get_curated_rule_set_deployment, + get_curated_rule_set_deployment_by_name, + update_curated_rule_set_deployment, + batch_update_curated_rule_set_deployments, +) +from secops.exceptions import APIError, SecOpsError + + +@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" + ) + + +@pytest.fixture +def mock_response(): + """Create a mock API response object.""" + mock = Mock() + mock.status_code = 200 + # Default return value, can be overridden in specific tests + mock.json.return_value = {} + return mock + + +@pytest.fixture +def mock_error_response(): + """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" + ) # To simulate requests.exceptions.HTTPError + return mock + + +# --- get_curated_rule tests --- +def test_get_curated_rule_success(chronicle_client, mock_response): + """Test get_curated_rule returns the JSON for a curated rule when the request succeeds.""" + mock_response.json.return_value = { + "name": "projects/test-project/locations/us/curatedRules/ur_abc-123", + "displayName": "Test ABC 123", + } + with patch.object( + chronicle_client.session, "get", return_value=mock_response + ) as mocked_request: + result = get_curated_rule(chronicle_client, "ur_abc-123") + assert result == mock_response.json.return_value + # Verify URL + expected_url = ( + f"{chronicle_client.base_url}/{chronicle_client.instance_id}/" + f"curatedRules/ur_abc-123" + ) + mocked_request.assert_called_once_with(expected_url) + + +def test_get_curated_rule_error(chronicle_client, mock_error_response): + """Test get_curated_rule raises APIError when the API returns non-200.""" + # Arrange + with patch.object( + chronicle_client.session, "get", return_value=mock_error_response + ): + # Act and Assert + with pytest.raises(APIError): + get_curated_rule(chronicle_client, "ur_abc-123") + + +# --- helpers --- + + +def _page(items_key: str, items: list[dict], next_token: str | None = None): + """Helper function for paginated 200 OK responses.""" + data = {items_key: items} + if next_token: + data["nextPageToken"] = next_token + resp = Mock() + resp.status_code = 200 + resp.json.return_value = data + return resp + + +# --- _paginated_request tests --- + + +def test_paginated_request_success(chronicle_client): + """Test helper function _paginated_request returns a flat list from multiple pages and forwards pageToken.""" + p1 = _page("curatedRules", [{"name": ".../ur_1"}], next_token="t2") + p2 = _page("curatedRules", [{"name": ".../ur_2"}]) + with patch.object( + chronicle_client.session, "get", side_effect=[p1, p2] + ) as mocked_response: + result = _paginated_request( + chronicle_client, + path="curatedRules", + items_key="curatedRules", + page_size=1000, + ) + assert [r["name"] for r in result] == [".../ur_1", ".../ur_2"] + + base = f"{chronicle_client.base_url}/{chronicle_client.instance_id}/curatedRules" + # first call: only pageSize + assert mocked_response.call_args_list[0].args[0] == base + assert mocked_response.call_args_list[0].kwargs["params"] == { + "pageSize": 1000 + } + # second call includes next token + assert mocked_response.call_args_list[1].kwargs["params"] == { + "pageSize": 1000, + "pageToken": "t2", + } + + +def test_paginated_request_error(chronicle_client, mock_error_response): + """Test helper function _paginated_request raises APIError on HTTP errors.""" + with patch.object( + chronicle_client.session, "get", return_value=mock_error_response + ): + with pytest.raises(APIError): + _paginated_request( + chronicle_client, + path="curatedRules", + items_key="curatedRules", + ) + + +# --- list_curated_rule_sets & list_curated_rule_set_categories function tests --- +def test_list_curated_rules_success(chronicle_client, mock_response): + """Test list_curated_rules""" + mock_response.json.return_value = {"curatedRules": [{"name": "n1"}]} + with patch.object( + chronicle_client.session, "get", return_value=mock_response + ): + rules = list_curated_rules(chronicle_client, page_size=50) + assert rules == [{"name": "n1"}] + + +def test_list_curated_rules_error(chronicle_client, mock_error_response): + """Test list_curated_rules failure.""" + with patch.object( + chronicle_client.session, "get", return_value=mock_error_response + ): + with pytest.raises(APIError): + list_curated_rules(chronicle_client) + + +def test_list_curated_rule_sets_and_categories_success( + chronicle_client, mock_response +): + """Test the two list_ functions.""" + mock_response.json.side_effect = [ + {"curatedRuleSets": [{"name": "rs1"}]}, + {"curatedRuleSetCategories": [{"name": "cat1"}]}, + ] + with patch.object( + chronicle_client.session, "get", return_value=mock_response + ) as mocked_response: + rule_sets = list_curated_rule_sets(chronicle_client) + categories = list_curated_rule_set_categories(chronicle_client) + assert rule_sets == [{"name": "rs1"}] + assert categories == [{"name": "cat1"}] + # ensure two calls happened + assert mocked_response.call_count == 2 + + +def test_list_curated_rule_sets_and_categories_error( + chronicle_client, mock_error_response +): + """Test the two list_ functions error correctly.""" + with patch.object( + chronicle_client.session, "get", return_value=mock_error_response + ): + with pytest.raises(APIError): + list_curated_rule_sets(chronicle_client) + list_curated_rule_set_categories(chronicle_client) + + +# --- get_curated_rule_by_name tests--- + + +def test_get_curated_rule_by_name_success(chronicle_client): + """Test get_curated_rule_by_name returns the rule matching displayName (case-insensitive).""" + p = _page( + "curatedRules", + [ + {"displayName": "Alpha", "name": ".../ur_A"}, + {"displayName": "Bravo", "name": ".../ur_B"}, + ], + ) + with patch.object(chronicle_client.session, "get", return_value=p): + out = get_curated_rule_by_name(chronicle_client, "bravo") + assert out["name"].endswith("ur_B") + + +def test_get_curated_rule_by_name_error(chronicle_client): + """Test get_curated_rule_by_name raises SecOpsError when not found.""" + p = _page("curatedRules", [{"displayName": "Alpha"}]) + with patch.object(chronicle_client.session, "get", return_value=p): + with pytest.raises(SecOpsError): + get_curated_rule_by_name(chronicle_client, "charlie") + + +# --- get_curated_rule_set tests --- + + +def test_get_curated_rule_set_success(chronicle_client, mock_response): + """Test get_curated_rule_set returns the rule set matching name.""" + mock_response.json.return_value = {"name": ".../curatedRuleSets/crs_1"} + with patch.object( + chronicle_client.session, "get", return_value=mock_response + ) as get_: + out = get_curated_rule_set(chronicle_client, "crs_1") + assert out["name"].endswith("/crs_1") + expected = ( + f"{chronicle_client.base_url}/{chronicle_client.instance_id}/" + "curatedRuleSetCategories/-/curatedRuleSets/crs_1" + ) + get_.assert_called_once() + assert get_.call_args.args[0] == expected + + +def test_get_curated_rule_set_error(chronicle_client, mock_error_response): + """Test get_curated_rule_set raises APIError on HTTP errors.""" + with patch.object( + chronicle_client.session, "get", return_value=mock_error_response + ): + with pytest.raises(APIError): + get_curated_rule_set(chronicle_client, "crs_1") + + +# --- get_curated_rule_set_category tests --- +def test_get_curated_rule_set_category_success(chronicle_client, mock_response): + mock_response.json.return_value = { + "name": ".../curatedRuleSetCategories/cat_1" + } + with patch.object( + chronicle_client.session, "get", return_value=mock_response + ) as get_: + out = get_curated_rule_set_category(chronicle_client, "cat_1") + assert out["name"].endswith("/cat_1") + expected = ( + f"{chronicle_client.base_url}/{chronicle_client.instance_id}/" + "curatedRuleSetCategories/cat_1" + ) + assert get_.call_args.args[0] == expected + + +def test_get_curated_rule_set_category_error( + chronicle_client, mock_error_response +): + with patch.object( + chronicle_client.session, "get", return_value=mock_error_response + ): + with pytest.raises(APIError): + get_curated_rule_set_category(chronicle_client, "cat_1") + + +# --- list_curated_rule_set_deployments --- + + +def test_list_deployments_success(chronicle_client): + """Test list_curated_rule_set_deployments enriches deployments with displayName and respects filters.""" + deployments_page = _page( + "curatedRuleSetDeployments", + [ + { + "name": f"{chronicle_client.instance_id}/curatedRuleSetCategories/c1/curatedRuleSets/crs_1/curatedRuleSetDeployments/precise", + "enabled": True, + "alerting": False, + }, + { + "name": f"{chronicle_client.instance_id}/curatedRuleSetCategories/c1/curatedRuleSets/crs_2/curatedRuleSetDeployments/broad", + "enabled": False, + "alerting": True, + }, + ], + ) + rulesets_page = _page( + "curatedRuleSets", + [ + { + "name": f"{chronicle_client.instance_id}/curatedRuleSetCategories/c1/curatedRuleSets/crs_1", + "displayName": "One", + }, + { + "name": f"{chronicle_client.instance_id}/curatedRuleSetCategories/c1/curatedRuleSets/crs_2", + "displayName": "Two", + }, + ], + ) + + # First: list deployments & list rulesets for enrichment + with patch.object( + chronicle_client.session, + "get", + side_effect=[deployments_page, rulesets_page], + ): + out = list_curated_rule_set_deployments(chronicle_client) + names = {d["displayName"] for d in out} + assert names == {"One", "Two"} + + # Now verify only_enabled and only_alerting filters + with patch.object( + chronicle_client.session, + "get", + side_effect=[deployments_page, rulesets_page], + ): + out_enabled = list_curated_rule_set_deployments( + chronicle_client, only_enabled=True + ) + assert len(out_enabled) == 1 and out_enabled[0]["displayName"] == "One" + + with patch.object( + chronicle_client.session, + "get", + side_effect=[deployments_page, rulesets_page], + ): + out_alerting = list_curated_rule_set_deployments( + chronicle_client, only_alerting=True + ) + assert ( + len(out_alerting) == 1 and out_alerting[0]["displayName"] == "Two" + ) + + +# --- get_curated_rule_set_deployment --- + + +def test_get_ruleset_deployment_success(chronicle_client, mock_response): + """Test get_curated_rule_set_deployment returns the deployment matching name.""" + rulesets = _page( + "curatedRuleSets", + [ + { + "name": f"{chronicle_client.instance_id}/curatedRuleSetCategories/c1/curatedRuleSets/crs_1", + "displayName": "My Ruleset", + } + ], + ) + deployment = Mock() + deployment.status_code = 200 + deployment.json.return_value = {"enabled": True, "alerting": False} + + with patch.object( + chronicle_client.session, "get", side_effect=[rulesets, deployment] + ) as mocked_request: + out = get_curated_rule_set_deployment( + chronicle_client, "crs_1", "precise" + ) + assert out["displayName"] == "My Ruleset" + # Second GET is the deployment URL + dep_url = ( + f"{chronicle_client.base_url}/" + f"{chronicle_client.instance_id}/curatedRuleSetCategories/c1/curatedRuleSets/crs_1/" + "curatedRuleSetDeployments/precise" + ) + assert mocked_request.call_args_list[1].args[0] == dep_url + + +def test_get_ruleset_deployment_error_invalid_precision(chronicle_client): + """Test get_curated_rule_set_deployment failure.""" + with pytest.raises(SecOpsError): + get_curated_rule_set_deployment(chronicle_client, "crs_1", "medium") + + +def test_get_ruleset_deployment_ruleset_error_not_found(chronicle_client): + """Test get_curated_rule_set_deployment failure.""" + empty_rulesets = _page("curatedRuleSets", []) + with patch.object( + chronicle_client.session, "get", return_value=empty_rulesets + ): + with pytest.raises(SecOpsError): + get_curated_rule_set_deployment( + chronicle_client, "crs_404", "precise" + ) + + +# --- get_curated_rule_set_deployment_by_name --- + + +def test_get_ruleset_deployment_by_name_success(chronicle_client): + """Test get_curated_rule_set_deployment_by_name success.""" + rulesets_data = [ + { + "name": f"{chronicle_client.instance_id}/curatedRuleSetCategories/c1/curatedRuleSets/crs_1", + "displayName": "Case Insensitive Name", + } + ] + deployment = Mock() + deployment.status_code = 200 + deployment.json.return_value = {"enabled": True} + + with patch( + "secops.chronicle.rule_set.list_curated_rule_sets", + return_value=rulesets_data, + ): + with patch.object( + chronicle_client.session, "get", return_value=deployment + ): + out = get_curated_rule_set_deployment_by_name( + chronicle_client, "case insensitive name", "broad" + ) + assert out["enabled"] is True + + +def test_get_ruleset_deployment_by_name_error(chronicle_client): + """Test get_curated_rule_set_deployment_by_name failure.""" + rulesets = _page("curatedRuleSets", [{"displayName": "Other"}]) + with patch.object(chronicle_client.session, "get", return_value=rulesets): + with pytest.raises(SecOpsError): + get_curated_rule_set_deployment_by_name(chronicle_client, "missing") + + +# --- update_curated_rule_set_deployment --- + + +def test_update_ruleset_deployment_success( + chronicle_client, +): + """Test update_curated_rule_set_deployment builds the correct PATCH payload and URL.""" + patch_resp = Mock() + patch_resp.status_code = 200 + patch_resp.json.return_value = {"ok": True} + with patch.object( + chronicle_client.session, "patch", return_value=patch_resp + ) as mocked_request: + out = update_curated_rule_set_deployment( + chronicle_client, + { + "category_id": "c1", + "rule_set_id": "crs_1", + "precision": "precise", + "enabled": True, + "alerting": False, + }, + ) + assert out == {"ok": True} + name = ( + f"{chronicle_client.instance_id}/curatedRuleSetCategories/c1/" + "curatedRuleSets/crs_1/curatedRuleSetDeployments/precise" + ) + expected_url = f"{chronicle_client.base_url}/{name}" + mocked_request.assert_called_once() + assert mocked_request.call_args.args[0] == expected_url + assert mocked_request.call_args.kwargs["json"] == { + "name": name, + "precision": "precise", + "enabled": True, + "alerting": False, + } + + +def test_update_ruleset_deployment_error_missing_fields(chronicle_client): + """Test update_curated_rule_set_deployment failure.""" + with pytest.raises(ValueError): + update_curated_rule_set_deployment( + chronicle_client, + { + "category_id": "c1", + # 'rule_set_id' missing + "precision": "precise", + "enabled": True, + }, + ) + + +def test_update_ruleset_deployment_error_http( + chronicle_client, mock_error_response +): + """Test update_curated_rule_set_deployment failure.""" + with patch.object( + chronicle_client.session, "patch", return_value=mock_error_response + ): + with pytest.raises(APIError): + update_curated_rule_set_deployment( + chronicle_client, + { + "category_id": "c1", + "rule_set_id": "crs_1", + "precision": "precise", + "enabled": True, + }, + ) + + +# --- batch_update_curated_rule_set_deployments --- + + +def test_batch_update_curated_rule_set_success(chronicle_client): + """Test batch_update_curated_rule_set_deployments success.""" + post_resp = Mock() + post_resp.status_code = 200 + post_resp.json.return_value = {"status": "ok"} + with patch.object( + chronicle_client.session, "post", return_value=post_resp + ) as post_: + out = batch_update_curated_rule_set_deployments( + chronicle_client, + [ + { + "category_id": "c1", + "rule_set_id": "r1", + "precision": "precise", + "enabled": True, + "alerting": True, + }, + { + "category_id": "c2", + "rule_set_id": "r2", + "precision": "broad", + "enabled": False, + }, + ], + ) + assert out == {"status": "ok"} + + # Inspect payload + payload = post_.call_args.kwargs["json"] + assert payload["parent"].startswith( + chronicle_client.instance_id + "/curatedRuleSetCategories/-" + ) + reqs = payload["requests"] + assert len(reqs) == 2 + assert reqs[0]["curated_rule_set_deployment"]["enabled"] is True + assert reqs[0]["curated_rule_set_deployment"]["alerting"] is True + assert reqs[0]["update_mask"]["paths"] == ["alerting", "enabled"] + + +def test_batch_update_curated_rule_set_error_missing_fields(chronicle_client): + """Test batch_update_curated_rule_set_deployments failure.""" + with pytest.raises(ValueError): + batch_update_curated_rule_set_deployments( + chronicle_client, + [ + { + "category_id": "c1", + "precision": "precise", + "enabled": True, + }, # rule_set_id missing + ], + ) + + +def test_batch_update_curated_rule_set_error_http( + chronicle_client, mock_error_response +): + """Test batch_update_curated_rule_set_deployments failure.""" + with patch.object( + chronicle_client.session, "post", return_value=mock_error_response + ): + with pytest.raises(APIError): + batch_update_curated_rule_set_deployments( + chronicle_client, + [ + { + "category_id": "c1", + "rule_set_id": "r1", + "precision": "precise", + "enabled": True, + }, + ], + ) From b442e32727bb898883827ad79f3e9b7bb0b487f9 Mon Sep 17 00:00:00 2001 From: PaperMtn Date: Sun, 26 Oct 2025 20:07:27 +0000 Subject: [PATCH 19/30] fix: fix f-string quote error --- src/secops/chronicle/rule_set.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/secops/chronicle/rule_set.py b/src/secops/chronicle/rule_set.py index 80a68594..07f41bc6 100644 --- a/src/secops/chronicle/rule_set.py +++ b/src/secops/chronicle/rule_set.py @@ -354,7 +354,7 @@ def get_curated_rule_set_deployment( raise SecOpsError(f"Rule set {rule_set_id} not found") url = ( - f"{client.base_url}/{rule_set.get("name", "")}/" + f"{client.base_url}/{rule_set.get('name', '')}/" f"curatedRuleSetDeployments/{precision}" ) From 670408ea4f9f1cbcc1fd920fa8e611d5eba5fb71 Mon Sep 17 00:00:00 2001 From: PaperMtn Date: Sun, 26 Oct 2025 20:37:18 +0000 Subject: [PATCH 20/30] fix: Remove typing syntax incompatible with Python 3.9 --- tests/chronicle/test_rule_set.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/chronicle/test_rule_set.py b/tests/chronicle/test_rule_set.py index 36779c7a..5786dc49 100644 --- a/tests/chronicle/test_rule_set.py +++ b/tests/chronicle/test_rule_set.py @@ -15,6 +15,7 @@ """Tests for Chronicle curated rule set functions.""" import pytest +from typing import Optional from unittest.mock import Mock, patch from secops.chronicle.client import ChronicleClient from secops.chronicle.rule_set import ( @@ -103,7 +104,7 @@ def test_get_curated_rule_error(chronicle_client, mock_error_response): # --- helpers --- -def _page(items_key: str, items: list[dict], next_token: str | None = None): +def _page(items_key: str, items: list[dict], next_token: Optional[str] = None): """Helper function for paginated 200 OK responses.""" data = {items_key: items} if next_token: From 1b26271fa7a1d21dcbca6240ed526b7de3771955 Mon Sep 17 00:00:00 2001 From: PaperMtn Date: Tue, 28 Oct 2025 20:12:29 +0000 Subject: [PATCH 21/30] refactor: Rename incorrectly named update function --- src/secops/chronicle/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/secops/chronicle/client.py b/src/secops/chronicle/client.py index d11b3cbd..b6518ba7 100644 --- a/src/secops/chronicle/client.py +++ b/src/secops/chronicle/client.py @@ -1894,7 +1894,7 @@ def get_curated_rule_by_name(self, display_name: str) -> Dict[str, Any]: """ return _get_curated_rule_by_name(self, display_name) - def patch_curated_rule_set_deployment( + def update_curated_rule_set_deployment( self, deployment: Dict[str, Any] ) -> Dict[str, Any]: """Update a curated rule set deployment to enable or disable From 6d60b46b1f8fb583879ca65815d51e10c8e4532e Mon Sep 17 00:00:00 2001 From: PaperMtn Date: Tue, 28 Oct 2025 21:16:27 +0000 Subject: [PATCH 22/30] feat: Added CLI support for curated rule actions --- CLI.md | 57 ++++ api_module_mapping.md | 750 +++++++++++++++++++++--------------------- src/secops/cli.py | 251 ++++++++++++++ 3 files changed, 683 insertions(+), 375 deletions(-) diff --git a/CLI.md b/CLI.md index 567093e9..76477df8 100644 --- a/CLI.md +++ b/CLI.md @@ -569,6 +569,63 @@ secops rule test --file "/path/to/rule.yaral" --time-window 24 > udm_events.json The `rule test` command outputs UDM events as pure JSON objects that can be piped to a file or processed by other tools. This makes it easy to integrate with other systems or perform additional analysis on the events. +### Curated Rule Set Management + +List all curated rules: +```bash +secops curated-rule rule list +``` +Get curated rules: +```bash +# Get rule by UUID +curated-rule rule get --id "ur_ttp_GCP_ServiceAPIDisable" + +# Get rule by name +curated-rule rule get --name "GCP Service API Disable" + +``` + +List all curated rule sets: +```bash +secops curated-rule rule-set list +``` + +Get specific curated rule set details: +```bash +# Get curated rule set by UUID +secops curated-rule rule-set get --id "f5533b66-9327-9880-93e6-75a738ac2345" +``` + +List all curated rule set categories: +```bash +secops curated-rule rule-set-category list +``` + +Get specific curated rule set category details: +```bash +# Get curated rule set category by UUID +secops curated-rule rule-set-category get --id "db1114d4-569b-5f5d-0fb4-f65aaa766c92" +``` + +List all curated rule set deployments: +```bash +secops curated-rule rule-set-deployment list +``` + +Get specific curated rule set deployment details: +```bash +# Get curated rule set deployment by UUID +secops curated-rule rule-set-deployment get --id "f5533b66-9327-9880-93e6-75a738ac2345" + +# Get curated rule set deployment by name +secops curated-rule rule-set-deployment get --name "Active Breach Priority Host Indicators" +``` + +Update curated rule set deployment: +```bash +secops curated-rule rule-set-deployment update --category-id "db1114d4-569b-5f5d-0fb4-f65aaa766c92" --rule-set-id "7e52cd71-03c6-97d2-ffcb-b8d7159e08e1" --precision precise --enabled false --alerting false +``` + ### Alert Management Get alerts: diff --git a/api_module_mapping.md b/api_module_mapping.md index cac9ef97..1c58479f 100644 --- a/api_module_mapping.md +++ b/api_module_mapping.md @@ -5,378 +5,378 @@ wrapper module and its respective CLI command (if available). **Note:** All the REST resources mentioned have suffix `projects.locations.instances`. -| REST Resource | Version | secops-wrapper module | CLI Command | -|--------------------------------------------------------------------------------|---------|-------------------------------------------------------------------------------------------------------------------|-----------------------------------------| -| dataAccessLabels.create | v1 | | | -| dataAccessLabels.delete | v1 | | | -| dataAccessLabels.get | v1 | | | -| dataAccessLabels.list | v1 | | | -| dataAccessLabels.patch | v1 | | | -| dataAccessScopes.create | v1 | | | -| dataAccessScopes.delete | v1 | | | -| dataAccessScopes.get | v1 | | | -| dataAccessScopes.list | v1 | | | -| dataAccessScopes.patch | v1 | | | -| get | v1 | | | -| operations.cancel | v1 | | | -| operations.delete | v1 | | | -| operations.get | v1 | | | -| operations.list | v1 | | | -| referenceLists.create | v1 | chronicle.reference_list.create_reference_list | secops reference-list create | -| referenceLists.get | v1 | chronicle.reference_list.get_reference_list | secops reference-list get | -| referenceLists.list | v1 | chronicle.reference_list.list_reference_lists | secops reference-list list | -| referenceLists.patch | v1 | chronicle.reference_list.update_reference_list | secops reference-list update | -| rules.create | v1 | chronicle.rule.create_rule | secops rule create | -| rules.delete | v1 | chronicle.rule.delete_rule | secops rule delete | -| rules.deployments.list | v1 | | | -| rules.get | v1 | chronicle.rule.get_rule | secops rule get | -| rules.getDeployment | v1 | | | -| rules.list | v1 | chronicle.rule.list_rules | secops rule list | -| rules.listRevisions | v1 | | | -| rules.patch | v1 | chronicle.rule.update_rule | secops rule update | -| rules.retrohunts.create | v1 | chronicle.rule_retrohunt.create_retrohunt | | -| rules.retrohunts.get | v1 | chronicle.rule_retrohunt.get_retrohunt | | -| rules.retrohunts.list | v1 | | | -| rules.updateDeployment | v1 | chronicle.rule.enable_rule | secops rule enable | -| watchlists.create | v1 | | | -| watchlists.delete | v1 | | | -| watchlists.get | v1 | | | -| watchlists.list | v1 | | | -| watchlists.patch | v1 | | | -| dataAccessLabels.create | v1beta | | | -| dataAccessLabels.delete | v1beta | | | -| dataAccessLabels.get | v1beta | | | -| dataAccessLabels.list | v1beta | | | -| dataAccessLabels.patch | v1beta | | | -| dataAccessScopes.create | v1beta | | | -| dataAccessScopes.delete | v1beta | | | -| dataAccessScopes.get | v1beta | | | -| dataAccessScopes.list | v1beta | | | -| dataAccessScopes.patch | v1beta | | | -| get | v1beta | | | -| operations.cancel | v1beta | | | -| operations.delete | v1beta | | | -| operations.get | v1beta | | | -| operations.list | v1beta | | | -| referenceLists.create | v1beta | | | -| referenceLists.get | v1beta | | | -| referenceLists.list | v1beta | | | -| referenceLists.patch | v1beta | | | -| rules.create | v1beta | | | -| rules.delete | v1beta | | | -| rules.deployments.list | v1beta | | | -| rules.get | v1beta | | | -| rules.getDeployment | v1beta | | | -| rules.list | v1beta | | | -| rules.listRevisions | v1beta | | | -| rules.patch | v1beta | | | -| rules.retrohunts.create | v1beta | | | -| rules.retrohunts.get | v1beta | | | -| rules.retrohunts.list | v1beta | | | -| rules.updateDeployment | v1beta | | | -| watchlists.create | v1beta | | | -| watchlists.delete | v1beta | | | -| watchlists.get | v1beta | | | -| watchlists.list | v1beta | | | -| watchlists.patch | v1beta | | | -| analytics.entities.analyticValues.list | v1alpha | | | -| analytics.list | v1alpha | | | -| batchValidateWatchlistEntities | v1alpha | | | -| bigQueryAccess.provide | v1alpha | | | -| bigQueryExport.provision | v1alpha | | | -| cases.countPriorities | v1alpha | | | -| curatedRuleSetCategories.curatedRuleSets.curatedRuleSetDeployments.batchUpdate | v1alpha | chronicle.rule_set.batch_update_curated_rule_set_deployments | | -| curatedRuleSetCategories.curatedRuleSets.curatedRuleSetDeployments.patch | v1alpha | chronicle.rule_set.update_curated_rule_set_deployment | | -| curatedRuleSetCategories.curatedRuleSets.curatedRuleSetDeployments.list | v1alpha | chronicle.rule_set.list_curated_rule_set_deployments | | -| curatedRuleSetCategories.curatedRuleSets.curatedRuleSetDeployments.get | v1alpha | chronicle.rule_set.get_curated_rule_set_deployment
chronicle.rule_set.get_curated_rule_set_deployment_by_name | | -| curatedRuleSetCategories.curatedRuleSets.get | v1alpha | chronicle.rule_set.get_curated_rule_set | | -| curatedRuleSetCategories.curatedRuleSets.list | v1alpha | chronicle.rule_set.list_curated_rule_sets | | -| curatedRuleSetCategories.get | v1alpha | chronicle.rule_set.get_curated_rule_set_category | | -| curatedRuleSetCategories.list | v1alpha | chronicle.rule_set.list_curated_rule_set_categories | | -| curatedRules.get | v1alpha | chronicle.rule_set.get_curated_rule
chronicle.rule_set.get_curated_rule_by_name | | -| curatedRules.list | v1alpha | chronicle.rule_set.list_curated_rules | | -| dashboardCharts.batchGet | v1alpha | | | -| dashboardCharts.get | v1alpha | chronicle.dashboard.get_chart | secops dashboard get-chart | -| dashboardQueries.execute | v1alpha | chronicle.dashboard_query.execute_query | secops dashboard-query execute | -| dashboardQueries.get | v1alpha | chronicle.dashboard_query.get_execute_query | secops dashboard-query get | -| dashboards.copy | v1alpha | | | -| dashboards.create | v1alpha | | | -| dashboards.delete | v1alpha | | | -| dashboards.get | v1alpha | | | -| dashboards.list | v1alpha | | | -| dataAccessLabels.create | v1alpha | | | -| dataAccessLabels.delete | v1alpha | | | -| dataAccessLabels.get | v1alpha | | | -| dataAccessLabels.list | v1alpha | | | -| dataAccessLabels.patch | v1alpha | | | -| dataAccessScopes.create | v1alpha | | | -| dataAccessScopes.delete | v1alpha | | | -| dataAccessScopes.get | v1alpha | | | -| dataAccessScopes.list | v1alpha | | | -| dataAccessScopes.patch | v1alpha | | | -| dataExports.cancel | v1alpha | chronicle.data_export.cancel_data_export | secops export cancel | -| dataExports.create | v1alpha | chronicle.data_export.create_data_export | secops export create | -| dataExports.fetchavailablelogtypes | v1alpha | chronicle.data_export.fetch_available_log_types | secops export log-types | -| dataExports.get | v1alpha | chronicle.data_export.get_data_export | secops export status | -| dataExports.list | v1alpha | chronicle.data_export.list_data_export | secops export list | -| dataExports.patch | v1alpha | chronicle.data_export.update_data_export | secops export update | -| dataTableOperationErrors.get | v1alpha | | | -| dataTables.create | v1alpha | chronicle.data_table.create_data_table | secops data-table create | -| dataTables.dataTableRows.bulkCreate | v1alpha | chronicle.data_table.create_data_table_rows | secops data-table add-rows | -| dataTables.dataTableRows.bulkCreateAsync | v1alpha | | | -| dataTables.dataTableRows.bulkGet | v1alpha | | | -| dataTables.dataTableRows.bulkReplace | v1alpha | | | -| dataTables.dataTableRows.bulkReplaceAsync | v1alpha | | | -| dataTables.dataTableRows.bulkUpdate | v1alpha | | | -| dataTables.dataTableRows.bulkUpdateAsync | v1alpha | | | -| dataTables.dataTableRows.create | v1alpha | | | -| dataTables.dataTableRows.delete | v1alpha | chronicle.data_table.delete_data_table_rows | secops data-table delete-rows | -| dataTables.dataTableRows.get | v1alpha | | | -| dataTables.dataTableRows.list | v1alpha | chronicle.data_table.list_data_table_rows | secops data-table list-rows | -| dataTables.dataTableRows.patch | v1alpha | | | -| dataTables.delete | v1alpha | chronicle.data_table.delete_data_table | secops data-table delete | -| dataTables.get | v1alpha | chronicle.data_table.get_data_table | secops data-table get | -| dataTables.list | v1alpha | chronicle.data_table.list_data_tables | secops data-table list | -| dataTables.patch | v1alpha | | | -| dataTables.upload | v1alpha | | | -| dataTaps.create | v1alpha | | | -| dataTaps.delete | v1alpha | | | -| dataTaps.get | v1alpha | | | -| dataTaps.list | v1alpha | | | -| dataTaps.patch | v1alpha | | | -| delete | v1alpha | | | -| enrichmentControls.create | v1alpha | | | -| enrichmentControls.delete | v1alpha | | | -| enrichmentControls.get | v1alpha | | | -| enrichmentControls.list | v1alpha | | | -| entities.get | v1alpha | | | -| entities.import | v1alpha | | | -| entities.modifyEntityRiskScore | v1alpha | | | -| entities.queryEntityRiskScoreModifications | v1alpha | | | -| entityRiskScores.query | v1alpha | | | -| errorNotificationConfigs.create | v1alpha | | | -| errorNotificationConfigs.delete | v1alpha | | | -| errorNotificationConfigs.get | v1alpha | | | -| errorNotificationConfigs.list | v1alpha | | | -| errorNotificationConfigs.patch | v1alpha | | | -| events.batchGet | v1alpha | | | -| events.get | v1alpha | | | -| events.import | v1alpha | chronicle.log_ingest.ingest_udm | secops log ingest-udm | -| extractSyslog | v1alpha | | | -| federationGroups.create | v1alpha | | | -| federationGroups.delete | v1alpha | | | -| federationGroups.get | v1alpha | | | -| federationGroups.list | v1alpha | | | -| federationGroups.patch | v1alpha | | | -| feedPacks.get | v1alpha | | | -| feedPacks.list | v1alpha | | | -| feedServiceAccounts.fetchServiceAccountForCustomer | v1alpha | | | -| feedSourceTypeSchemas.list | v1alpha | | | -| feedSourceTypeSchemas.logTypeSchemas.list | v1alpha | | | -| feeds.create | v1alpha | chronicle.feeds.create_feed | secops feed create | -| feeds.delete | v1alpha | chronicle.feeds.delete_feed | secops feed delete | -| feeds.disable | v1alpha | chronicle.feeds.disable_feed | secops feed disable | -| feeds.enable | v1alpha | chronicle.feeds.enable_feed | secops feed enable | -| feeds.generateSecret | v1alpha | chronicle.feeds.generate_secret | secops feed secret | -| feeds.get | v1alpha | chronicle.feeds.get_feed | secops feed get | -| feeds.importPushLogs | v1alpha | | | -| feeds.list | v1alpha | chronicle.feeds.list_feeds | secops feed list | -| feeds.patch | v1alpha | chronicle.feeds.update_feed | secops feed update | -| feeds.scheduleTransfer | v1alpha | | | -| fetchFederationAccess | v1alpha | | | -| findEntity | v1alpha | | | -| findEntityAlerts | v1alpha | | | -| findRelatedEntities | v1alpha | | | -| findUdmFieldValues | v1alpha | | | -| findingsGraph.exploreNode | v1alpha | | | -| findingsGraph.initializeGraph | v1alpha | | | -| findingsRefinements.computeFindingsRefinementActivity | v1alpha | chronicle.rule_exclusion.compute_rule_exclusion_activity | secops rule-exclusion compute-activity | -| findingsRefinements.create | v1alpha | chronicle.rule_exclusion.create_rule_exclusion | secops rule-exclusion create | -| findingsRefinements.get | v1alpha | chronicle.rule_exclusion.get_rule_exclusion | secops rule-exclusion get | -| findingsRefinements.getDeployment | v1alpha | chronicle.rule_exclusion.get_rule_exclusion_deployment | secops rule-exclusion get-deployment | -| findingsRefinements.list | v1alpha | chronicle.rule_exclusion.list_rule_exclusions | secops rule-exclusion list | -| findingsRefinements.patch | v1alpha | chronicle.rule_exclusion.patch_rule_exclusion | secops rule-exclusion update | -| findingsRefinements.updateDeployment | v1alpha | chronicle.rule_exclusion.update_rule_exclusion_deployment | secops rule-exclusion update-deployment | -| forwarders.collectors.create | v1alpha | | | -| forwarders.collectors.delete | v1alpha | | | -| forwarders.collectors.get | v1alpha | | | -| forwarders.collectors.list | v1alpha | | | -| forwarders.collectors.patch | v1alpha | | | -| forwarders.create | v1alpha | chronicle.log_ingest.create_forwarder | secops forwarder create | -| forwarders.delete | v1alpha | chronicle.log_ingest.delete_forwarder | secops forwarder delete | -| forwarders.generateForwarderFiles | v1alpha | | | -| forwarders.get | v1alpha | chronicle.log_ingest.get_forwarder | secops forwarder get | -| forwarders.importStatsEvents | v1alpha | | | -| forwarders.list | v1alpha | chronicle.log_ingest.list_forwarder | secops forwarder list | -| forwarders.patch | v1alpha | chronicle.log_ingest.update_forwarder | secops forwarder update | -| generateCollectionAgentAuth | v1alpha | | | -| generateSoarAuthJwt | v1alpha | | | -| generateUdmKeyValueMappings | v1alpha | | | -| generateWorkspaceConnectionToken | v1alpha | | | -| get | v1alpha | | | -| getBigQueryExport | v1alpha | | | -| getMultitenantDirectory | v1alpha | | | -| getRiskConfig | v1alpha | | | -| ingestionLogLabels.get | v1alpha | | | -| ingestionLogLabels.list | v1alpha | | | -| ingestionLogNamespaces.get | v1alpha | | | -| ingestionLogNamespaces.list | v1alpha | | | -| iocs.batchGet | v1alpha | | | -| iocs.findFirstAndLastSeen | v1alpha | | | -| iocs.get | v1alpha | | | -| iocs.getIocState | v1alpha | | | -| iocs.searchCuratedDetectionsForIoc | v1alpha | | | -| iocs.updateIocState | v1alpha | | | -| legacy.legacyBatchGetCases | v1alpha | chronicle.case.get_cases_from_list | secops case | -| legacy.legacyBatchGetCollections | v1alpha | | | -| legacy.legacyCreateOrUpdateCase | v1alpha | | | -| legacy.legacyCreateSoarAlert | v1alpha | | | -| legacy.legacyFetchAlertsView | v1alpha | chronicle.alert.get_alerts | secops alert | -| legacy.legacyFetchUdmSearchCsv | v1alpha | chronicle.udm_search.fetch_udm_search_csv | secops search --csv | -| legacy.legacyFetchUdmSearchView | v1alpha | chronicle.udm_search.fetch_udm_search_view | secops udm-search-view | -| legacy.legacyFindAssetEvents | v1alpha | | | -| legacy.legacyFindRawLogs | v1alpha | | | -| legacy.legacyFindUdmEvents | v1alpha | | | -| legacy.legacyGetAlert | v1alpha | chronicle.rule_alert.get_alert | | -| legacy.legacyGetCuratedRulesTrends | v1alpha | | | -| legacy.legacyGetDetection | v1alpha | | | -| legacy.legacyGetEventForDetection | v1alpha | | | -| legacy.legacyGetRuleCounts | v1alpha | | | -| legacy.legacyGetRulesTrends | v1alpha | | | -| legacy.legacyListCases | v1alpha | chronicle.case.get_cases | secops case --ids | -| legacy.legacyRunTestRule | v1alpha | chronicle.rule.run_rule_test | secops rule validate | -| legacy.legacySearchArtifactEvents | v1alpha | | | -| legacy.legacySearchArtifactIoCDetails | v1alpha | | | -| legacy.legacySearchAssetEvents | v1alpha | | | -| legacy.legacySearchCuratedDetections | v1alpha | | | -| legacy.legacySearchCustomerStats | v1alpha | | | -| legacy.legacySearchDetections | v1alpha | chronicle.rule_detection.list_detections | | -| legacy.legacySearchDomainsRecentlyRegistered | v1alpha | | | -| legacy.legacySearchDomainsTimingStats | v1alpha | | | -| legacy.legacySearchEnterpriseWideAlerts | v1alpha | | | -| legacy.legacySearchEnterpriseWideIoCs | v1alpha | chronicle.ioc.list_iocs | secops iocs | -| legacy.legacySearchFindings | v1alpha | | | -| legacy.legacySearchIngestionStats | v1alpha | | | -| legacy.legacySearchIoCInsights | v1alpha | | | -| legacy.legacySearchRawLogs | v1alpha | | | -| legacy.legacySearchRuleDetectionCountBuckets | v1alpha | | | -| legacy.legacySearchRuleDetectionEvents | v1alpha | | | -| legacy.legacySearchRuleResults | v1alpha | | | -| legacy.legacySearchRulesAlerts | v1alpha | chronicle.rule_alert.search_rule_alerts | | -| legacy.legacySearchUserEvents | v1alpha | | | -| legacy.legacyStreamDetectionAlerts | v1alpha | | | -| legacy.legacyTestRuleStreaming | v1alpha | | | -| legacy.legacyUpdateAlert | v1alpha | chronicle.rule_alert.update_alert | | -| listAllFindingsRefinementDeployments | v1alpha | | | -| logTypes.create | v1alpha | | | -| logTypes.generateEventTypesSuggestions | v1alpha | | | -| logTypes.get | v1alpha | | | -| logTypes.getLogTypeSetting | v1alpha | | | -| logTypes.legacySubmitParserExtension | v1alpha | | | -| logTypes.list | v1alpha | | | -| logTypes.logs.export | v1alpha | | | -| logTypes.logs.get | v1alpha | | | -| logTypes.logs.import | v1alpha | chronicle.log_ingest.ingest_log | secops log ingest | -| logTypes.logs.list | v1alpha | | | -| logTypes.parserExtensions.activate | v1alpha | chronicle.parser_extension.activate_parser_extension | secops parser-extension activate | -| logTypes.parserExtensions.create | v1alpha | chronicle.parser_extension.create_parser_extension | secops parser-extension create | -| logTypes.parserExtensions.delete | v1alpha | chronicle.parser_extension.delete_parser_extension | secops parser-extension delete | -| logTypes.parserExtensions.extensionValidationReports.get | v1alpha | | | -| logTypes.parserExtensions.extensionValidationReports.list | v1alpha | | | -| logTypes.parserExtensions.extensionValidationReports.validationErrors.list | v1alpha | | | -| logTypes.parserExtensions.get | v1alpha | chronicle.parser_extension.get_parser_extension | secops parser-extension get | -| logTypes.parserExtensions.list | v1alpha | chronicle.parser_extension.list_parser_extensions | secops parser-extension list | -| logTypes.parserExtensions.validationReports.get | v1alpha | | | -| logTypes.parserExtensions.validationReports.parsingErrors.list | v1alpha | | | -| logTypes.parsers.activate | v1alpha | chronicle.parser.activate_parser | secops parser activate | -| logTypes.parsers.activateReleaseCandidateParser | v1alpha | chronicle.parser.activate_release_candidate | secops parser activate-rc | -| logTypes.parsers.copy | v1alpha | chronicle.parser.copy_parser | secops parser copy | -| logTypes.parsers.create | v1alpha | chronicle.parser.create_parser | secops parser create | -| logTypes.parsers.deactivate | v1alpha | chronicle.parser.deactivate_parser | secops parser deactivate | -| logTypes.parsers.delete | v1alpha | chronicle.parser.delete_parser | secops parser delete | -| logTypes.parsers.get | v1alpha | chronicle.parser.get_parser | secops parser get | -| logTypes.parsers.list | v1alpha | chronicle.parser.list_parsers | secops parser list | -| logTypes.parsers.validationReports.get | v1alpha | | | -| logTypes.parsers.validationReports.parsingErrors.list | v1alpha | | | -| logTypes.patch | v1alpha | | | -| logTypes.runParser | v1alpha | chronicle.parser.run_parser | secops parser run | -| logTypes.updateLogTypeSetting | v1alpha | | | -| logs.classify | v1alpha | | | -| nativeDashboards.addChart | v1alpha | chronicle.dashboard.add_chart | secops dashboard add-chart | -| nativeDashboards.create | v1alpha | chronicle.dashboard.create_dashboard | secops dashboard create | -| nativeDashboards.delete | v1alpha | chronicle.dashboard.delete_dashboard | secops dashboard delete | -| nativeDashboards.duplicate | v1alpha | chronicle.dashboard.duplicate_dashboard | secops dashboard duplicate | -| nativeDashboards.duplicateChart | v1alpha | | | -| nativeDashboards.editChart | v1alpha | chronicle.dashboard.edit_chart | secops dashboard edit-chart | -| nativeDashboards.export | v1alpha | chronicle.dashboard.export_dashboard | secops dashboard export | -| nativeDashboards.get | v1alpha | chronicle.dashboard.get_dashboard | secops dashboard get | -| nativeDashboards.import | v1alpha | chronicle.dashboard.import_dashboard | secops dashboard import | -| nativeDashboards.list | v1alpha | chronicle.dashboard.list_dashboards | secops dashboard list | -| nativeDashboards.patch | v1alpha | chronicle.dashboard.update_dashboard | secops dashboard update | -| nativeDashboards.removeChart | v1alpha | chronicle.dashboard.remove_chart | secops dashboard remove-chart | -| operations.cancel | v1alpha | | | -| operations.delete | v1alpha | | | -| operations.get | v1alpha | | | -| operations.list | v1alpha | | | -| operations.streamSearch | v1alpha | | | -| queryProductSourceStats | v1alpha | | | -| referenceLists.create | v1alpha | | | -| referenceLists.get | v1alpha | | | -| referenceLists.list | v1alpha | | | -| referenceLists.patch | v1alpha | | | -| report | v1alpha | | | -| ruleExecutionErrors.list | v1alpha | chronicle.rule_detection.list_errors | | -| rules.create | v1alpha | | | -| rules.delete | v1alpha | | | -| rules.deployments.list | v1alpha | | | -| rules.get | v1alpha | | | -| rules.getDeployment | v1alpha | | | -| rules.list | v1alpha | | | -| rules.listRevisions | v1alpha | | | -| rules.patch | v1alpha | | | -| rules.retrohunts.create | v1alpha | | | -| rules.retrohunts.get | v1alpha | | | -| rules.retrohunts.list | v1alpha | | | -| rules.updateDeployment | v1alpha | | | -| searchEntities | v1alpha | | | -| searchRawLogs | v1alpha | | | -| summarizeEntitiesFromQuery | v1alpha | chronicle.entity.summarize_entity | secops entity | -| summarizeEntity | v1alpha | chronicle.entity.summarize_entity | | -| testFindingsRefinement | v1alpha | | | -| translateUdmQuery | v1alpha | chronicle.nl_search.translate_nl_to_udm | | -| translateYlRule | v1alpha | | | -| udmSearch | v1alpha | chronicle.search.search_udm | secops search | -| undelete | v1alpha | | | -| updateBigQueryExport | v1alpha | | | -| updateRiskConfig | v1alpha | | | -| users.clearConversationHistory | v1alpha | | | -| users.conversations.create | v1alpha | chronicle.gemini.create_conversation | | -| users.conversations.delete | v1alpha | | | -| users.conversations.get | v1alpha | | | -| users.conversations.list | v1alpha | | | -| users.conversations.messages.create | v1alpha | chronicle.gemini.query_gemini | secops gemini | -| users.conversations.messages.delete | v1alpha | | | -| users.conversations.messages.get | v1alpha | | | -| users.conversations.messages.list | v1alpha | | | -| users.conversations.messages.patch | v1alpha | | | -| users.conversations.patch | v1alpha | | | -| users.getPreferenceSet | v1alpha | chronicle.gemini.opt_in_to_gemini | secops gemini --opt-in | -| users.searchQueries.create | v1alpha | | | -| users.searchQueries.delete | v1alpha | | | -| users.searchQueries.get | v1alpha | | | -| users.searchQueries.list | v1alpha | | | -| users.searchQueries.patch | v1alpha | | | -| users.updatePreferenceSet | v1alpha | | | -| validateQuery | v1alpha | chronicle.validate.validate_query | | -| verifyReferenceList | v1alpha | | | -| verifyRuleText | v1alpha | chronicle.rule_validation.validate_rule | secops rule validate | -| watchlists.create | v1alpha | | | -| watchlists.delete | v1alpha | | | -| watchlists.entities.add | v1alpha | | | -| watchlists.entities.batchAdd | v1alpha | | | -| watchlists.entities.batchRemove | v1alpha | | | -| watchlists.entities.remove | v1alpha | | | -| watchlists.get | v1alpha | | | -| watchlists.list | v1alpha | | | -| watchlists.listEntities | v1alpha | | | -| watchlists.patch | v1alpha | | | +| REST Resource | Version | secops-wrapper module | CLI Command | +|--------------------------------------------------------------------------------|---------|-------------------------------------------------------------------------------------------------------------------|------------------------------------------------| +| dataAccessLabels.create | v1 | | | +| dataAccessLabels.delete | v1 | | | +| dataAccessLabels.get | v1 | | | +| dataAccessLabels.list | v1 | | | +| dataAccessLabels.patch | v1 | | | +| dataAccessScopes.create | v1 | | | +| dataAccessScopes.delete | v1 | | | +| dataAccessScopes.get | v1 | | | +| dataAccessScopes.list | v1 | | | +| dataAccessScopes.patch | v1 | | | +| get | v1 | | | +| operations.cancel | v1 | | | +| operations.delete | v1 | | | +| operations.get | v1 | | | +| operations.list | v1 | | | +| referenceLists.create | v1 | chronicle.reference_list.create_reference_list | secops reference-list create | +| referenceLists.get | v1 | chronicle.reference_list.get_reference_list | secops reference-list get | +| referenceLists.list | v1 | chronicle.reference_list.list_reference_lists | secops reference-list list | +| referenceLists.patch | v1 | chronicle.reference_list.update_reference_list | secops reference-list update | +| rules.create | v1 | chronicle.rule.create_rule | secops rule create | +| rules.delete | v1 | chronicle.rule.delete_rule | secops rule delete | +| rules.deployments.list | v1 | | | +| rules.get | v1 | chronicle.rule.get_rule | secops rule get | +| rules.getDeployment | v1 | | | +| rules.list | v1 | chronicle.rule.list_rules | secops rule list | +| rules.listRevisions | v1 | | | +| rules.patch | v1 | chronicle.rule.update_rule | secops rule update | +| rules.retrohunts.create | v1 | chronicle.rule_retrohunt.create_retrohunt | | +| rules.retrohunts.get | v1 | chronicle.rule_retrohunt.get_retrohunt | | +| rules.retrohunts.list | v1 | | | +| rules.updateDeployment | v1 | chronicle.rule.enable_rule | secops rule enable | +| watchlists.create | v1 | | | +| watchlists.delete | v1 | | | +| watchlists.get | v1 | | | +| watchlists.list | v1 | | | +| watchlists.patch | v1 | | | +| dataAccessLabels.create | v1beta | | | +| dataAccessLabels.delete | v1beta | | | +| dataAccessLabels.get | v1beta | | | +| dataAccessLabels.list | v1beta | | | +| dataAccessLabels.patch | v1beta | | | +| dataAccessScopes.create | v1beta | | | +| dataAccessScopes.delete | v1beta | | | +| dataAccessScopes.get | v1beta | | | +| dataAccessScopes.list | v1beta | | | +| dataAccessScopes.patch | v1beta | | | +| get | v1beta | | | +| operations.cancel | v1beta | | | +| operations.delete | v1beta | | | +| operations.get | v1beta | | | +| operations.list | v1beta | | | +| referenceLists.create | v1beta | | | +| referenceLists.get | v1beta | | | +| referenceLists.list | v1beta | | | +| referenceLists.patch | v1beta | | | +| rules.create | v1beta | | | +| rules.delete | v1beta | | | +| rules.deployments.list | v1beta | | | +| rules.get | v1beta | | | +| rules.getDeployment | v1beta | | | +| rules.list | v1beta | | | +| rules.listRevisions | v1beta | | | +| rules.patch | v1beta | | | +| rules.retrohunts.create | v1beta | | | +| rules.retrohunts.get | v1beta | | | +| rules.retrohunts.list | v1beta | | | +| rules.updateDeployment | v1beta | | | +| watchlists.create | v1beta | | | +| watchlists.delete | v1beta | | | +| watchlists.get | v1beta | | | +| watchlists.list | v1beta | | | +| watchlists.patch | v1beta | | | +| analytics.entities.analyticValues.list | v1alpha | | | +| analytics.list | v1alpha | | | +| batchValidateWatchlistEntities | v1alpha | | | +| bigQueryAccess.provide | v1alpha | | | +| bigQueryExport.provision | v1alpha | | | +| cases.countPriorities | v1alpha | | | +| curatedRuleSetCategories.curatedRuleSets.curatedRuleSetDeployments.batchUpdate | v1alpha | chronicle.rule_set.batch_update_curated_rule_set_deployments | | +| curatedRuleSetCategories.curatedRuleSets.curatedRuleSetDeployments.patch | v1alpha | chronicle.rule_set.update_curated_rule_set_deployment | secops curated-rule rule-set-deployment update | +| curatedRuleSetCategories.curatedRuleSets.curatedRuleSetDeployments.list | v1alpha | chronicle.rule_set.list_curated_rule_set_deployments | secops curated-rule rule-set-deployment list | +| curatedRuleSetCategories.curatedRuleSets.curatedRuleSetDeployments.get | v1alpha | chronicle.rule_set.get_curated_rule_set_deployment
chronicle.rule_set.get_curated_rule_set_deployment_by_name | secops curated-rule rule-set-deployment get | +| curatedRuleSetCategories.curatedRuleSets.get | v1alpha | chronicle.rule_set.get_curated_rule_set | secops curated-rule rule-set get | +| curatedRuleSetCategories.curatedRuleSets.list | v1alpha | chronicle.rule_set.list_curated_rule_sets | secops curated-rule rule-set list | +| curatedRuleSetCategories.get | v1alpha | chronicle.rule_set.get_curated_rule_set_category | secops curated-rule rule-set-category get | +| curatedRuleSetCategories.list | v1alpha | chronicle.rule_set.list_curated_rule_set_categories | secops curated-rule rule-set-category list | +| curatedRules.get | v1alpha | chronicle.rule_set.get_curated_rule
chronicle.rule_set.get_curated_rule_by_name | secops curated-rule rule get | +| curatedRules.list | v1alpha | chronicle.rule_set.list_curated_rules | secops curated-rule rule list | +| dashboardCharts.batchGet | v1alpha | | | +| dashboardCharts.get | v1alpha | chronicle.dashboard.get_chart | secops dashboard get-chart | +| dashboardQueries.execute | v1alpha | chronicle.dashboard_query.execute_query | secops dashboard-query execute | +| dashboardQueries.get | v1alpha | chronicle.dashboard_query.get_execute_query | secops dashboard-query get | +| dashboards.copy | v1alpha | | | +| dashboards.create | v1alpha | | | +| dashboards.delete | v1alpha | | | +| dashboards.get | v1alpha | | | +| dashboards.list | v1alpha | | | +| dataAccessLabels.create | v1alpha | | | +| dataAccessLabels.delete | v1alpha | | | +| dataAccessLabels.get | v1alpha | | | +| dataAccessLabels.list | v1alpha | | | +| dataAccessLabels.patch | v1alpha | | | +| dataAccessScopes.create | v1alpha | | | +| dataAccessScopes.delete | v1alpha | | | +| dataAccessScopes.get | v1alpha | | | +| dataAccessScopes.list | v1alpha | | | +| dataAccessScopes.patch | v1alpha | | | +| dataExports.cancel | v1alpha | chronicle.data_export.cancel_data_export | secops export cancel | +| dataExports.create | v1alpha | chronicle.data_export.create_data_export | secops export create | +| dataExports.fetchavailablelogtypes | v1alpha | chronicle.data_export.fetch_available_log_types | secops export log-types | +| dataExports.get | v1alpha | chronicle.data_export.get_data_export | secops export status | +| dataExports.list | v1alpha | chronicle.data_export.list_data_export | secops export list | +| dataExports.patch | v1alpha | chronicle.data_export.update_data_export | secops export update | +| dataTableOperationErrors.get | v1alpha | | | +| dataTables.create | v1alpha | chronicle.data_table.create_data_table | secops data-table create | +| dataTables.dataTableRows.bulkCreate | v1alpha | chronicle.data_table.create_data_table_rows | secops data-table add-rows | +| dataTables.dataTableRows.bulkCreateAsync | v1alpha | | | +| dataTables.dataTableRows.bulkGet | v1alpha | | | +| dataTables.dataTableRows.bulkReplace | v1alpha | | | +| dataTables.dataTableRows.bulkReplaceAsync | v1alpha | | | +| dataTables.dataTableRows.bulkUpdate | v1alpha | | | +| dataTables.dataTableRows.bulkUpdateAsync | v1alpha | | | +| dataTables.dataTableRows.create | v1alpha | | | +| dataTables.dataTableRows.delete | v1alpha | chronicle.data_table.delete_data_table_rows | secops data-table delete-rows | +| dataTables.dataTableRows.get | v1alpha | | | +| dataTables.dataTableRows.list | v1alpha | chronicle.data_table.list_data_table_rows | secops data-table list-rows | +| dataTables.dataTableRows.patch | v1alpha | | | +| dataTables.delete | v1alpha | chronicle.data_table.delete_data_table | secops data-table delete | +| dataTables.get | v1alpha | chronicle.data_table.get_data_table | secops data-table get | +| dataTables.list | v1alpha | chronicle.data_table.list_data_tables | secops data-table list | +| dataTables.patch | v1alpha | | | +| dataTables.upload | v1alpha | | | +| dataTaps.create | v1alpha | | | +| dataTaps.delete | v1alpha | | | +| dataTaps.get | v1alpha | | | +| dataTaps.list | v1alpha | | | +| dataTaps.patch | v1alpha | | | +| delete | v1alpha | | | +| enrichmentControls.create | v1alpha | | | +| enrichmentControls.delete | v1alpha | | | +| enrichmentControls.get | v1alpha | | | +| enrichmentControls.list | v1alpha | | | +| entities.get | v1alpha | | | +| entities.import | v1alpha | | | +| entities.modifyEntityRiskScore | v1alpha | | | +| entities.queryEntityRiskScoreModifications | v1alpha | | | +| entityRiskScores.query | v1alpha | | | +| errorNotificationConfigs.create | v1alpha | | | +| errorNotificationConfigs.delete | v1alpha | | | +| errorNotificationConfigs.get | v1alpha | | | +| errorNotificationConfigs.list | v1alpha | | | +| errorNotificationConfigs.patch | v1alpha | | | +| events.batchGet | v1alpha | | | +| events.get | v1alpha | | | +| events.import | v1alpha | chronicle.log_ingest.ingest_udm | secops log ingest-udm | +| extractSyslog | v1alpha | | | +| federationGroups.create | v1alpha | | | +| federationGroups.delete | v1alpha | | | +| federationGroups.get | v1alpha | | | +| federationGroups.list | v1alpha | | | +| federationGroups.patch | v1alpha | | | +| feedPacks.get | v1alpha | | | +| feedPacks.list | v1alpha | | | +| feedServiceAccounts.fetchServiceAccountForCustomer | v1alpha | | | +| feedSourceTypeSchemas.list | v1alpha | | | +| feedSourceTypeSchemas.logTypeSchemas.list | v1alpha | | | +| feeds.create | v1alpha | chronicle.feeds.create_feed | secops feed create | +| feeds.delete | v1alpha | chronicle.feeds.delete_feed | secops feed delete | +| feeds.disable | v1alpha | chronicle.feeds.disable_feed | secops feed disable | +| feeds.enable | v1alpha | chronicle.feeds.enable_feed | secops feed enable | +| feeds.generateSecret | v1alpha | chronicle.feeds.generate_secret | secops feed secret | +| feeds.get | v1alpha | chronicle.feeds.get_feed | secops feed get | +| feeds.importPushLogs | v1alpha | | | +| feeds.list | v1alpha | chronicle.feeds.list_feeds | secops feed list | +| feeds.patch | v1alpha | chronicle.feeds.update_feed | secops feed update | +| feeds.scheduleTransfer | v1alpha | | | +| fetchFederationAccess | v1alpha | | | +| findEntity | v1alpha | | | +| findEntityAlerts | v1alpha | | | +| findRelatedEntities | v1alpha | | | +| findUdmFieldValues | v1alpha | | | +| findingsGraph.exploreNode | v1alpha | | | +| findingsGraph.initializeGraph | v1alpha | | | +| findingsRefinements.computeFindingsRefinementActivity | v1alpha | chronicle.rule_exclusion.compute_rule_exclusion_activity | secops rule-exclusion compute-activity | +| findingsRefinements.create | v1alpha | chronicle.rule_exclusion.create_rule_exclusion | secops rule-exclusion create | +| findingsRefinements.get | v1alpha | chronicle.rule_exclusion.get_rule_exclusion | secops rule-exclusion get | +| findingsRefinements.getDeployment | v1alpha | chronicle.rule_exclusion.get_rule_exclusion_deployment | secops rule-exclusion get-deployment | +| findingsRefinements.list | v1alpha | chronicle.rule_exclusion.list_rule_exclusions | secops rule-exclusion list | +| findingsRefinements.patch | v1alpha | chronicle.rule_exclusion.patch_rule_exclusion | secops rule-exclusion update | +| findingsRefinements.updateDeployment | v1alpha | chronicle.rule_exclusion.update_rule_exclusion_deployment | secops rule-exclusion update-deployment | +| forwarders.collectors.create | v1alpha | | | +| forwarders.collectors.delete | v1alpha | | | +| forwarders.collectors.get | v1alpha | | | +| forwarders.collectors.list | v1alpha | | | +| forwarders.collectors.patch | v1alpha | | | +| forwarders.create | v1alpha | chronicle.log_ingest.create_forwarder | secops forwarder create | +| forwarders.delete | v1alpha | chronicle.log_ingest.delete_forwarder | secops forwarder delete | +| forwarders.generateForwarderFiles | v1alpha | | | +| forwarders.get | v1alpha | chronicle.log_ingest.get_forwarder | secops forwarder get | +| forwarders.importStatsEvents | v1alpha | | | +| forwarders.list | v1alpha | chronicle.log_ingest.list_forwarder | secops forwarder list | +| forwarders.patch | v1alpha | chronicle.log_ingest.update_forwarder | secops forwarder update | +| generateCollectionAgentAuth | v1alpha | | | +| generateSoarAuthJwt | v1alpha | | | +| generateUdmKeyValueMappings | v1alpha | | | +| generateWorkspaceConnectionToken | v1alpha | | | +| get | v1alpha | | | +| getBigQueryExport | v1alpha | | | +| getMultitenantDirectory | v1alpha | | | +| getRiskConfig | v1alpha | | | +| ingestionLogLabels.get | v1alpha | | | +| ingestionLogLabels.list | v1alpha | | | +| ingestionLogNamespaces.get | v1alpha | | | +| ingestionLogNamespaces.list | v1alpha | | | +| iocs.batchGet | v1alpha | | | +| iocs.findFirstAndLastSeen | v1alpha | | | +| iocs.get | v1alpha | | | +| iocs.getIocState | v1alpha | | | +| iocs.searchCuratedDetectionsForIoc | v1alpha | | | +| iocs.updateIocState | v1alpha | | | +| legacy.legacyBatchGetCases | v1alpha | chronicle.case.get_cases_from_list | secops case | +| legacy.legacyBatchGetCollections | v1alpha | | | +| legacy.legacyCreateOrUpdateCase | v1alpha | | | +| legacy.legacyCreateSoarAlert | v1alpha | | | +| legacy.legacyFetchAlertsView | v1alpha | chronicle.alert.get_alerts | secops alert | +| legacy.legacyFetchUdmSearchCsv | v1alpha | chronicle.udm_search.fetch_udm_search_csv | secops search --csv | +| legacy.legacyFetchUdmSearchView | v1alpha | chronicle.udm_search.fetch_udm_search_view | secops udm-search-view | +| legacy.legacyFindAssetEvents | v1alpha | | | +| legacy.legacyFindRawLogs | v1alpha | | | +| legacy.legacyFindUdmEvents | v1alpha | | | +| legacy.legacyGetAlert | v1alpha | chronicle.rule_alert.get_alert | | +| legacy.legacyGetCuratedRulesTrends | v1alpha | | | +| legacy.legacyGetDetection | v1alpha | | | +| legacy.legacyGetEventForDetection | v1alpha | | | +| legacy.legacyGetRuleCounts | v1alpha | | | +| legacy.legacyGetRulesTrends | v1alpha | | | +| legacy.legacyListCases | v1alpha | chronicle.case.get_cases | secops case --ids | +| legacy.legacyRunTestRule | v1alpha | chronicle.rule.run_rule_test | secops rule validate | +| legacy.legacySearchArtifactEvents | v1alpha | | | +| legacy.legacySearchArtifactIoCDetails | v1alpha | | | +| legacy.legacySearchAssetEvents | v1alpha | | | +| legacy.legacySearchCuratedDetections | v1alpha | | | +| legacy.legacySearchCustomerStats | v1alpha | | | +| legacy.legacySearchDetections | v1alpha | chronicle.rule_detection.list_detections | | +| legacy.legacySearchDomainsRecentlyRegistered | v1alpha | | | +| legacy.legacySearchDomainsTimingStats | v1alpha | | | +| legacy.legacySearchEnterpriseWideAlerts | v1alpha | | | +| legacy.legacySearchEnterpriseWideIoCs | v1alpha | chronicle.ioc.list_iocs | secops iocs | +| legacy.legacySearchFindings | v1alpha | | | +| legacy.legacySearchIngestionStats | v1alpha | | | +| legacy.legacySearchIoCInsights | v1alpha | | | +| legacy.legacySearchRawLogs | v1alpha | | | +| legacy.legacySearchRuleDetectionCountBuckets | v1alpha | | | +| legacy.legacySearchRuleDetectionEvents | v1alpha | | | +| legacy.legacySearchRuleResults | v1alpha | | | +| legacy.legacySearchRulesAlerts | v1alpha | chronicle.rule_alert.search_rule_alerts | | +| legacy.legacySearchUserEvents | v1alpha | | | +| legacy.legacyStreamDetectionAlerts | v1alpha | | | +| legacy.legacyTestRuleStreaming | v1alpha | | | +| legacy.legacyUpdateAlert | v1alpha | chronicle.rule_alert.update_alert | | +| listAllFindingsRefinementDeployments | v1alpha | | | +| logTypes.create | v1alpha | | | +| logTypes.generateEventTypesSuggestions | v1alpha | | | +| logTypes.get | v1alpha | | | +| logTypes.getLogTypeSetting | v1alpha | | | +| logTypes.legacySubmitParserExtension | v1alpha | | | +| logTypes.list | v1alpha | | | +| logTypes.logs.export | v1alpha | | | +| logTypes.logs.get | v1alpha | | | +| logTypes.logs.import | v1alpha | chronicle.log_ingest.ingest_log | secops log ingest | +| logTypes.logs.list | v1alpha | | | +| logTypes.parserExtensions.activate | v1alpha | chronicle.parser_extension.activate_parser_extension | secops parser-extension activate | +| logTypes.parserExtensions.create | v1alpha | chronicle.parser_extension.create_parser_extension | secops parser-extension create | +| logTypes.parserExtensions.delete | v1alpha | chronicle.parser_extension.delete_parser_extension | secops parser-extension delete | +| logTypes.parserExtensions.extensionValidationReports.get | v1alpha | | | +| logTypes.parserExtensions.extensionValidationReports.list | v1alpha | | | +| logTypes.parserExtensions.extensionValidationReports.validationErrors.list | v1alpha | | | +| logTypes.parserExtensions.get | v1alpha | chronicle.parser_extension.get_parser_extension | secops parser-extension get | +| logTypes.parserExtensions.list | v1alpha | chronicle.parser_extension.list_parser_extensions | secops parser-extension list | +| logTypes.parserExtensions.validationReports.get | v1alpha | | | +| logTypes.parserExtensions.validationReports.parsingErrors.list | v1alpha | | | +| logTypes.parsers.activate | v1alpha | chronicle.parser.activate_parser | secops parser activate | +| logTypes.parsers.activateReleaseCandidateParser | v1alpha | chronicle.parser.activate_release_candidate | secops parser activate-rc | +| logTypes.parsers.copy | v1alpha | chronicle.parser.copy_parser | secops parser copy | +| logTypes.parsers.create | v1alpha | chronicle.parser.create_parser | secops parser create | +| logTypes.parsers.deactivate | v1alpha | chronicle.parser.deactivate_parser | secops parser deactivate | +| logTypes.parsers.delete | v1alpha | chronicle.parser.delete_parser | secops parser delete | +| logTypes.parsers.get | v1alpha | chronicle.parser.get_parser | secops parser get | +| logTypes.parsers.list | v1alpha | chronicle.parser.list_parsers | secops parser list | +| logTypes.parsers.validationReports.get | v1alpha | | | +| logTypes.parsers.validationReports.parsingErrors.list | v1alpha | | | +| logTypes.patch | v1alpha | | | +| logTypes.runParser | v1alpha | chronicle.parser.run_parser | secops parser run | +| logTypes.updateLogTypeSetting | v1alpha | | | +| logs.classify | v1alpha | | | +| nativeDashboards.addChart | v1alpha | chronicle.dashboard.add_chart | secops dashboard add-chart | +| nativeDashboards.create | v1alpha | chronicle.dashboard.create_dashboard | secops dashboard create | +| nativeDashboards.delete | v1alpha | chronicle.dashboard.delete_dashboard | secops dashboard delete | +| nativeDashboards.duplicate | v1alpha | chronicle.dashboard.duplicate_dashboard | secops dashboard duplicate | +| nativeDashboards.duplicateChart | v1alpha | | | +| nativeDashboards.editChart | v1alpha | chronicle.dashboard.edit_chart | secops dashboard edit-chart | +| nativeDashboards.export | v1alpha | chronicle.dashboard.export_dashboard | secops dashboard export | +| nativeDashboards.get | v1alpha | chronicle.dashboard.get_dashboard | secops dashboard get | +| nativeDashboards.import | v1alpha | chronicle.dashboard.import_dashboard | secops dashboard import | +| nativeDashboards.list | v1alpha | chronicle.dashboard.list_dashboards | secops dashboard list | +| nativeDashboards.patch | v1alpha | chronicle.dashboard.update_dashboard | secops dashboard update | +| nativeDashboards.removeChart | v1alpha | chronicle.dashboard.remove_chart | secops dashboard remove-chart | +| operations.cancel | v1alpha | | | +| operations.delete | v1alpha | | | +| operations.get | v1alpha | | | +| operations.list | v1alpha | | | +| operations.streamSearch | v1alpha | | | +| queryProductSourceStats | v1alpha | | | +| referenceLists.create | v1alpha | | | +| referenceLists.get | v1alpha | | | +| referenceLists.list | v1alpha | | | +| referenceLists.patch | v1alpha | | | +| report | v1alpha | | | +| ruleExecutionErrors.list | v1alpha | chronicle.rule_detection.list_errors | | +| rules.create | v1alpha | | | +| rules.delete | v1alpha | | | +| rules.deployments.list | v1alpha | | | +| rules.get | v1alpha | | | +| rules.getDeployment | v1alpha | | | +| rules.list | v1alpha | | | +| rules.listRevisions | v1alpha | | | +| rules.patch | v1alpha | | | +| rules.retrohunts.create | v1alpha | | | +| rules.retrohunts.get | v1alpha | | | +| rules.retrohunts.list | v1alpha | | | +| rules.updateDeployment | v1alpha | | | +| searchEntities | v1alpha | | | +| searchRawLogs | v1alpha | | | +| summarizeEntitiesFromQuery | v1alpha | chronicle.entity.summarize_entity | secops entity | +| summarizeEntity | v1alpha | chronicle.entity.summarize_entity | | +| testFindingsRefinement | v1alpha | | | +| translateUdmQuery | v1alpha | chronicle.nl_search.translate_nl_to_udm | | +| translateYlRule | v1alpha | | | +| udmSearch | v1alpha | chronicle.search.search_udm | secops search | +| undelete | v1alpha | | | +| updateBigQueryExport | v1alpha | | | +| updateRiskConfig | v1alpha | | | +| users.clearConversationHistory | v1alpha | | | +| users.conversations.create | v1alpha | chronicle.gemini.create_conversation | | +| users.conversations.delete | v1alpha | | | +| users.conversations.get | v1alpha | | | +| users.conversations.list | v1alpha | | | +| users.conversations.messages.create | v1alpha | chronicle.gemini.query_gemini | secops gemini | +| users.conversations.messages.delete | v1alpha | | | +| users.conversations.messages.get | v1alpha | | | +| users.conversations.messages.list | v1alpha | | | +| users.conversations.messages.patch | v1alpha | | | +| users.conversations.patch | v1alpha | | | +| users.getPreferenceSet | v1alpha | chronicle.gemini.opt_in_to_gemini | secops gemini --opt-in | +| users.searchQueries.create | v1alpha | | | +| users.searchQueries.delete | v1alpha | | | +| users.searchQueries.get | v1alpha | | | +| users.searchQueries.list | v1alpha | | | +| users.searchQueries.patch | v1alpha | | | +| users.updatePreferenceSet | v1alpha | | | +| validateQuery | v1alpha | chronicle.validate.validate_query | | +| verifyReferenceList | v1alpha | | | +| verifyRuleText | v1alpha | chronicle.rule_validation.validate_rule | secops rule validate | +| watchlists.create | v1alpha | | | +| watchlists.delete | v1alpha | | | +| watchlists.entities.add | v1alpha | | | +| watchlists.entities.batchAdd | v1alpha | | | +| watchlists.entities.batchRemove | v1alpha | | | +| watchlists.entities.remove | v1alpha | | | +| watchlists.get | v1alpha | | | +| watchlists.list | v1alpha | | | +| watchlists.listEntities | v1alpha | | | +| watchlists.patch | v1alpha | | | diff --git a/src/secops/cli.py b/src/secops/cli.py index 0b4c2cc9..62c547c2 100644 --- a/src/secops/cli.py +++ b/src/secops/cli.py @@ -4770,6 +4770,255 @@ def handle_forwarder_delete_command(args, chronicle): sys.exit(1) +# --- Curated rule set commands --- + + +def setup_curated_rules_command(subparsers): + """Set up the curated-rule command group.""" + top = subparsers.add_parser( + "curated-rule", help="Manage curated rules and rule sets" + ) + lvl1 = top.add_subparsers(dest="curated_cmd", required=True) + + # ---- rules ---- + rules = lvl1.add_parser("rule", help="Manage curated rules") + rules_sp = rules.add_subparsers(dest="rule_cmd", required=True) + + rules_list = rules_sp.add_parser("list", help="List curated rules") + rules_list.set_defaults(func=handle_curated_rules_rules_list_command) + + rules_get = rules_sp.add_parser("get", help="Get a curated rule") + rg = rules_get.add_mutually_exclusive_group(required=True) + rg.add_argument("--id", help="Rule UUID (e.g., ur_abc...)") + rg.add_argument("--name", help="Rule display name") + rules_get.set_defaults(func=handle_curated_rules_rules_get_command) + + # ---- rule-set ---- + rule_set = lvl1.add_parser("rule-set", help="Manage curated rule sets") + rule_set_subparser = rule_set.add_subparsers(dest="rset_cmd", required=True) + + rule_set_list = rule_set_subparser.add_parser( + "list", help="List curated rule sets" + ) + rule_set_list.set_defaults(func=handle_curated_rules_rule_set_list_command) + + rule_set_get = rule_set_subparser.add_parser( + "get", help="Get a curated rule set" + ) + rule_set_get.add_argument( + "--id", required=True, help="Curated rule set UUID)" + ) + rule_set_get.set_defaults(func=handle_curated_rules_rule_set_get_command) + + # ---- rule-set-category ---- + rule_set_cat = lvl1.add_parser( + "rule-set-category", help="Manage curated rule set categories" + ) + rule_set_cat_subparser = rule_set_cat.add_subparsers( + dest="rcat_cmd", required=True + ) + + rule_set_cat_list = rule_set_cat_subparser.add_parser( + "list", help="List curated rule set categories" + ) + rule_set_cat_list.set_defaults( + func=handle_curated_rules_rule_set_category_list_command + ) + + rule_set_cat_get = rule_set_cat_subparser.add_parser( + "get", help="Get a curated rule set category" + ) + rule_set_cat_get.add_argument("--id", required=True, help="Category UUID") + rule_set_cat_get.set_defaults( + func=handle_curated_rules_rule_set_category_get_command + ) + + # ---- rule-set-deployment ---- + rule_set_deployment = lvl1.add_parser( + "rule-set-deployment", help="Manage curated rule set deployments" + ) + rule_set_deployment_subparser = rule_set_deployment.add_subparsers( + dest="rdep_cmd", required=True + ) + + rule_set_deployment_list = rule_set_deployment_subparser.add_parser( + "list", help="List curated rule set deployments" + ) + rule_set_deployment_list.add_argument( + "--only-enabled", dest="only_enabled", action="store_true" + ) + rule_set_deployment_list.add_argument( + "--only-alerting", dest="only_alerting", action="store_true" + ) + rule_set_deployment_list.set_defaults( + func=handle_curated_rules_rule_set_deployment_list_command + ) + + rule_set_deployment_get = rule_set_deployment_subparser.add_parser( + "get", help="Get a curated rule set deployment" + ) + get_group = rule_set_deployment_get.add_mutually_exclusive_group( + required=True + ) + get_group.add_argument("--id", help="Curated rule set ID (crs_...)") + get_group.add_argument( + "--name", help="Curated rule set display name (case-insensitive)" + ) + rule_set_deployment_get.add_argument( + "--precision", choices=["precise", "broad"], default="precise" + ) + rule_set_deployment_get.set_defaults( + func=handle_curated_rules_rule_set_deployment_get_command + ) + + rule_set_deployment_update = rule_set_deployment_subparser.add_parser( + "update", help="Update a curated rule set deployment" + ) + rule_set_deployment_update.add_argument( + "--category-id", required=True, dest="category_id" + ) + rule_set_deployment_update.add_argument( + "--rule-set-id", required=True, dest="rule_set_id" + ) + rule_set_deployment_update.add_argument( + "--precision", choices=["precise", "broad"], required=True + ) + rule_set_deployment_update.add_argument( + "--enabled", choices=["true", "false"], required=True + ) + rule_set_deployment_update.add_argument( + "--alerting", choices=["true", "false"], help="Enable/disable alerting" + ) + rule_set_deployment_update.set_defaults( + func=handle_curated_rules_rule_set_deployment_update_command + ) + + +# ----------------- handlers ----------------- + + +def handle_curated_rules_rules_list_command(args, chronicle): + """List curated rules.""" + try: + out = chronicle.list_curated_rules() + output_formatter(out, getattr(args, "output", "json")) + except Exception as e: + print(f"Error listing curated rules: {e}", file=sys.stderr) + sys.exit(1) + + +def handle_curated_rules_rules_get_command(args, chronicle): + """Get curated rule by ID or display name.""" + try: + if args.id: + out = chronicle.get_curated_rule(args.id) + else: + # by display name + out = chronicle.get_curated_rule_by_name(args.name) + output_formatter(out, getattr(args, "output", "json")) + except Exception as e: + print(f"Error getting curated rule: {e}", file=sys.stderr) + sys.exit(1) + + +def handle_curated_rules_rule_set_list_command(args, chronicle): + try: + out = chronicle.list_curated_rule_sets() + output_formatter(out, getattr(args, "output", "json")) + except Exception as e: + print(f"Error listing curated rule sets: {e}", file=sys.stderr) + sys.exit(1) + + +def handle_curated_rules_rule_set_get_command(args, chronicle): + try: + out = chronicle.get_curated_rule_set(args.id) + output_formatter(out, getattr(args, "output", "json")) + except Exception as e: + print(f"Error getting curated rule set: {e}", file=sys.stderr) + sys.exit(1) + + +def handle_curated_rules_rule_set_category_list_command(args, chronicle): + try: + out = chronicle.list_curated_rule_set_categories() + output_formatter(out, getattr(args, "output", "json")) + except Exception as e: + print( + f"Error listing curated rule set categories: {e}", file=sys.stderr + ) + sys.exit(1) + + +def handle_curated_rules_rule_set_category_get_command(args, chronicle): + try: + out = chronicle.get_curated_rule_set_category(args.id) + output_formatter(out, getattr(args, "output", "json")) + except Exception as e: + print(f"Error getting curated rule set category: {e}", file=sys.stderr) + sys.exit(1) + + +def handle_curated_rules_rule_set_deployment_list_command(args, chronicle): + try: + out = chronicle.list_curated_rule_set_deployments( + only_enabled=bool(args.only_enabled), + only_alerting=bool(args.only_alerting), + ) + output_formatter(out, getattr(args, "output", "json")) + except Exception as e: + print( + f"Error listing curated rule set deployments: {e}", file=sys.stderr + ) + sys.exit(1) + + +def handle_curated_rules_rule_set_deployment_get_command(args, chronicle): + try: + if args.name: + out = chronicle.get_curated_rule_set_deployment_by_name( + args.name, precision=args.precision + ) + else: + out = chronicle.get_curated_rule_set_deployment( + args.id, precision=args.precision + ) + output_formatter(out, getattr(args, "output", "json")) + except Exception as e: + print( + f"Error getting curated rule set deployment: {e}", file=sys.stderr + ) + sys.exit(1) + + +def handle_curated_rules_rule_set_deployment_update_command(args, chronicle): + """Update curated rule set deployment fields.""" + try: + + def _convert_bool(s): + """Convert "true"/"false" to bool.""" + return None if s is None else str(s).lower() == "true" + + payload = { + "category_id": args.category_id, + "rule_set_id": args.rule_set_id, + "precision": args.precision, + "enabled": _convert_bool(args.enabled), + } + if args.alerting is not None: + payload["alerting"] = _convert_bool(args.alerting) + out = chronicle.update_curated_rule_set_deployment(payload) + output_formatter(out, getattr(args, "output", "json")) + except Exception as e: + print( + f"Error updating curated rule set deployment: {e}", file=sys.stderr + ) + sys.exit(1) + + +# --- --- + + def main() -> None: """Main entry point for the CLI.""" parser = argparse.ArgumentParser(description="Google SecOps CLI") @@ -4802,6 +5051,7 @@ def main() -> None: setup_reference_list_command(subparsers) # Add reference list command setup_rule_exclusion_command(subparsers) # Add rule exclusion command setup_forwarder_command(subparsers) # Add forwarder command + setup_curated_rules_command(subparsers) # Add rule set command setup_config_command(subparsers) setup_help_command(subparsers) setup_dashboard_command(subparsers) @@ -4832,6 +5082,7 @@ def main() -> None: "export", "gemini", "rule-exclusion", + "curated-rule", "forwarder", "dashboard", ] From caa647ee6f0bce6f9af79816b5cf6520c5f0483e Mon Sep 17 00:00:00 2001 From: PaperMtn Date: Tue, 28 Oct 2025 21:20:50 +0000 Subject: [PATCH 23/30] chore: linting fixes --- src/secops/cli.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/secops/cli.py b/src/secops/cli.py index 62c547c2..ddda6082 100644 --- a/src/secops/cli.py +++ b/src/secops/cli.py @@ -4902,7 +4902,7 @@ def handle_curated_rules_rules_list_command(args, chronicle): try: out = chronicle.list_curated_rules() output_formatter(out, getattr(args, "output", "json")) - except Exception as e: + except Exception as e: # pylint: disable=broad-exception-caught print(f"Error listing curated rules: {e}", file=sys.stderr) sys.exit(1) @@ -4916,7 +4916,7 @@ def handle_curated_rules_rules_get_command(args, chronicle): # by display name out = chronicle.get_curated_rule_by_name(args.name) output_formatter(out, getattr(args, "output", "json")) - except Exception as e: + except Exception as e: # pylint: disable=broad-exception-caught print(f"Error getting curated rule: {e}", file=sys.stderr) sys.exit(1) @@ -4925,7 +4925,7 @@ def handle_curated_rules_rule_set_list_command(args, chronicle): try: out = chronicle.list_curated_rule_sets() output_formatter(out, getattr(args, "output", "json")) - except Exception as e: + except Exception as e: # pylint: disable=broad-exception-caught print(f"Error listing curated rule sets: {e}", file=sys.stderr) sys.exit(1) @@ -4934,7 +4934,7 @@ def handle_curated_rules_rule_set_get_command(args, chronicle): try: out = chronicle.get_curated_rule_set(args.id) output_formatter(out, getattr(args, "output", "json")) - except Exception as e: + except Exception as e: # pylint: disable=broad-exception-caught print(f"Error getting curated rule set: {e}", file=sys.stderr) sys.exit(1) @@ -4943,7 +4943,7 @@ def handle_curated_rules_rule_set_category_list_command(args, chronicle): try: out = chronicle.list_curated_rule_set_categories() output_formatter(out, getattr(args, "output", "json")) - except Exception as e: + except Exception as e: # pylint: disable=broad-exception-caught print( f"Error listing curated rule set categories: {e}", file=sys.stderr ) @@ -4954,7 +4954,7 @@ def handle_curated_rules_rule_set_category_get_command(args, chronicle): try: out = chronicle.get_curated_rule_set_category(args.id) output_formatter(out, getattr(args, "output", "json")) - except Exception as e: + except Exception as e: # pylint: disable=broad-exception-caught print(f"Error getting curated rule set category: {e}", file=sys.stderr) sys.exit(1) @@ -4966,7 +4966,7 @@ def handle_curated_rules_rule_set_deployment_list_command(args, chronicle): only_alerting=bool(args.only_alerting), ) output_formatter(out, getattr(args, "output", "json")) - except Exception as e: + except Exception as e: # pylint: disable=broad-exception-caught print( f"Error listing curated rule set deployments: {e}", file=sys.stderr ) @@ -4984,7 +4984,7 @@ def handle_curated_rules_rule_set_deployment_get_command(args, chronicle): args.id, precision=args.precision ) output_formatter(out, getattr(args, "output", "json")) - except Exception as e: + except Exception as e: # pylint: disable=broad-exception-caught print( f"Error getting curated rule set deployment: {e}", file=sys.stderr ) @@ -5009,7 +5009,7 @@ def _convert_bool(s): payload["alerting"] = _convert_bool(args.alerting) out = chronicle.update_curated_rule_set_deployment(payload) output_formatter(out, getattr(args, "output", "json")) - except Exception as e: + except Exception as e: # pylint: disable=broad-exception-caught print( f"Error updating curated rule set deployment: {e}", file=sys.stderr ) From 1deb407ac4b9e7293aa72cb86858ff4afe68eb24 Mon Sep 17 00:00:00 2001 From: PaperMtn Date: Fri, 31 Oct 2025 19:37:55 +0000 Subject: [PATCH 24/30] refactor: modify paginated request to respect page_size --- src/secops/chronicle/client.py | 8 +++---- src/secops/chronicle/rule_set.py | 39 +++++++++++++++++--------------- tests/chronicle/test_rule_set.py | 37 ++++++++++++++++++------------ 3 files changed, 47 insertions(+), 37 deletions(-) diff --git a/src/secops/chronicle/client.py b/src/secops/chronicle/client.py index b6518ba7..176e792d 100644 --- a/src/secops/chronicle/client.py +++ b/src/secops/chronicle/client.py @@ -1744,7 +1744,7 @@ def batch_update_curated_rule_set_deployments( def list_curated_rule_sets( self, - page_size: Optional[str] = None, + page_size: Optional[int] = None, page_token: Optional[str] = None, ) -> List[Dict[str, Any]]: """Get a list of all curated rule sets. @@ -1763,7 +1763,7 @@ def list_curated_rule_sets( def list_curated_rule_set_categories( self, - page_size: Optional[str] = None, + page_size: Optional[int] = None, page_token: Optional[str] = None, ) -> List[Dict[str, Any]]: """Get a list of all curated rule set categories. @@ -1782,7 +1782,7 @@ def list_curated_rule_set_categories( def list_curated_rule_set_deployments( self, - page_size: Optional[str] = None, + page_size: Optional[int] = None, page_token: Optional[str] = None, only_enabled: Optional[bool] = False, only_alerting: Optional[bool] = False, @@ -1848,7 +1848,7 @@ def get_curated_rule_set_deployment_by_name( def list_curated_rules( self, - page_size: Optional[str] = None, + page_size: Optional[int] = None, page_token: Optional[str] = None, ) -> List[Dict[str, Any]]: """Get a list of all curated rules. diff --git a/src/secops/chronicle/rule_set.py b/src/secops/chronicle/rule_set.py index 07f41bc6..afc0a394 100644 --- a/src/secops/chronicle/rule_set.py +++ b/src/secops/chronicle/rule_set.py @@ -24,7 +24,7 @@ def _paginated_request( items_key: str, *, page_size: Optional[int] = None, - start_page_token: Optional[str] = None, + page_token: Optional[str] = None, extra_params: Optional[Dict[str, Any]] = None, ) -> List[Dict[str, Any]]: """ @@ -34,8 +34,8 @@ def _paginated_request( client: ChronicleClient instance path: URL path after {base_url}/{instance_id}/ items_key: JSON key holding the array of items (e.g., 'curatedRules') - page_size: page size (defaults to API max) - start_page_token: if provided, start from this token + page_size: Maximum number of rules to return per page. + page_token: Token for the next page of results, if available. extra_params: extra query params to include on every request Returns: @@ -45,30 +45,33 @@ def _paginated_request( APIError: If the HTTP request fails. """ url = f"{client.base_url}/{client.instance_id}/{path}" - page_token = start_page_token - results = [] + next_token = page_token while True: + # Build params each loop to prevent stale keys being + # included in the next request params = {"pageSize": 1000 if not page_size else page_size} - if page_token: - params["pageToken"] = page_token + if next_token: + params["pageToken"] = next_token if extra_params: - params.update(extra_params) + # copy to avoid passed dict being mutated + params.update(dict(extra_params)) response = client.session.get(url, params=params) if response.status_code != 200: raise APIError(f"Failed to list {items_key}: {response.text}") data = response.json() - if not data: - return results + results.extend(data.get(items_key, [])) - curated_sets = data.get(items_key, []) - results.extend(curated_sets) + # If caller provided page_size, return only this page + if page_size is not None: + break - page_token = data.get("nextPageToken") - if not page_token: + # Otherwise, auto-paginate + next_token = data.get("nextPageToken") + if not next_token: break return results @@ -97,7 +100,7 @@ def list_curated_rule_sets( path="curatedRuleSetCategories/-/curatedRuleSets", items_key="curatedRuleSets", page_size=page_size, - start_page_token=page_token, + page_token=page_token, ) @@ -149,7 +152,7 @@ def list_curated_rule_set_categories( path="curatedRuleSetCategories", items_key="curatedRuleSetCategories", page_size=page_size, - start_page_token=page_token, + page_token=page_token, ) @@ -203,7 +206,7 @@ def list_curated_rules( path="curatedRules", items_key="curatedRules", page_size=page_size, - start_page_token=page_token, + page_token=page_token, ) @@ -287,7 +290,7 @@ def list_curated_rule_set_deployments( "-/curatedRuleSetDeployments", items_key="curatedRuleSetDeployments", page_size=page_size, - start_page_token=page_token, + page_token=page_token, ) # Enrich the deployment data with the rule set displayName diff --git a/tests/chronicle/test_rule_set.py b/tests/chronicle/test_rule_set.py index 5786dc49..f0ad7c0e 100644 --- a/tests/chronicle/test_rule_set.py +++ b/tests/chronicle/test_rule_set.py @@ -117,35 +117,42 @@ def _page(items_key: str, items: list[dict], next_token: Optional[str] = None): # --- _paginated_request tests --- - -def test_paginated_request_success(chronicle_client): - """Test helper function _paginated_request returns a flat list from multiple pages and forwards pageToken.""" +def test_paginated_request_auto_paginates_success(chronicle_client): p1 = _page("curatedRules", [{"name": ".../ur_1"}], next_token="t2") p2 = _page("curatedRules", [{"name": ".../ur_2"}]) - with patch.object( - chronicle_client.session, "get", side_effect=[p1, p2] - ) as mocked_response: + with patch.object(chronicle_client.session, "get", side_effect=[p1, p2]) as mocked: result = _paginated_request( chronicle_client, path="curatedRules", items_key="curatedRules", - page_size=1000, + page_size=None, ) assert [r["name"] for r in result] == [".../ur_1", ".../ur_2"] - base = f"{chronicle_client.base_url}/{chronicle_client.instance_id}/curatedRules" - # first call: only pageSize - assert mocked_response.call_args_list[0].args[0] == base - assert mocked_response.call_args_list[0].kwargs["params"] == { - "pageSize": 1000 - } - # second call includes next token - assert mocked_response.call_args_list[1].kwargs["params"] == { + assert mocked.call_args_list[0].args[0] == base + assert mocked.call_args_list[0].kwargs["params"] == {"pageSize": 1000} + assert mocked.call_args_list[1].kwargs["params"] == { "pageSize": 1000, "pageToken": "t2", } +def test_paginated_request_when_page_size_given_success(chronicle_client): + p1 = _page("curatedRules", [{"name": ".../ur_1"}], next_token="t2") + with patch.object(chronicle_client.session, "get", return_value=p1) as mocked: + result = _paginated_request( + chronicle_client, + path="curatedRules", + items_key="curatedRules", + page_size=1000, + ) + assert [r["name"] for r in result] == [".../ur_1"] + # Only one call, no follow-up with nextPageToken + assert mocked.call_count == 1 + assert mocked.call_args.kwargs["params"] == {"pageSize": 1000} + + + def test_paginated_request_error(chronicle_client, mock_error_response): """Test helper function _paginated_request raises APIError on HTTP errors.""" with patch.object( From 464b74ecbf34d834281392953685d88bcd768f7f Mon Sep 17 00:00:00 2001 From: PaperMtn Date: Fri, 31 Oct 2025 19:48:08 +0000 Subject: [PATCH 25/30] chore: update documentation of get_by_name functions --- README.md | 2 ++ src/secops/chronicle/client.py | 4 ++++ src/secops/chronicle/rule_set.py | 4 ++++ 3 files changed, 10 insertions(+) diff --git a/README.md b/README.md index c87514c1..44dab8a1 100644 --- a/README.md +++ b/README.md @@ -1731,6 +1731,7 @@ for rule in rules: rule = chronicle.get_curated_rule("ur_ttp_lol_Atbroker") # Get a curated rule set by display name +# NOTE: This is a linear scan of all curated rules which may be inefficient for large rule sets. rule_set = chronicle.get_curated_rule_by_name("Atbroker.exe Abuse") ``` @@ -1785,6 +1786,7 @@ for rs_deployment in rule_set_deployments: rule_set_deployment = chronicle.get_curated_rule_set_deployment("00ad672e-ebb3-0dd1-2a4d-99bd7c5e5f93") # Get curated rule set deployment by rule set display name +# NOTE: This is a linear scan of all curated rules which may be inefficient for large rule sets. rule_set_deployment = chronicle.get_curated_rule_set_deployment_by_name("Azure - Network") # Update multiple curated rule set deployments diff --git a/src/secops/chronicle/client.py b/src/secops/chronicle/client.py index 91152d05..ec88989a 100644 --- a/src/secops/chronicle/client.py +++ b/src/secops/chronicle/client.py @@ -1831,6 +1831,8 @@ def get_curated_rule_set_deployment_by_name( precision: str = "precise", ) -> Dict[str, Any]: """Get a curated rule set deployment by human-readable display name + NOTE: This is a linear scan of all curated rules, + so it may be inefficient for large rule sets. Args: display_name: Display name of the curated rule set @@ -1882,6 +1884,8 @@ def get_curated_rule(self, rule_id: str) -> Dict[str, Any]: def get_curated_rule_by_name(self, display_name: str) -> Dict[str, Any]: """Get a curated rule by human-readable display name + NOTE: This is a linear scan of all curated rules, + so it may be inefficient for large rule sets. Args: display_name: Display name of the curated rule diff --git a/src/secops/chronicle/rule_set.py b/src/secops/chronicle/rule_set.py index afc0a394..ab281225 100644 --- a/src/secops/chronicle/rule_set.py +++ b/src/secops/chronicle/rule_set.py @@ -240,6 +240,8 @@ def get_curated_rule(client, rule_id: str) -> Dict[str, Any]: def get_curated_rule_by_name(client, display_name: str) -> Dict[str, Any]: """Get a curated rule by display name + NOTE: This is a linear scan of all curated rules, + so it may be inefficient for large rule sets. Args: client: ChronicleClient instance @@ -380,6 +382,8 @@ def get_curated_rule_set_deployment_by_name( precision: str = "precise", ) -> Dict[str, Any]: """Get the deployment status of a curated rule set by its display name + NOTE: This is a linear scan of all curated rule sets, + so it may be inefficient for large rule sets. Args: client: ChronicleClient instance From cacc3968a87f3a474431d240af5065370f120bc4 Mon Sep 17 00:00:00 2001 From: PaperMtn Date: Fri, 31 Oct 2025 20:10:50 +0000 Subject: [PATCH 26/30] refactor: change get deployment status to use get function instead of listing all rule sets --- src/secops/chronicle/rule_set.py | 11 +-------- tests/chronicle/test_rule_set.py | 42 +++++++++++++++----------------- 2 files changed, 20 insertions(+), 33 deletions(-) diff --git a/src/secops/chronicle/rule_set.py b/src/secops/chronicle/rule_set.py index ab281225..7f1d60d1 100644 --- a/src/secops/chronicle/rule_set.py +++ b/src/secops/chronicle/rule_set.py @@ -347,16 +347,7 @@ def get_curated_rule_set_deployment( raise SecOpsError("Precision must be 'precise' or 'broad'") # Get the rule set by ID - rule_set = next( - ( - rs - for rs in list_curated_rule_sets(client) - if rule_set_id in rs.get("name", "") - ), - None, - ) - if rule_set is None: - raise SecOpsError(f"Rule set {rule_set_id} not found") + rule_set = get_curated_rule_set(client, rule_set_id) url = ( f"{client.base_url}/{rule_set.get('name', '')}/" diff --git a/tests/chronicle/test_rule_set.py b/tests/chronicle/test_rule_set.py index f0ad7c0e..7de438db 100644 --- a/tests/chronicle/test_rule_set.py +++ b/tests/chronicle/test_rule_set.py @@ -370,27 +370,23 @@ def test_list_deployments_success(chronicle_client): def test_get_ruleset_deployment_success(chronicle_client, mock_response): """Test get_curated_rule_set_deployment returns the deployment matching name.""" - rulesets = _page( - "curatedRuleSets", - [ - { - "name": f"{chronicle_client.instance_id}/curatedRuleSetCategories/c1/curatedRuleSets/crs_1", - "displayName": "My Ruleset", - } - ], - ) + ruleset = Mock() + ruleset.status_code = 200 + ruleset.json.return_value = { + "name": f"{chronicle_client.instance_id}/curatedRuleSetCategories/c1/curatedRuleSets/crs_1", + "displayName": "My Ruleset", + } + deployment = Mock() deployment.status_code = 200 deployment.json.return_value = {"enabled": True, "alerting": False} with patch.object( - chronicle_client.session, "get", side_effect=[rulesets, deployment] + chronicle_client.session, "get", side_effect=[ruleset, deployment] ) as mocked_request: - out = get_curated_rule_set_deployment( - chronicle_client, "crs_1", "precise" - ) + out = get_curated_rule_set_deployment(chronicle_client, "crs_1", "precise") assert out["displayName"] == "My Ruleset" - # Second GET is the deployment URL + dep_url = ( f"{chronicle_client.base_url}/" f"{chronicle_client.instance_id}/curatedRuleSetCategories/c1/curatedRuleSets/crs_1/" @@ -406,15 +402,15 @@ def test_get_ruleset_deployment_error_invalid_precision(chronicle_client): def test_get_ruleset_deployment_ruleset_error_not_found(chronicle_client): - """Test get_curated_rule_set_deployment failure.""" - empty_rulesets = _page("curatedRuleSets", []) - with patch.object( - chronicle_client.session, "get", return_value=empty_rulesets - ): - with pytest.raises(SecOpsError): - get_curated_rule_set_deployment( - chronicle_client, "crs_404", "precise" - ) + """Test get_curated_rule_set_deployment failure when ruleset ID doesn't exist.""" + not_found = Mock() + not_found.status_code = 404 + not_found.text = "Not found" + + with patch.object(chronicle_client.session, "get", return_value=not_found): + with pytest.raises(APIError): + get_curated_rule_set_deployment(chronicle_client, "crs_404", "precise") + # --- get_curated_rule_set_deployment_by_name --- From 1a8d4df503f9daa195290eef4f1d3ba8e7ea8c3c Mon Sep 17 00:00:00 2001 From: PaperMtn Date: Fri, 31 Oct 2025 20:52:16 +0000 Subject: [PATCH 27/30] refactor: add pagination args for curated rule list functions --- src/secops/cli.py | 87 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 75 insertions(+), 12 deletions(-) diff --git a/src/secops/cli.py b/src/secops/cli.py index 6f2b2002..2c1aa429 100644 --- a/src/secops/cli.py +++ b/src/secops/cli.py @@ -4845,6 +4845,18 @@ def setup_curated_rules_command(subparsers): rules_sp = rules.add_subparsers(dest="rule_cmd", required=True) rules_list = rules_sp.add_parser("list", help="List curated rules") + rules_list.add_argument( + "--page-size", + type=int, + dest="page_size", + help="The number of results to return per page.", + ) + rules_list.add_argument( + "--page-token", + type=str, + dest="page_token", + help="A page token, received from a previous `list` call.", + ) rules_list.set_defaults(func=handle_curated_rules_rules_list_command) rules_get = rules_sp.add_parser("get", help="Get a curated rule") @@ -4860,6 +4872,18 @@ def setup_curated_rules_command(subparsers): rule_set_list = rule_set_subparser.add_parser( "list", help="List curated rule sets" ) + rule_set_list.add_argument( + "--page-size", + type=int, + dest="page_size", + help="The number of results to return per page.", + ) + rule_set_list.add_argument( + "--page-token", + type=str, + dest="page_token", + help="A page token, received from a previous `list` call.", + ) rule_set_list.set_defaults(func=handle_curated_rules_rule_set_list_command) rule_set_get = rule_set_subparser.add_parser( @@ -4881,6 +4905,18 @@ def setup_curated_rules_command(subparsers): rule_set_cat_list = rule_set_cat_subparser.add_parser( "list", help="List curated rule set categories" ) + rule_set_cat_list.add_argument( + "--page-size", + type=int, + dest="page_size", + help="The number of results to return per page.", + ) + rule_set_cat_list.add_argument( + "--page-token", + type=str, + dest="page_token", + help="A page token, received from a previous `list` call.", + ) rule_set_cat_list.set_defaults( func=handle_curated_rules_rule_set_category_list_command ) @@ -4910,6 +4946,18 @@ def setup_curated_rules_command(subparsers): rule_set_deployment_list.add_argument( "--only-alerting", dest="only_alerting", action="store_true" ) + rule_set_deployment_list.add_argument( + "--page-size", + type=int, + dest="page_size", + help="The number of results to return per page.", + ) + rule_set_deployment_list.add_argument( + "--page-token", + type=str, + dest="page_token", + help="A page token, received from a previous `list` call.", + ) rule_set_deployment_list.set_defaults( func=handle_curated_rules_rule_set_deployment_list_command ) @@ -4960,9 +5008,12 @@ def setup_curated_rules_command(subparsers): def handle_curated_rules_rules_list_command(args, chronicle): """List curated rules.""" try: - out = chronicle.list_curated_rules() + out = chronicle.list_curated_rules( + page_size=getattr(args, "page_size", None), + page_token=getattr(args, "page_token", None), + ) output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught + except Exception as e: # pylint: disable=broad-exception-caught print(f"Error listing curated rules: {e}", file=sys.stderr) sys.exit(1) @@ -4976,34 +5027,43 @@ def handle_curated_rules_rules_get_command(args, chronicle): # by display name out = chronicle.get_curated_rule_by_name(args.name) output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught + except Exception as e: # pylint: disable=broad-exception-caught print(f"Error getting curated rule: {e}", file=sys.stderr) sys.exit(1) def handle_curated_rules_rule_set_list_command(args, chronicle): + """List all curated rule sets""" try: - out = chronicle.list_curated_rule_sets() + out = chronicle.list_curated_rule_sets( + page_size=getattr(args, "page_size", None), + page_token=getattr(args, "page_token", None), + ) output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught + except Exception as e: # pylint: disable=broad-exception-caught print(f"Error listing curated rule sets: {e}", file=sys.stderr) sys.exit(1) def handle_curated_rules_rule_set_get_command(args, chronicle): + """Get curated rule set by ID.""" try: out = chronicle.get_curated_rule_set(args.id) output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught + except Exception as e: # pylint: disable=broad-exception-caught print(f"Error getting curated rule set: {e}", file=sys.stderr) sys.exit(1) def handle_curated_rules_rule_set_category_list_command(args, chronicle): + """List all curated rule set categories.""" try: - out = chronicle.list_curated_rule_set_categories() + out = chronicle.list_curated_rule_set_categories( + page_size=getattr(args, "page_size", None), + page_token=getattr(args, "page_token", None), + ) output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught + except Exception as e: # pylint: disable=broad-exception-caught print( f"Error listing curated rule set categories: {e}", file=sys.stderr ) @@ -5011,10 +5071,11 @@ def handle_curated_rules_rule_set_category_list_command(args, chronicle): def handle_curated_rules_rule_set_category_get_command(args, chronicle): + """Get curated rule set category by ID.""" try: out = chronicle.get_curated_rule_set_category(args.id) output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught + except Exception as e: # pylint: disable=broad-exception-caught print(f"Error getting curated rule set category: {e}", file=sys.stderr) sys.exit(1) @@ -5024,9 +5085,11 @@ def handle_curated_rules_rule_set_deployment_list_command(args, chronicle): out = chronicle.list_curated_rule_set_deployments( only_enabled=bool(args.only_enabled), only_alerting=bool(args.only_alerting), + page_size=getattr(args, "page_size", None), + page_token=getattr(args, "page_token", None), ) output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught + except Exception as e: # pylint: disable=broad-exception-caught print( f"Error listing curated rule set deployments: {e}", file=sys.stderr ) @@ -5044,7 +5107,7 @@ def handle_curated_rules_rule_set_deployment_get_command(args, chronicle): args.id, precision=args.precision ) output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught + except Exception as e: # pylint: disable=broad-exception-caught print( f"Error getting curated rule set deployment: {e}", file=sys.stderr ) @@ -5069,7 +5132,7 @@ def _convert_bool(s): payload["alerting"] = _convert_bool(args.alerting) out = chronicle.update_curated_rule_set_deployment(payload) output_formatter(out, getattr(args, "output", "json")) - except Exception as e: # pylint: disable=broad-exception-caught + except Exception as e: # pylint: disable=broad-exception-caught print( f"Error updating curated rule set deployment: {e}", file=sys.stderr ) From 9deade92c2ecc8b356d85b50f67c1eadcc4edcda Mon Sep 17 00:00:00 2001 From: Mihir Vala <179564180+mihirvala-crestdata@users.noreply.github.com> Date: Mon, 3 Nov 2025 15:47:20 +0530 Subject: [PATCH 28/30] chore: added example usage. Added integration tests --- examples/rule_set_example.py | 727 ++++++++++++++++++ .../test_curated_rule_integration.py | 355 +++++++++ .../cli/test_curated_rule_cli_integration.py | 542 +++++++++++++ 3 files changed, 1624 insertions(+) create mode 100644 examples/rule_set_example.py create mode 100644 tests/chronicle/test_curated_rule_integration.py create mode 100644 tests/cli/test_curated_rule_cli_integration.py diff --git a/examples/rule_set_example.py b/examples/rule_set_example.py new file mode 100644 index 00000000..5014a8cc --- /dev/null +++ b/examples/rule_set_example.py @@ -0,0 +1,727 @@ +#!/usr/bin/env python3 +# 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. +# +"""Example script demonstrating Chronicle Rule Set functionality.""" + +import argparse + + +from secops.chronicle.client import ChronicleClient + + +def get_client(project_id: str, customer_id: str, region: str): + """Initialize and return the Chronicle client. + + Args: + project_id: Google Cloud Project ID + customer_id: Chronicle Customer ID (UUID) + region: Chronicle region (us or eu) + + Returns: + Chronicle client instance + """ + return ChronicleClient( + project_id=project_id, customer_id=customer_id, region=region + ) + + +def example_list_curated_rule_sets(chronicle): + """List all curated rule sets. + + Args: + chronicle: ChronicleClient instance + + Returns: + List of rule set IDs for further operations + """ + print("\n=== List Curated Rule Sets ===") + + try: + rule_sets = chronicle.list_curated_rule_sets(page_size=10) + print(f"\nFound {len(rule_sets)} curated rule sets") + + # Return the first few rule sets for use in other examples + results = [] + for i, rule_set in enumerate(rule_sets[:5]): + # Full name format: projects/PROJECT/locations/LOCATION/curatedRuleSetCategories/CATEGORY_ID/curatedRuleSets/RULE_SET_ID + name = rule_set.get("name", "") + + # Extract rule set ID from the full name + rule_set_id = name.split("/")[-1] if name else "" + + # Extract category ID from the full name + category_parts = name.split("/curatedRuleSets/")[0].split("/") + category_id = category_parts[-1] if len(category_parts) > 1 else "" + + display_name = rule_set.get("displayName", "Unknown") + print(f"- {display_name}: {rule_set_id}") + + results.append( + { + "name": name, + "rule_set_id": rule_set_id, + "category_id": category_id, + "display_name": display_name, + } + ) + + return results + except Exception as e: # pylint: disable=broad-exception-caught + print(f"Error listing curated rule sets: {e}") + return [] + + +def example_get_curated_rule_set(chronicle, rule_set_id): + """Get a specific curated rule set by ID. + + Args: + chronicle: ChronicleClient instance + rule_set_id: ID of the rule set to get + """ + print("\n=== Get Curated Rule Set ===") + + try: + rule_set = chronicle.get_curated_rule_set(rule_set_id) + print("\nCurated Rule Set details:") + print(f"Name: {rule_set.get('name')}") + print(f"Display Name: {rule_set.get('displayName')}") + print(f"Description: {rule_set.get('description')}") + print(f"Category: {rule_set.get('ruleSetCategory')}") + print(f"Rules Count: {len(rule_set.get('ruleIds', []))}") + except Exception as e: # pylint: disable=broad-exception-caught + print(f"Error getting curated rule set: {e}") + + +def example_list_curated_rule_set_categories(chronicle): + """List all curated rule set categories. + + Args: + chronicle: ChronicleClient instance + + Returns: + List of category IDs for further operations + """ + print("\n=== List Curated Rule Set Categories ===") + + try: + categories = chronicle.list_curated_rule_set_categories(page_size=10) + print(f"\nFound {len(categories)} curated rule set categories") + + results = [] + for i, category in enumerate(categories[:5]): + # Full name format: projects/PROJECT/locations/LOCATION/curatedRuleSetCategories/CATEGORY_ID + name = category.get("name", "") + + # Extract category ID from the full name + category_id = name.split("/")[-1] if name else "" + + display_name = category.get("displayName", "Unknown") + print(f"- {display_name}: {category_id}") + + results.append( + { + "name": name, + "category_id": category_id, + "display_name": display_name, + } + ) + + return results + except Exception as e: # pylint: disable=broad-exception-caught + print(f"Error listing curated rule set categories: {e}") + return [] + + +def example_get_curated_rule_set_category(chronicle, category_id): + """Get a specific curated rule set category by ID. + + Args: + chronicle: ChronicleClient instance + category_id: ID of the category to get + """ + print("\n=== Get Curated Rule Set Category ===") + + try: + category = chronicle.get_curated_rule_set_category(category_id) + print("\nCurated Rule Set Category details:") + print(f"Name: {category.get('name')}") + print(f"Display Name: {category.get('displayName')}") + print(f"Description: {category.get('description', 'No description')}") + except Exception as e: # pylint: disable=broad-exception-caught + print(f"Error getting curated rule set category: {e}") + + +def example_list_curated_rules(chronicle): + """List all curated rules. + + Args: + chronicle: ChronicleClient instance + + Returns: + List of rule IDs for further operations + """ + print("\n=== List Curated Rules ===") + + try: + rules = chronicle.list_curated_rules(page_size=10) + print(f"\nFound {len(rules)} curated rules") + + results = [] + for i, rule in enumerate(rules[:5]): + # Full name format: projects/PROJECT/locations/LOCATION/curatedRules/RULE_ID + name = rule.get("name", "") + + # Extract rule ID from the full name + rule_id = name.split("/")[-1] if name else "" + + display_name = rule.get("displayName", "Unknown") + print(f"- {display_name}: {rule_id}") + + results.append( + {"name": name, "rule_id": rule_id, "display_name": display_name} + ) + + return results + except Exception as e: # pylint: disable=broad-exception-caught + print(f"Error listing curated rules: {e}") + return [] + + +def example_get_curated_rule(chronicle, rule_id): + """Get a specific curated rule by ID. + + Args: + chronicle: ChronicleClient instance + rule_id: ID of the rule to get + """ + print("\n=== Get Curated Rule ===") + + try: + rule = chronicle.get_curated_rule(rule_id) + print("\nCurated Rule details:") + print(f"Name: {rule.get('name')}") + print(f"Display Name: {rule.get('displayName')}") + print(f"Description: {rule.get('description')}") + print(f"Severity: {rule.get('severity')}") + print(f"MITRE ATT&CK Tactics: {rule.get('mitreTactics', [])}") + except Exception as e: # pylint: disable=broad-exception-caught + print(f"Error getting curated rule: {e}") + + +def example_get_curated_rule_by_name(chronicle, display_name): + """Get a curated rule by display name. + + Args: + chronicle: ChronicleClient instance + display_name: Display name of the rule to find + """ + print("\n=== Get Curated Rule By Name ===") + + try: + print(f"\nSearching for rule with display name: {display_name}") + rule = chronicle.get_curated_rule_by_name(display_name) + print("\nCurated Rule details:") + print(f"Name: {rule.get('name')}") + print(f"Display Name: {rule.get('displayName')}") + print(f"Description: {rule.get('description')}") + print(f"Severity: {rule.get('severity')}") + except Exception as e: # pylint: disable=broad-exception-caught + print(f"Error getting curated rule by name: {e}") + + +def example_list_curated_rule_set_deployments(chronicle): + """List all curated rule set deployments. + + Args: + chronicle: ChronicleClient instance + + Returns: + Dictionary with rule set ID and deployment details + """ + print("\n=== List Curated Rule Set Deployments ===") + + try: + deployments = chronicle.list_curated_rule_set_deployments( + page_size=10, only_enabled=False + ) + print(f"\nFound {len(deployments)} curated rule set deployments") + + if deployments: + # Return the first deployment for use in other examples + deployment = deployments[0] + + # Full name format: projects/PROJECT/locations/LOCATION/curatedRuleSetCategories/CATEGORY_ID/curatedRuleSets/RULE_SET_ID/curatedRuleSetDeployments/PRECISION + name = deployment.get("name", "") + + # Parse name to extract IDs + parts = name.split("/") + precision = parts[-1] if len(parts) > 0 else "precise" + + # The full rule set path is everything before /curatedRuleSetDeployments/{precision} + rule_set_path = "/".join(parts[:-2]) if len(parts) > 2 else "" + + # Extract rule set ID - it's the part after the last /curatedRuleSets/ segment + rule_set_segments = rule_set_path.split("/curatedRuleSets/") + rule_set_id = ( + rule_set_segments[-1] if len(rule_set_segments) > 1 else "" + ) + + # Extract category ID - it's the part after the last /curatedRuleSetCategories/ but before /curatedRuleSets/ + if len(rule_set_segments) > 1: + category_path = rule_set_segments[0] + category_segments = category_path.split( + "/curatedRuleSetCategories/" + ) + category_id = ( + category_segments[-1] if len(category_segments) > 1 else "" + ) + else: + category_id = "" + + display_name = deployment.get("displayName", "Unknown") + print(f"- {display_name}") + print(f" Enabled: {deployment.get('enabled', False)}") + print(f" Alerting: {deployment.get('alerting', False)}") + print(f" Precision: {deployment.get('precision', 'Unknown')}") + + return { + "name": name, + "rule_set_path": rule_set_path, + "rule_set_id": rule_set_id, + "category_id": category_id, + "display_name": display_name, + "precision": precision, + } + return None + except Exception as e: # pylint: disable=broad-exception-caught + print(f"Error listing curated rule set deployments: {e}") + return None + + +def example_get_curated_rule_set_deployment( + chronicle, rule_set_id, precision="precise" +): + """Get deployment status of a curated rule set by ID. + + Args: + chronicle: ChronicleClient instance + rule_set_id: ID of the rule set + precision: Precision level ("precise" or "broad") + """ + print("\n=== Get Curated Rule Set Deployment ===") + + try: + print(f"\nGetting deployment for rule set ID: {rule_set_id}") + deployment = chronicle.get_curated_rule_set_deployment( + rule_set_id, precision + ) + print("\nDeployment details:") + print(f"Name: {deployment.get('name')}") + print(f"Display Name: {deployment.get('displayName')}") + print(f"Enabled: {deployment.get('enabled', False)}") + print(f"Alerting: {deployment.get('alerting', False)}") + print(f"Precision: {deployment.get('precision')}") + except Exception as e: # pylint: disable=broad-exception-caught + print(f"Error getting curated rule set deployment: {e}") + + +def example_get_curated_rule_set_deployment_by_name( + chronicle, display_name, precision="precise" +): + """Get deployment status of a curated rule set by name. + + Args: + chronicle: ChronicleClient instance + display_name: Display name of the rule set + precision: Precision level ("precise" or "broad") + """ + print("\n=== Get Curated Rule Set Deployment By Name ===") + + try: + print(f"\nGetting deployment for rule set: {display_name}") + deployment = chronicle.get_curated_rule_set_deployment_by_name( + display_name, precision + ) + print("\nDeployment details:") + print(f"Name: {deployment.get('name')}") + print(f"Display Name: {deployment.get('displayName')}") + print(f"Enabled: {deployment.get('enabled', False)}") + print(f"Alerting: {deployment.get('alerting', False)}") + print(f"Precision: {deployment.get('precision')}") + except Exception as e: # pylint: disable=broad-exception-caught + print(f"Error getting curated rule set deployment by name: {e}") + + +def example_update_curated_rule_set_deployment( + chronicle, category_id, rule_set_id, precision="precise" +): + """Update deployment settings of a curated rule set. + + Args: + chronicle: ChronicleClient instance + category_id: ID of the category + rule_set_id: ID of the rule set + precision: Precision level ("precise" or "broad") + + Returns: + Original deployment status for later cleanup + """ + print("\n=== Update Curated Rule Set Deployment ===") + + try: + print(f"\nCategory ID: {category_id}") + print(f"Rule Set ID: {rule_set_id}") + print(f"Precision: {precision}") + + # First get the current deployment state + current = chronicle.get_curated_rule_set_deployment( + rule_set_id, precision + ) + original_state = { + "category_id": category_id, + "rule_set_id": rule_set_id, + "precision": precision, + "enabled": current.get("enabled", False), + "alerting": current.get("alerting", False), + } + print( + f"\nCurrent deployment state: Enabled={original_state['enabled']}, " + f"Alerting={original_state['alerting']}" + ) + + print(f"\nUpdating deployment for rule set ID: {rule_set_id}") + + # Configuration for updating the deployment + deployment_config = { + "category_id": category_id, + "rule_set_id": rule_set_id, + "precision": precision, + "enabled": True, # Enable the rule set + "alerting": True, # Enable alerting for the rule set + } + + # Update the deployment + updated = chronicle.update_curated_rule_set_deployment( + deployment_config + ) + + print("\nUpdated deployment details:") + print(f"Name: {updated.get('name')}") + print(f"Enabled: {updated.get('enabled', False)}") + print(f"Alerting: {updated.get('alerting', False)}") + print(f"Precision: {updated.get('precision')}") + + return original_state + except Exception as e: # pylint: disable=broad-exception-caught + print(f"Error updating curated rule set deployment: {e}") + return None + + +def example_cleanup_rule_set_deployment( + chronicle, category_id, rule_set_id, original_state +): + """Revert deployment settings of a curated rule set to original state. + + Args: + chronicle: ChronicleClient instance + category_id: ID of the category + rule_set_id: ID of the rule set + original_state: Dictionary containing original configuration and states + """ + print("\n=== Cleanup: Revert Rule Set Deployment ===") + + if not original_state: + print("No original state provided, cannot revert") + return + + try: + # Get values from original_state, falling back to parameters if not present + category_id = original_state.get("category_id", category_id) + rule_set_id = original_state.get("rule_set_id", rule_set_id) + precision = original_state.get("precision", "precise") + + print(f"\nReverting deployment for rule set ID: {rule_set_id}") + print( + f"Restoring to: Enabled={original_state.get('enabled', False)}, " + f"Alerting={original_state.get('alerting', False)}" + ) + + # Configuration for reverting the deployment + deployment_config = { + "category_id": category_id, + "rule_set_id": rule_set_id, + "precision": precision, + "enabled": original_state.get("enabled", False), + "alerting": original_state.get("alerting", False), + } + + # Update the deployment back to original state + reverted = chronicle.update_curated_rule_set_deployment( + deployment_config + ) + + print("\nReverted deployment details:") + print(f"Name: {reverted.get('name')}") + print(f"Enabled: {reverted.get('enabled', False)}") + print(f"Alerting: {reverted.get('alerting', False)}") + print(f"Precision: {reverted.get('precision')}") + except Exception as e: # pylint: disable=broad-exception-caught + print(f"Error reverting curated rule set deployment: {e}") + + +# Map of example functions +EXAMPLES = { + "1": example_list_curated_rule_sets, + "2": example_get_curated_rule_set, + "3": example_list_curated_rule_set_categories, + "4": example_get_curated_rule_set_category, + "5": example_list_curated_rules, + "6": example_get_curated_rule, + "7": example_get_curated_rule_by_name, + "8": example_list_curated_rule_set_deployments, + "9": example_get_curated_rule_set_deployment, + "10": example_get_curated_rule_set_deployment_by_name, + "11": example_update_curated_rule_set_deployment, + "12": example_cleanup_rule_set_deployment, +} + + +def main(): + """Main function to run examples.""" + parser = argparse.ArgumentParser( + description="Run Chronicle Rule Set API examples" + ) + parser.add_argument( + "--project_id", required=True, help="Google Cloud Project ID" + ) + parser.add_argument( + "--customer_id", required=True, help="Chronicle Customer ID (UUID)" + ) + parser.add_argument( + "--region", default="us", help="Chronicle region (us or eu)" + ) + parser.add_argument( + "--example", + "-e", + help=( + "Example number to run (1-12). If not specified, runs all examples." + ), + ) + parser.add_argument( + "--rule_name", help="Rule display name for get_by_name examples" + ) + parser.add_argument( + "--rule_set_name", help="Rule set display name for get_by_name examples" + ) + + args = parser.parse_args() + + # Initialize the client + chronicle = get_client(args.project_id, args.customer_id, args.region) + + # Data needed across examples + rule_sets = None + categories = None + rules = None + deployment_info = None + + if args.example: + if args.example not in EXAMPLES: + print( + "Invalid example number. " + f"Available examples: {', '.join(EXAMPLES.keys())}" + ) + return + + # Examples that don't need additional input + if args.example in ["1", "3", "5", "8"]: + if args.example == "1": + rule_sets = EXAMPLES[args.example](chronicle) + elif args.example == "3": + categories = EXAMPLES[args.example](chronicle) + elif args.example == "5": + rules = EXAMPLES[args.example](chronicle) + elif args.example == "8": + deployment_info = EXAMPLES[args.example](chronicle) + + # Examples that need rule_set_id + elif args.example == "2": + if not rule_sets: + rule_sets = example_list_curated_rule_sets(chronicle) + + if rule_sets: + EXAMPLES[args.example](chronicle, rule_sets[0]["rule_set_id"]) + + # Examples that need category_id + elif args.example == "4": + if not categories: + categories = example_list_curated_rule_set_categories(chronicle) + + if categories: + EXAMPLES[args.example](chronicle, categories[0]["category_id"]) + + # Examples that need rule_id + elif args.example == "6": + if not rules: + rules = example_list_curated_rules(chronicle) + + if rules: + EXAMPLES[args.example](chronicle, rules[0]["rule_id"]) + + # Examples that need rule_name + elif args.example == "7": + EXAMPLES[args.example](chronicle, args.rule_name) + + # Examples that need rule_set_id and precision + elif args.example == "9": + if not rule_sets: + rule_sets = example_list_curated_rule_sets(chronicle) + + if rule_sets: + EXAMPLES[args.example](chronicle, rule_sets[0]["rule_set_id"]) + + # Examples that need rule_set_name and precision + elif args.example == "10": + EXAMPLES[args.example](chronicle, args.rule_set_name) + + # Examples that need category_id, rule_set_id and precision + elif args.example == "11": + if not rule_sets: + rule_sets = example_list_curated_rule_sets(chronicle) + + if rule_sets: + original_state = EXAMPLES[args.example]( + chronicle, + rule_sets[0]["category_id"], + rule_sets[0]["rule_set_id"], + ) + # Perform cleanup after update + if original_state and args.example != "12": + example_cleanup_rule_set_deployment( + chronicle, + rule_sets[0]["category_id"], + rule_sets[0]["rule_set_id"], + original_state, + ) + else: + # Run all examples in order + print("\nRunning all Rule Set examples...") + + # Examples that return data we need for other examples + rule_sets = example_list_curated_rule_sets(chronicle) + categories = example_list_curated_rule_set_categories(chronicle) + rules = example_list_curated_rules(chronicle) + deployment_info = example_list_curated_rule_set_deployments(chronicle) + + # If we have the needed data, run the dependent examples + if rule_sets and len(rule_sets) > 0: + print( + f"\nUsing rule set: {rule_sets[0]['display_name']} (ID: {rule_sets[0]['rule_set_id']})" + ) + example_get_curated_rule_set(chronicle, rule_sets[0]["rule_set_id"]) + + if categories and len(categories) > 0: + print( + f"\nUsing category: {categories[0]['display_name']} (ID: {categories[0]['category_id']})" + ) + example_get_curated_rule_set_category( + chronicle, categories[0]["category_id"] + ) + + if rules and len(rules) > 0: + print( + f"\nUsing rule: {rules[0]['display_name']} (ID: {rules[0]['rule_id']})" + ) + example_get_curated_rule(chronicle, rules[0]["rule_id"]) + + # Examples that use display names (prioritize arguments, fallback to list results) + # For curated rule by name + if args.rule_name: + # Use the user-provided rule name + print( + f"\nLooking up rule by display name: {args.rule_name} (user-provided)" + ) + rule_display_name = args.rule_name + elif rules and len(rules) > 0: + # Fallback: use the display name from the first rule in the list + rule_display_name = rules[0]["display_name"] + print( + f"\nLooking up rule by display name: {rule_display_name} (from list)" + ) + else: + # Default fallback + rule_display_name = "Remote Code Execution via Web Request" + print( + f"\nLooking up rule by display name: {rule_display_name} (default)" + ) + + example_get_curated_rule_by_name(chronicle, rule_display_name) + + # For curated rule set deployment by name + if args.rule_set_name: + # Use the user-provided rule set name + print( + f"\nLooking up rule set deployment by name: {args.rule_set_name} (user-provided)" + ) + rule_set_display_name = args.rule_set_name + elif rule_sets and len(rule_sets) > 0: + # Fallback: use the display name from the first rule set in the list + rule_set_display_name = rule_sets[0]["display_name"] + print( + f"\nLooking up rule set deployment by name: {rule_set_display_name} (from list)" + ) + else: + # Default fallback + rule_set_display_name = "Cloud Security" + print( + f"\nLooking up rule set deployment by name: {rule_set_display_name} (default)" + ) + + example_get_curated_rule_set_deployment_by_name( + chronicle, rule_set_display_name + ) + + # Examples that need data from other examples + if rule_sets and len(rule_sets) > 0: + example_get_curated_rule_set_deployment( + chronicle, rule_sets[0]["rule_set_id"] + ) + + # Update example only if we have all the data + if rule_sets and len(rule_sets) > 0: + print( + f"\nUpdating and then reverting rule set: {rule_sets[0]['display_name']}" + ) + print(f"Category ID: {rule_sets[0]['category_id']}") + print(f"Rule set ID: {rule_sets[0]['rule_set_id']}") + + original_state = example_update_curated_rule_set_deployment( + chronicle, + rule_sets[0]["category_id"], + rule_sets[0]["rule_set_id"], + ) + + # Cleanup after update + if original_state: + example_cleanup_rule_set_deployment( + chronicle, + rule_sets[0]["category_id"], + rule_sets[0]["rule_set_id"], + original_state, + ) + + +if __name__ == "__main__": + main() diff --git a/tests/chronicle/test_curated_rule_integration.py b/tests/chronicle/test_curated_rule_integration.py new file mode 100644 index 00000000..cb96c33a --- /dev/null +++ b/tests/chronicle/test_curated_rule_integration.py @@ -0,0 +1,355 @@ +# 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 tests for curated rule set functionality in Chronicle API. + +These tests require valid credentials and API access. +""" +import pytest + +from secops import SecOpsClient + +from ..config import CHRONICLE_CONFIG, SERVICE_ACCOUNT_JSON + + +@pytest.fixture(scope="module") +def chronicle(): + """Fixture to create a Chronicle client for testing.""" + client = SecOpsClient(service_account_info=SERVICE_ACCOUNT_JSON) + return client.chronicle(**CHRONICLE_CONFIG) + + +@pytest.mark.integration +def test_curated_rule_sets(chronicle): + """Test listing and retrieving curated rule sets.""" + # Test basic listing + rule_sets = chronicle.list_curated_rule_sets() + assert isinstance(rule_sets, list) + assert len(rule_sets) > 0, "Expected at least one curated rule set to exist" + + # Test with pagination parameters + page_size = 5 + rule_sets_paged = chronicle.list_curated_rule_sets(page_size=page_size) + assert isinstance(rule_sets_paged, list) + assert len(rule_sets_paged) <= page_size + + # Keep first rule set for get test and later use in other tests + first_rule_set = rule_sets[0] + assert "name" in first_rule_set + assert "displayName" in first_rule_set + + # Extract rule set ID from the name field + rule_set_id = first_rule_set["name"].split("/")[-1] + assert rule_set_id, "Failed to extract rule set ID from name" + + # Test get operation + print(f"\nTesting get_curated_rule_set with ID: {rule_set_id}") + rule_set = chronicle.get_curated_rule_set(rule_set_id) + assert rule_set["name"] == first_rule_set["name"] + assert rule_set["displayName"] == first_rule_set["displayName"] + + return first_rule_set + + +@pytest.mark.integration +def test_curated_rule_set_categories(chronicle): + """Test listing and retrieving curated rule set categories.""" + # Test basic listing + categories = chronicle.list_curated_rule_set_categories() + assert isinstance(categories, list) + assert len(categories) > 0, "Expected at least one category to exist" + + # Test with pagination parameters + page_size = 5 + categories_paged = chronicle.list_curated_rule_set_categories( + page_size=page_size + ) + assert isinstance(categories_paged, list) + assert len(categories_paged) <= page_size + + # Keep first category for get test and later use in other tests + first_category = categories[0] + assert "name" in first_category + assert "displayName" in first_category + + # Extract category ID from the name field + category_id = first_category["name"].split("/")[-1] + assert category_id, "Failed to extract category ID from name" + + # Test get operation + print(f"\nTesting get_curated_rule_set_category with ID: {category_id}") + category = chronicle.get_curated_rule_set_category(category_id) + assert category["name"] == first_category["name"] + assert category["displayName"] == first_category["displayName"] + + return first_category + + +@pytest.mark.integration +def test_curated_rules(chronicle): + """Test listing and retrieving curated rules.""" + # Test basic listing + rules = chronicle.list_curated_rules() + assert isinstance(rules, list) + assert len(rules) > 0, "Expected at least one curated rule to exist" + + # Test with pagination parameters + page_size = 5 + rules_paged = chronicle.list_curated_rules(page_size=page_size) + assert isinstance(rules_paged, list) + assert len(rules_paged) <= page_size + + # Keep first rule for get tests and later use in other tests + first_rule = rules[0] + assert "name" in first_rule + assert "displayName" in first_rule + + # Extract rule ID from the name field + rule_id = first_rule["name"].split("/")[-1] + assert rule_id, "Failed to extract rule ID from name" + + # Test get operation by ID + print(f"\nTesting get_curated_rule with ID: {rule_id}") + rule = chronicle.get_curated_rule(rule_id) + assert rule["name"] == first_rule["name"] + assert rule["displayName"] == first_rule["displayName"] + + # Test get operation by display name + display_name = first_rule["displayName"] + print(f"\nTesting get_curated_rule_by_name with name: {display_name}") + rule_by_name = chronicle.get_curated_rule_by_name(display_name) + assert rule_by_name["name"] == first_rule["name"] + assert rule_by_name["displayName"].lower() == display_name.lower() + + return first_rule + + +@pytest.mark.integration +def test_curated_rule_set_deployments(chronicle): + """Test listing and retrieving curated rule set deployments.""" + # Part 1: Test listing deployments + print("\nTesting list_curated_rule_set_deployments") + deployments = chronicle.list_curated_rule_set_deployments() + assert isinstance(deployments, list) + + if not deployments: + pytest.skip("No rule set deployments found to test with") + + # Test with filters + enabled_deployments = chronicle.list_curated_rule_set_deployments( + only_enabled=True + ) + assert isinstance(enabled_deployments, list) + for deployment in enabled_deployments: + assert deployment.get("enabled") is True + + alerting_deployments = chronicle.list_curated_rule_set_deployments( + only_alerting=True + ) + assert isinstance(alerting_deployments, list) + for deployment in alerting_deployments: + assert deployment.get("alerting") is True + + # Test with pagination parameters + page_size = 5 + deployments_paged = chronicle.list_curated_rule_set_deployments( + page_size=page_size + ) + assert isinstance(deployments_paged, list) + assert len(deployments_paged) <= page_size + + # Keep first deployment for reference + first_deployment = deployments[0] + assert "name" in first_deployment + assert "displayName" in first_deployment + + # Part 2: Test getting deployment by rule set ID and precision + print("\nTesting get_curated_rule_set_deployment") + rule_sets = chronicle.list_curated_rule_sets() + assert rule_sets, "No rule sets found to test with" + + # Get the first rule set's ID + first_rule_set = rule_sets[0] + rule_set_id = first_rule_set["name"].split("/")[-1] + + # Try to get deployment for both precision levels + deployment_found = False + for precision in ["precise", "broad"]: + try: + deployment = chronicle.get_curated_rule_set_deployment( + rule_set_id, precision + ) + print(f"Found {precision} deployment for rule set {rule_set_id}") + assert "name" in deployment + assert "displayName" in deployment + # Ensure the precision in the response matches what we requested + assert deployment.get("precision", "").upper() == precision.upper() + deployment_found = True + break # If we succeed with either precision, continue to next test + except Exception as e: + # Some rule sets might not have deployments for both precision levels + print(f"No {precision} deployment for rule set {rule_set_id}: {e}") + + if not deployment_found: + pytest.skip("No deployments found for any rule sets") + + # Part 3: Test getting deployment by display name and precision + print("\nTesting get_curated_rule_set_deployment_by_name") + display_name = first_rule_set["displayName"] + + # Try to get deployment by display name for both precision levels + found_by_name = False + for precision in ["precise", "broad"]: + try: + deployment_by_name = ( + chronicle.get_curated_rule_set_deployment_by_name( + display_name, precision + ) + ) + print(f"Found {precision} deployment for rule set '{display_name}'") + assert "name" in deployment_by_name + assert ( + deployment_by_name.get("displayName").lower() + == display_name.lower() + ) + # Ensure the precision in the response matches what we requested + assert ( + deployment_by_name.get("precision", "").upper() + == precision.upper() + ) + found_by_name = True + break # If we succeed with either precision, that's enough + except Exception as e: + print( + f"No {precision} deployment for rule set '{display_name}': {e}" + ) + + if not found_by_name: + pytest.skip(f"No deployments found for rule set '{display_name}'") + + return first_deployment + + +@pytest.mark.integration +def test_update_curated_rule_set_deployment(chronicle): + """Test updating and restoring a curated rule set deployment.""" + print("\nTesting update_curated_rule_set_deployment lifecycle") + + # 1. Find valid rule set and category IDs + rule_sets = chronicle.list_curated_rule_sets() + assert rule_sets, "No rule sets found to test with" + + # Get a rule set ID + first_rule_set = rule_sets[0] + rule_set_name = first_rule_set["name"] + rule_set_id = rule_set_name.split("/")[-1] + + # Extract category ID from rule set name + # Format: projects/PROJECT/locations/LOCATION/curatedRuleSetCategories/CATEGORY_ID/curatedRuleSets/RULE_SET_ID + name_parts = rule_set_name.split("/") + category_index = name_parts.index("curatedRuleSetCategories") + category_id = name_parts[category_index + 1] + + print( + f"Using rule set: {first_rule_set['displayName']} (ID: {rule_set_id})" + ) + print(f"Category ID: {category_id}") + + # Try both precision levels to find one that works + deployment_found = False + precision = None + current = None + + for prec in ["precise", "broad"]: + try: + current = chronicle.get_curated_rule_set_deployment( + rule_set_id, prec + ) + deployment_found = True + precision = prec + print(f"Found {prec} deployment for rule set {rule_set_id}") + break + except Exception as e: + print(f"No {prec} deployment available: {e}") + + if not deployment_found: + pytest.skip(f"No deployments found for rule set {rule_set_id}") + + # Save original state for restoration + original_enabled = current.get("enabled") + original_alerting = current.get("alerting") + + if original_enabled is None or original_alerting is None: + pytest.skip("Original state not found") + + print( + f"Original state - enabled: {original_enabled}, alerting: {original_alerting}" + ) + + try: + # Define the deployment configuration with opposite values + deployment_config = { + "category_id": category_id, + "rule_set_id": rule_set_id, + "precision": precision, + "enabled": not original_enabled, + "alerting": not original_alerting, + } + + print( + f"Updating to - enabled: {not original_enabled}, alerting: {not original_alerting}" + ) + + # Update the deployment + updated = chronicle.update_curated_rule_set_deployment( + deployment_config + ) + print("Update successful") + + # Verify the update + assert updated is not None + + # Double-check by getting the deployment again + updated_get = chronicle.get_curated_rule_set_deployment( + rule_set_id, precision + ) + if "enabled" in updated_get: + assert updated_get.get("enabled") == (not original_enabled) + + if "alerting" in updated_get: + assert updated_get.get("alerting") == (not original_alerting) + + finally: + # Always restore the original state + try: + print( + f"Restoring to original state - enabled: {original_enabled}, alerting: {original_alerting}" + ) + restore_config = { + "category_id": category_id, + "rule_set_id": rule_set_id, + "precision": precision, + "enabled": original_enabled, + "alerting": original_alerting, + } + + chronicle.update_curated_rule_set_deployment(restore_config) + print(f"Successfully restored deployment to original state") + except Exception as cleanup_error: + print(f"Warning: Failed to restore original state: {cleanup_error}") + + +if __name__ == "__main__": + # This allows running the tests directly from this file + pytest.main(["-v", __file__, "-m", "integration"]) diff --git a/tests/cli/test_curated_rule_cli_integration.py b/tests/cli/test_curated_rule_cli_integration.py new file mode 100644 index 00000000..0b0e486f --- /dev/null +++ b/tests/cli/test_curated_rule_cli_integration.py @@ -0,0 +1,542 @@ +# 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. +# +"""CLI Integration tests for curated rule set functionality in Chronicle. + +These tests require valid credentials and API access. +""" +import json +import pytest +import subprocess + + +@pytest.mark.integration +def test_cli_curated_rule_sets(cli_env, common_args): + """Test CLI commands for listing and getting curated rule sets. + + Args: + cli_env: Environment variables for CLI execution. + common_args: Common CLI arguments. + """ + print("\nTesting rule-set list and get commands") + + # Test list command + print("1. Listing curated rule sets") + list_cmd = ( + [ + "secops", + ] + + common_args + + ["curated-rule", "rule-set", "list"] + ) + + list_result = subprocess.run( + list_cmd, env=cli_env, capture_output=True, text=True + ) + + # Check that the command executed successfully + assert list_result.returncode == 0, f"Command failed: {list_result.stderr}" + + # Parse the output + rule_sets = json.loads(list_result.stdout) + assert isinstance(rule_sets, list), "Expected a list of rule sets" + assert len(rule_sets) > 0, "Expected at least one rule set" + + # Check structure of first rule set + first_rule_set = rule_sets[0] + assert "name" in first_rule_set, "Missing name in rule set" + assert "displayName" in first_rule_set, "Missing displayName in rule set" + + # Extract rule set ID from first result + rule_set_id = first_rule_set["name"].split("/")[-1] + print( + f"Found rule set: {first_rule_set['displayName']} (ID: {rule_set_id})" + ) + + # Test get command with the extracted ID + print("\n2. Getting specific rule set by ID") + get_cmd = ( + [ + "secops", + ] + + common_args + + [ + "curated-rule", + "rule-set", + "get", + "--id", # parameter is --id, not --rule-set-id + rule_set_id, + ] + ) + + get_result = subprocess.run( + get_cmd, env=cli_env, capture_output=True, text=True + ) + + # Check that the command executed successfully + assert get_result.returncode == 0, f"Command failed: {get_result.stderr}" + + # Parse and verify the output + rule_set_data = json.loads(get_result.stdout) + assert ( + rule_set_data["name"] == first_rule_set["name"] + ), "Rule set name doesn't match" + assert ( + rule_set_data["displayName"] == first_rule_set["displayName"] + ), "Rule set display name doesn't match" + + return rule_set_id, first_rule_set["displayName"] + + +@pytest.mark.integration +def test_cli_curated_rule_set_categories(cli_env, common_args): + """Test CLI commands for listing and getting curated rule set categories. + + Args: + cli_env: Environment variables for CLI execution. + common_args: Common CLI arguments. + """ + print("\nTesting rule-set categories commands") + + # Test list categories command + print("1. Listing curated rule set categories") + list_cmd = ( + [ + "secops", + ] + + common_args + + ["curated-rule", "rule-set-category", "list"] + ) + + list_result = subprocess.run( + list_cmd, env=cli_env, capture_output=True, text=True + ) + + # Check that the command executed successfully + assert list_result.returncode == 0, f"Command failed: {list_result.stderr}" + + # Parse the output + categories = json.loads(list_result.stdout) + assert isinstance(categories, list), "Expected a list of categories" + assert len(categories) > 0, "Expected at least one category" + + # Check structure of first category + first_category = categories[0] + assert "name" in first_category, "Missing name in category" + assert "displayName" in first_category, "Missing displayName in category" + + # Extract category ID from first result + category_id = first_category["name"].split("/")[-1] + print( + f"Found category: {first_category['displayName']} (ID: {category_id})" + ) + + # Test get category command + print("\n2. Getting specific category by ID") + get_cmd = ( + [ + "secops", + ] + + common_args + + [ + "curated-rule", + "rule-set-category", + "get", + "--id", # parameter is --id, not --category-id + category_id, + ] + ) + + get_result = subprocess.run( + get_cmd, env=cli_env, capture_output=True, text=True + ) + + # Check that the command executed successfully + assert get_result.returncode == 0, f"Command failed: {get_result.stderr}" + + # Parse and verify the output + category_data = json.loads(get_result.stdout) + assert ( + category_data["name"] == first_category["name"] + ), "Category name doesn't match" + assert ( + category_data["displayName"] == first_category["displayName"] + ), "Category display name doesn't match" + + return category_id, first_category["displayName"] + + +@pytest.mark.integration +def test_cli_curated_rules(cli_env, common_args): + """Test CLI commands for listing and getting curated rules. + + Args: + cli_env: Environment variables for CLI execution. + common_args: Common CLI arguments. + """ + print("\nTesting curated rules commands") + + # List curated rules + print("1. Listing curated rules") + list_cmd = ( + [ + "secops", + ] + + common_args + + ["curated-rule", "rule", "list"] + ) + + list_result = subprocess.run( + list_cmd, env=cli_env, capture_output=True, text=True + ) + + # Check that the command executed successfully + assert list_result.returncode == 0, f"Command failed: {list_result.stderr}" + + # Parse the output + rules = json.loads(list_result.stdout) + assert isinstance(rules, list), "Expected a list of rules" + assert len(rules) > 0, "Expected at least one rule" + + # Check structure of first rule + first_rule = rules[0] + assert "name" in first_rule, "Missing name in rule" + assert "displayName" in first_rule, "Missing displayName in rule" + + # Extract rule ID and display name + rule_id = first_rule["name"].split("/")[-1] + display_name = first_rule["displayName"] + print(f"Found rule: {display_name} (ID: {rule_id})") + + # Get rule by ID + print("\n2. Getting specific rule by ID") + get_cmd = ( + [ + "secops", + ] + + common_args + + [ + "curated-rule", + "rule", + "get", + "--id", # parameter is --id, not --rule-id + rule_id, + ] + ) + + get_result = subprocess.run( + get_cmd, env=cli_env, capture_output=True, text=True + ) + + # Check that the command executed successfully + assert get_result.returncode == 0, f"Command failed: {get_result.stderr}" + + # Parse and verify the output + rule_data = json.loads(get_result.stdout) + assert rule_data["name"] == first_rule["name"], "Rule name doesn't match" + assert ( + rule_data["displayName"] == first_rule["displayName"] + ), "Rule display name doesn't match" + + # Get rule by display name + print(f"\n3. Getting rule by display name: {display_name}") + # Need to quote the display name to handle spaces and special characters + name_cmd = ( + [ + "secops", + ] + + common_args + + [ + "curated-rule", + "rule", + "get", + "--name", # Use --name instead of ID + f"{display_name}", + ] + ) + + name_result = subprocess.run( + name_cmd, env=cli_env, capture_output=True, text=True + ) + + # Check that the command executed successfully + assert name_result.returncode == 0, f"Command failed: {name_result.stderr}" + + # Parse and verify the output + rule_by_name_data = json.loads(name_result.stdout) + assert ( + rule_by_name_data["name"] == first_rule["name"] + ), "Rule name doesn't match" + assert ( + rule_by_name_data["displayName"].lower() == display_name.lower() + ), "Rule display name doesn't match" + + return rule_id, display_name + + +@pytest.mark.integration +def test_cli_curated_rule_set_deployments(cli_env, common_args): + """Test CLI commands for listing, getting, and updating curated rule set deployments. + + Args: + cli_env: Environment variables for CLI execution. + common_args: Common CLI arguments. + """ + print("\nTesting rule-set deployment commands") + + # Part 1: List deployments + print("1. Listing curated rule set deployments") + list_cmd = ( + [ + "secops", + ] + + common_args + + ["curated-rule", "rule-set-deployment", "list"] + ) + + list_result = subprocess.run( + list_cmd, env=cli_env, capture_output=True, text=True + ) + + # Check that the command executed successfully + assert list_result.returncode == 0, f"Command failed: {list_result.stderr}" + + # Parse the output + deployments = json.loads(list_result.stdout) + assert isinstance(deployments, list), "Expected a list of deployments" + + # Part 2: Get rule set for testing + print("\n2. First list rule sets to get a valid ID") + list_rs_cmd = ( + [ + "secops", + ] + + common_args + + ["curated-rule", "rule-set", "list"] + ) + + list_rs_result = subprocess.run( + list_rs_cmd, env=cli_env, capture_output=True, text=True + ) + + # Check that the command executed successfully + assert ( + list_rs_result.returncode == 0 + ), f"Command failed: {list_rs_result.stderr}" + + # Parse the output + rule_sets = json.loads(list_rs_result.stdout) + assert len(rule_sets) > 0, "No rule sets found for testing" + + # Get first rule set metadata + first_rule_set = rule_sets[0] + rule_set_name = first_rule_set["name"] + rule_set_id = rule_set_name.split("/")[-1] + display_name = first_rule_set["displayName"] + print(f"Using rule set: {display_name} (ID: {rule_set_id})") + + # Extract category ID from the rule set name + try: + # Format: projects/PROJECT/locations/LOCATION/curatedRuleSetCategories/CATEGORY_ID/curatedRuleSets/RULE_SET_ID + name_parts = rule_set_name.split("/") + category_index = name_parts.index("curatedRuleSetCategories") + category_id = name_parts[category_index + 1] + print(f"Category ID: {category_id}") + except (ValueError, IndexError) as e: + pytest.skip(f"Cannot extract category ID from rule set name: {e}") + + # Part 3: Try to get a deployment + print("\n3. Finding a valid deployment") + deployment_found = False + working_precision = None + + for precision in ["precise", "broad"]: + print(f"Trying {precision} precision...") + get_cmd = ( + [ + "secops", + ] + + common_args + + [ + "curated-rule", + "rule-set-deployment", + "get", + "--id", # parameter is --id, not --rule-set-id + rule_set_id, + "--precision", + precision, + ] + ) + + get_result = subprocess.run( + get_cmd, env=cli_env, capture_output=True, text=True + ) + + if get_result.returncode == 0: + deployment_data = json.loads(get_result.stdout) + assert "name" in deployment_data, "Missing name in deployment" + assert ( + deployment_data.get("precision", "").upper() + == precision.upper() + ) + + # We found a working deployment + deployment_found = True + working_precision = precision + print(f"Found {precision} deployment for rule set {rule_set_id}") + + # Get original state for restoration + original_enabled = deployment_data.get("enabled") + original_alerting = deployment_data.get("alerting") + + if original_enabled is None or original_alerting is None: + print( + "Warning: Couldn't determine original state, skipping update test" + ) + pytest.skip("Original state not available") + + print( + f"Original state - enabled: {original_enabled}, alerting: {original_alerting}" + ) + break + else: + print(f"No {precision} deployment available: {get_result.stderr}") + + if not deployment_found: + pytest.skip(f"No deployments found for rule set {rule_set_id}") + + # Part 4: Test update + print("\n4. Testing update-deployment command") + print( + f"Updating to - enabled: {not original_enabled}, alerting: {not original_alerting}" + ) + + update_cmd = ( + [ + "secops", + ] + + common_args + + [ + "curated-rule", + "rule-set-deployment", + "update", + "--category-id", + category_id, + "--rule-set-id", + rule_set_id, + "--precision", + working_precision, + "--enabled", + str(not original_enabled).lower(), + "--alerting", + str(not original_alerting).lower(), + ] + ) + + try: + update_result = subprocess.run( + update_cmd, env=cli_env, capture_output=True, text=True + ) + + # Check that the command executed successfully + assert ( + update_result.returncode == 0 + ), f"Update failed: {update_result.stderr}" + print("Update command successful") + + # Verify the update worked by getting the deployment again + print("\n5. Verifying the update") + verify_cmd = ( + [ + "secops", + ] + + common_args + + [ + "curated-rule", + "rule-set-deployment", + "get", + "--id", + rule_set_id, + "--precision", + working_precision, + ] + ) + + verify_result = subprocess.run( + verify_cmd, env=cli_env, capture_output=True, text=True + ) + + # Check that the command executed successfully + assert ( + verify_result.returncode == 0 + ), f"Verification failed: {verify_result.stderr}" + + # Parse and verify + verify_data = json.loads(verify_result.stdout) + + # Check only if fields exist, they might not always be updated + if "enabled" in verify_data: + assert verify_data.get("enabled") == ( + not original_enabled + ), "Enabled state not updated" + + if "alerting" in verify_data: + assert verify_data.get("alerting") == ( + not original_alerting + ), "Alerting state not updated" + + print("Update verified successfully") + + finally: + # Part 6: Restore the original state + print("\n6. Restoring original state") + restore_cmd = ( + [ + "secops", + ] + + common_args + + [ + "curated-rule", + "rule-set-deployment", + "update", + "--category-id", + category_id, + "--rule-set-id", + rule_set_id, + "--precision", + working_precision, + "--enabled", + str(original_enabled).lower(), + "--alerting", + str(original_alerting).lower(), + ] + ) + + try: + restore_result = subprocess.run( + restore_cmd, env=cli_env, capture_output=True, text=True + ) + + # Check that the command executed successfully + assert ( + restore_result.returncode == 0 + ), f"Restore failed: {restore_result.stderr}" + print(f"Successfully restored deployment to original state") + except Exception as cleanup_error: + print(f"Warning: Failed to restore original state: {cleanup_error}") + + +if __name__ == "__main__": + # This allows running the tests directly from this file + pytest.main(["-v", __file__, "-m", "integration"]) From 36bfc1247603c922a6fe93f5540134f558870216 Mon Sep 17 00:00:00 2001 From: Mihir Vala <179564180+mihirvala-crestdata@users.noreply.github.com> Date: Mon, 3 Nov 2025 18:20:38 +0530 Subject: [PATCH 29/30] chore: cleanup --- README.md | 2 - api_module_mapping.md | 735 +++++++++++++++---------------- src/secops/chronicle/rule_set.py | 4 +- 3 files changed, 368 insertions(+), 373 deletions(-) diff --git a/README.md b/README.md index 44dab8a1..87e7a204 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,3 @@ -from docutils.nodes import description - # Google SecOps SDK for Python [![PyPI version](https://img.shields.io/pypi/v/secops.svg)](https://pypi.org/project/secops/) diff --git a/api_module_mapping.md b/api_module_mapping.md index 1c58479f..daeb31d2 100644 --- a/api_module_mapping.md +++ b/api_module_mapping.md @@ -1,91 +1,90 @@ # SecOps API Endpoint and SDK Wrapper Module Mapping -Following shows mapping between SecOps [REST Resource](https://cloud.google.com/chronicle/docs/reference/rest) and SDK -wrapper module and its respective CLI command (if available). +Following shows mapping between SecOps [REST Resource](https://cloud.google.com/chronicle/docs/reference/rest) and SDK wrapper module and its respective CLI command (if available). **Note:** All the REST resources mentioned have suffix `projects.locations.instances`. -| REST Resource | Version | secops-wrapper module | CLI Command | -|--------------------------------------------------------------------------------|---------|-------------------------------------------------------------------------------------------------------------------|------------------------------------------------| -| dataAccessLabels.create | v1 | | | -| dataAccessLabels.delete | v1 | | | -| dataAccessLabels.get | v1 | | | -| dataAccessLabels.list | v1 | | | -| dataAccessLabels.patch | v1 | | | -| dataAccessScopes.create | v1 | | | -| dataAccessScopes.delete | v1 | | | -| dataAccessScopes.get | v1 | | | -| dataAccessScopes.list | v1 | | | -| dataAccessScopes.patch | v1 | | | -| get | v1 | | | -| operations.cancel | v1 | | | -| operations.delete | v1 | | | -| operations.get | v1 | | | -| operations.list | v1 | | | -| referenceLists.create | v1 | chronicle.reference_list.create_reference_list | secops reference-list create | -| referenceLists.get | v1 | chronicle.reference_list.get_reference_list | secops reference-list get | -| referenceLists.list | v1 | chronicle.reference_list.list_reference_lists | secops reference-list list | -| referenceLists.patch | v1 | chronicle.reference_list.update_reference_list | secops reference-list update | -| rules.create | v1 | chronicle.rule.create_rule | secops rule create | -| rules.delete | v1 | chronicle.rule.delete_rule | secops rule delete | -| rules.deployments.list | v1 | | | -| rules.get | v1 | chronicle.rule.get_rule | secops rule get | -| rules.getDeployment | v1 | | | -| rules.list | v1 | chronicle.rule.list_rules | secops rule list | -| rules.listRevisions | v1 | | | -| rules.patch | v1 | chronicle.rule.update_rule | secops rule update | -| rules.retrohunts.create | v1 | chronicle.rule_retrohunt.create_retrohunt | | -| rules.retrohunts.get | v1 | chronicle.rule_retrohunt.get_retrohunt | | -| rules.retrohunts.list | v1 | | | -| rules.updateDeployment | v1 | chronicle.rule.enable_rule | secops rule enable | -| watchlists.create | v1 | | | -| watchlists.delete | v1 | | | -| watchlists.get | v1 | | | -| watchlists.list | v1 | | | -| watchlists.patch | v1 | | | -| dataAccessLabels.create | v1beta | | | -| dataAccessLabels.delete | v1beta | | | -| dataAccessLabels.get | v1beta | | | -| dataAccessLabels.list | v1beta | | | -| dataAccessLabels.patch | v1beta | | | -| dataAccessScopes.create | v1beta | | | -| dataAccessScopes.delete | v1beta | | | -| dataAccessScopes.get | v1beta | | | -| dataAccessScopes.list | v1beta | | | -| dataAccessScopes.patch | v1beta | | | -| get | v1beta | | | -| operations.cancel | v1beta | | | -| operations.delete | v1beta | | | -| operations.get | v1beta | | | -| operations.list | v1beta | | | -| referenceLists.create | v1beta | | | -| referenceLists.get | v1beta | | | -| referenceLists.list | v1beta | | | -| referenceLists.patch | v1beta | | | -| rules.create | v1beta | | | -| rules.delete | v1beta | | | -| rules.deployments.list | v1beta | | | -| rules.get | v1beta | | | -| rules.getDeployment | v1beta | | | -| rules.list | v1beta | | | -| rules.listRevisions | v1beta | | | -| rules.patch | v1beta | | | -| rules.retrohunts.create | v1beta | | | -| rules.retrohunts.get | v1beta | | | -| rules.retrohunts.list | v1beta | | | -| rules.updateDeployment | v1beta | | | -| watchlists.create | v1beta | | | -| watchlists.delete | v1beta | | | -| watchlists.get | v1beta | | | -| watchlists.list | v1beta | | | -| watchlists.patch | v1beta | | | -| analytics.entities.analyticValues.list | v1alpha | | | -| analytics.list | v1alpha | | | -| batchValidateWatchlistEntities | v1alpha | | | -| bigQueryAccess.provide | v1alpha | | | -| bigQueryExport.provision | v1alpha | | | -| cases.countPriorities | v1alpha | | | -| curatedRuleSetCategories.curatedRuleSets.curatedRuleSetDeployments.batchUpdate | v1alpha | chronicle.rule_set.batch_update_curated_rule_set_deployments | | +|REST Resource |Version|secops-wrapper module |CLI Command | +|------------------------------------------------------------------------------|-------|------------------------------------------------------------|---------------------------------------| +|dataAccessLabels.create |v1 | | | +|dataAccessLabels.delete |v1 | | | +|dataAccessLabels.get |v1 | | | +|dataAccessLabels.list |v1 | | | +|dataAccessLabels.patch |v1 | | | +|dataAccessScopes.create |v1 | | | +|dataAccessScopes.delete |v1 | | | +|dataAccessScopes.get |v1 | | | +|dataAccessScopes.list |v1 | | | +|dataAccessScopes.patch |v1 | | | +|get |v1 | | | +|operations.cancel |v1 | | | +|operations.delete |v1 | | | +|operations.get |v1 | | | +|operations.list |v1 | | | +|referenceLists.create |v1 |chronicle.reference_list.create_reference_list |secops reference-list create | +|referenceLists.get |v1 |chronicle.reference_list.get_reference_list |secops reference-list get | +|referenceLists.list |v1 |chronicle.reference_list.list_reference_lists |secops reference-list list | +|referenceLists.patch |v1 |chronicle.reference_list.update_reference_list |secops reference-list update | +|rules.create |v1 |chronicle.rule.create_rule |secops rule create | +|rules.delete |v1 |chronicle.rule.delete_rule |secops rule delete | +|rules.deployments.list |v1 | | | +|rules.get |v1 |chronicle.rule.get_rule |secops rule get | +|rules.getDeployment |v1 | | | +|rules.list |v1 |chronicle.rule.list_rules |secops rule list | +|rules.listRevisions |v1 | | | +|rules.patch |v1 |chronicle.rule.update_rule |secops rule update | +|rules.retrohunts.create |v1 |chronicle.rule_retrohunt.create_retrohunt | | +|rules.retrohunts.get |v1 |chronicle.rule_retrohunt.get_retrohunt | | +|rules.retrohunts.list |v1 | | | +|rules.updateDeployment |v1 |chronicle.rule.enable_rule |secops rule enable | +|watchlists.create |v1 | | | +|watchlists.delete |v1 | | | +|watchlists.get |v1 | | | +|watchlists.list |v1 | | | +|watchlists.patch |v1 | | | +|dataAccessLabels.create |v1beta | | | +|dataAccessLabels.delete |v1beta | | | +|dataAccessLabels.get |v1beta | | | +|dataAccessLabels.list |v1beta | | | +|dataAccessLabels.patch |v1beta | | | +|dataAccessScopes.create |v1beta | | | +|dataAccessScopes.delete |v1beta | | | +|dataAccessScopes.get |v1beta | | | +|dataAccessScopes.list |v1beta | | | +|dataAccessScopes.patch |v1beta | | | +|get |v1beta | | | +|operations.cancel |v1beta | | | +|operations.delete |v1beta | | | +|operations.get |v1beta | | | +|operations.list |v1beta | | | +|referenceLists.create |v1beta | | | +|referenceLists.get |v1beta | | | +|referenceLists.list |v1beta | | | +|referenceLists.patch |v1beta | | | +|rules.create |v1beta | | | +|rules.delete |v1beta | | | +|rules.deployments.list |v1beta | | | +|rules.get |v1beta | | | +|rules.getDeployment |v1beta | | | +|rules.list |v1beta | | | +|rules.listRevisions |v1beta | | | +|rules.patch |v1beta | | | +|rules.retrohunts.create |v1beta | | | +|rules.retrohunts.get |v1beta | | | +|rules.retrohunts.list |v1beta | | | +|rules.updateDeployment |v1beta | | | +|watchlists.create |v1beta | | | +|watchlists.delete |v1beta | | | +|watchlists.get |v1beta | | | +|watchlists.list |v1beta | | | +|watchlists.patch |v1beta | | | +|analytics.entities.analyticValues.list |v1alpha| | | +|analytics.list |v1alpha| | | +|batchValidateWatchlistEntities |v1alpha| | | +|bigQueryAccess.provide |v1alpha| | | +|bigQueryExport.provision |v1alpha| | | +|cases.countPriorities |v1alpha| | | +|curatedRuleSetCategories.curatedRuleSets.curatedRuleSetDeployments.batchUpdate | v1alpha | chronicle.rule_set.batch_update_curated_rule_set_deployments | | | curatedRuleSetCategories.curatedRuleSets.curatedRuleSetDeployments.patch | v1alpha | chronicle.rule_set.update_curated_rule_set_deployment | secops curated-rule rule-set-deployment update | | curatedRuleSetCategories.curatedRuleSets.curatedRuleSetDeployments.list | v1alpha | chronicle.rule_set.list_curated_rule_set_deployments | secops curated-rule rule-set-deployment list | | curatedRuleSetCategories.curatedRuleSets.curatedRuleSetDeployments.get | v1alpha | chronicle.rule_set.get_curated_rule_set_deployment
chronicle.rule_set.get_curated_rule_set_deployment_by_name | secops curated-rule rule-set-deployment get | @@ -95,288 +94,288 @@ wrapper module and its respective CLI command (if available). | curatedRuleSetCategories.list | v1alpha | chronicle.rule_set.list_curated_rule_set_categories | secops curated-rule rule-set-category list | | curatedRules.get | v1alpha | chronicle.rule_set.get_curated_rule
chronicle.rule_set.get_curated_rule_by_name | secops curated-rule rule get | | curatedRules.list | v1alpha | chronicle.rule_set.list_curated_rules | secops curated-rule rule list | -| dashboardCharts.batchGet | v1alpha | | | -| dashboardCharts.get | v1alpha | chronicle.dashboard.get_chart | secops dashboard get-chart | -| dashboardQueries.execute | v1alpha | chronicle.dashboard_query.execute_query | secops dashboard-query execute | -| dashboardQueries.get | v1alpha | chronicle.dashboard_query.get_execute_query | secops dashboard-query get | -| dashboards.copy | v1alpha | | | -| dashboards.create | v1alpha | | | -| dashboards.delete | v1alpha | | | -| dashboards.get | v1alpha | | | -| dashboards.list | v1alpha | | | -| dataAccessLabels.create | v1alpha | | | -| dataAccessLabels.delete | v1alpha | | | -| dataAccessLabels.get | v1alpha | | | -| dataAccessLabels.list | v1alpha | | | -| dataAccessLabels.patch | v1alpha | | | -| dataAccessScopes.create | v1alpha | | | -| dataAccessScopes.delete | v1alpha | | | -| dataAccessScopes.get | v1alpha | | | -| dataAccessScopes.list | v1alpha | | | -| dataAccessScopes.patch | v1alpha | | | -| dataExports.cancel | v1alpha | chronicle.data_export.cancel_data_export | secops export cancel | -| dataExports.create | v1alpha | chronicle.data_export.create_data_export | secops export create | -| dataExports.fetchavailablelogtypes | v1alpha | chronicle.data_export.fetch_available_log_types | secops export log-types | -| dataExports.get | v1alpha | chronicle.data_export.get_data_export | secops export status | -| dataExports.list | v1alpha | chronicle.data_export.list_data_export | secops export list | -| dataExports.patch | v1alpha | chronicle.data_export.update_data_export | secops export update | -| dataTableOperationErrors.get | v1alpha | | | -| dataTables.create | v1alpha | chronicle.data_table.create_data_table | secops data-table create | -| dataTables.dataTableRows.bulkCreate | v1alpha | chronicle.data_table.create_data_table_rows | secops data-table add-rows | -| dataTables.dataTableRows.bulkCreateAsync | v1alpha | | | -| dataTables.dataTableRows.bulkGet | v1alpha | | | -| dataTables.dataTableRows.bulkReplace | v1alpha | | | -| dataTables.dataTableRows.bulkReplaceAsync | v1alpha | | | -| dataTables.dataTableRows.bulkUpdate | v1alpha | | | -| dataTables.dataTableRows.bulkUpdateAsync | v1alpha | | | -| dataTables.dataTableRows.create | v1alpha | | | -| dataTables.dataTableRows.delete | v1alpha | chronicle.data_table.delete_data_table_rows | secops data-table delete-rows | -| dataTables.dataTableRows.get | v1alpha | | | -| dataTables.dataTableRows.list | v1alpha | chronicle.data_table.list_data_table_rows | secops data-table list-rows | -| dataTables.dataTableRows.patch | v1alpha | | | -| dataTables.delete | v1alpha | chronicle.data_table.delete_data_table | secops data-table delete | -| dataTables.get | v1alpha | chronicle.data_table.get_data_table | secops data-table get | -| dataTables.list | v1alpha | chronicle.data_table.list_data_tables | secops data-table list | -| dataTables.patch | v1alpha | | | -| dataTables.upload | v1alpha | | | -| dataTaps.create | v1alpha | | | -| dataTaps.delete | v1alpha | | | -| dataTaps.get | v1alpha | | | -| dataTaps.list | v1alpha | | | -| dataTaps.patch | v1alpha | | | -| delete | v1alpha | | | -| enrichmentControls.create | v1alpha | | | -| enrichmentControls.delete | v1alpha | | | -| enrichmentControls.get | v1alpha | | | -| enrichmentControls.list | v1alpha | | | -| entities.get | v1alpha | | | -| entities.import | v1alpha | | | -| entities.modifyEntityRiskScore | v1alpha | | | -| entities.queryEntityRiskScoreModifications | v1alpha | | | -| entityRiskScores.query | v1alpha | | | -| errorNotificationConfigs.create | v1alpha | | | -| errorNotificationConfigs.delete | v1alpha | | | -| errorNotificationConfigs.get | v1alpha | | | -| errorNotificationConfigs.list | v1alpha | | | -| errorNotificationConfigs.patch | v1alpha | | | -| events.batchGet | v1alpha | | | -| events.get | v1alpha | | | -| events.import | v1alpha | chronicle.log_ingest.ingest_udm | secops log ingest-udm | -| extractSyslog | v1alpha | | | -| federationGroups.create | v1alpha | | | -| federationGroups.delete | v1alpha | | | -| federationGroups.get | v1alpha | | | -| federationGroups.list | v1alpha | | | -| federationGroups.patch | v1alpha | | | -| feedPacks.get | v1alpha | | | -| feedPacks.list | v1alpha | | | -| feedServiceAccounts.fetchServiceAccountForCustomer | v1alpha | | | -| feedSourceTypeSchemas.list | v1alpha | | | -| feedSourceTypeSchemas.logTypeSchemas.list | v1alpha | | | -| feeds.create | v1alpha | chronicle.feeds.create_feed | secops feed create | -| feeds.delete | v1alpha | chronicle.feeds.delete_feed | secops feed delete | -| feeds.disable | v1alpha | chronicle.feeds.disable_feed | secops feed disable | -| feeds.enable | v1alpha | chronicle.feeds.enable_feed | secops feed enable | -| feeds.generateSecret | v1alpha | chronicle.feeds.generate_secret | secops feed secret | -| feeds.get | v1alpha | chronicle.feeds.get_feed | secops feed get | -| feeds.importPushLogs | v1alpha | | | -| feeds.list | v1alpha | chronicle.feeds.list_feeds | secops feed list | -| feeds.patch | v1alpha | chronicle.feeds.update_feed | secops feed update | -| feeds.scheduleTransfer | v1alpha | | | -| fetchFederationAccess | v1alpha | | | -| findEntity | v1alpha | | | -| findEntityAlerts | v1alpha | | | -| findRelatedEntities | v1alpha | | | -| findUdmFieldValues | v1alpha | | | -| findingsGraph.exploreNode | v1alpha | | | -| findingsGraph.initializeGraph | v1alpha | | | -| findingsRefinements.computeFindingsRefinementActivity | v1alpha | chronicle.rule_exclusion.compute_rule_exclusion_activity | secops rule-exclusion compute-activity | -| findingsRefinements.create | v1alpha | chronicle.rule_exclusion.create_rule_exclusion | secops rule-exclusion create | -| findingsRefinements.get | v1alpha | chronicle.rule_exclusion.get_rule_exclusion | secops rule-exclusion get | -| findingsRefinements.getDeployment | v1alpha | chronicle.rule_exclusion.get_rule_exclusion_deployment | secops rule-exclusion get-deployment | -| findingsRefinements.list | v1alpha | chronicle.rule_exclusion.list_rule_exclusions | secops rule-exclusion list | -| findingsRefinements.patch | v1alpha | chronicle.rule_exclusion.patch_rule_exclusion | secops rule-exclusion update | -| findingsRefinements.updateDeployment | v1alpha | chronicle.rule_exclusion.update_rule_exclusion_deployment | secops rule-exclusion update-deployment | -| forwarders.collectors.create | v1alpha | | | -| forwarders.collectors.delete | v1alpha | | | -| forwarders.collectors.get | v1alpha | | | -| forwarders.collectors.list | v1alpha | | | -| forwarders.collectors.patch | v1alpha | | | -| forwarders.create | v1alpha | chronicle.log_ingest.create_forwarder | secops forwarder create | -| forwarders.delete | v1alpha | chronicle.log_ingest.delete_forwarder | secops forwarder delete | -| forwarders.generateForwarderFiles | v1alpha | | | -| forwarders.get | v1alpha | chronicle.log_ingest.get_forwarder | secops forwarder get | -| forwarders.importStatsEvents | v1alpha | | | -| forwarders.list | v1alpha | chronicle.log_ingest.list_forwarder | secops forwarder list | -| forwarders.patch | v1alpha | chronicle.log_ingest.update_forwarder | secops forwarder update | -| generateCollectionAgentAuth | v1alpha | | | -| generateSoarAuthJwt | v1alpha | | | -| generateUdmKeyValueMappings | v1alpha | | | -| generateWorkspaceConnectionToken | v1alpha | | | -| get | v1alpha | | | -| getBigQueryExport | v1alpha | | | -| getMultitenantDirectory | v1alpha | | | -| getRiskConfig | v1alpha | | | -| ingestionLogLabels.get | v1alpha | | | -| ingestionLogLabels.list | v1alpha | | | -| ingestionLogNamespaces.get | v1alpha | | | -| ingestionLogNamespaces.list | v1alpha | | | -| iocs.batchGet | v1alpha | | | -| iocs.findFirstAndLastSeen | v1alpha | | | -| iocs.get | v1alpha | | | -| iocs.getIocState | v1alpha | | | -| iocs.searchCuratedDetectionsForIoc | v1alpha | | | -| iocs.updateIocState | v1alpha | | | -| legacy.legacyBatchGetCases | v1alpha | chronicle.case.get_cases_from_list | secops case | -| legacy.legacyBatchGetCollections | v1alpha | | | -| legacy.legacyCreateOrUpdateCase | v1alpha | | | -| legacy.legacyCreateSoarAlert | v1alpha | | | -| legacy.legacyFetchAlertsView | v1alpha | chronicle.alert.get_alerts | secops alert | -| legacy.legacyFetchUdmSearchCsv | v1alpha | chronicle.udm_search.fetch_udm_search_csv | secops search --csv | -| legacy.legacyFetchUdmSearchView | v1alpha | chronicle.udm_search.fetch_udm_search_view | secops udm-search-view | -| legacy.legacyFindAssetEvents | v1alpha | | | -| legacy.legacyFindRawLogs | v1alpha | | | -| legacy.legacyFindUdmEvents | v1alpha | | | -| legacy.legacyGetAlert | v1alpha | chronicle.rule_alert.get_alert | | -| legacy.legacyGetCuratedRulesTrends | v1alpha | | | -| legacy.legacyGetDetection | v1alpha | | | -| legacy.legacyGetEventForDetection | v1alpha | | | -| legacy.legacyGetRuleCounts | v1alpha | | | -| legacy.legacyGetRulesTrends | v1alpha | | | -| legacy.legacyListCases | v1alpha | chronicle.case.get_cases | secops case --ids | -| legacy.legacyRunTestRule | v1alpha | chronicle.rule.run_rule_test | secops rule validate | -| legacy.legacySearchArtifactEvents | v1alpha | | | -| legacy.legacySearchArtifactIoCDetails | v1alpha | | | -| legacy.legacySearchAssetEvents | v1alpha | | | -| legacy.legacySearchCuratedDetections | v1alpha | | | -| legacy.legacySearchCustomerStats | v1alpha | | | -| legacy.legacySearchDetections | v1alpha | chronicle.rule_detection.list_detections | | -| legacy.legacySearchDomainsRecentlyRegistered | v1alpha | | | -| legacy.legacySearchDomainsTimingStats | v1alpha | | | -| legacy.legacySearchEnterpriseWideAlerts | v1alpha | | | -| legacy.legacySearchEnterpriseWideIoCs | v1alpha | chronicle.ioc.list_iocs | secops iocs | -| legacy.legacySearchFindings | v1alpha | | | -| legacy.legacySearchIngestionStats | v1alpha | | | -| legacy.legacySearchIoCInsights | v1alpha | | | -| legacy.legacySearchRawLogs | v1alpha | | | -| legacy.legacySearchRuleDetectionCountBuckets | v1alpha | | | -| legacy.legacySearchRuleDetectionEvents | v1alpha | | | -| legacy.legacySearchRuleResults | v1alpha | | | -| legacy.legacySearchRulesAlerts | v1alpha | chronicle.rule_alert.search_rule_alerts | | -| legacy.legacySearchUserEvents | v1alpha | | | -| legacy.legacyStreamDetectionAlerts | v1alpha | | | -| legacy.legacyTestRuleStreaming | v1alpha | | | -| legacy.legacyUpdateAlert | v1alpha | chronicle.rule_alert.update_alert | | -| listAllFindingsRefinementDeployments | v1alpha | | | -| logTypes.create | v1alpha | | | -| logTypes.generateEventTypesSuggestions | v1alpha | | | -| logTypes.get | v1alpha | | | -| logTypes.getLogTypeSetting | v1alpha | | | -| logTypes.legacySubmitParserExtension | v1alpha | | | -| logTypes.list | v1alpha | | | -| logTypes.logs.export | v1alpha | | | -| logTypes.logs.get | v1alpha | | | -| logTypes.logs.import | v1alpha | chronicle.log_ingest.ingest_log | secops log ingest | -| logTypes.logs.list | v1alpha | | | -| logTypes.parserExtensions.activate | v1alpha | chronicle.parser_extension.activate_parser_extension | secops parser-extension activate | -| logTypes.parserExtensions.create | v1alpha | chronicle.parser_extension.create_parser_extension | secops parser-extension create | -| logTypes.parserExtensions.delete | v1alpha | chronicle.parser_extension.delete_parser_extension | secops parser-extension delete | -| logTypes.parserExtensions.extensionValidationReports.get | v1alpha | | | -| logTypes.parserExtensions.extensionValidationReports.list | v1alpha | | | -| logTypes.parserExtensions.extensionValidationReports.validationErrors.list | v1alpha | | | -| logTypes.parserExtensions.get | v1alpha | chronicle.parser_extension.get_parser_extension | secops parser-extension get | -| logTypes.parserExtensions.list | v1alpha | chronicle.parser_extension.list_parser_extensions | secops parser-extension list | -| logTypes.parserExtensions.validationReports.get | v1alpha | | | -| logTypes.parserExtensions.validationReports.parsingErrors.list | v1alpha | | | -| logTypes.parsers.activate | v1alpha | chronicle.parser.activate_parser | secops parser activate | -| logTypes.parsers.activateReleaseCandidateParser | v1alpha | chronicle.parser.activate_release_candidate | secops parser activate-rc | -| logTypes.parsers.copy | v1alpha | chronicle.parser.copy_parser | secops parser copy | -| logTypes.parsers.create | v1alpha | chronicle.parser.create_parser | secops parser create | -| logTypes.parsers.deactivate | v1alpha | chronicle.parser.deactivate_parser | secops parser deactivate | -| logTypes.parsers.delete | v1alpha | chronicle.parser.delete_parser | secops parser delete | -| logTypes.parsers.get | v1alpha | chronicle.parser.get_parser | secops parser get | -| logTypes.parsers.list | v1alpha | chronicle.parser.list_parsers | secops parser list | -| logTypes.parsers.validationReports.get | v1alpha | | | -| logTypes.parsers.validationReports.parsingErrors.list | v1alpha | | | -| logTypes.patch | v1alpha | | | -| logTypes.runParser | v1alpha | chronicle.parser.run_parser | secops parser run | -| logTypes.updateLogTypeSetting | v1alpha | | | -| logs.classify | v1alpha | | | -| nativeDashboards.addChart | v1alpha | chronicle.dashboard.add_chart | secops dashboard add-chart | -| nativeDashboards.create | v1alpha | chronicle.dashboard.create_dashboard | secops dashboard create | -| nativeDashboards.delete | v1alpha | chronicle.dashboard.delete_dashboard | secops dashboard delete | -| nativeDashboards.duplicate | v1alpha | chronicle.dashboard.duplicate_dashboard | secops dashboard duplicate | -| nativeDashboards.duplicateChart | v1alpha | | | -| nativeDashboards.editChart | v1alpha | chronicle.dashboard.edit_chart | secops dashboard edit-chart | -| nativeDashboards.export | v1alpha | chronicle.dashboard.export_dashboard | secops dashboard export | -| nativeDashboards.get | v1alpha | chronicle.dashboard.get_dashboard | secops dashboard get | -| nativeDashboards.import | v1alpha | chronicle.dashboard.import_dashboard | secops dashboard import | -| nativeDashboards.list | v1alpha | chronicle.dashboard.list_dashboards | secops dashboard list | -| nativeDashboards.patch | v1alpha | chronicle.dashboard.update_dashboard | secops dashboard update | -| nativeDashboards.removeChart | v1alpha | chronicle.dashboard.remove_chart | secops dashboard remove-chart | -| operations.cancel | v1alpha | | | -| operations.delete | v1alpha | | | -| operations.get | v1alpha | | | -| operations.list | v1alpha | | | -| operations.streamSearch | v1alpha | | | -| queryProductSourceStats | v1alpha | | | -| referenceLists.create | v1alpha | | | -| referenceLists.get | v1alpha | | | -| referenceLists.list | v1alpha | | | -| referenceLists.patch | v1alpha | | | -| report | v1alpha | | | -| ruleExecutionErrors.list | v1alpha | chronicle.rule_detection.list_errors | | -| rules.create | v1alpha | | | -| rules.delete | v1alpha | | | -| rules.deployments.list | v1alpha | | | -| rules.get | v1alpha | | | -| rules.getDeployment | v1alpha | | | -| rules.list | v1alpha | | | -| rules.listRevisions | v1alpha | | | -| rules.patch | v1alpha | | | -| rules.retrohunts.create | v1alpha | | | -| rules.retrohunts.get | v1alpha | | | -| rules.retrohunts.list | v1alpha | | | -| rules.updateDeployment | v1alpha | | | -| searchEntities | v1alpha | | | -| searchRawLogs | v1alpha | | | -| summarizeEntitiesFromQuery | v1alpha | chronicle.entity.summarize_entity | secops entity | -| summarizeEntity | v1alpha | chronicle.entity.summarize_entity | | -| testFindingsRefinement | v1alpha | | | -| translateUdmQuery | v1alpha | chronicle.nl_search.translate_nl_to_udm | | -| translateYlRule | v1alpha | | | -| udmSearch | v1alpha | chronicle.search.search_udm | secops search | -| undelete | v1alpha | | | -| updateBigQueryExport | v1alpha | | | -| updateRiskConfig | v1alpha | | | -| users.clearConversationHistory | v1alpha | | | -| users.conversations.create | v1alpha | chronicle.gemini.create_conversation | | -| users.conversations.delete | v1alpha | | | -| users.conversations.get | v1alpha | | | -| users.conversations.list | v1alpha | | | -| users.conversations.messages.create | v1alpha | chronicle.gemini.query_gemini | secops gemini | -| users.conversations.messages.delete | v1alpha | | | -| users.conversations.messages.get | v1alpha | | | -| users.conversations.messages.list | v1alpha | | | -| users.conversations.messages.patch | v1alpha | | | -| users.conversations.patch | v1alpha | | | -| users.getPreferenceSet | v1alpha | chronicle.gemini.opt_in_to_gemini | secops gemini --opt-in | -| users.searchQueries.create | v1alpha | | | -| users.searchQueries.delete | v1alpha | | | -| users.searchQueries.get | v1alpha | | | -| users.searchQueries.list | v1alpha | | | -| users.searchQueries.patch | v1alpha | | | -| users.updatePreferenceSet | v1alpha | | | -| validateQuery | v1alpha | chronicle.validate.validate_query | | -| verifyReferenceList | v1alpha | | | -| verifyRuleText | v1alpha | chronicle.rule_validation.validate_rule | secops rule validate | -| watchlists.create | v1alpha | | | -| watchlists.delete | v1alpha | | | -| watchlists.entities.add | v1alpha | | | -| watchlists.entities.batchAdd | v1alpha | | | -| watchlists.entities.batchRemove | v1alpha | | | -| watchlists.entities.remove | v1alpha | | | -| watchlists.get | v1alpha | | | -| watchlists.list | v1alpha | | | -| watchlists.listEntities | v1alpha | | | -| watchlists.patch | v1alpha | | | +| dashboardCharts.batchGet |v1alpha| | | +|dashboardCharts.get |v1alpha|chronicle.dashboard.get_chart |secops dashboard get-chart | +|dashboardQueries.execute |v1alpha|chronicle.dashboard_query.execute_query |secops dashboard-query execute | +|dashboardQueries.get |v1alpha|chronicle.dashboard_query.get_execute_query |secops dashboard-query get | +|dashboards.copy |v1alpha| | | +|dashboards.create |v1alpha| | | +|dashboards.delete |v1alpha| | | +|dashboards.get |v1alpha| | | +|dashboards.list |v1alpha| | | +|dataAccessLabels.create |v1alpha| | | +|dataAccessLabels.delete |v1alpha| | | +|dataAccessLabels.get |v1alpha| | | +|dataAccessLabels.list |v1alpha| | | +|dataAccessLabels.patch |v1alpha| | | +|dataAccessScopes.create |v1alpha| | | +|dataAccessScopes.delete |v1alpha| | | +|dataAccessScopes.get |v1alpha| | | +|dataAccessScopes.list |v1alpha| | | +|dataAccessScopes.patch |v1alpha| | | +|dataExports.cancel |v1alpha|chronicle.data_export.cancel_data_export |secops export cancel | +|dataExports.create |v1alpha|chronicle.data_export.create_data_export |secops export create | +|dataExports.fetchavailablelogtypes |v1alpha|chronicle.data_export.fetch_available_log_types |secops export log-types | +|dataExports.get |v1alpha|chronicle.data_export.get_data_export |secops export status | +|dataExports.list |v1alpha|chronicle.data_export.list_data_export |secops export list | +|dataExports.patch |v1alpha|chronicle.data_export.update_data_export |secops export update | +|dataTableOperationErrors.get |v1alpha| | | +|dataTables.create |v1alpha|chronicle.data_table.create_data_table |secops data-table create | +|dataTables.dataTableRows.bulkCreate |v1alpha|chronicle.data_table.create_data_table_rows |secops data-table add-rows | +|dataTables.dataTableRows.bulkCreateAsync |v1alpha| | | +|dataTables.dataTableRows.bulkGet |v1alpha| | | +|dataTables.dataTableRows.bulkReplace |v1alpha| | | +|dataTables.dataTableRows.bulkReplaceAsync |v1alpha| | | +|dataTables.dataTableRows.bulkUpdate |v1alpha| | | +|dataTables.dataTableRows.bulkUpdateAsync |v1alpha| | | +|dataTables.dataTableRows.create |v1alpha| | | +|dataTables.dataTableRows.delete |v1alpha|chronicle.data_table.delete_data_table_rows |secops data-table delete-rows | +|dataTables.dataTableRows.get |v1alpha| | | +|dataTables.dataTableRows.list |v1alpha|chronicle.data_table.list_data_table_rows |secops data-table list-rows | +|dataTables.dataTableRows.patch |v1alpha| | | +|dataTables.delete |v1alpha|chronicle.data_table.delete_data_table |secops data-table delete | +|dataTables.get |v1alpha|chronicle.data_table.get_data_table |secops data-table get | +|dataTables.list |v1alpha|chronicle.data_table.list_data_tables |secops data-table list | +|dataTables.patch |v1alpha| | | +|dataTables.upload |v1alpha| | | +|dataTaps.create |v1alpha| | | +|dataTaps.delete |v1alpha| | | +|dataTaps.get |v1alpha| | | +|dataTaps.list |v1alpha| | | +|dataTaps.patch |v1alpha| | | +|delete |v1alpha| | | +|enrichmentControls.create |v1alpha| | | +|enrichmentControls.delete |v1alpha| | | +|enrichmentControls.get |v1alpha| | | +|enrichmentControls.list |v1alpha| | | +|entities.get |v1alpha| | | +|entities.import |v1alpha|chronicle.log_ingest.import_entities |secops entity import | +|entities.modifyEntityRiskScore |v1alpha| | | +|entities.queryEntityRiskScoreModifications |v1alpha| | | +|entityRiskScores.query |v1alpha| | | +|errorNotificationConfigs.create |v1alpha| | | +|errorNotificationConfigs.delete |v1alpha| | | +|errorNotificationConfigs.get |v1alpha| | | +|errorNotificationConfigs.list |v1alpha| | | +|errorNotificationConfigs.patch |v1alpha| | | +|events.batchGet |v1alpha| | | +|events.get |v1alpha| | | +|events.import |v1alpha|chronicle.log_ingest.ingest_udm |secops log ingest-udm | +|extractSyslog |v1alpha| | | +|federationGroups.create |v1alpha| | | +|federationGroups.delete |v1alpha| | | +|federationGroups.get |v1alpha| | | +|federationGroups.list |v1alpha| | | +|federationGroups.patch |v1alpha| | | +|feedPacks.get |v1alpha| | | +|feedPacks.list |v1alpha| | | +|feedServiceAccounts.fetchServiceAccountForCustomer |v1alpha| | | +|feedSourceTypeSchemas.list |v1alpha| | | +|feedSourceTypeSchemas.logTypeSchemas.list |v1alpha| | | +|feeds.create |v1alpha|chronicle.feeds.create_feed |secops feed create | +|feeds.delete |v1alpha|chronicle.feeds.delete_feed |secops feed delete | +|feeds.disable |v1alpha|chronicle.feeds.disable_feed |secops feed disable | +|feeds.enable |v1alpha|chronicle.feeds.enable_feed |secops feed enable | +|feeds.generateSecret |v1alpha|chronicle.feeds.generate_secret |secops feed secret | +|feeds.get |v1alpha|chronicle.feeds.get_feed |secops feed get | +|feeds.importPushLogs |v1alpha| | | +|feeds.list |v1alpha|chronicle.feeds.list_feeds |secops feed list | +|feeds.patch |v1alpha|chronicle.feeds.update_feed |secops feed update | +|feeds.scheduleTransfer |v1alpha| | | +|fetchFederationAccess |v1alpha| | | +|findEntity |v1alpha| | | +|findEntityAlerts |v1alpha| | | +|findRelatedEntities |v1alpha| | | +|findUdmFieldValues |v1alpha| | | +|findingsGraph.exploreNode |v1alpha| | | +|findingsGraph.initializeGraph |v1alpha| | | +|findingsRefinements.computeFindingsRefinementActivity |v1alpha|chronicle.rule_exclusion.compute_rule_exclusion_activity |secops rule-exclusion compute-activity | +|findingsRefinements.create |v1alpha|chronicle.rule_exclusion.create_rule_exclusion |secops rule-exclusion create | +|findingsRefinements.get |v1alpha|chronicle.rule_exclusion.get_rule_exclusion |secops rule-exclusion get | +|findingsRefinements.getDeployment |v1alpha|chronicle.rule_exclusion.get_rule_exclusion_deployment |secops rule-exclusion get-deployment | +|findingsRefinements.list |v1alpha|chronicle.rule_exclusion.list_rule_exclusions |secops rule-exclusion list | +|findingsRefinements.patch |v1alpha|chronicle.rule_exclusion.patch_rule_exclusion |secops rule-exclusion update | +|findingsRefinements.updateDeployment |v1alpha|chronicle.rule_exclusion.update_rule_exclusion_deployment |secops rule-exclusion update-deployment| +|forwarders.collectors.create |v1alpha| | | +|forwarders.collectors.delete |v1alpha| | | +|forwarders.collectors.get |v1alpha| | | +|forwarders.collectors.list |v1alpha| | | +|forwarders.collectors.patch |v1alpha| | | +|forwarders.create |v1alpha|chronicle.log_ingest.create_forwarder |secops forwarder create | +|forwarders.delete |v1alpha|chronicle.log_ingest.delete_forwarder |secops forwarder delete | +|forwarders.generateForwarderFiles |v1alpha| | | +|forwarders.get |v1alpha|chronicle.log_ingest.get_forwarder |secops forwarder get | +|forwarders.importStatsEvents |v1alpha| | | +|forwarders.list |v1alpha|chronicle.log_ingest.list_forwarder |secops forwarder list | +|forwarders.patch |v1alpha|chronicle.log_ingest.update_forwarder |secops forwarder update | +|generateCollectionAgentAuth |v1alpha| | | +|generateSoarAuthJwt |v1alpha| | | +|generateUdmKeyValueMappings |v1alpha| | | +|generateWorkspaceConnectionToken |v1alpha| | | +|get |v1alpha| | | +|getBigQueryExport |v1alpha| | | +|getMultitenantDirectory |v1alpha| | | +|getRiskConfig |v1alpha| | | +|ingestionLogLabels.get |v1alpha| | | +|ingestionLogLabels.list |v1alpha| | | +|ingestionLogNamespaces.get |v1alpha| | | +|ingestionLogNamespaces.list |v1alpha| | | +|iocs.batchGet |v1alpha| | | +|iocs.findFirstAndLastSeen |v1alpha| | | +|iocs.get |v1alpha| | | +|iocs.getIocState |v1alpha| | | +|iocs.searchCuratedDetectionsForIoc |v1alpha| | | +|iocs.updateIocState |v1alpha| | | +|legacy.legacyBatchGetCases |v1alpha|chronicle.case.get_cases_from_list |secops case | +|legacy.legacyBatchGetCollections |v1alpha| | | +|legacy.legacyCreateOrUpdateCase |v1alpha| | | +|legacy.legacyCreateSoarAlert |v1alpha| | | +|legacy.legacyFetchAlertsView |v1alpha|chronicle.alert.get_alerts |secops alert | +|legacy.legacyFetchUdmSearchCsv |v1alpha|chronicle.udm_search.fetch_udm_search_csv |secops search --csv | +|legacy.legacyFetchUdmSearchView |v1alpha|chronicle.udm_search.fetch_udm_search_view |secops udm-search-view | +|legacy.legacyFindAssetEvents |v1alpha| | | +|legacy.legacyFindRawLogs |v1alpha| | | +|legacy.legacyFindUdmEvents |v1alpha| | | +|legacy.legacyGetAlert |v1alpha|chronicle.rule_alert.get_alert | | +|legacy.legacyGetCuratedRulesTrends |v1alpha| | | +|legacy.legacyGetDetection |v1alpha| | | +|legacy.legacyGetEventForDetection |v1alpha| | | +|legacy.legacyGetRuleCounts |v1alpha| | | +|legacy.legacyGetRulesTrends |v1alpha| | | +|legacy.legacyListCases |v1alpha|chronicle.case.get_cases |secops case --ids | +|legacy.legacyRunTestRule |v1alpha|chronicle.rule.run_rule_test |secops rule validate | +|legacy.legacySearchArtifactEvents |v1alpha| | | +|legacy.legacySearchArtifactIoCDetails |v1alpha| | | +|legacy.legacySearchAssetEvents |v1alpha| | | +|legacy.legacySearchCuratedDetections |v1alpha| | | +|legacy.legacySearchCustomerStats |v1alpha| | | +|legacy.legacySearchDetections |v1alpha|chronicle.rule_detection.list_detections | | +|legacy.legacySearchDomainsRecentlyRegistered |v1alpha| | | +|legacy.legacySearchDomainsTimingStats |v1alpha| | | +|legacy.legacySearchEnterpriseWideAlerts |v1alpha| | | +|legacy.legacySearchEnterpriseWideIoCs |v1alpha|chronicle.ioc.list_iocs |secops iocs | +|legacy.legacySearchFindings |v1alpha| | | +|legacy.legacySearchIngestionStats |v1alpha| | | +|legacy.legacySearchIoCInsights |v1alpha| | | +|legacy.legacySearchRawLogs |v1alpha| | | +|legacy.legacySearchRuleDetectionCountBuckets |v1alpha| | | +|legacy.legacySearchRuleDetectionEvents |v1alpha| | | +|legacy.legacySearchRuleResults |v1alpha| | | +|legacy.legacySearchRulesAlerts |v1alpha|chronicle.rule_alert.search_rule_alerts | | +|legacy.legacySearchUserEvents |v1alpha| | | +|legacy.legacyStreamDetectionAlerts |v1alpha| | | +|legacy.legacyTestRuleStreaming |v1alpha| | | +|legacy.legacyUpdateAlert |v1alpha|chronicle.rule_alert.update_alert | | +|listAllFindingsRefinementDeployments |v1alpha| | | +|logTypes.create |v1alpha| | | +|logTypes.generateEventTypesSuggestions |v1alpha| | | +|logTypes.get |v1alpha| | | +|logTypes.getLogTypeSetting |v1alpha| | | +|logTypes.legacySubmitParserExtension |v1alpha| | | +|logTypes.list |v1alpha| | | +|logTypes.logs.export |v1alpha| | | +|logTypes.logs.get |v1alpha| | | +|logTypes.logs.import |v1alpha|chronicle.log_ingest.ingest_log |secops log ingest | +|logTypes.logs.list |v1alpha| | | +|logTypes.parserExtensions.activate |v1alpha|chronicle.parser_extension.activate_parser_extension |secops parser-extension activate | +|logTypes.parserExtensions.create |v1alpha|chronicle.parser_extension.create_parser_extension |secops parser-extension create | +|logTypes.parserExtensions.delete |v1alpha|chronicle.parser_extension.delete_parser_extension |secops parser-extension delete | +|logTypes.parserExtensions.extensionValidationReports.get |v1alpha| | | +|logTypes.parserExtensions.extensionValidationReports.list |v1alpha| | | +|logTypes.parserExtensions.extensionValidationReports.validationErrors.list |v1alpha| | | +|logTypes.parserExtensions.get |v1alpha|chronicle.parser_extension.get_parser_extension |secops parser-extension get | +|logTypes.parserExtensions.list |v1alpha|chronicle.parser_extension.list_parser_extensions |secops parser-extension list | +|logTypes.parserExtensions.validationReports.get |v1alpha| | | +|logTypes.parserExtensions.validationReports.parsingErrors.list |v1alpha| | | +|logTypes.parsers.activate |v1alpha|chronicle.parser.activate_parser |secops parser activate | +|logTypes.parsers.activateReleaseCandidateParser |v1alpha|chronicle.parser.activate_release_candidate |secops parser activate-rc | +|logTypes.parsers.copy |v1alpha|chronicle.parser.copy_parser |secops parser copy | +|logTypes.parsers.create |v1alpha|chronicle.parser.create_parser |secops parser create | +|logTypes.parsers.deactivate |v1alpha|chronicle.parser.deactivate_parser |secops parser deactivate | +|logTypes.parsers.delete |v1alpha|chronicle.parser.delete_parser |secops parser delete | +|logTypes.parsers.get |v1alpha|chronicle.parser.get_parser |secops parser get | +|logTypes.parsers.list |v1alpha|chronicle.parser.list_parsers |secops parser list | +|logTypes.parsers.validationReports.get |v1alpha| | | +|logTypes.parsers.validationReports.parsingErrors.list |v1alpha| | | +|logTypes.patch |v1alpha| | | +|logTypes.runParser |v1alpha|chronicle.parser.run_parser |secops parser run | +|logTypes.updateLogTypeSetting |v1alpha| | | +|logs.classify |v1alpha| | | +| nativeDashboards.addChart | v1alpha |chronicle.dashboard.add_chart |secops dashboard add-chart | +| nativeDashboards.create | v1alpha |chronicle.dashboard.create_dashboard |secops dashboard create | +| nativeDashboards.delete | v1alpha |chronicle.dashboard.delete_dashboard |secops dashboard delete | +| nativeDashboards.duplicate | v1alpha |chronicle.dashboard.duplicate_dashboard |secops dashboard duplicate | +| nativeDashboards.duplicateChart | v1alpha | | | +| nativeDashboards.editChart | v1alpha |chronicle.dashboard.edit_chart |secops dashboard edit-chart | +| nativeDashboards.export | v1alpha |chronicle.dashboard.export_dashboard |secops dashboard export | +| nativeDashboards.get | v1alpha |chronicle.dashboard.get_dashboard |secops dashboard get | +| nativeDashboards.import | v1alpha |chronicle.dashboard.import_dashboard |secops dashboard import | +| nativeDashboards.list | v1alpha |chronicle.dashboard.list_dashboards |secops dashboard list | +| nativeDashboards.patch | v1alpha |chronicle.dashboard.update_dashboard |secops dashboard update | +| nativeDashboards.removeChart | v1alpha |chronicle.dashboard.remove_chart |secops dashboard remove-chart | +|operations.cancel |v1alpha| | | +|operations.delete |v1alpha| | | +|operations.get |v1alpha| | | +|operations.list |v1alpha| | | +|operations.streamSearch |v1alpha| | | +|queryProductSourceStats |v1alpha| | | +|referenceLists.create |v1alpha| | | +|referenceLists.get |v1alpha| | | +|referenceLists.list |v1alpha| | | +|referenceLists.patch |v1alpha| | | +|report |v1alpha| | | +|ruleExecutionErrors.list |v1alpha|chronicle.rule_detection.list_errors | | +|rules.create |v1alpha| | | +|rules.delete |v1alpha| | | +|rules.deployments.list |v1alpha| | | +|rules.get |v1alpha| | | +|rules.getDeployment |v1alpha| | | +|rules.list |v1alpha| | | +|rules.listRevisions |v1alpha| | | +|rules.patch |v1alpha| | | +|rules.retrohunts.create |v1alpha| | | +|rules.retrohunts.get |v1alpha| | | +|rules.retrohunts.list |v1alpha| | | +|rules.updateDeployment |v1alpha| | | +|searchEntities |v1alpha| | | +|searchRawLogs |v1alpha| | | +|summarizeEntitiesFromQuery |v1alpha|chronicle.entity.summarize_entity |secops entity | +|summarizeEntity |v1alpha|chronicle.entity.summarize_entity | | +|testFindingsRefinement |v1alpha| | | +|translateUdmQuery |v1alpha|chronicle.nl_search.translate_nl_to_udm | | +|translateYlRule |v1alpha| | | +|udmSearch |v1alpha|chronicle.search.search_udm |secops search | +|undelete |v1alpha| | | +|updateBigQueryExport |v1alpha| | | +|updateRiskConfig |v1alpha| | | +|users.clearConversationHistory |v1alpha| | | +|users.conversations.create |v1alpha|chronicle.gemini.create_conversation | | +|users.conversations.delete |v1alpha| | | +|users.conversations.get |v1alpha| | | +|users.conversations.list |v1alpha| | | +|users.conversations.messages.create |v1alpha|chronicle.gemini.query_gemini |secops gemini | +|users.conversations.messages.delete |v1alpha| | | +|users.conversations.messages.get |v1alpha| | | +|users.conversations.messages.list |v1alpha| | | +|users.conversations.messages.patch |v1alpha| | | +|users.conversations.patch |v1alpha| | | +|users.getPreferenceSet |v1alpha|chronicle.gemini.opt_in_to_gemini |secops gemini --opt-in | +|users.searchQueries.create |v1alpha| | | +|users.searchQueries.delete |v1alpha| | | +|users.searchQueries.get |v1alpha| | | +|users.searchQueries.list |v1alpha| | | +|users.searchQueries.patch |v1alpha| | | +|users.updatePreferenceSet |v1alpha| | | +|validateQuery |v1alpha|chronicle.validate.validate_query | | +|verifyReferenceList |v1alpha| | | +|verifyRuleText |v1alpha|chronicle.rule_validation.validate_rule |secops rule validate | +|watchlists.create |v1alpha| | | +|watchlists.delete |v1alpha| | | +|watchlists.entities.add |v1alpha| | | +|watchlists.entities.batchAdd |v1alpha| | | +|watchlists.entities.batchRemove |v1alpha| | | +|watchlists.entities.remove |v1alpha| | | +|watchlists.get |v1alpha| | | +|watchlists.list |v1alpha| | | +|watchlists.listEntities |v1alpha| | | +|watchlists.patch |v1alpha| | | diff --git a/src/secops/chronicle/rule_set.py b/src/secops/chronicle/rule_set.py index 7f1d60d1..ae075786 100644 --- a/src/secops/chronicle/rule_set.py +++ b/src/secops/chronicle/rule_set.py @@ -227,9 +227,7 @@ def get_curated_rule(client, rule_id: str) -> Dict[str, Any]: Raises: APIError: If the API request fails """ - base_url = ( - f"{client.base_url}/{client.instance_id}/" f"curatedRules/{rule_id}" - ) + base_url = f"{client.base_url}/{client.instance_id}/curatedRules/{rule_id}" response = client.session.get(base_url) if response.status_code != 200: From c340097658c097bfb1bceebaf8fce3930af1cedc Mon Sep 17 00:00:00 2001 From: Mihir Vala <179564180+mihirvala-crestdata@users.noreply.github.com> Date: Tue, 4 Nov 2025 11:12:12 +0530 Subject: [PATCH 30/30] chore: added changelogs. Updated version. --- CHANGELOG.md | 15 +++++++++++++++ pyproject.toml | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2892fdf4..cc5f8da9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,21 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.23.0] - 2025-11-04 +### Added +- Support for following methods: + - List Curated Rules + - Get Curated Rule + - Get Curated Rule By Name + - List Curated Rule Sets + - Get Curated Rule Set + - List Curated Rule Set Categories + - Get Curated Rule Set Category + - List Curated Rule Set Deployments + - Get Curated Rule Set Deployment + - Get Curated Rule Set Deployment By Name + - Updated Curated Rule Set Deployment + ## [0.22.0] - 2025-10-30 ### Added - Support for entity import method diff --git a/pyproject.toml b/pyproject.toml index bc681962..8e38e3e5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "secops" -version = "0.22.0" +version = "0.23.0" description = "Python SDK for wrapping the Google SecOps API for common use cases" readme = "README.md" requires-python = ">=3.7"