Skip to content

Commit

Permalink
Merge pull request #96 from veracode/main
Browse files Browse the repository at this point in the history
merge main into CMK branch
  • Loading branch information
tjarrettveracode authored Dec 2, 2024
2 parents 00b98b2 + 9375636 commit e0d8b60
Show file tree
Hide file tree
Showing 10 changed files with 98 additions and 23 deletions.
14 changes: 9 additions & 5 deletions docs/analytics.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,25 @@ The following methods call Veracode REST APIs and return JSON.

1. The Reporting API is available to Veracode customers by request. More information about the API is available in the [Veracode Docs](https://docs.veracode.com/r/Reporting_REST_API).

- `Analytics().create_report(report_type ('findings'),last_updated_start_date, last_updated_end_date (opt), scan_type (opt), finding_status(opt), passed_policy(opt), policy_sandbox(opt), application_id(opt), rawjson(opt))`: set up a request for a report. By default this command returns the GUID of the report request; specify `rawjson=True` to get the full response. Dates should be specified as `YYYY-MM-DD HH:MM:SS` with the timestamp optional. Options include:
- `report_type`: required, currently supports `findings` and `scans`.
- `last_updated_start_date`: required, beginning of date range for new or changed findings
- `last_updated_end_date`: optional, end of date range for new or changed findings
- `scan_type`: optional, one or more of 'Static Analysis', 'Dynamic Analysis', 'Manual', 'Software Composition Analysis', 'SCA'
- `Analytics().create_report(report_type ('findings'),last_updated_start_date(opt), last_updated_end_date (opt), scan_type (opt), finding_status(opt), passed_policy(opt), policy_sandbox(opt), application_id(opt), rawjson(opt), deletion_start_date(opt), deletion_end_date(opt))`: set up a request for a report. By default this command returns the GUID of the report request; specify `rawjson=True` to get the full response. Dates should be specified as `YYYY-MM-DD HH:MM:SS` with the timestamp optional. Options include:
- `report_type`: required, currently supports `findings`, `scans`, and `deletedscans`.
- `last_updated_start_date`: required for `findings` report type, beginning of date range for new or changed findings or scans
- `last_updated_end_date`: optional, end of date range for new or changed findings or scans
- `scan_type`: optional, one or more of 'Static Analysis', 'Dynamic Analysis', 'Manual', 'Software Composition Analysis', 'SCA'. `SCA` is only supported for the `findings` report type.
- `finding_status`: optional, 'Open' or 'Closed'. Applies only to the `findings` report.
- `passed_policy`: optional, boolean. Applies only to the `findings` report.
- `policy_sandbox`: optional, 'Policy' or 'Sandbox'
- `application_id`: optional, application ID for which to return results
- `rawjson`: optional, defaults to False. Returns full response if True, the GUID of the request if false
- `deletion_start_date`: required for `deletedscans` report type, beginning of date range for deleted scans.
- `deletion_end_date`: optional, end of date range for deleted scans.

- `Analytics().get(guid, report_type(findings))`: check the status of the report request and return the report contents when ready. Note that this method returns a tuple of `status` (string) and `results` (list); when `status` is `COMPLETED`, the `results` list will populate with results. Also, you need to specify the type of data expected by the GUID with `report_type`; this defaults to `findings`.

- `Analytics().get_findings(guid)`: check the status of a findings report request specified by `guid` and return the report contents when ready. Note that this method returns a tuple of `status` (string) and `results` (list); when `status` is `COMPLETED`, the `results` list will populate with results.

- `Analytics().get_scans(guid)`: check the status of a scans report request specified by `guid` and return the report contents when ready. Note that this method returns a tuple of `status` (string) and `results` (list); when `status` is `COMPLETED`, the `results` list will populate with results.

- `Analytics().get_deletedscans(guid)`: check the status of a deleted scans report request specified by `guid` and return the report contents when ready. Note that this method returns a tuple of `status` (string) and `results` (list); when `status` is `COMPLETED`, the `results` list will populate with results.

[All docs](docs.md)
5 changes: 2 additions & 3 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,14 @@ As an alternative to importing individual objects into your library, you can acc

### Analytics Reporting

1. *Accessing*: The Reporting API is available to Veracode customers by request.
1. *More information*: See the [Veracode Docs](https://docs.veracode.com/r/Reporting_REST_API).
1. *See Also*: You can also access these methods from the [Analytics class](analytics.md).

- `create_analytics_report(report_type ('findings'),last_updated_start_date, last_updated_end_date (opt), scan_type (opt), finding_status(opt), passed_policy(opt), policy_sandbox(opt), application_id(opt), rawjson(opt))`: set up a request for a report. By default this command returns the GUID of the report request; specify `rawjson=True` to get the full response. Dates should be specified as `YYYY-MM-DD HH:MM:SS` with the timestamp optional. Options include:
- `report_type`: required, currently only supports `findings`
- `report_type`: required, currently only supports `findings`, `scans` and `deletedscans`
- `last_updated_start_date`: required, beginning of date range for new or changed findings
- `last_updated_end_date`: optional, end of date range for new or changed findings
- `scan_type`: optional, one or more of 'Static Analysis', 'Dynamic Analysis', 'Manual', 'Software Composition Analysis', 'SCA'
- `scan_type`: optional, one or more of 'Static Analysis', 'Dynamic Analysis', 'Manual', 'Software Composition Analysis', 'SCA'. `SCA` is only supported for the `findings` type
- `finding_status`: optional, 'Open' or 'Closed'
- `passed_policy`: optional, boolean
- `policy_sandbox`: optional, 'Policy' or 'Sandbox'
Expand Down
2 changes: 1 addition & 1 deletion docs/findings.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ The following methods call Veracode REST APIs and return JSON.
## Findings and Annotations

- `Findings().get_findings(app,scantype(opt),annot(opt),request_params(opt),sandbox(opt))`: get the findings for `app` (guid).
- `scantype`: Defaults to STATIC findings, but can be STATIC, DYNAMIC, MANUAL, SCA, or ALL (static, dynamic, manual).
- `scantype`: Defaults to STATIC findings, but can be STATIC, DYNAMIC, MANUAL, SCA, or ALL (static, dynamic, manual). You can also pass a comma-delimited string of valid scantype options.
- `annot`: Defaults to TRUE but can be FALSE
- `sandbox`: The guid of the sandbox in `app` for which you want findings. (Use the Sandboxes APIs to get the sandbox guid.)
- `request_params`: Dictionary of additional query parameters. See the full [Findings API specification](https://help.veracode.com/r/c_findings_v2_intro) for some of the other options available.
Expand Down
3 changes: 1 addition & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
requests>=2.32.0
veracode-api-signing>=22.3.0
urllib3>= 2.2.2
veracode-api-signing>=24.11.0
Pygments>= 2.9.0
idna>=3.7
certifi>=2024.7.4
32 changes: 32 additions & 0 deletions samples/reportingapi_deleted_sample.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import time
import sys
import json
import datetime
from veracode_api_py import Analytics

wait_seconds = 15

print('Generating deleted scans report...')
theguid = Analytics().create_report(report_type="deletedscans",deletion_start_date='2024-07-01',deletion_end_date='2024-12-31')

print('Checking status for report {}...'.format(theguid))
thestatus,thescans=Analytics().get_deleted_scans(theguid)

while thestatus != 'COMPLETED':
print('Waiting {} seconds before we try again...'.format(wait_seconds))
time.sleep(wait_seconds)
print('Checking status for report {}...'.format(theguid))
thestatus,thescans=Analytics().get_deleted_scans(theguid)

recordcount = len(thescans)

print('Retrieved {} scans'.format(recordcount))

if recordcount > 0:
now = datetime.datetime.now().astimezone()
filename = 'report-{}'.format(now)
with open('{}.json'.format(filename), 'w') as outfile:
json.dump(thescans,outfile)
outfile.close()

print('Wrote {} findings to {}.json'.format(recordcount,filename))
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
long_description_content_type="text/markdown",
author = 'Tim Jarrett',
author_email = '[email protected]',
url = 'https://github.com/tjarrettveracode',
url = 'https://github.com/tjarrettveracode',
download_url = 'https://github.com/veracode/veracode-api-py/archive/v_0957.tar.gz',
keywords = ['veracode', 'veracode-api'],
install_requires=[
Expand Down
30 changes: 25 additions & 5 deletions veracode_api_py/analytics.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,30 +6,46 @@
from .apihelper import APIHelper

class Analytics():
report_types = [ "findings", "scans" ]
report_types = [ "findings", "scans", "deletedscans" ]

findings_scan_types = ["Static Analysis", "Dynamic Analysis", "Manual", "SCA", "Software Composition Analysis" ]
scan_scan_types = ["Static Analysis", "Dynamic Analysis", "Manual" ]

base_url = 'appsec/v1/analytics/report'

#public methods
def create_report(self,report_type,last_updated_start_date,last_updated_end_date=None,
def create_report(self,report_type,last_updated_start_date=None,last_updated_end_date=None,
scan_type:list = [], finding_status=None,passed_policy=None,
policy_sandbox=None,application_id=None,rawjson=False):
policy_sandbox=None,application_id=None,rawjson=False, deletion_start_date=None,
deletion_end_date=None):

if report_type not in self.report_types:
raise ValueError("{} is not in the list of valid report types ({})".format(report_type,self.report_types))

report_def = { "report_type": report_type,"last_updated_start_date": last_updated_start_date }
report_def = { 'report_type': report_type }

if last_updated_start_date:
report_def['last_updated_start_date'] = last_updated_start_date
else:
if report_type in ['findings','scans']:
raise ValueError("{} report type requires a last updated start date.").format(report_type)

if last_updated_end_date:
report_def['last_updated_end_date'] = last_updated_end_date

if deletion_end_date:
report_def['deletion_end_date'] = deletion_end_date

if deletion_start_date:
report_def['deletion_start_date'] = deletion_start_date
else:
if report_type == 'deletedscans':
raise ValueError("{} report type requires a deleteion start date.").format(report_type)

if len(scan_type) > 0:
if report_type == 'findings':
valid_scan_types = self.findings_scan_types
elif report_type == 'scans':
elif report_type in [ 'scans', 'deletedscans' ]:
valid_scan_types = self.scan_scan_types
if not(self._case_insensitive_list_compare(scan_type,valid_scan_types)):
raise ValueError("{} is not in the list of valid scan types ({})".format(report_type,valid_scan_types))
Expand Down Expand Up @@ -62,6 +78,10 @@ def get_findings(self, guid: UUID):
def get_scans(self, guid: UUID):
thestatus, thescans = self.get(guid=guid,report_type='scans')
return thestatus, thescans

def get_deleted_scans(self, guid: UUID):
thestatus, thescans = self.get(guid=guid,report_type='deletedscans')
return thestatus, thescans

def get(self,guid: UUID,report_type='findings'):
# handle multiple scan types
Expand Down
20 changes: 17 additions & 3 deletions veracode_api_py/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -642,15 +642,29 @@ def dyn_start_scan(self, length, unit):
return DynUtils().start_scan(length,unit)

# analytics apis
def create_analytics_report(self,report_type,last_updated_start_date,last_updated_end_date=None,
def create_analytics_report(self,report_type,last_updated_start_date=None,last_updated_end_date=None,
scan_type:list = [], finding_status=None,passed_policy=None,
policy_sandbox=None,application_id=None,rawjson=False):
policy_sandbox=None,application_id=None,rawjson=False,deletion_start_date=None,
deletion_end_date=None):
return Analytics().create_report(report_type=report_type,last_updated_start_date=last_updated_start_date,
last_updated_end_date=last_updated_end_date,scan_type=scan_type,
finding_status=finding_status,passed_policy=passed_policy,
policy_sandbox=policy_sandbox,application_id=application_id,
rawjson=rawjson)
rawjson=rawjson, deletion_start_date=deletion_start_date,
deletion_end_date=deletion_end_date)

def get_analytics_report(self,guid: UUID):
status, findings = Analytics().get(guid=guid)
return status, findings

def get_analytics_findings_report(self,guid:UUID):
status, findings = Analytics().get_findings(guid=guid)
return status, findings

def get_analytics_scans(self,guid:UUID):
status, findings = Analytics().get_scans(guid=guid)
return status, findings

def get_analytics_deleted_scans(self,guid:UUID):
status, findings = Analytics().get_deleted_scans(guid=guid)
return status, findings
11 changes: 9 additions & 2 deletions veracode_api_py/findings.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,15 @@ def get_findings(self,app: UUID,scantype='STATIC',annot='TRUE',request_params=No
if request_params == None:
request_params = {}

if scantype in ['STATIC', 'DYNAMIC', 'MANUAL','SCA']:
request_params['scan_type'] = scantype
scantypes = ""
scantype = scantype.split(',')
for st in scantype:
if st in ['STATIC', 'DYNAMIC', 'MANUAL','SCA']:
if len(scantypes) > 0:
scantypes += ","
scantypes += st
if len(scantypes) > 0:
request_params['scan_type'] = scantypes
#note that scantype='ALL' will result in no scan_type parameter as in API

request_params['include_annot'] = annot
Expand Down
2 changes: 1 addition & 1 deletion veracode_api_py/identity.py
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ def _create_or_update(self, method, role_name, role_description, role_guid: UUID
if len(child_roles) > 0:
role_def['child_roles'] = child_roles

payload = json.dumps({"profile": role_def})
payload = json.dumps(role_def)
return APIHelper()._rest_request(uri,httpmethod,body=payload)

class Permissions():
Expand Down

0 comments on commit e0d8b60

Please sign in to comment.