diff --git a/cmd/kosli/attestSonar.go b/cmd/kosli/attestSonar.go index cf8a9692a..b6a149c07 100644 --- a/cmd/kosli/attestSonar.go +++ b/cmd/kosli/attestSonar.go @@ -27,10 +27,10 @@ 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: @@ -38,15 +38,15 @@ The scan to be retrieved can be specified in two ways: 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 \ @@ -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 \ @@ -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 \ @@ -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 \ @@ -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 \ diff --git a/docs.kosli.com/content/getting_started/attestations.md b/docs.kosli.com/content/getting_started/attestations.md index 5f967fb81..edb0ebd72 100644 --- a/docs.kosli.com/content/getting_started/attestations.md +++ b/docs.kosli.com/content/getting_started/attestations.md @@ -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. diff --git a/docs.kosli.com/content/integrations/sonar.md b/docs.kosli.com/content/integrations/sonar.md index 63905d685..8c08ebd71 100644 --- a/docs.kosli.com/content/integrations/sonar.md +++ b/docs.kosli.com/content/integrations/sonar.md @@ -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 @@ -18,44 +18,44 @@ 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= @@ -63,7 +63,7 @@ These parameters can be passed to the scanner in three ways: ``` - As arguments to the CLI scanner ```shell -$ sonar scanner \ +$ sonar-scanner \ -Dsonar.analysis.kosli_flow= \ -Dsonar.analysis.kosli_trail= ``` @@ -71,13 +71,13 @@ $ sonar scanner \ ### Scanner parameters: - `sonar.analysis.kosli_flow=` - - 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=` - - 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=` - 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 ``), either the artifact fingerprint or git commit is also required (see below). - `sonar.analysis.kosli_git_commit=` - - 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=` - 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=` @@ -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.
+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.
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 diff --git a/docs.kosli.com/static/images/sonarcloud_integration_global.png b/docs.kosli.com/static/images/sonarcloud_integration_global.png deleted file mode 100644 index 3eeb1baa8..000000000 Binary files a/docs.kosli.com/static/images/sonarcloud_integration_global.png and /dev/null differ diff --git a/docs.kosli.com/static/images/sonarcloud_integration_project.png b/docs.kosli.com/static/images/sonarcloud_integration_project.png deleted file mode 100644 index fb3667b4c..000000000 Binary files a/docs.kosli.com/static/images/sonarcloud_integration_project.png and /dev/null differ diff --git a/docs.kosli.com/static/images/sonarqube-cloud-integration-global.png b/docs.kosli.com/static/images/sonarqube-cloud-integration-global.png new file mode 100644 index 000000000..546290cf0 Binary files /dev/null and b/docs.kosli.com/static/images/sonarqube-cloud-integration-global.png differ diff --git a/docs.kosli.com/static/images/sonarqube-cloud-integration-project.png b/docs.kosli.com/static/images/sonarqube-cloud-integration-project.png new file mode 100644 index 000000000..d6f2475a7 Binary files /dev/null and b/docs.kosli.com/static/images/sonarqube-cloud-integration-project.png differ diff --git a/docs.kosli.com/static/images/sonarqube-integration-global.png b/docs.kosli.com/static/images/sonarqube-integration-global.png new file mode 100644 index 000000000..518314105 Binary files /dev/null and b/docs.kosli.com/static/images/sonarqube-integration-global.png differ diff --git a/docs.kosli.com/static/images/sonarqube-integration-project.png b/docs.kosli.com/static/images/sonarqube-integration-project.png new file mode 100644 index 000000000..b3c0ca498 Binary files /dev/null and b/docs.kosli.com/static/images/sonarqube-integration-project.png differ diff --git a/docs.kosli.com/static/images/sonarqube_integration_global.png b/docs.kosli.com/static/images/sonarqube_integration_global.png deleted file mode 100644 index 2ca1ba190..000000000 Binary files a/docs.kosli.com/static/images/sonarqube_integration_global.png and /dev/null differ diff --git a/docs.kosli.com/static/images/sonarqube_integration_project.png b/docs.kosli.com/static/images/sonarqube_integration_project.png deleted file mode 100644 index c5d845ac0..000000000 Binary files a/docs.kosli.com/static/images/sonarqube_integration_project.png and /dev/null differ diff --git a/internal/sonar/sonar.go b/internal/sonar/sonar.go index 8782fd4d4..242348eaf 100644 --- a/internal/sonar/sonar.go +++ b/internal/sonar/sonar.go @@ -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 @@ -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 @@ -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 { @@ -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() @@ -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 { @@ -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 @@ -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 {