Skip to content

Commit

Permalink
chore(config): allow simple commands without external script
Browse files Browse the repository at this point in the history
  • Loading branch information
klorenz authored and nejch committed Apr 18, 2021
1 parent 7a7c9fd commit 91ffb8e
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 16 deletions.
50 changes: 40 additions & 10 deletions docs/cli-usage.rst
Expand Up @@ -93,6 +93,8 @@ Only one of ``private_token``, ``oauth_token`` or ``job_token`` should be
defined. If neither are defined an anonymous request will be sent to the Gitlab
server, with very limited permissions.

We recommend that you use `Credential helpers`_ to securely store your tokens.

.. list-table:: GitLab server options
:header-rows: 1

Expand All @@ -119,22 +121,50 @@ server, with very limited permissions.
* - ``http_password``
- Password for optional HTTP authentication

For all settings, which contain secrets (``http_password``,

Credential helpers
------------------

For all configuration options that contain secrets (``http_password``,
``personal_token``, ``oauth_token``, ``job_token``), you can specify
a helper program to retrieve the secret indicated by ``helper:``
prefix. You can only specify a path to a program without any
parameters. You may use ``~`` for expanding your homedir in helper
program's path. It is expected, that the program prints the secret
to standard output.
a helper program to retrieve the secret indicated by a ``helper:``
prefix. This allows you to fetch values from a local keyring store
or cloud-hosted vaults such as Bitwarden. Environment variables are
expanded if they exist and ``~`` expands to your home directory.

It is expected that the helper program prints the secret to standard output.
To use shell features such as piping to retrieve the value, you will need
to use a wrapper script; see below.

Example for a `keyring <https://github.com/jaraco/keyring>`_ helper:

.. code-block:: bash
.. code-block:: ini
#!/bin/bash
keyring get Service Username
[global]
default = somewhere
ssl_verify = true
timeout = 5
[somewhere]
url = http://somewhe.re
private_token = helper: keyring get Service Username
timeout = 1
Example for a `pass <https://www.passwordstore.org>`_ helper with a wrapper script:

.. code-block:: ini
[global]
default = somewhere
ssl_verify = true
timeout = 5
[somewhere]
url = http://somewhe.re
private_token = helper: /path/to/helper.sh
timeout = 1
Example for a `pass <https://www.passwordstore.org>`_ helper:
In `/path/to/helper.sh`:

.. code-block:: bash
Expand Down
33 changes: 27 additions & 6 deletions gitlab/config.py
Expand Up @@ -17,9 +17,10 @@

import os
import configparser
import shlex
import subprocess
from typing import List, Optional, Union
from os.path import expanduser
from os.path import expanduser, expandvars

from gitlab.const import USER_AGENT

Expand Down Expand Up @@ -56,6 +57,10 @@ class GitlabConfigMissingError(ConfigError):
pass


class GitlabConfigHelperError(ConfigError):
pass


class GitlabConfigParser(object):
def __init__(
self, gitlab_id: Optional[str] = None, config_files: Optional[List[str]] = None
Expand Down Expand Up @@ -202,13 +207,29 @@ def __init__(
pass

def _get_values_from_helper(self):
"""Update attributes, which may get values from an external helper program"""
"""Update attributes that may get values from an external helper program"""
for attr in HELPER_ATTRIBUTES:
value = getattr(self, attr)
if not isinstance(value, str):
continue

if value.lower().strip().startswith(HELPER_PREFIX):
helper = expanduser(value[len(HELPER_PREFIX) :].strip())
value = subprocess.check_output([helper]).decode("utf-8").strip()
setattr(self, attr, value)
if not value.lower().strip().startswith(HELPER_PREFIX):
continue

helper = value[len(HELPER_PREFIX) :].strip()
commmand = [expanduser(expandvars(token)) for token in shlex.split(helper)]

try:
value = (
subprocess.check_output(commmand, stderr=subprocess.PIPE)
.decode("utf-8")
.strip()
)
except subprocess.CalledProcessError as e:
stderr = e.stderr.decode().strip()
raise GitlabConfigHelperError(
f"Failed to read {attr} value from helper "
f"for {self.gitlab_id}:\n{stderr}"
) from e

setattr(self, attr, value)

0 comments on commit 91ffb8e

Please sign in to comment.