Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions cmd/kosli/attestSonar.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,26 +27,26 @@ type attestSonarOptions struct {
payload SonarAttestationPayload
}

const attestSonarShortDesc = `Report a SonarCloud or SonarQube attestation to an artifact or a trail in a Kosli flow. `
const attestSonarShortDesc = `Report a SonarQube attestation to an artifact or a trail in a Kosli flow. `

const attestSonarLongDesc = attestSonarShortDesc + `
Retrieves results for the specified scan from SonarCloud or SonarQube and attests them to Kosli.
Retrieves results for the specified scan from SonarQube Cloud or SonarQube Server and attests them to Kosli.
The results are parsed to find the status of the project's quality gate which is used to determine the attestation's compliance status.

The scan to be retrieved can be specified in two ways:
1. (Default) Using metadata created by the Sonar scanner. By default this is located within a temporary .scannerwork folder in the repo base directory.
If you have overriden the location of this folder by passing parameters to the Sonar scanner, or are running Kosli's CLI locally outside the repo's base directory,
you can provide the correct path using the --sonar-working-dir flag. This metadata is generated by a specific scan, allowing Kosli to retrieve the results of that scan.
2. Providing the Sonar project key and the revision of the scan (plus the SonarQube server URL if relevant). If running the Kosli CLI in some CI/CD pipeline, the revision
is defaulted to the commit SHA. If you are running the command locally, or have overriden the revision in SonarCloud/SonarQube via parameters to the Sonar scanner, you can
is defaulted to the commit SHA. If you are running the command locally, or have overriden the revision in SonarQube via parameters to the Sonar scanner, you can
provide the correct revision using the --sonar-revision flag. Kosli then finds the scan results for the specified project key and revision.

Note that if your project is very large and you are using SonarCloud's automatic analysis, it is possible for the attest sonar command to run before the SonarCloud scan is completed.
Note that if your project is very large and you are using SonarQube Cloud's automatic analysis, it is possible for the attest sonar command to run before the SonarQube Cloud scan is completed.
In this case, we recommend using Kosli's Sonar webhook integration ( https://docs.kosli.com/integrations/sonar/ ) rather than the CLI to attest the scan results.
` + attestationBindingDesc

const attestSonarExample = `
# report a sonarcloud attestation about a trail using Sonar's metadata:
# report a SonarQube Cloud attestation about a trail using Sonar's metadata:
kosli attest sonar \
--name yourAttestationName \
--flow yourFlowName \
Expand All @@ -56,7 +56,7 @@ kosli attest sonar \
--api-token yourAPIToken \
--org yourOrgName \

# report a sonarqube attestation about a trail using Sonar's metadata:
# report a SonarQube Server attestation about a trail using Sonar's metadata:
kosli attest sonar \
--name yourAttestationName \
--flow yourFlowName \
Expand All @@ -66,7 +66,7 @@ kosli attest sonar \
--api-token yourAPIToken \
--org yourOrgName \

# report a sonarcloud attestation for a specific branch about a trail using key/revision:
# report a SonarQube Cloud attestation for a specific branch about a trail using key/revision:
kosli attest sonar \
--name yourAttestationName \
--flow yourFlowName \
Expand All @@ -78,7 +78,7 @@ kosli attest sonar \
--api-token yourAPIToken \
--org yourOrgName \

# report a sonarqube attestation for a pull-request about a trail using key/revision:
# report a SonarQube Server attestation for a pull-request about a trail using key/revision:
kosli attest sonar \
--name yourAttestationName \
--flow yourFlowName \
Expand All @@ -91,7 +91,7 @@ kosli attest sonar \
--api-token yourAPIToken \
--org yourOrgName \

# report a sonarcloud attestation about a trail with an attachment using Sonar's metadata:
# report a SonarQube Cloud attestation about a trail with an attachment using Sonar's metadata:
kosli attest sonar \
--name yourAttestationName \
--flow yourFlowName \
Expand Down
8 changes: 8 additions & 0 deletions docs.kosli.com/content/getting_started/attestations.md
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,14 @@ Kosli CLI will also verify and report if the detected issue reference is found a

See [attest Jira issue to an artifact or a trail](/client_reference/kosli_attest_jira/) for usage details and examples.

### SonarQube scan results

You can report the results of a SonarQube Server or SonarQube Cloud scan to Kosli. Kosli will use the status of the scan's Quality Gate (passing or failing) to determine the compliance status.

These scan result can be attested in two ways:
- Using Kosli's [webhook integration](/integrations/sonar) with Sonar
- Using [Kosli's CLI](/client_reference/kosli_attest_sonar)

### Custom

The above attestations are all "fully typed" - each one knows how to interpret its own particular kind of input.
Expand Down
42 changes: 21 additions & 21 deletions docs.kosli.com/content/integrations/sonar.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
title: Sonar
bookCollapseSection: false
weight: 340
summary: "The results of SonarCloud and SonarQube scans can be tracked in Kosli trails. This integration involves setting up a Sonar webhook in Kosli and a corresponding webhook in SonarCloud or SonarQube. When you run a scan of your SonarCloud/SonarQube project, the webhook is triggered and the results of the scan are sent to Kosli."
summary: "The results of SonarQube Server and SonarQube Cloud scans can be tracked in Kosli trails. This integration involves setting up a Sonar webhook in Kosli and a corresponding webhook in SonarQube. When you run a scan of your SonarQube project, the webhook is triggered and the results of the scan are sent to Kosli."
---
# Record Sonar scan results in Kosli

The results of SonarCloud and SonarQube scans can be tracked in [Kosli trails](/getting_started/trails/).
This integration involves setting up a Sonar webhook in Kosli and a corresponding webhook in SonarCloud or SonarQube. When you run a scan of your SonarCloud/SonarQube project, the webhook is triggered and the results of the scan are sent to Kosli.
The results of SonarQube Server and SonarQube Cloud scans can be tracked in [Kosli trails](/getting_started/trails/).
This integration involves setting up a Sonar webhook in Kosli and a corresponding webhook in SonarQube. When you run a scan of your SonarQube project, the webhook is triggered and the results of the scan are sent to Kosli.
Some parameters must be passed to the Sonar scanner when it is run (e.g. the name of the Flow corresponding to the project, and the name of the trail the results should be attested to); these are sent with the scan results, and allow Kosli to determine the compliance status of the results and attest them to the correct trail/artifact.

## Setting up in Kosli
Expand All @@ -18,66 +18,66 @@ After switching on the integration, you will be provided with a webhook and a se

## Setting up Sonar Webhooks

You're now just a few steps away from connecting SonarCloud/SonarQube to Kosli.
You're now just a few steps away from connecting SonarQube to Kosli.

Both SonarCloud and SonarQube provide two types of webhooks: global (which are triggered when any project in your organization is scanned) and project-specific (which are triggered by a scan for that project only). Kosli supports both types of webhooks.
Both SonarQube Server and SonarQube Cloud provide two types of webhooks: global (which are triggered when any project in your organization is scanned) and project-specific (which are triggered by a scan for that project only). Kosli supports both types of webhooks.

In [SonarCloud](https://sonarcloud.io/) or [SonarQube](https://sonarqube.org):
In [SonarQube Cloud](https://sonarcloud.io/) or [SonarQube Server](https://sonarqube.org):

### To create a global webhook:

- In SonarCloud: Go to your Organization, then Administration > Webhooks
- In SonarQube: Go to Administration > Configuration > Webhooks
- In SonarQube Cloud: Go to your Organization, then Administration > Webhooks
- In SonarQube Server: Go to Administration > Configuration > Webhooks
- Create a new Webhook
- Add the Kosli webhook URL and secret provided
- Click Create

![SonarCloud Global Webhook page](/images/sonarcloud_integration_global.png)
![SonarQube Global Webhook page](/images/sonarqube_integration_global.png)
![SonarQube Cloud Global Webhook page](/images/sonarqube-cloud-integration-global.png)
![SonarQube Server Global Webhook page](/images/sonarqube-integration-global.png)

### To create a project-specific webhook:

- Go to the project you want to create a webhook for
- Click on Administration (SonarCloud) or Project Settings (SonarQube) and go to Webhooks in the dropdown menu
- Click on Administration (SonarQube Cloud) or Project Settings (SonarQube Server) and go to Webhooks in the dropdown menu
- Create a new Webhook
- Add the Kosli webhook URL and secret provided
- Click Create

![SonarCloud Project Webhook page](/images/sonarcloud_integration_project.png)
![SonarQube Project Webhook page](/images/sonarqube_integration_project.png)
![SonarQube Cloud Project Webhook page](/images/sonarqube-cloud-integration-project.png)
![SonarQube Server Project Webhook page](/images/sonarqube-integration-project.png)

## Setting up the SonarScanner

In order for Kosli to know where the scan results should be attested, certain parameters can be passed to the SonarScanner. Note that parameters cannot be passed with SonarCloud's Automatic Analysis - in this case, Kosli determines the relevant Flow and Trail as described below.
In order for Kosli to know where the scan results should be attested, certain parameters can be passed to the SonarScanner. Note that parameters cannot be passed with SonarQube Cloud's Automatic Analysis - in this case, Kosli determines the relevant Flow and Trail as described below.

These parameters can be passed to the scanner in three ways:
- As part of the sonar-project.properties file used in CI analysis
- As arguments to the scanner in your CI pipeline's YML file
```shell
- name: SonarCloud Scan
uses: sonarsource/sonarcloud-github-action@master
- name: SonarQube Scan
uses: SonarSource/sonarqube-scan-action@master
with:
args: >
-Dsonar.analysis.kosli_flow=<YourFlowName>
-Dsonar.analysis.kosli_trail=<YourTrailName>
```
- As arguments to the CLI scanner
```shell
$ sonar scanner \
$ sonar-scanner \
-Dsonar.analysis.kosli_flow=<YourFlowName> \
-Dsonar.analysis.kosli_trail=<YourTrailName>
```


### Scanner parameters:
- `sonar.analysis.kosli_flow=<YourFlowName>`
- The name of the Flow relevant to your project. If a Flow does not already exist with the given name, it is created. If no Flow name is provided, the project key of your project in SonarCloud/SonarQube is used as the name (with any invalid symbols replaced by '-').
- The name of the Flow relevant to your project. If a Flow does not already exist with the given name, it is created. If no Flow name is provided, the project key of your project in SonarQube is used as the name (with any invalid symbols replaced by '-').
- `sonar.analysis.kosli_trail=<YourTrailName>`
- The name of the Trail to attest the scan results. If a Trail does not already exist with the given name it is created. If no Trail name is provided, the revision ID of the Sonar project (typically defaulted to the Git SHA) is used as the name.
- The name of the Trail to attest the scan results. If a Trail does not already exist with the given name it is created. If no Trail name is provided, the revision ID of the SonarQube project (typically defaulted to the Git SHA) is used as the name.
- `sonar.analysis.kosli_attestation=<YourAttestationName>`
- The name you want to give to the attestation. If not provided, a default name "sonar" is used. If using dot-notation (of the form `<YourTargetArtifact.YourAttestationName>`), either the artifact fingerprint or git commit is also required (see below).
- `sonar.analysis.kosli_git_commit=<GitCommitSHA>`
- The git commit for the attestation. If not provided the revision ID of the Sonar project is used (provided it has the correct format for a git SHA).
- The git commit for the attestation. If not provided the revision ID of the SonarQube project is used (provided it has the correct format for a git SHA).
- `sonar.analysis.kosli_artifact_fingerprint=<YourArtifactFingerprint>`
- The fingerprint of the artifact you want the attestation to be attached to. Requires that the artifact has already been reported to Kosli.
- `sonar.analysis.kosli_flow_description=<DescriptionOfYourKosliFlow>`
Expand All @@ -87,7 +87,7 @@ $ sonar scanner \

## Testing the integration

To test the webhook once configured, simply scan a project in SonarCloud or SonarQube. If successful, the results of the scan will be attested to the relevant Flow and Trail (and artifact, if applicable) as a sonar attestation. <br>
To test the webhook once configured, simply scan a project in SonarQube. If successful, the results of the scan will be attested to the relevant Flow and Trail (and artifact, if applicable) as a sonar attestation. <br>
If the webhook fails, check that you have passed the parameters to the scanner correctly, and that the trail name, attestation name and artifact fingerprint are valid.

## Live Example in CI system
Expand Down
Binary file not shown.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Binary file not shown.
14 changes: 7 additions & 7 deletions internal/sonar/sonar.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ func (sc *SonarConfig) GetSonarResults() (*SonarResults, error) {
if sc.APIToken != "" {
tokenHeader = fmt.Sprintf("Bearer %s", sc.APIToken)
} else {
return nil, fmt.Errorf("API token must be given to retrieve data from SonarCloud/SonarQube")
return nil, fmt.Errorf("API token must be given to retrieve data from SonarQube")
}

// Read the report-task.txt file (if it exists) to get the project key, server URL, dashboard URL and ceTaskURL
Expand Down Expand Up @@ -225,7 +225,7 @@ func GetCETaskData(httpClient *http.Client, project *Project, sonarResults *Sona
taskResponseData := &TaskResponse{}
err = json.NewDecoder(taskResponse.Body).Decode(taskResponseData)
if err != nil {
return "", fmt.Errorf("please check your API token is correct and you have the correct permissions in SonarCloud/SonarQube")
return "", fmt.Errorf("please check your API token is correct and you have the correct permissions in SonarQube")
}

project.Name = taskResponseData.Task.ComponentName
Expand Down Expand Up @@ -272,7 +272,7 @@ func GetProjectAnalysisFromRevision(httpClient *http.Client, sonarResults *Sonar
projectAnalysesData := &ProjectAnalyses{}
err = json.NewDecoder(projectAnalysesResponse.Body).Decode(projectAnalysesData)
if err != nil {
return "", fmt.Errorf("please check your API token and SonarQube server URL are correct and you have the correct permissions in SonarCloud/SonarQube")
return "", fmt.Errorf("please check your API token and SonarQube server URL are correct and you have the correct permissions in SonarQube")
}

for analysis := range projectAnalysesData.Analyses {
Expand All @@ -288,7 +288,7 @@ func GetProjectAnalysisFromRevision(httpClient *http.Client, sonarResults *Sonar
}

if sonarResults.AnalaysedAt == "" {
return "", fmt.Errorf("analysis for revision %s of project %s not found. Check the revision is correct. Snapshot may also have been deleted by Sonar", revision, project.Key)
return "", fmt.Errorf("analysis for revision %s of project %s not found. Check the revision is correct. Snapshot may also have been deleted by SonarQube", revision, project.Key)
}
projectAnalysesResponse.Body.Close()

Expand All @@ -311,7 +311,7 @@ func GetProjectAnalysisFromAnalysisID(httpClient *http.Client, sonarResults *Son
projectAnalysesData := &ProjectAnalyses{}
err = json.NewDecoder(projectAnalysesResponse.Body).Decode(projectAnalysesData)
if err != nil {
return fmt.Errorf("please check your API token is correct and you have the correct permissions in SonarCloud/SonarQube")
return fmt.Errorf("please check your API token is correct and you have the correct permissions in SonarQube")
}

for analysis := range projectAnalysesData.Analyses {
Expand All @@ -323,7 +323,7 @@ func GetProjectAnalysisFromAnalysisID(httpClient *http.Client, sonarResults *Son
}

if sonarResults.AnalaysedAt == "" {
return fmt.Errorf("analysis with ID %s not found. Snapshot may have been deleted by Sonar", analysisID)
return fmt.Errorf("analysis with ID %s not found. Snapshot may have been deleted by SonarQube", analysisID)
}

return nil
Expand Down Expand Up @@ -385,7 +385,7 @@ func GetTaskID(httpClient *http.Client, sonarResults *SonarResults, project *Pro
CEActivityData := &ActivityResponse{}
err = json.NewDecoder(CEActivityResponse.Body).Decode(CEActivityData)
if err != nil {
return fmt.Errorf("please check your API token is correct and you have the correct permissions in SonarCloud/SonarQube")
return fmt.Errorf("please check your API token is correct and you have the correct permissions in SonarQube")
}

for task := range CEActivityData.Tasks {
Expand Down
Loading