<commit_before>from cis_profile import profile
from cis_profile.common import MozillaDataClassification
from cis_profile.common import DisplayLevel

import copy
import cis_profile.exceptions
import pytest
import os
import json
import jsonschema


class TestProfile(object):
    def setup(self):
        os.environ["CIS_CONFIG_INI"] = "tests/fixture/mozilla-cis.ini"

    def test_user_init(self):
        u = profile.User()
        j = u.as_json()
        d = u.as_dict()
        assert j is not None
        assert d is not None
        assert u is not None

    def test_filter_scopes(self):
        u = profile.User()
        # Make sure a value is non-public
        u.user_id.metadata.classification = MozillaDataClassification.MOZILLA_CONFIDENTIAL[0]
        u.staff_information.title.metadata.classification = MozillaDataClassification.MOZILLA_CONFIDENTIAL[0]
        u.filter_scopes(MozillaDataClassification.PUBLIC)
        assert "user_id" not in u.as_dict().keys()
        assert "title" not in u.as_dict()["staff_information"].keys()

    def test_filter_display(self):
        u = profile.User()
        # Make sure a value is non-public
        u.user_id.metadata.display = DisplayLevel.STAFF
        u.staff_information.title.metadata.display = DisplayLevel.NULL
        u.filter_scopes(DisplayLevel.PUBLIC)
        assert "user_id" not in u.as_dict().keys()
        assert "title" not in u.as_dict()["staff_information"].keys()

    def test_profile_override(self):
        u = profile.User(user_id="test")
        assert u.user_id.value == "test"

    def test_profile_update(self):
        u = profile.User()
        old_ts = "1971-09-14T13:41:36.000Z"
        u.user_id.metadata.last_modified = old_ts
        u.user_id.value = "test"
        u.update_timestamp("user_id")
        assert old_ts != u.user_id.metadata.last_modified

    def test_profile_validation(self):
        from cis_profile import profile
        import jsonschema.exceptions

        u = profile.User()
        u.validate()

        u.user_id.value = {"invalid": "test"}
        try:
            u.validate()
            raise Exception("ValidationFailure", "Should have failed validation, did not")
        except jsonschema.exceptions.ValidationError:
            pass
        else:
            raise Exception("ValidationFailure", "Should have failed validation, did not")

    def test_full_profile_signing(self):
        u = profile.User(user_id="test")
        u.access_information.ldap.values = {
            "SecurityWiki": None,
            "communitybuild": None,
            "all_scm_level_1": None,
            "active_scm_level_1": None,
            "all_scm_level_3": None,
            "active_scm_level_3": None,
            "active_scm_nss": None,
            "all_scm_sec_sensitive": None,
            "active_scm_sec_sensitive": None,
            "all_scm_level_2": None,
            "active_scm_level_2": None,
            "all_scm_nss": None,
        }
        u.fun_title.value = "test title"
        for _ in ["ldap", "access_provider", "cis", "hris", "mozilliansorg"]:
            u.sign_all(publisher_name=_, safety=False)
        # assert 2 different publisher attributes are signed properly
        assert u.user_id.signature.publisher.value is not None
        assert len(u.user_id.signature.publisher.value) > 0
        assert u.fun_title.signature.publisher.value is not None
        assert len(u.fun_title.signature.publisher.value) > 0
        assert u.access_information.ldap.signature.publisher.value is not None
        # Empty attributes should not be signed
        assert u.last_name.value is None

    def test_full_profile_signing_wrong_publisher(self):
        u = profile.User()
        u.fun_title.value = "test title"
        u.fun_title.signature.publisher.name = "wrong"
        try:
            u.sign_all(publisher_name="ldap")
        except cis_profile.exceptions.SignatureRefused:
            pass
        else:
            raise Exception("ValidationFailure", "Should have failed validation, did not")

    def test_single_attribute_signing(self):
        u = profile.User(user_id="test")
        u.sign_attribute("user_id", publisher_name="ldap")
        assert u.user_id.signature.publisher.value is not None
        assert len(u.user_id.signature.publisher.value) > 0

        # Empty attributes should be signed in this case since it's directly requested to be signed
        # (empty but not None)
        u.fun_title.value = ""
        u.sign_attribute("fun_title", publisher_name="ldap")
        assert u.fun_title.signature.publisher.value is not None
        assert len(u.fun_title.signature.publisher.value) > 0

        # test for subitems
        u.access_information.ldap.values = {"test": None}
        u.sign_attribute("access_information.ldap", publisher_name="ldap")
        assert u.access_information.ldap.signature.publisher.value is not None
        assert len(u.access_information.ldap.signature.publisher.value) > 0

        # test for NULL values
        try:
            u.active.value = None
            u.sign_attribute("active", publisher_name="ldap")
            raise Exception("ValidationFailure", "Should have failed validation, did not")
        except cis_profile.exceptions.SignatureRefused:
            pass
        else:
            raise Exception("ValidationFailure", "Should have failed validation, did not")

    def test_full_profile_signing_verification(self):
        u = profile.User(user_id="test")
        u.access_information.ldap.values = {"test_group": None, "test_group_2": None}
        for _ in ["ldap", "access_provider", "cis", "hris", "mozilliansorg"]:
            u.sign_all(publisher_name=_, safety=False)
        ret = u.verify_all_signatures()
        assert ret is True

    def test_single_attribute_signing_verification(self):
        u = profile.User(user_id="test")
        u.sign_attribute("user_id", publisher_name="ldap")
        ret = u.verify_attribute_signature("user_id")
        assert ret is not None
        with pytest.raises(cis_profile.exceptions.SignatureVerificationFailure):
            u.verify_attribute_signature("fun_title")  # Unsigned, so should raise and fail

    def test_initialize_uuid_and_primary_username(self):
        u = profile.User(user_id="test")
        u.initialize_uuid_and_primary_username()
        assert u.uuid["value"] is not None
        assert u.uuid["value"] != ""
        assert u.primary_username["value"] is not None
        assert u.primary_username["value"].startswith("r--")

    def test_verify_can_publish(self):
        u_old = profile.User(user_id="test")
        u_new = copy.deepcopy(u_old)

        u_new.first_name["signature"]["publisher"]["name"] = "failure"
        u_new.first_name["value"] = "failure"
        with pytest.raises(cis_profile.exceptions.PublisherVerificationFailure):
            u_new.verify_can_publish(u_new.first_name, "first_name", previous_attribute=u_old.first_name) is True

        assert u_new.verify_can_publish(u_new.user_id, "user_id", previous_attribute=u_old.user_id)

    def test_verify_can_publish_when_merging(self):
        u_orig = profile.User()
        u_orig.access_information.ldap.values = {"test": None}
        u_orig.uuid.value = "31337"
        u_orig.active.value = True

        u_patch = profile.User()
        u_patch.access_information.ldap.values = {"test_replacement": None}
        u_orig.merge(u_patch)

        u_orig.verify_all_publishers(u_patch)

    def test_verify_all_publishers(self):
        u = profile.User(user_id="test")
        u.verify_all_publishers(u)

        old_user = profile.User()
        old_user.active.value = True
        with pytest.raises(cis_profile.exceptions.PublisherVerificationFailure):
            u.verify_all_publishers(old_user)

    def test_verify_can_publish_login_method(self):<commit_msg>better merge + sign test<commit_after>from cis_profile import profile
from cis_profile.common import MozillaDataClassification
from cis_profile.common import DisplayLevel

import copy
import cis_profile.exceptions
import pytest
import os
import json
import jsonschema


class TestProfile(object):
    def setup(self):
        os.environ["CIS_CONFIG_INI"] = "tests/fixture/mozilla-cis.ini"

    def test_user_init(self):
        u = profile.User()
        j = u.as_json()
        d = u.as_dict()
        assert j is not None
        assert d is not None
        assert u is not None

    def test_filter_scopes(self):
        u = profile.User()
        # Make sure a value is non-public
        u.user_id.metadata.classification = MozillaDataClassification.MOZILLA_CONFIDENTIAL[0]
        u.staff_information.title.metadata.classification = MozillaDataClassification.MOZILLA_CONFIDENTIAL[0]
        u.filter_scopes(MozillaDataClassification.PUBLIC)
        assert "user_id" not in u.as_dict().keys()
        assert "title" not in u.as_dict()["staff_information"].keys()

    def test_filter_display(self):
        u = profile.User()
        # Make sure a value is non-public
        u.user_id.metadata.display = DisplayLevel.STAFF
        u.staff_information.title.metadata.display = DisplayLevel.NULL
        u.filter_scopes(DisplayLevel.PUBLIC)
        assert "user_id" not in u.as_dict().keys()
        assert "title" not in u.as_dict()["staff_information"].keys()

    def test_profile_override(self):
        u = profile.User(user_id="test")
        assert u.user_id.value == "test"

    def test_profile_update(self):
        u = profile.User()
        old_ts = "1971-09-14T13:41:36.000Z"
        u.user_id.metadata.last_modified = old_ts
        u.user_id.value = "test"
        u.update_timestamp("user_id")
        assert old_ts != u.user_id.metadata.last_modified

    def test_profile_validation(self):
        from cis_profile import profile
        import jsonschema.exceptions

        u = profile.User()
        u.validate()

        u.user_id.value = {"invalid": "test"}
        try:
            u.validate()
            raise Exception("ValidationFailure", "Should have failed validation, did not")
        except jsonschema.exceptions.ValidationError:
            pass
        else:
            raise Exception("ValidationFailure", "Should have failed validation, did not")

    def test_full_profile_signing(self):
        u = profile.User(user_id="test")
        u.access_information.ldap.values = {
            "SecurityWiki": None,
            "communitybuild": None,
            "all_scm_level_1": None,
            "active_scm_level_1": None,
            "all_scm_level_3": None,
            "active_scm_level_3": None,
            "active_scm_nss": None,
            "all_scm_sec_sensitive": None,
            "active_scm_sec_sensitive": None,
            "all_scm_level_2": None,
            "active_scm_level_2": None,
            "all_scm_nss": None,
        }
        u.fun_title.value = "test title"
        for _ in ["ldap", "access_provider", "cis", "hris", "mozilliansorg"]:
            u.sign_all(publisher_name=_, safety=False)
        # assert 2 different publisher attributes are signed properly
        assert u.user_id.signature.publisher.value is not None
        assert len(u.user_id.signature.publisher.value) > 0
        assert u.fun_title.signature.publisher.value is not None
        assert len(u.fun_title.signature.publisher.value) > 0
        assert u.access_information.ldap.signature.publisher.value is not None
        # Empty attributes should not be signed
        assert u.last_name.value is None

    def test_full_profile_signing_wrong_publisher(self):
        u = profile.User()
        u.fun_title.value = "test title"
        u.fun_title.signature.publisher.name = "wrong"
        try:
            u.sign_all(publisher_name="ldap")
        except cis_profile.exceptions.SignatureRefused:
            pass
        else:
            raise Exception("ValidationFailure", "Should have failed validation, did not")

    def test_single_attribute_signing(self):
        u = profile.User(user_id="test")
        u.sign_attribute("user_id", publisher_name="ldap")
        assert u.user_id.signature.publisher.value is not None
        assert len(u.user_id.signature.publisher.value) > 0

        # Empty attributes should be signed in this case since it's directly requested to be signed
        # (empty but not None)
        u.fun_title.value = ""
        u.sign_attribute("fun_title", publisher_name="ldap")
        assert u.fun_title.signature.publisher.value is not None
        assert len(u.fun_title.signature.publisher.value) > 0

        # test for subitems
        u.access_information.ldap.values = {"test": None}
        u.sign_attribute("access_information.ldap", publisher_name="ldap")
        assert u.access_information.ldap.signature.publisher.value is not None
        assert len(u.access_information.ldap.signature.publisher.value) > 0

        # test for NULL values
        try:
            u.active.value = None
            u.sign_attribute("active", publisher_name="ldap")
            raise Exception("ValidationFailure", "Should have failed validation, did not")
        except cis_profile.exceptions.SignatureRefused:
            pass
        else:
            raise Exception("ValidationFailure", "Should have failed validation, did not")

    def test_full_profile_signing_verification(self):
        u = profile.User(user_id="test")
        u.access_information.ldap.values = {"test_group": None, "test_group_2": None}
        for _ in ["ldap", "access_provider", "cis", "hris", "mozilliansorg"]:
            u.sign_all(publisher_name=_, safety=False)
        ret = u.verify_all_signatures()
        assert ret is True

    def test_single_attribute_signing_verification(self):
        u = profile.User(user_id="test")
        u.sign_attribute("user_id", publisher_name="ldap")
        ret = u.verify_attribute_signature("user_id")
        assert ret is not None
        with pytest.raises(cis_profile.exceptions.SignatureVerificationFailure):
            u.verify_attribute_signature("fun_title")  # Unsigned, so should raise and fail

    def test_initialize_uuid_and_primary_username(self):
        u = profile.User(user_id="test")
        u.initialize_uuid_and_primary_username()
        assert u.uuid["value"] is not None
        assert u.uuid["value"] != ""
        assert u.primary_username["value"] is not None
        assert u.primary_username["value"].startswith("r--")

    def test_verify_can_publish(self):
        u_old = profile.User(user_id="test")
        u_new = copy.deepcopy(u_old)

        u_new.first_name["signature"]["publisher"]["name"] = "failure"
        u_new.first_name["value"] = "failure"
        with pytest.raises(cis_profile.exceptions.PublisherVerificationFailure):
            u_new.verify_can_publish(u_new.first_name, "first_name", previous_attribute=u_old.first_name) is True

        assert u_new.verify_can_publish(u_new.user_id, "user_id", previous_attribute=u_old.user_id)

    def test_verify_can_publish_when_merging(self):
        u_orig = profile.User()
        u_orig.access_information.ldap.values = {"test": None}
        u_orig.uuid.value = "31337"
        u_orig.active.value = None
        for _ in ["ldap", "access_provider", "cis", "hris", "mozilliansorg"]:
            u_orig.sign_all(publisher_name=_, safety=False)
        u_patch = profile.User()
        u_patch.access_information.ldap.values = {"test_replacement": None}
        u_orig.merge(u_patch)

        u_orig.verify_all_publishers(u_patch)
        assert u_orig.active.value is None

    def test_verify_all_publishers(self):
        u = profile.User(user_id="test")
        u.verify_all_publishers(u)

        old_user = profile.User()
        old_user.active.value = True
        with pytest.raises(cis_profile.exceptions.PublisherVerificationFailure):
            u.verify_all_publishers(old_user)

    def test_verify_can_publish_login_method(self):
{'fraction_non_alphanumeric': 0.10032057326041863, 'fraction_numerical': 0.004651455151172292, 'mean_word_length': 2.7944192702122583, 'pattern_counts': {'":': 36, '<': 3, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2552074', 'n_tokens_mistral': 4896, 'n_tokens_neox': 4758, 'n_words': 955}