def test_make_addresses(): """Test making the message addresses""" related_id = helper.user.id() object_id = helper.role.id() proposal_id = helper.proposal.id() proposal_address = Role().owner.propose.address(object_id, related_id) reason = helper.proposal.reason() signer_user_id = helper.user.id() signer_admin_address = Role().admin.address(object_id, signer_user_id) signer_owner_address = Role().owner.address(object_id, signer_user_id) message = Role().owner.reject.make( proposal_id=proposal_id, related_id=related_id, object_id=object_id, reason=reason, ) inputs, outputs = Role().owner.reject.make_addresses( message=message, signer_user_id=signer_user_id) assert signer_owner_address in inputs assert signer_admin_address in inputs assert proposal_address in inputs assert proposal_address in outputs
def test_create(): """Test creating a role""" user, keypair = helper.user.create() name = helper.role.name() description = helper.role.description() role_id = helper.role.id() message = Role().make( role_id=role_id, name=name, owners=[user.next_id], admins=[user.next_id], description=description, ) status = Role().new(signer_keypair=keypair, signer_user_id=user.next_id, message=message) assert len(status) == 1 assert status[0]["status"] == "COMMITTED" role = Role().get(object_id=role_id) assert role.role_id == message.role_id assert role.name == message.name assert role.description == message.description assert Role().owner.exists(object_id=role.role_id, related_id=user.next_id) assert Role().admin.exists(object_id=role.role_id, related_id=user.next_id)
def create(self): """Create a test role""" role_id = self.id() name = self.name() user, key_pair = helper.user.create() message = Role().make(role_id=role_id, name=name, owners=[user.next_id], admins=[user.next_id]) status = Role().new(signer_keypair=key_pair, signer_user_id=user.next_id, message=message) assert len(status) == 1 assert status[0]["status"] == "COMMITTED" role = Role().get(object_id=message.role_id) assert role.role_id == message.role_id assert role.name == message.name assert Role().owner.exists(object_id=role.role_id, related_id=user.next_id) assert Role().admin.exists(object_id=role.role_id, related_id=user.next_id) return role, user, key_pair
def test_create(): """Test executing the message on the blockchain""" proposal, _, role_owner, role_owner_key, _, _ = helper.role.member.propose.create( ) reason = helper.role.member.propose.reason() status = Role().member.confirm.new( signer_keypair=role_owner_key, signer_user_id=role_owner.next_id, proposal_id=proposal.proposal_id, object_id=proposal.object_id, related_id=proposal.related_id, reason=reason, ) assert len(status) == 1 assert status[0]["status"] == "COMMITTED" confirm = Role().member.confirm.get(object_id=proposal.object_id, related_id=proposal.related_id) assert isinstance(confirm, protobuf.proposal_state_pb2.Proposal) assert confirm.proposal_type == protobuf.proposal_state_pb2.Proposal.ADD_ROLE_MEMBER assert confirm.proposal_id == proposal.proposal_id assert confirm.object_id == proposal.object_id assert confirm.related_id == proposal.related_id assert confirm.close_reason == reason assert confirm.closer == role_owner.next_id assert confirm.status == protobuf.proposal_state_pb2.Proposal.CONFIRMED assert Role().member.exists(object_id=proposal.object_id, related_id=proposal.related_id)
def test_create(): """Test executing the message on the blockchain""" role, _, _ = helper.role.create() proposal_id = addresser.proposal.unique_id() reason = helper.proposal.reason() user, signer_keypair = helper.user.create() message = Role().owner.propose.make( proposal_id=proposal_id, next_id=user.next_id, role_id=role.role_id, reason=reason, metadata=None, ) status = Role().owner.propose.new( signer_keypair=signer_keypair, signer_user_id=user.next_id, message=message ) assert len(status) == 1 assert status[0]["status"] == "COMMITTED" proposal = Role().owner.propose.get(object_id=role.role_id, related_id=user.next_id) assert isinstance(proposal, protobuf.proposal_state_pb2.Proposal) assert proposal.proposal_type == protobuf.proposal_state_pb2.Proposal.ADD_ROLE_OWNER assert proposal.proposal_id == proposal_id assert proposal.object_id == role.role_id assert proposal.related_id == user.next_id assert proposal.opener == user.next_id assert proposal.open_reason == reason
def test_make_addresses(): """Test making the message addresses""" next_id = helper.user.id() user_address = User().address(next_id) role_id = helper.role.id() role_address = Role().address(role_id) proposal_id = addresser.proposal.unique_id() reason = helper.proposal.reason() relationship_address = Role().owner.address(role_id, next_id) proposal_address = Role().owner.propose.address(role_id, next_id) signer_user_id = helper.user.id() message = Role().owner.propose.make( proposal_id=proposal_id, next_id=next_id, role_id=role_id, reason=reason, metadata=None, ) inputs, outputs = Role().owner.propose.make_addresses( message=message, signer_user_id=signer_user_id ) assert relationship_address in inputs assert user_address in inputs assert role_address in inputs assert proposal_address in inputs assert proposal_address in outputs
def test_create(): """Test executing the message on the blockchain""" proposal, _, role_admin, role_admin_key, _, _ = helper.role.admin.propose.create( ) reason = helper.role.admin.propose.reason() message = Role().admin.reject.make( proposal_id=proposal.proposal_id, object_id=proposal.object_id, related_id=proposal.related_id, reason=reason, ) status = Role().admin.reject.new( signer_keypair=role_admin_key, signer_user_id=role_admin.next_id, message=message, ) assert len(status) == 1 assert status[0]["status"] == "COMMITTED" reject = Role().admin.propose.get(object_id=proposal.object_id, related_id=proposal.related_id) assert isinstance(reject, protobuf.proposal_state_pb2.Proposal) assert reject.proposal_type == protobuf.proposal_state_pb2.Proposal.ADD_ROLE_ADMIN assert reject.proposal_id == proposal.proposal_id assert reject.object_id == proposal.object_id assert reject.related_id == proposal.related_id assert reject.close_reason == reason assert reject.closer == role_admin.next_id assert reject.status == protobuf.proposal_state_pb2.Proposal.REJECTED
def test_make_addresses(): """Test making the message addresses""" related_id = helper.task.id() object_id = helper.role.id() proposal_id = helper.proposal.id() proposal_address = Role().task.propose.address(object_id, related_id) reason = helper.proposal.reason() relationship_address = Role().task.address(object_id, related_id) signer_user_id = helper.user.id() task_owner_address = Task().owner.address(related_id, signer_user_id) message = Role().task.confirm.make( proposal_id=proposal_id, related_id=related_id, object_id=object_id, reason=reason, ) inputs, outputs = Role().task.confirm.make_addresses( message=message, signer_user_id=signer_user_id) assert task_owner_address in inputs assert proposal_address in inputs assert relationship_address in inputs assert proposal_address in outputs assert relationship_address in outputs
def create(self): """A user creates an add role owner proposal to add themselves as an owner to a role""" role, role_owner, role_owner_key = helper.role.create() user, user_key = helper.user.create() proposal_id = self.id() reason = helper.user.reason() message = Role().owner.propose.make( proposal_id=proposal_id, role_id=role.role_id, next_id=user.next_id, reason=reason, metadata=None, ) status = Role().owner.propose.new(signer_keypair=user_key, signer_user_id=user.next_id, message=message) assert len(status) == 1 assert status[0]["status"] == "COMMITTED" proposal = Role().owner.propose.get(object_id=role.role_id, related_id=user.next_id) assert isinstance(proposal, protobuf.proposal_state_pb2.Proposal) assert (proposal.proposal_type == protobuf.proposal_state_pb2.Proposal.ADD_ROLE_OWNER) assert proposal.proposal_id == proposal_id assert proposal.object_id == role.role_id assert proposal.related_id == user.next_id assert proposal.opener == user.next_id assert proposal.open_reason == reason return proposal, role, role_owner, role_owner_key, user, user_key
def test_make_addresses(): """Test making the message addresses""" next_id = helper.user.id() role_id = helper.role.id() proposal_id = addresser.proposal.unique_id() reason = helper.proposal.reason() signer_user_id = helper.user.id() relationship_address = Role().member.address(role_id, next_id) proposal_address = Role().member.remove.address(role_id, next_id) role_owner_address = Role().owner.address(role_id, signer_user_id) message = Role().member.remove.make(proposal_id=proposal_id, object_id=role_id, related_id=next_id, reason=reason) inputs, outputs = Role().member.remove.make_addresses( message=message, signer_user_id=signer_user_id) assert relationship_address in inputs assert proposal_address in inputs assert role_owner_address in inputs assert proposal_address in outputs assert relationship_address in outputs
def test_create(): """Test importing a role""" user, keypair = helper.user.create() name = helper.role.name() role_id = helper.role.id() status = Role().imports.new( signer_keypair=keypair, signer_user_id=user.next_id, role_id=role_id, name=name, owners=[user.next_id], admins=[user.next_id], members=[user.next_id], ) assert len(status) == 1 assert status[0]["status"] == "COMMITTED" role = Role().get(object_id=role_id) assert role.role_id == role_id assert role.name == name assert Role().owner.exists(object_id=role.role_id, related_id=user.next_id) assert Role().admin.exists(object_id=role.role_id, related_id=user.next_id) assert Role().member.exists(object_id=role.role_id, related_id=user.next_id)
def test_make_addresses(): """Test the make addresses method for the message""" name = helper.role.name() role_id = helper.role.id() role_address = Role().address(role_id) next_id = helper.user.id() user_address = User().address(next_id) signer_user_id = helper.user.id() owner_address = Role().owner.address(role_id, next_id) admin_address = Role().admin.address(role_id, next_id) message = Role().make(role_id=role_id, name=name, owners=[next_id], admins=[next_id]) inputs, outputs = Role().make_addresses(message=message, signer_user_id=signer_user_id) assert role_address in inputs assert user_address in inputs assert owner_address in inputs assert admin_address in inputs assert role_address in outputs assert user_address in outputs assert owner_address in outputs assert admin_address in outputs
async def add_role_owner(request, role_id): """Add an owner to a role.""" log_request(request) env = Env() if not env.int("ENABLE_NEXT_BASE_USE"): raise ApiDisabled("Not a valid action. Source not enabled") required_fields = ["id"] validate_fields(required_fields, request.json) txn_key, txn_user_id = await get_transactor_key(request) proposal_id = str(uuid4()) conn = await create_connection() approver = await fetch_relationships("role_admins", "role_id", role_id).run(conn) conn.close() batch_list = Role().owner.propose.batch_list( signer_keypair=txn_key, signer_user_id=txn_user_id, proposal_id=proposal_id, role_id=role_id, next_id=request.json.get("id"), reason=request.json.get("reason"), metadata=request.json.get("metadata"), assigned_approver=approver, ) await send(request.app.config.VAL_CONN, batch_list, request.app.config.TIMEOUT) if isinstance(approver, list): for user in approver: await send_notification(user, proposal_id) else: await send_notification(approver, proposal_id) return json({"proposal_id": proposal_id})
async def add_role_task(request, role_id): """Add a task to a role.""" required_fields = ["id"] utils.validate_fields(required_fields, request.json) txn_key, txn_user_id = await utils.get_transactor_key(request) proposal_id = str(uuid4()) conn = await create_connection() approver = await fetch_relationships( "task_owners", "task_id", request.json.get("id") ).run(conn) conn.close() batch_list = Role().task.propose.batch_list( signer_keypair=txn_key, signer_user_id=txn_user_id, proposal_id=proposal_id, role_id=role_id, task_id=request.json.get("id"), reason=request.json.get("reason"), metadata=request.json.get("metadata"), assigned_approver=approver, ) await utils.send( request.app.config.VAL_CONN, batch_list, request.app.config.TIMEOUT ) return json({"proposal_id": proposal_id})
async def create_new_role(request): """Create a new role.""" required_fields = ["name", "administrators", "owners"] utils.validate_fields(required_fields, request.json) conn = await db_utils.create_connection( request.app.config.DB_HOST, request.app.config.DB_PORT, request.app.config.DB_NAME, ) response = await roles_query.roles_search_duplicate(conn, request.json.get("name")) if not response: txn_key, txn_user_id = await utils.get_transactor_key(request) role_id = str(uuid4()) batch_list = Role().batch_list( signer_keypair=txn_key, signer_user_id=txn_user_id, name=request.json.get("name"), role_id=role_id, metadata=request.json.get("metadata"), admins=request.json.get("administrators"), owners=request.json.get("owners"), description=request.json.get("description"), ) await utils.send( request.app.config.VAL_CONN, batch_list, request.app.config.TIMEOUT ) return create_role_response(request, role_id) raise ApiBadRequest( "Error: could not create this role because role name has been taken or already exists" )
async def add_role_member(request, role_id): """Add a member to a role.""" required_fields = ["id"] utils.validate_fields(required_fields, request.json) txn_key, txn_user_id = await utils.get_transactor_key(request) proposal_id = str(uuid4()) batch_list = Role().member.propose.batch_list( signer_keypair=txn_key, signer_user_id=txn_user_id, proposal_id=proposal_id, role_id=role_id, pack_id=request.json.get("pack_id"), next_id=request.json.get("id"), reason=request.json.get("reason"), metadata=request.json.get("metadata"), ) batch_status = await utils.send( request.app.config.VAL_CONN, batch_list, request.app.config.TIMEOUT, request.json.get("tracker") and True, ) if request.json.get("tracker"): return utils.create_tracker_response("batch_status", batch_status) return json({"proposal_id": proposal_id})
async def create_new_role(request): """Create a new role.""" required_fields = ["name", "administrators", "owners"] utils.validate_fields(required_fields, request.json) conn = await create_connection() role_title = " ".join(request.json.get("name").split()) response = await roles_query.roles_search_duplicate(conn, role_title) if request.json.get("metadata") is None or request.json.get("metadata") == {}: set_metadata = {} else: set_metadata = request.json.get("metadata") set_metadata["sync_direction"] = "OUTBOUND" if not response: txn_key, txn_user_id = await utils.get_transactor_key(request) role_id = str(uuid4()) batch_list = Role().batch_list( signer_keypair=txn_key, signer_user_id=txn_user_id, name=role_title, role_id=role_id, metadata=set_metadata, admins=request.json.get("administrators"), owners=request.json.get("owners"), description=request.json.get("description"), ) await utils.send( request.app.config.VAL_CONN, batch_list, request.app.config.TIMEOUT ) conn.close() if role_title != "NextAdmins": distinguished_name_formatted = "CN=" + role_title + "," + GROUP_BASE_DN data_formatted = { "created_date": r.now(), "distinguished_name": distinguished_name_formatted, "group_nickname": role_title, "group_types": -2147483646, "name": role_title, "remote_id": distinguished_name_formatted, } outbound_entry = { "data": data_formatted, "data_type": "group", "timestamp": r.now(), "provider_id": LDAP_DC, } # Insert to outbound_queue and close conn = await create_connection() role_outbound_resource = await roles_query.insert_to_outboundqueue( conn, outbound_entry ) conn.close() else: LOGGER.info( "The role being created is NextAdmins, which is local to NEXT and will not be inserted into the outbound_queue." ) return create_role_response(request, role_id) raise ApiBadRequest( "Error: Could not create this role because the role name already exists." )
def create(self): """A role owner creates an add role task proposal to add a task to their role""" role, role_owner, role_owner_key = helper.role.create() task, task_owner, task_owner_key = helper.task.create() proposal_id = self.id() reason = self.reason() message = Role().task.propose.make( proposal_id=proposal_id, role_id=role.role_id, task_id=task.task_id, reason=reason, metadata=None, ) status = Role().task.propose.new( signer_keypair=role_owner_key, signer_user_id=role_owner.next_id, message=message, ) assert len(status) == 1 assert status[0]["status"] == "COMMITTED" proposal = Role().task.propose.get( object_id=role.role_id, related_id=task.task_id ) assert isinstance(proposal, protobuf.proposal_state_pb2.Proposal) assert ( proposal.proposal_type == protobuf.proposal_state_pb2.Proposal.ADD_ROLE_TASK ) assert proposal.proposal_id == proposal_id assert proposal.object_id == role.role_id assert proposal.related_id == task.task_id assert proposal.opener == role_owner.next_id assert proposal.open_reason == reason return ( proposal, role, role_owner, role_owner_key, task, task_owner, task_owner_key, )
def import_role_transaction(data, inbound_entry, key_pair, role_id, role_exists=False): """ Creates ImportRole batch and append to inbound_entry Args: data: dict: A dict containing the contents of the imported role Fields that can be included: members: A list of next_ids for the role members owners: A list of next_ids for the role owners inbound_entry: dict: transaction entry from the inbound queue containing one user/group data that was fetched from the integrated provider along with additional information like: provider_id, timestamp, and sync_type. key_pair: obj: public and private keys for Ledger Sync Inbound processor. role_id: str: UUID4 formatted id of the imported role role_exists: bool: Indicates if the imported provider role already exists within RethinkDB - defaults to False. """ if role_exists: # Add any deleted members or owners to deleted_members or deleted_owners field data["deleted_members"] = get_deleted_relationships( data=data, relationship="members", role_id=role_id) data["deleted_owners"] = get_deleted_relationships( data=data, relationship="owners", role_id=role_id) message = Role().imports.make(signer_keypair=key_pair, role_id=role_id, **data) batch = Role().imports.batch(signer_keypair=key_pair, signer_user_id=key_pair.public_key, message=message) inbound_entry["batch"] = batch.SerializeToString() add_metadata(inbound_entry, message)
def message(self): """Get a test data CreateRole message""" role_id = self.id() name = self.name() next_id = helper.user.id() message = Role().make(role_id=role_id, name=name, owners=[next_id], admins=[next_id]) assert isinstance(message, protobuf.role_transaction_pb2.CreateRole) assert message.role_id == role_id assert message.name == name return message
async def create_new_role(request): """Create a new role.""" log_request(request) env = Env() if not env.int("ENABLE_NEXT_BASE_USE"): raise ApiDisabled("Not a valid action. Source not enabled.") required_fields = ["name", "administrators", "owners"] validate_fields(required_fields, request.json) role_title = " ".join(request.json.get("name").split()) conn = await create_connection() response = await roles_query.roles_search_duplicate(conn, role_title) conn.close() if not response: txn_key, txn_user_id = await get_transactor_key(request) role_id = str(uuid4()) if request.json.get("metadata") is None: set_metadata = {} else: set_metadata = request.json.get("metadata") set_metadata["sync_direction"] = "OUTBOUND" batch_list = Role().batch_list( signer_keypair=txn_key, signer_user_id=txn_user_id, name=role_title, role_id=role_id, metadata=set_metadata, admins=request.json.get("administrators"), owners=request.json.get("owners"), description=request.json.get("description"), ) sawtooth_response = await send( request.app.config.VAL_CONN, batch_list, request.app.config.TIMEOUT ) if not sawtooth_response: LOGGER.warning("There was an error submitting the sawtooth transaction.") return await handle_errors( request, ApiInternalError( "There was an error submitting the sawtooth transaction." ), ) return create_role_response(request, role_id) return await handle_errors( request, ApiTargetConflict( "Error: Could not create this role because the role name already exists." ), )
def confirm_add_role_members(self, key, proposal_id, role_id, next_id, reason): """Confirm addition of role member.""" batch_list = Role().member.confirm.batch_list( signer_keypair=key, signer_user_id=key.public_key, proposal_id=proposal_id, object_id=role_id, related_id=next_id, reason=reason, ) batch_ids = batcher.get_batch_ids(batch_list=batch_list) self._client.send_batches(batch_list) return self._client.get_statuses(batch_ids, wait=10)
def reject_add_role_tasks(self, key, proposal_id, role_id, task_id, reason): """Reject addition of task to role.""" batch_list = Role().task.reject.batch_list( signer_keypair=key, signer_user_id=key.public_key, proposal_id=proposal_id, object_id=role_id, related_id=task_id, reason=reason, ) batch_ids = batcher.get_batch_ids(batch_list=batch_list) self._client.send_batches(batch_list) return self._client.get_statuses(batch_ids, wait=10)
def create_role(self, key, role_name, role_id, metadata, admins, owners): """Create a new role.""" batch_list = Role().batch_list( signer_keypair=key, signer_user_id=key.public_key, name=role_name, role_id=role_id, metadata=metadata, admins=admins, owners=owners, ) batch_ids = batcher.get_batch_ids(batch_list=batch_list) self._client.send_batches(batch_list) return self._client.get_statuses(batch_ids, wait=10)
def test_new(): """Test executing the message on the blockchain""" proposal, _, role_owner, role_owner_key, _, _ = helper.role.member.propose.create( ) reason = helper.role.member.propose.reason() status = Role().member.confirm.new( signer_keypair=role_owner_key, signer_user_id=role_owner.next_id, proposal_id=proposal.proposal_id, object_id=proposal.object_id, related_id=proposal.related_id, reason=reason, ) assert len(status) == 1 assert status[0]["status"] == "COMMITTED" assert Role().member.exists(object_id=proposal.object_id, related_id=proposal.related_id) proposal_id = helper.proposal.id() reason = helper.proposal.reason() Role().member.confirm.get(object_id=proposal.object_id, related_id=proposal.related_id) status2 = Role().member.remove.new( signer_keypair=role_owner_key, signer_user_id=role_owner.next_id, proposal_id=proposal_id, object_id=proposal.object_id, related_id=proposal.related_id, reason=reason, ) assert len(status2) == 1 assert status2[0]["status"] == "COMMITTED" removal = Role().member.remove.get(object_id=proposal.object_id, related_id=proposal.related_id) assert isinstance(removal, protobuf.proposal_state_pb2.Proposal) assert (removal.proposal_type == protobuf.proposal_state_pb2.Proposal.REMOVE_ROLE_MEMBER) assert removal.proposal_id == proposal_id assert removal.object_id == proposal.object_id assert removal.related_id == proposal.related_id assert removal.open_reason == reason assert removal.close_reason == "" assert removal.opener == role_owner.next_id assert removal.closer == role_owner.next_id assert removal.status == protobuf.proposal_state_pb2.Proposal.REMOVED assert Role().member.not_exists(object_id=proposal.object_id, related_id=proposal.related_id)
def add_sawtooth_prereqs(entry_id, inbound_entry, data_type): """ Adds the following fields to inbound_entry: address, object_id, object_type, and next_id if data_type is set as 'user'. Args: entry_id: A string containing the user's or group's UUID4 formatted id. inbound_entry: A dictionary containing one user/group data that was fetched from the integrated provider along with additional information like: provider_id, timestamp, and sync_type. data_type: A string with the value of either 'user' or 'group'. Returns: inbound_entry: A dictionary of the original inbound_entry with additional fields added as they are required to process the data to Sawtooth Blockchain. Raises: ValueError: If the data_type parameter does not have the value of 'user' or 'group'. """ if data_type == "user": object_id = User().hash(entry_id) address = User().address(object_id=object_id) inbound_entry["next_id"] = entry_id inbound_entry["object_type"] = addresser.ObjectType.USER.value elif data_type == "group": object_id = Role().hash(entry_id) address = Role().address(object_id=object_id) inbound_entry["object_type"] = addresser.ObjectType.ROLE.value else: raise ValueError( "Expecting data_type to be 'user' or 'group, found: {}".format( data_type)) inbound_entry["address"] = bytes_from_hex(address) inbound_entry["object_id"] = bytes_from_hex(object_id) return inbound_entry
async def update_role(request, role_id): """Update a role.""" required_fields = ["description"] utils.validate_fields(required_fields, request.json) txn_key, txn_user_id = await utils.get_transactor_key(request) role_description = request.json.get("description") batch_list = Role().update.batch_list( signer_keypair=txn_key, signer_user_id=txn_user_id, role_id=role_id, description=role_description, ) await utils.send(request.app.config.VAL_CONN, batch_list, request.app.config.TIMEOUT) return json({"id": role_id, "description": role_description})
def test_make(): """Test making a message""" name = helper.role.name() role_id = helper.role.id() next_id = helper.user.id() message = Role().imports.make( role_id=role_id, name=name, owners=[next_id], admins=[next_id] ) assert isinstance(message, protobuf.role_transaction_pb2.ImportsRole) assert isinstance(message.role_id, str) assert isinstance(message.name, str) assert message.role_id == role_id assert message.name == name assert message.owners == [next_id] assert message.admins == [next_id]
def propose_add_role_tasks(self, key, proposal_id, role_id, task_id, reason, metadata): """Propose adding task to role.""" batch_list = Role().task.propose.batch_list( signer_keypair=key, signer_user_id=key.public_key, proposal_id=proposal_id, role_id=role_id, task_id=task_id, reason=reason, metadata=metadata, ) batch_ids = batcher.get_batch_ids(batch_list=batch_list) self._client.send_batches(batch_list) return self._client.get_statuses(batch_ids, wait=10)
def test_make(): """ Test making the message """ next_id = helper.user.id() role_id = helper.role.id() reason = helper.proposal.reason() proposal_id = addresser.proposal.unique_id() message = Role().member.remove.make(proposal_id=proposal_id, object_id=role_id, related_id=next_id, reason=reason) assert isinstance(message, protobuf.proposal_transaction_pb2.RemovalProposal) assert message.proposal_id == proposal_id assert message.object_id == role_id assert message.related_id == next_id assert message.reason == reason