Coverage for veracode/api.py : 100%
Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1#!/usr/bin/env python3
2"""
3A python module to interface with the Veracode Static Analysis APIs
4"""
6# built-ins
7from pathlib import Path
8import logging
9from typing import Optional, Dict, Any
10from datetime import datetime
12# custom
13from veracode import constants, __project_name__
14from veracode.utils import (
15 is_valid_attribute,
16 http_request,
17 get_app_id,
18)
20LOG = logging.getLogger(__project_name__ + "." + __name__)
23class VeracodeXMLAPI:
24 """
25 A base Veracode XML API class to inherit from
27 For more details, see Veracode's documentation at
28 https://help.veracode.com/reader/LMv_dtSHyb7iIxAQznC~9w/pd_p6JjB9PcDNH3GzWF5Ag
29 """
31 def __init__(self, *, app_name: str):
32 # Hard code to None as it should be specified in the derived classes
33 self._version = None
35 ## Use the setter to apply a default to ensure it is valid
36 self.base_url = constants.API_BASE_URL
38 """
39 Set app name and look up ID
41 Note: App ID resolution depends on access to the Veracode upload API and
42 the "getapplist.do" endpoint:
43 https://help.veracode.com/reader/orRWez4I0tnZNaA_i0zn9g/Z4Ecf1fw7868vYPVgkglww
44 """
45 self.app_name = app_name
46 self.app_id = get_app_id(app_name=app_name)
48 def http_get(
49 self,
50 *,
51 endpoint: str,
52 params: Optional[Dict] = None,
53 headers: Optional[Dict] = None,
54 ):
55 """
56 Perform a HTTP GET request to a Veracode XML API and return the
57 response
58 """
59 return http_request(
60 verb="get",
61 url=self.base_url + self.version[endpoint] + "/" + endpoint,
62 params=params,
63 headers=headers,
64 )
66 def http_post(
67 self,
68 *,
69 endpoint: str,
70 data: Optional[bytes] = None,
71 params: Optional[Dict] = None,
72 headers: Optional[Dict] = None,
73 ):
74 """
75 Perform a HTTP POST request to a Veracode XML API and return the
76 response
77 """
78 return http_request(
79 verb="post",
80 url=self.base_url + self.version[endpoint] + "/" + endpoint,
81 data=data,
82 params=params,
83 headers=headers,
84 )
86 @property
87 def base_url(self):
88 """
89 Create the base_url property
90 """
91 return self._base_url # pragma: no cover
93 @base_url.getter
94 def base_url(self):
95 """
96 Create a base_url getter that validates before returning
97 """
98 # Validate what was already stored
99 self._validate(key="base_url", value=self._base_url)
100 return self._base_url
102 @base_url.setter
103 def base_url(self, base_url):
104 """
105 Create a base_url setter that validates before setting
106 """
107 # Validate what was provided
108 self._validate(key="base_url", value=base_url)
109 self._base_url = base_url
111 @property
112 def version(self):
113 """
114 Create the version property
115 """
116 return self._version # pragma: no cover
118 @version.getter
119 def version(self):
120 """
121 Create a version getter that validates before returning
122 """
123 # Validate what was already stored
124 self._validate(key="version", value=self._version)
125 return self._version
127 @version.setter
128 def version(self, version):
129 """
130 Create a version setter that validates before setting
131 """
132 # Validate what was provided
133 self._validate(key="version", value=version)
134 self._version = version
136 @property
137 def app_id(self):
138 """
139 Create the app_id property
140 """
141 return self._app_id # pragma: no cover
143 @app_id.getter
144 def app_id(self):
145 """
146 Create an app_id getter that validates before returning
147 """
148 # Validate what was already stored
149 self._validate(key="app_id", value=self._app_id)
150 return self._app_id
152 @app_id.setter
153 def app_id(self, app_id):
154 """
155 Create an app_id setter that validates before setting
156 """
157 # Validate what was provided
158 self._validate(key="app_id", value=app_id)
159 self._app_id = app_id
161 @property
162 def app_name(self):
163 """
164 Create the app_name property
165 """
166 return self._app_name # pragma: no cover
168 @app_name.getter
169 def app_name(self):
170 """
171 Create an app_name getter that validates before returning
172 """
173 # Validate what was already stored
174 self._validate(key="app_name", value=self._app_name)
175 return self._app_name
177 @app_name.setter
178 def app_name(self, app_name):
179 """
180 Create an app_name setter that validates before setting
181 """
182 # Validate what was provided
183 self._validate(key="app_name", value=app_name)
184 self._app_name = app_name
186 @staticmethod
187 def _validate(*, key: str, value: Any):
188 if is_valid_attribute(key=key, value=value):
189 return True
190 raise ValueError(f"Invalid {key}")
193class UploadAPI(VeracodeXMLAPI): # pylint: disable=too-many-instance-attributes
194 """
195 A class to interact with the Upload API
196 """
198 def __init__(self, *, app_name: str):
199 # Don't forget to call the init of the parent
200 super().__init__(app_name=app_name)
202 ## Use the setter to apply a default to ensure it is valid
203 # version information was pulled from
204 # https://help.veracode.com/reader/LMv_dtSHyb7iIxAQznC~9w/G1Nd5yH0QSlT~vPccPhtRQ
205 self.version = constants.UPLOAD_API_VERSIONS
206 self.build_dir = Path("/build").absolute()
207 self.build_id = datetime.utcnow().strftime("%F_%H-%M-%S")
208 self.scan_all_nonfatal_top_level_modules = True
209 self.auto_scan = True
210 # sandbox_id is not meant to be set manually. Instead, configure using
211 # the response of a Sandbox API query using the intended sandbox name
212 self.sandbox_id = None
214 @property
215 def build_dir(self):
216 """
217 Create the build_dir property
218 """
219 return self._build_dir # pragma: no cover
221 @build_dir.getter
222 def build_dir(self):
223 """
224 Create a build_dir getter that validates before returning
225 """
226 # Validate what was already stored
227 self._validate(key="build_dir", value=self._build_dir)
228 return self._build_dir
230 @build_dir.setter
231 def build_dir(self, build_dir):
232 """
233 Create a build_dir setter that validates before setting
234 """
235 # Validate what was provided
236 self._validate(key="build_dir", value=build_dir)
237 self._build_dir = build_dir
239 @property
240 def build_id(self):
241 """
242 Create the build_id property
243 """
244 return self._build_id # pragma: no cover
246 @build_id.getter
247 def build_id(self):
248 """
249 Create a build_id getter that validates before returning
250 """
251 # Validate what was already stored
252 self._validate(key="build_id", value=self._build_id)
253 return self._build_id
255 @build_id.setter
256 def build_id(self, build_id):
257 """
258 Create a build_id setter that validates before setting
259 """
260 # Validate what was provided
261 self._validate(key="build_id", value=build_id)
262 self._build_id = build_id
264 @property
265 def sandbox_id(self):
266 """
267 Create the sandbox_id property
268 """
269 return self._sandbox_id # pragma: no cover
271 @sandbox_id.getter
272 def sandbox_id(self):
273 """
274 Create a sandbox_id getter that validates before returning
276 This should only be set using the response of a Sandbox API query using
277 the intended sandbox name
278 """
279 # Validate what was already stored
280 self._validate(key="sandbox_id", value=self._sandbox_id)
281 return self._sandbox_id
283 @sandbox_id.setter
284 def sandbox_id(self, sandbox_id):
285 """
286 Create a sandbox_id setter that validates before setting
287 """
288 # Validate what was provided
289 self._validate(key="sandbox_id", value=sandbox_id)
290 self._sandbox_id = sandbox_id
292 @property
293 def scan_all_nonfatal_top_level_modules(self):
294 """
295 Create the scan_all_nonfatal_top_level_modules property
296 """
297 return self._scan_all_nonfatal_top_level_modules # pragma: no cover
299 @scan_all_nonfatal_top_level_modules.getter
300 def scan_all_nonfatal_top_level_modules(self):
301 """
302 Create a scan_all_nonfatal_top_level_modules getter that validates
303 before returning
304 """
305 # Validate what was already stored
306 self._validate(
307 key="scan_all_nonfatal_top_level_modules",
308 value=self._scan_all_nonfatal_top_level_modules,
309 )
310 return self._scan_all_nonfatal_top_level_modules
312 @scan_all_nonfatal_top_level_modules.setter
313 def scan_all_nonfatal_top_level_modules(self, scan_all_nonfatal_top_level_modules):
314 """
315 Create a scan_all_nonfatal_top_level_modules setter that validates before setting
316 """
317 # Validate what was provided
318 self._validate(
319 key="scan_all_nonfatal_top_level_modules",
320 value=scan_all_nonfatal_top_level_modules,
321 )
322 self._scan_all_nonfatal_top_level_modules = scan_all_nonfatal_top_level_modules
324 @property
325 def auto_scan(self):
326 """
327 Create the auto_scan property
328 """
329 return self._auto_scan # pragma: no cover
331 @auto_scan.getter
332 def auto_scan(self):
333 """
334 Create an auto_scan getter that validates before returning
335 """
336 # Validate what was already stored
337 self._validate(key="auto_scan", value=self._auto_scan)
338 return self._auto_scan
340 @auto_scan.setter
341 def auto_scan(self, auto_scan):
342 """
343 Create an auto_scan setter that validates before setting
344 """
345 # Validate what was provided
346 self._validate(key="auto_scan", value=auto_scan)
347 self._auto_scan = auto_scan
350# pylint: disable=too-many-instance-attributes
351class ResultsAPI(VeracodeXMLAPI):
352 """
353 A class to interact with the Results API
355 Note: App ID resolution depends on access to the Veracode upload API and
356 the "getapplist.do" endpoint:
357 https://help.veracode.com/reader/orRWez4I0tnZNaA_i0zn9g/Z4Ecf1fw7868vYPVgkglww
358 """
360 def __init__(self, *, app_name: str):
361 # Don't forget to call the init of the parent
362 super().__init__(app_name=app_name)
364 ## Use the setter to apply a default to ensure it is valid
365 self.ignore_compliance_status = False
366 # version information was pulled from
367 # https://help.veracode.com/reader/LMv_dtSHyb7iIxAQznC~9w/Mp2BEkLx6rD87k465BWqQg
368 self.version = constants.RESULTS_API_VERSIONS
370 @property
371 def ignore_compliance_status(self):
372 """
373 Specify whether or not to ignore the app compliance status
374 """
375 return self._ignore_compliance_status # pragma: no cover
377 @ignore_compliance_status.getter
378 def ignore_compliance_status(self):
379 """
380 Create an ignore_compliance_status getter that validates before returning
381 """
382 # Validate what was already stored
383 self._validate(
384 key="ignore_compliance_status", value=self._ignore_compliance_status
385 )
386 return self._ignore_compliance_status
388 @ignore_compliance_status.setter
389 def ignore_compliance_status(self, ignore_compliance_status):
390 """
391 Create an ignore_compliance_status setter that validates before setting
392 """
393 # Validate what was provided
394 self._validate(key="ignore_compliance_status", value=ignore_compliance_status)
395 self._ignore_compliance_status = ignore_compliance_status
398class SandboxAPI(VeracodeXMLAPI):
399 """
400 A class to interact with the Sandbox API
402 Note: App ID resolution depends on access to the Veracode upload API and
403 the "getapplist.do" endpoint:
404 https://help.veracode.com/reader/orRWez4I0tnZNaA_i0zn9g/Z4Ecf1fw7868vYPVgkglww
405 """
407 def __init__(self, *, app_name: str, sandbox_name: str):
408 # Don't forget to call the init of the parent
409 super().__init__(app_name=app_name)
411 # version information was pulled from
412 # https://help.veracode.com/reader/LMv_dtSHyb7iIxAQznC~9w/KusbW5J7EG8jEr64JEiBzw
413 self.version = constants.SANDBOX_API_VERSIONS
414 self.build_id = datetime.utcnow().strftime("%F_%H-%M-%S")
415 self.sandbox_name = sandbox_name
416 # sandbox_id is not meant to be set manually. Instead, configure using
417 # the response of a Sandbox API query using the intended sandbox name
418 self.sandbox_id = None
420 @property
421 def build_id(self):
422 """
423 Create the build_id property
424 """
425 return self._build_id # pragma: no cover
427 @build_id.getter
428 def build_id(self):
429 """
430 Create a build_id getter that validates before returning
431 """
432 # Validate what was already stored
433 self._validate(key="build_id", value=self._build_id)
434 return self._build_id
436 @build_id.setter
437 def build_id(self, build_id):
438 """
439 Create a build_id setter that validates before setting
440 """
441 # Validate what was provided
442 self._validate(key="build_id", value=build_id)
443 self._build_id = build_id
445 @property
446 def sandbox_id(self):
447 """
448 Create the sandbox_id property
449 """
450 return self._sandbox_id # pragma: no cover
452 @sandbox_id.getter
453 def sandbox_id(self):
454 """
455 Create a sandbox_id getter that validates before returning
456 """
457 # Validate what was already stored
458 self._validate(key="sandbox_id", value=self._sandbox_id)
459 return self._sandbox_id
461 @sandbox_id.setter
462 def sandbox_id(self, sandbox_id):
463 """
464 Create a sandbox_id setter that validates before setting
466 This should only be set using the response of a Sandbox API query using
467 the intended sandbox name
468 """
469 # Validate what was provided
470 self._validate(key="sandbox_id", value=sandbox_id)
471 self._sandbox_id = sandbox_id
473 @property
474 def sandbox_name(self):
475 """
476 Create the sandbox_name property
477 """
478 return self._sandbox_name # pragma: no cover
480 @sandbox_name.getter
481 def sandbox_name(self):
482 """
483 Create a sandbox_name getter that validates before returning
484 """
485 # Validate what was already stored
486 self._validate(key="sandbox_name", value=self._sandbox_name)
487 return self._sandbox_name
489 @sandbox_name.setter
490 def sandbox_name(self, sandbox_name):
491 """
492 Create a sandbox_name setter that validates before setting
493 """
494 # Validate what was provided
495 self._validate(key="sandbox_name", value=sandbox_name)
496 self._sandbox_name = sandbox_name