def prepare_scan(source_type, cleanup): """Prepare a scan from the 'sources' section of config file. :param source_type: The scan will be configured to use one source, of the type specified with this parameter. Uses ``get_network_source`` to retreive a source of this type from the config file. :param cleanup: The "cleanup" list that tests use to destroy objects after a test has run. The "cleanup" list is provided by the py.test fixture of the same name defined in camayoc/tests/qpc/conftest.py. This scan is not meant for testing the results of the scan, rather for functional tests that test the ability to effect the state of the scan, for example if you can restart a paused scan. :returns: camayoc.qpc_models.Scan configured for the network source found in the config file. """ src = get_source(source_type, cleanup) if not src: return scn = Scan(scan_type="inspect", source_ids=[src._id]) scn.create() cleanup.append(scn) return scn
def run_scan( scan, disabled_optional_products, enabled_extended_product_search, cleanup, scan_type="inspect", ): """Scan a machine and cache any available results. If errors are encountered, save those and they can be included in test results. """ src_ids = scan["source_ids"] scan_name = scan["name"] SCAN_DATA[scan_name] = { "scan_id": None, # scan id "scan_job_id": None, # scan job id "final_status": None, # Did the scan job contain any failed tasks? "scan_results": None, # Number of systems reached, etc "report_id": None, # so we can retrieve report "connection_results": None, # details about connection scan "inspection_results": None, # details about inspection scan "errors": [], "expected_products": scan["expected_products"], "source_id_to_hostname": scan["source_id_to_hostname"], } try: scan = Scan( source_ids=src_ids, scan_type=scan_type, disabled_optional_products=disabled_optional_products, enabled_extended_product_search=enabled_extended_product_search, ) scan.create() cleanup.append(scan) scanjob = ScanJob(scan_id=scan._id) scanjob.create() SCAN_DATA[scan_name]["scan_id"] = scan._id SCAN_DATA[scan_name]["scan_job_id"] = scanjob._id wait_until_state(scanjob, state="stopped") SCAN_DATA[scan_name]["final_status"] = scanjob.status() SCAN_DATA[scan_name]["scan_results"] = scanjob.read().json() SCAN_DATA[scan_name]["report_id"] = scanjob.read().json().get("report_id") if scan_type == "inspect": SCAN_DATA[scan_name]["task_results"] = scanjob.read().json().get("tasks") SCAN_DATA[scan_name]["inspection_results"] = ( scanjob.inspection_results().json().get("results") ) except (requests.HTTPError, WaitTimeError) as e: SCAN_DATA[scan_name]["errors"].append("{}".format(pformat(str(e))))
def test_scan_with_optional_products(scan_type, shared_client, cleanup): """Create a scan with disabled optional products. :id: 366604ed-e423-4140-b0d8-38626e264688 :description: Perform a scan and disable an optional product. :steps: 1) Create a network credential 2) Create network source using the network credential. 3) Create a scan using the network source. When creating the scan disable the optional products. :expectedresults: The scan is created. """ num_products = random.randint(0, len(QPC_OPTIONAL_PRODUCTS)) product_combinations = combinations(QPC_OPTIONAL_PRODUCTS, num_products) for combo in product_combinations: source_ids = [] for _ in range(random.randint(1, 10)): src_type = random.choice(QPC_SOURCE_TYPES) src = gen_valid_source(cleanup, src_type, "localhost") source_ids.append(src._id) scan = Scan(source_ids=source_ids, scan_type=scan_type, client=shared_client) products = {p: True for p in QPC_OPTIONAL_PRODUCTS if p not in combo} products.update({p: False for p in combo}) scan.options.update({OPTIONAL_PROD: products}) scan.create() cleanup.append(scan) assert scan.equivalent(scan.read().json())
def test_negative_disable_optional_products(scan_type, shared_client, cleanup): """Attempt to disable optional products with non-acceptable booleans. :id: 2adb483c-578d-4131-b426-9f772c1803de :description: Create a scan with bad input for optional products :steps: 1) Create a network credential 2) Create network source using the network credential. 3) Create a scan using the network source. When creating the scan disable the optional products with bad values. :expectedresults: The scan is not created. """ num_products = random.randint(1, len(QPC_OPTIONAL_PRODUCTS)) product_combinations = combinations(QPC_OPTIONAL_PRODUCTS, num_products) for combo in product_combinations: source_ids = [] for _ in range(random.randint(1, 10)): src_type = random.choice(QPC_SOURCE_TYPES) src = gen_valid_source(cleanup, src_type, "localhost") source_ids.append(src._id) scan = Scan(source_ids=source_ids, scan_type=scan_type, client=shared_client) products = {p: True for p in QPC_OPTIONAL_PRODUCTS if p not in combo} bad_choice = random.choice(["hamburger", "87", 42, "*"]) products.update({p: bad_choice for p in combo}) scan.options.update({OPTIONAL_PROD: products}) echo_client = api.Client(response_handler=api.echo_handler) scan.client = echo_client create_response = scan.create() if create_response.status_code == 201: cleanup.append(scan) raise AssertionError( "Optional products should be disabled and\n" "enabled with booleans. If invalid input is given, the user\n" "should be alerted." "The following data was provided: {}".format(products) ) assert create_response.status_code == 400 message = create_response.json().get("options", {}) assert message.get(OPTIONAL_PROD) is not None
def test_equivalent(self): """If a hostname is specified in the config file, we use it.""" with mock.patch.object(config, "_CONFIG", self.config): scn = Scan(source_ids=[153], scan_type="connect", name=MOCK_SCAN["name"]) scn._id = MOCK_SCAN["id"] self.assertTrue(scn.equivalent(MOCK_SCAN)) self.assertTrue(scn.equivalent(scn)) with self.assertRaises(TypeError): scn.equivalent([])
def test_delete_with_dependencies(src_type, cleanup, shared_client): """Test that cannot delete sources if other objects depend on them. :id: 76d79090-a3f7-4750-a8b8-eaf6c2ed4b89 :description: Test that sources cannot be deleted if they are members of a scan. :steps: 1) Create a valid source and one or more scans that use it. 2) Attempt to delete the source, this should fail 3) Delete the scan(s) 4) Assert that we can now delete the source :expectedresults: The source is not created :caseautomation: notautomated """ src1 = gen_valid_source(cleanup, src_type, "localhost") src2 = gen_valid_source(cleanup, src_type, "localhost") scns = [] for i in range(random.randint(2, 6)): if i % 2 == 0: scn = Scan(source_ids=[src1._id]) else: scn = Scan(source_ids=[src1._id, src2._id]) scns.append(scn) scn.create() cleanup.append(scn) src1.client = api.Client(api.echo_handler) # this should fail del_response = src1.delete() assert del_response.status_code == 400 # now delete scan, and then we should be allowed to delete source for scn in scns: scn.delete() cleanup.remove(scn) src1.client = shared_client src1.delete() cleanup.remove(src1)
def test_create(shared_client, cleanup, scan_type): """Create scan and assert it has correct values. :id: ee3b0bc8-1489-443e-86bb-e2a2349e9c98 :description: Create a scan and assert that it completes :steps: 1) Create a network credential 2) Create a network source with the credential 3) Create a scan with the network source 4) Assert that the scan is created and all fields match the request. :expectedresults: A scan is created with all options set as requested. """ source_ids = [] for _ in range(random.randint(1, 10)): src_type = random.choice(QPC_SOURCE_TYPES) src = gen_valid_source(cleanup, src_type, "localhost") source_ids.append(src._id) scan = Scan(source_ids=source_ids, scan_type=scan_type, client=shared_client) scan.create() cleanup.append(scan) remote_scn = scan.read().json() assert scan.equivalent(remote_scn)
def test_update(update_field, shared_client, cleanup, scan_type): """Create scan, then update it and assert the values are changed. :id: c40a64c1-346e-4fce-ad18-4090066050a1 :description: Create a scan and assert that it completes :steps: 1) Create a network credential 2) Create a network source with the credential 3) Create a scan with the network source 4) Assert that the scan is created and all fields match the request. 5) Update a field and assert that changes are made :expectedresults: A scan is created with all options set as requested. """ source_ids = [] for _ in range(random.randint(1, 10)): src_type = random.choice(QPC_SOURCE_TYPES) src = gen_valid_source(cleanup, src_type, "localhost") source_ids.append(src._id) scan = Scan(source_ids=source_ids, scan_type=scan_type, client=shared_client) scan.create() cleanup.append(scan) remote_scn = scan.read().json() assert scan.equivalent(remote_scn) if update_field == "source": src_type = random.choice(QPC_SOURCE_TYPES) src = gen_valid_source(cleanup, src_type, "localhost") scan.sources.append(src._id) if update_field == "max_concurrency": scan.options.update({"max_concurrecny": random.randint(1, 49)}) if update_field == "name": scan.name = uuid4() scan.update() remote_scn = scan.read().json() assert scan.equivalent(remote_scn)