Skip to content

CI: SonarQube job fails on every fork PR because SONAR_TOKEN is unavailable #6492

Description

@almacbe

Problem

The sonarqube job in continuous-integration.yml runs on PRs from forks, but GitHub does not expose repository secrets to pull_request workflows triggered from a fork. SONAR_TOKEN is therefore empty and the scanner fails at startup, before analysing anything:

ERROR Error retrieving feature flags, using default analyzer behavior
Not authorized or project not found. Please check the 'SONAR_TOKEN' environment
variable, the 'sonar.projectKey' and 'sonar.organization' properties, or contact
the project administrator to verify the token's permissions.
INFO  Check ALM binding of project 'scrumlr_scrumlr' -> Detected project binding: ERROR
INFO  EXECUTION FAILURE   (Total time: 14.650s)
##[error]Action failed: sonar-scanner failed with exit code 3

The result is a red check that carries no information: external contributions get no Sonar analysis at all, and the failure looks identical whether the code is clean or not.

Affected PRs

#6488, #6489, #6490 — all from almacbe/scrumlr.io. In all three:

Check Result
Build and Test – Backend pass
Build and Test – Frontend pass
SonarQube fail (~14s, exit 3)
package, Cypress, e2e, deploy, docs skipping

Root cause

The job is triggered by pull_request, which runs in the fork's context without access to secrets:

# .github/workflows/continuous-integration.yml:111
if: ${{ github.event.pull_request.user.login != 'dependabot[bot]' }}

On same-repo branches the scanner runs to completion (EXECUTION SUCCESS) and any failure is a genuine Quality Gate result. On forks it never gets that far.

Note that the existing dependabot exclusion is not the same problem and should stay: those PRs only bump dependency versions and never touch repository code, so there are no Sonar metrics worth measuring. Fork PRs are the opposite case — they are exactly the contributions that need the quality gate — so skipping them is not an acceptable fix.

Options

  1. Split the analysis into a workflow_run workflow (GitHub's recommended pattern for handling untrusted PR builds). The pull_request workflow builds and uploads the compiled output, coverage reports and PR metadata as artifacts; a second workflow triggered on workflow_run: completed runs in the base repo's context, has access to SONAR_TOKEN, downloads those artifacts and submits the analysis. Untrusted code is never executed with secrets in scope. Cost: one extra workflow file and some artifact plumbing.

  2. Use pull_request_target for the Sonar job. Simpler to wire up, but it runs with secrets available in a context where the PR's own code is checked out, so it needs careful handling (pinned checkout of the base ref, no execution of fork-supplied scripts) to avoid secret exfiltration. Only worth it if option 1 is considered too heavy.

Option 1 is the safer of the two and the one I would suggest. Happy to open the PR implementing it if you agree on the approach.


Edited: option 1 originally read "SonarSource's recommended pattern for forks". That attribution was wrong and has been corrected above — see this comment.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions