Releases and versions
Qualor records each release of a project as a version: a label and the release’s dependency list. A scan in a tag pipeline records it. The GitLab component and the GitHub workflow templates run that scan on every tag.
A project’s rules decide which of its versions are tracked. The settings panel, the Dependencies tab and the API show which ones are. The server checks the tracked ones for vulnerabilities (Dependency vulnerabilities).
Record a version on each tag
GitLab
The job of the CI/CD component runs on tags. A
job without the component needs this rule among its rules:
rules:
- if: $CI_COMMIT_TAG
GitHub
The workflows of GitHub run on tags. If your workflow has no tags
under push, add them:
on:
push:
tags: ['**']
The tag scan uses the job’s token and settings. It needs nothing else.
Other CI systems
Pass the tag with --tag:
qualor scan --tag "$TAG_NAME"
--tagcannot be combined with--branchor--mr.- The name has at most 255 characters, and git must accept it as a tag name.
Releases you shipped earlier
Check out each release tag and scan it, as in A local scan:
for tag in v2.1.4 v2.2.3 v2.3.1; do
git checkout --quiet "$tag"
docker run --rm -v "$PWD":/src -w /src -e QUALOR_URL -e QUALOR_TOKEN -e QUALOR_PROJECT_KEY \
qualor/scanner:0.15 scan --tag "$tag"
done
Scan the oldest first, because Qualor orders versions by the date of their scan.
What a tag scan does
A tag scan collects only the dependency list.
| Scan of a branch or merge request | Tag scan | |
|---|---|---|
| Analyzers, metrics, duplication and coverage | run | do not run |
| SARIF files and coverage reports | read | not read. The analysis shows the warning TAG_SCAN_IGNORES_INPUTS |
| The dependency list (Trivy’s licence pass) | unless analyzers.trivy.licenses: false |
always |
| Issues, measures and the quality gate | yes | no |
| Comments, commit status, webhooks and emails | yes | no |
- A tag scan is quick, because no code analyzer runs.
- It applies no quality gate. The release’s code was already checked on its branch and in merge requests.
- It needs Trivy. With
analyzers.trivy.enabled: false, it exits 2. - When Trivy is not installed, the scan warns
LICENSE_SCAN_FAILED. A new version then has no packages, and a version scanned before keeps its own. The scanner images include Trivy. - A server older than 0.15 cannot record versions. The scanner then uploads nothing, warns, and exits 0, so the release pipeline does not fail.
- With C#, the job still runs
qualor dotnet beginand your build.qualor dotnet endthen records the version and reads no Roslyn log. - To run the full scan with the quality gate in a tag pipeline, pass
--branch <name>. The analysis then belongs to that branch.
The version label
A version’s label is project.version from qualor.yml when it is set. Otherwise it is the tag’s
name, such as v2.3.4.
- A label has at most 100 characters. A longer tag needs a shorter
project.version. Without one, the scanner exits 2 before the upload. - Scanning the same label again replaces that version’s packages. A scan without a dependency list leaves them as they are. The version keeps its pin or unsupported mark.
- A tag scan that started before the stored tag scan of its label fails with
STALE_ANALYSIS. The stored packages stay.
Exit codes
| Code | When |
|---|---|
| 0 | the server recorded the version, and the scanner logged Recorded version <label>. With --no-wait or gate.wait: false, the scanner exits 0 right after the upload. With a server older than 0.15, it uploads nothing and exits 0 with a warning |
| 2 | --tag with --branch or --mr, a tag name git does not accept, a label longer than 100 characters, or analyzers.trivy.enabled: false |
| 4 | the server did not record the version. The scanner prints the server’s code and message, such as STALE_ANALYSIS. Also when the server has not confirmed the version within gate.timeoutSeconds: the scanner says the version was uploaded but not confirmed |
Codes 2, 4 and 5 also have their usual causes (CLI reference). A tag scan never exits 1 or 3: it has no quality gate and no required analyzer.
Which versions are tracked
The rule is set under Released versions in the settings panel.
A label is a version number when it has two to four numbers separated by dots, with an optional
v in front, such as 2.3, 2.3.4 or v2.3.4. Its line is its first two numbers: 2.3.4 is
in line 2.3. A pre-release is a version number with a part after a -, such as 2.4.0-rc.1
or 2.4.0-SNAPSHOT.
| Rule | Tracked versions |
|---|---|
| The newest version of each line (the default) | the highest version of each of the newest N lines. 2.3.4 replaces 2.3.0 to 2.3.3. N is Lines to track: 1 to 20, and 5 by default |
| Every version | every version |
| None | none |
- The newest version of each line tracks labels that are not version numbers by date: the N scanned most recently.
- No rule tracks a pre-release.
- Now tracked shows the tracked labels as chips, the most recently scanned first, up to 50.
- A version that is not tracked keeps its packages.
A version’s mark decides whether the rule applies. You set it in the row menu of the Vulnerabilities tab (Pin, Unpin, Mark as unsupported, Track automatically; Dependency vulnerabilities) or through the API (The API):
| Mark | Effect |
|---|---|
pinned |
the version is tracked, whatever the rule says |
unsupported |
the version is never tracked |
auto |
no mark: the rule decides |
An unsupported version still counts as the newest of its line. Its line’s older versions stay untracked.
The settings panel
Project → Settings → Vulnerability monitoring holds these settings. Organization admins and project admins change them.
The panel has the project’s switch, then three sections. Save applies the changes.
| Part | Meaning |
|---|---|
| Track vulnerabilities in this project | on by default. Versions are recorded whether it is on or off |
| Branches | the tracked branches: the main branch, always, and those that match Also track branches matching |
| Released versions | the rule of Which versions are tracked |
| Version labels | the switch Also take versions from branch analyses that carry project.version, off by default. See Version labels on branch analyses |
- Also track branches matching takes up to 10 patterns, such as
release/*, separated by commas. - Matches now shows the branches that match them, as chips.
While the project has no version, the panel shows the two CI snippets of Record a version on each tag.
Version labels on branch analyses
With Also take versions from branch analyses that carry project.version on, an analysis of a
tracked branch records a version too. The tracked branches are those of the panel’s Branches.
The version’s label is project.version, and its packages are that analysis’s.
Turn it on only when project.version changes once per release, not with every build. Otherwise
each analysis records a new version.
- Merge request analyses never record a version.
- Pre-release labels, such as
2.4.0-SNAPSHOTor2.4.0-rc.1, are skipped. - A later analysis with the same label replaces the version’s packages.
- A branch analysis never replaces a version that a tag scan recorded. A tag scan with the same label replaces a version taken from a branch.
- An analysis without a dependency list records no version, for example with
analyzers.trivy.licenses: false.
A version’s packages
Project → Dependencies shows a version’s packages. Choose the version under Versions in the Branch picker (The Dependencies tab).
The API
# the versions, the latest scan first, with their tracking
q "$QUALOR_URL/api/v0/projects/<project id>/versions"
# pin a version ("unsupported" marks it unsupported, "auto" removes the mark)
q -X PATCH "$QUALOR_URL/api/v0/projects/<project id>/versions/<version id>" \
-d '{"tracking":"pinned"}'
# a version's packages
q "$QUALOR_URL/api/v0/projects/<project id>/dependencies?version=<version id>"
# the panel's settings, read and saved
q "$QUALOR_URL/api/v0/projects/<project id>/vulnerability-monitoring"
q -X PUT "$QUALOR_URL/api/v0/projects/<project id>/vulnerability-monitoring" -d '{"enabled":true,
"branchPatterns":["release/*"],"versionRule":{"kind":"lines","lines":5},"labelVersions":false}'
q is the helper of Webhooks and REST API.
GET /projects/{id}/versionspages withlimit(1 to 100, 50 by default) andcursor. Each version has:id,label,tagandanalyzedAt, the date of its scan;source:tag, orlabelfor a version taken from a branch analysis;tracking: the mark,auto,pinnedorunsupported;trackedandtrackingReason, below;prerelease, andpackages, the number of packages.
PATCH /projects/{id}/versions/{versionId}takes{"tracking": …}and answers the version.GET /projects/{id}/vulnerability-monitoringanswers the four settings, plusmainBranchName,matchingBranches(up to 50),trackedVersionsandversionCount.trackedVersionsholds up to 50 labels, the most recently scanned first.PUT /projects/{id}/vulnerability-monitoringtakes all four settings:enabled, true or false;branchPatterns, up to 10 patterns of 1 to 255 characters. A pattern that is not a valid glob answers 422VALIDATION_FAILED;versionRule:{"kind":"lines","lines":N}with N from 1 to 20,{"kind":"all"}or{"kind":"none"};labelVersions, true or false.
- The two reads need read access to the project.
PATCHandPUTneed the right to change project settings, and a personal token needs the Admin scope for them. GET /analyses/{id}of a tag scan answersversion(idandlabel),"branch": null, and the gate statusnone.- With
audit-log, changes are recorded asproject.vulnerability_monitoring_updatedandproject_version.updated(Roles and the audit log).
trackingReason |
Tracked | Why |
|---|---|---|
pinned |
yes | the version is pinned |
unsupported |
no | the version is marked unsupported |
prerelease |
no | a pre-release |
newest_in_line |
yes | the highest version of one of the newest N lines |
replaced |
no | its line has a higher version |
older_line |
no | its line is not among the newest N |
recent |
yes | not a version number, and among the N scanned most recently |
older |
no | not a version number, and scanned before the most recent N |
rule_all |
yes | the rule is Every version |
rule_none |
no | the rule is None |
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
BRANCH_REQUIRED in a tag pipeline |
the scanner is older than 0.15, or the server is older than 0.15 and did not report its version | upgrade both to 0.15 or later |
| exit 0 and no version, with the warning “The server is older than 0.15 and cannot record versions; upgrade the server to record releases” | the server is older than 0.15. The scanner uploaded nothing | upgrade the server to 0.15 or later, then scan the tag again |
| exit 2, “A version label is at most 100 characters; set project.version” | project.version is not set, and the tag is longer than 100 characters. The scanner refuses the label before the upload. The server would fail it with VERSION_LABEL_INVALID |
set project.version to a label of at most 100 characters |
exit 4, STALE_ANALYSIS |
a newer tag scan of the same label was stored first | none needed: the newer packages stay |
the version has no packages, and the scan warned LICENSE_SCAN_FAILED |
Trivy did not run | use the scanner image (Dependencies (Trivy)) |
the version has no packages, and the scan warned LICENSE_SCAN_TIMEOUT |
Trivy’s licence pass took longer than analyzers.trivy.licenseTimeoutSeconds (300 s by default) |
raise the timeout, or exclude directories you do not ship (Dependency licences) |
the version has no packages, and no LICENSE_SCAN_FAILED |
the repository has no lockfile Trivy reads | see Which ecosystems give licences |
| a tag pipeline does not run the job | the job has no rule or trigger for tags | add the snippet |