Enterprise
Qualor Enterprise is the same qualor/server image with a licence key. Without a key the server
is the community edition: MIT, with no limit on users, projects or lines of code, and at most 3
organisations. With a valid key it becomes the enterprise edition. Nothing is installed or
downloaded, and the key is checked on your server: Qualor never calls home, so it works in
air-gapped networks.
What a licence adds
| Community | Enterprise | |
|---|---|---|
| Organisations | up to 3 | the number in your licence |
| AI fix suggestions | at most 25 per organisation per day | up to your own budget (Settings → AI assistant) |
| Single sign-on (SAML, OIDC), SCIM, roles, audit log, portfolio reports, compliance exports | no | not yet: they are being built and will switch on with the same key |
Today a licence changes two things: the organisation limit and the fix suggestion ceiling of the AI assistant. The other enterprise features are not available yet, in any edition.
The enterprise code ships inside the qualor/server image, in /app/enterprise. It is inert
without a key: the server does not even open the file. There is no separate image to pull and
nothing to switch when you buy a licence.
That code lives in the repository’s enterprise/ directory under its own
licence, enterprise/LICENSE. It is source-available, not open source:
you can read it, and copy and change it for development and testing, without a key. Running,
mirroring or redistributing the qualor/server image with no key configured needs no
subscription: the enterprise code is not in use then. Using the enterprise features in production
needs a subscription. The licence text is a draft: it is still to be reviewed by a lawyer and
may change before the first licence is sold. Everything outside enterprise/ is MIT.
Licence keys are not on sale yet. No release of Qualor accepts a production key so far: the public key that checks them ships with the first release that sells them. Until then everything on this page describes how a key will work. To register your interest, use qualor.dev/enterprise.
Apply a key
A key is one line of text that starts with QLK1.. Give it to the server in one of three ways.
When more than one is present, the server uses the first of this list:
-
QUALOR_LICENSE, an environment variable holding the key. In thecompose.ymlof Install the server, add a line underenvironment:services: server: environment: QUALOR_LICENSE: ${QUALOR_LICENSE:-}and put the key in your
.envfile (QUALOR_LICENSE=QLK1.…). With Helm, keep the key in a Secret and pass it withextraEnv:kubectl -n qualor create secret generic qualor-license --from-literal=license='QLK1.…'extraEnv: - name: QUALOR_LICENSE valueFrom: secretKeyRef: name: qualor-license key: license -
QUALOR_LICENSE_FILE, the absolute path of a file holding the key, for example a Docker secret:services: server: environment: QUALOR_LICENSE_FILE: /run/secrets/qualor_license secrets: - qualor_license secrets: qualor_license: file: ./qualor-license.txtThe file is read once, at start, and may be at most 16 KiB. The server runs as user 65532, so that user must be able to read it. Save it as UTF-8, with or without a byte-order mark. UTF-16 with a byte-order mark works too: that is what Notepad’s “Unicode” and PowerShell 5.1’s
>write. -
The web UI or the API. An instance admin opens Settings → Licence, pastes the key and selects Save (or sends it to
PUT /api/v0/license). The key is checked at once, and a key that is not valid is refused with the reason. A saved key is stored in the database, in the instance settings.
Set at most one of the two variables: with both, the server does not start and says
set QUALOR_LICENSE or QUALOR_LICENSE_FILE, not both. While a variable is set, Settings →
Licence shows the key’s status and names the variable, but cannot change or remove the key.
Restart to apply it
A new key takes effect at the next start of the server, whichever way you gave it. After you save a key in the web UI, the page says “Saved. Restart the server to apply the new key.” and shows Restart required. until you restart. Then restart it:
docker compose up -d server # Docker Compose, after a change to .env or compose.yml
docker compose restart server # Docker Compose, after saving a key in the web UI
kubectl -n qualor rollout restart statefulset/qualor # Helm with the embedded database (the default)
kubectl -n qualor rollout restart deployment/qualor # Helm with an external or bundled database
At start the server writes one line about the licence to its log, such as:
{"level":30,"component":"licence","licence":"active","edition":"enterprise","source":"environment","expires":"2027-10-01T00:00:00.000Z","plugins":["qualor-enterprise"],"msg":"running as the enterprise edition"}
It says the state of the licence (none, active, grace, expired or invalid), the edition,
where the key came from, when it expires and which enterprise plugins loaded. It never contains the
key, the customer’s name or the licence id, so you can ship your logs to another service.
A key that the server rejects never stops it. The server starts as the community edition and logs
licence key rejected at level error with a reason (see Troubleshooting).
A typo in a key never takes Qualor down.
A QUALOR_LICENSE_FILE that the server cannot read does stop the start, because a secret that
is not mounted is a mistake in the deployment. The server exits with one of these messages, and
never prints the file’s content:
qualor-server: QUALOR_LICENSE_FILE: cannot read /run/secrets/qualor_license
qualor-server: QUALOR_LICENSE_FILE: /run/secrets/qualor_license is not a file
qualor-server: QUALOR_LICENSE_FILE: /run/secrets/qualor_license is larger than 16 KiB
qualor-server: QUALOR_LICENSE_FILE: /run/secrets/qualor_license is not a text file in UTF-8 (or UTF-16 with a byte-order mark); save it as UTF-8
Pasting a key
A key copied from an e-mail is often broken over several lines. That is fine: the server removes spaces and line breaks before it checks a key, in every one of the three ways. The web UI also removes invisible characters that some mail and chat programs add (non-breaking spaces, zero-width spaces, byte-order marks). After you save a key, the page never shows it again.
Check the licence
Settings → Licence (instance admins only) shows:
- the edition and the state in words, such as “active until 1 October 2027”, or the reason a key was rejected;
- whom the licence is for, the licence id, and when it was issued and expires;
- how many organisations you use of how many are allowed, and how many are read-only;
- the active enterprise features and the enterprise plugins, with any load error;
- where the key comes from:
QUALOR_LICENSE,QUALOR_LICENSE_FILE, or saved in Qualor.
Unless a variable sets the key, the page also has a field to paste a key with Save and, once a key is saved in Qualor, a Remove button.
Every signed-in user can see the edition, the active features and the organisation limit in
GET /api/v0/system/info. Users who are not instance admins see nothing else about the licence.
When a licence expires
- From 30 days before the expiry date, instance admins see a notice at the top of every page: “The Qualor licence expires on … Renew it to keep the enterprise features.” It links to the licence page.
- On the expiry date a 14-day grace period starts. Everything keeps working, and the notice says when the enterprise features stop.
- When the grace period ends, the server runs as the community edition, without a restart:
- the AI assistant’s fix suggestions are limited to 25 per organisation per day again. A higher fix budget you saved stays saved and applies again with a renewed key; until then you can keep it or lower it in Settings → AI assistant, but not raise it;
- organisations beyond the third become read-only (see below);
- nothing is deleted. Projects, issues, history and settings all stay.
- Apply a renewed key and restart: everything works as before, with all its data.
Removing a key, or replacing it with one that allows fewer organisations, has the same effect at the next start.
Read-only organisations
When a server has more organisations than its edition allows, the oldest organisations stay
as they are, up to the limit (3 in the community edition), and the newer ones become read-only.
This only happens after a licence lapses, is removed, or is replaced by a smaller one: you can never
create an organisation beyond the limit (ORG_LIMIT_REACHED).
In a read-only organisation:
-
Everything can still be read. The web UI, the REST API, exports and downloads work as before. Everyone who can see the organisation sees the marks: the organisation switcher says “(read-only)” after its name, and each of its project pages says why changes fail. Instance admins also see a notice at the top of every page with the number of read-only organisations. A refused change in the web UI says how many organisations the licence allows.
-
Every change is refused with HTTP 409 and the code
ORG_READ_ONLY: projects, tokens, branches, issue statuses, quality gates, profiles, webhooks, GitLab/GitHub connections, members and AI assistant requests. That includes a few requests that only look at data but are sent asPOST: the dry run ofqualor import sonarqube(for issue statuses) and the connection test in Settings → GitLab and GitHub. -
New analyses are refused. A CI job that uploads to one of its projects fails with exit code 4 and says why, instead of losing the analysis silently:
error: the server rejected the upload (409 ORG_READ_ONLY: This organization is read-only: the licence allows 3 organizations. Renew the licence, or ask for a key with a higher organization limit.) -
Work that was already queued finishes, and the normal housekeeping still runs: old uploaded reports, closed issues and webhook deliveries are cleaned up on the usual retention schedule.
-
Instance-level settings are not affected. Users, personal tokens, sign-in and the licence itself work as usual, and an instance admin can still change an organisation’s AI assistant settings in Settings → AI assistant.
The API’s 409 answer carries the limit as a number, organizationLimit, next to code, so a
script can report it.
GET /api/v0/organizations tells you which organisations are read-only: each item has a
readOnly field (true or false).
A key that allows enough organisations makes them all writable again at the next start, with all their data.
The licence API
Instance admins can manage the key over the REST API, with a session or a personal token with the Admin scope. The key text is never returned by any of these endpoints.
export QUALOR_URL=https://qualor.example.com
H="Authorization: Bearer $QUALOR_ADMIN_TOKEN"
curl -fsS -H "$H" "$QUALOR_URL/api/v0/license" # the status
curl -fsS -X PUT -H "$H" -H 'Content-Type: application/json' \
-d "{\"key\":\"$(tr -d '\r\n' < qualor-license.txt)\"}" "$QUALOR_URL/api/v0/license" # save a key
curl -fsS -X DELETE -H "$H" "$QUALOR_URL/api/v0/license" # remove the saved key
| Endpoint | What it does |
|---|---|
GET /api/v0/license |
the edition, the state (none, invalid, active, grace or expired), the reason a key was rejected, where the key comes from, the licence’s customer, dates, organisation limit and features, the organisation count with the limit and the number of read-only organisations, the active features and the plugins, and restartRequired |
PUT /api/v0/license {"key": "QLK1.…"} |
checks the key and saves it. It answers with the status, with restartRequired: true until the next start |
DELETE /api/v0/license |
removes the saved key. The server runs as the community edition from the next start |
| Status and code | Meaning |
|---|---|
422 LICENSE_INVALID |
the key was refused. The reason field gives the reason as a code: malformed (not a Qualor licence key: check that it was copied completely), unknown-key (signed with a key this version of Qualor does not accept), bad-signature (changed: the signature does not match), bad-payload (contents not valid), revoked, or not-yet-valid. errors[0].message says the same in English |
422 LICENSE_EXPIRED |
the key is past its grace period: ask for a renewed one |
409 LICENSE_MANAGED_BY_ENVIRONMENT |
the key comes from QUALOR_LICENSE or QUALOR_LICENSE_FILE. Change the variable and restart instead |
413 BODY_TOO_LARGE |
the request body is larger than 17 KiB. A key is far smaller: check what you sent |
| 403 | you are not an instance admin, or the token lacks the Admin scope |
Questions
- Is the key tied to a server? No. It works on any server of yours, including a test instance and a standby.
- Does the key send anything anywhere? No. It is checked offline, with a public key built into Qualor.
- Several replicas? Each replica reads the key when it starts. A key saved in the web UI is stored in the database, so all replicas use it after their next start.
- What if the server’s clock is wrong? The expiry uses the server’s clock. A key issued “in the future” by more than a day is refused as not valid yet: check the clock.
- A key that is not valid yet? The server checks the key once, when it starts. If it started more than a day before the key’s issue date, it keeps running as the community edition: restart it after the issue date. Saving such a key in the web UI is refused the same way until then.