From 293a099e411fbdbb8dbc203ce2d19bab2f15747b Mon Sep 17 00:00:00 2001 From: Federico Barcelona Date: Mon, 10 Aug 2020 09:57:38 +0200 Subject: [PATCH 1/4] ci: Solve some PEP 8 problems --- examples/add_notification_email.py | 3 +-- examples/add_policy.py | 5 ++-- examples/add_policy_v1.py | 5 ++-- examples/add_users_to_secure.py | 5 +--- examples/create_alert.py | 9 ++++---- examples/create_dashboard.py | 3 +-- examples/create_default_policies.py | 5 ++-- examples/create_default_policies_v1.py | 5 ++-- examples/create_sysdig_capture.py | 3 +-- examples/dashboard.py | 13 +++-------- examples/dashboard_backup_v1_restore_v2.py | 9 +++----- examples/dashboard_basic_crud.py | 7 +++--- examples/dashboard_ibm_cloud.py | 5 ++-- examples/dashboard_save_load.py | 4 +--- examples/dashboard_scope.py | 16 ++++++------- examples/delete_alert.py | 3 +-- examples/delete_all_policies.py | 4 +--- examples/delete_all_policies_v1.py | 4 +--- examples/delete_dashboard.py | 3 +-- examples/delete_event.py | 4 +--- examples/delete_policy.py | 7 +++--- examples/delete_policy_v1.py | 7 +++--- examples/download_dashboards.py | 9 +++----- examples/flip_alerts_enabled.py | 8 ++----- examples/get_agents_config.py | 5 ++-- examples/get_anchore_users_account.py | 3 +-- examples/get_data_advanced.py | 20 ++++++++-------- examples/get_data_datasource.py | 23 +++++++++---------- examples/get_data_simple.py | 11 +++++---- examples/get_image_info_by_id.py | 3 +-- examples/get_image_scan_result_by_id.py | 3 +-- examples/get_latest_pdf_report_by_digest.py | 4 ++-- examples/get_pdf_report.py | 3 +-- examples/get_policy.py | 5 ++-- examples/get_policy_v1.py | 5 ++-- .../get_secure_default_falco_rules_files.py | 7 +++--- examples/get_secure_policy_events.py | 10 ++++---- examples/get_secure_system_falco_rules.py | 3 +-- examples/get_secure_user_falco_rules.py | 3 +-- examples/list_admins.py | 3 +-- examples/list_alert_notifications.py | 6 ++--- examples/list_alerts.py | 5 ++-- examples/list_dashboards.py | 3 +-- examples/list_events.py | 6 ++--- examples/list_hosts.py | 5 ++-- examples/list_metrics.py | 3 +-- examples/list_notification_channels.py | 5 ++-- examples/list_policies.py | 6 ++--- examples/list_policies_v1.py | 10 ++++---- examples/list_profiles.py | 10 +++----- examples/list_sysdig_captures.py | 5 ++-- examples/list_users.py | 3 +-- examples/notification_channels.py | 6 ++--- examples/post_event.py | 14 ++++++----- examples/post_event_simple.py | 3 +-- examples/print_conn_table.py | 5 ++-- examples/print_data_retention_info.py | 3 +-- examples/print_explore_grouping.py | 3 +-- examples/print_user_info.py | 3 +-- examples/resolve_alert_notifications.py | 3 +-- examples/restore_alerts.py | 12 ++++------ examples/restore_dashboards.py | 5 ++-- examples/set_agents_config.py | 4 ++-- examples/set_explore_group_configuration.py | 3 +-- examples/set_policy_order_v1.py | 5 ++-- .../set_secure_default_falco_rules_files.py | 10 ++++---- examples/set_secure_system_falco_rules.py | 4 ++-- examples/set_secure_user_falco_rules.py | 4 ++-- examples/update_alert.py | 7 +++--- examples/update_policy.py | 7 ++---- examples/update_policy_v1.py | 7 ++---- examples/user_team_mgmt.py | 4 ++-- examples/user_team_mgmt_extended.py | 12 ++++------ 73 files changed, 183 insertions(+), 265 deletions(-) diff --git a/examples/add_notification_email.py b/examples/add_notification_email.py index 5589d853..c81e5861 100755 --- a/examples/add_notification_email.py +++ b/examples/add_notification_email.py @@ -3,9 +3,8 @@ # Post a user event to Sysdig Cloud # -import os import sys -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) + from sdcclient import SdcClient # diff --git a/examples/add_policy.py b/examples/add_policy.py index bbcedf78..7bbf2db7 100755 --- a/examples/add_policy.py +++ b/examples/add_policy.py @@ -3,10 +3,9 @@ # Add a new policy # -import os -import sys import json -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) +import sys + from sdcclient import SdSecureClient diff --git a/examples/add_policy_v1.py b/examples/add_policy_v1.py index 1b1f8493..f9a63098 100755 --- a/examples/add_policy_v1.py +++ b/examples/add_policy_v1.py @@ -3,10 +3,9 @@ # Add a new policy # -import os -import sys import json -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) +import sys + from sdcclient import SdSecureClientV1 diff --git a/examples/add_users_to_secure.py b/examples/add_users_to_secure.py index 6c7de21c..59f4f066 100755 --- a/examples/add_users_to_secure.py +++ b/examples/add_users_to_secure.py @@ -12,11 +12,8 @@ # of the Secure Operations team as well. # -import os import sys -import json -import logging -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) + from sdcclient import SdcClient # diff --git a/examples/create_alert.py b/examples/create_alert.py index 7b7548b8..04aeb62a 100755 --- a/examples/create_alert.py +++ b/examples/create_alert.py @@ -7,9 +7,8 @@ # import getopt -import os import sys -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) + from sdcclient import SdcClient @@ -68,8 +67,10 @@ def usage(): 60, # The alert will fire if the condition is met for at least 60 seconds. 'avg(cpu.used.percent) > 80', # The condition. ['host.mac', 'proc.name'], # Segmentation. We want to check this metric for every process on every machine. - 'ANY', # in case there is more than one tomcat process, this alert will fire when a single one of them crosses the 80% threshold. - 'proc.name = "tomcat"', # Filter. We want to receive a notification only if the name of the process meeting the condition is 'tomcat'. + 'ANY', + # in case there is more than one tomcat process, this alert will fire when a single one of them crosses the 80% threshold. + 'proc.name = "tomcat"', + # Filter. We want to receive a notification only if the name of the process meeting the condition is 'tomcat'. notification_channel_ids, False) # This alert will be disabled when it's created. diff --git a/examples/create_dashboard.py b/examples/create_dashboard.py index 380595c9..9bee7b97 100755 --- a/examples/create_dashboard.py +++ b/examples/create_dashboard.py @@ -7,9 +7,8 @@ # import getopt -import os import sys -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) + from sdcclient import SdMonitorClient diff --git a/examples/create_default_policies.py b/examples/create_default_policies.py index a6b17b89..d7c904fd 100755 --- a/examples/create_default_policies.py +++ b/examples/create_default_policies.py @@ -6,10 +6,9 @@ # policies created. # -import os -import sys import json -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) +import sys + from sdcclient import SdSecureClient diff --git a/examples/create_default_policies_v1.py b/examples/create_default_policies_v1.py index d55ac5ae..620ab063 100755 --- a/examples/create_default_policies_v1.py +++ b/examples/create_default_policies_v1.py @@ -6,10 +6,9 @@ # policies created. # -import os -import sys import json -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) +import sys + from sdcclient import SdSecureClientV1 diff --git a/examples/create_sysdig_capture.py b/examples/create_sysdig_capture.py index 865e8736..bbf5d31f 100755 --- a/examples/create_sysdig_capture.py +++ b/examples/create_sysdig_capture.py @@ -3,10 +3,9 @@ # Creates a sysdig capture, waits for termination and prints the download URL. # -import os import sys import time -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) + from sdcclient import SdcClient # diff --git a/examples/dashboard.py b/examples/dashboard.py index 5af39fba..2441a4e9 100755 --- a/examples/dashboard.py +++ b/examples/dashboard.py @@ -5,9 +5,8 @@ # import getopt -import os import sys -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) + from sdcclient import SdMonitorClient @@ -41,7 +40,6 @@ def usage(): # sdclient = SdMonitorClient(sdc_token) - # # Create an empty dashboard # @@ -56,7 +54,6 @@ def usage(): print(res) sys.exit(1) - # # Find a dashboard by name # @@ -70,7 +67,6 @@ def usage(): print(res) sys.exit(1) - # # Add a time series # @@ -91,7 +87,6 @@ def usage(): print(res) sys.exit(1) - # # Add a top bar chart # @@ -104,7 +99,8 @@ def usage(): sort_direction = 'desc' limit = 10 layout = {'col': 1, 'row': 7, 'size_x': 12, 'size_y': 6} -ok, res = sdclient.add_dashboard_panel(dashboard_configuration, panel_name, panel_type, metrics, sort_direction=sort_direction, limit=limit, layout=layout) +ok, res = sdclient.add_dashboard_panel(dashboard_configuration, panel_name, panel_type, metrics, + sort_direction=sort_direction, limit=limit, layout=layout) # Check the result if ok: @@ -114,7 +110,6 @@ def usage(): print(res) sys.exit(1) - # # Add a number panel # @@ -134,7 +129,6 @@ def usage(): print(res) sys.exit(1) - # # Remove a panel # @@ -148,7 +142,6 @@ def usage(): print(res) sys.exit(1) - # # Delete the dashboard # diff --git a/examples/dashboard_backup_v1_restore_v2.py b/examples/dashboard_backup_v1_restore_v2.py index 74c29b51..f33d9ba0 100755 --- a/examples/dashboard_backup_v1_restore_v2.py +++ b/examples/dashboard_backup_v1_restore_v2.py @@ -3,11 +3,8 @@ # Save the first user dashboard to file and then use create_dashboard_from_file() # to apply the stored dasboard again with a different filter. # -import os import sys -import json -sys.path.insert( - 0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) + from sdcclient import SdMonitorClient from sdcclient import SdMonitorClientV1 @@ -16,8 +13,8 @@ # if len(sys.argv) != 5: print(( - 'usage: %s ' - % sys.argv[0])) + 'usage: %s ' + % sys.argv[0])) print( 'You can find your token at https://app.sysdigcloud.com/#/settings/user' ) diff --git a/examples/dashboard_basic_crud.py b/examples/dashboard_basic_crud.py index 78d8624e..89945e29 100755 --- a/examples/dashboard_basic_crud.py +++ b/examples/dashboard_basic_crud.py @@ -2,12 +2,11 @@ # # Simple example of dashboard creation, retrieval, updating, and deletion. # -import os import sys -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) -from sdcclient import SdMonitorClient import uuid +from sdcclient import SdMonitorClient + # # Parse arguments # @@ -76,4 +75,4 @@ # if not ok: print(res) - sys.exit(1) \ No newline at end of file + sys.exit(1) diff --git a/examples/dashboard_ibm_cloud.py b/examples/dashboard_ibm_cloud.py index 14395d88..ad9745e1 100755 --- a/examples/dashboard_ibm_cloud.py +++ b/examples/dashboard_ibm_cloud.py @@ -3,11 +3,11 @@ # This example uses IBM Cloud IAM authentication and makes a few calls to the # Dashboard API as validation. Creates, edits and then deletes a dashboard. -import os import sys -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) + from sdcclient import IbmAuthHelper, SdMonitorClient + # Parse arguments. def usage(): print(('usage: %s ' % sys.argv[0])) @@ -16,6 +16,7 @@ def usage(): print('instance-guid: GUID of an IBM Cloud Monitoring with Sysdig instance') sys.exit(1) + if len(sys.argv) != 4: usage() diff --git a/examples/dashboard_save_load.py b/examples/dashboard_save_load.py index ec9d04c5..8cb5924c 100755 --- a/examples/dashboard_save_load.py +++ b/examples/dashboard_save_load.py @@ -3,10 +3,8 @@ # Save the first user dashboard to file and then use create_dashboard_from_file() # to apply the stored dasboard again with a different filter. # -import os import sys -import json -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) + from sdcclient import SdMonitorClient # diff --git a/examples/dashboard_scope.py b/examples/dashboard_scope.py index 49d7f281..f1c95698 100755 --- a/examples/dashboard_scope.py +++ b/examples/dashboard_scope.py @@ -3,10 +3,8 @@ # This example shows some examples of scope you can use for dashboards. # -import getopt -import os import sys -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) + from sdcclient import SdcClient @@ -18,7 +16,7 @@ # def evaluate(scope, expected): parsed_scope = SdcClient.convert_scope_string_to_expression(scope) - print('{} is valid: {}'.format(scope, parsed_scope[0] == True)) + print('{} is valid: {}'.format(scope, parsed_scope[0] is True)) if parsed_scope[0] != expected: print('Unexpected parsing result!') @@ -53,17 +51,17 @@ def evaluate(scope, expected): evaluate(None, True) # invalid scopes will cause errors -evaluate('proc.name == "cassandra"', False) # invalid operator +evaluate('proc.name == "cassandra"', False) # invalid operator # currently, one space is required around operands and operators -- improvements will come soon evaluate('proc.name="cassandra"', False) # -# The current grammer is unable to validate all errors -- in these cases, the API will fail! +# The current grammar is unable to validate all errors -- in these cases, the API will fail! # Improvements will come soon! # # Here some errors that will not be detected by the Python library, but the API will # -evaluate('proc.name = "cassandra" or proc.name = "mysql"', True) # not AND'd expressions are supported -evaluate('proc.name in ("cassandra\', \'mysql")', True) # mismatching quotes -evaluate('proc.name in ("cassandra", "mysql"', True) # missing parenthesis +evaluate('proc.name = "cassandra" or proc.name = "mysql"', True) # not AND'd expressions are supported +evaluate('proc.name in ("cassandra\', \'mysql")', True) # mismatching quotes +evaluate('proc.name in ("cassandra", "mysql"', True) # missing parenthesis diff --git a/examples/delete_alert.py b/examples/delete_alert.py index ed2a6820..dd3cfe84 100755 --- a/examples/delete_alert.py +++ b/examples/delete_alert.py @@ -4,9 +4,8 @@ # import getopt -import os import sys -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) + from sdcclient import SdcClient diff --git a/examples/delete_all_policies.py b/examples/delete_all_policies.py index 9e249b37..0cb3a1c9 100755 --- a/examples/delete_all_policies.py +++ b/examples/delete_all_policies.py @@ -3,10 +3,8 @@ # Delete all secure policies. # -import os import sys -import json -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) + from sdcclient import SdSecureClient diff --git a/examples/delete_all_policies_v1.py b/examples/delete_all_policies_v1.py index 025e00ef..b13a3d27 100755 --- a/examples/delete_all_policies_v1.py +++ b/examples/delete_all_policies_v1.py @@ -3,10 +3,8 @@ # Delete all secure policies. # -import os import sys -import json -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) + from sdcclient import SdSecureClientV1 diff --git a/examples/delete_dashboard.py b/examples/delete_dashboard.py index e7c32bd3..220a4122 100755 --- a/examples/delete_dashboard.py +++ b/examples/delete_dashboard.py @@ -4,9 +4,8 @@ # import getopt -import os import sys -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) + from sdcclient import SdMonitorClient diff --git a/examples/delete_event.py b/examples/delete_event.py index a9d2d77c..dff7edb7 100755 --- a/examples/delete_event.py +++ b/examples/delete_event.py @@ -4,10 +4,8 @@ # import getopt -import json -import os import sys -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) + from sdcclient import SdcClient diff --git a/examples/delete_policy.py b/examples/delete_policy.py index 03a9e85b..c644da2d 100755 --- a/examples/delete_policy.py +++ b/examples/delete_policy.py @@ -3,11 +3,10 @@ # Delete a policy, by either id or name. # -import os -import sys -import json import getopt -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) +import json +import sys + from sdcclient import SdSecureClient diff --git a/examples/delete_policy_v1.py b/examples/delete_policy_v1.py index c566f5b4..bd8f7f06 100755 --- a/examples/delete_policy_v1.py +++ b/examples/delete_policy_v1.py @@ -3,11 +3,10 @@ # Delete a policy, by either id or name. # -import os -import sys -import json import getopt -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) +import json +import sys + from sdcclient import SdSecureClientV1 diff --git a/examples/download_dashboards.py b/examples/download_dashboards.py index 120c2182..860acc29 100755 --- a/examples/download_dashboards.py +++ b/examples/download_dashboards.py @@ -6,8 +6,7 @@ import os import sys import zipfile -import json -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) + from sdcclient import SdMonitorClient @@ -19,9 +18,9 @@ def zipdir(path, ziph): def cleanup_dir(path): - if os.path.exists(path) == False: + if not os.path.exists(path): return - if os.path.isdir(path) == False: + if not os.path.isdir(path): print('Provided path is not a directory') sys.exit(-1) @@ -66,7 +65,6 @@ def cleanup_dir(path): print(res) sys.exit(1) - # Clean up any state in the tmp directory cleanup_dir(sysdig_dashboard_dir) @@ -74,7 +72,6 @@ def cleanup_dir(path): if not os.path.exists(sysdig_dashboard_dir): os.makedirs(sysdig_dashboard_dir) - for db in res['dashboards']: sdclient.save_dashboard_to_file(db, os.path.join(sysdig_dashboard_dir, str(db['id']))) diff --git a/examples/flip_alerts_enabled.py b/examples/flip_alerts_enabled.py index 00715bfa..62075854 100755 --- a/examples/flip_alerts_enabled.py +++ b/examples/flip_alerts_enabled.py @@ -6,9 +6,8 @@ # import getopt -import os import sys -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) + from sdcclient import SdcClient @@ -53,10 +52,7 @@ def usage(): alert_found = True print(("Updating \'" + alert['name'] + "\'. Enabled status before change:")) print((alert['enabled'])) - if alert['enabled'] == True: - alert['enabled'] = False - else: - alert['enabled'] = True + alert['enabled'] = not alert['enabled'] ok, res_update = sdclient.update_alert(alert) if not ok: diff --git a/examples/get_agents_config.py b/examples/get_agents_config.py index b5c3048e..f13785b0 100755 --- a/examples/get_agents_config.py +++ b/examples/get_agents_config.py @@ -6,9 +6,8 @@ # the set_agents_config script. # -import os import sys -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) + from sdcclient import SdcClient # @@ -35,7 +34,7 @@ # Return the result # if ok: - if not("files" in res) or len(res["files"]) == 0: + if not ("files" in res) or len(res["files"]) == 0: print("No current auto configuration") else: print("Current contents of config file:") diff --git a/examples/get_anchore_users_account.py b/examples/get_anchore_users_account.py index 5ff7bcb7..e7703654 100644 --- a/examples/get_anchore_users_account.py +++ b/examples/get_anchore_users_account.py @@ -3,9 +3,8 @@ # Get a specific anchore user account # -import os import sys -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) + from sdcclient import SdScanningClient diff --git a/examples/get_data_advanced.py b/examples/get_data_advanced.py index c05c32b8..a1959aa6 100755 --- a/examples/get_data_advanced.py +++ b/examples/get_data_advanced.py @@ -7,12 +7,10 @@ # busiest containers inside the given host, with 1 minute data granularity # -import os -import sys import json -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) -from sdcclient import SdcClient +import sys +from sdcclient import SdcClient # # Parse arguments @@ -62,13 +60,13 @@ # # Fire the query. # -ok, res = sdclient.get_data(metrics=metrics, # List of metrics to query - start_ts=-600, # Start of query span is 600 seconds ago - end_ts=0, # End the query span now - sampling_s=60, # 1 data point per minute - filter=filter, # The filter specifying the target host - paging=paging, # Paging to limit to just the 5 most busy - datasource_type='container') # The source for our metrics is the container +ok, res = sdclient.get_data(metrics=metrics, # List of metrics to query + start_ts=-600, # Start of query span is 600 seconds ago + end_ts=0, # End the query span now + sampling_s=60, # 1 data point per minute + filter=filter, # The filter specifying the target host + paging=paging, # Paging to limit to just the 5 most busy + datasource_type='container') # The source for our metrics is the container # # Show the result! diff --git a/examples/get_data_datasource.py b/examples/get_data_datasource.py index e1492b81..e7625079 100755 --- a/examples/get_data_datasource.py +++ b/examples/get_data_datasource.py @@ -4,9 +4,8 @@ # by providing a few clarifying examples # -import os import sys -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) + from sdcclient import SdcClient # @@ -39,8 +38,8 @@ req = [{"id": "host.hostName"}] req.extend(cpu_metric) ok, res = sdclient.get_data(req, # metrics list - -600, # start_ts = 600 seconds ago - 0) # end_ts = now + -600, # start_ts = 600 seconds ago + 0) # end_ts = now if ok: data = res @@ -57,9 +56,9 @@ # req = [{"id": "container.name"}] req.extend(cpu_metric) -ok, res = sdclient.get_data(req, # metrics list +ok, res = sdclient.get_data(req, # metrics list -600, # start_ts = 600 seconds ago - 0) # end_ts = now + 0) # end_ts = now if ok: data = res @@ -74,9 +73,9 @@ # Third example: CPU average across all hosts # datasource_type is set to host since no grouping keys or filters are specified (default would be host anyway) # -ok, res = sdclient.get_data(cpu_metric, # metrics list - -600, # start_ts = 600 seconds ago - 0, # end_ts = now +ok, res = sdclient.get_data(cpu_metric, # metrics list + -600, # start_ts = 600 seconds ago + 0, # end_ts = now datasource_type='host') # ask data from hosts if ok: @@ -92,9 +91,9 @@ # Third example: CPU average across all containers # datasource_type is set to container since no grouping keys or filters are specified (ovverrides the host default) # -ok, res = sdclient.get_data(cpu_metric, # metrics list - -600, # start_ts = 600 seconds ago - 0, # end_ts = now +ok, res = sdclient.get_data(cpu_metric, # metrics list + -600, # start_ts = 600 seconds ago + 0, # end_ts = now datasource_type='container') # ask data from containers if ok: diff --git a/examples/get_data_simple.py b/examples/get_data_simple.py index 9cbf9607..2da2ffb6 100755 --- a/examples/get_data_simple.py +++ b/examples/get_data_simple.py @@ -7,9 +7,8 @@ # the last 10 minutes, with 1 minute data granularity # -import os import sys -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) + from sdcclient import SdcClient # @@ -93,7 +92,9 @@ # # Print table headers # - dataToPrint = ' '.join([str(x['id']).ljust(colLen) if len(str(x['id'])) < colLen else str(x['id'])[:(colLen - 3)].ljust(colLen - 3) + '...' for x in metrics]) + dataToPrint = ' '.join([str(x['id']).ljust(colLen) if len(str(x['id'])) < colLen else str(x['id'])[ + :(colLen - 3)].ljust( + colLen - 3) + '...' for x in metrics]) print(('%s %s' % ('timestamp'.ljust(colLen), dataToPrint) if sampling > 0 else dataToPrint)) print('') @@ -104,7 +105,9 @@ timestamp = d['t'] if sampling > 0 else start values = d['d'] - dataToPrint = ' '.join([str(x).ljust(colLen) if len(str(x)) < colLen else str(x)[:(colLen - 3)].ljust(colLen - 3) + '...' for x in values]) + dataToPrint = ' '.join( + [str(x).ljust(colLen) if len(str(x)) < colLen else str(x)[:(colLen - 3)].ljust(colLen - 3) + '...' for x in + values]) print(('%s %s' % (('' % (timestamp)).ljust(colLen), dataToPrint) if sampling > 0 else dataToPrint)) diff --git a/examples/get_image_info_by_id.py b/examples/get_image_info_by_id.py index 0375be7f..00857832 100644 --- a/examples/get_image_info_by_id.py +++ b/examples/get_image_info_by_id.py @@ -3,9 +3,8 @@ # Get an image scan result given image id # -import os import sys -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) + from sdcclient import SdScanningClient diff --git a/examples/get_image_scan_result_by_id.py b/examples/get_image_scan_result_by_id.py index eaf3957d..de8b2a87 100644 --- a/examples/get_image_scan_result_by_id.py +++ b/examples/get_image_scan_result_by_id.py @@ -3,9 +3,8 @@ # Get an image scan result given image id # -import os import sys -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) + from sdcclient import SdScanningClient diff --git a/examples/get_latest_pdf_report_by_digest.py b/examples/get_latest_pdf_report_by_digest.py index 09f02546..78495c14 100644 --- a/examples/get_latest_pdf_report_by_digest.py +++ b/examples/get_latest_pdf_report_by_digest.py @@ -3,9 +3,8 @@ # Get a specific policy # -import os import sys -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) + from sdcclient import SdScanningClient @@ -14,6 +13,7 @@ def usage(): print('You can find your token at https://secure.sysdig.com/#/settings/user') sys.exit(1) + # # Parse arguments # diff --git a/examples/get_pdf_report.py b/examples/get_pdf_report.py index 9b5ebb48..33136d46 100755 --- a/examples/get_pdf_report.py +++ b/examples/get_pdf_report.py @@ -3,9 +3,8 @@ # Get a specific policy # -import os import sys -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) + from sdcclient import SdScanningClient diff --git a/examples/get_policy.py b/examples/get_policy.py index 163371df..99db48c8 100755 --- a/examples/get_policy.py +++ b/examples/get_policy.py @@ -3,10 +3,9 @@ # Get a specific policy # -import os -import sys import json -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) +import sys + from sdcclient import SdSecureClient diff --git a/examples/get_policy_v1.py b/examples/get_policy_v1.py index 73b26c5e..b94d1e7d 100755 --- a/examples/get_policy_v1.py +++ b/examples/get_policy_v1.py @@ -3,10 +3,9 @@ # Get a specific policy # -import os -import sys import json -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) +import sys + from sdcclient import SdSecureClientV1 diff --git a/examples/get_secure_default_falco_rules_files.py b/examples/get_secure_default_falco_rules_files.py index 3771a0e2..be526718 100755 --- a/examples/get_secure_default_falco_rules_files.py +++ b/examples/get_secure_default_falco_rules_files.py @@ -8,11 +8,10 @@ # a given file that are compatible with different agent versions. # -import os -import sys -import pprint import getopt -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) +import pprint +import sys + from sdcclient import SdSecureClient diff --git a/examples/get_secure_policy_events.py b/examples/get_secure_policy_events.py index 40356a6e..cd027b80 100755 --- a/examples/get_secure_policy_events.py +++ b/examples/get_secure_policy_events.py @@ -11,18 +11,18 @@ # Progress information is written to standard error. # -import os -import sys +import getopt import json import operator import re -import getopt -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) +import sys + from sdcclient import SdSecureClient def usage(): - print(('usage: %s [-s|--summarize] [-l|--limit ] [| ]' % sys.argv[0])) + print(('usage: %s [-s|--summarize] [-l|--limit ] [| ]' % + sys.argv[0])) print('-s|--summarize: group policy events by sanitized output and print by frequency') print('-l|--limit: with -s, only print the first outputs') print('You can find your token at https://secure.sysdig.com/#/settings/user') diff --git a/examples/get_secure_system_falco_rules.py b/examples/get_secure_system_falco_rules.py index d54eb3c0..e2672279 100755 --- a/examples/get_secure_system_falco_rules.py +++ b/examples/get_secure_system_falco_rules.py @@ -3,9 +3,8 @@ # Get the sysdig secure system rules file. # -import os import sys -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) + from sdcclient import SdSecureClient # diff --git a/examples/get_secure_user_falco_rules.py b/examples/get_secure_user_falco_rules.py index fd21f907..91d84e26 100755 --- a/examples/get_secure_user_falco_rules.py +++ b/examples/get_secure_user_falco_rules.py @@ -3,9 +3,8 @@ # Get the sysdig secure user rules file. # -import os import sys -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) + from sdcclient import SdSecureClient # diff --git a/examples/list_admins.py b/examples/list_admins.py index 17cc0dae..048a45cf 100755 --- a/examples/list_admins.py +++ b/examples/list_admins.py @@ -7,9 +7,8 @@ # install) will be highlighted. # -import os import sys -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) + from sdcclient import SdcClient # diff --git a/examples/list_alert_notifications.py b/examples/list_alert_notifications.py index 2dcbe400..b64ff355 100755 --- a/examples/list_alert_notifications.py +++ b/examples/list_alert_notifications.py @@ -3,10 +3,9 @@ # Get alert notifications from Sysdig Cloud # -import os import sys import time -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) + from sdcclient import SdcClient @@ -18,7 +17,8 @@ def print_notifications(notifications): values.append(str(value['value'])) notification.update({'values': ','.join(values)}) notification["filter"] = notification.get("filter", "") - print("#%(id)s, State: %(state)s, Severity: %(severity)s, Scope: %(filter)s, Condition: %(condition)s, Value: %(values)s, Resolved: %(resolved)s" % + print("#%(id)s, State: %(state)s, Severity: %(severity)s, Scope: %(filter)s, Condition: %(condition)s, " + "Value: %(values)s, Resolved: %(resolved)s" % notification) diff --git a/examples/list_alerts.py b/examples/list_alerts.py index b041d7cc..95ff1d68 100755 --- a/examples/list_alerts.py +++ b/examples/list_alerts.py @@ -4,10 +4,9 @@ # Optionally dump the full Alerts list as a JSON object to a target file. # -import os -import sys import json -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) +import sys + from sdcclient import SdcClient # diff --git a/examples/list_dashboards.py b/examples/list_dashboards.py index a8c076b6..0023bdce 100755 --- a/examples/list_dashboards.py +++ b/examples/list_dashboards.py @@ -3,9 +3,8 @@ # Print the list of dashboards. # -import os import sys -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) + from sdcclient import SdMonitorClient # diff --git a/examples/list_events.py b/examples/list_events.py index 98703fc9..bddc6167 100755 --- a/examples/list_events.py +++ b/examples/list_events.py @@ -3,9 +3,8 @@ # Get user events from Sysdig Cloud # -import os import sys -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) + from sdcclient import SdcClient @@ -13,7 +12,8 @@ def print_events(data): for event in data['events']: event['sev'] = event.get('severity', 'not set') event['description'] = event.get('description', 'not set') - print(('id: %(id)s, time: %(timestamp)d, name: %(name)s, description: %(description)s, severity: %(sev)s' % event)) + print(('id: %(id)s, time: %(timestamp)d, name: %(name)s, description: %(description)s, severity: %(sev)s' + % event)) # diff --git a/examples/list_hosts.py b/examples/list_hosts.py index c5b26cfd..fb767d86 100755 --- a/examples/list_hosts.py +++ b/examples/list_hosts.py @@ -13,9 +13,8 @@ # import getopt import json -import os import sys -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) + from sdcclient import SdcClient @@ -67,7 +66,7 @@ def usage(): -duration, # start time: either a unix timestamp, or a difference from "now" 0, # end time: either a unix timestamp, or a difference from "now" (0 means you need "last X seconds") duration, # sampling time, ie. data granularity; - # if equal to the time window span then the result will contain a single sample + # if equal to the time window span then the result will contain a single sample paging={ "from": 0, "to": count - 1 diff --git a/examples/list_metrics.py b/examples/list_metrics.py index 76223612..a9da394b 100755 --- a/examples/list_metrics.py +++ b/examples/list_metrics.py @@ -3,9 +3,8 @@ # Print the list of metrics. # -import os import sys -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) + from sdcclient import SdcClient # diff --git a/examples/list_notification_channels.py b/examples/list_notification_channels.py index 59d2a973..3025c230 100755 --- a/examples/list_notification_channels.py +++ b/examples/list_notification_channels.py @@ -3,10 +3,9 @@ # Post a user event to Sysdig Cloud # -import os -import sys import json -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) +import sys + from sdcclient import SdcClient # diff --git a/examples/list_policies.py b/examples/list_policies.py index bddbac09..2146c93d 100755 --- a/examples/list_policies.py +++ b/examples/list_policies.py @@ -3,11 +3,9 @@ # List the current set of secure policies. # -import os -import sys import json -import getopt -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) +import sys + from sdcclient import SdSecureClient diff --git a/examples/list_policies_v1.py b/examples/list_policies_v1.py index 15a30dde..30758a7f 100755 --- a/examples/list_policies_v1.py +++ b/examples/list_policies_v1.py @@ -3,17 +3,17 @@ # List the current set of secure policies. # -import os -import sys -import json import getopt -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) +import json +import sys + from sdcclient import SdSecureClientV1 def usage(): print(('usage: %s [-o|--order-only] ' % sys.argv[0])) - print('-o|--order-only: Only display the list of policy ids in evaluation order. Suitable for use by set_policy_order.py') + print('-o|--order-only: Only display the list of policy ids in evaluation order. ' + 'Suitable for use by set_policy_order.py') print('You can find your token at https://secure.sysdig.com/#/settings/user') sys.exit(1) diff --git a/examples/list_profiles.py b/examples/list_profiles.py index 86a0846f..963e4db8 100755 --- a/examples/list_profiles.py +++ b/examples/list_profiles.py @@ -3,10 +3,8 @@ # List the current set of image profiles. # -import os import sys -import json -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) + from sdcclient import SdSecureClient @@ -22,7 +20,7 @@ def usage(): usage() sdc_endpoint = sys.argv[1] -sdc_token = sys.argv[2] +sdc_token = sys.argv[2] # # Instantiate the SDC client @@ -34,14 +32,12 @@ def usage(): # ok, res = sdclient.list_image_profiles() - if not ok: print(res) sys.exit(1) - # Strip the surrounding json to only keep the list of profiles res = res['profiles'] for profile in res: - print(("ID: {}, Name: {}".format(profile["profileId"], profile["imageName"]))) \ No newline at end of file + print(("ID: {}, Name: {}".format(profile["profileId"], profile["imageName"]))) diff --git a/examples/list_sysdig_captures.py b/examples/list_sysdig_captures.py index 95f6cb6f..fb72b4b0 100755 --- a/examples/list_sysdig_captures.py +++ b/examples/list_sysdig_captures.py @@ -3,9 +3,8 @@ # Print the list of sysdig captures. # -import os import sys -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) + from sdcclient import SdcClient # @@ -39,4 +38,4 @@ for capture in captures: print(("Folder %s, Name %s, Host: %s, Size: %d, Status: %s" % - (capture['folder'], capture['name'], capture['agent']['hostName'], capture['size'], capture['status']))) + (capture['folder'], capture['name'], capture['agent']['hostName'], capture['size'], capture['status']))) diff --git a/examples/list_users.py b/examples/list_users.py index 23a30d7b..642d7904 100755 --- a/examples/list_users.py +++ b/examples/list_users.py @@ -4,9 +4,8 @@ # have Admin rights. # -import os import sys -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) + from sdcclient import SdcClient # diff --git a/examples/notification_channels.py b/examples/notification_channels.py index e8ac4447..bf93eed8 100755 --- a/examples/notification_channels.py +++ b/examples/notification_channels.py @@ -4,9 +4,8 @@ # import getopt -import os import sys -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) + from sdcclient import SdcClient @@ -44,7 +43,8 @@ def usage(): # # Create an email notification channel # -ok, res = sdclient.create_email_notification_channel(channel_name, ['gianluca.borello@sysdig.com', 'foo@sysdig.com', 'bar@sysdig.com']) +ok, res = sdclient.create_email_notification_channel(channel_name, ['gianluca.borello@sysdig.com', 'foo@sysdig.com', + 'bar@sysdig.com']) if not ok: print(res) sys.exit(1) diff --git a/examples/post_event.py b/examples/post_event.py index 534fb9bd..10bb8ea0 100755 --- a/examples/post_event.py +++ b/examples/post_event.py @@ -3,11 +3,10 @@ # Post a user event to Sysdig Cloud # -import os -import sys -import json import argparse -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) +import json +import sys + from sdcclient import SdcClient # @@ -18,8 +17,11 @@ parser = argparse.ArgumentParser() parser.add_argument('-d', '--description') parser.add_argument('-s', '--severity', help='syslog style from 0 (high) to 7 (low)') -parser.add_argument('-c', '--scope', help='metadata, in Sysdig Cloud format, of nodes to associate with the event, eg: \'host.hostName = "ip-10-1-1-1" and container.name = "foo"\'') -parser.add_argument('-t', '--tags', help='dictionary of arbitrary key-value pairs, eg: \'{"app":"my_app", "file":"text.py"}\'') +parser.add_argument('-c', '--scope', + help='metadata, in Sysdig Cloud format, of nodes to associate with the event, ' + 'eg: \'host.hostName = "ip-10-1-1-1" and container.name = "foo"\'') +parser.add_argument('-t', '--tags', + help='dictionary of arbitrary key-value pairs, eg: \'{"app":"my_app", "file":"text.py"}\'') parser.add_argument('sysdig_token', help='You can find your token at https://app.sysdigcloud.com/#/settings/user') parser.add_argument('name') args = parser.parse_args() diff --git a/examples/post_event_simple.py b/examples/post_event_simple.py index 6f342f39..61f0cda4 100755 --- a/examples/post_event_simple.py +++ b/examples/post_event_simple.py @@ -3,9 +3,8 @@ # Post a user event to Sysdig Cloud # -import os import sys -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) + from sdcclient import SdcClient # diff --git a/examples/print_conn_table.py b/examples/print_conn_table.py index d352a2bd..dadc71d5 100755 --- a/examples/print_conn_table.py +++ b/examples/print_conn_table.py @@ -4,9 +4,8 @@ # mimicking the top connections table in the Sysdig Monitor UI # -import os import sys -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) + from sdcclient import SdcClient # @@ -108,7 +107,7 @@ row_format = "{:20.20}\t{:20.20}\t{:20.20}\t{:20.20}\t{:10}\t{:10}\t{:10}\t{:10}\t{:10}\t{:10}\t{:10}" print((row_format.format("Source", "Source Process", "Destination", "Destination Process", "Count", - "Bytes In", "Bytes Out", "Bytes", "Req In", "Req Out", "Req"))) + "Bytes In", "Bytes Out", "Bytes", "Req In", "Req Out", "Req"))) while cur < fetch_limit: paging = {'from': cur, 'to': cur + page_size} diff --git a/examples/print_data_retention_info.py b/examples/print_data_retention_info.py index fff3d977..b0e97ff6 100755 --- a/examples/print_data_retention_info.py +++ b/examples/print_data_retention_info.py @@ -3,9 +3,8 @@ # Print the different retention intervals available for data export. # -import os import sys -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) + from sdcclient import SdcClient # diff --git a/examples/print_explore_grouping.py b/examples/print_explore_grouping.py index ec5fa9f8..4ee28154 100755 --- a/examples/print_explore_grouping.py +++ b/examples/print_explore_grouping.py @@ -3,9 +3,8 @@ # Print the user's Explore grouping hierarchy. # -import os import sys -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) + from sdcclient import SdcClient # diff --git a/examples/print_user_info.py b/examples/print_user_info.py index 5a67b497..e7cbb302 100755 --- a/examples/print_user_info.py +++ b/examples/print_user_info.py @@ -4,9 +4,8 @@ # identified by the given token. # -import os import sys -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) + from sdcclient import SdcClient # diff --git a/examples/resolve_alert_notifications.py b/examples/resolve_alert_notifications.py index 8f5ae4ee..2aab3e0c 100755 --- a/examples/resolve_alert_notifications.py +++ b/examples/resolve_alert_notifications.py @@ -3,10 +3,9 @@ # Resolve alert notifications from Sysdig Cloud # -import os import sys import time -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) + from sdcclient import SdcClient # diff --git a/examples/restore_alerts.py b/examples/restore_alerts.py index 5b89e6bc..b30a6e91 100755 --- a/examples/restore_alerts.py +++ b/examples/restore_alerts.py @@ -3,12 +3,9 @@ # Restore Alerts of the format in a JSON dumpfile from the list_alerts.py example. # -import os -import sys import json -import datetime -import calendar -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) +import sys + from sdcclient import SdcClient # @@ -66,7 +63,8 @@ if 'notificationChannelIds' in a: for channel_id in a['notificationChannelIds']: if channel_id not in existing_notification_channel_ids: - print(('Notification Channel ID ' + str(channel_id) + ' referenced in Alert "' + a['name'] + '" does not exist.\n Restoring without this ID.')) + print(('Notification Channel ID ' + str(channel_id) + ' referenced in Alert "' + a[ + 'name'] + '" does not exist.\n Restoring without this ID.')) a['notificationChannelIds'].remove(channel_id) # The Create/Update APIs will validate but actually ignore these fields; @@ -98,4 +96,4 @@ sys.exit(1) print(('All Alerts in ' + alerts_dump_file + ' restored successfully (' - + str(created_count) + ' created, ' + str(updated_count) + ' updated)')) + + str(created_count) + ' created, ' + str(updated_count) + ' updated)')) diff --git a/examples/restore_dashboards.py b/examples/restore_dashboards.py index 9825cae5..c29720d2 100755 --- a/examples/restore_dashboards.py +++ b/examples/restore_dashboards.py @@ -3,11 +3,10 @@ # Save/restore dashboards # -import os +import json import sys import zipfile -import json -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) + from sdcclient import SdMonitorClient # diff --git a/examples/set_agents_config.py b/examples/set_agents_config.py index d09dd836..963053bd 100755 --- a/examples/set_agents_config.py +++ b/examples/set_agents_config.py @@ -7,10 +7,10 @@ # edit it and then push it back with this script. # -import os import sys + import yaml -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) + from sdcclient import SdcClient # diff --git a/examples/set_explore_group_configuration.py b/examples/set_explore_group_configuration.py index 6da11b97..112b3fad 100755 --- a/examples/set_explore_group_configuration.py +++ b/examples/set_explore_group_configuration.py @@ -3,9 +3,8 @@ # Set the group configuration in explore. # -import os import sys -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) + from sdcclient import SdcClient # diff --git a/examples/set_policy_order_v1.py b/examples/set_policy_order_v1.py index 6ee10646..e2b7d812 100755 --- a/examples/set_policy_order_v1.py +++ b/examples/set_policy_order_v1.py @@ -3,10 +3,9 @@ # Change the evaluation order of policies to match the provided json. # -import os -import sys import json -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) +import sys + from sdcclient import SdSecureClientV1 diff --git a/examples/set_secure_default_falco_rules_files.py b/examples/set_secure_default_falco_rules_files.py index 247267a9..a0b49a57 100755 --- a/examples/set_secure_default_falco_rules_files.py +++ b/examples/set_secure_default_falco_rules_files.py @@ -8,13 +8,12 @@ # a given file that are compatible with different agent versions. # +import getopt import os import sys -import pprint -import getopt -import shutil + import yaml -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) + from sdcclient import SdSecureClient @@ -81,7 +80,8 @@ def usage(): try: required_engine_version = int(obj["required_engine_version"]) except ValueError: - print(("Required engine version \"{}\" in content {} must be a number".format(obj["required_engine_version"], cpath))) + print(("Required engine version \"{}\" in content {} must be a number".format( + obj["required_engine_version"], cpath))) sys.exit(1) files_obj = { "tag": tag, diff --git a/examples/set_secure_system_falco_rules.py b/examples/set_secure_system_falco_rules.py index 2e6cf366..6ae7b185 100755 --- a/examples/set_secure_system_falco_rules.py +++ b/examples/set_secure_system_falco_rules.py @@ -5,10 +5,10 @@ # system falco rules file for this customer to that file. # -import os import sys + import yaml -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) + from sdcclient import SdSecureClient # diff --git a/examples/set_secure_user_falco_rules.py b/examples/set_secure_user_falco_rules.py index 168c259e..ec790375 100755 --- a/examples/set_secure_user_falco_rules.py +++ b/examples/set_secure_user_falco_rules.py @@ -5,10 +5,10 @@ # system falco rules file for this customer to that file. # -import os import sys + import yaml -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) + from sdcclient import SdSecureClient # diff --git a/examples/update_alert.py b/examples/update_alert.py index 6bcc6e4f..d134d7b8 100755 --- a/examples/update_alert.py +++ b/examples/update_alert.py @@ -6,10 +6,9 @@ # import getopt -import os -import sys import json -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) +import sys + from sdcclient import SdcClient @@ -59,7 +58,7 @@ def usage(): update_txt = ' (changed by update_alert)' if alert['description'][-len(update_txt):] != update_txt: alert['description'] = alert['description'] + update_txt - alert['timespan'] = alert['timespan'] * 2 # Note: Expressed in seconds * 1000000 + alert['timespan'] = alert['timespan'] * 2 # Note: Expressed in seconds * 1000000 ok, res_update = sdclient.update_alert(alert) if not ok: diff --git a/examples/update_policy.py b/examples/update_policy.py index bc102913..f5b8d3ab 100755 --- a/examples/update_policy.py +++ b/examples/update_policy.py @@ -3,10 +3,9 @@ # Update a specific policy # -import os -import sys import json -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) +import sys + from sdcclient import SdSecureClient @@ -41,5 +40,3 @@ def usage(): else: print(res) sys.exit(1) - - diff --git a/examples/update_policy_v1.py b/examples/update_policy_v1.py index f0eec26b..d4eb056a 100755 --- a/examples/update_policy_v1.py +++ b/examples/update_policy_v1.py @@ -3,10 +3,9 @@ # Update a specific policy # -import os -import sys import json -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) +import sys + from sdcclient import SdSecureClientV1 @@ -41,5 +40,3 @@ def usage(): else: print(res) sys.exit(1) - - diff --git a/examples/user_team_mgmt.py b/examples/user_team_mgmt.py index e2cea0ff..214049d1 100755 --- a/examples/user_team_mgmt.py +++ b/examples/user_team_mgmt.py @@ -3,10 +3,10 @@ # This example shows the different aspects of user/team management. # -import os import sys -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) + from sdcclient import SdcClient + # # Parse arguments # diff --git a/examples/user_team_mgmt_extended.py b/examples/user_team_mgmt_extended.py index 32e81369..ff33a1f9 100755 --- a/examples/user_team_mgmt_extended.py +++ b/examples/user_team_mgmt_extended.py @@ -3,9 +3,8 @@ # This example shows the different aspects of user/team management. # -import os import sys -sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), '..')) + from sdcclient import SdcClient # @@ -77,7 +76,6 @@ # error as a genuine fail of the test. # - print('Creating test teams...') ok, res = sdclient.create_team(teamA) @@ -167,7 +165,8 @@ # Add new or update existing memberships ok, res = sdclient.save_memberships(teamA, {userA: 'ROLE_TEAM_READ', userB: 'ROLE_TEAM_EDIT'}) if not ok: - print(('-- Unable to modify membership for ', userA, ' and to add ', userB, ' to ', teamA, ' due to: ', res, '. Exiting.')) + print(('-- Unable to modify membership for ', userA, ' and to add ', userB, ' to ', teamA, ' due to: ', res, + '. Exiting.')) sys.exit(1) ok, res = sdclient.list_memberships(teamA) @@ -178,7 +177,8 @@ print(('-- Users ', userA, ', ', userB, ' and ', admin, ' should be part of team ', teamA, '!', 'Exiting.')) sys.exit(1) elif res[userA] != 'ROLE_TEAM_READ' or res[userB] != 'ROLE_TEAM_EDIT': - print(('-- Users ', userA, ' and ', userB, ' should have appropriate roles assigned for team ', teamA, '!', 'Exiting.')) + print(('-- Users ', userA, ' and ', userB, ' should have appropriate roles assigned for team ', teamA, '!', + 'Exiting.')) sys.exit(1) # Remove team memberships @@ -237,7 +237,6 @@ except Exception as exception: print(('-- Team \'', teamB, '\' deletion failed: ', exception)) - print('-- Deleting test users.') try: @@ -261,7 +260,6 @@ except Exception as exception: print(('-- User \'', userB, '\' deletion failed: ', exception)) - print('All done successfully!!!') sys.exit(0) From ecd50b965590316274424b2b58df2353e479f694 Mon Sep 17 00:00:00 2001 From: Federico Barcelona Date: Mon, 10 Aug 2020 09:58:35 +0200 Subject: [PATCH 2/4] ci: Add flake8 to dev dependencies --- Pipfile | 1 + Pipfile.lock | 167 ++++++++++++++++++++++++++++++++------------------- 2 files changed, 105 insertions(+), 63 deletions(-) diff --git a/Pipfile b/Pipfile index a29ad8c6..9a3484e8 100644 --- a/Pipfile +++ b/Pipfile @@ -9,6 +9,7 @@ doublex = "*" doublex-expects = "*" expects = "*" sdcclient = {editable = true,path = "."} +flake8 = "*" [packages] requests = "*" diff --git a/Pipfile.lock b/Pipfile.lock index d5ae936f..4dc88e9c 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "28fd7960027212644cd5e7b1c46aa8425a1cfccf6bd47ef3f73f95c2d27d38d8" + "sha256": "b1dcbe4d8658c5a20a21a43a3e6a4d97d18d68aa380560c5e079fd370f2d3291" }, "pipfile-spec": 6, "requires": { @@ -18,10 +18,10 @@ "default": { "certifi": { "hashes": [ - "sha256:1d987a998c75633c40847cc966fcf5904906c920a7f17ef374f5aa4282abd304", - "sha256:51fcb31174be6e6664c5f69e3e1691a2d72a1a12e90f872cbdb1567eb47b6519" + "sha256:5930595817496dd21bb8dc35dad090f1c2cd0adfaf21204bf6732ca5d8ee34d3", + "sha256:8fc0819f1f30ba15bdb34cceffb9ef04d99f420f68eb75d901e9560b8749fc41" ], - "version": "==2020.4.5.1" + "version": "==2020.6.20" }, "chardet": { "hashes": [ @@ -32,10 +32,11 @@ }, "idna": { "hashes": [ - "sha256:7588d1c14ae4c77d74036e8c22ff447b26d0fde8f007354fd48a7814db15b7cb", - "sha256:a068a21ceac8a4d63dbfd964670474107f541babbd2250d61922f029858365fa" + "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6", + "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0" ], - "version": "==2.9" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==2.10" }, "pyaml": { "hashes": [ @@ -63,11 +64,11 @@ }, "requests": { "hashes": [ - "sha256:43999036bfa82904b6af1d99e4882b560e5e2c68e5c4b0aa03b655f3d7d73fee", - "sha256:b3f43d496c6daba4493e7c431722aeb7dbc6288f52a6e04e7b6023b0247817e6" + "sha256:b3559a131db72c33ee969480840fff4bb6dd111de7dd27c8ee1f820f4f00231b", + "sha256:fe75cc94a9443b9246fc7049224f75604b113c36acb93f87b80ed42c44cbb898" ], "index": "pypi", - "version": "==2.23.0" + "version": "==2.24.0" }, "requests-toolbelt": { "hashes": [ @@ -79,10 +80,11 @@ }, "urllib3": { "hashes": [ - "sha256:3018294ebefce6572a474f0604c2021e33b3fd8006ecd11d62107a5d2a963527", - "sha256:88206b0eb87e6d677d424843ac5209e3fb9d0190d0ee169599165ec25e9d9115" + "sha256:91056c15fa70756691db97756772bb1eb9678fa585d9184f24534b100dc60f4a", + "sha256:e7983572181f5e1522d9c98453462384ee92a0be7fac5f1413a1e35c56cc0461" ], - "version": "==1.25.9" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'", + "version": "==1.25.10" } }, "develop": { @@ -94,10 +96,10 @@ }, "certifi": { "hashes": [ - "sha256:1d987a998c75633c40847cc966fcf5904906c920a7f17ef374f5aa4282abd304", - "sha256:51fcb31174be6e6664c5f69e3e1691a2d72a1a12e90f872cbdb1567eb47b6519" + "sha256:5930595817496dd21bb8dc35dad090f1c2cd0adfaf21204bf6732ca5d8ee34d3", + "sha256:8fc0819f1f30ba15bdb34cceffb9ef04d99f420f68eb75d901e9560b8749fc41" ], - "version": "==2020.4.5.1" + "version": "==2020.6.20" }, "chardet": { "hashes": [ @@ -114,39 +116,43 @@ }, "coverage": { "hashes": [ - "sha256:00f1d23f4336efc3b311ed0d807feb45098fc86dee1ca13b3d6768cdab187c8a", - "sha256:01333e1bd22c59713ba8a79f088b3955946e293114479bbfc2e37d522be03355", - "sha256:0cb4be7e784dcdc050fc58ef05b71aa8e89b7e6636b99967fadbdba694cf2b65", - "sha256:0e61d9803d5851849c24f78227939c701ced6704f337cad0a91e0972c51c1ee7", - "sha256:1601e480b9b99697a570cea7ef749e88123c04b92d84cedaa01e117436b4a0a9", - "sha256:2742c7515b9eb368718cd091bad1a1b44135cc72468c731302b3d641895b83d1", - "sha256:2d27a3f742c98e5c6b461ee6ef7287400a1956c11421eb574d843d9ec1f772f0", - "sha256:402e1744733df483b93abbf209283898e9f0d67470707e3c7516d84f48524f55", - "sha256:5c542d1e62eece33c306d66fe0a5c4f7f7b3c08fecc46ead86d7916684b36d6c", - "sha256:5f2294dbf7875b991c381e3d5af2bcc3494d836affa52b809c91697449d0eda6", - "sha256:6402bd2fdedabbdb63a316308142597534ea8e1895f4e7d8bf7476c5e8751fef", - "sha256:66460ab1599d3cf894bb6baee8c684788819b71a5dc1e8fa2ecc152e5d752019", - "sha256:782caea581a6e9ff75eccda79287daefd1d2631cc09d642b6ee2d6da21fc0a4e", - "sha256:79a3cfd6346ce6c13145731d39db47b7a7b859c0272f02cdb89a3bdcbae233a0", - "sha256:7a5bdad4edec57b5fb8dae7d3ee58622d626fd3a0be0dfceda162a7035885ecf", - "sha256:8fa0cbc7ecad630e5b0f4f35b0f6ad419246b02bc750de7ac66db92667996d24", - "sha256:a027ef0492ede1e03a8054e3c37b8def89a1e3c471482e9f046906ba4f2aafd2", - "sha256:a3f3654d5734a3ece152636aad89f58afc9213c6520062db3978239db122f03c", - "sha256:a82b92b04a23d3c8a581fc049228bafde988abacba397d57ce95fe95e0338ab4", - "sha256:acf3763ed01af8410fc36afea23707d4ea58ba7e86a8ee915dfb9ceff9ef69d0", - "sha256:adeb4c5b608574a3d647011af36f7586811a2c1197c861aedb548dd2453b41cd", - "sha256:b83835506dfc185a319031cf853fa4bb1b3974b1f913f5bb1a0f3d98bdcded04", - "sha256:bb28a7245de68bf29f6fb199545d072d1036a1917dca17a1e75bbb919e14ee8e", - "sha256:bf9cb9a9fd8891e7efd2d44deb24b86d647394b9705b744ff6f8261e6f29a730", - "sha256:c317eaf5ff46a34305b202e73404f55f7389ef834b8dbf4da09b9b9b37f76dd2", - "sha256:dbe8c6ae7534b5b024296464f387d57c13caa942f6d8e6e0346f27e509f0f768", - "sha256:de807ae933cfb7f0c7d9d981a053772452217df2bf38e7e6267c9cbf9545a796", - "sha256:dead2ddede4c7ba6cb3a721870f5141c97dc7d85a079edb4bd8d88c3ad5b20c7", - "sha256:dec5202bfe6f672d4511086e125db035a52b00f1648d6407cc8e526912c0353a", - "sha256:e1ea316102ea1e1770724db01998d1603ed921c54a86a2efcb03428d5417e489", - "sha256:f90bfc4ad18450c80b024036eaf91e4a246ae287701aaa88eaebebf150868052" - ], - "version": "==5.1" + "sha256:098a703d913be6fbd146a8c50cc76513d726b022d170e5e98dc56d958fd592fb", + "sha256:16042dc7f8e632e0dcd5206a5095ebd18cb1d005f4c89694f7f8aafd96dd43a3", + "sha256:1adb6be0dcef0cf9434619d3b892772fdb48e793300f9d762e480e043bd8e716", + "sha256:27ca5a2bc04d68f0776f2cdcb8bbd508bbe430a7bf9c02315cd05fb1d86d0034", + "sha256:28f42dc5172ebdc32622a2c3f7ead1b836cdbf253569ae5673f499e35db0bac3", + "sha256:2fcc8b58953d74d199a1a4d633df8146f0ac36c4e720b4a1997e9b6327af43a8", + "sha256:304fbe451698373dc6653772c72c5d5e883a4aadaf20343592a7abb2e643dae0", + "sha256:30bc103587e0d3df9e52cd9da1dd915265a22fad0b72afe54daf840c984b564f", + "sha256:40f70f81be4d34f8d491e55936904db5c527b0711b2a46513641a5729783c2e4", + "sha256:4186fc95c9febeab5681bc3248553d5ec8c2999b8424d4fc3a39c9cba5796962", + "sha256:46794c815e56f1431c66d81943fa90721bb858375fb36e5903697d5eef88627d", + "sha256:4869ab1c1ed33953bb2433ce7b894a28d724b7aa76c19b11e2878034a4e4680b", + "sha256:4f6428b55d2916a69f8d6453e48a505c07b2245653b0aa9f0dee38785939f5e4", + "sha256:52f185ffd3291196dc1aae506b42e178a592b0b60a8610b108e6ad892cfc1bb3", + "sha256:538f2fd5eb64366f37c97fdb3077d665fa946d2b6d95447622292f38407f9258", + "sha256:64c4f340338c68c463f1b56e3f2f0423f7b17ba6c3febae80b81f0e093077f59", + "sha256:675192fca634f0df69af3493a48224f211f8db4e84452b08d5fcebb9167adb01", + "sha256:700997b77cfab016533b3e7dbc03b71d33ee4df1d79f2463a318ca0263fc29dd", + "sha256:8505e614c983834239f865da2dd336dcf9d72776b951d5dfa5ac36b987726e1b", + "sha256:962c44070c281d86398aeb8f64e1bf37816a4dfc6f4c0f114756b14fc575621d", + "sha256:9e536783a5acee79a9b308be97d3952b662748c4037b6a24cbb339dc7ed8eb89", + "sha256:9ea749fd447ce7fb1ac71f7616371f04054d969d412d37611716721931e36efd", + "sha256:a34cb28e0747ea15e82d13e14de606747e9e484fb28d63c999483f5d5188e89b", + "sha256:a3ee9c793ffefe2944d3a2bd928a0e436cd0ac2d9e3723152d6fd5398838ce7d", + "sha256:aab75d99f3f2874733946a7648ce87a50019eb90baef931698f96b76b6769a46", + "sha256:b1ed2bdb27b4c9fc87058a1cb751c4df8752002143ed393899edb82b131e0546", + "sha256:b360d8fd88d2bad01cb953d81fd2edd4be539df7bfec41e8753fe9f4456a5082", + "sha256:b8f58c7db64d8f27078cbf2a4391af6aa4e4767cc08b37555c4ae064b8558d9b", + "sha256:c1bbb628ed5192124889b51204de27c575b3ffc05a5a91307e7640eff1d48da4", + "sha256:c2ff24df02a125b7b346c4c9078c8936da06964cc2d276292c357d64378158f8", + "sha256:c890728a93fffd0407d7d37c1e6083ff3f9f211c83b4316fae3778417eab9811", + "sha256:c96472b8ca5dc135fb0aa62f79b033f02aa434fb03a8b190600a5ae4102df1fd", + "sha256:ce7866f29d3025b5b34c2e944e66ebef0d92e4a4f2463f7266daa03a1332a651", + "sha256:e26c993bd4b220429d4ec8c1468eca445a4064a61c74ca08da7429af9bc53bb0" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'", + "version": "==5.2.1" }, "doublex": { "hashes": [ @@ -169,19 +175,35 @@ "index": "pypi", "version": "==0.9.0" }, + "flake8": { + "hashes": [ + "sha256:15e351d19611c887e482fb960eae4d44845013cc142d42896e9862f775d8cf5c", + "sha256:f04b9fcbac03b0a3e58c0ab3a0ecc462e023a9faf046d57794184028123aa208" + ], + "index": "pypi", + "version": "==3.8.3" + }, "idna": { "hashes": [ - "sha256:7588d1c14ae4c77d74036e8c22ff447b26d0fde8f007354fd48a7814db15b7cb", - "sha256:a068a21ceac8a4d63dbfd964670474107f541babbd2250d61922f029858365fa" + "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6", + "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0" ], - "version": "==2.9" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==2.10" }, "mamba": { "hashes": [ - "sha256:5fdb77be323dc4c9723f0752ff73d1753a94f3b60bb12ba555370fb3d37feb2e" + "sha256:f976735949bc9a8731cc0876aaea2720949bd3d1554b0e94004c91a4f61abecb" ], "index": "pypi", - "version": "==0.11.0" + "version": "==0.11.1" + }, + "mccabe": { + "hashes": [ + "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", + "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f" + ], + "version": "==0.6.1" }, "pyaml": { "hashes": [ @@ -191,11 +213,28 @@ "index": "pypi", "version": "==20.4.0" }, + "pycodestyle": { + "hashes": [ + "sha256:2295e7b2f6b5bd100585ebcb1f616591b652db8a741695b3d8f5d28bdc934367", + "sha256:c58a7d2815e0e8d7972bf1803331fb0152f867bd89adf8a01dfd55085434192e" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==2.6.0" + }, + "pyflakes": { + "hashes": [ + "sha256:0d94e0e05a19e57a99444b6ddcf9a6eb2e5c68d3ca1e98e90707af8152c90a92", + "sha256:35b2d75ee967ea93b55750aa9edbbf72813e06a66ba54438df2cfac9e3c27fc8" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==2.2.0" + }, "pyhamcrest": { "hashes": [ "sha256:412e00137858f04bde0729913874a48485665f2d36fe9ee449f26be864af9316", "sha256:7ead136e03655af85069b6f47b23eb7c3e5c221aa9f022a4fbb499f5b7308f29" ], + "markers": "python_version >= '3.5'", "version": "==2.0.2" }, "pyyaml": { @@ -216,11 +255,11 @@ }, "requests": { "hashes": [ - "sha256:43999036bfa82904b6af1d99e4882b560e5e2c68e5c4b0aa03b655f3d7d73fee", - "sha256:b3f43d496c6daba4493e7c431722aeb7dbc6288f52a6e04e7b6023b0247817e6" + "sha256:b3559a131db72c33ee969480840fff4bb6dd111de7dd27c8ee1f820f4f00231b", + "sha256:fe75cc94a9443b9246fc7049224f75604b113c36acb93f87b80ed42c44cbb898" ], "index": "pypi", - "version": "==2.23.0" + "version": "==2.24.0" }, "requests-toolbelt": { "hashes": [ @@ -236,17 +275,19 @@ }, "six": { "hashes": [ - "sha256:236bdbdce46e6e6a3d61a337c0f8b763ca1e8717c03b369e87a7ec7ce1319c0a", - "sha256:8f3cd2e254d8f793e7f3d6d9df77b92252b52637291d0f0da013c76ea2724b6c" + "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259", + "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced" ], - "version": "==1.14.0" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==1.15.0" }, "urllib3": { "hashes": [ - "sha256:3018294ebefce6572a474f0604c2021e33b3fd8006ecd11d62107a5d2a963527", - "sha256:88206b0eb87e6d677d424843ac5209e3fb9d0190d0ee169599165ec25e9d9115" + "sha256:91056c15fa70756691db97756772bb1eb9678fa585d9184f24534b100dc60f4a", + "sha256:e7983572181f5e1522d9c98453462384ee92a0be7fac5f1413a1e35c56cc0461" ], - "version": "==1.25.9" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'", + "version": "==1.25.10" } } } From bf852052240735340090e6fdfd7b123185f9257f Mon Sep 17 00:00:00 2001 From: Federico Barcelona Date: Mon, 10 Aug 2020 09:59:15 +0200 Subject: [PATCH 3/4] fix(utils): Solve unknown reference to function --- utils/sync_pagerduty_policies.py | 1 + 1 file changed, 1 insertion(+) diff --git a/utils/sync_pagerduty_policies.py b/utils/sync_pagerduty_policies.py index beae78c6..669d94ff 100644 --- a/utils/sync_pagerduty_policies.py +++ b/utils/sync_pagerduty_policies.py @@ -7,6 +7,7 @@ import json import os import sys +from functools import reduce import requests From e2fa2a1969687ebefbdd32a8cc45424c4b043a7a Mon Sep 17 00:00:00 2001 From: Federico Barcelona Date: Mon, 10 Aug 2020 10:00:27 +0200 Subject: [PATCH 4/4] feat: Split Secure client into PolicyEvents clients --- .github/workflows/ci-pull-request.yml | 14 +- sdcclient/_secure.py | 309 ++++++------------------- sdcclient/secure/__init__.py | 2 + sdcclient/secure/_policy_events_old.py | 216 +++++++++++++++++ sdcclient/secure/_policy_events_v1.py | 122 ++++++++++ specs/__init__.py | 12 + specs/_common/event_spec.py | 12 +- specs/secure/policy_events_v1_spec.py | 67 ++++++ 8 files changed, 502 insertions(+), 252 deletions(-) create mode 100644 sdcclient/secure/__init__.py create mode 100644 sdcclient/secure/_policy_events_old.py create mode 100644 sdcclient/secure/_policy_events_v1.py create mode 100644 specs/secure/policy_events_v1_spec.py diff --git a/.github/workflows/ci-pull-request.yml b/.github/workflows/ci-pull-request.yml index 59ed5bd2..44d787e9 100644 --- a/.github/workflows/ci-pull-request.yml +++ b/.github/workflows/ci-pull-request.yml @@ -61,9 +61,11 @@ jobs: run: ./test/stop_agent.sh if: steps.start_agent.outcome == 'success' -# - name: Test -# env: -# SDC_MONITOR_TOKEN: ${{ secrets.STAGING_MONITOR_API_TOKEN }} -# SDC_SECURE_TOKEN: ${{ secrets.STAGING_SECURE_API_TOKEN }} -# run: | -# pipenv run mamba -f documentation + - name: Test in staging + env: + SDC_MONITOR_TOKEN: ${{ secrets.STAGING_MONITOR_API_TOKEN }} + SDC_SECURE_TOKEN: ${{ secrets.STAGING_SECURE_API_TOKEN }} + SDC_MONITOR_URL: "https://app-staging.sysdigcloud.com" + SDC_SECURE_URL: "https://secure-staging.sysdig.com" + run: | + pipenv run mamba -f documentation diff --git a/sdcclient/_secure.py b/sdcclient/_secure.py index 308d059f..85629a09 100644 --- a/sdcclient/_secure.py +++ b/sdcclient/_secure.py @@ -7,10 +7,10 @@ import yaml from sdcclient._common import _SdcCommon +from sdcclient.secure import PolicyEventsClientV1, PolicyEventsClientOld -class SdSecureClient(_SdcCommon): - +class SdSecureClient(PolicyEventsClientV1, PolicyEventsClientOld, _SdcCommon): def __init__(self, token="", sdc_url='https://secure.sysdig.com', ssl_verify=True, custom_headers=None): super(SdSecureClient, self).__init__(token, sdc_url, ssl_verify, custom_headers) @@ -29,7 +29,8 @@ def policy_v2(self): return self._policy_v2 def _get_falco_rules(self, kind): - res = requests.get(self.url + '/api/settings/falco/{}RulesFile'.format(kind), headers=self.hdrs, verify=self.ssl_verify) + res = requests.get(self.url + '/api/settings/falco/{}RulesFile'.format(kind), headers=self.hdrs, + verify=self.ssl_verify) if not self._checkResponse(res): return [False, self.lasterr] data = res.json() @@ -74,7 +75,8 @@ def _set_falco_rules(self, kind, rules_content): payload[1]["{}RulesFile".format(kind)]["content"] = rules_content # pylint: disable=unsubscriptable-object - res = requests.put(self.url + '/api/settings/falco/{}RulesFile'.format(kind), headers=self.hdrs, data=json.dumps(payload[1]), verify=self.ssl_verify) + res = requests.put(self.url + '/api/settings/falco/{}RulesFile'.format(kind), headers=self.hdrs, + data=json.dumps(payload[1]), verify=self.ssl_verify) if not self._checkResponse(res): return [False, self.lasterr] return [True, res.json()] @@ -114,7 +116,8 @@ def set_user_falco_rules(self, rules_content): # Only one kind for now called "default", but might add a "custom" kind later. def _get_falco_rules_files(self, kind): - res = requests.get(self.url + '/api/settings/falco/{}RulesFiles'.format(kind), headers=self.hdrs, verify=self.ssl_verify) + res = requests.get(self.url + '/api/settings/falco/{}RulesFiles'.format(kind), headers=self.hdrs, + verify=self.ssl_verify) if not self._checkResponse(res): return [False, self.lasterr] data = res.json() @@ -276,7 +279,8 @@ def _set_falco_rules_files(self, kind, rules_files): if "defaultPolicies" in rules_files: obj["defaultPolicies"] = rules_files["defaultPolicies"] - res = requests.put(self.url + '/api/settings/falco/{}RulesFiles'.format(kind), headers=self.hdrs, data=json.dumps(payload[1]), verify=self.ssl_verify) + res = requests.put(self.url + '/api/settings/falco/{}RulesFiles'.format(kind), headers=self.hdrs, + data=json.dumps(payload[1]), verify=self.ssl_verify) if not self._checkResponse(res): return [False, self.lasterr] return [True, res.json()] @@ -372,203 +376,6 @@ def load_default_falco_rules_files(self, save_dir): return [True, ret] - def _get_policy_events_int(self, ctx): - policy_events_url = self.url + '/api/policyEvents{id}?from={frm:d}&to={to:d}&offset={offset}&limit={limit}{sampling}{aggregations}{scope}{filter}'.format( - id="/%s" % ctx["id"] if "id" in ctx else "", - frm=int(ctx['from']), - to=int(ctx['to']), - offset=ctx['offset'], - limit=ctx['limit'], - sampling='&sampling=%d' % int(ctx['sampling']) if "sampling" in ctx else "", - aggregations='&aggregations=%s' % json.dumps(ctx['aggregations']) if "aggregations" in ctx else "", - scope='&scopeFilter=%s' % ctx['scopeFilter'] if "scopeFilter" in ctx else "", - filter='&eventFilter=%s' % ctx['eventFilter'] if "eventFilter" in ctx else "") - - res = requests.get(policy_events_url, headers=self.hdrs, verify=self.ssl_verify) - if not self._checkResponse(res): - return [False, self.lasterr] - - # Increment the offset by limit - ctx['offset'] += ctx['limit'] - - return [True, {"ctx": ctx, "data": res.json()}] - - def get_policy_events_range(self, from_sec, to_sec, sampling=None, aggregations=None, scope_filter=None, event_filter=None): - '''**Description** - Fetch all policy events that occurred in the time range [from_sec:to_sec]. This method is used in conjunction - with :func:`~sdcclient.SdSecureClient.get_more_policy_events` to provide paginated access to policy events. - - **Arguments** - - from_sec: the start of the timerange for which to get events - - end_sec: the end of the timerange for which to get events - - sampling: sample all policy events using *sampling* interval. - - aggregations: When present it specifies how to aggregate events (sampling does not need to be specified, because when it's present it automatically means events will be aggregated). This field can either be a list of scope metrics or a list of policyEvents fields but (currently) not a mix of the two. When policy events fields are specified, only these can be used= severity, agentId, containerId, policyId, ruleType. - - scope_filter: this is a SysdigMonitor-like filter (e.g 'container.image=ubuntu'). When provided, events are filtered by their scope, so only a subset will be returned (e.g. 'container.image=ubuntu' will provide only events that have happened on an ubuntu container). - - event_filter: this is a SysdigMonitor-like filter (e.g. policyEvent.policyId=3). When provided, events are filtered by some of their properties. Currently the supported set of filters is policyEvent.all(which can be used just with matches, policyEvent.policyId, policyEvent.id, policyEvent.severity, policyEvent.ruleTye, policyEvent.ruleSubtype. - - **Success Return Value** - An array containing: - - A context object that should be passed to later calls to get_more_policy_events. - - An array of policy events, in JSON format. See :func:`~sdcclient.SdSecureClient.get_more_policy_events` - for details on the contents of policy events. - - **Example** - `examples/get_secure_policy_events.py `_ - - ''' - options = {"from": int(from_sec) * 1000000, - "to": int(to_sec) * 1000000, - "offset": 0, - "limit": 1000, - "sampling": sampling, - "aggregations": aggregations, - "scopeFilter": scope_filter, - "eventFilter": event_filter} - ctx = {k: v for k, v in options.items() if v is not None} - return self._get_policy_events_int(ctx) - - def get_policy_events_duration(self, duration_sec, sampling=None, aggregations=None, scope_filter=None, event_filter=None): - '''**Description** - Fetch all policy events that occurred in the last duration_sec seconds. This method is used in conjunction with - :func:`~sdcclient.SdSecureClient.get_more_policy_events` to provide paginated access to policy events. - - **Arguments** - - duration_sec: Fetch all policy events that have occurred in the last *duration_sec* seconds. - - sampling: Sample all policy events using *sampling* interval. - - aggregations: When present it specifies how to aggregate events (sampling does not need to be specified, because when it's present it automatically means events will be aggregated). This field can either be a list of scope metrics or a list of policyEvents fields but (currently) not a mix of the two. When policy events fields are specified, only these can be used= severity, agentId, containerId, policyId, ruleType. - - scope_filter: this is a SysdigMonitor-like filter (e.g 'container.image=ubuntu'). When provided, events are filtered by their scope, so only a subset will be returned (e.g. 'container.image=ubuntu' will provide only events that have happened on an ubuntu container). - - event_filter: this is a SysdigMonitor-like filter (e.g. policyEvent.policyId=3). When provided, events are filtered by some of their properties. Currently the supported set of filters is policyEvent.all(which can be used just with matches, policyEvent.policyId, policyEvent.id, policyEvent.severity, policyEvent.ruleTye, policyEvent.ruleSubtype. - - **Success Return Value** - An array containing: - - A context object that should be passed to later calls to get_more_policy_events. - - An array of policy events, in JSON format. See :func:`~sdcclient.SdSecureClient.get_more_policy_events` - for details on the contents of policy events. - - **Example** - `examples/get_secure_policy_events.py `_ - - ''' - epoch = datetime.datetime.utcfromtimestamp(0) - to_ts = (datetime.datetime.utcnow() - epoch).total_seconds() * 1000 * 1000 - from_ts = to_ts - (int(duration_sec) * 1000 * 1000) - - options = {"to": to_ts, - "from": from_ts, - "offset": 0, - "limit": 1000, - "sampling": sampling, - "aggregations": aggregations, - "scopeFilter": scope_filter, - "eventFilter": event_filter} - ctx = {k: v for k, v in options.items() if v is not None} - return self._get_policy_events_int(ctx) - - def get_policy_events_id_range(self, id, from_sec, to_sec, sampling=None, aggregations=None, scope_filter=None, event_filter=None): - '''**Description** - Fetch all policy events with id that occurred in the time range [from_sec:to_sec]. This method is used in conjunction - with :func:`~sdcclient.SdSecureClient.get_more_policy_events` to provide paginated access to policy events. - - **Arguments** - - id: the id of the policy events to fetch. - - from_sec: the start of the timerange for which to get events - - end_sec: the end of the timerange for which to get events - - sampling: sample all policy events using *sampling* interval. - - scope_filter: this is a SysdigMonitor-like filter (e.g 'container.image=ubuntu'). When provided, events are filtered by their scope, so only a subset will be returned (e.g. 'container.image=ubuntu' will provide only events that have happened on an ubuntu container). - - event_filter: this is a SysdigMonitor-like filter (e.g. policyEvent.policyId=3). When provided, events are filtered by some of their properties. Currently the supported set of filters is policyEvent.all(which can be used just with matches, policyEvent.policyId, policyEvent.id, policyEvent.severity, policyEvent.ruleTye, policyEvent.ruleSubtype. - - aggregations: When present it specifies how to aggregate events (sampling does not need to be specified, because when it's present it automatically means events will be aggregated). This field can either be a list of scope metrics or a list of policyEvents fields but (currently) not a mix of the two. When policy events fields are specified, only these can be used= severity, agentId, containerId, policyId, ruleType. - - **Success Return Value** - An array containing: - - A context object that should be passed to later calls to get_more_policy_events. - - An array of policy events, in JSON format. See :func:`~sdcclient.SdSecureClient.get_more_policy_events` - for details on the contents of policy events. - - **Example** - `examples/get_secure_policy_events.py `_ - - ''' - options = {"id": id, - "from": int(from_sec) * 1000000, - "to": int(to_sec) * 1000000, - "offset": 0, - "limit": 1000, - "sampling": sampling, - "aggregations": aggregations, - "scopeFilter": scope_filter, - "eventFilter": event_filter} - ctx = {k: v for k, v in options.items() if v is not None} - return self._get_policy_events_int(ctx) - - def get_policy_events_id_duration(self, id, duration_sec, sampling=None, aggregations=None, scope_filter=None, event_filter=None): - '''**Description** - Fetch all policy events with id that occurred in the last duration_sec seconds. This method is used in conjunction with - :func:`~sdcclient.SdSecureClient.get_more_policy_events` to provide paginated access to policy events. - - **Arguments** - - id: the id of the policy events to fetch. - - duration_sec: Fetch all policy events that have occurred in the last *duration_sec* seconds. - - sampling: Sample all policy events using *sampling* interval. - - aggregations: When present it specifies how to aggregate events (sampling does not need to be specified, because when it's present it automatically means events will be aggregated). This field can either be a list of scope metrics or a list of policyEvents fields but (currently) not a mix of the two. When policy events fields are specified, only these can be used= severity, agentId, containerId, policyId, ruleType. - - scope_filter: this is a SysdigMonitor-like filter (e.g 'container.image=ubuntu'). When provided, events are filtered by their scope, so only a subset will be returned (e.g. 'container.image=ubuntu' will provide only events that have happened on an ubuntu container). - - event_filter: this is a SysdigMonitor-like filter (e.g. policyEvent.policyId=3). When provided, events are filtered by some of their properties. Currently the supported set of filters is policyEvent.all(which can be used just with matches, policyEvent.policyId, policyEvent.id, policyEvent.severity, policyEvent.ruleTye, policyEvent.ruleSubtype. - - **Success Return Value** - An array containing: - - A context object that should be passed to later calls to get_more_policy_events. - - An array of policy events, in JSON format. See :func:`~sdcclient.SdSecureClient.get_more_policy_events` - for details on the contents of policy events. - - **Example** - `examples/get_secure_policy_events.py `_ - - ''' - epoch = datetime.datetime.utcfromtimestamp(0) - to_ts = (datetime.datetime.utcnow() - epoch).total_seconds() * 1000 * 1000 - from_ts = to_ts - (int(duration_sec) * 1000 * 1000) - - options = {"id": id, - "to": to_ts, - "from": from_ts, - "offset": 0, - "limit": 1000, - "sampling": sampling, - "aggregations": aggregations, - "scopeFilter": scope_filter, - "eventFilter": event_filter} - ctx = {k: v for k, v in options.items() if v is not None} - return self._get_policy_events_int(ctx) - - def get_more_policy_events(self, ctx): - '''**Description** - Fetch additional policy events after an initial call to :func:`~sdcclient.SdSecureClient.get_policy_events_range` / - :func:`~sdcclient.SdSecureClient.get_policy_events_duration` or a prior call to get_more_policy_events. - - **Arguments** - - ctx: a context object returned from an initial call to :func:`~sdcclient.SdSecureClient.get_policy_events_range` / - :func:`~sdcclient.SdSecureClient.get_policy_events_duration` or a prior call to get_more_policy_events. - - **Success Return Value** - An array containing: - - A context object that should be passed to later calls to get_more_policy_events() - - An array of policy events, in JSON format. Each policy event contains the following: - - hostMac: the mac address of the machine where the event occurred - - severity: a severity level from 1-7 - - timestamp: when the event occurred (ns since the epoch) - - version: a version number for this message (currently 1) - - policyId: a reference to the policy that generated this policy event - - output: A string describing the event that occurred - - id: a unique identifier for this policy event - - isAggregated: if true, this is a combination of multiple policy events - - containerId: the container in which the policy event occurred - - When the number of policy events returned is 0, there are no remaining events and you can stop calling get_more_policy_events(). - - **Example** - `examples/get_secure_policy_events.py `_ - ''' - return self._get_policy_events_int(ctx) - def create_default_policies(self): '''**Description** Create new policies based on the currently available set of rules. For now, this only covers Falco rules, but we might extend @@ -672,7 +479,8 @@ def get_policy_id(self, id): res = requests.get(self.url + '/api/v2/policies/{}'.format(id), headers=self.hdrs, verify=self.ssl_verify) return self._request_result(res) - def add_policy(self, name, description, rule_names=[], actions=[], scope=None, severity=0, enabled=True, notification_channels=[]): + def add_policy(self, name, description, rule_names=[], actions=[], scope=None, severity=0, enabled=True, + notification_channels=[]): '''**Description** Add a new policy. @@ -699,7 +507,8 @@ def add_policy(self, name, description, rule_names=[], actions=[], scope=None, s "enabled": enabled, "notificationChannelIds": notification_channels } - res = requests.post(self.url + '/api/v2/policies', headers=self.hdrs, data=json.dumps(policy), verify=self.ssl_verify) + res = requests.post(self.url + '/api/v2/policies', headers=self.hdrs, data=json.dumps(policy), + verify=self.ssl_verify) return self._request_result(res) def add_policy_json(self, policy_json): @@ -724,7 +533,8 @@ def add_policy_json(self, policy_json): except Exception as e: return [False, "policy json is not valid json: {}".format(str(e))] - res = requests.post(self.url + '/api/v2/policies', headers=self.hdrs, data=json.dumps(policy_obj), verify=self.ssl_verify) + res = requests.post(self.url + '/api/v2/policies', headers=self.hdrs, data=json.dumps(policy_obj), + verify=self.ssl_verify) return self._request_result(res) def update_policy(self, id, name=None, description=None, rule_names=None, actions=None, scope=None, @@ -768,7 +578,8 @@ def update_policy(self, id, name=None, description=None, rule_names=None, action if notification_channels is not None: policy["notificationChannelIds"] = notification_channels - res = requests.put(self.url + '/api/v2/policies/{}'.format(id), headers=self.hdrs, data=json.dumps(policy), verify=self.ssl_verify) + res = requests.put(self.url + '/api/v2/policies/{}'.format(id), headers=self.hdrs, data=json.dumps(policy), + verify=self.ssl_verify) return self._request_result(res) def update_policy_json(self, policy_json): @@ -796,7 +607,8 @@ def update_policy_json(self, policy_json): if "id" not in policy_obj: return [False, "Policy Json does not have an 'id' field"] - res = requests.put(self.url + '/api/v2/policies/{}'.format(policy_obj["id"]), headers=self.hdrs, data=json.dumps(policy_obj), verify=self.ssl_verify) + res = requests.put(self.url + '/api/v2/policies/{}'.format(policy_obj["id"]), headers=self.hdrs, + data=json.dumps(policy_obj), verify=self.ssl_verify) return self._request_result(res) def delete_policy_name(self, name): @@ -868,7 +680,8 @@ def get_rules_group(self, name): **Success Return Value** A JSON object representing the list of rules. ''' - res = requests.get(self.url + '/api/secure/rules/groups?name={}'.format(name), headers=self.hdrs, verify=self.ssl_verify) + res = requests.get(self.url + '/api/secure/rules/groups?name={}'.format(name), headers=self.hdrs, + verify=self.ssl_verify) return self._request_result(res) def get_rule_id(self, id): @@ -903,7 +716,8 @@ def add_rule(self, name, details={}, description="", tags=[]): "details": details, "tags": tags } - res = requests.post(self.url + '/api/secure/rules', data=json.dumps(rule), headers=self.hdrs, verify=self.ssl_verify) + res = requests.post(self.url + '/api/secure/rules', data=json.dumps(rule), headers=self.hdrs, + verify=self.ssl_verify) return self._request_result(res) def update_rule(self, id, details={}, description="", tags=[]): @@ -930,7 +744,8 @@ def update_rule(self, id, details={}, description="", tags=[]): rule['description'] = description if tags: rule['tags'] = tags - res = requests.put(self.url + '/api/secure/rules/{}'.format(id), data=json.dumps(rule), headers=self.hdrs, verify=self.ssl_verify) + res = requests.put(self.url + '/api/secure/rules/{}'.format(id), data=json.dumps(rule), headers=self.hdrs, + verify=self.ssl_verify) return self._request_result(res) def delete_rule(self, id): @@ -973,7 +788,8 @@ def get_falco_macros_group(self, name): **Success Return Value** A JSON object representing the list of falco macros. ''' - res = requests.get(self.url + '/api/secure/falco/macros/groups?name={}'.format(name), headers=self.hdrs, verify=self.ssl_verify) + res = requests.get(self.url + '/api/secure/falco/macros/groups?name={}'.format(name), headers=self.hdrs, + verify=self.ssl_verify) return self._request_result(res) def get_falco_macro_id(self, id): @@ -986,7 +802,8 @@ def get_falco_macro_id(self, id): **Success Return Value** A JSON object representing the falco macro. ''' - res = requests.get(self.url + '/api/secure/falco/macros/{}'.format(id), headers=self.hdrs, verify=self.ssl_verify) + res = requests.get(self.url + '/api/secure/falco/macros/{}'.format(id), headers=self.hdrs, + verify=self.ssl_verify) return self._request_result(res) def add_falco_macro(self, name, condition): @@ -1007,7 +824,8 @@ def add_falco_macro(self, name, condition): "condition": condition } } - res = requests.post(self.url + '/api/secure/falco/macros', data=json.dumps(macro), headers=self.hdrs, verify=self.ssl_verify) + res = requests.post(self.url + '/api/secure/falco/macros', data=json.dumps(macro), headers=self.hdrs, + verify=self.ssl_verify) return self._request_result(res) def update_falco_macro(self, id, condition): @@ -1027,7 +845,8 @@ def update_falco_macro(self, id, condition): macro = res macro['condition']['condition'] = condition - res = requests.put(self.url + '/api/secure/falco/macros/{}'.format(id), data=json.dumps(macro), headers=self.hdrs, verify=self.ssl_verify) + res = requests.put(self.url + '/api/secure/falco/macros/{}'.format(id), data=json.dumps(macro), + headers=self.hdrs, verify=self.ssl_verify) return self._request_result(res) def delete_falco_macro(self, id): @@ -1040,7 +859,8 @@ def delete_falco_macro(self, id): **Success Return Value** A JSON object representing the macro. ''' - res = requests.delete(self.url + '/api/secure/falco/macros/{}'.format(id), headers=self.hdrs, verify=self.ssl_verify) + res = requests.delete(self.url + '/api/secure/falco/macros/{}'.format(id), headers=self.hdrs, + verify=self.ssl_verify) return self._request_result(res) def list_falco_lists(self): @@ -1070,7 +890,8 @@ def get_falco_lists_group(self, name): **Success Return Value** A JSON object representing the list of falco lists. ''' - res = requests.get(self.url + '/api/secure/falco/lists/groups?name={}'.format(name), headers=self.hdrs, verify=self.ssl_verify) + res = requests.get(self.url + '/api/secure/falco/lists/groups?name={}'.format(name), headers=self.hdrs, + verify=self.ssl_verify) return self._request_result(res) def get_falco_list_id(self, id): @@ -1083,7 +904,8 @@ def get_falco_list_id(self, id): **Success Return Value** A JSON object representing the falco list. ''' - res = requests.get(self.url + '/api/secure/falco/lists/{}'.format(id), headers=self.hdrs, verify=self.ssl_verify) + res = requests.get(self.url + '/api/secure/falco/lists/{}'.format(id), headers=self.hdrs, + verify=self.ssl_verify) return self._request_result(res) def add_falco_list(self, name, items): @@ -1103,7 +925,8 @@ def add_falco_list(self, name, items): "items": items } } - res = requests.post(self.url + '/api/secure/falco/lists', data=json.dumps(flist), headers=self.hdrs, verify=self.ssl_verify) + res = requests.post(self.url + '/api/secure/falco/lists', data=json.dumps(flist), headers=self.hdrs, + verify=self.ssl_verify) return self._request_result(res) def update_falco_list(self, id, items): @@ -1123,7 +946,8 @@ def update_falco_list(self, id, items): flist = res flist['items']['items'] = items - res = requests.put(self.url + '/api/secure/falco/lists/{}'.format(id), data=json.dumps(flist), headers=self.hdrs, verify=self.ssl_verify) + res = requests.put(self.url + '/api/secure/falco/lists/{}'.format(id), data=json.dumps(flist), + headers=self.hdrs, verify=self.ssl_verify) return self._request_result(res) def delete_falco_list(self, id): @@ -1136,10 +960,12 @@ def delete_falco_list(self, id): **Success Return Value** A JSON object representing the list. ''' - res = requests.delete(self.url + '/api/secure/falco/lists/{}'.format(id), headers=self.hdrs, verify=self.ssl_verify) + res = requests.delete(self.url + '/api/secure/falco/lists/{}'.format(id), headers=self.hdrs, + verify=self.ssl_verify) return self._request_result(res) - def add_compliance_task(self, name, module_name='docker-bench-security', schedule='06:00:00Z/PT12H', scope=None, enabled=True): + def add_compliance_task(self, name, module_name='docker-bench-security', schedule='06:00:00Z/PT12H', scope=None, + enabled=True): '''**Description** Add a new compliance task. @@ -1161,7 +987,8 @@ def add_compliance_task(self, name, module_name='docker-bench-security', schedul "scope": scope, "schedule": schedule } - res = requests.post(self.url + '/api/complianceTasks', data=json.dumps(task), headers=self.hdrs, verify=self.ssl_verify) + res = requests.post(self.url + '/api/complianceTasks', data=json.dumps(task), headers=self.hdrs, + verify=self.ssl_verify) return self._request_result(res) def list_compliance_tasks(self): @@ -1218,7 +1045,8 @@ def update_compliance_task(self, id, name=None, module_name=None, schedule=None, 'enabled': enabled } task.update({k: v for k, v in options.items() if v is not None}) - res = requests.put(self.url + '/api/complianceTasks/{}'.format(id), data=json.dumps(task), headers=self.hdrs, verify=self.ssl_verify) + res = requests.put(self.url + '/api/complianceTasks/{}'.format(id), data=json.dumps(task), headers=self.hdrs, + verify=self.ssl_verify) return self._request_result(res) def delete_compliance_task(self, id): @@ -1228,7 +1056,8 @@ def delete_compliance_task(self, id): **Arguments** - id: the id of the compliance task to delete ''' - res = requests.delete(self.url + '/api/complianceTasks/{}'.format(id), headers=self.hdrs, verify=self.ssl_verify) + res = requests.delete(self.url + '/api/complianceTasks/{}'.format(id), headers=self.hdrs, + verify=self.ssl_verify) if not self._checkResponse(res): return False, self.lasterr @@ -1279,13 +1108,15 @@ def get_compliance_results_csv(self, id): **Success Return Value** A CSV representation of the compliance task run result. ''' - res = requests.get(self.url + '/api/complianceResults/{}/csv'.format(id), headers=self.hdrs, verify=self.ssl_verify) + res = requests.get(self.url + '/api/complianceResults/{}/csv'.format(id), headers=self.hdrs, + verify=self.ssl_verify) if not self._checkResponse(res): return False, self.lasterr return True, res.text - def list_commands_audit(self, from_sec=None, to_sec=None, scope_filter=None, command_filter=None, limit=100, offset=0, metrics=[]): + def list_commands_audit(self, from_sec=None, to_sec=None, scope_filter=None, command_filter=None, limit=100, + offset=0, metrics=[]): '''**Description** List the commands audit. @@ -1309,8 +1140,8 @@ def list_commands_audit(self, from_sec=None, to_sec=None, scope_filter=None, com url=self.url, offset=offset, limit=limit, - frm=int(from_sec * 10**6), - to=int(to_sec * 10**6), + frm=int(from_sec * 10 ** 6), + to=int(to_sec * 10 ** 6), scope="&scopeFilter=" + scope_filter if scope_filter else "", commandFilter="&commandFilter=" + command_filter if command_filter else "", metrics="&metrics=" + json.dumps(metrics) if metrics else "") @@ -1330,7 +1161,7 @@ def get_command_audit(self, id, metrics=[]): url = "{url}/api/commands/{id}?from=0&to={to}{metrics}".format( url=self.url, id=id, - to=int(time.time() * 10**6), + to=int(time.time() * 10 ** 6), metrics="&metrics=" + json.dumps(metrics) if metrics else "") res = requests.get(url, headers=self.hdrs, verify=self.ssl_verify) return self._request_result(res) @@ -1347,13 +1178,12 @@ def list_image_profiles(self): ''' url = "{url}/api/v1/profiling/profileGroups/0/profiles".format( - url = self.url + url=self.url ) res = requests.get(url, headers=self.hdrs, verify=self.ssl_verify) return self._request_result(res) - def get_image_profile(self, profileId): '''**Description** Find the image profile with a (partial) profile ID and return its json description. @@ -1376,7 +1206,6 @@ def get_image_profile(self, profileId): if not ok: return [False, self.lasterr] - ''' The content of the json stored in the image_profiles dictionary: @@ -1389,21 +1218,21 @@ def get_image_profile(self, profileId): ] } ''' - + matched_profiles = self.__get_matched_profileIDs(profileId, image_profiles['profiles']) - + # Profile ID not found if len(matched_profiles) == 0: return [False, "No profile with ID {}".format(profileId)] - + # Principal workflow. Profile ID found elif len(matched_profiles) == 1: # Matched id. Return information url = "{url}/api/v1/profiling/profiles/{profileId}".format( - url = self.url, - profileId = matched_profiles[0]['profileId'] + url=self.url, + profileId=matched_profiles[0]['profileId'] ) - + res = requests.get(url, headers=self.hdrs, verify=self.ssl_verify) return self._request_result(res) @@ -1411,7 +1240,6 @@ def get_image_profile(self, profileId): elif len(matched_profiles) >= 2: return [False, matched_profiles] - def __get_matched_profileIDs(self, requested_profile, profile_list): ''' **Description** @@ -1511,4 +1339,3 @@ def __get_matched_profileIDs(self, requested_profile, profile_list): matched_profiles.append(profile) return matched_profiles - diff --git a/sdcclient/secure/__init__.py b/sdcclient/secure/__init__.py new file mode 100644 index 00000000..098e7de6 --- /dev/null +++ b/sdcclient/secure/__init__.py @@ -0,0 +1,2 @@ +from ._policy_events_old import PolicyEventsClientOld +from ._policy_events_v1 import PolicyEventsClientV1 \ No newline at end of file diff --git a/sdcclient/secure/_policy_events_old.py b/sdcclient/secure/_policy_events_old.py new file mode 100644 index 00000000..0b4a56f3 --- /dev/null +++ b/sdcclient/secure/_policy_events_old.py @@ -0,0 +1,216 @@ +import datetime +import json + +import requests + +from sdcclient._common import _SdcCommon + + +class PolicyEventsClientOld(_SdcCommon): + def __init__(self, token="", sdc_url='https://secure.sysdig.com', ssl_verify=True, custom_headers=None): + super(PolicyEventsClientOld, self).__init__(token, sdc_url, ssl_verify, custom_headers) + + self.customer_id = None + self.product = "SDS" + self._policy_v2 = None + + def _get_policy_events_int(self, ctx): + policy_events_url = self.url + '/api/policyEvents{id}?from={frm:d}&to={to:d}&offset={offset}&limit={limit}{sampling}{aggregations}{scope}{filter}'.format( + id="/%s" % ctx["id"] if "id" in ctx else "", + frm=int(ctx['from']), + to=int(ctx['to']), + offset=ctx['offset'], + limit=ctx['limit'], + sampling='&sampling=%d' % int(ctx['sampling']) if "sampling" in ctx else "", + aggregations='&aggregations=%s' % json.dumps(ctx['aggregations']) if "aggregations" in ctx else "", + scope='&scopeFilter=%s' % ctx['scopeFilter'] if "scopeFilter" in ctx else "", + filter='&eventFilter=%s' % ctx['eventFilter'] if "eventFilter" in ctx else "") + + res = requests.get(policy_events_url, headers=self.hdrs, verify=self.ssl_verify) + if not self._checkResponse(res): + return [False, self.lasterr] + + # Increment the offset by limit + ctx['offset'] += ctx['limit'] + + return [True, {"ctx": ctx, "data": res.json()}] + + def get_policy_events_range(self, from_sec, to_sec, sampling=None, aggregations=None, scope_filter=None, + event_filter=None): + '''**Description** + Fetch all policy events that occurred in the time range [from_sec:to_sec]. This method is used in conjunction + with :func:`~sdcclient.SdSecureClient.get_more_policy_events` to provide paginated access to policy events. + + **Arguments** + - from_sec: the start of the timerange for which to get events + - end_sec: the end of the timerange for which to get events + - sampling: sample all policy events using *sampling* interval. + - aggregations: When present it specifies how to aggregate events (sampling does not need to be specified, because when it's present it automatically means events will be aggregated). This field can either be a list of scope metrics or a list of policyEvents fields but (currently) not a mix of the two. When policy events fields are specified, only these can be used= severity, agentId, containerId, policyId, ruleType. + - scope_filter: this is a SysdigMonitor-like filter (e.g 'container.image=ubuntu'). When provided, events are filtered by their scope, so only a subset will be returned (e.g. 'container.image=ubuntu' will provide only events that have happened on an ubuntu container). + - event_filter: this is a SysdigMonitor-like filter (e.g. policyEvent.policyId=3). When provided, events are filtered by some of their properties. Currently the supported set of filters is policyEvent.all(which can be used just with matches, policyEvent.policyId, policyEvent.id, policyEvent.severity, policyEvent.ruleTye, policyEvent.ruleSubtype. + + **Success Return Value** + An array containing: + - A context object that should be passed to later calls to get_more_policy_events. + - An array of policy events, in JSON format. See :func:`~sdcclient.SdSecureClient.get_more_policy_events` + for details on the contents of policy events. + + **Example** + `examples/get_secure_policy_events.py `_ + + ''' + options = {"from": int(from_sec) * 1000000, + "to": int(to_sec) * 1000000, + "offset": 0, + "limit": 1000, + "sampling": sampling, + "aggregations": aggregations, + "scopeFilter": scope_filter, + "eventFilter": event_filter} + ctx = {k: v for k, v in options.items() if v is not None} + return self._get_policy_events_int(ctx) + + def get_policy_events_duration(self, duration_sec, sampling=None, aggregations=None, scope_filter=None, + event_filter=None): + '''**Description** + Fetch all policy events that occurred in the last duration_sec seconds. This method is used in conjunction with + :func:`~sdcclient.SdSecureClient.get_more_policy_events` to provide paginated access to policy events. + + **Arguments** + - duration_sec: Fetch all policy events that have occurred in the last *duration_sec* seconds. + - sampling: Sample all policy events using *sampling* interval. + - aggregations: When present it specifies how to aggregate events (sampling does not need to be specified, because when it's present it automatically means events will be aggregated). This field can either be a list of scope metrics or a list of policyEvents fields but (currently) not a mix of the two. When policy events fields are specified, only these can be used= severity, agentId, containerId, policyId, ruleType. + - scope_filter: this is a SysdigMonitor-like filter (e.g 'container.image=ubuntu'). When provided, events are filtered by their scope, so only a subset will be returned (e.g. 'container.image=ubuntu' will provide only events that have happened on an ubuntu container). + - event_filter: this is a SysdigMonitor-like filter (e.g. policyEvent.policyId=3). When provided, events are filtered by some of their properties. Currently the supported set of filters is policyEvent.all(which can be used just with matches, policyEvent.policyId, policyEvent.id, policyEvent.severity, policyEvent.ruleTye, policyEvent.ruleSubtype. + + **Success Return Value** + An array containing: + - A context object that should be passed to later calls to get_more_policy_events. + - An array of policy events, in JSON format. See :func:`~sdcclient.SdSecureClient.get_more_policy_events` + for details on the contents of policy events. + + **Example** + `examples/get_secure_policy_events.py `_ + + ''' + epoch = datetime.datetime.utcfromtimestamp(0) + to_ts = (datetime.datetime.utcnow() - epoch).total_seconds() * 1000 * 1000 + from_ts = to_ts - (int(duration_sec) * 1000 * 1000) + + options = {"to": to_ts, + "from": from_ts, + "offset": 0, + "limit": 1000, + "sampling": sampling, + "aggregations": aggregations, + "scopeFilter": scope_filter, + "eventFilter": event_filter} + ctx = {k: v for k, v in options.items() if v is not None} + return self._get_policy_events_int(ctx) + + def get_policy_events_id_range(self, id, from_sec, to_sec, sampling=None, aggregations=None, scope_filter=None, + event_filter=None): + '''**Description** + Fetch all policy events with id that occurred in the time range [from_sec:to_sec]. This method is used in conjunction + with :func:`~sdcclient.SdSecureClient.get_more_policy_events` to provide paginated access to policy events. + + **Arguments** + - id: the id of the policy events to fetch. + - from_sec: the start of the timerange for which to get events + - end_sec: the end of the timerange for which to get events + - sampling: sample all policy events using *sampling* interval. + - scope_filter: this is a SysdigMonitor-like filter (e.g 'container.image=ubuntu'). When provided, events are filtered by their scope, so only a subset will be returned (e.g. 'container.image=ubuntu' will provide only events that have happened on an ubuntu container). + - event_filter: this is a SysdigMonitor-like filter (e.g. policyEvent.policyId=3). When provided, events are filtered by some of their properties. Currently the supported set of filters is policyEvent.all(which can be used just with matches, policyEvent.policyId, policyEvent.id, policyEvent.severity, policyEvent.ruleTye, policyEvent.ruleSubtype. + - aggregations: When present it specifies how to aggregate events (sampling does not need to be specified, because when it's present it automatically means events will be aggregated). This field can either be a list of scope metrics or a list of policyEvents fields but (currently) not a mix of the two. When policy events fields are specified, only these can be used= severity, agentId, containerId, policyId, ruleType. + + **Success Return Value** + An array containing: + - A context object that should be passed to later calls to get_more_policy_events. + - An array of policy events, in JSON format. See :func:`~sdcclient.SdSecureClient.get_more_policy_events` + for details on the contents of policy events. + + **Example** + `examples/get_secure_policy_events.py `_ + + ''' + options = {"id": id, + "from": int(from_sec) * 1000000, + "to": int(to_sec) * 1000000, + "offset": 0, + "limit": 1000, + "sampling": sampling, + "aggregations": aggregations, + "scopeFilter": scope_filter, + "eventFilter": event_filter} + ctx = {k: v for k, v in options.items() if v is not None} + return self._get_policy_events_int(ctx) + + def get_policy_events_id_duration(self, id, duration_sec, sampling=None, aggregations=None, scope_filter=None, + event_filter=None): + '''**Description** + Fetch all policy events with id that occurred in the last duration_sec seconds. This method is used in conjunction with + :func:`~sdcclient.SdSecureClient.get_more_policy_events` to provide paginated access to policy events. + + **Arguments** + - id: the id of the policy events to fetch. + - duration_sec: Fetch all policy events that have occurred in the last *duration_sec* seconds. + - sampling: Sample all policy events using *sampling* interval. + - aggregations: When present it specifies how to aggregate events (sampling does not need to be specified, because when it's present it automatically means events will be aggregated). This field can either be a list of scope metrics or a list of policyEvents fields but (currently) not a mix of the two. When policy events fields are specified, only these can be used= severity, agentId, containerId, policyId, ruleType. + - scope_filter: this is a SysdigMonitor-like filter (e.g 'container.image=ubuntu'). When provided, events are filtered by their scope, so only a subset will be returned (e.g. 'container.image=ubuntu' will provide only events that have happened on an ubuntu container). + - event_filter: this is a SysdigMonitor-like filter (e.g. policyEvent.policyId=3). When provided, events are filtered by some of their properties. Currently the supported set of filters is policyEvent.all(which can be used just with matches, policyEvent.policyId, policyEvent.id, policyEvent.severity, policyEvent.ruleTye, policyEvent.ruleSubtype. + + **Success Return Value** + An array containing: + - A context object that should be passed to later calls to get_more_policy_events. + - An array of policy events, in JSON format. See :func:`~sdcclient.SdSecureClient.get_more_policy_events` + for details on the contents of policy events. + + **Example** + `examples/get_secure_policy_events.py `_ + + ''' + epoch = datetime.datetime.utcfromtimestamp(0) + to_ts = (datetime.datetime.utcnow() - epoch).total_seconds() * 1000 * 1000 + from_ts = to_ts - (int(duration_sec) * 1000 * 1000) + + options = {"id": id, + "to": to_ts, + "from": from_ts, + "offset": 0, + "limit": 1000, + "sampling": sampling, + "aggregations": aggregations, + "scopeFilter": scope_filter, + "eventFilter": event_filter} + ctx = {k: v for k, v in options.items() if v is not None} + return self._get_policy_events_int(ctx) + + def get_more_policy_events(self, ctx): + '''**Description** + Fetch additional policy events after an initial call to :func:`~sdcclient.SdSecureClient.get_policy_events_range` / + :func:`~sdcclient.SdSecureClient.get_policy_events_duration` or a prior call to get_more_policy_events. + + **Arguments** + - ctx: a context object returned from an initial call to :func:`~sdcclient.SdSecureClient.get_policy_events_range` / + :func:`~sdcclient.SdSecureClient.get_policy_events_duration` or a prior call to get_more_policy_events. + + **Success Return Value** + An array containing: + - A context object that should be passed to later calls to get_more_policy_events() + - An array of policy events, in JSON format. Each policy event contains the following: + - hostMac: the mac address of the machine where the event occurred + - severity: a severity level from 1-7 + - timestamp: when the event occurred (ns since the epoch) + - version: a version number for this message (currently 1) + - policyId: a reference to the policy that generated this policy event + - output: A string describing the event that occurred + - id: a unique identifier for this policy event + - isAggregated: if true, this is a combination of multiple policy events + - containerId: the container in which the policy event occurred + + When the number of policy events returned is 0, there are no remaining events and you can stop calling get_more_policy_events(). + + **Example** + `examples/get_secure_policy_events.py `_ + ''' + return self._get_policy_events_int(ctx) diff --git a/sdcclient/secure/_policy_events_v1.py b/sdcclient/secure/_policy_events_v1.py new file mode 100644 index 00000000..55b4628e --- /dev/null +++ b/sdcclient/secure/_policy_events_v1.py @@ -0,0 +1,122 @@ +import datetime + +import requests + +from sdcclient._common import _SdcCommon + + +class PolicyEventsClientV1(_SdcCommon): + def __init__(self, token="", sdc_url='https://secure.sysdig.com', ssl_verify=True, custom_headers=None): + super(PolicyEventsClientV1, self).__init__(token, sdc_url, ssl_verify, custom_headers) + + self.customer_id = None + self.product = "SDS" + self._policy_v2 = None + + def _get_policy_events_int(self, ctx): + limit = ctx.get("limit", 50) + policy_events_url = self.url + '/api/v1/secureEvents?limit={limit}{frm}{to}{filter}{cursor}'.format( + limit=limit, + frm=f"&from={int(ctx['from']):d}" if "from" in ctx else "", + to=f"&to={int(ctx['to']):d}" if "to" in ctx else "", + filter=f'&filter={ctx["filter"]}' if "filter" in ctx else "", + cursor=f'&cursor={ctx["cursor"]}' if "cursor" in ctx else "") + + res = requests.get(policy_events_url, headers=self.hdrs, verify=self.ssl_verify) + if not self._checkResponse(res): + return [False, self.lasterr] + + ctx = { + "limit": limit, + "cursor": res.json()["page"].get("prev", "") + } + + return [True, {"ctx": ctx, "data": res.json()["data"]}] + + def get_policy_events_range(self, from_sec, to_sec, filter=None): + '''**Description** + Fetch all policy events that occurred in the time range [from_sec:to_sec]. This method is used in conjunction + with :func:`~sdcclient.SdSecureClient.get_more_policy_events` to provide paginated access to policy events. + + **Arguments** + - from_sec: the start of the timerange for which to get events + - end_sec: the end of the timerange for which to get events + - filter: this is a SysdigMonitor-like filter (e.g. filter: 'severity in ("4","5") and freeText in ("Suspicious")') + + **Success Return Value** + An array containing: + - A context object that should be passed to later calls to get_more_policy_events. + - An array of policy events, in JSON format. See :func:`~sdcclient.SdSecureClient.get_more_policy_events` + for details on the contents of policy events. + + **Example** + `examples/get_secure_policy_events.py `_ + + ''' + options = {"from": int(from_sec) * 1_000_000_000, + "to": int(to_sec) * 1_000_000_000, + "limit": 50, + "filter": filter} + ctx = {k: v for k, v in options.items() if v is not None} + return self._get_policy_events_int(ctx) + + def get_policy_events_duration(self, duration_sec, filter=None): + '''**Description** + Fetch all policy events that occurred in the last duration_sec seconds. This method is used in conjunction with + :func:`~sdcclient.SdSecureClient.get_more_policy_events` to provide paginated access to policy events. + + **Arguments** + - duration_sec: Fetch all policy events that have occurred in the last *duration_sec* seconds. + - filter: this is a SysdigMonitor-like filter (e.g. filter: 'severity in ("4","5") and freeText in ("Suspicious")') + + **Success Return Value** + An array containing: + - A context object that should be passed to later calls to get_more_policy_events. + - An array of policy events, in JSON format. See :func:`~sdcclient.SdSecureClient.get_more_policy_events` + for details on the contents of policy events. + + **Example** + `examples/get_secure_policy_events.py `_ + + ''' + to_sec = int((datetime.datetime.utcnow() - datetime.datetime.utcfromtimestamp(0)).total_seconds()) + from_sec = to_sec - (int(duration_sec)) + + return self.get_policy_events_range(from_sec, to_sec, filter) + + def get_more_policy_events(self, ctx): + '''**Description** + Fetch additional policy events after an initial call to :func:`~sdcclient.SdSecureClient.get_policy_events_range` / + :func:`~sdcclient.SdSecureClient.get_policy_events_duration` or a prior call to get_more_policy_events. + + **Arguments** + - ctx: a context object returned from an initial call to :func:`~sdcclient.SdSecureClient.get_policy_events_range` / + :func:`~sdcclient.SdSecureClient.get_policy_events_duration` or a prior call to get_more_policy_events. + + **Success Return Value** + An array containing: + - A context object that should be passed to later calls to get_more_policy_events() + - An array of policy events, in JSON format. Each policy event contains the following: + - id: a unique identifier for this policy event + - cursor: unique ID that can be used with get_more_policy_events context to retrieve paginated policy events + - timestamp: when the event occurred (ns since the epoch) + - source: the source of the policy event. It can be "syscall" or "k8s_audit" + - description: the description of the event + - severity: a severity level from 1-7 + - agentId: the agent that reported this event + - machineId: the MAC of the machine that reported this event + - content: More information about what triggered the event + - falsePositive: if the event is considered a false-positive + - fields: raw information from the rule that fired this event + - output: Output from the rule that fired this event + - policyId: the ID of the policy that fired this event + - ruleName: name of the rule that fired this event + - ruleTags: tags from the rule that fired this event + - labels: more information from the scope of this event + + When the number of policy events returned is 0, there are no remaining events and you can stop calling get_more_policy_events(). + + **Example** + `examples/get_secure_policy_events.py `_ + ''' + return self._get_policy_events_int(ctx) diff --git a/specs/__init__.py b/specs/__init__.py index e69de29b..38cb982d 100644 --- a/specs/__init__.py +++ b/specs/__init__.py @@ -0,0 +1,12 @@ +from expects.matchers import Matcher + + +class _be_successful_api_call(Matcher): + def _match(self, expect): + ok, result = expect + if ok: + return True, [f"the api call was successful: {str(result)}"] + return False, [f"the result is {str(result)}"] + + +be_successful_api_call = _be_successful_api_call() diff --git a/specs/_common/event_spec.py b/specs/_common/event_spec.py index 0500366b..778e91ba 100644 --- a/specs/_common/event_spec.py +++ b/specs/_common/event_spec.py @@ -1,13 +1,16 @@ import os -from expects import * -from mamba import * +from expects import equal, expect, contain, have_key, be_empty, be_true, be_false, be_above_or_equal, \ + have_keys +from expects.matchers import _Or +from mamba import before, context, description, it from sdcclient import SdcClient with description("Events") as self: with before.each: self.client = SdcClient( + sdc_url=os.getenv("SDC_MONITOR_URL", "https://app.sysdigcloud.com"), token=os.getenv("SDC_MONITOR_TOKEN"), ) @@ -34,7 +37,7 @@ expect(ok).to(be_true) expect(res).to(have_keys('events', 'total', 'matched')) - expect(len(res['events'])).to_not(equal(0)) + expect(res["total"]).to(be_above_or_equal(0)) with it("fails to retrieve the events with an incorrect category"): ok, res = self.client.get_events(category=['incorrect_category']) @@ -76,8 +79,7 @@ expect(ok).to(be_true) expect(res).to(have_key("events")) - expect(res["events"]).to(contain(have_key("name"))) - expect(res["events"][0]["name"]).to(contain("Container")) + expect(res["events"]).to(_Or(contain(have_key("name", contain("Container"))), be_empty)) with it("retrieves an empty list when the name provided is not found"): ok, res = self.client.get_events(name="RandomUnexistingEvent") diff --git a/specs/secure/policy_events_v1_spec.py b/specs/secure/policy_events_v1_spec.py new file mode 100644 index 00000000..b7d4aa96 --- /dev/null +++ b/specs/secure/policy_events_v1_spec.py @@ -0,0 +1,67 @@ +import datetime +import os + +from expects import be_within, have_len, expect, contain, have_key, be_empty, have_keys +from mamba import before, context, description, it + +from sdcclient.secure import PolicyEventsClientV1 +from specs import be_successful_api_call + +with description("Policy Events v1") as self: + with before.each: + self.client = PolicyEventsClientV1(sdc_url=os.getenv("SDC_SECURE_URL", "https://secure.sysdig.com"), + token=os.getenv("SDC_SECURE_TOKEN")) + with context("when we try to retrieve policy events from the last 7 days"): + with it("returns the list of all events happened"): + day_in_seconds = 7 * 24 * 60 * 60 + + ok, res = self.client.get_policy_events_duration(day_in_seconds) + + expect((ok, res)).to(be_successful_api_call) + expect(res).to(have_keys("ctx", "data")) + expect(res["data"]).to( + contain(have_keys("id", "timestamp", "customerId", "source", "name", "description", "cursor"))) + + with it("returns the list of all events from a range"): + to_sec = int((datetime.datetime.utcnow() - datetime.datetime.utcfromtimestamp(0)).total_seconds()) + from_sec = to_sec - (7 * 24 * 60 * 60) + + ok, res = self.client.get_policy_events_range(from_sec, to_sec) + + expect((ok, res)).to(be_successful_api_call) + expect(res).to(have_keys("ctx", "data")) + expect(res["data"]).to( + contain(have_keys("id", "timestamp", "customerId", "source", "name", "description", "cursor"))) + + + with it("returns the list of all events from the last 7 days that match a filter"): + day_in_seconds = 7 * 24 * 60 * 60 + + ok, res = self.client.get_policy_events_duration(day_in_seconds, filter='severity in ("4","5")') + + expect((ok, res)).to(be_successful_api_call) + expect(res).to(have_keys("ctx", "data")) + expect(res["data"]).to(contain(have_key("severity", be_within(3, 6)))) + + with it("returns an empty list if the filter does not match"): + day_in_seconds = 7 * 24 * 60 * 60 + + ok, res = self.client.get_policy_events_duration(day_in_seconds, filter='severity in ("-1")') + + expect((ok, res)).to(be_successful_api_call) + expect(res).to(have_keys("ctx", "data")) + expect(res["data"]).to(be_empty) + + + with _context("and from the first event we retrieve the rest of events"): + # Deactivated tests. There seems to be a bug in the API -- need confirmation + with it("returns the list of all events except the first"): + day_in_seconds = 7 * 24 * 60 * 60 + _, res = self.client.get_policy_events_duration(day_in_seconds) + ctx = {"cursor": res["data"][0]["cursor"]} + qty_before = len(res["data"]) + + ok, res = self.client.get_more_policy_events(ctx) + + expect((ok, res)).to(be_successful_api_call) + expect(res["data"]).to(have_len(qty_before - 1))