GitLab

Qualor works with GitLab.com and self-managed GitLab. Setup has two parts:

  1. 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.
  2. 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/scanner from 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

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 is qualor, and GitLab needs a shell.
  • GIT_DEPTH: 0 gives the job the full history. With a shallow clone, the CLI tries to fetch the baseline. If that fails, new-code conditions end in error, 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:

  1. New GitLab connection. Enter the GitLab address (https://gitlab.example.com; a path such as /gitlab is allowed) and an access token:
    • scope api and 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.
  2. 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.
  3. Ask the server operator to set QUALOR_PUBLIC_URL so 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: false and turn on Settings → Merge requests → Pipelines must succeed; or
  • keep the pipeline green (allow-failure: true during 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.