Skip to content

Commit eeeddba

Browse files
committed
Support for sonar selfhosted evidence
1 parent bed0bbe commit eeeddba

4 files changed

Lines changed: 209 additions & 157 deletions

File tree

examples/sonar-scan-example/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ should be checked using a policy.
1010

1111
## Environment variables
1212
- `SONAR_TOKEN` - The sonar server token.
13+
- `SONAR_TYPE` - Should be Either SAAS or SELFHOSTED.
14+
- `SONAR_HOST` - The sonar server host name, for example sonar.myconpany.org. required for SELFHOSTED type, if not provided for SAAS type sonarcloud.io is used as default.
1315

1416
## Arguments
1517
`--reportTaskFile=<path>` - The path to the sonar report task file.

examples/sonar-scan-example/main.go

Lines changed: 23 additions & 154 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,8 @@ import (
33
"context"
44
"encoding/json"
55
"os"
6-
"fmt"
7-
"io"
86
"log"
9-
"net/http"
107
"time"
11-
"bufio"
128
"strings"
139
"strconv"
1410
)
@@ -71,8 +67,7 @@ type SonarAnalysis struct {
7167

7268
const (
7369
DEFAULT_HTTP_TIMEOUT = 10 * time.Second
74-
ANALYSIS_URL = "https://sonarcloud.io/api/qualitygates/project_status?analysisId=$analysisId"
75-
LOG_FILE_LOCATION = "sonar-scan.log"
70+
LOG_FILE_LOCATION = "sonar-scan.log"
7671
)
7772
func main() {
7873
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
@@ -90,11 +85,17 @@ func main() {
9085
logger.Println("Sonar token not found, set SONAR_TOKEN variable")
9186
os.Exit(1)
9287
}
93-
///home/runner/work/Evidence-Examples/Evidence-Examples/.scannerwork/report-task.txt
88+
sonar_type := os.Getenv("SONAR_TYPE")
89+
if sonar_type != "SELFHOSTED" && sonar_type != "SAAS" {
90+
logger.Println("Wrong Sonar type, set SONAR_TYPE variable to either SAAS or SELFHOSTED")
91+
os.Exit(1)
92+
}
93+
94+
//home/runner/work/Evidence-Examples/Evidence-Examples/.scannerwork/report-task.txt
9495
//get the sonar report file location or details to .scannerwork/.report-task.txt
9596
reportTaskFile := ".scannerwork/.report-task.txt"
9697
failOnAnalysisFailure := false
97-
maxRetries := 0
98+
maxRetries := 1
9899
waitTime := 5
99100
if len(os.Args) > 0 {
100101
// loop over all args
@@ -127,95 +128,30 @@ func main() {
127128
logger.Println("maxRetries:", maxRetries)
128129
logger.Println("WaitTime:", waitTime)
129130
}
130-
// fmt.Println("reportTaskFile: ", reportTaskFile)
131-
// Open the reportTaskFile
132-
file, err := os.Open(reportTaskFile)
133-
if err != nil {
134-
logger.Println("Error opening file:", reportTaskFile, "error:", err)
135-
os.Exit(1)
136-
}
137-
defer file.Close()
138-
ceTaskUrl:=""
131+
response := SonarResponse{}
132+
defaultSonarHost := "sonarcloud.io"
133+
sonarHost := os.Getenv("SONAR_HOST")
139134

140-
// Read the file line by line
141-
scanner := bufio.NewScanner(file)
142-
for scanner.Scan() {
143-
line := scanner.Text()
144-
// Skip empty lines and comments
145-
if len(line) == 0 || strings.HasPrefix(line, "#") {
146-
continue
147-
}
148-
// Split the line into key and value
149-
parts := strings.SplitN(line, "=", 2)
150-
if len(parts) == 2 {
151-
key := strings.TrimSpace(parts[0])
152-
value := strings.TrimSpace(parts[1])
153-
if key == "ceTaskUrl" {
154-
ceTaskUrl = value
155-
break
156-
}
157-
}
158-
}
159-
if err := scanner.Err(); err != nil {
160-
logger.Println("Error reading file:", reportTaskFile , "error", err)
161-
os.Exit(1)
162-
}
163-
if ceTaskUrl == "" {
164-
fmt.Printf("ceTaskUrl Key not found")
165-
os.Exit(1)
166-
}
167-
// Add a reusable HTTP client
168-
var client = &http.Client{
169-
Timeout: DEFAULT_HTTP_TIMEOUT,
170-
Transport: &http.Transport{
171-
MaxIdleConns: 100,
172-
IdleConnTimeout: 10 * time.Second,
173-
DisableCompression: true,
174-
},
175-
}
176-
logger.Println("ceTaskUrl", ceTaskUrl)
177-
// get the report task
178-
retries := 0
135+
if sonar_type == "SAAS" {
136+
if sonarHost == "" {
137+
sonarHost = defaultSonarHost
138+
}
139+
logger.Println("Running sonar analysis extraction for SAAS, host:", sonarHost)
179140

180-
var taskResponse SonarTaskResponse
181-
for retries < maxRetries {
182-
taskResponse, err = getReport(ctx, client, logger, ceTaskUrl, sonar_token )
183-
if err != nil {
184-
logger.Println("Error getting sonar report task", err)
141+
}else if sonar_type == "SELFHOSTED" {
142+
if sonarHost == "" {
143+
logger.Println("Sonar host not found, set SONAR_HOST variable")
185144
os.Exit(1)
186145
}
187-
if taskResponse.Task.Status == "SUCCESS" {
188-
logger.Println("Sonar analysis task completed successfully after ", retries, " retries")
189-
break
190-
}
191-
if taskResponse.Task.Status == "PENDING" || taskResponse.Task.Status == "IN_PROGRESS" {
192-
logger.Println("Sonar analysis task is still in progress, waiting for ", waitTime, " seconds before retrying")
193-
time.Sleep(time.Duration(waitTime) * time.Second)
194-
retries++
195-
}
196-
}
197-
if (taskResponse.Task.Status != "SUCCESS") {
198-
logger.Println("Sonar analysis task after ", maxRetries, " retries is ", taskResponse.Task.Status, "exiting")
199-
os.Exit(1)
146+
logger.Println("Running sonar analysis extraction for " , sonar_type, " server", sonarHost)
200147
}
148+
response, err = runReport(ctx, logger, sonarHost, sonar_token, reportTaskFile, failOnAnalysisFailure, maxRetries, waitTime)
201149

202-
logger.Println("taskResponse.Task.AnalysisId", taskResponse.Task.AnalysisId)
203-
// get the analysis content
204-
analysis , err := getAnalysis(ctx, client, logger, sonar_token, taskResponse.Task.AnalysisId)
205150
if err != nil {
206-
logger.Println("Error getting sonar analysis report: ", err)
207-
os.Exit(1)
208-
}
209-
if analysis.ProjectStatus.Status != "OK" && failOnAnalysisFailure {
210-
logger.Println("Sonar analysis failed, exiting according to failOnAnalysisFailure argument")
151+
logger.Println("Error in generating report predicate:", err)
211152
os.Exit(1)
212153
}
213154

214-
response := SonarResponse{
215-
Task: taskResponse.Task,
216-
Analysis: analysis.ProjectStatus,
217-
}
218-
219155
// marshal the response to JSON
220156
jsonBytes, err := json.Marshal(response)
221157
if err != nil {
@@ -225,70 +161,3 @@ func main() {
225161
// return response to caller through stdout
226162
os.Stdout.Write(jsonBytes)
227163
}
228-
229-
230-
func getReport(ctx context.Context , client *http.Client, logger *log.Logger, ceTaskUrl string, sonar_token string) (SonarTaskResponse, error) {
231-
// Make the HTTP GET request
232-
logger.Println("getReport ceTaskUrl:",ceTaskUrl)
233-
req, err := http.NewRequestWithContext(ctx, "GET", ceTaskUrl, nil)
234-
req.Header.Set("Authorization", "Bearer " + sonar_token)
235-
resp, err := client.Do(req)
236-
if err != nil {
237-
return SonarTaskResponse{}, fmt.Errorf("Error making the request, url:",ceTaskUrl, "error", err)
238-
}
239-
240-
defer resp.Body.Close()
241-
body, err := io.ReadAll(resp.Body)
242-
if err != nil {
243-
logger.Println("getReport error getting response body error:", err)
244-
return SonarTaskResponse{}, fmt.Errorf("getReport error getting response body error, url:",ceTaskUrl, "error", err)
245-
}
246-
247-
if resp.StatusCode != http.StatusOK {
248-
return SonarTaskResponse{}, fmt.Errorf("getReport error getting response from", ceTaskUrl, " returned ", resp.StatusCode, " response body ", body)
249-
}
250-
251-
logger.Println("getReport resp.StatusCode:", resp.StatusCode)
252-
253-
var taskResponse SonarTaskResponse
254-
err = json.Unmarshal(body, &taskResponse)
255-
if err != nil {
256-
logger.Println("getReport error Unmarshal response body ", string(body))
257-
return SonarTaskResponse{}, fmt.Errorf("error unmarshal report response for report", ceTaskUrl, "error", err)
258-
}
259-
logger.Println("getReport taskResponse:", taskResponse)
260-
return taskResponse, nil
261-
}
262-
263-
func getAnalysis(ctx context.Context, client *http.Client, logger *log.Logger, sonar_token string, analysisId string) (SonarAnalysis, error) {
264-
265-
analysisUrl := strings.Replace(ANALYSIS_URL, "$analysisId", analysisId, 1)
266-
logger.Println("analysisId", analysisId)
267-
//logger.Println("analysisUrl", analysisUrl)
268-
// Make the HTTP GET request
269-
req, err := http.NewRequestWithContext(ctx, "GET", analysisUrl , nil)
270-
req.Header.Set("Authorization", "Bearer " + sonar_token)
271-
resp, err := client.Do(req)
272-
if err != nil {
273-
return SonarAnalysis{}, fmt.Errorf("getAnalysis, Error making the request, url:",analysisUrl, "error", err)
274-
}
275-
defer resp.Body.Close()
276-
body, err := io.ReadAll(resp.Body)
277-
if err != nil {
278-
logger.Println("getAnalysis error getting response body error:", err)
279-
return SonarAnalysis{}, fmt.Errorf("getAnalysis error getting response body error, url:",analysisUrl, "error", err)
280-
}
281-
282-
if resp.StatusCode != http.StatusOK {
283-
return SonarAnalysis{}, fmt.Errorf("getAnalysis, error getting response from", analysisUrl, " returned ", resp.StatusCode, " response body ", body)
284-
}
285-
286-
var analysisResponse SonarAnalysis
287-
err = json.Unmarshal(body, &analysisResponse)
288-
if err != nil {
289-
log.Println("getAnalysis, get temp credentials response body ", string(body))
290-
return SonarAnalysis{}, fmt.Errorf("getAnalysis, error unmarshal analysis response", analysisUrl, "error", err)
291-
}
292-
293-
return analysisResponse, nil
294-
}

0 commit comments

Comments
 (0)