def X_test_env_vars(): domain = "app.compliancedb.com" build_url = "https://gitlab/build/1956" protocol = "docker://" image_name = "acme/widget:4.67" api_token = "5199831f4ee3b79e7c5b7e0ebe75d67aa66e79d4" env = { "MERKELY_API_TOKEN": api_token, "MERKELY_CI_BUILD_URL": build_url, "MERKELY_COMMAND": "log_evidence", "MERKELY_DESCRIPTION": "branch coverage", "MERKELY_EVIDENCE_TYPE": "unit_test", "MERKELY_FINGERPRINT": f"{protocol}/{image_name}", "MERKELY_HOST": f"https://{domain}", "MERKELY_IS_COMPLIANT": "TRUE", } command = LogEvidence(External(env=env)) env_vars = command.merkely_env_vars assert env_vars.api_token.value == api_token assert env_vars.ci_build_url.value == build_url assert env_vars.description.value == "branch coverage" assert env_vars.evidence_type.value == "unit_test" assert env_vars.fingerprint.value == f"{protocol}/{image_name}" assert env_vars.host.value == f"https://{domain}" assert env_vars.is_compliant.value == 'TRUE'
def test_raises_when_api_token_is_empty_string(capsys): ev = core_env_vars() ev["MERKELY_API_TOKEN"] = "" with dry_run(ev) as env, scoped_merkelypipe_json(): with raises(ChangeError): run(External(env=env))
def test_required_env_vars(capsys, mocker): env = old_log_artifact_env() set_env_vars = { 'CDB_ARTIFACT_GIT_URL': f"{BB}/{BB_ORG}/{BB_REPO}/commits/{COMMIT}", 'CDB_ARTIFACT_GIT_COMMIT': COMMIT, 'CDB_BUILD_NUMBER': BUILD_NUMBER, 'CDB_CI_BUILD_URL': f'{BB}/{BB_ORG}/{BB_REPO}/addon/pipelines/home#!/results/{BUILD_NUMBER}', 'CDB_ARTIFACT_SHA': SHA256, } with dry_run(env, set_env_vars): pipe = BitbucketPipe(pipe_metadata='/pipe.yml', schema=schema) mocker.patch('cdb.cdb_utils.calculate_sha_digest_for_docker_image', return_value=SHA256) pipe.run() # extract data from approved cdb text file import inspect this_test = inspect.stack()[0].function approved = f"{APPROVAL_DIR}/{APPROVAL_FILE}.{this_test}.approved.txt" with open(approved) as file: old_approval = file.read() _old_blurb, old_method, old_payload, old_url = extract_blurb_method_payload_url( old_approval) expected_method = "Putting" expected_url = f"https://{DOMAIN}/api/v1/projects/{OWNER}/{PIPELINE}/artifacts/" expected_payload = { "build_url": f"{BB}/{BB_ORG}/{BB_REPO}/addon/pipelines/home#!/results/{BUILD_NUMBER}", "commit_url": f"{BB}/{BB_ORG}/{BB_REPO}/commits/{COMMIT}", "description": f"Created by build {BUILD_NUMBER}", "filename": IMAGE_NAME, "git_commit": COMMIT, "is_compliant": False, "sha256": SHA256, } # verify data from approved cdb text file assert old_payload == expected_payload assert old_method == expected_method assert old_url == expected_url # make merkely call ev = new_log_artifact_env() with dry_run(ev) as env: with MockDockerFingerprinter(IMAGE_NAME, SHA256) as fingerprinter: external = External(env=env, docker_fingerprinter=fingerprinter) method, url, payload = run(external) capsys_read(capsys) # CHANGE IN BEHAVIOUR expected_payload['user_data'] = {} # verify matching data assert method == expected_method assert url == expected_url assert payload == expected_payload
def test_raises_when_src_repo_root_does_not_exist(capsys): ev = new_log_approval_env() with dry_run(ev) as env: with raises(ChangeError) as exc: run(External(env=env)) silent(capsys) assert str(exc.value) == "Error: Repository not found at /src/.git"
def test_bitbucket(capsys, mocker): # The original bitbucket code did not do a translation for put_evidence env = old_log_evidence_env() set_env_vars = {} with dry_run(env, set_env_vars): mocker.patch('cdb.cdb_utils.calculate_sha_digest_for_docker_image', return_value=SHA256) put_evidence("tests/data/Merkelypipe.acme-roadrunner.json") verify_approval(capsys, ["out"]) # extract data from approved cdb text file import inspect this_test = inspect.stack()[0].function approved = f"{APPROVAL_DIR}/{APPROVAL_FILE}.{this_test}.approved.txt" with open(approved) as file: old_approval = file.read() _old_blurb, old_method, old_payload, old_url = extract_blurb_method_payload_url( old_approval) expected_method = "Putting" expected_url = f"https://{DOMAIN}/api/v1/projects/{OWNER}/{PIPELINE}/artifacts/{SHA256}" expected_payload = { "contents": { "description": DESCRIPTION, "is_compliant": True, "url": f"https://{BB}/{BB_ORG}/{BB_REPO}/addon/pipelines/home#!/results/{BUILD_NUMBER}", }, "evidence_type": EVIDENCE_TYPE } # verify data from approved cdb text file assert old_method == expected_method assert old_url == expected_url assert old_payload == expected_payload # make merkely call ev = new_log_evidence_env() with dry_run(ev) as env: with MockDockerFingerprinter(IMAGE_NAME, SHA256) as fingerprinter: external = External(env=env, docker_fingerprinter=fingerprinter) method, url, payload = run(external) # CHANGE IN BEHAVIOUR expected_payload['user_data'] = {} # verify matching data assert method == expected_method assert url == expected_url assert payload == expected_payload assert extract_blurb(capsys_read(capsys)) == [ 'MERKELY_COMMAND=log_evidence', 'MERKELY_IS_COMPLIANT: True', ]
def test_docker_image(capsys, mocker): # make the cdb call env = { "CDB_ARTIFACT_DOCKER_IMAGE": IMAGE_NAME, "CDB_DESCRIPTION": DESCRIPTION, "CDB_ENVIRONMENT": ENVIRONMENT, "CDB_CI_BUILD_URL": CI_BUILD_URL, "CDB_USER_DATA": USER_DATA, } set_env_vars = {'CDB_ARTIFACT_SHA': SHA256} with dry_run(env, set_env_vars): mocker.patch('cdb.cdb_utils.calculate_sha_digest_for_docker_image', return_value=SHA256) create_deployment("tests/integration/test-pipefile.json") verify_approval(capsys, ["out"]) # extract data from approved cdb text file import inspect this_test = inspect.stack()[0].function approved = f"{APPROVAL_DIR}/{APPROVAL_FILE}.{this_test}.approved.txt" with open(approved) as file: old_approval = file.read() _old_blurb, old_method, old_payload, old_url = extract_blurb_method_payload_url( old_approval) expected_method = "Posting" expected_url = f"https://{DOMAIN}/api/v1/projects/{OWNER}/{NAME}/deployments/" expected_payload = { "artifact_sha256": SHA256, "build_url": CI_BUILD_URL, "description": DESCRIPTION, "environment": ENVIRONMENT, "user_data": { 'status': 'deployed' }, } # verify data from approved cdb text file assert old_method == expected_method assert old_url == expected_url assert old_payload == expected_payload # make merkely call protocol = "docker://" ev = create_new_deployment_env() ev["MERKELY_FINGERPRINT"] = f"{protocol}{IMAGE_NAME}" with dry_run(ev) as env: with MockDockerFingerprinter(IMAGE_NAME, SHA256) as fingerprinter: external = External(env=env, docker_fingerprinter=fingerprinter) method, url, payload = run(external) # verify matching data assert method == expected_method assert url == expected_url assert payload == expected_payload assert extract_blurb(capsys_read(capsys)) == [ 'MERKELY_COMMAND=log_deployment', ]
def X_test_each_required_env_var_missing(capsys): for env_var in make_command_env_vars(): if env_var.is_required: ev = new_log_artifact_env() ev.pop(env_var.name) with dry_run(ev) as env, scoped_merkelypipe_json(): status = main(External(env=env)) assert status != 0 verify_approval(capsys)
def test_raises_when_api_token_not_set(capsys): ev = core_env_vars() ev.pop("MERKELY_API_TOKEN") with dry_run(ev) as env: with ScopedFileCopier("/app/tests/data/Merkelypipe.json", "/Merkelypipe.json"): with raises(ChangeError): run(External(env=env))
def test_MEREKELY_OWNER_and_MERKELY_PIPE_LINE_are_used_for_all_commands_except_declare_pipeline(): os_env = { "MERKELY_OWNER": "acme", "MERKELY_PIPELINE": "road-runner", } external = External(env=os_env) cls = Command.named('declare_pipeline') json = cls(external).merkelypipe assert json["owner"] == "acme" assert json["name"] == "road-runner"
def test_summary(): env = {"MERKELY_COMMAND": "unused"} external = External(env=env) for klass in Command.all().values(): command = klass(external) if klass.__name__ == 'ControlPullRequest': continue if klass.__name__ == 'LogApproval': continue assert len(command.summary('github')) > 0, klass.__name__
def test_bitbucket(capsys, mocker): # The original bitbucket code did not do a BitBucket translation for create_deployment env = old_log_deployment_env() set_env_vars = {'CDB_ARTIFACT_SHA': SHA256} with dry_run(env, set_env_vars): mocker.patch('cdb.cdb_utils.calculate_sha_digest_for_docker_image', return_value=SHA256) create_deployment("tests/data/Merkelypipe.acme-roadrunner.json") verify_approval(capsys, ["out"]) # extract data from approved cdb text file import inspect this_test = inspect.stack()[0].function approved = f"{APPROVAL_DIR}/{APPROVAL_FILE}.{this_test}.approved.txt" with open(approved) as file: old_approval = file.read() _old_blurb, old_method, old_payload, old_url = extract_blurb_method_payload_url( old_approval) expected_method = "Posting" expected_url = f"https://{DOMAIN}/api/v1/projects/{OWNER}/{PIPELINE}/deployments/" expected_payload = { "artifact_sha256": SHA256, "build_url": f"https://{BB}/{BB_ORG}/{BB_REPO}/addon/pipelines/home#!/results/{BUILD_NUMBER}", "description": DESCRIPTION, "environment": ENVIRONMENT, "user_data": USER_DATA_JSON, } # verify data from approved cdb text file assert old_method == expected_method assert old_url == expected_url assert old_payload == expected_payload # make merkely call ev = new_log_deployment_env() with dry_run(ev) as env: with MockDockerFingerprinter(IMAGE_NAME, SHA256) as fingerprinter: external = External(env=env, docker_fingerprinter=fingerprinter) method, url, payload = run(external) # verify matching data assert method == expected_method assert url == expected_url assert payload == expected_payload assert extract_blurb(capsys_read(capsys)) == [ 'MERKELY_COMMAND=log_deployment', ]
def test_non_zero_status_when_no_data_directory(capsys, mocker): _image_name = "acme/widget:4.67" sha256 = "aecdaef69c676c2466571d3233380d559ccc2032b258fc5e73f99a103db462ef" build_url = "https://gitlab/build/1457" evidence_type = "coverage" env = old_control_junit_env() set_env_vars = {} with dry_run(env, set_env_vars): mocker.patch('cdb.cdb_utils.calculate_sha_digest_for_docker_image', return_value=sha256) control_junit("tests/integration/test-pipefile.json") verify_approval(capsys, ["out"]) # extract data from approved cdb text file import inspect this_test = inspect.stack()[0].function approved = f"{APPROVAL_DIR}/{APPROVAL_FILE}.{this_test}.approved.txt" with open(approved) as file: old_approval = file.read() _old_blurb, old_method, old_payload, old_url = extract_blurb_method_payload_url( old_approval) expected_method = "Putting" expected_url = f"https://{DOMAIN}/api/v1/projects/{OWNER}/{PIPELINE}/artifacts/{sha256}" expected_payload = { "contents": { "description": "JUnit results xml verified by compliancedb/cdb_controls: All tests passed in 0 test suites", "is_compliant": True, "url": build_url }, "evidence_type": evidence_type } # verify data from approved cdb text file assert old_method == expected_method assert old_url == expected_url assert old_payload == expected_payload # new behaviour is to fail with non-zero exit status ev = new_log_test_env() ev.pop('MERKELY_USER_DATA') with dry_run(ev) as env: status = main(External(env=env)) assert status != 0 output = capsys_read(capsys) lines = list(output.split("\n")) assert lines == [ 'MERKELY_COMMAND=log_test', "Error: no directory /data/junit/", '' ]
def test_when_no_approvals_then_raises(mocker): mocked_get = mocker.patch('commands.control_deployment.http_get_json', return_value=[]) ev = new_control_deployment_env() with dry_run(ev) as env: with MockDockerFingerprinter(IMAGE_NAME, SHA256) as fingerprinter: external = External(env=env, docker_fingerprinter=fingerprinter) with raises(ChangeError): run(external) mocked_get.assert_called_once_with( f"https://{DOMAIN}/api/v1/projects/{OWNER}/{PIPELINE}/artifacts/{SHA256}/approvals/", "MY_SUPER_SECRET_API_TOKEN")
def test_MERKELY_OWNER_and_MERKELY_PIPE_override_entries_in_Merkelypipe_even_for_declare_pipeline(): # declare_pipeline requires a Merkelypipe.json file until its contents are # provided on the server. Till then allow env-vars to override the "owner" # and "name" entries so that when anyone is doing the loan-calculator demo # they only need to set the values once in the env-vars for all commands. os_env = { "MERKELY_OWNER": "Acme", "MERKELY_PIPELINE": "road-runner-beep-beep", } external = External(env=os_env) cls = Command.named('declare_pipeline') with ScopedFileCopier('/app/tests/data/Merkelypipe.json', '/data/Merkelypipe.json'): json = cls(external).merkelypipe assert json["owner"] == "Acme" assert json["name"] == "road-runner-beep-beep"
def test_when_approved_then_does_not_raise(mocker): mock_payload = [{"some_random": "stuff"}] mocked_get = mocker.patch('commands.control_deployment.http_get_json', return_value=mock_payload) mocker.patch('commands.control_deployment.control_deployment_approved', return_value=True) ev = new_control_deployment_env() with dry_run(ev) as env: with MockDockerFingerprinter(IMAGE_NAME, SHA256) as fingerprinter: external = External(env=env, docker_fingerprinter=fingerprinter) method, url, payload = run(external) assert mock_payload == payload mocked_get.assert_called_once_with( f"https://{DOMAIN}/api/v1/projects/{OWNER}/{PIPELINE}/artifacts/{SHA256}/approvals/", "MY_SUPER_SECRET_API_TOKEN")
def test_bitbucket(capsys): env = {"CDB_API_TOKEN": API_TOKEN} with dry_run({}): put_pipeline("tests/data/Merkelypipe.acme-roadrunner.json", env) verify_approval(capsys) # extract data from approved cdb text file import inspect this_test = inspect.stack()[0].function approved = f"{APPROVAL_DIR}/{APPROVAL_FILE}.{this_test}.approved.txt" with open(approved) as file: old_approval = file.read() _old_blurb, old_method, old_payload, old_url = extract_blurb_method_payload_url( old_approval) expected_method = "Putting" expected_url = f"https://{DOMAIN}/api/v1/projects/{OWNER}/" expected_payload = { "owner": OWNER, "name": PIPELINE, "description": "Test Pipeline for merkely/change", "template": ["artifact", "unit_test", "coverage"], "visibility": "public" } # verify data from approved cdb text file assert old_method == expected_method assert old_url == expected_url assert old_payload == expected_payload # make merkely call ev = new_declare_pipeline_env() merkelypipe = "Merkelypipe.acme-roadrunner.json" with dry_run(ev) as env, scoped_merkelypipe_json(filename=merkelypipe): method, url, payload = run(External(env=env)) capsys_read(capsys) # verify matching data assert method == expected_method assert url == expected_url assert payload == expected_payload
def test_junit_xml_results_dir_specified_with_env_var(capsys): image_name = "acme/widget:4.67" sha256 = "aecdaef69c676c2466571d3233380d559ccc2032b258fc5e73f99a103db462ef" build_url = "https://gitlab/build/1457" evidence_type = "coverage" expected_method = "Putting" expected_url = f"https://{DOMAIN}/api/v1/projects/{OWNER}/{PIPELINE}/artifacts/{sha256}" expected_payload = { "contents": { "description": "JUnit results xml verified by compliancedb/cdb_controls: All tests passed in 2 test suites", "is_compliant": True, "url": build_url }, "evidence_type": evidence_type } # make merkely call ev = new_log_test_env() ev['MERKELY_TEST_RESULTS_DIR'] = "/app/tests/data/control_junit/xml-with-passed-results" with dry_run(ev) as env: with MockDockerFingerprinter(image_name, sha256) as fingerprinter: external = External(env=env, docker_fingerprinter=fingerprinter) method, url, payload = run(external) capsys_read(capsys) # verify matching data assert method == expected_method assert url == expected_url # image name has changed string = expected_payload['contents']['description'] string = string.replace('compliancedb/cdb_controls', 'merkely/change') expected_payload['contents']['description'] = string # user_data works in new code expected_payload["user_data"] = {'status': 'deployed'} assert payload == expected_payload
def test_raises_when_merkely_command_not_set(capsys): ev = core_env_vars() ev.pop("MERKELY_COMMAND") with dry_run(ev) as env, raises(ChangeError): run(External(env=env))
def test_raises_when_merkely_command_is_unknown(capsys): ev = core_env_vars() ev["MERKELY_COMMAND"] = "wibble" with dry_run(ev) as env, raises(ChangeError): run(External(env=env))
from commands import External, main import sys if __name__ == '__main__': external = External() sys.exit(main(external))
def test_defaults_to_Merkelypipe_dot_json_in_data_dir(): os_env = {} external = External(env=os_env) with ScopedFileCopier('/app/tests/data/Merkelypipe.json', '/data/Merkelypipe.json'): json = external.merkelypipe assert json['owner'] == 'merkely-test'
def test_required_is_true(): env = core_env_vars() command = DeclarePipeline(External(env=env)) assert command.api_token.is_required('bitbucket')
def test_all_env_vars_file(capsys, mocker): """ New: MERKELY_COMMAND=log_evidence MERKELY_FINGERPRINT="file://${FILE_PATH}" docker run ... merkely/change Old: CDB_ARTIFACT_FILENAME=${FILE_PATH} docker run ... cdb.put_artifact ... """ # input data commit = "abc50c8a53f79974d615df335669b59fb56a4444" sha256 = "ccdd89ccdc05772d90dc6929ad4f1fbc14aa105addf3326aa5cf575a104f5115" directory = "app/tests/data" filename = "jam.jar" artifact_name = f"{directory}/{filename}" build_url = "https://gitlab/build/1456" build_number = '23' # make cdb call old_env = old_put_artifact_env(commit) old_env["CDB_ARTIFACT_FILENAME"] = artifact_name set_env_vars = {'CDB_ARTIFACT_SHA': sha256} with dry_run(old_env, set_env_vars): mocker.patch('cdb.cdb_utils.calculate_sha_digest_for_file', return_value=sha256) put_artifact("tests/integration/test-pipefile.json") # compare with approved cdb text file verify_approval(capsys, ["out"]) # extract data from approved cdb text file this_test = "test_all_env_vars_file" approved = f"{APPROVAL_DIR}/{APPROVAL_FILE}.{this_test}.approved.txt" with open(approved) as file: old_approval = file.read() _old_blurb, old_method, old_payload, old_url = extract_blurb_method_payload_url(old_approval) expected_method = "Putting" expected_url = f"https://{DOMAIN}/api/v1/projects/{OWNER}/{PIPELINE}/artifacts/" expected_payload = { 'build_url': build_url, 'commit_url': commit_url(commit), 'description': f'Created by build {build_number}', 'filename': artifact_name, 'git_commit': commit, 'is_compliant': True, 'sha256': sha256, } # verify data from approved cdb text file assert old_method == expected_method assert old_url == expected_url assert old_payload == expected_payload # make merkely call protocol = "file://" ev = new_log_artifact_env(commit) ev["MERKELY_FINGERPRINT"] = f"{protocol}{artifact_name}" with dry_run(ev) as env: with MockFileFingerprinter(artifact_name, sha256) as fingerprinter: external = External(env=env, file_fingerprinter=fingerprinter) method, url, payload = run(external) # verify matching data assert method == expected_method assert url == expected_url # CHANGE IN BEHAVIOUR expected_payload['user_data'] = {} expected_payload['filename'] = filename assert payload == expected_payload assert extract_blurb(capsys_read(capsys)) == [ 'MERKELY_COMMAND=log_artifact', 'MERKELY_IS_COMPLIANT: True', ]
def command_for(name): cls = Command.named(name) env = {"MERKELY_COMMAND": name} external = External(env=env) return cls(external)
def test_env_var_can_override_the_default(): os_env = {"MERKELY_PIPE_PATH": "/app/tests/data/Merkelypipe.acme-roadrunner.json"} external = External(env=os_env) json = external.merkelypipe assert json['owner'] == 'acme'
def test_raises_when_not_found(capsys): with dry_run(core_env_vars()) as env, raises(ChangeError): # no /data/Merkelypipe.json run(External(env=env))
def test_raises_when_is_a_dir(capsys): with dry_run(core_env_vars()) as env: external = External(env=env) with ScopedDirCopier("/app/tests/data", "/data/Merkelypipe.json"): with raises(ChangeError): run(external)
def test_raises_when_invalid_json(capsys): with dry_run(core_env_vars()) as env: external = External(env=env) with ScopedFileCopier("/app/tests/data/Merkelypipe.bad.json", "/Merkelypipe.json"): with raises(ChangeError): run(external)
def test_green(capsys): with dry_run(core_env_vars()) as env, scoped_merkelypipe_json(): run(External(env=env)) verify_approval(capsys)
def test_zero_exit_status_when_there_is_a_data_directory(capsys, mocker): """ The cdb code looks at CDB_USER_DATA but the line to add the json (in cdb_utils.py build_evidence_dict) is this: if user_data is not None: evidence["user_data"]: user_data which should be if user_data is not None: evidence["user_data"] = user_data So that functionality does not exist in the old cdb code. """ image_name = "acme/widget:4.67" sha256 = "aecdaef69c676c2466571d3233380d559ccc2032b258fc5e73f99a103db462ef" build_url = "https://gitlab/build/1457" evidence_type = "coverage" env = old_control_junit_env() set_env_vars = {} with dry_run(env, set_env_vars): with ScopedDirCopier( '/app/tests/data/control_junit/xml-with-passed-results', '/data/junit'): mocker.patch('cdb.cdb_utils.calculate_sha_digest_for_docker_image', return_value=sha256) control_junit("tests/integration/test-pipefile.json") verify_approval(capsys, ["out"]) # extract data from approved cdb text file import inspect this_test = inspect.stack()[0].function approved = f"{APPROVAL_DIR}/{APPROVAL_FILE}.{this_test}.approved.txt" with open(approved) as file: old_approval = file.read() _old_blurb, old_method, old_payload, old_url = extract_blurb_method_payload_url( old_approval) expected_method = "Putting" expected_url = f"https://{DOMAIN}/api/v1/projects/{OWNER}/{PIPELINE}/artifacts/{sha256}" expected_payload = { "contents": { "description": "JUnit results xml verified by compliancedb/cdb_controls: All tests passed in 2 test suites", "is_compliant": True, "url": build_url }, "evidence_type": evidence_type } # verify data from approved cdb text file assert old_method == expected_method assert old_url == expected_url assert old_payload == expected_payload # make merkely call ev = new_log_test_env() with dry_run(ev) as env: with MockDockerFingerprinter(image_name, sha256) as fingerprinter: with ScopedDirCopier( '/app/tests/data/control_junit/xml-with-passed-results', '/data/junit'): external = External(env=env, docker_fingerprinter=fingerprinter) method, url, payload = run(external) capsys_read(capsys) # verify matching data assert method == expected_method assert url == expected_url # image name has changed string = expected_payload['contents']['description'] string = string.replace('compliancedb/cdb_controls', 'merkely/change') expected_payload['contents']['description'] = string # user_data works in new code expected_payload["user_data"] = {'status': 'deployed'} assert payload == expected_payload