Example #1
0
def test_upload_asset_only_component_failed(mock_requests):
    mock_open = mock.mock_open(read_data=b"some tgz file")
    mock_requests.post.return_value.ok = False

    expected = "Failed to upload a component to Nexus"
    with mock.patch("cachito.workers.nexus.open", mock_open):
        with pytest.raises(CachitoError, match=expected):
            nexus.upload_asset_only_component("cachito-js-hosted", "npm",
                                              "/path/to/rxjs-6.5.5.tgz")
Example #2
0
def test_upload_asset_only_component_connection_error(mock_requests):
    mock_open = mock.mock_open(read_data=b"some tgz file")
    mock_requests.post.side_effect = requests.ConnectionError()

    expected = "Could not connect to the Nexus instance to upload a component"
    with mock.patch("cachito.workers.nexus.open", mock_open):
        with pytest.raises(CachitoError, match=expected):
            nexus.upload_asset_only_component("cachito-js-hosted", "npm",
                                              "/path/to/rxjs-6.5.5.tgz")
Example #3
0
def test_upload_asset_only_component(mock_requests, use_hoster):
    mock_open = mock.mock_open(read_data=b"some tgz file")
    mock_requests.post.return_value.ok = True

    with mock.patch("cachito.workers.nexus.open", mock_open):
        nexus.upload_asset_only_component("cachito-js-hosted", "npm",
                                          "/path/to/rxjs-6.5.5.tgz",
                                          use_hoster)

    expected_asset = {"npm.asset": ("rxjs-6.5.5.tgz", b"some tgz file")}
    assert mock_requests.post.call_args[1]["files"] == expected_asset
    assert mock_requests.post.call_args[1]["params"] == {
        "repository": "cachito-js-hosted"
    }
    assert mock_requests.post.call_args[1]["auth"].username == "cachito"
    assert mock_requests.post.call_args[1]["auth"].password == "cachito"
Example #4
0
def test_upload_asset_only_component_wrong_type():
    repo_type = "unsupported"
    expected = f"Type {repo_type!r} is not supported or requires additional params"
    with pytest.raises(ValueError, match=expected):
        nexus.upload_asset_only_component("cachito-js-hosted", repo_type,
                                          "/path/to/rxjs-6.5.5.tgz")
Example #5
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)