Skip to content

Commit 4a396d3

Browse files
authored
Merge pull request #9 from CallMeGreg/CallMeGreg/release-cleanup
CallMeGreg/release-cleanup
2 parents 6d3cec0 + 27b0f8e commit 4a396d3

File tree

4 files changed

+40
-42
lines changed

4 files changed

+40
-42
lines changed

README.md

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Overview
22
This project is a GitHub CLI (`gh`) extension that provides commands for interacting with secret scanning alerts. Primary uses include:
33
- Listing secret scanning alerts for an enterprise, organization, or repository
4-
- Verifying if a secret is valid
4+
- Verifying if secret alerts are still active
55
- Opening issues in repos that contain valid secrets
66

77
# Supported Token Types
@@ -103,9 +103,7 @@ Use "secret-scanning [command] --help" for more information about a command.
103103
```
104104

105105
# Demo
106-
This example first lists the alerts for an organization with the `alerts` subcommand, and then verifies the secrets with the `verify` subcommand. The `-c` flag is used to generate a csv report of the results, and the `-i` flag is used to create an issue in any repository that contains a valid secret.
107-
108-
https://github.com/CallMeGreg/gh-secret-scanning/assets/110078080/58f685a2-52a8-4478-92f9-d7468065ede5
109-
106+
This example first lists the alerts for an organization with the `alerts` subcommand, and then verifies the secrets with the `verify` subcommand. The `-c` flag is used to generate a csv report of the results, and the `-i` flag is used to create issues in any repository that contains a valid secret.
110107

108+
https://github.com/CallMeGreg/gh-secret-scanning/assets/110078080/fa8d7b08-1a2c-4522-ae96-5c3aab60107d
111109

cmd/alerts.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package cmd
22

33
import (
44
"fmt"
5-
"log"
65
"math"
76
"net/url"
87
"strconv"
@@ -79,10 +78,10 @@ func runAlerts(cmd *cobra.Command, args []string) (err error) {
7978
}
8079

8180
for page := 1; page <= pages; page++ {
82-
log.Printf("Processing page: %d\n", page)
81+
fmt.Println("Processing page: " + strconv.Itoa(page))
8382
_, nextPage, err := callGitHubAPI(client, requestPath, &pageOfSecretAlerts, GET)
8483
if err != nil {
85-
log.Printf("ERROR: Unable to get alerts for target: %s\n", requestPath)
84+
fmt.Println("ERROR: Unable to get alerts for target: " + requestPath)
8685
return err
8786
}
8887
for _, secretAlert := range pageOfSecretAlerts {
@@ -108,7 +107,7 @@ func runAlerts(cmd *cobra.Command, args []string) (err error) {
108107

109108
// pretty print all of the response details:
110109
if !quiet {
111-
prettyPrintAlerts(sortedAlerts, false)
110+
err = prettyPrintAlerts(sortedAlerts, false)
112111
}
113112

114113
// optionally generate a csv report of the results:

cmd/common.go

Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import (
77
"errors"
88
"fmt"
99
"io"
10-
"log"
1110
"net/http"
1211
"os"
1312
"regexp"
@@ -84,7 +83,7 @@ func createGitHubSecretAlertsAPIPath(scope string, target string) (apiURL string
8483
replacer := strings.NewReplacer("{owner}", owner, "{repo}", repo)
8584
apiURL = replacer.Replace(repositoryAlertsURL)
8685
default:
87-
log.Fatal("Invalid API target.")
86+
err = fmt.Errorf("Invalid API target.")
8887
}
8988
return apiURL, err
9089
}
@@ -159,13 +158,13 @@ func callGitHubAPI(client *api.RESTClient, requestPath string, parseType interfa
159158
nextPage := response.Header.Get("Link")
160159
responseBody, err := io.ReadAll(response.Body)
161160
if err != nil {
162-
log.Println("ERROR: Unable to read next page link")
161+
fmt.Println("ERROR: Unable to read next page link")
163162
return response.StatusCode, nextPage, err
164163
}
165164

166165
err = decodeJSONResponse(responseBody, &parseType)
167166
if err != nil {
168-
log.Println("ERROR: Unable to decode JSON response")
167+
fmt.Println("ERROR: Unable to decode JSON response")
169168
return response.StatusCode, nextPage, err
170169
}
171170

@@ -176,7 +175,7 @@ func decodeJSONResponse(body []byte, parseType interface{}) error {
176175
decoder := json.NewDecoder(bytes.NewReader(body))
177176
err := decoder.Decode(&parseType)
178177
if err != nil {
179-
log.Println("ERROR: Unable to decode JSON response")
178+
fmt.Println("ERROR: Unable to decode JSON response")
180179
return err
181180
}
182181

@@ -263,7 +262,7 @@ func getScopeAndTarget() (scope string, target string, err error) {
263262
return scope, target, err
264263
}
265264

266-
func prettyPrintAlerts(alerts []Alert, validity_check bool) {
265+
func prettyPrintAlerts(alerts []Alert, validity_check bool) (err error) {
267266
counter := 0
268267
if len(alerts) > 0 {
269268
terminal := term.FromEnv()
@@ -327,14 +326,16 @@ func prettyPrintAlerts(alerts []Alert, validity_check bool) {
327326
counter++
328327
}
329328
if err := t.Render(); err != nil {
330-
log.Fatal(err)
329+
err = fmt.Errorf("error rendering table: %v", err)
330+
return err
331331
}
332332
}
333333
if limit < len(alerts) {
334334
fmt.Println(Blue("Fetched " + strconv.Itoa(limit) + " secret alerts."))
335335
} else {
336336
fmt.Println(Blue("Fetched " + strconv.Itoa(len(alerts)) + " secret alerts."))
337337
}
338+
return err
338339
}
339340

340341
func generateCSVReport(alerts []Alert, scope string, validity_check bool) (err error) {
@@ -348,7 +349,8 @@ func generateCSVReport(alerts []Alert, scope string, validity_check bool) (err e
348349
// Create a CSV file
349350
file, err := os.Create(filename)
350351
if err != nil {
351-
log.Fatal(err)
352+
fmt.Println("ERROR: Error creating CSV file.")
353+
return err
352354
}
353355
defer file.Close()
354356
// Initialize CSV writer
@@ -383,7 +385,8 @@ func generateCSVReport(alerts []Alert, scope string, validity_check bool) (err e
383385
counter++
384386
}
385387
if err := writer.Error(); err != nil {
386-
log.Fatal(err)
388+
fmt.Println("ERROR: Error writing to CSV file.")
389+
return err
387390
}
388391
fmt.Println(Blue("CSV report generated: " + filename))
389392
return err
@@ -406,7 +409,7 @@ func verifyAlerts(alerts []Alert) (alertsOutput []Alert, err error) {
406409
}
407410
client, err := api.NewHTTPClient(opts)
408411
if err != nil {
409-
log.Println("ERROR: Unable to create HTTP client")
412+
fmt.Println("ERROR: Unable to create HTTP client.")
410413
return alerts, err
411414
}
412415
// send a request to the validation endpoint:
@@ -420,20 +423,20 @@ func verifyAlerts(alerts []Alert) (alertsOutput []Alert, err error) {
420423
response, err = client.Do(req)
421424
// response, err = client.Post(alert.Validity_endpoint, secret_validation_content_type, body)
422425
if err != nil {
423-
log.Println("ERROR: Unable to send " + secret_validation_method + " request to " + alert.Validity_endpoint)
426+
fmt.Println("WARNING: Unable to send " + secret_validation_method + " request to " + alert.Validity_endpoint)
424427
continue
425428
}
426429
alert.Validity_response_code = strconv.Itoa(response.StatusCode)
427430
defer response.Body.Close()
428431
} else if secret_validation_method == "GET" {
429432
response, err = client.Get(alert.Validity_endpoint)
430433
if err != nil {
431-
log.Println("ERROR: Unable to send " + secret_validation_method + " request to " + alert.Validity_endpoint)
434+
fmt.Println("WARNING: Unable to send " + secret_validation_method + " request to " + alert.Validity_endpoint)
432435
continue
433436
}
434437
alert.Validity_response_code = strconv.Itoa(response.StatusCode)
435438
} else {
436-
log.Println("ERROR: Invalid HTTP method for validation endpoint")
439+
fmt.Println("WARNING: Invalid HTTP method for validation endpoint for " + alert.Secret_type + " secret type.")
437440
continue
438441
}
439442
expected_body_key := SupportedProviders[provider][secret_type]["ExpectedBodyKey"]
@@ -443,7 +446,7 @@ func verifyAlerts(alerts []Alert) (alertsOutput []Alert, err error) {
443446
} else if alert.Validity_response_code == "200" {
444447
alert.Validity_boolean = true
445448
if verbose {
446-
log.Println(Yellow("CONFIRMED: Alert " + strconv.Itoa(alert.Number) + " in " + alert.Repository.Full_name + " is valid."))
449+
fmt.Println(Yellow("CONFIRMED: Alert " + strconv.Itoa(alert.Number) + " in " + alert.Repository.Full_name + " is valid."))
447450
}
448451
} else {
449452
alert.Validity_boolean = false
@@ -454,7 +457,7 @@ func verifyAlerts(alerts []Alert) (alertsOutput []Alert, err error) {
454457
if alert.Validity_response_code == "200" {
455458
alert.Validity_boolean = true
456459
if verbose {
457-
log.Println(Yellow("CONFIRMED: Alert " + strconv.Itoa(alert.Number) + " in " + alert.Repository.Full_name + " is valid."))
460+
fmt.Println(Yellow("CONFIRMED: Alert " + strconv.Itoa(alert.Number) + " in " + alert.Repository.Full_name + " is valid."))
458461
}
459462
} else {
460463
alert.Validity_boolean = false
@@ -468,16 +471,15 @@ func verifyAlerts(alerts []Alert) (alertsOutput []Alert, err error) {
468471
func checkForExpectedBody(response *http.Response, expected_body_key string, expected_body_value string, alert Alert) (validity_boolean bool) {
469472
body, err := io.ReadAll(response.Body)
470473
if err != nil {
471-
log.Println("ERROR: Unable to read response body")
474+
fmt.Println("ERROR: Unable to read response body for alert " + strconv.Itoa(alert.Number) + " in " + alert.Repository.Full_name)
472475
return false
473476
}
474477
var response_body map[string]interface{}
475478
err = json.Unmarshal(body, &response_body)
476479
if err != nil {
477-
log.Println("ERROR: Unable to unmarshal response body")
480+
fmt.Println("ERROR: Unable to unmarshal response body for alert " + strconv.Itoa(alert.Number) + " in " + alert.Repository.Full_name)
478481
return false
479482
}
480-
log.Println(response_body)
481483
body_value := response_body[expected_body_key]
482484
if body_value.(bool) {
483485
// convert response_value to a string
@@ -486,7 +488,7 @@ func checkForExpectedBody(response *http.Response, expected_body_key string, exp
486488
if body_value == expected_body_value {
487489
alert.Validity_boolean = true
488490
if verbose {
489-
log.Println(Yellow("CONFIRMED: Alert " + strconv.Itoa(alert.Number) + " in " + alert.Repository.Full_name + " is valid."))
491+
fmt.Println(Yellow("CONFIRMED: Alert " + strconv.Itoa(alert.Number) + " in " + alert.Repository.Full_name + " is valid."))
490492
}
491493
} else {
492494
alert.Validity_boolean = false
@@ -503,7 +505,7 @@ func checkEnterpriseServerAPI(alert Alert, client *http.Client, secret_validatio
503505
req.Header.Set("User-Agent", "gh-secret-scanning")
504506
response, err := client.Do(req)
505507
if err != nil {
506-
log.Println("ERROR: Unable to send " + secret_validation_method + " request to " + alert.Validity_endpoint)
508+
fmt.Println("WARNING: Unable to send " + secret_validation_method + " request to " + alert.Validity_endpoint)
507509
}
508510
alert.Validity_response_code = strconv.Itoa(response.StatusCode)
509511
alert.Validity_endpoint = enterprise_server_api_endpoint
@@ -518,19 +520,19 @@ func createIssuesForValidAlerts(alerts []Alert) (err error) {
518520
alertsByRepo[alert.Repository.Full_name] = append(alertsByRepo[alert.Repository.Full_name], alert)
519521
}
520522
for repo, alerts := range alertsByRepo {
521-
// Check if there is at least one confirmed valid secret alert
523+
// check if there is at least one confirmed valid secret alert
522524
hasValidAlert := false
523525
for _, alert := range alerts {
524526
if alert.Validity_boolean {
525527
hasValidAlert = true
526528
break
527529
}
528530
}
529-
// If there is no confirmed valid secret alert, skip this repository
531+
// if there is no confirmed valid secret alert, skip this repository
530532
if !hasValidAlert {
531533
continue
532534
}
533-
// Create a string with the details of the alerts
535+
// create a string with the details of the alerts
534536
details := "**Please promptly revoke the following secrets and confirm in the provider's logs that they have not been used maliciously:**\n\n"
535537
details += "| Alert ID | Secret Type | Alert Link |\n"
536538
details += "| --- | --- | --- |\n"
@@ -539,7 +541,7 @@ func createIssuesForValidAlerts(alerts []Alert) (err error) {
539541
details += fmt.Sprintf("| %d | %s | [Link](%s) |\n", alert.Number, alert.Secret_type, alert.HTML_URL)
540542
}
541543
}
542-
// Create the issue
544+
// create the issue
543545
var repo_with_host string
544546
if host == "" {
545547
repo_with_host = repo

cmd/verify.go

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package cmd
22

33
import (
44
"fmt"
5-
"log"
65
"math"
76
"net/url"
87
"strconv"
@@ -79,10 +78,10 @@ func runVerify(cmd *cobra.Command, args []string) (err error) {
7978
}
8079

8180
for page := 1; page <= pages; page++ {
82-
log.Printf("Processing page: %d\n", page)
81+
fmt.Println("Processing page: " + strconv.Itoa(page))
8382
_, nextPage, err := callGitHubAPI(client, requestPath, &pageOfSecretAlerts, GET)
8483
if err != nil {
85-
log.Printf("ERROR: Unable to get alerts for target: %s\n", requestPath)
84+
fmt.Println("ERROR: Unable to get alerts for target: " + requestPath)
8685
return err
8786
}
8887
for _, secretAlert := range pageOfSecretAlerts {
@@ -109,8 +108,8 @@ func runVerify(cmd *cobra.Command, args []string) (err error) {
109108
// verify which secret alerts are confirmed valid:
110109
verifiedAlerts, err := verifyAlerts(sortedAlerts)
111110
if err != nil {
112-
// Log to console
113-
fmt.Println("ERROR sending verify request: " + err.Error())
111+
// print to console
112+
fmt.Println("WARNING: issues encountered while sending verify requests.")
114113
}
115114
// pretty print with validity status
116115
if !quiet {
@@ -127,10 +126,10 @@ func runVerify(cmd *cobra.Command, args []string) (err error) {
127126
// optionally create an issue for each repository that contains at least one valid secret alert:
128127
if createIssues {
129128
err = createIssuesForValidAlerts(verifiedAlerts)
130-
}
131-
if err != nil {
132-
fmt.Println(err)
133-
return err
129+
if err != nil {
130+
fmt.Println(err)
131+
return err
132+
}
134133
}
135134
return err
136135
}

0 commit comments

Comments
 (0)