Ejemplo n.º 1
0
def _setup_travis_ci(gh_repo_name, auth_token, repo_access_token):
    # travis-ci.org is the open source endpoint only! We will need to hit
    # travis-ci.com for private projects!

    # Headers for API v2. This is only necessary because generating a Travis
    # API token from a GitHub Token isn't possible in the API v3 yet. This way
    # is recommended as per:
    # https://github.com/travis-ci/travis-ci/issues/9273
    headers_v2_only = {
        'User-Agent': 'Memote',
        'Accept': 'application/vnd.travis-ci.2+json',
    }

    # Generate Travis API token:
    try:
        LOGGER.info("Generating Travis API token.")
        response = requests.post("https://api.travis-ci.org/auth/github",
                                 headers=headers_v2_only,
                                 data={'github_token': auth_token})
        response.raise_for_status()
    except HTTPError as error:
        LOGGER.critical(
            "Something is wrong with the generated APIv3 authentication token "
            "or you did not link your GitHub account on "
            "'https://travis-ci.org/'? Please refer to the following error "
            "message for further information: {}".format(str(error)))
        sys.exit(1)
    else:
        LOGGER.info("Success!")
        travis_api_token = response.json()["access_token"]

    # Headers for API v3!
    headers = {
        'Travis-API-Version': '3',
        'Authorization': 'token {}'.format(travis_api_token),
        'User-Agent': 'Memote Query'
    }

    # Authenticate the User on Travis
    try:
        LOGGER.info("Authorizing with TravisCI.")
        response = requests.get("https://api.travis-ci.org/user",
                                headers=headers)
        response.raise_for_status()
    except HTTPError as error:
        LOGGER.critical(
            "Something is wrong with the generated token or you did not "
            "link your GitHub account on 'https://travis-ci.org/'? Please "
            "refer to the following error code for "
            "further information: {}".format(str(error)))
        sys.exit(1)
    else:
        LOGGER.info("Success!")
        t_user = response.json()

    # Synchronize a User's projects between GitHub and Travis
    LOGGER.info("Synchronizing user projects between GitHub and Travis.")
    synced = False
    for _ in range(60):
        response = requests.post(
            "https://api.travis-ci.org/user/{}/sync".format(t_user["id"]),
            headers=headers)
        if response.status_code == 200:
            synced = True
            LOGGER.info("Success!")
            break
        else:
            LOGGER.info("Still synchronizing...")
            sleep(0.5)
    if not synced:
        LOGGER.critical(
            "Could not synchronize your projects between GitHub and Travis!"
            "The latest response code is {}".format(response.status_code))
        sys.exit(1)

    # Make sure GitHub repo can be found on Travis CI.#
    url_safe_repo_name = quote_plus(gh_repo_name)
    try:
        LOGGER.info("Find repository {} on Travis CI".format(gh_repo_name))
        response = requests.get(
            "https://api.travis-ci.org/repo/{}".format(url_safe_repo_name),
            headers=headers)
        response.raise_for_status()
    except HTTPError as error:
        if error.response.status_code == 404:
            LOGGER.critical(
                "Repository could not be found. Is it on GitHub already and "
                "spelled correctly?")
            sys.exit(1)
        else:
            LOGGER.critical(
                "An error occurred. Please refer to the following error "
                "message for further information: {}".format(str(error)))
            sys.exit(1)
    else:
        LOGGER.info("Success!")
        t_repo = response.json()

    # Use repo ID to activate Travis CI for this repo
    try:
        LOGGER.info("Activating automatic testing for you " "on Travis CI.")
        endpoint = "https://api.travis-ci.org/repo/{}/activate".format(
            url_safe_repo_name)
        response = requests.post(endpoint, headers=headers)
        response.raise_for_status()
    except HTTPError as error:
        LOGGER.critical("Unable to enable automatic testing on Travis CI! "
                        "Please refer to the following error message for "
                        "further information: {}".format(str(error)))
        sys.exit(1)

    # Check if activation was successful
    activated = False
    for _ in range(60):
        try:
            LOGGER.info("Check if activation {} on Travis CI "
                        "was successful".format(gh_repo_name))
            response = requests.get(
                "https://api.travis-ci.org/repo/{}".format(url_safe_repo_name),
                headers=headers)
        except HTTPError as error:
            LOGGER.critical(
                "An error occurred. Please refer to the following error "
                "message for further information: {}".format(str(error)))
            sys.exit(1)
        else:
            t_repo = response.json()
        if t_repo["active"]:
            activated = True
            LOGGER.info(
                "Your repository is now on GitHub and automatic testing has "
                "been enabled on Travis CI. Congrats!")
            break
        else:
            LOGGER.info("Still activating...")
            sleep(0.5)
    if not activated:
        LOGGER.critical("Unable to enable automatic testing on Travis CI! "
                        "Delete all tokens belonging to this repo at "
                        "https://github.com/settings/tokens then try running "
                        "`memote online` again. If this fails yet again, "
                        "please open an issue at "
                        "https://github.com/opencobra/memote/issues.")
        sys.exit(1)
    LOGGER.info("Encrypting GitHub token for repo '{}'.".format(gh_repo_name))
    key = te.retrieve_public_key(gh_repo_name)
    secret = te.encrypt_key(
        key, "GITHUB_TOKEN={}".format(repo_access_token).encode())
    return secret
Ejemplo n.º 2
0
def online(note, github_repository, github_username):
    """Upload the repository to GitHub and enable testing on Travis CI."""
    try:
        repo = git.Repo()
    except git.InvalidGitRepositoryError:
        LOGGER.critical(
            "The history requires a git repository in order to follow "
            "the current branch's commit history.")
        sys.exit(1)
    password = getpass("GitHub Password: "******" ")
        LOGGER.info(
            "Logged in to user '{}' created on '{}'.".format(user.login, when))
    except BadCredentialsException:
        LOGGER.critical("Incorrect username or password!")
        sys.exit(1)
    try:
        gh_repo = user.get_repo(github_repository)
        LOGGER.warning(
            "Using existing repository '{}'. This may override previous "
            "settings.".format(github_repository))
    except UnknownObjectException:
        gh_repo = user.create_repo(github_repository)
    try:
        LOGGER.info("Creating token.")
        auth = user.create_authorization(scopes=["repo"], note=note)
    except GithubException:
        LOGGER.critical(
            "A personal access token with the note '{}' already exists. "
            "Either delete it or choose another note.".format(note))
        sys.exit(1)
    try:
        LOGGER.info("Authorizing with TravisCI.")
        travis = TravisPy.github_auth(auth.token)
        t_user = travis.user()
    except TravisError:
        LOGGER.critical(
            "Something is wrong with the generated token or you did not "
            "link your GitHub account on 'https://travis-ci.org/'!")
        sys.exit(1)
    LOGGER.info("Synchronizing repositories.")
    while not t_user.sync():
        sleep(0.1)
    try:
        t_repo = travis.repo(gh_repo.full_name)
    except TravisError:
        LOGGER.critical(
            "Repository could not be found. Is it on GitHub already and "
            "spelled correctly?")
        sys.exit(1)
    if t_repo.enable():
        LOGGER.info(
            "Your repository is now on GitHub and automatic testing has "
            "been enabled on Travis CI. Congrats!")
    else:
        LOGGER.critical("Unable to enable automatic testing on Travis CI!")
        sys.exit(1)
    LOGGER.info(
        "Encrypting GitHub token for repo '{}'.".format(gh_repo.full_name))
    key = retrieve_public_key(gh_repo.full_name)
    secret = encrypt_key(key, "GITHUB_TOKEN={}".format(auth.token).encode())
    LOGGER.info("Storing GitHub token in '.travis.yml'.")
    with io.open(".travis.yml", "r") as file_h:
        config = yaml.load(file_h, yaml.RoundTripLoader)
    config["env"]["global"].append({"secure": secret})
    with io.open(".travis.yml", "w") as file_h:
        yaml.dump(config, file_h, Dumper=yaml.RoundTripDumper)
    repo.index.add([".travis.yml"])
    repo.index.commit("chore: add encrypted GitHub access token")
    repo.remotes.origin.push(all=True)
Ejemplo n.º 3
0
def test_encrypt_key(repository):
    """Test the encrypt module's encrypt_key function."""
    public_key = retrieve_public_key(repository)
    password = '******'
    encrypted_password = encrypt_key(public_key, password.encode())
    assert isinstance(encrypted_password, six.text_type)
Ejemplo n.º 4
0
def test_invalid_credentials():
    """Test that an InvalidCredentialsError is raised."""
    with pytest.raises(InvalidCredentialsError):
        retrieve_public_key("INVALID_USER_NAME/INVALID_REPO")
Ejemplo n.º 5
0
def test_public_key_retrieval(repository):
    """Test the encrypt module's retrieve_public_key function."""
    public_key = retrieve_public_key(repository)
    assert isinstance(public_key, six.text_type)
    assert 'BEGIN PUBLIC KEY' in public_key
    assert 'END PUBLIC KEY' in public_key
Ejemplo n.º 6
0
def cli(username, repository, path, password, deploy, env, clipboard,
        env_file):
    """Encrypt passwords and environment variables for use with Travis CI.

    Travis Encrypt requires as arguments the user's GitHub username and repository name.
    Once the arguments are passed, a password prompt will ask for the password that needs
    to be encrypted. The given password will then be encrypted via the PKCS1v15 padding
    scheme and printed to standard output. If the path to a .travis.yml file
    is given as an argument, the encrypted password is added to the .travis.yml file.
    """
    key = retrieve_public_key('{}/{}'.format(username, repository))
    if env_file:
        if path:
            config = load_travis_configuration(path)

            for env_var, value in dotenv_values(env_file).items():
                encrypted_env = encrypt_key(key, value.encode())
                config.setdefault('env',
                                  {}).setdefault('global', {})[env_var] = {
                                      'secure': encrypted_env
                                  }
            dump_travis_configuration(config, path)
            print('Encrypted variables from {} added to {}'.format(
                env_file, path))
        else:
            print('\nPlease add the following to your .travis.yml:')
            for env_var, value in dotenv_values(env_file).items():
                encrypted_env = encrypt_key(key, value.encode())
                print("{}:\n  secure: {}".format(env_var, encrypted_env))
        return

    encrypted_password = encrypt_key(key, password.encode())

    if path:
        config = load_travis_configuration(path)

        if deploy:
            config.setdefault('deploy',
                              {}).setdefault('password',
                                             {})['secure'] = encrypted_password

        elif env:
            try:
                config.setdefault('env', {}).setdefault(
                    'global', {})['secure'] = encrypted_password
            except TypeError:
                for item in config['env']['global']:
                    if isinstance(item, dict) and 'secure' in item:
                        item['secure'] = encrypted_password

        else:
            config.setdefault('password', {})['secure'] = encrypted_password

        dump_travis_configuration(config, path)

        print('Encrypted password added to {}'.format(path))
    elif clipboard:
        pyperclip.copy(encrypted_password)
        print('\nThe encrypted password has been copied to your clipboard.')
    else:
        print('\nPlease add the following to your .travis.yml:\nsecure: {}'.
              format(encrypted_password))
Ejemplo n.º 7
0
def _setup_travis_ci(gh_repo_name, auth_token, repo_access_token):
    # travis-ci.org is the open source endpoint only! We will need to hit
    # travis-ci.com for private projects!

    # Headers for API v2. This is only necessary because generating a Travis
    # API token from a GitHub Token isn't possible in the API v3 yet. This way
    # is recommended as per:
    # https://github.com/travis-ci/travis-ci/issues/9273
    headers_v2_only = {
        'User-Agent': 'Memote',
        'Accept': 'application/vnd.travis-ci.2+json',
    }

    # Generate Travis API token:
    try:
        LOGGER.info("Generating Travis API token.")
        response = requests.post(
            "https://api.travis-ci.org/auth/github",
            headers=headers_v2_only,
            data={'github_token': auth_token}
        )
        response.raise_for_status()
    except HTTPError as error:
        LOGGER.critical(
            "Something is wrong with the generated APIv3 authentication token "
            "or you did not link your GitHub account on "
            "'https://travis-ci.org/'? Please refer to the following error "
            "message for further information: {}".format(str(error)))
        sys.exit(1)
    else:
        LOGGER.info("Success!")
        travis_api_token = response.json()["access_token"]

    # Headers for API v3!
    headers = {
        'Travis-API-Version': '3',
        'Authorization': 'token {}'.format(travis_api_token),
        'User-Agent': 'Memote Query'
    }

    # Authenticate the User on Travis
    try:
        LOGGER.info("Authorizing with TravisCI.")
        response = requests.get(
            "https://api.travis-ci.org/user", headers=headers
        )
        response.raise_for_status()
    except HTTPError as error:
        LOGGER.critical(
            "Something is wrong with the generated token or you did not "
            "link your GitHub account on 'https://travis-ci.org/'? Please "
            "refer to the following error code for "
            "further information:".format(str(error)))
        sys.exit(1)
    else:
        LOGGER.info("Success!")
        t_user = response.json()

    # Synchronize a User's projects between GitHub and Travis
    LOGGER.info("Synchronizing user projects between GitHub and Travis.")
    synced = False
    for _ in range(60):
        response = requests.post(
            "https://api.travis-ci.org/user/{}/sync".format(t_user["id"]),
            headers=headers
        )
        if response.status_code == 200:
            synced = True
            LOGGER.info("Success!")
            break
        else:
            LOGGER.info("Still synchronizing...")
            sleep(0.5)
    if not synced:
        LOGGER.critical(
            "Could not synchronize your projects between GitHub and Travis!"
            "The latest response code is {}".format(response.status_code))
        sys.exit(1)

    # Make sure GitHub repo can be found on Travis CI.#
    url_safe_repo_name = quote_plus(gh_repo_name)
    try:
        LOGGER.info("Find repository {} on Travis CI".format(gh_repo_name))
        response = requests.get(
            "https://api.travis-ci.org/repo/{}".format(url_safe_repo_name),
            headers=headers
        )
        response.raise_for_status()
    except HTTPError as error:
        if error.response.status_code == 404:
            LOGGER.critical(
                "Repository could not be found. Is it on GitHub already and "
                "spelled correctly?")
            sys.exit(1)
        else:
            LOGGER.critical(
                "An error occurred. Please refer to the following error "
                "message for further information: {}".format(str(error)))
            sys.exit(1)
    else:
        LOGGER.info("Success!")
        t_repo = response.json()

    # Use repo ID to activate Travis CI for this repo
    try:
        LOGGER.info(
            "Activating automatic testing for you "
            "on Travis CI.")
        endpoint = "https://api.travis-ci.org/repo/{}/activate".format(
            url_safe_repo_name
        )
        response = requests.post(
            endpoint,
            headers=headers
        )
        response.raise_for_status()
    except HTTPError as error:
        LOGGER.critical("Unable to enable automatic testing on Travis CI! "
                        "Please refer to the following error message for "
                        "further information: {}".format(str(error)))
        sys.exit(1)

    # Check if activation was successful
    activated = False
    for _ in range(60):
        try:
            LOGGER.info("Check if activation {} on Travis CI "
                        "was successful".format(gh_repo_name))
            response = requests.get(
                "https://api.travis-ci.org/repo/{}".format(url_safe_repo_name),
                headers=headers
            )
        except HTTPError as error:
            LOGGER.critical(
                "An error occurred. Please refer to the following error "
                "message for further information: {}".format(str(error)))
            sys.exit(1)
        else:
            t_repo = response.json()
        if t_repo["active"]:
            activated = True
            LOGGER.info(
                "Your repository is now on GitHub and automatic testing has "
                "been enabled on Travis CI. Congrats!")
            break
        else:
            LOGGER.info("Still activating...")
            sleep(0.5)
    if not activated:
        LOGGER.critical("Unable to enable automatic testing on Travis CI! "
                        "Delete all tokens belonging to this repo at "
                        "https://github.com/settings/tokens then try running "
                        "`memote online` again. If this fails yet again, "
                        "please open an issue at "
                        "https://github.com/opencobra/memote/issues.")
        sys.exit(1)
    LOGGER.info(
        "Encrypting GitHub token for repo '{}'.".format(gh_repo_name))
    key = te.retrieve_public_key(gh_repo_name)
    secret = te.encrypt_key(
        key, "GITHUB_TOKEN={}".format(repo_access_token).encode()
    )
    return secret