示例#1
0
def test_verify_checksum_unsupported_algorithm(tmpdir):
    file = tmpdir.join("spells.txt")
    file.write("Beetlejuice! Beetlejuice! Beetlejuice!")

    expected_error = "Cannot perform checksum on the file spells.txt,.*bacon.*"
    with pytest.raises(CachitoError, match=expected_error):
        verify_checksum(str(file), ChecksumInfo("bacon", "spam"))
示例#2
0
def test_verify_checksum_invalid_hexdigest(tmpdir):
    file = tmpdir.join("spells.txt")
    file.write("Beetlejuice! Beetlejuice! Beetlejuice!")

    expected_error = "The file spells.txt has an unexpected checksum value"
    with pytest.raises(CachitoError, match=expected_error):
        verify_checksum(str(file), ChecksumInfo("sha512", "spam"))
示例#3
0
def test_verify_checksum(tmpdir):
    file = tmpdir.join("spells.txt")
    file.write("Beetlejuice! Beetlejuice! Beetlejuice!")

    expected = {
        "sha512": (
            "da518fe8b800b3325fe35ca680085fe37626414d0916937a01a25ef8f5d7aa769b7233073235fce85ee"
            "c717e02bb9d72062656cf2d79223792a784910c267b54"
        ),
        "sha256": "ed1f8cd69bfacf0528744b6a7084f36e8841b6128de0217503e215612a0ee835",
        "md5": "308764bc995153f7d853827a675e6731",
    }
    for algorithm, checksum in expected.items():
        verify_checksum(str(file), ChecksumInfo(algorithm, checksum))
示例#4
0
def upload_non_registry_dependency(
    dep_identifier, version_suffix, verify_scripts=False, checksum_info=None
):
    """
    Upload the non-registry npm dependency to the Nexus hosted repository with a custom version.

    :param str dep_identifier: the identifier of the dependency to download
    :param str version_suffix: the suffix to append to the dependency's version in its package.json
        file
    :param bool verify_scripts: if ``True``, raise an exception if dangerous scripts are present in
        the ``package.json`` file and would have been executed by ``npm pack`` if ``ignore-scripts``
        was set to ``false``
    :param ChecksumInfo checksum_info: if not ``None``, the checksum of the downloaded artifact
        will be verified.
    :raise CachitoError: if the dependency cannot be download, uploaded, or is invalid
    """
    # These are the scripts that should not be present if verify_scripts is True
    dangerous_scripts = {"prepare", "prepack"}
    with tempfile.TemporaryDirectory(prefix="cachito-") as temp_dir:
        env = {
            # This is set since the home directory must be determined by the HOME environment
            # variable or by looking at the /etc/passwd file. The latter does not always work
            # since some deployments (e.g. OpenShift) don't have an entry for the running user
            # in /etc/passwd.
            "HOME": os.environ.get("HOME", ""),
            "NPM_CONFIG_CACHE": os.path.join(temp_dir, "cache"),
            # This is important to avoid executing any dangerous scripts if it's a Git dependency
            "NPM_CONFIG_IGNORE_SCRIPTS": "true",
            "PATH": os.environ.get("PATH", ""),
            # Have `npm pack` fail without a prompt if the SSH key from a protected source such
            # as a private GitHub repo is not trusted
            "GIT_SSH_COMMAND": "ssh -o StrictHostKeyChecking=yes",
        }
        run_params = {"env": env, "cwd": temp_dir}
        npm_pack_args = ["npm", "pack", dep_identifier]
        log.info("Downloading the npm dependency %s to be uploaded to Nexus", dep_identifier)
        # An example of the command's stdout:
        #   "reactivex-rxjs-6.5.5.tgz\n"
        stdout = run_cmd(
            npm_pack_args, run_params, f"Failed to download the npm dependency {dep_identifier}"
        )
        dep_archive = os.path.join(temp_dir, stdout.strip())
        if checksum_info:
            verify_checksum(dep_archive, checksum_info)

        package_json_rel_path = find_package_json(dep_archive)
        if not package_json_rel_path:
            msg = f"The dependency {dep_identifier} does not have a package.json file"
            log.error(msg)
            raise CachitoError(msg)

        modified_dep_archive = os.path.join(
            os.path.dirname(dep_archive), f"modified-{os.path.basename(dep_archive)}"
        )
        with tarfile.open(dep_archive, mode="r:*") as dep_archive_file:
            with tarfile.open(modified_dep_archive, mode="x:gz") as modified_dep_archive_file:
                for member in dep_archive_file.getmembers():
                    # Add all the files except for the package.json file without any modifications
                    if member.path != package_json_rel_path:
                        modified_dep_archive_file.addfile(
                            member, dep_archive_file.extractfile(member)
                        )
                        continue

                    # Modify the version in the package.json file
                    try:
                        package_json = json.load(dep_archive_file.extractfile(member))
                    except json.JSONDecodeError:
                        msg = (
                            f"The dependency {dep_identifier} does not have a valid "
                            "package.json file"
                        )
                        log.exception(msg)
                        raise CachitoError(msg)

                    if verify_scripts:
                        log.info(
                            "Checking for dangerous scripts in the package.json of %s",
                            dep_identifier,
                        )
                        scripts = package_json.get("scripts", {})
                        if dangerous_scripts & scripts.keys():
                            msg = (
                                f"The dependency {dep_identifier} is not supported because Cachito "
                                "cannot execute the following required scripts of Git "
                                f"dependencies: {', '.join(sorted(dangerous_scripts))}"
                            )
                            log.error(msg)
                            raise CachitoError(msg)

                    new_version = f"{package_json['version']}{version_suffix}"
                    log.debug(
                        "Modifying the version of %s from %s to %s",
                        dep_identifier,
                        package_json["version"],
                        new_version,
                    )
                    package_json["version"] = new_version
                    package_json_bytes = json.dumps(package_json, indent=2).encode("utf-8")
                    package_json_file_obj = io.BytesIO(package_json_bytes)
                    member.size = len(package_json_bytes)
                    modified_dep_archive_file.addfile(member, package_json_file_obj)

        repo_name = get_js_hosted_repo_name()
        nexus.upload_asset_only_component(repo_name, "npm", modified_dep_archive)