GitLab
Qualor works with GitLab.com and self-managed GitLab. Setup has two parts:
- The CI job runs
qualor scan, uploads the analysis and fails the pipeline when the quality gate fails. That is enough to block bad merge requests. - The connection (optional, recommended) lets the Qualor server comment on merge requests. It
posts one summary comment, one discussion per new issue on a changed line, and a commit status
qualor/<project key>.
Before you start
- A running Qualor server that the runners can reach over HTTPS (Install the server).
- Runners that can pull
qualor/scannerfrom Docker Hub, or your own copy of it (Images). - A project in Qualor whose key is the GitLab project path (
group/subgroup/app), and a token. A project analysis token is best (Tokens).
1. CI/CD variables
In GitLab, under Settings → CI/CD → Variables of the project (or of a group, for many projects at once):
| Variable | Value | Flags |
|---|---|---|
QUALOR_URL |
https://qualor.example.com |
— |
QUALOR_TOKEN |
the token | Masked, and not Protected |
The token must not be protected. GitLab gives protected variables only to pipelines of protected branches, so merge request pipelines would get no token.
A group-level token has to be a personal token with Upload analyses, because a project token uploads to one project only. If the token’s user is an org admin, Qualor creates missing projects on their first upload.
2. The CI job
With the CI/CD component (recommended)
Qualor is in the GitLab CI/CD catalog as gitlab.com/qualor/qualor.
On GitLab.com:
# .gitlab-ci.yml
include:
- component: gitlab.com/qualor/qualor/qualor@1
inputs:
image-tag: '1'
Self-managed GitLab can include components only from its own instance. Create a project there
that mirrors https://gitlab.com/qualor/qualor.git (New project → Import project → Repository by
URL with Mirror repository, or a pull mirror), for example at tools/qualor, and include from it:
include:
- component: $CI_SERVER_FQDN/tools/qualor/qualor@1
inputs:
image-tag: '1'
# image: mirror.acme.internal/qualor/scanner # your own copy of the image, without the tag
Pin the component and the image to the same release. Use a full version (@1.2.3,
image-tag: '1.2.3') where every pipeline must run exactly the same analyzers.
The job runs in merge request pipelines and on the default branch. It uploads the analysis, fails with the quality gate, and keeps GitLab’s Code Quality, SAST and Dependency Scanning reports as artifacts. Findings then show in the merge request widget and in the security tab. The SAST and Dependency Scanning widgets need GitLab Ultimate. The Code Quality report works on every tier.
| Input | Default | Meaning |
|---|---|---|
image-tag |
required | the scanner image tag, such as 1 or 1.2.3 |
image |
qualor/scanner |
the scanner image, without the tag |
stage |
test |
the stage of the job |
job-name |
qualor |
the job’s name |
args |
empty | extra qualor scan arguments, for example --sarif osv.sarif |
allow-failure |
false |
let the pipeline pass when the gate fails (a soft rollout) |
dotnet |
false |
C#: run qualor dotnet begin, the build, then qualor dotnet end |
build-command |
dotnet build --no-incremental |
the build that runs between begin and end when dotnet is true |
The component runs qualor scan from the repository root. If your project needs dependencies
installed (JavaScript/TypeScript) or a build (Java) first, use the job below instead, or extend the
component’s job with a before_script:
qualor: # the component's job-name
before_script:
- npm ci
Without the component
qualor:
stage: test
image: { name: qualor/scanner:1, entrypoint: [''] }
variables: { GIT_DEPTH: 0 } # full history: new code is computed from git
script:
- npm ci # JS/TS: ESLint runs from node_modules. Java: build first.
- >-
qualor scan
--gitlab-code-quality gl-code-quality-report.json
--gitlab-sast gl-sast-report.json
--gitlab-dependency-scanning gl-dependency-scanning-report.json
artifacts:
when: always
reports:
codequality: gl-code-quality-report.json
sast: gl-sast-report.json
dependency_scanning: gl-dependency-scanning-report.json
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
entrypoint: ['']is needed because the image’s entrypoint isqualor, and GitLab needs a shell.GIT_DEPTH: 0gives the job the full history. With a shallow clone, the CLI tries to fetch the baseline. If that fails, new-code conditions end inerror, and Qualor fails the gate rather than guessing.- Use merge request pipelines (
merge_request_event). Only in them does the CLI know the target branch, and the analysis becomes a merge request analysis.
A C# project uses qualor/scanner-dotnet and wraps its own build. See
Languages and analyzers.
3. Merge request comments and commit status
In Qualor, an org admin opens Settings → GitLab:
- New GitLab connection. Enter the GitLab address (
https://gitlab.example.com; a path such as/gitlabis allowed) and an access token:- scope
apiand role Developer; - best, a project access token of the GitLab project, because it can reach nothing else. For many projects, use a group access token, or a personal token of a dedicated bot user. Never use a person’s own token: every comment would carry their name.
- scope
- In the Projects table on the same page, pick the connection for each Qualor project and enter
the GitLab project: its numeric id or its full path
group/project. Use the test action to check that the token can see the project. - Ask the server operator to set
QUALOR_PUBLIC_URLso that comments link back to Qualor.
Self-managed GitLab on an internal network. The server calls only hosts that resolve to public addresses, unless the operator allows the host explicitly:
QUALOR_SCM_INTERNAL_HOSTS=gitlab.corp.example.com # https on 443
QUALOR_SCM_INTERNAL_HOSTS=gitlab.corp.example.com:8443,10.0.0.12
If GitLab’s certificate comes from a private CA, give the server that CA with NODE_EXTRA_CA_CERTS.
What reviewers see
- A commit status
qualor/<project key>: success when the gate passes, failed with the failed conditions otherwise. It is posted for every analysed branch, not only for merge requests. - One summary comment per merge request, edited in place on every analysis and never posted twice. It holds the verdict, the failed conditions, the new issues by severity, the ten most severe ones and a link to Qualor.
- A discussion on each new issue that sits on an added line, up to 50 per merge request. Qualor resolves the discussion when the issue is fixed. It never reopens a thread a person resolved, and it leaves alone a thread a person replied in.
- Marking an issue false positive or won’t fix in Qualor re-evaluates the gate right away, with no new scan. If that was the only new issue, the status turns green and the thread is resolved.
Everything a comment quotes from the code is put in code spans. No snippet, no rule text and no link that the report controls reaches GitLab.
4. Block merges on the gate
Either:
- keep the job’s default
allow_failure: falseand turn on Settings → Merge requests → Pipelines must succeed; or - keep the pipeline green (
allow-failure: trueduring a soft rollout) and rely on the commit status as information.
Troubleshooting
| Symptom | Cause |
|---|---|
| Exit 5 | the token is wrong, revoked, or of another project |
new code unavailable, gate error |
shallow clone: set GIT_DEPTH: 0 |
| The analysis appears as a branch, not a merge request | the job ran in a branch pipeline. Use merge_request_event rules |
| No comments | no connection or mapping, QUALOR_SCM_INTERNAL_HOSTS missing, or the token lacks api/Developer. The test on Settings → GitLab says which |
| Comments but no links | QUALOR_PUBLIC_URL is not set on the server |
More in Troubleshooting.