How to create a GitLab bot that provides GitLab users self-help services?

Posted by Jie Gao on February 27, 2023 · 5 mins read

A GitLab bot can aid administrators in identifying GitLab user profiles and providing fast, secure, and tailored services to these users. In the daily routine of a Linux administrator, there are often numerous repetitive tasks related to user access requests and permissions. Typically, an administrator needs to manually inspect user profiles and perform the necessary tasks. This manual process can involve significant communication overhead and waiting time for both parties involved.

GitLab team has a bot for Triage operations. What about we building our own bot to fullfill our own needs?

In this blog post, I will illustrate how to create a GitLab bot that simplifies an administrator’s tasks, making their work more efficient and streamlined.

For the full project, you can checkout the source code here

use Rack to provide adaptable interface for developing web applications in Ruby

Rack is a modular Ruby web server interface. Rack can be used to support a range of Ruby web servers.

In the config.ru file, type the following the start a web application.

# frozen_string_literal: true

require_relative 'general/rack/app'

run General::Rack::App.app


Notice that we start a web application by running in the file in General::Rack::App. Lets go in to this file and see what’s there.

require 'rack'
require 'rack/requestid'
require 'json'

require_relative 'authenticator'
require_relative 'webhook_event'
require_relative 'processor'

module General
  module Rack
    module App
      def self.app
        ::Rack::Builder.app do
          use ::Rack::RequestID # makes sure `env` has an X-Request-Id header

          use ::Rack::ContentType, 'application/json'
          use General::Rack::Authenticator
          use General::Rack::WebhookEvent
          run General::Rack::Processor.new
        end
      end
    end
  end
end

In this file, we do the three things: 1. finish GitLab bot authentication, 2. Start to respond a webhook event, 3. fullfil the new command.

Now what we can do is the install a puma webserver, and start the GitLab bot.

gem install puma
puma

Understand Authenticator

To ensure both the secure transfer of code and the verification of requests from genuine users, we employ a GitLab feature called webhooks. After configuring the webhook, it sends an HTTP request to the bot along with a payload and a webhook token. In the code snippet below, it verifies the webhook token received from the webhook against the token stored in the bot’s configuration file.

      def self.secure_compare(a, b)
        ::Rack::Utils.secure_compare(
          ::OpenSSL::Digest::SHA256.hexdigest(a),
          ::OpenSSL::Digest::SHA256.hexdigest(b)
        ) &&
          a == b
      end

      def call(env)
        if webhook_token_empty?
          return ::Rack::Response.new([JSON.dump(status: :unauthenticated, message: "Token wasn't provided")],
                                      400).finish
        end

        if authenticated?(env)
          @app.call(env)
        else
          @logger.error(info: 'Unauthenticated request!', payload: env)
          warn 'Unauthenticated request!'

          ::Rack::Response.new([JSON.dump(status: :unauthenticated)], 401).finish
        end
      end

      private

      def authenticated?(env)
        self.class.secure_compare(http_gitlab_token(env), webhook_token)
      end

Build Json log file for monitoring events

Even though the bot securely transfers information, it’s essential to have a means of auditing events in case of any future issues.

To address this, we developed a JsonLogger class derived from ::Labkit::Logging::JsonLogger to facilitate logging functionality.

Please see the MR for further check.

In the class where we wish to utilize the log, we can invoke it as follows:

logger.info(command: 'HelloBot', username: @event.event_actor_username)