runspec-gitlab-core 0.3.0__tar.gz → 0.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -59,3 +59,6 @@ chainlit-docs/
59
59
 
60
60
  # Stray committed test venv (removed from tracking)
61
61
  .venv-test/
62
+
63
+ # Private gitleaks rules (see .gitleaks.toml)
64
+ .gitleaks.local.toml
@@ -2,6 +2,14 @@
2
2
 
3
3
  All notable changes to `runspec-gitlab-core` are documented here.
4
4
 
5
+ ## [0.4.0] — 2026-10-25
6
+
7
+ - `config_from_env` reads the token from `GITLAB_TOKEN` or `GITLAB_PAT` (each
8
+ also under the `GITLAB_<ENV>_` prefix) — the two names a runspec-console token
9
+ credential labelled `GitLab` sets — and takes `url` / `token` keyword
10
+ overrides that win over the environment.
11
+ - The "No token configured" error also names the console credential route.
12
+
5
13
  ## [0.3.0]
6
14
 
7
15
  Write helpers, each taking a `GitlabConfig` first like the reads.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: runspec-gitlab-core
3
- Version: 0.3.0
3
+ Version: 0.4.0
4
4
  Summary: Pure-Python GitLab REST helpers — the importable core behind runspec-gitlab (no runspec dependency, no runnables)
5
5
  Requires-Python: >=3.10
6
6
  Requires-Dist: httpx
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "runspec-gitlab-core"
7
- version = "0.3.0"
7
+ version = "0.4.0"
8
8
  requires-python = ">=3.10"
9
9
  description = "Pure-Python GitLab REST helpers — the importable core behind runspec-gitlab (no runspec dependency, no runnables)"
10
10
  dependencies = [
@@ -7,7 +7,7 @@ credentials and call the same functions the CLI runnable's verbs call.
7
7
 
8
8
  Auth is environment-variable driven (see :func:`config_from_env`) but a caller is
9
9
  free to build a :class:`GitlabConfig` by hand. A single personal-access token
10
- (``GITLAB_TOKEN``) is sent as the ``PRIVATE-TOKEN`` header; the instance URL
10
+ (``GITLAB_TOKEN`` or ``GITLAB_PAT``) is sent as the ``PRIVATE-TOKEN`` header; the instance URL
11
11
  (``GITLAB_URL``) defaults to ``https://gitlab.com`` for the SaaS case.
12
12
 
13
13
  This mirrors the read tools of GitLab's own (hosted) MCP server, but ports them
@@ -65,13 +65,16 @@ def _env_first(names: list[str]) -> str | None:
65
65
  return None
66
66
 
67
67
 
68
- def config_from_env(env: str | None = None) -> GitlabConfig:
68
+ def config_from_env(env: str | None = None, *, url: str | None = None, token: str | None = None) -> GitlabConfig:
69
69
  """Build a :class:`GitlabConfig` from environment variables.
70
70
 
71
71
  When ``env`` (or the ``GITLAB_ENV`` variable) selects dev/uat/prod, the
72
72
  environment-prefixed variables are read first (e.g. ``GITLAB_UAT_TOKEN``),
73
73
  falling back to the unprefixed ``GITLAB_*`` family for single-instance
74
- setups. ``GITLAB_URL`` defaults to ``https://gitlab.com`` when unset. Raises
74
+ setups. The token is read from ``GITLAB_TOKEN`` or ``GITLAB_PAT`` (the two
75
+ names a runspec-console token credential labelled ``GitLab`` sets).
76
+ ``GITLAB_URL`` defaults to ``https://gitlab.com`` when unset. Explicit
77
+ ``url`` / ``token`` arguments win over the environment. Raises
75
78
  :class:`GitlabError` with an actionable message when the env label is invalid
76
79
  or the token is missing.
77
80
  """
@@ -81,19 +84,19 @@ def config_from_env(env: str | None = None) -> GitlabConfig:
81
84
  if env not in VALID_ENVS:
82
85
  raise GitlabError(f"Invalid env {env!r} — expected one of {', '.join(VALID_ENVS)}")
83
86
 
84
- def lookup(suffix: str) -> str | None:
87
+ def lookup(*suffixes: str) -> str | None:
85
88
  names = []
86
89
  if env:
87
- names.append(f"GITLAB_{env.upper()}_{suffix}")
88
- names.append(f"GITLAB_{suffix}")
90
+ names += [f"GITLAB_{env.upper()}_{suffix}" for suffix in suffixes]
91
+ names += [f"GITLAB_{suffix}" for suffix in suffixes]
89
92
  return _env_first(names)
90
93
 
91
- token = lookup("TOKEN")
94
+ token = token or lookup("TOKEN", "PAT")
92
95
  if not token:
93
96
  hint = f"GITLAB_{env.upper()}_TOKEN" if env else "GITLAB_TOKEN"
94
- raise GitlabError(f"No token configured — set {hint} (a GitLab personal access token)")
97
+ raise GitlabError(f"No token configured — set {hint} (a GitLab personal access token), or add a runspec-console token credential labelled GitLab")
95
98
 
96
- base_url = lookup("URL") or DEFAULT_URL
99
+ base_url = url or lookup("URL") or DEFAULT_URL
97
100
 
98
101
  return GitlabConfig(
99
102
  base_url=base_url.rstrip("/"),
@@ -9,7 +9,7 @@ import pytest
9
9
 
10
10
  from runspec_gitlab_core import client as client_mod
11
11
 
12
- _SUFFIXES = ("URL", "TOKEN", "PROJECT")
12
+ _SUFFIXES = ("URL", "TOKEN", "PAT", "PROJECT")
13
13
  _ALL_VARS = ["GITLAB_ENV"] + [f"GITLAB_{s}" for s in _SUFFIXES]
14
14
  for _env in ("DEV", "UAT", "PROD"):
15
15
  _ALL_VARS += [f"GITLAB_{_env}_{s}" for s in _SUFFIXES]
@@ -68,6 +68,30 @@ def test_missing_token_raises(monkeypatch):
68
68
  # ── encode_project ──────────────────────────────────────────────────────────
69
69
 
70
70
 
71
+ def test_token_read_from_gitlab_pat(monkeypatch):
72
+ # A runspec-console token credential labelled "GitLab" sets GITLAB_TOKEN and GITLAB_PAT.
73
+ monkeypatch.setenv("GITLAB_PAT", "pat-tok")
74
+ assert config_from_env().token == "pat-tok"
75
+
76
+
77
+ def test_env_prefixed_pat_beats_unprefixed_token(monkeypatch):
78
+ monkeypatch.setenv("GITLAB_TOKEN", "shared")
79
+ monkeypatch.setenv("GITLAB_UAT_PAT", "uat-pat")
80
+ assert config_from_env(env="uat").token == "uat-pat"
81
+
82
+
83
+ def test_explicit_url_and_token_win(monkeypatch):
84
+ monkeypatch.setenv("GITLAB_TOKEN", "env-tok")
85
+ monkeypatch.setenv("GITLAB_URL", "https://env.example.com")
86
+ cfg = config_from_env(url="https://cli.example.com/", token="cli-tok")
87
+ assert (cfg.base_url, cfg.token) == ("https://cli.example.com", "cli-tok")
88
+
89
+
90
+ def test_missing_token_names_the_console_credential(monkeypatch):
91
+ with pytest.raises(GitlabError, match="credential labelled GitLab"):
92
+ config_from_env()
93
+
94
+
71
95
  def test_encode_project_path():
72
96
  assert encode_project("group/sub/app") == "group%2Fsub%2Fapp"
73
97