def test_detail_report_invalid_scan_job(self): """Summary report with scanjob but no report_id.""" report_out = StringIO() get_scanjob_url = get_server_location() + \ SCAN_JOB_URI + '1' get_scanjob_json_data = {'id': 1} with requests_mock.Mocker() as mocker: mocker.get(get_scanjob_url, status_code=200, json=get_scanjob_json_data) nac = ReportDetailCommand(SUBPARSER) args = Namespace(scan_job_id='1', report_id=None, output_json=True, output_csv=False, path=self.test_json_filename) with self.assertRaises(SystemExit): with redirect_stdout(report_out): nac.main(args) self.assertEqual(report_out.getvalue(), messages.REPORT_NO_DETAIL_REPORT_FOR_SJ)
def test_insights_nonjson_path(self): """Testing error for nonjson output path.""" non_json_dir = '/Users/insights.tar.gz' report_out = StringIO() get_report_url = get_server_location() + \ REPORT_URI + '1/insights/' get_report_json_data = {'id': 1, 'report': [{'key': 'value'}]} test_dict = dict() test_dict[self.test_json_filename] = get_report_json_data buffer_content = create_tar_buffer(test_dict) with requests_mock.Mocker() as mocker: mocker.get(get_report_url, status_code=200, content=buffer_content) nac = ReportInsightsCommand(SUBPARSER) args = Namespace(scan_job_id=None, report_id='1', path=non_json_dir) with redirect_stdout(report_out): with self.assertRaises(SystemExit): nac.main(args) self.assertEqual(report_out.getvalue().strip(), (messages.OUTPUT_FILE_TYPE % '.json'))
def test_summary_report_scan_job_not_exist(self): """Summary report with nonexistent scanjob.""" report_out = StringIO() get_scanjob_url = get_server_location() + \ SCAN_JOB_URI + '1' get_scanjob_json_data = {'id': 1, 'report_id': 1} with requests_mock.Mocker() as mocker: mocker.get(get_scanjob_url, status_code=400, json=get_scanjob_json_data) nac = ReportSummaryCommand(SUBPARSER) args = Namespace(scan_job_id='1', output_json=True, report_id=None, output_csv=False, path=self.test_json_filename) with self.assertRaises(SystemExit): with redirect_stdout(report_out): nac.main(args) self.assertEqual(report_out.getvalue(), messages.REPORT_SJ_DOES_NOT_EXIST)
def test_insights_upload_nonexistent_report(self, subprocess): """Testing error response with an invalid report id.""" subprocess.return_value.communicate.side_effect = self.success_effect subprocess.return_value.returncode = 0 report_out = StringIO() get_report_url = get_server_location() + \ REPORT_URI + '1/insights/' with requests_mock.Mocker() as mocker: mocker.get(get_report_url, status_code=404, headers={'X-Server-Version': VERSION}, content=None) nac = InsightsUploadCommand(SUBPARSER) args = Namespace(report_id='1', scan_job_id=None, input_file=None, no_gpg=None) with self.assertRaises(SystemExit): with redirect_stdout(report_out): nac.main(args) self.assertIn(messages.INSIGHTS_REPORT_NOT_FOUND % ('1'), report_out.getvalue().strip())
def test_deployments_report_id_not_exist(self): """Test deployments with nonexistent report id.""" report_out = StringIO() get_report_url = get_server_location() + \ REPORT_URI + '1/deployments/' get_report_json_data = {'id': 1, 'report': [{'key': 'value'}]} test_dict = dict() test_dict[self.test_json_filename] = get_report_json_data buffer_content = create_tar_buffer(test_dict) with requests_mock.Mocker() as mocker: mocker.get(get_report_url, status_code=400, content=buffer_content) nac = ReportDeploymentsCommand(SUBPARSER) args = Namespace(scan_job_id=None, report_id='1', output_json=True, output_csv=False, path=self.test_json_filename) with redirect_stdout(report_out): with self.assertRaises(SystemExit): nac.main(args) err = (messages.REPORT_NO_DEPLOYMENTS_REPORT_FOR_REPORT_ID % 1) self.assertEqual(report_out.getvalue().strip(), err)
def test_details_report_id_not_exist(self): """Test details with nonexistent report id.""" report_out = StringIO() get_report_url = get_server_location() + \ REPORT_URI + '1/details/' get_report_json_data = {'id': 1, 'report': [{'key': 'value'}]} with requests_mock.Mocker() as mocker: mocker.get(get_report_url, status_code=400, json=get_report_json_data) nac = ReportDetailsCommand(SUBPARSER) args = Namespace(scan_job_id=None, report_id='1', output_json=True, output_csv=False, path=self.test_json_filename) with redirect_stdout(report_out): with self.assertRaises(SystemExit): nac.main(args) self.assertEqual( report_out.getvalue().strip(), messages.REPORT_NO_DETAIL_REPORT_FOR_REPORT_ID % 1)
def test_download_from_server_with_old_version(self): """Test download with nonexistent report id.""" report_out = StringIO() get_report_url = get_server_location() + \ REPORT_URI + '1' get_report_json_data = {'id': 1, 'report': [{'key': 'value'}]} with requests_mock.Mocker() as mocker: mocker.get(get_report_url, status_code=400, headers={'X-Server-Version': QPC_MIN_SERVER_VERSION}, json=get_report_json_data) nac = ReportDownloadCommand(SUBPARSER) args = Namespace(scan_job_id=None, report_id=1, path=self.test_tar_filename) with redirect_stdout(report_out): with self.assertRaises(SystemExit): nac.main(args) self.assertEqual( report_out.getvalue().strip(), messages.SERVER_TOO_OLD_FOR_CLI % ('0.0.46', '0.0.46', QPC_MIN_SERVER_VERSION))
def test_insights_upload_valid_scan_job_no_report_id(self, subprocess): """Testing response with a valid scan job id but no report_id.""" subprocess.return_value.communicate.side_effect = self.success_effect subprocess.return_value.returncode = 0 report_out = StringIO() get_scanjob_url = get_server_location() + \ SCAN_JOB_URI + '1' get_scanjob_json_data = {'id': 1} with requests_mock.Mocker() as mocker: mocker.get(get_scanjob_url, status_code=200, json=get_scanjob_json_data) nac = InsightsUploadCommand(SUBPARSER) args = Namespace(scan_job_id='1', report_id=None, input_file=None, no_gpg=None) with self.assertRaises(SystemExit): with redirect_stdout(report_out): nac.main(args) self.assertIn(messages.REPORT_NO_DEPLOYMENTS_REPORT_FOR_SJ % '1', report_out.getvalue().strip())
def test_print_server_status(self): """Testing recording server status command in a file.""" status_out = StringIO() get_status_url = get_server_location() + \ STATUS_URI get_status_json_data = { 'api_version': 1, 'build': 'a64eee4', 'environment_vars': { 'key': 'value' } } with requests_mock.Mocker() as mocker: mocker.get(get_status_url, status_code=200, json=get_status_json_data) ssc = ServerStatusCommand(SUBPARSER) args = Namespace(path=None) with redirect_stdout(status_out): ssc.main(args) self.assertDictEqual(json.loads(status_out.getvalue().strip()), get_status_json_data)
def test_insights_nonexistent_directory(self): """Testing error for nonexistent directory in output.""" fake_dir = '/kevan/is/awesome/insights.tar.gz' report_out = StringIO() get_report_url = get_server_location() + \ REPORT_URI + '1/insights/' get_report_json_data = {'id': 1, 'report': [{'key': 'value'}]} test_dict = dict() test_dict[self.test_tar_gz_filename] = get_report_json_data buffer_content = create_tar_buffer(test_dict) with requests_mock.Mocker() as mocker: mocker.get(get_report_url, status_code=200, content=buffer_content) nac = ReportInsightsCommand(SUBPARSER) args = Namespace(scan_job_id=None, report_id='1', path=fake_dir) with redirect_stdout(report_out): with self.assertRaises(SystemExit): nac.main(args) self.assertEqual(report_out.getvalue().strip(), (messages.REPORT_DIRECTORY_DOES_NOT_EXIST % os.path.dirname(fake_dir)))
def test_details_old_version(self): """Test too old server version.""" report_out = StringIO() get_report_url = get_server_location() + \ REPORT_URI + '1/details/' get_report_json_data = {'id': 1, 'report': [{'key': 'value'}]} with requests_mock.Mocker() as mocker: mocker.get(get_report_url, status_code=400, headers={'X-Server-Version': '0.0.45'}, json=get_report_json_data) nac = ReportDetailsCommand(SUBPARSER) args = Namespace(scan_job_id=None, report_id='1', output_json=False, output_csv=True, path=self.test_csv_filename, mask=False) with redirect_stdout(report_out): with self.assertRaises(SystemExit): nac.main(args) self.assertEqual(report_out.getvalue().strip(), messages.SERVER_TOO_OLD_FOR_CLI % ('0.9.2', '0.9.2', '0.0.45'))
def test_download_report_id(self): """Testing download with report id.""" report_out = StringIO() get_report_url = get_server_location() + \ REPORT_URI + '1' get_report_json_data = {'id': 1, 'report': [{'key': 'value'}]} test_dict = dict() test_dict[self.test_tar_filename] = get_report_json_data buffer_content = create_tar_buffer(test_dict) with requests_mock.Mocker() as mocker: mocker.get(get_report_url, status_code=200, headers={'X-Server-Version': VERSION}, content=buffer_content) nac = ReportDownloadCommand(SUBPARSER) args = Namespace(scan_job_id=None, report_id='1', path=self.test_tar_filename, mask=False) with redirect_stdout(report_out): nac.main(args) self.assertEqual(report_out.getvalue().strip(), messages.DOWNLOAD_SUCCESSFULLY_WRITTEN % ('1', self.test_tar_filename))
def test_insights_upload_invalid_report(self, subprocess): """Testing response with an invaild report id.""" subprocess.return_value.communicate.side_effect = self.success_effect subprocess.return_value.returncode = 0 report_out = StringIO() get_report_url = get_server_location() + REPORT_URI + '1/insights/' buffer_content = create_tar_buffer( {'insights.json': self.json_missing_hosts}) with requests_mock.Mocker() as mocker: mocker.get(get_report_url, status_code=200, headers={'X-Server-Version': VERSION}, content=buffer_content) nac = InsightsUploadCommand(SUBPARSER) args = Namespace(report_id='1', scan_job=None, json_file=None, no_gpg=None) with self.assertRaises(SystemExit): with redirect_stdout(report_out): nac.main(args) self.assertIn(messages.INSIGHTS_REPORT_MISSING_FIELDS % 'hosts', report_out.getvalue().strip())
def test_download_bad_file_extension(self): """Test download with bad file extension.""" report_out = StringIO() get_report_url = get_server_location() + \ REPORT_URI + '1' get_report_json_data = {'id': 1, 'report': [{'key': 'value'}]} test_dict = dict() test_dict[self.test_tar_filename] = get_report_json_data buffer_content = create_tar_buffer(test_dict) with requests_mock.Mocker() as mocker: mocker.get(get_report_url, status_code=200, headers={'X-Server-Version': VERSION}, content=buffer_content) nac = ReportDownloadCommand(SUBPARSER) args = Namespace(scan_job_id=None, report_id='1', path='test.json', mask=False) with redirect_stdout(report_out): with self.assertRaises(SystemExit): nac.main(args) self.assertEqual(report_out.getvalue().strip(), messages.OUTPUT_FILE_TYPE % 'tar.gz')
def test_scan_job_filter_status(self): """Testing the scan job with filter by status.""" scan_out = StringIO() url = get_server_location() + SCAN_URI # set up scan object scan_entry = {'id': 1, 'name': 'scan1', 'scan_type': 'inspect', 'source': { 'id': 1, 'name': 'scan1'}} results = [scan_entry] data = { 'count': 1, 'next': None, 'results': results } # set up scan jobs urlscanjob = url + '1/jobs/?status=completed' scan_job = {'count': 3, 'results': [{'id': 1, 'status': 'completed', 'scan': 'scan1'}, {'id': 2, 'status': 'completed', 'scan': 'scan1'}]} with requests_mock.Mocker() as mocker: mocker.get(url, status_code=200, json=data) mocker.get(urlscanjob, status_code=200, json=scan_job) sjc = ScanJobCommand(SUBPARSER) args = Namespace(name='scan1', status='completed', id=None) with redirect_stdout(scan_out): sjc.main(args) expected = '[{"id":1,"scan":"scan1","status":"completed"},' \ '{"id":2,"scan":"scan1","status":"completed"}]' self.assertEqual(scan_out.getvalue().replace('\n', '') .replace(' ', '').strip(), expected)
def test_list_filtered_cred_data(self): """Testing the list credential with filter by cred type.""" cred_out = StringIO() url = get_server_location() + CREDENTIAL_URI credential_entry = {'id': 1, 'name': 'cred1', 'cred_type': 'network', 'username': '******', 'password': '******'} results = [credential_entry] data = { 'count': 1, 'next': None, 'results': results } with requests_mock.Mocker() as mocker: mocker.get(url, status_code=200, json=data) alc = CredListCommand(SUBPARSER) args = Namespace(type='network') with redirect_stdout(cred_out): alc.main(args) expected = '[{"cred_type":"network","id":1,'\ '"name":"cred1","password":"******",' \ '"username":"******"}]' self.assertEqual(cred_out.getvalue().replace('\n', '') .replace(' ', '').strip(), expected)
def test_details_file_fails_to_write(self, file): """Testing details failure while writing to file.""" file.side_effect = EnvironmentError() report_out = StringIO() get_report_url = get_server_location() + \ REPORT_URI + '1/details/' get_report_json_data = {'id': 1, 'report': [{'key': 'value'}]} test_dict = dict() test_dict[self.test_json_filename] = get_report_json_data buffer_content = create_tar_buffer(test_dict) with requests_mock.Mocker() as mocker: mocker.get(get_report_url, status_code=200, content=buffer_content) nac = ReportDetailsCommand(SUBPARSER) args = Namespace(scan_job_id=None, report_id='1', output_json=True, output_csv=False, path=self.test_json_filename) with redirect_stdout(report_out): with self.assertRaises(SystemExit): nac.main(args) err_msg = (messages.WRITE_FILE_ERROR % (self.test_json_filename, '')) self.assertEqual(report_out.getvalue().strip(), err_msg)
def test_insights_upload_valid_report(self, subprocess): """Testing response with a valid report id.""" subprocess.return_value.communicate.side_effect = self.success_effect subprocess.return_value.returncode = 0 report_out = StringIO() get_report_url = get_server_location() + \ REPORT_URI + '1/insights/' buffer_content = create_tar_buffer( {'insights.json': self.success_json}) with requests_mock.Mocker() as mocker: mocker.get(get_report_url, status_code=200, headers={'X-Server-Version': VERSION}, content=buffer_content) nac = InsightsUploadCommand(SUBPARSER) args = Namespace(report_id='1', scan_job=None, input_file=None, no_gpg=True) with redirect_stdout(report_out): nac.main(args) self.assertIn( messages.REPORT_INSIGHTS_REPORT_SUCCESSFULLY_UPLOADED, report_out.getvalue().strip())
def main(self): """Execute of subcommand operation. Method determine whether to display usage or pass input to find the best command match. If no match is found the usage is displayed """ self.args = self.parser.parse_args() setup_logging(self.args.verbosity) is_server_cmd = self.args.subcommand == server.SUBCOMMAND is_server_login = is_server_cmd and self.args.action == server.LOGIN is_server_logout = is_server_cmd and self.args.action == server.LOGOUT if not is_server_cmd or is_server_login or is_server_logout: # Before attempting to run command, check server location server_location = get_server_location() if server_location is None or server_location == '': log.error(_(messages.SERVER_CONFIG_REQUIRED)) log.error('$ qpc server config --host HOST --port PORT') sys.exit(1) if ((not is_server_cmd or is_server_logout) and not read_client_token()): log.error(_(messages.SERVER_LOGIN_REQUIRED)) log.error('$ qpc server login') sys.exit(1) if self.args.subcommand in self.subcommands: subcommand = self.subcommands[self.args.subcommand] if self.args.action in subcommand: action = subcommand[self.args.action] action.main(self.args) else: self.parser.print_help() else: self.parser.print_help()
def test_show_cred_data(self): """Testing the show credential command with stubbed data.""" cred_out = StringIO() url = get_server_location() + CREDENTIAL_URI + '?name=cred1' credential_entry = { 'id': 1, 'name': 'cred1', 'username': '******', 'password': '******' } results = [credential_entry] data = {'count': 1, 'results': results} with requests_mock.Mocker() as mocker: mocker.get(url, status_code=200, json=data) asc = CredShowCommand(SUBPARSER) args = Namespace(name='cred1') with redirect_stdout(cred_out): asc.main(args) expected = '{"id":1,"name":"cred1","password":"******",' \ '"username":"******"}' self.assertEqual( cred_out.getvalue().replace('\n', '').replace(' ', '').strip(), expected)
def test_detail_report_as_json_report_id(self): """Testing retreiving detail report as json with report id.""" report_out = StringIO() get_report_url = get_server_location() + \ REPORT_URI + '1/details/' get_report_json_data = {'id': 1, 'report': [{'key': 'value'}]} with requests_mock.Mocker() as mocker: mocker.get(get_report_url, status_code=200, json=get_report_json_data) nac = ReportDetailCommand(SUBPARSER) args = Namespace(scan_job_id=None, report_id='1', output_json=True, output_csv=False, path=self.test_json_filename) with redirect_stdout(report_out): nac.main(args) self.assertEqual(report_out.getvalue().strip(), messages.REPORT_SUCCESSFULLY_WRITTEN) with open(self.test_json_filename, 'r') as json_file: data = json_file.read() file_content_dict = json.loads(data) self.assertDictEqual(get_report_json_data, file_content_dict)
def test_cmd_not_found_response(self, subprocess): """Testing error response with unexpected response version.""" subprocess.return_value.communicate.side_effect = \ [(None, b'insights-client: command not found')] subprocess.return_value.returncode = 0 report_out = StringIO() get_report_url = get_server_location() + \ REPORT_URI + '1/insights/' with requests_mock.Mocker() as mocker: mocker.get(get_report_url, status_code=400, headers={'X-Server-Version': VERSION}, json=None) nac = InsightsUploadCommand(SUBPARSER) args = Namespace(report_id='1', scan_job_id=None, input_file=None, no_gpg=None) with self.assertRaises(SystemExit): with redirect_stdout(report_out): nac.main(args) cli_error_msg = (messages.BAD_INSIGHTS_INSTALL % ('sudo insights-client --test-connection')) self.assertIn(cli_error_msg, report_out.getvalue())
def request(method, path, params=None, payload=None, parser=None, headers=None): """Create a generic handler for passing to specific request methods. :param method: the request method to execute :param path: path after server and port (i.e. /api/v1/credentials) :param params: uri encoding params (i.e. ?param1=hello¶m2=world) :param payload: dictionary of payload to be posted :param parser: parser for printing usage on failure :param headers: headers to include :returns: reponse object :raises: AssertionError error if method is not supported """ # grab the cli command for the log if the parser is provided log_command = None if parser is not None: log_command = parser.prog req_headers = {} token = read_client_token() # create the url by adding the path to the configured server location url = get_server_location() + path if headers: req_headers.update(headers) if token: req_headers['Authorization'] = 'Token {}'.format(token) try: if method == POST: result = handle_general_errors(post(url, payload, req_headers)) elif method == GET: result = handle_general_errors(get(url, params, req_headers)) elif method == PATCH: result = handle_general_errors(patch(url, payload, req_headers)) elif method == DELETE: result = handle_general_errors(delete(url, req_headers)) elif method == PUT: result = handle_general_errors(put(url, payload, req_headers)) else: log.error('Unsupported request method %s', method) parser.print_help() sys.exit(1) try: log_request_info(method, log_command, url, result.json(), result.status_code) except ValueError: log_request_info(method, log_command, url, result.text, result.status_code) return result except requests.exceptions.SSLError as ssl_error: print(_(SSL_ERROR_MSG)) log.error(ssl_error) if parser is not None: parser.print_help() sys.exit(1) except requests.exceptions.ConnectionError as conn_err: print(_(CONNECTION_ERROR_MSG)) log.error(conn_err) if parser is not None: parser.print_help() sys.exit(1)
from qpc.request import CONNECTION_ERROR_MSG, SSL_ERROR_MSG from qpc.source import SOURCE_URI from qpc.source.show import SourceShowCommand from qpc.tests_utilities import HushUpStderr, redirect_stdout from qpc.utils import get_server_location, write_server_config import requests import requests_mock PARSER = ArgumentParser() SUBPARSER = PARSER.add_subparsers(dest='subcommand') write_server_config({'host': '127.0.0.1', 'port': 8000, 'use_http': True}) BASE_URL = get_server_location() print(BASE_URL) class SourceShowCliTests(unittest.TestCase): """Class for testing the source show commands for qpc.""" def setUp(self): """Create test setup.""" # Temporarily disable stderr for these tests, CLI errors clutter up # nosetests command. self.orig_stderr = sys.stderr sys.stderr = HushUpStderr() def tearDown(self): """Remove test setup.""" # Restore stderr
def request(method, path, params=None, payload=None, parser=None, headers=None, min_server_version=QPC_MIN_SERVER_VERSION): """Create a generic handler for passing to specific request methods. :param method: the request method to execute :param path: path after server and port (i.e. /api/v1/credentials) :param params: uri encoding params (i.e. ?param1=hello¶m2=world) :param payload: dictionary of payload to be posted :param parser: parser for printing usage on failure :param headers: headers to include :param min_server_version: min qpc server version allowed :returns: reponse object :raises: AssertionError error if method is not supported """ # grab the cli command for the log if the parser is provided log_command = None if parser is not None: log_command = parser.prog req_headers = {} token = read_client_token() # create the url by adding the path to the configured server location url = get_server_location() + path if headers: req_headers.update(headers) if token: req_headers['Authorization'] = 'Token {}'.format(token) try: if method == POST: result = handle_general_errors(post(url, payload, req_headers), min_server_version) elif method == GET: result = handle_general_errors(get(url, params, req_headers), min_server_version) elif method == PATCH: result = handle_general_errors(patch(url, payload, req_headers), min_server_version) elif method == DELETE: result = handle_general_errors(delete(url, req_headers), min_server_version) elif method == PUT: result = handle_general_errors(put(url, payload, req_headers), min_server_version) else: log.error('Unsupported request method %s', method) parser.print_help() sys.exit(1) try: log_request_info(method, log_command, url, result.json(), result.status_code) except ValueError: log_request_info(method, log_command, url, result.text, result.status_code) return result except (requests.exceptions.ConnectionError, requests.exceptions.SSLError): config = read_server_config() if config is not None: protocol = 'https' host = config.get(CONFIG_HOST_KEY) port = config.get(CONFIG_PORT_KEY) if config.get(CONFIG_USE_HTTP): protocol = 'http' log.error(_(CONNECTION_ERROR_MSG % (protocol, host, port))) log.error(_(messages.SERVER_CONFIG_REQUIRED % PKG_NAME)) else: log.error(_(messages.SERVER_CONFIG_REQUIRED % PKG_NAME)) sys.exit(1)
def setUp(self): """Create test setup.""" write_server_config(DEFAULT_CONFIG) self.orig_stderr = sys.stderr sys.stderr = HushUpStderr() self.url = get_server_location() + ASYNC_MERGE_URI