← 返回首页
fix: make secret helper more user friendly · python-gitlab/python-gitlab@fc2798f · GitHub
Skip to content

Navigation Menu

Toggle navigation
Sign in
Appearance settings
Search or jump to...

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Include my email address so I can be contacted

Saved searches

Use saved searches to filter your results more quickly

Appearance settings
Resetting focus

Commit fc2798f

Browse files
committed
fix: make secret helper more user friendly
1 parent b04dd2c commit fc2798f

3 files changed

Lines changed: 63 additions & 21 deletions

File tree

‎docs/cli-usage.rst‎

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ example:
4848
4949
[elsewhere]
5050
url = http://else.whe.re:8080
51-
private_token = lookup: pass show path/to/password | head -n1
51+
private_token = helper: path/to/helper.sh
5252
timeout = 1
5353
5454
The ``default`` option of the ``[global]`` section defines the GitLab server to
@@ -119,6 +119,27 @@ server, with very limited permissions.
119119
* - ``http_password``
120120
- Password for optional HTTP authentication
121121

122+
For all settings, which contain secrets (``http_password``,
123+
``personal_token``, ``oauth_token``, ``job_token``), you can specify
124+
a helper program to retrieve the secret indicated by ``helper:``
125+
prefix. You can only specify a path to a program without any
126+
parameters. It is expected, that the program prints the secret to
127+
standard output.
128+
129+
Example for a `keyring <https://github.com/jaraco/keyring>`_ helper:
130+
131+
.. code-block:: bash
132+
133+
#!/bin/bash
134+
keyring get Service Username
135+
136+
Example for a `pass <https://www.passwordstore.org>`_ helper:
137+
138+
.. code-block:: bash
139+
140+
#!/bin/bash
141+
pass show path/to/password | head -n 1
142+
122143
CLI
123144
===
124145

‎gitlab/config.py‎

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ def _env_config() -> List[str]:
3434
os.path.expanduser("~/.python-gitlab.cfg"),
3535
]
3636

37+
HELPER_PREFIX = "helper:"
38+
39+
HELPER_ATTRIBUTES = [
40+
"job_token", "http_password", "private_token", "oauth_token"
41+
]
3742

3843
class ConfigError(Exception):
3944
pass
@@ -151,15 +156,7 @@ def __init__(
151156
except Exception:
152157
pass
153158

154-
for attr in ("job_token", "http_password", "private_token", "oauth_token"):
155-
value = getattr(self, attr)
156-
prefix = "lookup:"
157-
if isinstance(value, str) and value.lower().strip().startswith(prefix):
158-
helper = value[len(prefix) :].strip()
159-
value = (
160-
subprocess.check_output(helper, shell=True).decode("utf-8").strip()
161-
)
162-
setattr(self, attr, value)
159+
self._get_values_from_helper()
163160

164161
self.api_version = "4"
165162
try:
@@ -203,3 +200,13 @@ def __init__(
203200
self.user_agent = self._config.get(self.gitlab_id, "user_agent")
204201
except Exception:
205202
pass
203+
204+
def _get_values_from_helper(self):
205+
"""Update attributes, which may get values from an external helper program
206+
"""
207+
for attr in HELPER_ATTRIBUTES:
208+
value = getattr(self, attr)
209+
if isinstance(value, str) and value.lower().strip().startswith(HELPER_PREFIX):
210+
helper = value[len(HELPER_PREFIX) :].strip()
211+
value = subprocess.check_output([helper]).decode("utf-8").strip()
212+
setattr(self, attr, value)

‎gitlab/tests/test_config.py‎

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import os
1919
import unittest
20+
from textwrap import dedent
2021

2122
import mock
2223
import io
@@ -51,10 +52,6 @@
5152
[four]
5253
url = https://four.url
5354
oauth_token = STUV
54-
55-
[five]
56-
url = https://five.url
57-
oauth_token = lookup: echo "foobar"
5855
"""
5956

6057
custom_user_agent_config = """[global]
@@ -196,16 +193,33 @@ def test_valid_data(m_open, path_exists):
196193
assert 2 == cp.timeout
197194
assert True == cp.ssl_verify
198195

199-
fd = io.StringIO(valid_config)
196+
197+
@mock.patch("os.path.exists")
198+
@mock.patch("builtins.open")
199+
def test_data_from_helper(m_open, path_exists, tmp_path):
200+
helper = (tmp_path / "helper.sh")
201+
helper.write_text(dedent("""\
202+
#!/bin/sh
203+
echo "secret"
204+
"""))
205+
helper.chmod(0o755)
206+
207+
fd = io.StringIO(dedent("""\
208+
[global]
209+
default = helper
210+
211+
[helper]
212+
url = https://helper.url
213+
oauth_token = helper: %s
214+
""") % helper)
215+
200216
fd.close = mock.Mock(return_value=None)
201217
m_open.return_value = fd
202-
cp = config.GitlabConfigParser(gitlab_id="five")
203-
assert "five" == cp.gitlab_id
204-
assert "https://five.url" == cp.url
218+
cp = config.GitlabConfigParser(gitlab_id="helper")
219+
assert "helper" == cp.gitlab_id
220+
assert "https://helper.url" == cp.url
205221
assert None == cp.private_token
206-
assert "foobar" == cp.oauth_token
207-
assert 2 == cp.timeout
208-
assert True == cp.ssl_verify
222+
assert "secret" == cp.oauth_token
209223

210224

211225
@mock.patch("os.path.exists")

0 commit comments

Comments
 (0)

Footer

© 2026 GitHub, Inc.