示例#1
0
def test_normalize_policies_1():
    policies = EntitiesSet({
        EntityWrapper(
            policy(
                name='policy-1',
                entitlements=['entitlement1', 'entitlement2',
                              'entitlement3'])),
        EntityWrapper(
            policy(name='policy-2',
                   entitlements=[
                       'entitlement1',
                       'entitlement2',
                       'entitlement3',
                   ])),
    })
    entitlements = EntitiesSet()
    policies_set, conflicts = resolve_entities(
        policies, [(entitlements, 'entitlements')])
    assert conflicts == {
        'policy-1': {
            'entitlements':
            frozenset({'entitlement1', 'entitlement2', 'entitlement3'})
        },
        'policy-2': {
            'entitlements':
            frozenset({'entitlement1', 'entitlement2', 'entitlement3'})
        }
    }
示例#2
0
def test_normalize_entitlements_1():
    entitlements = EntitiesSet({
        EntityWrapper(
            entitlement(name='entitlement-1',
                        conditions=['condition1', 'condition2',
                                    'condition3'])),
        EntityWrapper(
            entitlement(name='entitlement-2',
                        conditions=[
                            'condition1',
                            'condition2',
                            'condition3',
                        ])),
    })
    conditions = EntitiesSet()
    entitlements_set, conflicts = resolve_entities(
        entitlements, [(conditions, 'conditions')])
    assert entitlements_set.entities == entitlements.entities
    assert conflicts == {
        'entitlement-1': {
            'conditions': frozenset({'condition1', 'condition2', 'condition3'})
        },
        'entitlement-2': {
            'conditions': frozenset({'condition1', 'condition2', 'condition3'})
        },
    }
示例#3
0
def test_compare_entity_with_secrets_with_metadata_4():
    EntityTest2 = load_test_open_api_spec(
        reload=True,
        k8s_get_secret=_k8s_get_secret).entities['EntityTest2'].cls
    data_1 = {
        'fieldOne': {
            'type': 'k8s/secret',
            'name': 'secret-storage-1',
            'key': 'field-one'
        },
        'fieldTwo': 'this is write only',
        'fieldThree': 'this is a field',
    }
    data_2 = {
        'fieldOne': {
            'type': 'k8s/secret',
            'name': 'secret-storage-1',
            'key': 'field-one'
        },
        'fieldTwo': 'this is write only',
        'fieldThree': 'this is a field',
        'created': '2020-09-10T12:20:14Z',
        'updated': '2020-09-20T12:20:14Z'
    }
    appgate_metadata = {
        'generation': 2,
        'latestGeneration': 3,
        'creationTimestamp': '2020-09-10T10:20:14Z',
        'modificationTimestamp': '2020-09-20T12:19:14Z',
    }
    e1 = EntityWrapper(K8S_LOADER.load(data_1, appgate_metadata, EntityTest2))
    e2 = EntityWrapper(APPGATE_LOADER.load(data_2, None, EntityTest2))
    assert e1 == e2
示例#4
0
def test_dependencies_3():
    """
    several dependencies (even nested)
    See EntityDep5 for details
    """
    api = load_test_open_api_spec()
    EntityDep1 = api.entities['EntityDep1'].cls
    EntityDep5 = api.entities['EntityDep5'].cls
    EntityDep5_Obj1 = api.entities['EntityDep5_Obj1'].cls
    EntityDep5_Obj1_Obj2 = api.entities['EntityDep5_Obj1_Obj2'].cls
    deps1 = EntitiesSet({
        EntityWrapper(EntityDep1(id='d11', name='dep11')),
        EntityWrapper(EntityDep1(id='d12', name='dep12')),
        EntityWrapper(EntityDep1(id='d13', name='dep13')),
    })
    data = {'id': 'd51', 'name': 'dep51', 'obj1': {'obj2': {'dep1': 'dep11'}}}
    deps5 = EntitiesSet(
        {EntityWrapper(K8S_LOADER.load(data, None, EntityDep5))})
    deps5_resolved, conflicts = resolve_entities(deps5,
                                                 [(deps1, 'obj1.obj2.dep1')])
    assert conflicts is None
    assert deps5_resolved.entities == {
        EntityWrapper(
            EntityDep5(
                id='d51',
                name='dep51',
                obj1=EntityDep5_Obj1(obj2=EntityDep5_Obj1_Obj2(dep1='d11'))))
    }
示例#5
0
def test_compare_entity_with_secrets():
    """
    If we are missing metadata frm k8s we should always update the entity
    """
    EntityTest2 = load_test_open_api_spec(
        reload=True,
        k8s_get_secret=_k8s_get_secret).entities['EntityTest2'].cls
    data_1 = {
        'fieldOne': {
            'type': 'k8s/secret',
            'name': 'secret-storage-1',
            'key': 'field-one'
        },
        'fieldTwo': 'this is write only',
        'fieldThree': 'this is a field',
    }
    data_2 = {
        'fieldOne': {
            'type': 'k8s/secret',
            'name': 'secret-storage-1',
            'key': 'field-one'
        },
        'fieldTwo': 'this is write only',
        'fieldThree': 'this is a field',
        'created': '2020-09-10T12:20:14Z',
        'updated': '2020-09-10T12:20:14Z'
    }
    e1 = EntityWrapper(K8S_LOADER.load(data_1, None, EntityTest2))
    e2 = EntityWrapper(APPGATE_LOADER.load(data_2, None, EntityTest2))
    assert e1 != e2
示例#6
0
def test_compare_plan_entity_pem():
    EntityCert = load_test_open_api_spec(
        secrets_key=None, reload=True).entities['EntityCert'].cls
    appgate_data = {
        'name': 'c1',
        'fieldOne': PEM_TEST,
        'fieldTwo': {
            'version': 1,
            'serial': '3578',
            'issuer': join_string(ISSUER),
            'subject': join_string(SUBJECT),
            'validFrom': '2012-08-22T05:26:54.000Z',
            'validTo': '2017-08-21T05:26:54.000Z',
            'fingerprint': 'Xw+1FmWBquZKEBwVg7G+vnToFKkeeooUuh6DXXj26ec=',
            'certificate': join_string(CERTIFICATE_FIELD),
            'subjectPublicKey': join_string(PUBKEY_FIELD),
        }
    }
    k8s_data = {'name': 'c1', 'fieldOne': PEM2}
    current_entities = EntitiesSet(
        {EntityWrapper(APPGATE_LOADER.load(appgate_data, None, EntityCert))})
    new_e = K8S_LOADER.load(k8s_data, None, EntityCert)
    expected_entities = EntitiesSet({EntityWrapper(new_e)})
    plan = compare_entities(current_entities, expected_entities, BUILTIN_TAGS)
    assert plan.modify.entities == frozenset({EntityWrapper(new_e)})
    assert plan.modifications_diff == {
        'c1': [
            '--- \n', '+++ \n', '@@ -3,10 +3,10 @@\n', '     "fieldTwo": {\n',
            '-        "version": 1,\n', '-        "serial": "3578",\n',
            '+        "version": 3,\n', '+        "serial": "0",\n',
            '         "issuer": "[email protected], CN=Frank4DD Web CA, OU=WebCert Support, O=Frank4DD, L=Chuo-ku, ST=Tokyo, C=JP",\n',
            '         "subject": "CN=www.example.com, O=Frank4DD, ST=Tokyo, C=JP",\n',
            '-        "validFrom": "2012-08-22T05:26:54.000Z",\n',
            '-        "validTo": "2017-08-21T05:26:54.000Z",\n',
            '-        "fingerprint": "Xw+1FmWBquZKEBwVg7G+vnToFKkeeooUuh6DXXj26ec=",\n',
            '-        "certificate": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNFakNDQVhzQ0FnMzZNQTBHQ1NxR1NJYjNEUUVCQlFVQU1JR2JNUXN3Q1FZRFZRUUdF'
            'd0pLVURFT01Bd0cKQTFVRUNCTUZWRzlyZVc4eEVEQU9CZ05WQkFjVEIwTm9kVzh0YTNVeEVUQVBCZ05WQkFvVENFWnlZVzVyTkVSRQpNUmd3RmdZRFZRUUxFdzlYWldKRFpYS'
            'jBJRk4xY0hCdmNuUXhHREFXQmdOVkJBTVREMFp5WVc1ck5FUkVJRmRsCllpQkRRVEVqTUNFR0NTcUdTSWIzRFFFSkFSWVVjM1Z3Y0c5eWRFQm1jbUZ1YXpSa1pDNWpiMjB3SG'
            'hjTk1USXcKT0RJeU1EVXlOalUwV2hjTk1UY3dPREl4TURVeU5qVTBXakJLTVFzd0NRWURWUVFHRXdKS1VERU9NQXdHQTFVRQpDQXdGVkc5cmVXOHhFVEFQQmdOVkJBb01DRVp'
            '5WVc1ck5FUkVNUmd3RmdZRFZRUUREQTkzZDNjdVpYaGhiWEJzClpTNWpiMjB3WERBTkJna3Foa2lHOXcwQkFRRUZBQU5MQURCSUFrRUFtL3hta0htRVFydXJFLzByZS9qZUZS'
            'TGwKOFpQakJvcDd1TEhobmlhN2xRRy81ekR0WklVQzNSVnBxRFN3QnV3L05Ud2VHeXVQK284QUc5OEh4cXhUQndJRApBUUFCTUEwR0NTcUdTSWIzRFFFQkJRVUFBNEdCQUJTM'
            'lRMdUJlVFBtY2FUYVVXL0xDQjJOWU95OEdNZHpSMW14CjhpQkl1Mkg2L0UydGlZM1JJZXZWMk9XNjFxWTIvWFJRZzdZUHh4M2ZmZVV1Z1g5RjRKL2lQbm51MXpBeHh5QnkKMl'
            'ZndUt2NFNXalJGb1JrSWZJbEhYMHFWdmlNaFNsTnkyaW9GTHk3SmNQWmIrdjNmdERHeXdVcWNCaVZEb2VhMApIbitHbXhaQQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==",\n',
            '+        "validFrom": "1901-12-13T20:45:52.000Z",\n',
            '+        "validTo": "2038-01-19T03:14:07.000Z",\n',
            '+        "fingerprint": "6b7fb51b56acaf0a8f9b9a3f8ca6737cb97821ddb830106c9fc9a14b8bfdfa36",\n',
            '+        "certificate": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNHakNDQVlPZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRVUZBRENCbXpFTE1Ba0dB'
            'MVVFQmhNQ1NsQXgKRGpBTUJnTlZCQWdUQlZSdmEzbHZNUkF3RGdZRFZRUUhFd2REYUhWdkxXdDFNUkV3RHdZRFZRUUtFd2hHY21GdQphelJFUkRFWU1CWUdBMVVFQ3hNUFYyV'
            'mlRMlZ5ZENCVGRYQndiM0owTVJnd0ZnWURWUVFERXc5R2NtRnVhelJFClJDQlhaV0lnUTBFeEl6QWhCZ2txaGtpRzl3MEJDUUVXRkhOMWNIQnZjblJBWm5KaGJtczBaR1F1WT'
            'I5dE1DSVkKRHpFNU1ERXhNakV6TWpBME5UVXlXaGdQTWpBek9EQXhNVGt3TXpFME1EZGFNRW94Q3pBSkJnTlZCQVlUQWtwUQpNUTR3REFZRFZRUUlEQVZVYjJ0NWJ6RVJNQTh'
            'HQTFVRUNnd0lSbkpoYm1zMFJFUXhHREFXQmdOVkJBTU1EM2QzCmR5NWxlR0Z0Y0d4bExtTnZiVEJjTUEwR0NTcUdTSWIzRFFFQkFRVUFBMHNBTUVnQ1FRQ2IvR2FRZVlSQ3U2'
            'c1QKL1N0NytONFZFdVh4aytNR2ludTRzZUdlSnJ1VkFiL25NTzFraFFMZEZXbW9OTEFHN0Q4MVBCNGJLNC82andBYgozd2ZHckZNSEFnTUJBQUV3RFFZSktvWklodmNOQVFFR'
            'kJRQURnWUVBbnpkZVFCRzJjclhudlp5SGdDTDlkU25tCmxuYVhKSVRPLy8rRzU5dUN2REtiblgrQkt2WFh4WFFJYTdHbXR6WXV3M0xDL2pKSkwzMDdyL0NFQ1pyNnZWOUkKS0'
            'huMjcreU90clBET3dURHRYeWFZT2FmOFY2ZmtTVk4zaUx4N3RiRVA2UjB1RUt4YVZhcU1aNzFlZDNTTzFPTAp3cTBqOEdrS1kvSy96bDJOd3pjPQotLS0tLUVORCBDRVJUSUZ'
            'JQ0FURS0tLS0tCg==",\n',
            '         "subjectPublicKey": "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJv8ZpB5hEK7qxP9K3v43hUS5'
            'fGT4waKe7ix4Z4mu5UBv+cw7WSFAt0Vaag0sAbsPzU8Hhsrj/qPABvfB8asUwcCAwEAAQ=="\n'
        ]
    }
示例#7
0
def test_compare_plan_entity_bytes():
    EntityTest3Appgate = load_test_open_api_spec(
        secrets_key=None, reload=True).entities['EntityTest3Appgate'].cls
    # fieldOne is writeOnly :: byte
    # fieldTwo is readOnly :: checksum of fieldOne
    # fieldThree is readOnly :: size of fieldOne
    e_data = {
        'id':
        '6a01c585-c192-475b-b86f-0e632ada6769',  # Current data always has ids
        'name': 'entity1',
        'fieldOne': None,
        'fieldTwo': SHA256_FILE,
        'fieldThree': 1563,
    }
    entities_current = EntitiesSet(
        {EntityWrapper(APPGATE_LOADER.load(e_data, None, EntityTest3Appgate))})
    e_data = {
        'name': 'entity1',
        'fieldOne': BASE64_FILE_W0,
        'fieldTwo': None,
        'fieldThree': None,
    }
    e_metadata = {'uuid': '6a01c585-c192-475b-b86f-0e632ada6769'}
    entities_expected = EntitiesSet({
        EntityWrapper(K8S_LOADER.load(e_data, e_metadata, EntityTest3Appgate))
    })
    plan = compare_entities(entities_current, entities_expected, BUILTIN_TAGS)
    assert plan.modify.entities == frozenset()
    assert plan.modifications_diff == {}

    assert compute_diff(
        list(entities_current.entities)[0],
        list(entities_expected.entities)[0]) == []

    # Let's change the bytes
    e_data = {
        'name': 'entity1',
        'fieldOne': 'Some other content',
        'fieldTwo': None,
        'fieldThree': None,
    }
    new_e = K8S_LOADER.load(e_data, e_metadata, EntityTest3Appgate)

    entities_expected = EntitiesSet({EntityWrapper(new_e)})
    plan = compare_entities(entities_current, entities_expected, BUILTIN_TAGS)
    assert plan.modify.entities == frozenset({EntityWrapper(new_e)})
    assert plan.modifications_diff == {
        'entity1': [
            '--- \n', '+++ \n', '@@ -2,4 +2,4 @@\n',
            '     "name": "entity1",\n',
            '-    "fieldTwo": "0d373afdccb82399b29ba0d6d1a282b4d10d7e70d948257e75c05999f0be9f3e",\n',
            '-    "fieldThree": 1563\n',
            '+    "fieldTwo": "c8f4fc85b689f8f3a70e7024e2bb8c7c8f4f7f9ffd2a1a8d01fc8fba74d1af34",\n',
            '+    "fieldThree": 12\n', ' }'
        ]
    }
示例#8
0
def test_normalize_entitlements_2():
    entitlements = EntitiesSet({
        EntityWrapper(
            entitlement(name='entitlement-1',
                        conditions=['condition1', 'condition2',
                                    'condition3'])),
        EntityWrapper(
            entitlement(name='entitlement-2',
                        conditions=[
                            'condition1',
                            'condition4',
                            'condition5',
                        ])),
    })
    conditions = EntitiesSet({
        EntityWrapper(condition(id='c1', name='condition1')),
        EntityWrapper(condition(id='c2', name='condition2')),
        EntityWrapper(condition(id='c3', name='condition3')),
        EntityWrapper(condition(id='c4', name='condition4')),
        EntityWrapper(condition(id='c5', name='condition5')),
    })
    entitlements_set, conflicts = resolve_entities(
        entitlements, [(conditions, 'conditions')])
    assert entitlements_set.entities == {
        EntityWrapper(
            entitlement(name='entitlement-1', conditions=['c1', 'c2', 'c3'])),
        EntityWrapper(
            entitlement(name='entitlement-2', conditions=[
                'c1',
                'c4',
                'c5',
            ])),
    }
    assert conflicts is None
示例#9
0
def test_compare_policies_2():
    current_policies = EntitiesSet({
        EntityWrapper(
            Policy(id='id1', name='policy1', expression='expression-1')),
        EntityWrapper(
            Policy(id='id2', name='policy2', expression='expression-2')),
        EntityWrapper(
            Policy(id='id3', name='policy3', expression='expression-3'))
    })
    expected_policies = EntitiesSet({
        EntityWrapper(
            Policy(id='id1', name='policy1', expression='expression-1')),
        EntityWrapper(
            Policy(id='id2', name='policy2', expression='expression-2')),
        EntityWrapper(
            Policy(id='id3', name='policy3', expression='expression-3'))
    })
    plan = compare_entities(current_policies, expected_policies, BUILTIN_TAGS)
    assert plan.modify.entities == set()
    assert plan.delete.entities == set()
    assert plan.create.entities == set()
    assert plan.share.entities == {
        EntityWrapper(
            Policy(id='id1', name='policy1', expression='expression-1')),
        EntityWrapper(
            Policy(id='id2', name='policy2', expression='expression-2')),
        EntityWrapper(
            Policy(id='id3', name='policy3', expression='expression-3'))
    }
    share_ids = [p.id for p in plan.share.entities]
    assert len(list(filter(None, share_ids))) == 3
    share_ids.sort()
    assert share_ids == ['id1', 'id2', 'id3']
示例#10
0
def test_normalize_policies_2():
    policies = EntitiesSet({
        EntityWrapper(
            policy(
                name='policy-1',
                entitlements=['entitlement1', 'entitlement2',
                              'entitlement3'])),
        EntityWrapper(
            policy(name='policy-2',
                   entitlements=[
                       'entitlement1',
                       'entitlement4',
                       'entitlement5',
                   ])),
    })
    entitlements = EntitiesSet({
        EntityWrapper(entitlement(id='e1', name='entitlement1')),
        EntityWrapper(entitlement(id='e2', name='entitlement2')),
        EntityWrapper(entitlement(id='e3', name='entitlement3')),
        EntityWrapper(entitlement(id='e4', name='entitlement4')),
        EntityWrapper(entitlement(id='e5', name='entitlement5')),
    })
    policies_set, conflicts = resolve_entities(
        policies, [(entitlements, 'entitlements')])
    assert conflicts is None
    assert policies_set.entities == {
        EntityWrapper(policy(name='policy-1', entitlements=['e1', 'e2',
                                                            'e3'])),
        EntityWrapper(
            policy(name='policy-2', entitlements=[
                'e1',
                'e4',
                'e5',
            ])),
    }
示例#11
0
def test_dependencies_2():
    """
    Two dependencies
    EntityDep4 has an array field (deps1) with deps from EntityDep1
    EntityDep4 has a string field (dep2) with deps from EntityDep2
    """
    api = load_test_open_api_spec()
    EntityDep1 = api.entities['EntityDep1'].cls
    EntityDep2 = api.entities['EntityDep2'].cls
    EntityDep4 = api.entities['EntityDep4'].cls
    deps1 = EntitiesSet({
        EntityWrapper(EntityDep1(id='d11', name='dep11')),
        EntityWrapper(EntityDep1(id='d12', name='dep12')),
        EntityWrapper(EntityDep1(id='d13', name='dep13')),
    })
    deps2 = EntitiesSet({
        EntityWrapper(EntityDep2(id='d21', name='dep21')),
        EntityWrapper(EntityDep2(id='d22', name='dep22')),
        EntityWrapper(EntityDep2(id='d23', name='dep23')),
    })

    # no conflicts
    deps4 = EntitiesSet({
        EntityWrapper(
            EntityDep4(id='d31',
                       name='dep31',
                       deps1=frozenset({'dep11', 'dep12'}),
                       dep2='dep23'))
    })
    deps3_resolved, conflicts = resolve_entities(deps4, [(deps1, 'deps1'),
                                                         (deps2, 'dep2')])
    assert conflicts is None
    assert deps3_resolved.entities == {
        EntityWrapper(
            EntityDep4(id='d31',
                       name='dep31',
                       deps1=frozenset({'d11', 'd12'}),
                       dep2='d23'))
    }

    # conflicts in field deps1
    deps4 = EntitiesSet({
        EntityWrapper(
            EntityDep4(id='d31',
                       name='dep31',
                       deps1=frozenset({'dep14', 'dep12'}),
                       dep2='dep33'))
    })
    deps3_resolved, conflicts = resolve_entities(deps4, [(deps1, 'deps1'),
                                                         (deps2, 'dep2')])
    assert conflicts == {
        'dep31': {
            'deps1': frozenset({'dep14'}),
            'dep2': frozenset({'dep33'})
        }
    }
示例#12
0
def resolve_entity(entity: Entity_T,
                   field: str,
                   names: Dict[str, EntityWrapper],
                   ids: Dict[str, EntityWrapper],
                   missing_dependencies: Dict[str, Dict[str, FrozenSet[str]]],
                   reverse: bool = False) -> Optional[EntityWrapper]:
    new_dependencies = set()
    missing_dependencies_set = set()
    log.debug(f'Getting field %s in entity %s', field,
              entity.__class__.__name__)
    dependencies, rest_fields = get_field(entity, field.split('.'))
    if dependencies is None:
        raise Exception(f'Object {entity} has not field {field}.')
    is_iterable = isinstance(dependencies, frozenset)
    if not is_iterable:
        dependencies = frozenset({dependencies})
    for dependency in dependencies:
        if type(dependency) not in PYTHON_TYPES and rest_fields:
            log.debug('dependency %s and rest_fields %s', dependency,
                      rest_fields)
            resolve_entity(dependency, rest_fields, names, ids,
                           missing_dependencies, reverse)
        elif dependency in ids:
            # dependency is an id
            if reverse:
                new_dependencies.add(ids[dependency].name)
            else:
                new_dependencies.add(dependency)
        elif dependency in names and names[dependency].id:
            # dependency is a name
            if reverse:
                new_dependencies.add(dependency)
            else:
                new_dependencies.add(names[dependency].id)
        else:
            missing_dependencies_set.add(dependency)
    if missing_dependencies_set:
        if entity.name not in missing_dependencies:
            missing_dependencies[entity.name] = {}
        missing_dependencies[entity.name][field] = frozenset(
            missing_dependencies_set)
    if new_dependencies:
        if is_iterable:
            return EntityWrapper(
                evolve_rec(entity, field.split('.'),
                           frozenset(new_dependencies)))
        else:
            return EntityWrapper(
                evolve_rec(entity, field.split('.'),
                           list(new_dependencies)[0]))
    return None
示例#13
0
def test_compare_policies_3():
    current_policies = EntitiesSet({
        EntityWrapper(
            Policy(id='id1', name='policy3', expression='expression-1')),
        EntityWrapper(
            Policy(id='id2', name='policy2', expression='expression-2')),
        EntityWrapper(
            Policy(id='id3', name='policy4', expression='expression-3'))
    })
    expected_policies = EntitiesSet({
        EntityWrapper(Policy(name='policy1', expression='expression-1')),
        EntityWrapper(
            Policy(id='id2', name='policy2', expression='expression-2')),
        EntityWrapper(
            Policy(id='id3', name='policy4', expression='expression-3'))
    })
    plan = compare_entities(current_policies, expected_policies, BUILTIN_TAGS)
    assert plan.delete.entities == {
        EntityWrapper(
            Policy(id='id1', name='policy3', expression='expression-1'))
    }
    # test that the ids are propagated when modifying
    assert [p.id for p in plan.delete.entities] == ['id1']
    assert plan.create.entities == {
        EntityWrapper(Policy(name='policy1', expression='expression-1'))
    }
    assert plan.modify.entities == set()
示例#14
0
def test_normalize_entitlements_3():
    entitlements = EntitiesSet({
        EntityWrapper(
            entitlement(name='entitlement-1',
                        conditions=['condition1', 'condition2',
                                    'condition3'])),
        EntityWrapper(
            entitlement(name='entitlement-2',
                        conditions=[
                            'condition1',
                            'condition4',
                            'condition5',
                        ])),
    })
    conditions = EntitiesSet({
        EntityWrapper(condition(id='id1', name='condition1')),
        EntityWrapper(condition(id='id2', name='condition2')),
        EntityWrapper(condition(id='id3', name='condition3')),
        EntityWrapper(condition(name='condition4')),
        EntityWrapper(condition(name='condition5')),
    })
    entitlements_set, conflicts = resolve_entities(
        entitlements, [(conditions, 'conditions')])
    assert conflicts == {
        'entitlement-2': {
            'conditions': frozenset({'condition4', 'condition5'}),
        }
    }
示例#15
0
 def modify(self, entity: EntityWrapper) -> None:
     if entity.name not in self.entities_by_name:
         # Not yet in the system, register it with its own id
         return self.add(entity)
     # All the entities expect the one being modified
     self.entities = {e for e in self.entities if e.name != entity.name}
     # Replace always the id with the one registered in the system
     self.entities.add(
         entity.with_id(id=self.entities_by_name[entity.name].id))
示例#16
0
def entity_sync_generation(entity_wrapper: EntityWrapper) -> EntityWrapper:
    """
    Syncs current generation to latest.
    """
    entity = entity_wrapper.value
    appgate_metadata = evolve(
        entity.appgate_metadata,
        latest_generation=entity.appgate_metadata.current_generation)
    return EntityWrapper(evolve(entity, appgate_metadata=appgate_metadata))
示例#17
0
def exclude_appgate_entities(entities: List[Entity_T], target_tags: Optional[FrozenSet[str]],
                             exclude_tags: Optional[FrozenSet[str]]) -> Set[EntityWrapper]:
    """
    Filter out entities according to target_tags and exclude_rags
    Returns the entities that are member of target_tags (all entities if None)
    but not member of exclude_tags
    """
    return set(filter(lambda e: is_target(e, target_tags) and not has_tag(e, exclude_tags),
                      [EntityWrapper(e) for e in entities]))
示例#18
0
def test_compare_entities_updated_changed():
    EntityTest2 = load_test_open_api_spec(
        reload=True,
        k8s_get_secret=_k8s_get_secret).entities['EntityTest2'].cls
    data_1 = {
        'fieldOne': {
            'type': 'k8s/secret',
            'name': 'secret-storage-1',
            'key': 'field-one'
        },
        'fieldTwo': 'this is write only',
        'fieldThree': 'this is a field',
    }
    data_2 = {
        'fieldOne': {
            'type': 'k8s/secret',
            'name': 'secret-storage-1',
            'key': 'field-one'
        },
        'fieldTwo': 'this is write only',
        'fieldThree': 'this is a field',
        'created': '2020-09-10T12:20:14Z',
        'updated': '2020-09-10T12:20:14Z'
    }
    appgate_metadata = {
        'generation': 1,
        'latestGeneration': 1,
        'creationTimestamp': '2020-09-10T10:20:14Z',
        'modificationTimestamp': '2020-09-16T12:20:14Z',
    }
    e1 = EntityWrapper(K8S_LOADER.load(data_1, appgate_metadata, EntityTest2))
    e2 = EntityWrapper(APPGATE_LOADER.load(data_2, None, EntityTest2))

    diff = compute_diff(e2, e1)
    assert diff == [
        '--- \n', '+++ \n', '@@ -2,3 +2,3 @@\n',
        '     "fieldThree": "this is a field",\n',
        '-    "updated": "2020-09-10T12:20:14.000Z"\n',
        '+    "updated": "2020-09-16T12:20:14.000Z"\n', ' }'
    ]
示例#19
0
def test_normalize_policies_3():
    policies = EntitiesSet({
        EntityWrapper(
            policy(
                name='policy-1',
                entitlements=['entitlement1', 'entitlement2',
                              'entitlement3'])),
        EntityWrapper(
            policy(name='policy-2',
                   entitlements=[
                       'entitlement1',
                       'entitlement4',
                       'entitlement5',
                   ])),
    })
    entitlements = EntitiesSet({
        EntityWrapper(entitlement(id='id1', name='entitlement1')),
        EntityWrapper(entitlement(id='id2', name='entitlement2')),
        EntityWrapper(entitlement(id='id3', name='entitlement3')),
        EntityWrapper(entitlement(name='entitlement5'))
    })
    policies_set, conflicts = resolve_entities(
        policies, [(entitlements, 'entitlements')])
    assert conflicts == {
        'policy-2': {
            'entitlements': frozenset({'entitlement4', 'entitlement5'})
        }
    }
示例#20
0
def entities_op(entity_set: EntitiesSet, entity: EntityWrapper,
                op: Literal['ADDED', 'DELETED', 'MODIFIED'],
                current_entities: EntitiesSet) -> None:
    # Current state should always contain the real id!!
    cached_entity = current_entities.entities_by_name.get(entity.name)
    if cached_entity:
        entity = entity.with_id(id=cached_entity.id)
    if op == 'ADDED':
        entity_set.add(entity)
    elif op == 'DELETED':
        entity_set.delete(entity)
    elif op == 'MODIFIED':
        entity_set.modify(entity)
示例#21
0
def dump_entity(entity: EntityWrapper, entity_type: str) -> Dict[str, Any]:
    r"""
    name should match this regexp:
       '[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*'
    """
    entity_name = k8s_name(
        entity.name) if has_name(entity) else k8s_name(entity_type)
    entity_mt = getattr(entity.value, ENTITY_METADATA_ATTRIB_NAME, {})
    singleton = entity_mt.get('singleton', False)
    if not singleton:
        entity.value = evolve(entity.value,
                              appgate_metadata=evolve(
                                  entity.value.appgate_metadata,
                                  uuid=entity.id))
    return {
        'apiVersion': f'{K8S_APPGATE_DOMAIN}/{K8S_APPGATE_VERSION}',
        'kind': entity_type,
        'metadata': {
            'name':
            entity_name if entity.is_singleton() else k8s_name(entity.name)
        },
        'spec': K8S_DUMPER.dump(entity.value)
    }
示例#22
0
def compute_diff(e1: EntityWrapper, e2: EntityWrapper) -> List[str]:
    """
    Computes a list with differences between e1 and e2.
    e1 is current entity
    e2 is expected entity
    """
    e1_dump = DIFF_DUMPER.dump(e1.value)
    e2_dump = DIFF_DUMPER.dump(e2.value)
    if e2.has_secrets() and e2.changed_generation():
        e1_dump['generation'] = e2.value.appgate_metadata.latest_generation
        e2_dump['generation'] = e2.value.appgate_metadata.current_generation
    elif e2.has_secrets() and e2.updated(e1):
        updated_field = getattr(e1.value, 'updated', None)
        if updated_field:
            e1_dump['updated'] = dump_datetime(updated_field)
            e2_dump['updated'] = dump_datetime(
                e2.value.appgate_metadata.modified)
    diff = list(
        difflib.unified_diff(json.dumps(e1_dump,
                                        indent=4).splitlines(keepends=True),
                             json.dumps(e2_dump,
                                        indent=4).splitlines(keepends=True),
                             n=1))
    return diff
示例#23
0
def test_compare_policies_1():
    current_policies = EntitiesSet(set())
    expected_policies = EntitiesSet({
        EntityWrapper(Policy(name='policy1', expression='expression-1')),
        EntityWrapper(Policy(name='policy2', expression='expression-2')),
        EntityWrapper(Policy(name='policy3', expression='expression-3'))
    })
    plan = compare_entities(current_policies, expected_policies, BUILTIN_TAGS)
    assert plan.create.entities == {
        EntityWrapper(Policy(name='policy1', expression='expression-1')),
        EntityWrapper(Policy(name='policy2', expression='expression-2')),
        EntityWrapper(Policy(name='policy3', expression='expression-3'))
    }
    assert plan.modify.entities == set()
    assert plan.delete.entities == set()
示例#24
0
def test_dependencies_1():
    """
    One dependency
    EntityDep3 has an array field (deps1) with deps from EntityDep1
    """
    api = load_test_open_api_spec()
    EntityDep1 = api.entities['EntityDep1'].cls
    EntityDep3 = api.entities['EntityDep3'].cls
    deps1 = EntitiesSet({
        EntityWrapper(EntityDep1(id='d11', name='dep11')),
        EntityWrapper(EntityDep1(id='d12', name='dep12')),
        EntityWrapper(EntityDep1(id='d13', name='dep13')),
    })
    deps3 = EntitiesSet({
        EntityWrapper(
            EntityDep3(id='d31',
                       name='dep31',
                       deps1=frozenset({'dep11', 'dep12'})))
    })

    # No conflits
    deps3_resolved, conflicts = resolve_entities(deps3, [(deps1, 'deps1')])
    assert conflicts is None
    assert deps3_resolved.entities == {
        EntityWrapper(
            EntityDep3(id='d31', name='dep31', deps1=frozenset({'d11',
                                                                'd12'})))
    }

    # Conflicts
    deps3 = EntitiesSet({
        EntityWrapper(
            EntityDep3(id='d31',
                       name='dep31',
                       deps1=frozenset({'dep14', 'dep12'})))
    })
    deps3_resolved, conflicts = resolve_entities(deps3, [(deps1, 'deps1')])
    assert conflicts == {'dep31': {'deps1': frozenset({'dep14'})}}
示例#25
0
def test_dependencies_4():
    """
    several dependencies (even nested)
    See EntityDep5 for details
    """
    test_api_spec = load_test_open_api_spec()
    EntityDep1 = test_api_spec.entities['EntityDep1'].cls
    EntityDep2 = test_api_spec.entities['EntityDep2'].cls
    EntityDep3 = test_api_spec.entities['EntityDep3'].cls
    EntityDep4 = test_api_spec.entities['EntityDep4'].cls
    EntityDep6 = test_api_spec.entities['EntityDep6'].cls
    EntityDep6_Obj1 = test_api_spec.entities['EntityDep6_Obj1'].cls
    EntityDep6_Obj1_Obj2 = test_api_spec.entities['EntityDep6_Obj1_Obj2'].cls
    EntityDep6_Obj1_Obj2_Deps1 = test_api_spec.entities[
        'EntityDep6_Obj1_Obj2_Deps1'].cls

    deps1 = EntitiesSet({
        EntityWrapper(EntityDep1(id='d11', name='dep11')),
        EntityWrapper(EntityDep1(id='d12', name='dep12')),
        EntityWrapper(EntityDep1(id='d13', name='dep13')),
    })
    deps2 = EntitiesSet({
        EntityWrapper(EntityDep2(id='d21', name='dep21')),
        EntityWrapper(EntityDep2(id='d22', name='dep22')),
        EntityWrapper(EntityDep2(id='d23', name='dep23')),
    })
    deps3 = EntitiesSet({
        EntityWrapper(
            EntityDep3(id='d31',
                       name='dep31',
                       deps1=frozenset({'dep11', 'dep12'}))),
        EntityWrapper(
            EntityDep3(id='d32',
                       name='dep32',
                       deps1=frozenset({'dep11', 'dep13'}))),
        EntityWrapper(
            EntityDep3(id='d33',
                       name='dep33',
                       deps1=frozenset({'dep12', 'dep13'}))),
    })
    deps4 = EntitiesSet({
        EntityWrapper(
            EntityDep4(id='d41',
                       name='dep41',
                       deps1=frozenset({'dep11', 'dep12'}),
                       dep2='dep21')),
        EntityWrapper(
            EntityDep4(id='d42',
                       name='dep42',
                       deps1=frozenset({'dep11', 'dep13'}),
                       dep2='dep22')),
        EntityWrapper(
            EntityDep4(id='d43',
                       name='dep43',
                       deps1=frozenset({'dep12', 'dep13'}),
                       dep2='dep23')),
    })

    # no conflicts
    data = {
        'id': 'd61',
        'name': 'dep61',
        'deps4': ['dep41', 'dep42'],
        'obj1': {
            'dep3': 'dep31',
            'obj2': {
                'deps1': [
                    {
                        'dep1': 'dep11'
                    },
                    {
                        'dep1': 'dep12'
                    },
                    {
                        'dep1': 'dep13'
                    },
                ],
                'deps2': ['dep21', 'dep22']
            }
        }
    }
    deps6 = EntitiesSet(
        {EntityWrapper(K8S_LOADER.load(data, None, EntityDep6))})
    appgate_state = AppgateState(
        entities_set={
            'EntityDep1': deps1,
            'EntityDep2': deps2,
            'EntityDep3': deps3,
            'EntityDep4': deps4,
            'EntityDep5': EntitiesSet(),
            'EntityDep6': deps6,
        })
    conflicts = resolve_appgate_state(appgate_state, test_api_spec)
    assert conflicts == {}
    assert appgate_state.entities_set['EntityDep1'].entities == {
        EntityWrapper(EntityDep1(id='d11', name='dep11')),
        EntityWrapper(EntityDep1(id='d12', name='dep12')),
        EntityWrapper(EntityDep1(id='d13', name='dep13')),
    }
    assert appgate_state.entities_set['EntityDep2'].entities == {
        EntityWrapper(EntityDep2(id='d21', name='dep21')),
        EntityWrapper(EntityDep2(id='d22', name='dep22')),
        EntityWrapper(EntityDep2(id='d23', name='dep23')),
    }
    assert appgate_state.entities_set['EntityDep3'].entities == {
        EntityWrapper(
            EntityDep3(id='d31', name='dep31', deps1=frozenset({'d11',
                                                                'd12'}))),
        EntityWrapper(
            EntityDep3(id='d32', name='dep32', deps1=frozenset({'d11',
                                                                'd13'}))),
        EntityWrapper(
            EntityDep3(id='d33', name='dep33', deps1=frozenset({'d12',
                                                                'd13'}))),
    }
    assert appgate_state.entities_set['EntityDep4'].entities == {
        EntityWrapper(
            EntityDep4(id='d41',
                       name='dep41',
                       deps1=frozenset({'d11', 'd12'}),
                       dep2='d21')),
        EntityWrapper(
            EntityDep4(id='d42',
                       name='dep42',
                       deps1=frozenset({'d11', 'd13'}),
                       dep2='d22')),
        EntityWrapper(
            EntityDep4(id='d43',
                       name='dep43',
                       deps1=frozenset({'d12', 'd13'}),
                       dep2='d23')),
    }
    assert appgate_state.entities_set['EntityDep6'].entities == {
        EntityWrapper(
            EntityDep6(name='dep61',
                       deps4=frozenset({'d42', 'd41'}),
                       obj1=EntityDep6_Obj1(
                           dep3='d31',
                           obj2=EntityDep6_Obj1_Obj2(deps1=frozenset({
                               EntityDep6_Obj1_Obj2_Deps1(dep1='dep11'),
                               EntityDep6_Obj1_Obj2_Deps1(dep1='dep12'),
                               EntityDep6_Obj1_Obj2_Deps1(dep1='dep13'),
                           }),
                                                     deps2=frozenset(
                                                         {'d21', 'd22'})))))
    }

    # Test empty list in dependencies
    data = {
        'id': 'd61',
        'name': 'dep61',
        'obj1': {
            'dep3': 'dep31',
            'obj2': {
                'deps1': [],
                'deps2': ['dep21', 'dep22']
            }
        }
    }
    deps6 = EntitiesSet(
        {EntityWrapper(K8S_LOADER.load(data, None, EntityDep6))})
    appgate_state = AppgateState(
        entities_set={
            'EntityDep1': deps1,
            'EntityDep2': deps2,
            'EntityDep3': deps3,
            'EntityDep4': deps4,
            'EntityDep5': EntitiesSet(),
            'EntityDep6': deps6,
        })
    conflicts = resolve_appgate_state(appgate_state, test_api_spec)
    assert conflicts == {}
    assert appgate_state.entities_set['EntityDep6'].entities == {
        EntityWrapper(
            EntityDep6(name='dep61',
                       deps4=frozenset(),
                       obj1=EntityDep6_Obj1(dep3='d31',
                                            obj2=EntityDep6_Obj1_Obj2(
                                                deps1=frozenset(),
                                                deps2=frozenset({'d21',
                                                                 'd22'})))))
    }
示例#26
0
def test_filter_appgate_entities():
    entities = [
        Policy(id='id0',
               name='policy0',
               expression='expression-0',
               tags=frozenset({'tag1', 'tag2', 'tag3'})),
        Policy(id='id1',
               name='policy1',
               expression='expression-1',
               tags=frozenset({'tag1', 'tag4', 'tag5'})),
        Policy(id='id2',
               name='policy2',
               expression='expression-2',
               tags=frozenset({'tag3', 'tag6', 'tag7'})),
        Policy(id='id3',
               name='policy3',
               expression='expression-3',
               tags=frozenset({'tag4', 'tag9', 'tag10'}))
    ]
    r1 = exclude_appgate_entities(entities,
                                  target_tags=None,
                                  exclude_tags=None)
    assert frozenset(set(EntityWrapper(a) for a in entities)) == r1

    r1 = exclude_appgate_entities(entities,
                                  target_tags=frozenset({'tag1'}),
                                  exclude_tags=None)
    assert r1 == frozenset(
        set(
            EntityWrapper(a) for a in [
                Policy(id='id0',
                       name='policy0',
                       expression='expression-0',
                       tags=frozenset({'tag1', 'tag2', 'tag3'})),
                Policy(id='id1',
                       name='policy1',
                       expression='expression-1',
                       tags=frozenset({'tag1', 'tag4', 'tag5'}))
            ]))

    r1 = exclude_appgate_entities(entities,
                                  target_tags=frozenset({'tag1'}),
                                  exclude_tags=frozenset({'tag2'}))
    assert r1 == frozenset(
        set(
            EntityWrapper(a) for a in [
                Policy(id='id1',
                       name='policy1',
                       expression='expression-1',
                       tags=frozenset({'tag1', 'tag4', 'tag5'}))
            ]))

    r1 = exclude_appgate_entities(entities,
                                  target_tags=None,
                                  exclude_tags=frozenset({'tag2'}))
    assert r1 == frozenset(
        set(
            EntityWrapper(a) for a in [
                Policy(id='id1',
                       name='policy1',
                       expression='expression-1',
                       tags=frozenset({'tag1', 'tag4', 'tag5'})),
                Policy(id='id2',
                       name='policy2',
                       expression='expression-2',
                       tags=frozenset({'tag3', 'tag6', 'tag7'})),
                Policy(id='id3',
                       name='policy3',
                       expression='expression-3',
                       tags=frozenset({'tag4', 'tag9', 'tag10'}))
            ]))

    r1 = exclude_appgate_entities(entities,
                                  target_tags=None,
                                  exclude_tags=frozenset({'tag7'}))
    assert r1 == frozenset(
        set(
            EntityWrapper(a) for a in [
                Policy(id='id0',
                       name='policy0',
                       expression='expression-0',
                       tags=frozenset({'tag1', 'tag2', 'tag3'})),
                Policy(id='id1',
                       name='policy1',
                       expression='expression-1',
                       tags=frozenset({'tag1', 'tag4', 'tag5'})),
                Policy(id='id3',
                       name='policy3',
                       expression='expression-3',
                       tags=frozenset({'tag4', 'tag9', 'tag10'}))
            ]))

    r1 = exclude_appgate_entities(entities,
                                  target_tags=None,
                                  exclude_tags=frozenset(
                                      {'tag1', 'tag4', 'tag6', 'tag9'}))
    assert r1 == frozenset()

    r1 = exclude_appgate_entities(entities,
                                  target_tags=frozenset({'tag11', 'tag12'}),
                                  exclude_tags=None)
    assert r1 == frozenset()
示例#27
0
async def main_loop(queue: Queue, ctx: Context, k8s_configmap_client: K8SConfigMapClient) -> None:
    namespace = ctx.namespace
    log.info('[appgate-operator/%s] Main loop started:', namespace)
    log.info('[appgate-operator/%s]   + namespace: %s', namespace, namespace)
    log.info('[appgate-operator/%s]   + host: %s', namespace, ctx.controller)
    log.info('[appgate-operator/%s]   + timeout: %s', namespace, ctx.timeout)
    log.info('[appgate-operator/%s]   + dry-run: %s', namespace, ctx.dry_run_mode)
    log.info('[appgate-operator/%s]   + cleanup: %s', namespace, ctx.cleanup_mode)
    log.info('[appgate-operator/%s]   + two-way-sync: %s', namespace, ctx.two_way_sync)
    log.info('[appgate-operator/%s] Getting current state from controller',
             namespace)
    current_appgate_state = await get_current_appgate_state(ctx=ctx)
    if ctx.cleanup_mode:
        expected_appgate_state = AppgateState(
            {k: v.entities_with_tags(ctx.builtin_tags) for k, v in current_appgate_state.entities_set.items()})
    else:
        expected_appgate_state = deepcopy(current_appgate_state)
    log.info('[appgate-operator/%s] Ready to get new events and compute a new plan',
             namespace)
    while True:
        try:
            event: AppgateEvent = await asyncio.wait_for(queue.get(), timeout=ctx.timeout)
            log.info('[appgate-operator/%s}] Event op: %s %s with name %s', namespace,
                     event.op, str(type(event.entity)), event.entity.name)
            expected_appgate_state.with_entity(EntityWrapper(event.entity), event.op, current_appgate_state)
        except asyncio.exceptions.TimeoutError:
            # Log all entities in expected state
            log.info('[appgate-operator/%s] Expected entities:', namespace)
            for entity_type, xs in expected_appgate_state.entities_set.items():
                for entity_name, e in xs.entities_by_name.items():
                    log.info('[appgate-operator/%s] %s: %s: %s', namespace, entity_type, entity_name,
                             e.id)

            # Resolve entities now, in order
            # this will be the Topological sort
            total_conflicts = resolve_appgate_state(appgate_state=expected_appgate_state,
                                                    reverse=False,
                                                    api_spec=ctx.api_spec)
            if total_conflicts:
                log.error('[appgate-operator/%s] Found errors in expected state and plan can'
                          ' not be applied.', namespace)
                entities_conflict_summary(conflicts=total_conflicts, namespace=namespace)
                log.info('[appgate-operator/%s] Waiting for more events that can fix the state.',
                         namespace)
                continue
                
            if ctx.two_way_sync:
                # use current appgate state from controller instead of from memory
                current_appgate_state = await get_current_appgate_state(ctx=ctx)

            # Create a plan
            # Need to copy?
            # Now we use dicts so resolving update the contents of the keys
            plan = create_appgate_plan(current_appgate_state, expected_appgate_state,
                                       ctx.builtin_tags,)
            if plan.needs_apply:
                log.info('[appgate-operator/%s] No more events for a while, creating a plan',
                         namespace)
                async with AsyncExitStack() as exit_stack:
                    appgate_client = None
                    if not ctx.dry_run_mode:
                        if ctx.device_id is None:
                            raise AppgateException('No device id specified')
                        appgate_client = await exit_stack.enter_async_context(AppgateClient(
                            controller=ctx.controller,
                            user=ctx.user, password=ctx.password, provider=ctx.provider,
                            device_id=ctx.device_id,
                            version=ctx.api_spec.api_version, no_verify=ctx.no_verify,
                            cafile=ctx.cafile))
                    else:
                        log.warning('[appgate-operator/%s] Running in dry-mode, nothing will be created',
                                    namespace)
                    new_plan = await appgate_plan_apply(appgate_plan=plan, namespace=namespace,
                                                        entity_clients=generate_api_spec_clients(
                                                            api_spec=ctx.api_spec,
                                                            appgate_client=appgate_client)
                                                        if appgate_client else {},
                                                        k8s_configmap_client=k8s_configmap_client,
                                                        api_spec=ctx.api_spec)

                    if len(new_plan.errors) > 0:
                        log.error('[appgate-operator/%s] Found errors when applying plan:', namespace)
                        for err in new_plan.errors:
                            log.error('[appgate-operator/%s] Error %s:', namespace, err)
                        sys.exit(1)

                    if appgate_client:
                        current_appgate_state = new_plan.appgate_state
                        expected_appgate_state = expected_appgate_state.sync_generations()
            else:
                log.info('[appgate-operator/%s] Nothing changed! Keeping watching!', namespace)