From 429b49a021fee89a7ccea68915dd4573a8f77089 Mon Sep 17 00:00:00 2001 From: Jacob Boddey Date: Mon, 20 May 2024 13:19:01 +0100 Subject: [PATCH] Add get profiles format endpoint --- framework/python/src/api/api.py | 22 +++- framework/python/src/common/session.py | 34 +++++- framework/python/src/core/testrun.py | 3 +- resources/devices/template/device_config.json | 4 +- resources/risk_assessment.json | 115 ++++++++++++++++++ 5 files changed, 171 insertions(+), 7 deletions(-) create mode 100644 resources/risk_assessment.json diff --git a/framework/python/src/api/api.py b/framework/python/src/api/api.py index 9f0da15c2..a5a72f31f 100644 --- a/framework/python/src/api/api.py +++ b/framework/python/src/api/api.py @@ -95,10 +95,14 @@ def __init__(self, test_run): self._router.add_api_route("/device/edit", self.edit_device, methods=["POST"]) - + self._router.add_api_route("/system/modules", self.get_test_modules) + # Profiles + self._router.add_api_route("/profiles/format", + self._get_profiles_format) + # Allow all origins to access the API origins = ["*"] @@ -130,6 +134,9 @@ def _start(self): def stop(self): LOGGER.info("Stopping API") + def get_session(self): + return self._session + async def get_sys_interfaces(self): addrs = psutil.net_if_addrs() ifaces = {} @@ -527,7 +534,6 @@ async def edit_device(self, request: Request, response: Response): response.status_code = status.HTTP_400_BAD_REQUEST return self._generate_msg(False, "Invalid JSON received") - async def get_report(self, response: Response, device_name, timestamp): @@ -596,3 +602,15 @@ def _validate_device_json(self, json_obj): def _get_test_run(self): return self._test_run + + # Profiles + def _get_profiles_format(self, response: Response): + + # Check if Testrun was able to load the format originally + if self.get_session().get_profiles_format() is None: + response.status_code = status.HTTP_500_INTERNAL_SERVER_ERROR + return self._generate_msg( + False, + "Testrun could not load the risk assessment format") + + return self.get_session().get_profiles_format() diff --git a/framework/python/src/common/session.py b/framework/python/src/common/session.py index df7a1c3b2..bd9dc658a 100644 --- a/framework/python/src/common/session.py +++ b/framework/python/src/common/session.py @@ -29,12 +29,17 @@ API_PORT_KEY = 'api_port' MAX_DEVICE_REPORTS_KEY = 'max_device_reports' +PROFILE_FORMAT_PATH = 'resources/risk_assessment.json' +PROFILES_DIR = 'local/profiles' + LOGGER = logger.get_logger('session') class TestrunSession(): """Represents the current session of Test Run.""" - def __init__(self, config_file, version): + def __init__(self, root_dir, config_file, version): + self._root_dir = root_dir + self._status = 'Idle' self._device = None self._started = None @@ -46,11 +51,18 @@ def __init__(self, config_file, version): self._total_tests = 0 self._report_url = None - self._load_version(default_version=version) + # Profiles + self._profiles = [] + self._profile_format_json = None + # System configuration self._config_file = config_file self._config = self._get_default_config() + + # Loading methods + self._load_version(default_version=version) self._load_config() + self._load_profiles() tz = util.run_command('cat /etc/timezone') # TODO: Check if timezone is fetched successfully @@ -292,6 +304,24 @@ def get_report_url(self): def set_report_url(self, url): self._report_url = url + def _load_profiles(self): + + # Load format of questionnaire + LOGGER.debug('Loading risk assessment format') + + try: + with open(os.path.join( + self._root_dir, PROFILE_FORMAT_PATH + ), encoding='utf-8') as profile_format_file: + self._profile_format_json = json.load(profile_format_file) + except (IOError, ValueError) as e: + LOGGER.error( + 'An error occurred whilst loading the risk assessment format') + LOGGER.debug(e) + + def get_profiles_format(self): + return self._profile_format_json + def reset(self): self.set_status('Idle') self.set_target_device(None) diff --git a/framework/python/src/core/testrun.py b/framework/python/src/core/testrun.py index 22607a520..e7c77c517 100644 --- a/framework/python/src/core/testrun.py +++ b/framework/python/src/core/testrun.py @@ -89,7 +89,8 @@ def __init__(self, self._register_exits() # Create session - self._session = TestrunSession(config_file=self._config_file, + self._session = TestrunSession(root_dir=root_dir, + config_file=self._config_file, version=self.get_version()) # Register runtime parameters diff --git a/resources/devices/template/device_config.json b/resources/devices/template/device_config.json index dc6d74924..85ff6aafe 100644 --- a/resources/devices/template/device_config.json +++ b/resources/devices/template/device_config.json @@ -2,7 +2,7 @@ "manufacturer": "Manufacturer X", "model": "Device X", "mac_addr": "aa:bb:cc:dd:ee:ff", - "max_device_tests":5, + "max_device_tests": 0, "test_modules": { "dns": { "enabled": true @@ -16,7 +16,7 @@ "baseline": { "enabled": false }, - "nmap": { + "services": { "enabled": true }, "tls": { diff --git a/resources/risk_assessment.json b/resources/risk_assessment.json new file mode 100644 index 000000000..25f0f6888 --- /dev/null +++ b/resources/risk_assessment.json @@ -0,0 +1,115 @@ +[ + { + "question": "What type of device is this?", + "type": "select", + "options": [ + "IoT Sensor", + "IoT Controller", + "Smart Device", + "Something else" + ], + "validation": { + "required": true + } + }, + { + "question": "How will this device be used at Google?", + "type": "text", + "validation": { + "max": "128", + "required": true + } + }, + { + "question": "What is the email of the device owner(s)?", + "type": "text", + "validation": { + "required": true, + "max": "128" + } + }, + { + "question": "Is this device going to be managed by Google or a third party?", + "type": "select", + "options": [ + "Google", + "Third Party" + ], + "validation": { + "required": true + } + }, + { + "question": "Will the third-party device administrator be able to grant access to authorized Google personnel upon request?", + "type": "select", + "options": [ + "Yes", + "No", + "N/A" + ], + "default": "N/A", + "validation": { + "required": true + } + }, + { + "question": "Are any of the following statements true about your device?", + "description": "This tells us about the data your device will collect", + "type": "select-multiple", + "options": [ + "The device collects any Personal Identifiable Information (PII) or Personal Health Information (PHI)", + "The device collects intellectual property and trade secrets, sensitive business data, critical infrastructure data, identity assets", + "The device stream confidential business data in real-time (seconds)?" + ] + }, + { + "question": "Which of the following statements are true about this device?", + "description": "This tells us about the types of data that are transmitted from this device and how the transmission is performed from a technical standpoint.", + "type": "select-multiple", + "options": [ + "PII/PHI, confidential business data, or crown jewel data is transmitted to a destination outside Alphabet's ownership", + "Data transmission occurs across less-trusted networks (e.g. the internet).", + "A failure in data transmission would likely have a substantial negative impact (https://www.rra.rocks/docs/standard_levels#levels-definitions)", + "A confidentiality breach during transmission would have a substantial negative impact", + "The device encrypts data during transmission", + "The device network protocol is well-established and currently used by Google" + ] + }, + { + "question": "Does the network protocol assure server-to-client identity verification?", + "type": "select", + "options": [ + "Yes", + "No", + "I don't know" + ], + "validation": { + "required": true + } + }, + { + "question": "Click the statements that best describe the characteristics of this device.", + "description": "This tells us about how this device is managed remotely.", + "type": "select-multiple", + "options": [ + "PII/PHI, or confidential business data is accessible from the device without authentication", + "Unrecoverable actions (e.g. disk wipe) can be performed remotely", + "Authentication is required for remote access", + "The management interface is accessible from the public internet", + "Static credentials are used for administration" + ] + }, + { + "question": "Are any of the following statements true about this device?", + "description": "This informs us about what other systems and processes this device is a part of.", + "type": "select-multiple", + "options": [ + "The device monitors an environment for active risks to human life.", + "The device is used to convey people, or critical property.", + "The device controls robotics in human-accessible spaces.", + "The device controls physical access systems.", + "The device is involved in processes required by regulations, or compliance. (ex. privacy, security, safety regulations)", + "The device's failure would cause faults in other high-criticality processes." + ] + } +] \ No newline at end of file