Skip to content

feat(gitlab-webhook): add token validation for webhook requests#194

Merged
flc1125 merged 2 commits intov2.xfrom
token
Nov 13, 2025
Merged

feat(gitlab-webhook): add token validation for webhook requests#194
flc1125 merged 2 commits intov2.xfrom
token

Conversation

@flc1125
Copy link
Copy Markdown
Owner

@flc1125 flc1125 commented Nov 13, 2025

Summary by CodeRabbit

  • New Features

    • Added token-based validation for webhook requests to verify authenticity before processing.
  • Documentation

    • Updated docs and examples to show how to provide an optional token for request validation.
  • Tests

    • Added tests covering valid tokens, invalid tokens, missing tokens, and successful dispatch when no token is configured.

@dosubot dosubot bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Nov 13, 2025
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Nov 13, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Token-based request validation is added to the webhook dispatcher. A new DispatchRequestWithToken option allows callers to provide a security token, which is validated against the X-Gitlab-Token header before webhook dispatch. A corresponding ErrInvalidToken error is introduced for validation failures.

Changes

Cohort / File(s) Change Summary
Core token validation implementation
dispatcher.go
Adds DispatchRequestWithToken(token string) dispatch option; extends internal options with a token field; adds header extraction and constant-time comparison of X-Gitlab-Token in DispatchRequest; returns ErrInvalidToken on mismatch; introduces public ErrInvalidToken.
Token validation tests
dispatcher_test.go
Adds TestDispatcher_DispatchRequestWithToken covering: valid token (dispatches), invalid token (returns ErrInvalidToken, no dispatch), missing header with token configured (returns ErrInvalidToken), and no token configured (dispatches). Adds simpleTestListener test helper and invocation assertions.
Documentation update
README.md
Updates feature list to mention token-based validation and example usage showing DispatchRequestWithToken("your-secret-token") passed to Dispatcher.DispatchRequest.

Sequence Diagram

sequenceDiagram
    participant Caller
    participant Dispatcher
    participant Validator as Token Validator
    participant Listener

    Caller->>Dispatcher: DispatchRequest(req, DispatchRequestWithToken(token))
    Dispatcher->>Validator: Read X-Gitlab-Token header

    alt Token configured
        alt Header present
            Validator->>Validator: constant-time compare(header, token)
            alt Match
                Validator-->>Dispatcher: valid
                Dispatcher->>Listener: invoke OnPush()
                Listener-->>Dispatcher: handled
                Dispatcher-->>Caller: success
            else Mismatch
                Validator-->>Dispatcher: ErrInvalidToken
                Dispatcher-->>Caller: ErrInvalidToken
            end
        else Header missing
            Validator-->>Dispatcher: ErrInvalidToken
            Dispatcher-->>Caller: ErrInvalidToken
        end
    else No token configured
        Dispatcher->>Listener: invoke OnPush()
        Listener-->>Dispatcher: handled
        Dispatcher-->>Caller: success
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Areas to review closely:
    • Correct use of constant-time comparison and header extraction in dispatcher.go.
    • Error handling paths to ensure payload is not processed when token validation fails.
    • Tests in dispatcher_test.go for isolation and accurate assertions of listener invocation.

"I hopped through headers, soft and quick,
A secret token tucked in my kit.
If it matches true, I sing — dispatch!
If not, I pause, and guard the stash.
— 🐇"

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main feature addition: token validation for webhook requests, which is reflected across all modified files (README updates, new validation logic in dispatcher.go, and comprehensive tests).
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch token

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello @flc1125, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a significant security enhancement by adding token validation for incoming GitLab webhook requests. It allows users to configure a secret token, which the dispatcher will then verify against the X-Gitlab-Token header in the request. Any requests with invalid or missing tokens will be rejected, ensuring that only legitimate webhook payloads are processed and improving the overall security posture of the webhook dispatcher.

Highlights

  • Security Enhancement: Added token validation for GitLab webhook requests to ensure that only authenticated requests are processed, significantly improving security.
  • New Configuration Option: Introduced a new DispatchRequestWithToken option, allowing users to easily configure and enable token validation for their webhook dispatchers.
  • Documentation Update: Updated the README.md file to include documentation and an example demonstrating how to utilize the new token validation feature.
  • Comprehensive Testing: Implemented a dedicated test suite (TestDispatcher_DispatchRequestWithToken) to thoroughly cover various token validation scenarios, including valid, invalid, and missing tokens.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@codecov
Copy link
Copy Markdown

codecov bot commented Nov 13, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 92.27%. Comparing base (4528705) to head (9520843).
⚠️ Report is 9 commits behind head on v2.x.

Additional details and impacted files
@@            Coverage Diff             @@
##             v2.x     #194      +/-   ##
==========================================
- Coverage   94.73%   92.27%   -2.47%     
==========================================
  Files           1        1              
  Lines         190      207      +17     
==========================================
+ Hits          180      191      +11     
- Misses          8       11       +3     
- Partials        2        5       +3     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a valuable feature for validating GitLab webhook requests using a secret token. The implementation is clear and is accompanied by a comprehensive set of tests covering various scenarios. My main feedback is a security concern regarding the token comparison method, which is susceptible to timing attacks. I've provided a suggestion to use a constant-time comparison on token hashes to mitigate this vulnerability.

dispatcher.go Outdated
Comment on lines +295 to +297
if token != o.token {
return ErrInvalidToken
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The direct string comparison token != o.token is vulnerable to timing attacks. An attacker could potentially deduce the secret token by measuring response time variations. For a secure comparison, you should use a constant-time comparison function. The recommended approach is to compare the SHA-256 hashes of the tokens, which ensures the comparison is always performed on fixed-length inputs, thus preventing length leakage.

Remember to add the necessary imports:

import (
	"crypto/sha256"
	"crypto/subtle"
)
		expectedTokenHash := sha256.Sum256([]byte(o.token))
		receivedTokenHash := sha256.Sum256([]byte(token))
		if subtle.ConstantTimeCompare(expectedTokenHash[:], receivedTokenHash[:]) != 1 {
			return ErrInvalidToken
		}

@dosubot dosubot bot added the enhancement New feature or request label Nov 13, 2025
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds token validation support for webhook requests, allowing users to secure their GitLab webhooks by validating an authentication token sent in the request header.

  • Adds ErrInvalidToken error and DispatchRequestWithToken() option function
  • Implements token validation logic in DispatchRequest() that checks the X-Gitlab-Token header
  • Provides comprehensive test coverage for token validation scenarios including valid tokens, invalid tokens, missing tokens, and no validation

Reviewed Changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
dispatcher.go Adds token validation infrastructure including new error type, option function, and validation logic in request dispatch
dispatcher_test.go Adds comprehensive test suite with 4 test cases covering various token validation scenarios
README.md Updates documentation to showcase the new token validation feature with usage example

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +292 to +298
// check token if provided
if o.token != "" {
token := req.Header.Get("X-Gitlab-Token")
if token != o.token {
return ErrInvalidToken
}
}
Copy link

Copilot AI Nov 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The token comparison uses a direct string equality check (token != o.token), which is vulnerable to timing attacks. An attacker could use timing differences to gradually guess the correct token byte by byte.

Use crypto/subtle.ConstantTimeCompare() for secure token comparison:

import "crypto/subtle"

// check token if provided
if o.token != "" {
    token := req.Header.Get("X-Gitlab-Token")
    if subtle.ConstantTimeCompare([]byte(token), []byte(o.token)) != 1 {
        return ErrInvalidToken
    }
}

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
README.md (1)

91-91: Good example, but fix the tab formatting.

The example clearly demonstrates the token validation feature. However, the line uses hard tabs instead of spaces, which violates markdown best practices.

Apply this diff to fix the formatting:

-			gitlabwebhook.DispatchRequestWithToken("your-secret-token"), // validate token, if needed
+		gitlabwebhook.DispatchRequestWithToken("your-secret-token"), // validate token, if needed

Note: Replace the leading tab with two additional tabs (to match the existing indentation level using tabs consistently with the rest of the file) or convert the entire file to use spaces.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2637268 and 2f732a4.

📒 Files selected for processing (3)
  • README.md (2 hunks)
  • dispatcher.go (3 hunks)
  • dispatcher_test.go (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
dispatcher_test.go (2)
dispatcher.go (5)
  • NewDispatcher (48-54)
  • RegisterListeners (42-46)
  • ErrInvalidToken (15-15)
  • DispatchRequestOption (270-270)
  • DispatchRequestWithToken (278-282)
listeners.go (1)
  • PushListener (61-63)
🪛 markdownlint-cli2 (0.18.1)
README.md

91-91: Hard tabs
Column: 1

(MD010, no-hard-tabs)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Agent
  • GitHub Check: CodeQL analysis (go)
  • GitHub Check: go test (1.25.x, windows-latest)
🔇 Additional comments (5)
dispatcher.go (2)

13-16: LGTM! Clean error declaration.

Converting to a var block for multiple error variables is idiomatic Go, and the new ErrInvalidToken follows the established naming and message format.


278-282: LGTM! Consistent option pattern.

The function follows the established functional options pattern used elsewhere in the codebase (e.g., DispatchRequestWithContext).

README.md (1)

20-20: LGTM! Clear feature documentation.

The new feature is well-documented and follows the established format with consistent emoji usage.

dispatcher_test.go (2)

232-309: LGTM! Comprehensive test coverage.

The test thoroughly covers all token validation scenarios:

  • Valid token dispatch path
  • Invalid token rejection
  • Missing token header rejection
  • Optional validation when no token configured

The table-driven structure is clean, and the assertions correctly verify both error conditions and listener invocation state.


311-320: LGTM! Clean test helper.

The simpleTestListener provides a minimal, focused test double for verifying dispatch behavior in token validation tests. The implementation is appropriately simple and separate from the more comprehensive testListener used elsewhere.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
dispatcher.go (1)

285-310: Consider rate limiting for failed token attempts.

While the token validation implementation is secure, consider adding rate limiting at the application or infrastructure level to prevent brute-force attacks on the webhook endpoint. This is particularly important since failed validation attempts could be used to guess valid tokens over time.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2f732a4 and 9520843.

📒 Files selected for processing (1)
  • dispatcher.go (4 hunks)
🔇 Additional comments (5)
dispatcher.go (5)

5-5: LGTM! Correct import for secure token comparison.

The crypto/subtle import is properly added to support constant-time comparison for token validation.


14-17: LGTM! Clean error declarations.

The error grouping follows Go conventions, and the new ErrInvalidToken is properly exported for callers to handle token validation failures.


266-269: LGTM! Clean struct extension.

The token field addition follows the existing pattern for dispatch request options.


279-283: LGTM! Follows established patterns.

The new option constructor follows the same functional options pattern as DispatchRequestWithContext, maintaining API consistency.


293-300: LGTM! Timing attack vulnerability addressed.

The token validation correctly uses subtle.ConstantTimeCompare to prevent timing attacks, addressing the concerns raised in previous reviews. The logic properly validates the X-Gitlab-Token header only when a token is configured.

@flc1125 flc1125 merged commit d57a52f into v2.x Nov 13, 2025
11 of 12 checks passed
@flc1125 flc1125 deleted the token branch November 13, 2025 00:35
This was referenced Nov 13, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants