Example #1
0
def in_toto_record_start(step_name,
                         material_list,
                         signing_key=None,
                         gpg_keyid=None,
                         gpg_use_default=False,
                         gpg_home=None,
                         exclude_patterns=None,
                         base_path=None,
                         record_environment=False,
                         normalize_line_endings=False,
                         lstrip_paths=None):
    """Generates preliminary link metadata.

  Records paths and hashes of materials in a preliminary link metadata file.
  The metadata is signed with the passed signing_key, a gpg key identified by
  its ID, or the default gpg key. If multiple key arguments are passed, only
  one key is used in above order of precedence. At least one key argument must
  be passed. The resulting link file is written to
  ``.STEP-NAME.KEYID-PREFIX.link-unfinished``.

  Use this function together with in_toto_record_stop as an alternative to
  in_toto_run, in order to provide evidence for supply chain steps that cannot
  be carried out by a single command.

  Arguments:
    step_name: A unique name to associate link metadata with a step.

    material_list: A list of artifact paths to be recorded as materials.
        Directories are traversed recursively.

    signing_key (optional): A key used to sign the resulting link metadata. The
        format is securesystemslib.formats.KEY_SCHEMA.

    gpg_keyid (optional): A keyid used to identify a local gpg key used to sign
        the resulting link metadata.

    gpg_use_default (optional): A boolean indicating if the default gpg key
        should be used to sign the resulting link metadata.

    gpg_home (optional): A path to the gpg home directory. If not set the
        default gpg home directory is used.

    exclude_patterns (optional): A list of filename patterns to exclude certain
        files from being recorded as artifacts. See Config docs for details.

    base_path (optional): A path relative to which artifacts are recorded.
        Default is the current working directory.

    record_environment (optional): A boolean indicating if information about
        the environment should be added in the resulting link metadata.

    normalize_line_endings (optional): A boolean indicating if line endings of
        artifacts should be normalized before hashing for cross-platform
        support.

    lstrip_paths (optional): A list of path prefixes used to left-strip
        artifact paths before storing them in the resulting link metadata.

  Raises:
    securesystemslib.exceptions.FormatError: Passed arguments are malformed.

    ValueError: None of signing_key, gpg_keyid or gpg_use_default=True is
        passed.

    securesystemslib.exceptions.StorageError: Cannot hash artifacts.

    PrefixError: Left-stripping artifact paths results in non-unique dict keys.

    securesystemslib.process.subprocess.TimeoutExpired: Link command times out.

    IOError, PermissionError:
        Cannot write link metadata.

    securesystemslib.exceptions.CryptoError, \
            securesystemslib.exceptions.UnsupportedAlgorithmError:
        Signing errors.

    ValueError, OSError, securesystemslib.gpg.exceptions.CommandError, \
            securesystemslib.gpg.exceptions.KeyNotFoundError:
        gpg signing errors.

  Side Effects:
    Reads artifact files from disk.
    Calls system gpg in a subprocess, if a gpg key argument is passed.
    Writes preliminary link metadata file to disk.

  """
    LOG.info("Start recording '{}'...".format(step_name))

    # Fail if there is no signing key arg at all
    if not signing_key and not gpg_keyid and not gpg_use_default:
        raise ValueError("Pass either a signing key, a gpg keyid or set"
                         " gpg_use_default to True!")

    # Check key formats to fail early
    if signing_key:
        _check_match_signing_key(signing_key)
    if gpg_keyid:
        securesystemslib.formats.KEYID_SCHEMA.check_match(gpg_keyid)

    if exclude_patterns:
        securesystemslib.formats.NAMES_SCHEMA.check_match(exclude_patterns)

    if base_path:
        securesystemslib.formats.PATH_SCHEMA.check_match(base_path)

    if material_list:
        LOG.info("Recording materials '{}'...".format(
            ", ".join(material_list)))

    materials_dict = record_artifacts_as_dict(
        material_list,
        exclude_patterns=exclude_patterns,
        base_path=base_path,
        follow_symlink_dirs=True,
        normalize_line_endings=normalize_line_endings,
        lstrip_paths=lstrip_paths)

    LOG.info("Creating preliminary link metadata...")
    environment = {}
    if record_environment:
        environment['workdir'] = os.getcwd().replace('\\', '/')

    link = in_toto.models.link.Link(name=step_name,
                                    materials=materials_dict,
                                    products={},
                                    command=[],
                                    byproducts={},
                                    environment=environment)

    link_metadata = Metablock(signed=link)

    if signing_key:
        LOG.info("Signing link metadata using passed key...")
        signature = link_metadata.sign(signing_key)

    elif gpg_keyid:
        LOG.info("Signing link metadata using passed GPG keyid...")
        signature = link_metadata.sign_gpg(gpg_keyid, gpg_home=gpg_home)

    else:  # (gpg_use_default)
        LOG.info("Signing link metadata using default GPG key ...")
        signature = link_metadata.sign_gpg(gpg_keyid=None, gpg_home=gpg_home)

    # We need the signature's keyid to write the link to keyid infix'ed filename
    signing_keyid = signature["keyid"]

    unfinished_fn = UNFINISHED_FILENAME_FORMAT.format(step_name=step_name,
                                                      keyid=signing_keyid)

    LOG.info(
        "Storing preliminary link metadata to '{}'...".format(unfinished_fn))
    link_metadata.dump(unfinished_fn)
Example #2
0
def in_toto_record_start(step_name,
                         material_list,
                         signing_key=None,
                         gpg_keyid=None,
                         gpg_use_default=False,
                         gpg_home=None,
                         exclude_patterns=None,
                         base_path=None,
                         record_environment=False,
                         normalize_line_endings=False):
    """
  <Purpose>
    Starts creating link metadata for a multi-part in-toto step. I.e.
    records passed materials, creates link meta data object from it, signs it
    with passed signing_key, gpg key identified by the passed gpg_keyid
    or the default gpg key and stores it to disk under
    UNFINISHED_FILENAME_FORMAT.

    One of signing_key, gpg_keyid or gpg_use_default has to be passed.

  <Arguments>
    step_name:
            A unique name to relate link metadata with a step defined in the
            layout.
    material_list:
            List of file or directory paths that should be recorded as
            materials.
    signing_key: (optional)
            If not None, link metadata is signed with this key.
            Format is securesystemslib.formats.KEY_SCHEMA
    gpg_keyid: (optional)
            If not None, link metadata is signed with a gpg key identified
            by the passed keyid.
    gpg_use_default: (optional)
            If True, link metadata is signed with default gpg key.
    gpg_home: (optional)
            Path to GPG keyring (if not set the default keyring is used).
    exclude_patterns: (optional)
            Artifacts matched by the pattern are excluded from the materials
            section in the resulting preliminary link.
    base_path: (optional)
            If passed, record materials relative to base_path. Default is
            current working directory.
            NOTE: The base_path part of the recorded materials is not included
            in the resulting preliminary link's material section.
    record_environment: (optional)
            if values such as workdir should be recorded  on the environment
            dictionary (false by default)
    normalize_line_endings: (optional)
            If True, replaces windows and mac line endings with unix line
            endings before hashing materials, for cross-platform support.

  <Exceptions>
    ValueError if none of signing_key, gpg_keyid or gpg_use_default=True
        is passed.

    securesystemslib.FormatError if a signing_key is passed and does not match
        securesystemslib.formats.KEY_SCHEMA or a gpg_keyid is passed and does
        not match securesystemslib.formats.KEYID_SCHEMA or exclude_patterns
        are passed and don't match securesystemslib.formats.NAMES_SCHEMA, or
        base_path is passed and does not match
        securesystemslib.formats.PATH_SCHEMA or is not a directory.

  <Side Effects>
    Writes newly created link metadata file to disk using the filename scheme
    from link.UNFINISHED_FILENAME_FORMAT

  <Returns>
    None.

  """
    log.info("Start recording '{}'...".format(step_name))

    # Fail if there is no signing key arg at all
    if not signing_key and not gpg_keyid and not gpg_use_default:
        raise ValueError("Pass either a signing key, a gpg keyid or set"
                         " gpg_use_default to True!")

    # Check key formats to fail early
    if signing_key:
        _check_match_signing_key(signing_key)
    if gpg_keyid:
        securesystemslib.formats.KEYID_SCHEMA.check_match(gpg_keyid)

    if exclude_patterns:
        securesystemslib.formats.NAMES_SCHEMA.check_match(exclude_patterns)

    if base_path:
        securesystemslib.formats.PATH_SCHEMA.check_match(base_path)

    if material_list:
        log.info("Recording materials '{}'...".format(
            ", ".join(material_list)))

    materials_dict = record_artifacts_as_dict(
        material_list,
        exclude_patterns=exclude_patterns,
        base_path=base_path,
        follow_symlink_dirs=True,
        normalize_line_endings=normalize_line_endings)

    log.info("Creating preliminary link metadata...")
    environment = {}
    if record_environment:
        environment['workdir'] = os.getcwd().replace('\\', '/')

    link = in_toto.models.link.Link(name=step_name,
                                    materials=materials_dict,
                                    products={},
                                    command=[],
                                    byproducts={},
                                    environment=environment)

    link_metadata = Metablock(signed=link)

    if signing_key:
        log.info("Signing link metadata using passed key...")
        signature = link_metadata.sign(signing_key)

    elif gpg_keyid:
        log.info("Signing link metadata using passed GPG keyid...")
        signature = link_metadata.sign_gpg(gpg_keyid, gpg_home=gpg_home)

    else:  # (gpg_use_default)
        log.info("Signing link metadata using default GPG key ...")
        signature = link_metadata.sign_gpg(gpg_keyid=None, gpg_home=gpg_home)

    # We need the signature's keyid to write the link to keyid infix'ed filename
    signing_keyid = signature["keyid"]

    unfinished_fn = UNFINISHED_FILENAME_FORMAT.format(step_name=step_name,
                                                      keyid=signing_keyid)

    log.info(
        "Storing preliminary link metadata to '{}'...".format(unfinished_fn))
    link_metadata.dump(unfinished_fn)
Example #3
0
def in_toto_run(name,
                material_list,
                product_list,
                link_cmd_args,
                record_streams=False,
                signing_key=None,
                gpg_keyid=None,
                gpg_use_default=False,
                gpg_home=None,
                exclude_patterns=None,
                base_path=None,
                compact_json=False,
                record_environment=False,
                normalize_line_endings=False,
                lstrip_paths=None,
                metadata_directory=None):
    """Performs a supply chain step or inspection generating link metadata.

  Executes link_cmd_args, recording paths and hashes of files before and after
  command execution (aka. artifacts) in a link metadata file. The metadata is
  signed with the passed signing_key, a gpg key identified by its ID, or the
  default gpg key. If multiple key arguments are passed, only one key is used
  in above order of precedence. The resulting link file is written to
  ``STEP-NAME.KEYID-PREFIX.link``. If no key argument is passed the link
  metadata is neither signed nor written to disk.

  Arguments:
    name: A unique name to associate link metadata with a step or inspection.

    material_list: A list of artifact paths to be recorded before command
        execution. Directories are traversed recursively.

    product_list: A list of artifact paths to be recorded after command
        execution. Directories are traversed recursively.

    link_cmd_args: A list where the first element is a command and the
        remaining elements are arguments passed to that command.

    record_streams (optional): A boolean indicating if standard output and
        standard error of the link command should be recorded in the link
        metadata in addition to being displayed while the command is executed.

    signing_key (optional): A key used to sign the resulting link metadata. The
        format is securesystemslib.formats.KEY_SCHEMA.

    gpg_keyid (optional): A keyid used to identify a local gpg key used to sign
        the resulting link metadata.

    gpg_use_default (optional): A boolean indicating if the default gpg key
        should be used to sign the resulting link metadata.

    gpg_home (optional): A path to the gpg home directory. If not set the
        default gpg home directory is used.

    exclude_patterns (optional): A list of filename patterns to exclude certain
        files from being recorded as artifacts. See Config docs for details.

    base_path (optional): A path relative to which artifacts are recorded.
        Default is the current working directory.

    compact_json (optional): A boolean indicating if the resulting link
        metadata should be written in the most compact JSON representation.

    record_environment (optional): A boolean indicating if information about
        the environment should be added in the resulting link metadata.

    normalize_line_endings (optional): A boolean indicating if line endings of
        artifacts should be normalized before hashing for cross-platform
        support.

    lstrip_paths (optional): A list of path prefixes used to left-strip
        artifact paths before storing them in the resulting link metadata.

    metadata_directory (optional): A directory path to write the resulting link
        metadata file to. Default destination is the current working directory.

  Raises:
    securesystemslib.exceptions.FormatError: Passed arguments are malformed.

    ValueError: Cannot change to base path directory.

    securesystemslib.exceptions.StorageError: Cannot hash artifacts.

    PrefixError: Left-stripping artifact paths results in non-unique dict keys.

    securesystemslib.process.subprocess.TimeoutExpired: Link command times out.

    IOError, FileNotFoundError, NotADirectoryError, PermissionError:
        Cannot write link metadata.

    securesystemslib.exceptions.CryptoError, \
            securesystemslib.exceptions.UnsupportedAlgorithmError:
        Signing errors.

    ValueError, OSError, securesystemslib.gpg.exceptions.CommandError, \
            securesystemslib.gpg.exceptions.KeyNotFoundError:
        gpg signing errors.

  Side Effects:
    Reads artifact files from disk.
    Runs link command in subprocess.
    Calls system gpg in a subprocess, if a gpg key argument is passed.
    Writes link metadata file to disk, if any key argument is passed.

  Returns:
    A Metablock object that contains the resulting link object.

  """
    LOG.info("Running '{}'...".format(name))

    # Check key formats to fail early
    if signing_key:
        _check_match_signing_key(signing_key)
    if gpg_keyid:
        securesystemslib.formats.KEYID_SCHEMA.check_match(gpg_keyid)

    if exclude_patterns:
        securesystemslib.formats.NAMES_SCHEMA.check_match(exclude_patterns)

    if base_path:
        securesystemslib.formats.PATH_SCHEMA.check_match(base_path)

    if metadata_directory:
        securesystemslib.formats.PATH_SCHEMA.check_match(metadata_directory)

    if material_list:
        LOG.info("Recording materials '{}'...".format(
            ", ".join(material_list)))

    materials_dict = record_artifacts_as_dict(
        material_list,
        exclude_patterns=exclude_patterns,
        base_path=base_path,
        follow_symlink_dirs=True,
        normalize_line_endings=normalize_line_endings,
        lstrip_paths=lstrip_paths)

    if link_cmd_args:
        LOG.info("Running command '{}'...".format(" ".join(link_cmd_args)))
        byproducts = execute_link(link_cmd_args, record_streams)
    else:
        byproducts = {}

    if product_list:
        securesystemslib.formats.PATHS_SCHEMA.check_match(product_list)
        LOG.info("Recording products '{}'...".format(", ".join(product_list)))

    products_dict = record_artifacts_as_dict(
        product_list,
        exclude_patterns=exclude_patterns,
        base_path=base_path,
        follow_symlink_dirs=True,
        normalize_line_endings=normalize_line_endings,
        lstrip_paths=lstrip_paths)

    LOG.info("Creating link metadata...")
    environment = {}
    if record_environment:
        environment['workdir'] = os.getcwd().replace('\\', '/')

    link = in_toto.models.link.Link(name=name,
                                    materials=materials_dict,
                                    products=products_dict,
                                    command=link_cmd_args,
                                    byproducts=byproducts,
                                    environment=environment)

    link_metadata = Metablock(signed=link, compact_json=compact_json)

    signature = None
    if signing_key:
        LOG.info("Signing link metadata using passed key...")
        signature = link_metadata.sign(signing_key)

    elif gpg_keyid:
        LOG.info("Signing link metadata using passed GPG keyid...")
        signature = link_metadata.sign_gpg(gpg_keyid, gpg_home=gpg_home)

    elif gpg_use_default:
        LOG.info("Signing link metadata using default GPG key ...")
        signature = link_metadata.sign_gpg(gpg_keyid=None, gpg_home=gpg_home)

    # We need the signature's keyid to write the link to keyid infix'ed filename
    if signature:
        signing_keyid = signature["keyid"]
        filename = FILENAME_FORMAT.format(step_name=name, keyid=signing_keyid)

        if metadata_directory is not None:
            filename = os.path.join(metadata_directory, filename)

        LOG.info("Storing link metadata to '{}'...".format(filename))
        link_metadata.dump(filename)

    return link_metadata
Example #4
0
def in_toto_run(name,
                material_list,
                product_list,
                link_cmd_args,
                record_streams=False,
                signing_key=None,
                gpg_keyid=None,
                gpg_use_default=False,
                gpg_home=None,
                exclude_patterns=None,
                base_path=None,
                compact_json=False,
                record_environment=False,
                normalize_line_endings=False):
    """
  <Purpose>
    Calls functions in this module to run the command passed as link_cmd_args
    argument and to store materials, products, by-products and environment
    information into a link metadata file.

    The link metadata file is signed either with the passed signing_key, or
    a gpg key identified by the passed gpg_keyid or with the default gpg
    key if gpg_use_default is True.

    Even if multiple key parameters are passed, only one key is used for
    signing (in above order of precedence).

    The link file is dumped to `link.FILENAME_FORMAT` using the signing key's
    keyid.

    If no key parameter is passed the link is neither signed nor dumped.

  <Arguments>
    name:
            A unique name to relate link metadata with a step or inspection
            defined in the layout.
    material_list:
            List of file or directory paths that should be recorded as
            materials.
    product_list:
            List of file or directory paths that should be recorded as
            products.
    link_cmd_args:
            A list where the first element is a command and the remaining
            elements are arguments passed to that command.
    record_streams: (optional)
            A bool that specifies whether to redirect standard output and
            and standard error to a temporary file which is returned to the
            caller (True) or not (False).
    signing_key: (optional)
            If not None, link metadata is signed with this key.
            Format is securesystemslib.formats.KEY_SCHEMA
    gpg_keyid: (optional)
            If not None, link metadata is signed with a gpg key identified
            by the passed keyid.
    gpg_use_default: (optional)
            If True, link metadata is signed with default gpg key.
    gpg_home: (optional)
            Path to GPG keyring (if not set the default keyring is used).
    exclude_patterns: (optional)
            Artifacts matched by the pattern are excluded from the materials
            and products sections in the resulting link.
    base_path: (optional)
            If passed, record artifacts relative to base_path. Default is
            current working directory.
            NOTE: The base_path part of the recorded material is not included
            in the resulting preliminary link's material/product sections.
    compact_json: (optional)
            Whether or not to use the most compact json representation.
    record_environment: (optional)
            if values such as workdir should be recorded  on the environment
            dictionary (false by default)
    normalize_line_endings: (optional)
            If True, replaces windows and mac line endings with unix line
            endings before hashing materials and products, for cross-platform
            support.

  <Exceptions>
    securesystemslib.FormatError if a signing_key is passed and does not match
        securesystemslib.formats.KEY_SCHEMA or a gpg_keyid is passed and does
        not match securesystemslib.formats.KEYID_SCHEMA or exclude_patterns
        are passed and don't match securesystemslib.formats.NAMES_SCHEMA, or
        base_path is passed and does not match
        securesystemslib.formats.PATH_SCHEMA or is not a directory.

  <Side Effects>
    If a key parameter is passed for signing, the newly created link metadata
    file is written to disk using the filename scheme: `link.FILENAME_FORMAT`

  <Returns>
    Newly created Metablock object containing a Link object

  """
    log.info("Running '{}'...".format(name))

    # Check key formats to fail early
    if signing_key:
        _check_match_signing_key(signing_key)
    if gpg_keyid:
        securesystemslib.formats.KEYID_SCHEMA.check_match(gpg_keyid)

    if exclude_patterns:
        securesystemslib.formats.NAMES_SCHEMA.check_match(exclude_patterns)

    if base_path:
        securesystemslib.formats.PATH_SCHEMA.check_match(base_path)

    if material_list:
        log.info("Recording materials '{}'...".format(
            ", ".join(material_list)))

    materials_dict = record_artifacts_as_dict(
        material_list,
        exclude_patterns=exclude_patterns,
        base_path=base_path,
        follow_symlink_dirs=True,
        normalize_line_endings=normalize_line_endings)

    if link_cmd_args:
        log.info("Running command '{}'...".format(" ".join(link_cmd_args)))
        byproducts = execute_link(link_cmd_args, record_streams)
    else:
        byproducts = {}

    if product_list:
        securesystemslib.formats.PATHS_SCHEMA.check_match(product_list)
        log.info("Recording products '{}'...".format(", ".join(product_list)))

    products_dict = record_artifacts_as_dict(
        product_list,
        exclude_patterns=exclude_patterns,
        base_path=base_path,
        follow_symlink_dirs=True,
        normalize_line_endings=normalize_line_endings)

    log.info("Creating link metadata...")
    environment = {}
    if record_environment:
        environment['workdir'] = os.getcwd().replace('\\', '/')

    link = in_toto.models.link.Link(name=name,
                                    materials=materials_dict,
                                    products=products_dict,
                                    command=link_cmd_args,
                                    byproducts=byproducts,
                                    environment=environment)

    link_metadata = Metablock(signed=link, compact_json=compact_json)

    signature = None
    if signing_key:
        log.info("Signing link metadata using passed key...")
        signature = link_metadata.sign(signing_key)

    elif gpg_keyid:
        log.info("Signing link metadata using passed GPG keyid...")
        signature = link_metadata.sign_gpg(gpg_keyid, gpg_home=gpg_home)

    elif gpg_use_default:
        log.info("Signing link metadata using default GPG key ...")
        signature = link_metadata.sign_gpg(gpg_keyid=None, gpg_home=gpg_home)

    # We need the signature's keyid to write the link to keyid infix'ed filename
    if signature:
        signing_keyid = signature["keyid"]
        filename = FILENAME_FORMAT.format(step_name=name, keyid=signing_keyid)
        log.info("Storing link metadata to '{}'...".format(filename))
        link_metadata.dump(filename)

    return link_metadata