Skip to content

Use Bearer authentication to support fine-grained GitLab PATs - #381

Merged
mglaman merged 1 commit into
mglaman:mainfrom
balintbrews:fix/gitlab-bearer-auth
Sep 16, 2026
Merged

mglaman merged 1 commit into
mglaman:mainfrom
balintbrews:fix/gitlab-bearer-auth

Conversation

@balintbrews

@balintbrews balintbrews commented Sep 16, 2026 •

Copy link
Copy Markdown

Send GitLab API tokens using Authorization: Bearer instead of PRIVATE-TOKEN to support fine-grained PATs. GitLab also supports Bearer authentication for classic PATs, so no separate mode is needed.

Token resolution is unchanged: DRUPALORG_GITLAB_TOKEN takes precedence over the existing glab fallback.

Testing

With both classic and fine-grained PATs:

  • Read an issue, MR, pipeline status, and failed-job logs.
  • Post unassign/reassign notes on an approved work item.
  • Confirm the classic token also works through the glab fallback.

Verify note creation separately from bot-applied changes, which may be delayed.

@mglaman
mglaman merged commit 836ec96 into mglaman:main Sep 16, 2026
9 checks passed
mglaman added a commit that referenced this pull request Sep 22, 2026
* test: assert on the requests the GitLab client sends

Both HTTP clients accept an optional HandlerStack. When one is passed
it still gets the retry middleware, the default headers, and the
base_uri, so a test can build the stack around a MockHandler plus
Guzzle's history middleware and inspect what was actually sent.

The new GitLab client test covers the gap #381 exposed: the Bearer
header, the User-Agent and Accept headers, the unauthenticated case,
project path encoding, note pagination, the concurrent
getIssuesByIid() fan-out, the JSON body of a slash command note, and a
503 recovered by the retry middleware.

Refs #382

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* test: assert on the requests the Drupal.org client sends

Replace the anonymous subclass that swapped in a bare Guzzle client
with the HandlerStack the constructor now accepts. The client under
test keeps its headers, base_uri, cookie jar, and retry middleware, so
the test can cover the default headers, the --no-cache headers, cookie
persistence across requests, the request URLs, and a 503 recovered by
the retry middleware.

Refs #382

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* fix: fail with an exception when no git repository is found

initRepo() called exit(1) from inside the command, which no test can
observe. It also never reached that branch: when git rev-parse fails
its output is empty, and realpath('') is the current directory, so
GitRepository opened a non-repository without complaint and the
failure surfaced later as an unrelated GitException.

Check the git process result and throw a RuntimeException. The console
application renders the message and exits 1, so the user-facing exit
code is unchanged.

Refs #382

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* test: run IssueCommandBase::initialize() against a temporary git repository

Each test runs a throwaway command inside a fresh temporary directory,
with or without a git repository in it, and asserts on the nid, the
work item reference, and whether the repository was opened.

This covers the regression fixed in #385, where a project#nid or work
item URL argument returned before initRepo() ran, along with reading
the nid from the branch name and both failure messages.

Refs #382

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants