Skip to content

Commit 7914853

Browse files
Improving ScanResult functionality (#74)
* ensure end time is passed to GetAllScanResultsByTime API call * remove the use of deprecated function * consolidate managable and usable scan results * use url values for crafting scan result query * add example for scan result * Add generated changelog entries --------- Co-authored-by: Armin <[email protected]> Co-authored-by: svc-changelog <[email protected]>
1 parent 95b2d54 commit 7914853

File tree

3 files changed

+84
-18
lines changed

3 files changed

+84
-18
lines changed

_examples/scanresult/main.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"log"
6+
"os"
7+
"time"
8+
9+
"github.com/palantir/tenablesc-client/tenablesc"
10+
)
11+
12+
func main() {
13+
client := tenablesc.NewClient(
14+
os.Getenv("TENABLE_URL"), // Tenable SC host. ensure the url has /rest in their path.
15+
).SetAPIKey(
16+
os.Getenv("TENABLE_ACCESS_KEY"), // Tenable SC access key.
17+
os.Getenv("TENABLE_SECRET_KEY"), // Tenable SC secret key.
18+
)
19+
20+
now := time.Now()
21+
dayBefore := now.Add(-1 * 24 * time.Hour)
22+
scans, err := client.GetAllScanResultsByTime(dayBefore, now)
23+
if err != nil {
24+
log.Fatal(err)
25+
}
26+
27+
log.Println("listing scan results for the past 24 hours")
28+
for _, scan := range scans {
29+
log.Println(scan.Name, scan.ID)
30+
}
31+
32+
firstScanResult := scans[0]
33+
log.Printf("get scan result for ID: %s\n", firstScanResult.ID)
34+
result, err := client.GetScanResult(string(firstScanResult.ID))
35+
if err != nil {
36+
log.Fatal(err)
37+
}
38+
log.Println("scan result name returned:", result.Name)
39+
40+
log.Printf("downloading scan results for ID: %s\n", firstScanResult.ID)
41+
outFileName := fmt.Sprintf("scan-results-%s.nessus", firstScanResult.ID)
42+
downloadedData, err := client.DownloadScanResult(string(firstScanResult.ID))
43+
if err != nil {
44+
log.Fatal(err)
45+
}
46+
47+
log.Printf("writing downloaded data to file: %s", outFileName)
48+
err = os.WriteFile(outFileName, downloadedData, os.FileMode(0600))
49+
if err != nil {
50+
log.Fatal(err)
51+
}
52+
53+
}

changelog/@unreleased/pr-74.v2.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
type: fix
2+
fix:
3+
description: Improving ScanResult functionality
4+
links:
5+
- https://github.com/palantir/tenablesc-client/pull/74

tenablesc/scanresult.go

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,8 @@ import (
55
"bytes"
66
"errors"
77
"fmt"
8-
"io/ioutil"
8+
"io"
99
"net/url"
10-
"strings"
1110
"time"
1211

1312
"github.com/go-resty/resty/v2"
@@ -56,11 +55,9 @@ type ScanResult struct {
5655

5756
type scanResultInternal struct {
5857
Manageable []*ScanResult `json:"manageable" tenable:"recurse"`
59-
Useable []*ScanResult `json:"useable" tenable:"recurse"`
58+
Usable []*ScanResult `json:"usable" tenable:"recurse"`
6059
}
6160

62-
// Do the usable/manageable split thing. ffff.
63-
6461
// takes startTime + endTime parameters, but defaults to last 30d.
6562

6663
func (c *Client) GetAllScanResults() ([]*ScanResult, error) {
@@ -69,32 +66,43 @@ func (c *Client) GetAllScanResults() ([]*ScanResult, error) {
6966

7067
func (c *Client) GetAllScanResultsByTime(start, end time.Time) ([]*ScanResult, error) {
7168

72-
v := url.Values{}
73-
69+
params := url.Values{}
7470
if !start.IsZero() {
75-
v.Add("startTime", fmt.Sprintf("%d", start.Unix()))
71+
params.Add("startTime", fmt.Sprintf("%d", start.Unix()))
7672
}
7773
if !end.IsZero() {
78-
v.Add("endTime", fmt.Sprintf("%d", start.Unix()))
74+
params.Add("endTime", fmt.Sprintf("%d", end.Unix()))
7975
}
8076

81-
resourceURL := strings.Builder{}
82-
resourceURL.WriteString(scanResultEndpoint)
83-
if len(v) > 0 {
84-
resourceURL.WriteString(fmt.Sprintf("?%s", v.Encode()))
77+
resourceURL := url.URL{
78+
Path: scanResultEndpoint,
79+
RawQuery: params.Encode(),
8580
}
8681

8782
var resp scanResultInternal
88-
8983
if _, err := c.getResource(resourceURL.String(), &resp); err != nil {
9084
return nil, fmt.Errorf("failed to get scan results: %w", err)
9185
}
9286

93-
return resp.Manageable, nil
87+
var spOut []*ScanResult
88+
spMap := make(map[ProbablyString]bool)
89+
90+
for _, o := range resp.Usable {
91+
spOut = append(spOut, o)
92+
spMap[o.ID] = true
93+
}
94+
for _, o := range resp.Manageable {
95+
if _, exists := spMap[o.ID]; !exists {
96+
spOut = append(spOut, o)
97+
spMap[o.ID] = true
98+
}
99+
}
100+
101+
return spOut, nil
94102
}
95103

96104
func (c *Client) GetScanResult(id string) (*ScanResult, error) {
97-
resp := ScanResult{}
105+
var resp ScanResult
98106
if _, err := c.getResource(fmt.Sprintf("%s/%s", scanResultEndpoint, id), &resp); err != nil {
99107
return nil, fmt.Errorf("failed to get scan result %s: %w", id, err)
100108
}
@@ -177,7 +185,7 @@ func firstFileFromPKZipSlice(slice []byte) ([]byte, error) {
177185

178186
reader, err := zip.NewReader(bytes.NewReader(slice), int64(len(slice)))
179187
if err != nil {
180-
return nil, fmt.Errorf("nessus scan result zip could not be parsed: %w", err)
188+
return nil, fmt.Errorf("failed to create zip reader: %w", err)
181189
}
182190

183191
if len(reader.File) == 0 {
@@ -189,7 +197,7 @@ func firstFileFromPKZipSlice(slice []byte) ([]byte, error) {
189197
return nil, fmt.Errorf("could not open first file in zip: %w", err)
190198
}
191199

192-
results, err = ioutil.ReadAll(file)
200+
results, err = io.ReadAll(file)
193201
if err != nil {
194202
return nil, fmt.Errorf("failed to read zip file: %w", err)
195203
}

0 commit comments

Comments
 (0)