Add Repository X-ray service in monolith
What does this MR do and why?
Background
The Repository X-Ray is a tool that searches for dependency manager configuration files (aka "lock files") and then extracts a list of libraries from the content.
In #474306 (comment 2025085630), we decided to migrate the Repository X-Ray functionality into the GitLab Rails monolith. This gives us two main benefits: (i) it will eventually allow us to run the service outside of the CI pipeline, and (ii) we can maintain the parsing logic centrally so that other domains can utilize it.
Previous MRs
In !162313 (merged), we added the ConfigFiles::Base
class where the intention is for each dependency manager config file type to be represented by a child class. The child class contains the parsing logic to extract a list of libraries and their versions from the file content.
In !162891 (merged), we added the ConfigFileParser
class which searches through the project repository for dependency config files, matches them to the applicable config file class, and then parses them.
This MR
In this MR, we introduce a Repository Xray service which utilizes ConfigFileParser
to extract the config files from a repository. Then it saves the parsed data to the xray_reports
table, and outputs a service response with success/error messages. In the next MR, these messages will be logged in Sidekiq as metadata when we introduce the worker that runs this service.
Additionally, added sentry error tracking on the config file base class so we can be notified if the parsing logic needs to change.
Partially resolves #476180 (closed).
Query plan
Projects::XrayReport.upsert_all(reports_array, unique_by: [:project_id, :lang])
NOTE: The batches uploaded would always be small. We parse at most one config file per language, and we only support a few languages presently (and will unlikely support a number that would be detrimental to this bulk upsert).
INSERT INTO "xray_reports" ("project_id","payload","lang","file_checksum","created_at","updated_at")
VALUES
(32, '{"libs":[{"name":"abc.org/mylib (1.3.0)"},{"name":"golang.org/x/mod (0.5.0)"}],"checksum":"ba58588b25327d8c3d1e64e9fb57c256f3bd0e25b07edf05774d5540f201d1de","fileName":"dir1/dir2/go.mod","scannerVersion":"0.0.0"}', 'go', '\x62613538353838623235333237643863336431653634653966623537633235366633626430653235623037656466303537373464353534306632303164316465', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
(32, '{"libs":[{"name":"bcrypt (3.1.20)"}],"checksum":"fc37c826eee95606926e3d62104fb8ea7a07a256ade74fea4c044a7df9ee3073","fileName":"Gemfile.lock","scannerVersion":"0.0.0"}', 'ruby', '\x66633337633832366565653935363036393236653364363231303466623865613761303761323536616465373466656134633034346137646639656533303733', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
ON CONFLICT ("project_id","lang") DO UPDATE SET updated_at=(CASE WHEN ("xray_reports"."payload" IS NOT DISTINCT FROM excluded."payload" AND "xray_reports"."file_checksum" IS NOT DISTINCT FROM excluded."file_checksum") THEN "xray_reports".updated_at ELSE CURRENT_TIMESTAMP END),"payload"=excluded."payload","file_checksum"=excluded."file_checksum" RETURNING "id"
Query plan: https://console.postgres.ai/gitlab/gitlab-production-main/sessions/31102/commands/96618
MR acceptance checklist
Please evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.
How to set up and validate locally
- Create a new blank project and commit these two files to the repo:
subdir/Gemfile.lock
:
GEM
remote: https://rubygems.org/
specs:
bcrypt (3.1.20)
logger (1.5.3)
my_lib (1.0.2)
PLATFORMS
ruby
DEPENDENCIES
bcrypt (~> 3.1, >= 3.1.14)
logger (~> 1.5.3)
BUNDLED WITH
2.5.16
pom.xml
:
invalid content
- Run the service in the Rails console:
project = Project.last # Should be the project you created in Step 1
response = Ai::RepositoryXrayService.new(project).execute
- Observe that the service response is as expected:
- Observe that the X-ray report for the valid config file (
Gemfile.lock
) is recorded:
project.reload.xray_reports
Related to #476180 (closed)