def create_task(txn_key, batch_key, task_id, task_name, admins, owners, metadata):

    create_payload = task_transaction_pb2.CreateTask(task_id=task_id, name=task_name)

    create_payload.admins.extend(admins)

    inputs = [
        addresser.make_task_attributes_address(task_id=task_id),
        addresser.make_sysadmin_members_address(txn_key.public_key),
    ]

    inputs.extend([addresser.make_user_address(user_id=u) for u in admins])
    inputs.extend([addresser.make_task_admins_address(task_id, u) for u in admins])

    outputs = [addresser.make_task_attributes_address(task_id=task_id)]

    outputs.extend([addresser.make_task_admins_address(task_id, u) for u in admins])

    if owners:
        create_payload.owners.extend(owners)
        inputs.extend([addresser.make_user_address(user_id=u) for u in owners])
        inputs.extend([addresser.make_task_owners_address(task_id, u) for u in owners])
        outputs.extend([addresser.make_task_owners_address(task_id, u) for u in owners])

    rbac_payload = rbac_payload_pb2.RBACPayload(
        content=create_payload.SerializeToString(),
        message_type=rbac_payload_pb2.RBACPayload.CREATE_TASK,
    )

    return make_header_and_batch(rbac_payload, inputs, outputs, txn_key, batch_key)
Exemplo n.º 2
0
def create_task(state_entries, payload, state):
    try:
        entry = state_accessor.get_state_entry(
            state_entries,
            addresser.make_task_attributes_address(payload.task_id))
        container = message_accessor.get_task_container(entry)

    except KeyError:
        container = task_state_pb2.TaskAttributesContainer()

    task = container.task_attributes.add()

    task.task_id = payload.task_id
    task.name = payload.name
    task.metadata = payload.metadata

    address_values = {}

    pubkeys_by_address = {}
    for pubkey in payload.admins:
        address = addresser.make_task_admins_address(task_id=payload.task_id,
                                                     user_id=pubkey)
        if address in pubkeys_by_address:
            pubkeys_by_address[address].append(pubkey)
        else:
            pubkeys_by_address[address] = [pubkey]

    address_values.update(
        _handle_task_rel_container(
            state_entries=state_entries,
            task_id=payload.task_id,
            pubkeys_by_address=pubkeys_by_address,
        ))

    pubkeys_by_address = {}
    for pubkey in payload.owners:
        address = addresser.make_task_owners_address(task_id=payload.task_id,
                                                     user_id=pubkey)
        if address in pubkeys_by_address:
            pubkeys_by_address[address].append(pubkey)
        else:
            pubkeys_by_address[address] = [pubkey]

    address_values.update(
        _handle_task_rel_container(
            state_entries=state_entries,
            task_id=payload.task_id,
            pubkeys_by_address=pubkeys_by_address,
        ))

    address_values[addresser.make_task_attributes_address(
        payload.task_id)] = container.SerializeToString()

    state_accessor.set_state(state, address_values)
def propose_add_task_admins(
    txn_key, batch_key, proposal_id, task_id, user_id, reason, metadata
):
    propose_payload = task_transaction_pb2.ProposeAddTaskAdmin(
        proposal_id=proposal_id,
        task_id=task_id,
        user_id=user_id,
        reason=reason,
        metadata=metadata,
    )

    inputs = [
        addresser.make_user_address(user_id),
        addresser.make_task_admins_address(task_id=task_id, user_id=user_id),
        addresser.make_proposal_address(task_id, user_id),
        addresser.make_task_attributes_address(task_id),
    ]

    outputs = [addresser.make_proposal_address(task_id, user_id)]

    rbac_payload = rbac_payload_pb2.RBACPayload(
        content=propose_payload.SerializeToString(),
        message_type=rbac_payload_pb2.RBACPayload.PROPOSE_ADD_TASK_ADMINS,
    )

    return make_header_and_batch(rbac_payload, inputs, outputs, txn_key, batch_key)
def propose_remove_task_owners(
    txn_key, batch_key, proposal_id, task_id, user_id, reason, metadata
):
    propose = task_transaction_pb2.ProposeRemoveTaskOwner(
        proposal_id=proposal_id,
        task_id=task_id,
        user_id=user_id,
        reason=reason,
        metadata=metadata,
    )

    inputs = [
        addresser.make_user_address(user_id),
        addresser.make_task_owners_address(task_id=task_id, user_id=user_id),
        addresser.make_proposal_address(task_id, user_id),
        addresser.make_task_attributes_address(task_id),
    ]

    outputs = [addresser.make_proposal_address(task_id, user_id)]

    rbac_payload = rbac_payload_pb2.RBACPayload(
        content=propose.SerializeToString(),
        message_type=rbac_payload_pb2.RBACPayload.PROPOSE_REMOVE_TASK_OWNERS,
    )

    return make_header_and_batch(rbac_payload, inputs, outputs, txn_key, batch_key)
Exemplo n.º 5
0
def validate_task_rel_proposal(header, propose, rel_address, state):
    """Validates that the User exists, the Task exists, and the User is not
    in the Task's relationship specified by rel_address.

    Args:
        header (TransactionHeader): The transaction header.
        propose (ProposeAddTask_____): The Task relationship proposal.
        rel_address (str): The Task relationship address produced by the Task
            and the User.
        state (sawtooth_sdk.Context): The way to communicate to the validator
            the state gets and sets.

    Returns:
        (dict of addresses)
    """

    task_id = propose.task_id
    user_id = propose.user_id
    user_address = addresser.make_user_address(user_id)
    task_address = addresser.make_task_attributes_address(task_id)
    proposal_address = addresser.make_proposal_address(object_id=task_id,
                                                       related_id=user_id)

    state_entries = state_accessor.get_state(
        state, [user_address, task_address, proposal_address, rel_address])
    user_validator.validate_identifier_is_user(state_entries,
                                               identifier=user_id,
                                               address=user_address)
    user_entry = state_accessor.get_state_entry(state_entries, user_address)
    user = message_accessor.get_user_from_container(
        message_accessor.get_user_container(user_entry), user_id)

    validate_identifier_is_task(state_entries,
                                identifier=task_id,
                                address=task_address)

    try:
        task_rel_entry = state_accessor.get_state_entry(
            state_entries, rel_address)
        task_rel_container = message_accessor.get_task_rel_container(
            task_rel_entry)

        if (header.signer_public_key not in [
                user.user_id, user.manager_id
        ]) and (not message_accessor.is_in_task_rel_container(
                task_rel_container, task_id, user_id)):
            raise InvalidTransaction(
                "Txn signer {} is not the user or the user's "
                "manager {} nor the task owner / admin".format(
                    header.signer_public_key, [user.user_id, user.manager_id]))
        if message_accessor.is_in_task_rel_container(task_rel_container,
                                                     task_id, user_id):
            raise InvalidTransaction("User {} is already in the Task {} "
                                     "relationship".format(user_id, task_id))

    except KeyError:
        # The task rel container doesn't exist so no task relationship exists
        pass

    return state_entries
def propose_add_role_tasks(
    txn_key, batch_key, proposal_id, role_id, task_id, reason, metadata
):
    propose_payload = role_transaction_pb2.ProposeAddRoleTask(
        proposal_id=proposal_id,
        role_id=role_id,
        task_id=task_id,
        reason=reason,
        metadata=metadata,
    )

    inputs = [
        addresser.make_proposal_address(role_id, task_id),
        addresser.make_role_tasks_address(role_id, task_id),
        addresser.make_role_owners_address(role_id, txn_key.public_key),
        addresser.make_role_attributes_address(role_id),
        addresser.make_task_attributes_address(task_id),
    ]

    outputs = [addresser.make_proposal_address(role_id, task_id)]

    rbac_payload = rbac_payload_pb2.RBACPayload(
        content=propose_payload.SerializeToString(),
        message_type=rbac_payload_pb2.RBACPayload.PROPOSE_ADD_ROLE_TASKS,
    )

    return make_header_and_batch(rbac_payload, inputs, outputs, txn_key, batch_key)
Exemplo n.º 7
0
    def test_generated_task_address(self):
        """Tests the task address creation function as well as the
        address_is function.
        """

        ident = uuid4().hex
        address = addresser.make_task_attributes_address(ident)

        self.assertEqual(len(address), addresser.ADDRESS_LENGTH,
                         "The address is 70 characters")

        self.assertTrue(addresser.is_address(address),
                        "The address is 70 character hexidecimal")

        self.assertTrue(addresser.namespace_ok(address),
                        "The address has correct namespace prefix")

        self.assertTrue(
            addresser.is_family_address(address),
            "The address is 70 character hexidecimal with family prefix",
        )

        self.assertEqual(
            addresser.address_is(address),
            AddressSpace.TASKS_ATTRIBUTES,
            "The address created must be a Task Attributes address.",
        )
Exemplo n.º 8
0
    def test_deterministic_task_address(self):
        """Tests that a specific task_id generates the expected
        task address, and thus is probably deterministic.
        """

        ident = "99968acb8f1a48b3a4bc21e2cd252e67"
        expected_address = "9f44481e326a1713a905b26359fc8d\
a2817c1a5f67de6f464701f0c10042da345d2800"

        address = addresser.make_task_attributes_address(ident)

        self.assertEqual(len(address), addresser.ADDRESS_LENGTH,
                         "The address is 70 characters")

        self.assertTrue(addresser.is_address(address),
                        "The address is 70 character hexidecimal")

        self.assertTrue(addresser.namespace_ok(address),
                        "The address has correct namespace prefix")

        self.assertTrue(
            addresser.is_family_address(address),
            "The address is 70 character hexidecimal with family prefix",
        )

        self.assertEqual(address, expected_address,
                         "The address is the one we expected it to be")

        self.assertEqual(
            addresser.address_is(address),
            AddressSpace.TASKS_ATTRIBUTES,
            "The address created must be a Task Attributes address.",
        )
    def test_task_addresses(self):
        """Tests the Task address creation functions as well as the
        address_is function.

        Notes:
            1. Create an address of a particular type:
                - Task Attributes
                - Task Owners
                - Task Admins
            2. Assert that address_is returns the correct address type.

        """

        task_address = addresser.make_task_attributes_address(uuid4().hex)

        self.assertEqual(len(task_address), 70, "The address is a well-formed address.")

        self.assertEqual(
            addresser.address_is(task_address),
            AddressSpace.TASKS_ATTRIBUTES,
            "The Task Attributes address created must be "
            "found to be a Task Attributes address.",
        )

        task_owners_address = addresser.make_task_owners_address(
            task_id=uuid4().hex, user_id=uuid4().hex
        )

        self.assertEqual(
            len(task_owners_address), 70, "The address is a well-formed address."
        )

        self.assertEqual(
            addresser.address_is(task_owners_address),
            AddressSpace.TASKS_OWNERS,
            "The Task Owners address created must be "
            "found to be a Task Owners address.",
        )

        task_admins_address = addresser.make_task_admins_address(
            task_id=uuid4().hex, user_id=uuid4().hex
        )

        self.assertEqual(
            len(task_admins_address), 70, "The address is a well-formed address."
        )

        self.assertEqual(
            addresser.address_is(task_admins_address),
            AddressSpace.TASKS_ADMINS,
            "The Task Admins address created must be "
            "found to be a Task Admins address.",
        )
def validate_create_task_state(state_entries, payload):
    user_validator.validate_list_of_user_are_users(state_entries, payload.admins)
    user_validator.validate_list_of_user_are_users(state_entries, payload.owners)

    try:
        entry = state_accessor.get_state_entry(
            state_entries, addresser.make_task_attributes_address(payload.task_id)
        )
        container = message_accessor.get_task_container(entry)

        if message_accessor.is_in_task_container(container, payload.task_id):
            raise InvalidTransaction(
                "Task with id {} already in " "state".format(payload.task_id)
            )
    except KeyError:
        # The task container is not in state, so no at this address.
        pass
Exemplo n.º 11
0
def new_task(payload, state):
    create_payload = task_transaction_pb2.CreateTask()
    create_payload.ParseFromString(payload.content)

    addresses = [
        addresser.make_task_attributes_address(create_payload.task_id)
    ]
    if not create_payload.admins:
        raise InvalidTransaction("New tasks must have administrators.")

    if not create_payload.owners:
        raise InvalidTransaction("New tasks must have owners.")

    if create_payload.admins:
        addresses.extend(
            [addresser.make_user_address(u) for u in create_payload.admins])

        addresses.extend([
            addresser.make_task_admins_address(task_id=create_payload.task_id,
                                               user_id=u)
            for u in create_payload.admins
        ])

    if create_payload.owners:
        addresses.extend(
            [addresser.make_user_address(u) for u in create_payload.owners])
        addresses.extend([
            addresser.make_task_owners_address(create_payload.task_id,
                                               user_id=u)
            for u in create_payload.owners
        ])

    state_entries = state_accessor.get_state(state, addresses)

    task_validator.validate_create_task_state(state_entries=state_entries,
                                              payload=create_payload)

    create_task(state_entries, create_payload, state)
Exemplo n.º 12
0
def validate_task_rel_del_proposal(header, propose, rel_address, state):
    """Validates that the User exists, the Task exists, and the User is in
    the Tasks's relationship specified by the rel_address.

    Args:
        header (TransactionHeader): The transaction header.
        propose (ProposeRemoveTask____): The Task Remove relationship proposal
        rel_address (str): The task relationship address.
        state (Context:: The way to communicate to the validator State gets
            and sets.

    Returns:
        (dict of addresses)
    """

    user_address = addresser.make_user_address(propose.user_id)
    task_address = addresser.make_task_attributes_address(propose.task_id)

    proposal_address = addresser.make_proposal_address(
        object_id=propose.task_id, related_id=propose.user_id)

    state_entries = state_accessor.get_state(
        state, [user_address, task_address, proposal_address, rel_address])

    user_validator.validate_identifier_is_user(state_entries,
                                               identifier=propose.user_id,
                                               address=user_address)

    user_entry = state_accessor.get_state_entry(state_entries, user_address)

    user = message_accessor.get_user_from_container(
        message_accessor.get_user_container(user_entry), propose.user_id)

    validate_identifier_is_task(state_entries,
                                identifier=propose.task_id,
                                address=task_address)

    try:
        task_rel_entry = state_accessor.get_state_entry(
            state_entries, rel_address)
        task_rel_container = message_accessor.get_task_rel_container(
            task_rel_entry)

        if (header.signer_public_key not in [
                user.user_id, user.manager_id
        ]) and (not message_accessor.is_in_task_rel_container(
                task_rel_container, propose.task_id, propose.user_id)):
            raise InvalidTransaction(
                "Txn signer {} is not the user or the user's "
                "manager {} nor the task owner / admin".format(
                    header.signer_public_key, [user.user_id, user.manager_id]))

        if not message_accessor.is_in_task_rel_container(
                task_rel_container, propose.task_id, propose.user_id):
            raise InvalidTransaction("User {} isn't in the Task {} "
                                     "relationship".format(
                                         propose.user_id, propose.task_id))
    except KeyError:
        raise InvalidTransaction(
            "User {} isn't in the Task {} relationship, "
            "since there isn't a container at the address".format(
                propose.user_id, propose.task_id))

    return state_entries
def validate_role_task_proposal(header, propose, state):
    """Applies state validation rules for ADDRoleTaskProposal.
        - The Role exists.
        - The Task exists.
        - The Transaction was signed by a Role Owner.
        - There is no open Proposal for the same change.
        - The task is not already part of the Role.

    Args:
        header (TransactionHeader): The propobuf transaction header.
        propose (ProposeAddRoleTask): The protobuf transaction.
        state (Context): A connection to the validator to ask about state.

    Returns:
        (list of StateEntry)

    """

    role_address = addresser.make_role_attributes_address(propose.role_id)

    task_address = addresser.make_task_attributes_address(propose.task_id)

    proposal_address = addresser.make_proposal_address(propose.role_id,
                                                       propose.task_id)

    txn_signer_role_owner_address = addresser.make_role_owners_address(
        role_id=propose.role_id, user_id=header.signer_public_key)

    role_tasks_address = addresser.make_role_tasks_address(
        propose.role_id, propose.task_id)

    state_entries = state_accessor.get_state(
        state=state,
        addresses=[
            role_address,
            task_address,
            proposal_address,
            role_tasks_address,
            txn_signer_role_owner_address,
        ],
    )

    role_validator.validate_identifier_is_role(state_entries=state_entries,
                                               address=role_address,
                                               identifier=propose.role_id)

    task_validator.validate_identifier_is_task(state_entries=state_entries,
                                               identifier=propose.task_id,
                                               address=task_address)
    try:
        role_task_entry = state_accessor.get_state_entry(
            state_entries, role_tasks_address)
        role_task_container = message_accessor.get_role_rel_container(
            role_task_entry)
        if message_accessor.is_in_role_rel_container(
                role_task_container,
                role_id=propose.role_id,
                identifier=propose.task_id):
            raise InvalidTransaction("Role {} already contains task {}".format(
                propose.role_id, propose.task_id))
    except KeyError:
        # The Task is not in the RoleTask state
        pass

    try:
        role_owner_entry = state_accessor.get_state_entry(
            state_entries, txn_signer_role_owner_address)
        role_owner_container = message_accessor.get_role_rel_container(
            role_owner_entry)

        if not message_accessor.is_in_role_rel_container(
                role_owner_container,
                role_id=propose.role_id,
                identifier=header.signer_public_key,
        ):
            raise InvalidTransaction(
                "Txn signer {} is not a role owner".format(
                    header.signer_public_key))
    except KeyError:
        raise InvalidTransaction("Txn signer {} is not a role owner.".format(
            header.signer_public_key))

    if not has_no_open_proposal(
            state_entries=state_entries,
            object_id=propose.role_id,
            related_id=propose.task_id,
            proposal_address=proposal_address,
            proposal_type=proposal_state_pb2.Proposal.ADD_ROLE_TASKS,
    ):
        raise InvalidTransaction(
            "There is already an open proposal to add task {} to "
            "role {}".format(propose.task_id, propose.role_id))
    return state_entries