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
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
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
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)