Ejemplo n.º 1
0
    def status(self):
        """
    <Purpose>
      Determine the status of the project, including its delegated roles.
      status() checks if each role provides sufficient public keys, signatures,
      and that a valid metadata file is generated if write() were to be called.
      Metadata files are temporarily written to check that proper metadata files
      is written, where file hashes and lengths are calculated and referenced
      by the project.  status() does not do a simple check for number of
      threshold keys and signatures.

    <Arguments>
      None.

    <Exceptions>
      securesystemslib.exceptions.Error, if the project, or any of its
      delegated roles, do not have a minimum threshold of signatures.

    <Side Effects>
      Generates and writes temporary metadata files.

    <Returns>
      None.
    """

        temp_project_directory = None

        try:
            temp_project_directory = tempfile.mkdtemp()

            metadata_directory = os.path.join(temp_project_directory,
                                              'metadata')
            targets_directory = self.targets_directory

            os.makedirs(metadata_directory)

            # TODO: We should do the schema check.
            filenames = {}
            filenames['targets'] = os.path.join(metadata_directory,
                                                self.project_name)

            # Delegated roles.
            delegated_roles = roledb.get_delegated_rolenames(
                self.project_name, self.repository_name)
            insufficient_keys = []
            insufficient_signatures = []

            for delegated_role in delegated_roles:
                try:
                    _check_role_keys(delegated_role, self.repository_name)

                except exceptions.InsufficientKeysError:
                    insufficient_keys.append(delegated_role)
                    continue

                try:
                    signable = _generate_and_write_metadata(
                        delegated_role,
                        filenames['targets'],
                        False,
                        targets_directory,
                        False,
                        repository_name=self.repository_name)
                    self._log_status(delegated_role, signable[0],
                                     self.repository_name)

                except sslib_exceptions.Error:
                    insufficient_signatures.append(delegated_role)

            if len(insufficient_keys):
                message = 'Delegated roles with insufficient keys: ' +\
                  repr(insufficient_keys)
                logger.info(message)
                return

            if len(insufficient_signatures):
                message = 'Delegated roles with insufficient signatures: ' +\
                  repr(insufficient_signatures)
                logger.info(message)
                return

            # Targets role.
            try:
                _check_role_keys(self.rolename, self.repository_name)

            except exceptions.InsufficientKeysError as e:
                logger.info(str(e))
                return

            try:
                signable, junk = _generate_and_write_metadata(
                    self.project_name, filenames['targets'], False,
                    targets_directory, metadata_directory,
                    self.repository_name)
                self._log_status(self.project_name, signable,
                                 self.repository_name)

            except exceptions.UnsignedMetadataError as e:
                # This error is raised if the metadata has insufficient signatures to
                # meet the threshold.
                self._log_status(self.project_name, e.signable,
                                 self.repository_name)
                return

        finally:
            shutil.rmtree(temp_project_directory, ignore_errors=True)
Ejemplo n.º 2
0
    def write(self, write_partial=False):
        """
    <Purpose>
      Write all the JSON Metadata objects to their corresponding files.
      write() raises an exception if any of the role metadata to be written to
      disk is invalid, such as an insufficient threshold of signatures, missing
      private keys, etc.

    <Arguments>
      write_partial:
        A boolean indicating whether partial metadata should be written to
        disk.  Partial metadata may be written to allow multiple maintainters
        to independently sign and update role metadata.  write() raises an
        exception if a metadata role cannot be written due to not having enough
        signatures.

    <Exceptions>
      securesystemslib.exceptions.Error, if any of the project roles do not
      have a minimum threshold of signatures.

    <Side Effects>
      Creates metadata files in the project's metadata directory.

    <Returns>
      None.
    """

        # Does 'write_partial' have the correct format?
        # Ensure the arguments have the appropriate number of objects and object
        # types, and that all dict keys are properly named.
        # Raise 'securesystemslib.exceptions.FormatError' if any are improperly formatted.
        sslib_formats.BOOLEAN_SCHEMA.check_match(write_partial)

        # At this point the keydb and roledb stores must be fully
        # populated, otherwise write() throwns a 'tuf.Repository' exception if
        # any of the project roles are missing signatures, keys, etc.

        # Write the metadata files of all the delegated roles of the project.
        delegated_rolenames = roledb.get_delegated_rolenames(
            self.project_name, self.repository_name)

        for delegated_rolename in delegated_rolenames:
            delegated_filename = os.path.join(
                self.metadata_directory,
                delegated_rolename + METADATA_EXTENSION)

            # Ensure the parent directories of 'metadata_filepath' exist, otherwise an
            # IO exception is raised if 'metadata_filepath' is written to a
            # sub-directory.
            sslib_util.ensure_parent_dir(delegated_filename)

            _generate_and_write_metadata(delegated_rolename,
                                         delegated_filename,
                                         write_partial,
                                         self.targets_directory,
                                         prefix=self.prefix,
                                         repository_name=self.repository_name)

        # Generate the 'project_name' metadata file.
        targets_filename = self.project_name + METADATA_EXTENSION
        targets_filename = os.path.join(self.metadata_directory,
                                        targets_filename)
        junk, targets_filename = _generate_and_write_metadata(
            self.project_name,
            targets_filename,
            write_partial,
            self.targets_directory,
            prefix=self.prefix,
            repository_name=self.repository_name)

        # Save configuration information that is not stored in the project's
        # metadata
        _save_project_configuration(self.metadata_directory,
                                    self.targets_directory, self.keys,
                                    self.prefix, self.threshold,
                                    self.layout_type, self.project_name)