Split out of #61, which raised this as a "Related" note. Kept separate so a permissions change is not buried inside a CI-config commit.
Full write-up: docs/ci/sonarqube-ci-identity.md.
Problem
Gitea Actions authenticates to SonarQube with a token belonging to the admin account.
An analysis job needs exactly one permission: submit an analysis report for one project. The admin token carries every permission the server has — creating and deleting projects, editing quality gates and profiles, managing users, and reading every project on the server including sql-utilities.
The related half of this is already fixed: #67 removed the -Dsonar.login= command-line argument, so the token now reaches the scanner only through the SONAR_TOKEN environment variable and no longer appears on a command line where it could reach a log. What remains is whose token it is.
Why it matters
Three ordinary situations, none of which need anyone to act badly:
A leaked token is a leaked server. CI secrets end up in more places than intended — a debug run with set -x, a third-party action, a fork's workflow. The blast radius of a restricted analysis token is one project's analysis history. The blast radius of this one is everything on the server.
A misconfigured scan can destroy history.sonar.projectKey is just a string in a properties file. A wrong value combined with admin rights silently creates projects, and other admin endpoints can delete them. A restricted token fails instead.
Rotation is painful today. Rotating admin's token means tracking down everywhere else that account is used. A dedicated account rotates on its own.
There is also a plainer reason: with CI showing up as admin in the analysis history, the audit trail cannot tell an automated scan from a person making a change.
Fix
Create a SonarQube user gitea-ci with no global permissions.
Grant it Execute Analysis on redefined-designs only.
Generate a user token for it — not a project or global analysis token. This server is 9.9, where the distinction matters, and SonarSource tooling requires the user type.
Update the SONAR_TOKEN secret in the repository's Actions settings.
Run the SonarQube workflow and confirm it still passes.
Revoke the admin token CI was using.
Step 6 is worth calling out: the workflow is already green after step 5, so it is easy to stop there and leave the old credential valid, which makes the whole change cosmetic.
Note for whoever does this
This server does not accept Authorization: Bearer — it is 9.9, and bearer auth arrived in SonarQube 10. A token goes in as the basic-auth username: curl -u "$TOKEN:" .... Any script verifying the new account's permissions with a bearer header will report a permissions problem that is really an auth-scheme problem.
Severity
Medium. Nothing is broken and nothing has gone wrong; the exposure is disproportionate to what the job actually needs, and the cost of fixing it is about ten minutes.
Split out of #61, which raised this as a "Related" note. Kept separate so a permissions change is not buried inside a CI-config commit.
Full write-up: `docs/ci/sonarqube-ci-identity.md`.
## Problem
Gitea Actions authenticates to SonarQube with a token belonging to the **`admin`** account.
An analysis job needs exactly one permission: submit an analysis report for one project. The `admin` token carries every permission the server has — creating and deleting projects, editing quality gates and profiles, managing users, and reading every project on the server including `sql-utilities`.
The related half of this is already fixed: #67 removed the `-Dsonar.login=` command-line argument, so the token now reaches the scanner only through the `SONAR_TOKEN` environment variable and no longer appears on a command line where it could reach a log. What remains is whose token it is.
## Why it matters
Three ordinary situations, none of which need anyone to act badly:
- **A leaked token is a leaked server.** CI secrets end up in more places than intended — a debug run with `set -x`, a third-party action, a fork's workflow. The blast radius of a restricted analysis token is one project's analysis history. The blast radius of this one is everything on the server.
- **A misconfigured scan can destroy history.** `sonar.projectKey` is just a string in a properties file. A wrong value combined with admin rights silently creates projects, and other admin endpoints can delete them. A restricted token fails instead.
- **Rotation is painful today.** Rotating `admin`'s token means tracking down everywhere else that account is used. A dedicated account rotates on its own.
There is also a plainer reason: with CI showing up as `admin` in the analysis history, the audit trail cannot tell an automated scan from a person making a change.
## Fix
1. Create a SonarQube user `gitea-ci` with **no** global permissions.
2. Grant it **Execute Analysis** on `redefined-designs` only.
3. Generate a **user** token for it — not a project or global analysis token. This server is 9.9, where the distinction matters, and SonarSource tooling requires the user type.
4. Update the `SONAR_TOKEN` secret in the repository's Actions settings.
5. Run the SonarQube workflow and confirm it still passes.
6. **Revoke the `admin` token CI was using.**
Step 6 is worth calling out: the workflow is already green after step 5, so it is easy to stop there and leave the old credential valid, which makes the whole change cosmetic.
## Note for whoever does this
This server does not accept `Authorization: Bearer` — it is 9.9, and bearer auth arrived in SonarQube 10. A token goes in as the basic-auth username: `curl -u "$TOKEN:" ...`. Any script verifying the new account's permissions with a bearer header will report a permissions problem that is really an auth-scheme problem.
## Severity
Medium. Nothing is broken and nothing has gone wrong; the exposure is disproportionate to what the job actually needs, and the cost of fixing it is about ten minutes.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Split out of #61, which raised this as a "Related" note. Kept separate so a permissions change is not buried inside a CI-config commit.
Full write-up:
docs/ci/sonarqube-ci-identity.md.Problem
Gitea Actions authenticates to SonarQube with a token belonging to the
adminaccount.An analysis job needs exactly one permission: submit an analysis report for one project. The
admintoken carries every permission the server has — creating and deleting projects, editing quality gates and profiles, managing users, and reading every project on the server includingsql-utilities.The related half of this is already fixed: #67 removed the
-Dsonar.login=command-line argument, so the token now reaches the scanner only through theSONAR_TOKENenvironment variable and no longer appears on a command line where it could reach a log. What remains is whose token it is.Why it matters
Three ordinary situations, none of which need anyone to act badly:
set -x, a third-party action, a fork's workflow. The blast radius of a restricted analysis token is one project's analysis history. The blast radius of this one is everything on the server.sonar.projectKeyis just a string in a properties file. A wrong value combined with admin rights silently creates projects, and other admin endpoints can delete them. A restricted token fails instead.admin's token means tracking down everywhere else that account is used. A dedicated account rotates on its own.There is also a plainer reason: with CI showing up as
adminin the analysis history, the audit trail cannot tell an automated scan from a person making a change.Fix
gitea-ciwith no global permissions.redefined-designsonly.SONAR_TOKENsecret in the repository's Actions settings.admintoken CI was using.Step 6 is worth calling out: the workflow is already green after step 5, so it is easy to stop there and leave the old credential valid, which makes the whole change cosmetic.
Note for whoever does this
This server does not accept
Authorization: Bearer— it is 9.9, and bearer auth arrived in SonarQube 10. A token goes in as the basic-auth username:curl -u "$TOKEN:" .... Any script verifying the new account's permissions with a bearer header will report a permissions problem that is really an auth-scheme problem.Severity
Medium. Nothing is broken and nothing has gone wrong; the exposure is disproportionate to what the job actually needs, and the cost of fixing it is about ten minutes.