Skip to content

Post the SCA report to GitLab merge requests, not only GitHub pull requests - #378

Merged
haksungjang merged 1 commit into
mainfrom
er47-gitlab-mr-comment
Sep 4, 2026
Merged

Post the SCA report to GitLab merge requests, not only GitHub pull requests#378
haksungjang merged 1 commit into
mainfrom
er47-gitlab-mr-comment

Conversation

@haksungjang

Copy link
Copy Markdown
Contributor

A GitLab shop got the build gate and nothing else. The shipped templates/gitlab-ci.yml already staged the comment request and the backend only knew api.github.com, so the job ran, got a 404, and warned. The documentation said so plainly, which made it an unfinished feature rather than a defect, but for a self-hosted organisation on GitLab it is half of the CI integration.

POST /v1/scans/{id}/post-pr-comment now takes a provider, and the template sends gitlab.

Two implementations rather than an interface over both, and that is the design decision worth reviewing. They differ in the auth header (PRIVATE-TOKEN against a bearer), in the verb an update uses (PUT against PATCH), and in whether a comment is addressed on its own or under the request it belongs to. Those are exactly the places an interface leaks, and a framework written now would be shaped by whichever of the two came first. A third forge is the moment to look at what two real implementations share.

The default is the part that needed a decision. provider defaults to github, because every caller before this was GitHub and making the field required would break them. That leaves the case where a GitLab pipeline omits it and receives a GitHub error naming a project it never mentioned. So the response carries provider_assumed, set from model_fields_set rather than from the value, and the GitLab template sends the field explicitly so nobody new meets it. The assumption is reasonable; an unstated one is not.

GITLAB_API_BASE is configurable where GITHUB_API_BASE is a constant. The asymmetry is not an oversight: a self-hosted GitLab is the ordinary case for the deployments this is for, while GitHub Enterprise Server needs more than a base URL and is not supported, so opening one and leaving the other says what is true instead of what is symmetrical. The constant now carries a note explaining why, which is where somebody adding Enterprise support will look. An instance behind an internal certificate authority is configured like every other outbound call, and the GitLab CI page points at that page.

repo_full_name is validated per provider instead of by one looser pattern. GitHub is owner/repo and nothing longer; GitLab is a full path through however many groups the project nests under. A single permissive pattern would accept a/b/c on the GitHub path, which is not a repository. The field name still says repo and the route still says pr, and both stay: the surface speaks GitHub throughout, and changing the field without the path would leave half of it neutral, which reads worse than consistent. The field description carries the per-provider format, because the name no longer states it.

Depends on the webhook activation fix that just merged, in the sense that it establishes webhook_provider as a column deployments actually populate. This pull request does not read it: the provider comes from the request, because a project can use CI without a webhook at all, and those are precisely the users this serves.

Verified: mypy over 918 files, ruff, 69 tests across the comment service, the gate API, the config-key contract and the webhook activation. Reversing each provider-specific choice fails a different test: PATCH instead of PUT, a bearer instead of PRIVATE-TOKEN, and leaving the project path unencoded so its slashes become path segments.

Not verified, and the tests say so where a reader will meet it: the mocked responses were written from GitLab's REST documentation and have not been run against a live instance. The fixtures carry every field that documentation lists rather than the three this code reads, so a real thread with system notes and author objects is what the parser walks. A field GitLab renamed, or an error shape the documentation does not show, would pass here and fail on first contact.

…quests

The GitLab CI template already staged the request and the backend only knew
api.github.com, so a GitLab shop got the build gate and a 404 where the comment
should have been. The endpoint now takes a provider and the template sends it.

Two implementations rather than an interface over both. They differ in the auth
header, in the verb an update uses, and in whether a comment is addressed on
its own or under the request it belongs to, which are the three places an
abstraction would leak. A third forge is the time to look at what two of them
have in common.

The provider defaults to github so existing integrations keep working, and the
response reports when the default was used: an unstated assumption leaves a
GitLab pipeline reading a GitHub error about a project it never named.

GITLAB_API_BASE is configurable where GitHub's base is a constant, because a
self-hosted GitLab is the ordinary case and GitHub Enterprise needs more than a
base URL. The path is validated per provider: one pattern loose enough for
GitLab's nested groups would accept a/b/c as a GitHub repository.

The mocked responses carry every field the API documents rather than the three
this reads, and the tests record that they came from documentation and have not
met a live instance.
@haksungjang
haksungjang merged commit a8d235e into main Sep 4, 2026
30 checks passed
@haksungjang
haksungjang deleted the er47-gitlab-mr-comment branch September 4, 2026 23:12
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.

1 participant