feat(gitlab): system hooks, project allowlist, internal URL, encrypted secrets (v0.9.47) - #135
Merged
Conversation
…d secrets (v0.9.47)
One admin-level GitLab System Hook now drives reviews for every project on
an instance, with per-platform project filtering and dual-network URLs.
System Hook support:
- X-Gitlab-Event: System Hook payloads are routed by event type
(GitLab 19+ sends event_type; older versions event_name; event_name
preferred), mapping merge_request/note/push to the existing handlers.
- Instance-URL extraction falls back project.web_url -> project.homepage
-> repository.homepage -> object_attributes.url, since system-hook
payloads carry no project.web_url; MR/Note handlers read the full MR
URL from object_attributes.url.
- Verified end-to-end against GitLab EE 19.2.4 (local Docker testbed):
signed system hook -> verification -> routing -> full 11-expert review
-> notes posted back to the MR.
Project allowlist (allowedProjects / allowed_projects):
- path_with_namespace allowlist gates webhook-triggered MR/Note reviews;
non-listed projects get 200 {"status":"ignored",...}. Hot-effective
via PUT /config, no restart. Empty = all projects. REST gitlab_mr
routing unaffected.
Dual-network URLs (internalBaseUrl / internal_base_url):
- base_url (external) identifies the instance for webhook verification;
the optional internal URL is used for review-time GitLab API fetches
(container-reachable endpoint, e.g. host.docker.internal or an in-net
NAS address) where the external port-mapped URL is unreachable. Falls
back internal -> base_url -> payload URL.
Encrypted secrets at rest:
- token/webhook_secret/webhook_signing_secret encrypted in ui-state.toml
as enc:<base64(nonce||ct||tag)> (ChaCha20-Poly1305) under a per-config
secrets.key (32B, 0600, auto-created). Legacy plaintext loads
transparently and is encrypted on next save; missing key on encrypted
values is a hard error pointing at re-entry in the Web UI.
env/CLI deprecation:
- ui-state.toml is the authoritative source for GitLab credentials;
GITLAB_TOKEN/GITLAB_WEBHOOK_*/--gitlab-* are fallback-only (used only
when the file lacks a value) with deprecation warnings.
Docs: integrations/gitlab.md (System Hook + filtering + internal URL),
configuration.md, config-schema.md, faq.md, rest-api.md. Frontend:
allowed projects + internal URL fields, 6 locales.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
One admin-level GitLab System Hook now drives reviews for every project on an instance, with per-platform project filtering, dual-network (external/internal) URLs, and secrets encrypted at rest.
What's in
X-Gitlab-Event: System Hookrouted by event type — GitLab 19+ sendsevent_type, older versionsevent_name(both supported). Payload URL extraction falls backproject.web_url→project.homepage→repository.homepage→object_attributes.url(system-hook payloads carry noproject.web_url).allowedProjectsper platform; non-listed projects get200 ignored; hot-effective via PUT /config.internalBaseUrl(optional): payload URL (external) matches the platform for verification; internal URL (container-reachable) is used for review-time GitLab API fetches. Falls back internal → base_url → payload URL.token/webhook secrets encrypted at rest (enc:prefix, ChaCha20-Poly1305,secrets.key0600); legacy plaintext auto-migrates on next save.ui-state.tomlauthoritative;GITLAB_TOKEN/GITLAB_WEBHOOK_*/flags are fallback-only with deprecation warnings.Verification (per user requirement: local E2E BEFORE PR)
Full chain verified against a local GitLab EE 19.2.4 Docker testbed with a real MR:
event_typerouting → MR dispatch (this exposed a real bug: GitLab 19.2 sendsevent_type, notevent_name— fixed with fallback)host.docker.internal:8929(exposed another real bug: payloadexternal_urlis unreachable from the reng container — fixed)allowedProjects=[other/project]→MR hook ignored: project not in allowlist; restored → review runs again (dispatcher dedup on same SHA)enc:values,secrets.key0600Checks
cargo fmt --check/cargo clippy --all-targets --all-features: cleancargo test(single-threaded): 1548 passed, 0 failed (9 new system-hook tests, 6 internal-URL tests, encryption roundtrip/migration tests, allowlist tests)