diff --git a/README.rst b/README.rst index 8ba00cc5a89eb14417bc987b0956f3177c75f33e..a17815d8d615dcec3606cb5b53340a915203eaff 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ DefectDojo API -============= +============== A Python API wrapper to facilitate interactions with `DefectDojo <https://github.com/OWASP/django-DefectDojo>`_. @@ -10,7 +10,7 @@ Quick Start Several quick start options are available: -- Install with pip (recommended): :code:`pip install defect_dojo_api` +- Install with pip (recommended): :code:`pip install defectdojo_api` - `Download the latest release <https://github.com/aaronweaver/defectdojo_api/releases/latest>`_ - Clone the repository: :code:`git clone https://github.com/aaronweaver/defectdojo_api` @@ -33,19 +33,25 @@ Example # If you need to disable certificate verification, set verify_ssl to False. # dd = defectdojo.DefectDojoAPI(host, api_key, user, verify_ssl=False) - # You can also specify a local cert to use as client side certificate, as a - # single file (containing the private key and the certificate) or as a tuple - # of both file's path. - # cert=('/path/server.crt', '/path/key') - # dd = defectdojo.DefectDojoAPI(host, api_key, user, cert=cert) + # Create a product + prod_type = 1 #1 - Research and Development, product type + product = dd.create_product("API Product Test", "This is a detailed product description.", prod_type) + + if product.success: + # Get the product id + product_id = product.id() + print "Product successfully created with an id: " + str(product_id) #List Products - products = dd.get_products() + products = dd.list_products() - print(products.data_json(pretty=True)) # Decoded JSON object + if products.success: + print(products.data_json(pretty=True)) # Decoded JSON object - for product in products.data["objects"]: - print(product['name']) # Print the name of each product + for product in products.data["objects"]: + print(product['name']) # Print the name of each product + else: + print products.message Supporting information for each method available can be found in the `documentation <https://github.com/aaronweaver/defectdojo_api/tree/master/docs>`_. diff --git a/defectdojo_api/__init__.py b/defectdojo_api/__init__.py index 156d6f9a28526eef969da384ac3b5b101f58f603..eead3198634f4d98e3e90e5ba08ee78146842718 100644 --- a/defectdojo_api/__init__.py +++ b/defectdojo_api/__init__.py @@ -1 +1 @@ -__version__ = '0.0.4' +__version__ = '0.0.5' diff --git a/defectdojo_api/defectdojo.py b/defectdojo_api/defectdojo.py index afa925b34e5285dd07b70367c54b8373233d55f3..4f640fd54064a321f9650ded46bdd89955b21cdd 100644 --- a/defectdojo_api/defectdojo.py +++ b/defectdojo_api/defectdojo.py @@ -9,19 +9,21 @@ from . import __version__ as version class DefectDojoAPI(object): """An API wrapper for DefectDojo.""" - def __init__(self, host, api_key, user, api_version='v1', verify_ssl=True, timeout=30, user_agent=None, cert=None, debug=False): - """ - Initialize a DefectDojo API instance. + def __init__(self, host, api_key, user, api_version='v1', verify_ssl=True, timeout=30, proxies=None, user_agent=None, cert=None, debug=False): + """Initialize a DefectDojo API instance. + :param host: The URL for the DefectDojo server. (e.g., http://localhost:8000/DefectDojo/) :param api_key: The API key generated on the DefectDojo API key page. :param user: The user associated with the API key. :param api_version: API version to call, the default is v1. :param verify_ssl: Specify if API requests will verify the host's SSL certificate, defaults to true. :param timeout: HTTP timeout in seconds, default is 30. + :param proxis: Proxy for API requests. :param user_agent: HTTP user agent string, default is "DefectDojo_api/[version]". :param cert: You can also specify a local cert to use as client side certificate, as a single file (containing the private key and the certificate) or as a tuple of both file's path :param debug: Prints requests and responses, useful for debugging. + """ self.host = host + '/api/' + api_version + '/' @@ -29,6 +31,7 @@ class DefectDojoAPI(object): self.user = user self.api_version = api_version self.verify_ssl = verify_ssl + self.proxies = proxies self.timeout = timeout if not user_agent: @@ -44,26 +47,51 @@ class DefectDojoAPI(object): ###### Helper Functions ###### def get_user_uri(self, user_id): + """Returns the DefectDojo API URI for a user. + + :param user_id: Id of the user + + """ + return "/api/" + self.api_version + "/users/" + str(user_id) + "/" def get_engagement_uri(self, engagement_id): + """Returns the DefectDojo API URI for an engagement. + + :param engagement_id: Id of the engagement + + """ return "/api/" + self.api_version + "/engagements/" + str(engagement_id) + "/" def get_product_uri(self, product_id): + """Returns the DefectDojo API URI for a product. + + :param product_id: Id of the product + + """ return "/api/" + self.api_version + "/products/" + str(product_id) + "/" def get_test_uri(self, test_id): + """Returns the DefectDojo API URI for a test. + + :param test_id: Id of the test + + """ return "/api/" + self.api_version + "/tests/" + str(test_id) + "/" def version_url(self): + """Returns the DefectDojo API version. + + """ return self.api_version ###### User API ####### - def get_users(self, username=None, limit=20): - """ - Retrieves all the users. - :param usename: Search by username. + def list_users(self, username=None, limit=20): + """Retrieves all the users. + + :param username: Search by username. :param limit: Number of records to return. + """ params = {} if limit: @@ -75,18 +103,20 @@ class DefectDojoAPI(object): return self._request('GET', 'users/') def get_user(self, user_id): - """ - Retrieves a user using the given user id. + """Retrieves a user using the given user id. + :param user_id: User identification. + """ return self._request('GET', 'users/' + str(user_id) + '/') ###### Engagements API ####### - def get_engagements(self, product_in=None,limit=20): - """ - Retrieves all the engagements. + def list_engagements(self, product_in=None,limit=20): + """Retrieves all the engagements. + :param product_in: List of product ids (1,2). :param limit: Number of records to return. + """ params = {} @@ -99,17 +129,18 @@ class DefectDojoAPI(object): return self._request('GET', 'engagements/', params) def get_engagement(self, engagement_id): - """ - Retrieves an engagement using the given engagement id. + """Retrieves an engagement using the given engagement id. + :param engagement_id: Engagement identification. + """ return self._request('GET', 'engagements/' + str(engagement_id) + '/') def create_engagement(self, name, product_id, lead_id, status, target_start, target_end, active='true', pen_test='false', check_list='false', threat_model='false', risk_path="", test_strategy="", progress="", done_testing=""): - """ - Creates an engagement with the given properties. + """Creates an engagement with the given properties. + :param name: Engagement name. :param product_id: Product key id.. :param lead_id: Testing lead from the user table. @@ -123,6 +154,7 @@ class DefectDojoAPI(object): :param risk_path: risk_path :param test_strategy: Test Strategy URLs :param progress: Engagement progresss measured in percent. + """ data = { @@ -148,8 +180,8 @@ class DefectDojoAPI(object): target_end=None, active=None, pen_test=None, check_list=None, threat_model=None, risk_path=None, test_strategy=None, progress=None, done_testing=None): - """ - Updates an engagement with the given properties. + """Updates an engagement with the given properties. + :param id: Engagement id. :param name: Engagement name. :param product_id: Product key id.. @@ -164,7 +196,9 @@ class DefectDojoAPI(object): :param risk_path: risk_path :param test_strategy: Test Strategy URLs :param progress: Engagement progresss measured in percent. + """ + data = {} if name: @@ -212,13 +246,15 @@ class DefectDojoAPI(object): return self._request('PUT', 'engagements/' + str(id) + '/', data=data) ###### Product API ####### - def get_products(self, name=None, name_contains=None, limit=20): - """ - Retrieves all the products. + def list_products(self, name=None, name_contains=None, limit=20): + """Retrieves all the products. + :param name: Search by product name. :param name_contains: Search by product name. :param limit: Number of records to return. + """ + params = {} if limit: params['limit'] = limit @@ -232,18 +268,20 @@ class DefectDojoAPI(object): return self._request('GET', 'products/', params) def get_product(self, product_id): - """ - Retrieves a product using the given product id. + """Retrieves a product using the given product id. + :param product_id: Product identification. + """ return self._request('GET', 'products/' + str(product_id) + '/') def create_product(self, name, description, prod_type): - """ - Creates a product with the given properties. + """Creates a product with the given properties. + :param name: Product name. :param description: Product key id.. :param prod_type: Product type. + """ data = { @@ -255,12 +293,13 @@ class DefectDojoAPI(object): return self._request('POST', 'products/', data=data) def set_product(self, product_id, name=None, description=None, prod_type=None): - """ - Updates a product with the given properties. + """Updates a product with the given properties. + :param product_id: Product ID :param name: Product name. :param description: Product key id.. :param prod_type: Product type. + """ data = {} @@ -278,12 +317,14 @@ class DefectDojoAPI(object): ###### Test API ####### - def get_tests(self, name=None, engagement_in=None, limit=20): - """ - Retrieves all the tests. + def list_tests(self, name=None, engagement_in=None, limit=20): + """Retrieves all the tests. + :param name_contains: Search by product name. :param limit: Number of records to return. + """ + params = {} if limit: params['limit'] = limit @@ -294,20 +335,22 @@ class DefectDojoAPI(object): return self._request('GET', 'tests/', params) def get_test(self, test_id): - """ - Retrieves a test using the given test id. + """Retrieves a test using the given test id. + :param test_id: Test identification. + """ return self._request('GET', 'tests/' + str(test_id) + '/') def create_test(self, engagement_id, test_type, environment, target_start, target_end, percent_complete=None): - """ - Creates a product with the given properties. + """Creates a product with the given properties. + :param engagement_id: Engagement id. :param test_type: Test type key id. :param target_start: Test start date. :param target_end: Test end date. :param percent_complete: Percentage until test completion. + """ data = { @@ -323,13 +366,14 @@ class DefectDojoAPI(object): def set_test(self, test_id, engagement_id=None, test_type=None, environment=None, target_start=None, target_end=None, percent_complete=None): - """ - Creates a product with the given properties. + """Creates a product with the given properties. + :param engagement_id: Engagement id. :param test_type: Test type key id. :param target_start: Test start date. :param target_end: Test end date. :param percent_complete: Percentage until test completion. + """ data = {} @@ -355,11 +399,12 @@ class DefectDojoAPI(object): return self._request('PUT', 'tests/' + str(test_id) + '/', data=data) ###### Findings API ####### - def get_findings(self, active=None, duplicate=None, mitigated=None, severity=None, verified=None, severity_lt=None, + def list_findings(self, active=None, duplicate=None, mitigated=None, severity=None, verified=None, severity_lt=None, severity_gt=None, severity_contains=None, title_contains=None, url_contains=None, date_lt=None, date_gt=None, date=None, product_id_in=None, engagement_id_in=None, test_in=None, limit=20): - """ - Returns filtered list of findings. + + """Returns filtered list of findings. + :param active: Finding is active: (true or false) :param duplicate: Duplicate finding (true or false) :param mitigated: Mitigated finding (true or false) @@ -377,6 +422,7 @@ class DefectDojoAPI(object): :param engagement_id_in: Engagement id(s) associated with a finding. (1,2 or 1) :param test_in: Test id(s) associated with a finding. (1,2 or 1) :param limit: Number of records to return. + """ params = {} @@ -442,8 +488,9 @@ class DefectDojoAPI(object): def create_finding(self, title, description, severity, cwe, date, product_id, engagement_id, test_id, user_id, impact, active, verified, mitigation, references=None): - """ - Creates a finding with the given properties. + + """Creates a finding with the given properties. + :param title: Finding title :param description: Finding detailed description. :param severity: Finding severity: Low, Medium, High and Critical @@ -458,6 +505,7 @@ class DefectDojoAPI(object): :param verified: Finding has been verified. :param mitigation: Steps to mitigate the finding. :param references: Details on finding. + """ data = { @@ -482,8 +530,9 @@ class DefectDojoAPI(object): def set_finding(self, finding_id, product_id, engagement_id, test_id, title=None, description=None, severity=None, cwe=None, date=None, user_id=None, impact=None, active=None, verified=None, mitigation=None, references=None): - """ - Updates a finding with the given properties. + + """Updates a finding with the given properties. + :param title: Finding title :param description: Finding detailed description. :param severity: Finding severity: Low, Medium, High and Critical @@ -498,6 +547,7 @@ class DefectDojoAPI(object): :param verified: Finding has been verified. :param mitigation: Steps to mitigate the finding. :param references: Details on finding. + """ data = {} @@ -549,10 +599,11 @@ class DefectDojoAPI(object): ##### Upload API ##### def upload_scan(self, engagement_id, scan_type, file_path, active, scan_date, tags): - """ - Uploads and processes a scan file. + """Uploads and processes a scan file. + :param application_id: Application identifier. :param file_path: Path to the scan file to be uploaded. + """ data = { @@ -569,12 +620,6 @@ class DefectDojoAPI(object): files=data ) - """ - return self._request( - 'POST', 'importscan/', - files={'file': open(file_path, 'rb'), 'eid': ('', str(engagement_id)), 'scan_type': ('', scan_type)} - ) - """ # Utility @staticmethod @@ -607,10 +652,10 @@ class DefectDojoAPI(object): headers['Accept'] = 'application/json' headers['Content-Type'] = 'application/json' - proxies = { - 'http': 'http://localhost:8080', - 'https': 'http://localhost:8080', - } + if self.proxies: + proxies=self.proxies + else: + proxies = {} try: if self.debug: @@ -655,7 +700,10 @@ class DefectDojoAPI(object): class DefectDojoResponse(object): - """Container for all DefectDojo API responses, even errors.""" + """ + Container for all DefectDojo API responses, even errors. + + """ def __init__(self, message, success, data=None, response_code=-1): self.message = message diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..7814d9feea635a6601e65ae64f1da0eeb170bdab --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,225 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = _build + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help +help: + @echo "Please use \`make <target>' where <target> is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " applehelp to make an Apple Help Book" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " epub3 to make an epub3" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " xml to make Docutils-native XML files" + @echo " pseudoxml to make pseudoxml-XML files for display purposes" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + @echo " coverage to run coverage check of the documentation (if enabled)" + @echo " dummy to check syntax errors of document sources" + +.PHONY: clean +clean: + rm -rf $(BUILDDIR)/* + +.PHONY: html +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +.PHONY: dirhtml +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +.PHONY: singlehtml +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +.PHONY: pickle +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +.PHONY: json +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +.PHONY: htmlhelp +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +.PHONY: qthelp +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/DefectDojoAPI.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/DefectDojoAPI.qhc" + +.PHONY: applehelp +applehelp: + $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp + @echo + @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." + @echo "N.B. You won't be able to view it unless you put it in" \ + "~/Library/Documentation/Help or install it in your application" \ + "bundle." + +.PHONY: devhelp +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/DefectDojoAPI" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/DefectDojoAPI" + @echo "# devhelp" + +.PHONY: epub +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +.PHONY: epub3 +epub3: + $(SPHINXBUILD) -b epub3 $(ALLSPHINXOPTS) $(BUILDDIR)/epub3 + @echo + @echo "Build finished. The epub3 file is in $(BUILDDIR)/epub3." + +.PHONY: latex +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +.PHONY: latexpdf +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +.PHONY: latexpdfja +latexpdfja: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through platex and dvipdfmx..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +.PHONY: text +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +.PHONY: man +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +.PHONY: texinfo +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +.PHONY: info +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +.PHONY: gettext +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +.PHONY: changes +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +.PHONY: linkcheck +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +.PHONY: doctest +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." + +.PHONY: coverage +coverage: + $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage + @echo "Testing of coverage in the sources finished, look at the " \ + "results in $(BUILDDIR)/coverage/python.txt." + +.PHONY: xml +xml: + $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml + @echo + @echo "Build finished. The XML files are in $(BUILDDIR)/xml." + +.PHONY: pseudoxml +pseudoxml: + $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml + @echo + @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." + +.PHONY: dummy +dummy: + $(SPHINXBUILD) -b dummy $(ALLSPHINXOPTS) $(BUILDDIR)/dummy + @echo + @echo "Build finished. Dummy builder generates no files." diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000000000000000000000000000000000000..fd57d75ce220315b614cd5e2cbb68b3ea47f3fc1 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,537 @@ +# ThreadFix API Documentation + +**Before you start**, its important to understand that all responses to api calls (even when errors occur) are wrapped in a response object. This object mimics the behavior of the ThreadFix API and allows you to simply check if the API call was successful and get the response message. Here is a simple example demonstrating this functionality. + +```python +from threadfix_api import threadfix + +tf = threadfix.ThreadFixAPI(host, api_key) + +teams = tf.list_teams() + +if teams.success: # Was the request a success? + # Everything worked fine, lets view the response data + print(teams.data) + + # If we want to print valid json + print(teams.data_json()) + + # Fancy indented json + print(teams.data_json(pretty=True)) +else: + # Print the reason why the request was not a success + print(teams.message) +``` + +If you are using a **self-signed certificate**, you can disable certificate verification when you instantiate the API wrapper. If disabled, API requests could be intercepted by third-parties -- use with caution. Option verify_ssl only applies to host certs. + +```python +tf = threadfix.ThreadFixAPI(host, api_key, verify_ssl=False) +``` + +You can also specify a local cert to use as client side certificate, as a single file (containing the private key and the certificate) or as a tuple of both file’s path: + +```python +cert=('/path/server.crt', '/path/key') +tf = threadfix.ThreadFixAPI(host, api_key, cert=cert) +``` + +## Table of Contents + +[Teams](#teams) + +- [List Teams: `list_teams`](#list-teams-list_teams) +- [Get Team: `get_team`](##get-team-get_team) +- [Get Team By Name: `get_team_by_name`](#get-team-by-name-get_team_by_name) + +[Applications](#applications) + +- [Create Application: `create_application`](#create-application-create_application) +- [Get Application: `get_application`](#get-application-get_application) +- [Get Application By Name: `get_application_by_name`](#get-application-by-name-get_application_by_name) +- [Set Application Parameters: `set_application_parameters`](#set-application-parameters-set_application_parameters) +- [Set Application URL: `set_application_url`](#set-application-url-set_application_url) +- [Set Application WAF: `set_application_waf`](#set-application-waf-set_application_waf) + +[Findings](#findings) + +- [Create Manual Finding: `create_manual_finding`](#create-manual-finding-create_manual_finding) +- [Create Static Finding: `create_static_finding`](#create-static-finding-create_static_finding) +- [Upload Scan: `upload_scan`](#upload-scan-upload_scan) + +[WAFs](#wafs) + +- [List WAFs: `list_wafs`](#list-wafs-list_wafs) +- [Create WAF: `create_waf`](#create-waf-create_waf) +- [Get WAF: `get_waf`](#get-waf-get_waf) +- [Get WAF By Name: `get_waf_by_name`](#get-waf-by-name-get_waf_by_name) +- [Get WAF Rules: `get_waf_rules`](#get-waf-rules-get_waf_rules) +- [Get WAF Rules By Application: `get_waf_rules_by_application`](#get-waf-rules-by-application-get_waf_rules_by_application) +- [Upload WAF Log: `upload_waf_log`](#upload-waf-log-upload_waf_log) + +[Vulnerabilities](#vulnerabilities) + +- [Get Vulnerabilities: `get_vulnerabilities`](#get-vulnerabilities-get_vulnerabilities) + +## Teams + +### List Teams: `list_teams` + +Retrieves all the teams. + +#### Parameters + +_None_ + +#### Example + +```python +tf = threadfix.ThreadFixAPI(host, api_key) +response = tf.list_teams() +``` + +### Create Team: `create_team` + +Creates a team with the given name. + +#### Parameters + +| Parameter | Required | Default | Description | Values | +| ---------- | -------- | ------- | ----------- | ------ | +| name | **Yes** | | The name of the new team that is being created. | | + +#### Example + +```python +tf = threadfix.ThreadFixAPI(host, api_key) +response = tf.create_team('Example Team') +``` + +### Get Team: `get_team` + +Retrieves a team using the given team id. + +#### Parameters + +| Parameter | Required | Default | Description | Values | +| ---------- | -------- | ------- | ----------- | ------ | +| team_id | **Yes** | | Team identifier. | | + +#### Example + +```python +tf = threadfix.ThreadFixAPI(host, api_key) +response = tf.get_team(4) +``` + +### Get Team By Name: `get_team_by_name` + +Retrieves a team using the given name. + +#### Parameters + +| Parameter | Required | Default | Description | Values | +| ---------- | -------- | ------- | ----------- | ------ | +| name | **Yes** | | The name of the team to be retrieved. | | + +#### Example + +```python +tf = threadfix.ThreadFixAPI(host, api_key) +response = tf.get_team_by_name('Home Team') +``` + +## Applications + +### Create Application: `create_application` + +Creates an application under a given team. + +#### Parameters + +| Parameter | Required | Default | Description | Values | +| ---------- | -------- | ------- | ----------- | ------ | +| team_id | **Yes** | | Team identifier. | | +| name | **Yes** | | The name of the new team being created. | | +| url | No | | The url of where application is located. | | + +#### Example + +```python +tf = threadfix.ThreadFixAPI(host, api_key) +response = tf.create_application( + team_id=1, + name='Example Application', + url='http://www.example.com/' +) +``` + +### Get Application: `get_application` + +Retrieves an application using the given application id. + +#### Parameters + +| Parameter | Required | Default | Description | Values | +| ---------- | -------- | ------- | ----------- | ------ | +| application_id | **Yes** | | Application identifier. | | + +#### Example + +```python +tf = threadfix.ThreadFixAPI(host, api_key) +response = tf.get_application(1) +``` + +### Get Application By Name: `get_application_by_name` + +Retrieves an application using the given team name and application name. + +#### Parameters + +| Parameter | Required | Default | Description | Values | +| ---------- | -------- | ------- | ----------- | ------ | +| team_id | **Yes** | | Team identifier. | | +| application_id | **Yes** | | Application identifier. | | + +#### Example + +```python +tf = threadfix.ThreadFixAPI(host, api_key) +response = tf.get_application_by_name('Home Team', 'Alfa Application') +``` + +### Set Application Parameters: `set_application_parameters` + +Sets parameters for the Hybrid Analysis Mapping ThreadFix functionality. + +#### Parameters + +| Parameter | Required | Default | Description | Values | +| ---------- | -------- | ------- | ----------- | ------ | +| application_id | **Yes** | | Application identifier. | | +| framework_type | **Yes** | | The web framework the app was built on. | `'None'`, `'DETECT'`, `'JSP'`, `'SPRING_MVC'` | +| repository_url | **Yes** | | The git repository where the source code for the application can be found. | | + +#### Example + +```python +tf = threadfix.ThreadFixAPI(host, api_key) +response = tf.set_application_parameters( + application_id=1, + framework_type='DETECT', + repository_url='http://repository.example.com/' +) +``` + +### Set Application URL: `set_application_url` + +Sets the application's URL. + +#### Parameters + +| Parameter | Required | Default | Description | Values | +| ---------- | -------- | ------- | ----------- | ------ | +| application_id | **Yes** | | Application identifier. | | +| url | **Yes** | | The url you want to assign to the application. | | + +#### Example + +```python +tf = threadfix.ThreadFixAPI(host, api_key) +response = tf.set_application_url( + application_id=1, + url='http://www.example.com/' +) +``` + +### Set Application WAF: `set_application_waf` + +Sets the application's WAF to the WAF with the specified id. + +#### Parameters + +| Parameter | Required | Default | Description | Values | +| ---------- | -------- | ------- | ----------- | ------ | +| application_id | **Yes** | | Application identifier. | | +| waf_id | **Yes** | | WAF identifier. | | + +#### Example + +```python +tf = threadfix.ThreadFixAPI(host, api_key) +response = tf.set_application_waf( + application_id=4, + waf_id=3 +) +``` + +## Findings + +### Create Manual Finding: `create_manual_finding` + +Creates a manual finding with given properties. + +#### Parameters + +| Parameter | Required | Default | Description | Values | +| ---------- | -------- | ------- | ----------- | ------ | +| application_id | **Yes** | | Application identifier. | | +| vulnerability_type | **Yes** | | Name of CWE vulnerability. | | +| description | **Yes** | | General description of the issue. | | +| severity | **Yes** | | Severity level. | 0 - 8 | +| full_url | No | | Absolute URL to the page with the vulnerability. | | +| native_id | No | | Specific identifier for vulnerability. | | +| path | No | | Relative path to vulnerability page. | | + +#### Example + +```python +tf = threadfix.ThreadFixAPI(host, api_key) +response = tf.create_manual_finding( + application_id=4, + vulnerability_type='Location', + description='This should be addressed', + severity=3, + full_url='http://www.samplewebsite.com', + native_id=24, + path='/store/3' +) +``` + +### Create Static Finding: `create_static_finding` + +Creates a static finding with given properties. + +#### Parameters + +| Parameter | Required | Default | Description | Values | +| ---------- | -------- | ------- | ----------- | ------ | +| application_id | **Yes** | | Application identifier. | | +| vulnerability_type | **Yes** | | Name of CWE vulnerability. | | +| description | **Yes** | | General description of the issue. | | +| severity | **Yes** | | Severity level. | 0 - 8 | +| parameter | _See Note_ | | Request parameter for vulnerability. | | +| file_path | _See Note_ | | Location of source file. | | +| native_id | No | | Specific identifier for vulnerability. | | +| column | No | | Column number for finding vulnerability source. | | +| line_text | No | | Specific line text to finding vulnerability. | | +| line_number | No | | Specific source line number to finding vulnerability. | | + +**Note:** Either `parameter` or `file_path` must be specified. If not, a ValueError will be raised. + +#### Example + +```python +tf = threadfix.ThreadFixAPI(host, api_key) +response = tf.create_static_finding( + application_id=4, + vulnerability_type='Location', + description='This should be addressed', + severity=3, + parameter='store', + native_id=24, + column=2, + line_text='findStore()', + line_number='234' +) +``` + +### Upload Scan: `upload_scan` + +Uploads and processes a scan file. + +#### Parameters + +| Parameter | Required | Default | Description | Values | +| ---------- | -------- | ------- | ----------- | ------ | +| application_id | **Yes** | | Application identifier. | | +| file_path | **Yes** | | Path to the scan file to be uploaded. | | + +#### Example + +```python +tf = threadfix.ThreadFixAPI(host, api_key) +response = tf.upload_scan( + application_id=4, + file_path='/home/threadfix/zap_scan.xml' +) +``` + +## WAFs + +### List WAFs: `list_wafs` + +Retrieves all WAFs in system. + +#### Parameters + +_None_ + +#### Example + +```python +tf = threadfix.ThreadFixAPI(host, api_key) +response = tf.list_wafs() +``` + +### Create WAF: `create_waf` + +Creates a WAF with the given type. + +#### Parameters + +| Parameter | Required | Default | Description | Values | +| ---------- | -------- | ------- | ----------- | ------ | +| name | **Yes** | | Name of the WAF. | | +| waf_type | **Yes** | | WAF type. | `'mod_security'`, `'Snort'`, `'Imperva SecureSphere'`, `'F5 BigIP ASM'`, `'DenyAll rWeb'` | + +#### Example + +```python +tf = threadfix.ThreadFixAPI(host, api_key) +response = tf.create_waf( + name='My Application WAF', + waf_type='mod_security' +) +``` + +### Get WAF: `get_waf` + +Retrieves WAF using the given WAF id. + +#### Parameters + +| Parameter | Required | Default | Description | Values | +| ---------- | -------- | ------- | ----------- | ------ | +| waf_id | **Yes** | | WAF identifier. | | + +#### Example + +```python +tf = threadfix.ThreadFixAPI(host, api_key) +response = tf.get_waf(4) +``` + +### Get WAF By Name: `get_waf_by_name` + +Retrieves waf using the given name. + +#### Parameters + +| Parameter | Required | Default | Description | Values | +| ---------- | -------- | ------- | ----------- | ------ | +| name | **Yes** | | Name of the WAF. | | + +#### Example + +```python +tf = threadfix.ThreadFixAPI(host, api_key) +response = tf.get_waf_by_name('My Application WAF') +``` + +### Get WAF Rules: `get_waf_rules` + +Retrieves all the rules for WAF with the given WAF id. + +#### Parameters + +| Parameter | Required | Default | Description | Values | +| ---------- | -------- | ------- | ----------- | ------ | +| waf_id | **Yes** | | WAF identifier. | | + +#### Example + +```python +tf = threadfix.ThreadFixAPI(host, api_key) +response = tf.get_waf_rules(4) +``` + +### Get WAF Rules By Application: `get_waf_rules_by_application` + +Returns the WAF rule text for one or all of the applications in a WAF. If the application id is -1, it will get rules for all apps. If the application is a valid application id, rules will be generated for that application. + +#### Parameters + +| Parameter | Required | Default | Description | Values | +| ---------- | -------- | ------- | ----------- | ------ | +| waf_id | **Yes** | | WAF identifier. | | +| application_id | **Yes** | | Application identifier. | | + +#### Example + +```python +tf = threadfix.ThreadFixAPI(host, api_key) +response = tf.get_waf_rules_by_application(4, 1) +``` + +### Upload WAF Log: `upload_waf_log` + +Uploads and processes a WAF log file. + +#### Parameters + +| Parameter | Required | Default | Description | Values | +| ---------- | -------- | ------- | ----------- | ------ | +| waf_id | **Yes** | | WAF identifier. | | +| file_path | **Yes** | | Path to the WAF log file to be uploaded. | | + +#### Example + +```python +tf = threadfix.ThreadFixAPI(host, api_key) +response = tf.upload_waf_log( + waf_id=4, + file_path='/home/threadfix/mod_secuity.log' +) +``` + +## Vulnerabilities + +### Get Vulnerabilities: `get_vulnerabilities` + +Returns filtered list of vulnerabilities. + +#### Parameters + +| Parameter | Required | Default | Description | Values | +| ---------- | -------- | ------- | ----------- | ------ | +| teams | No | | List of team ids. | | +| applications | No | | List of application ids. | | +| channel_types | No | | List of scanner names. | | +| start_date | No | | Lower bound on scan dates. | | +| end_date | No | | Upper bound on scan dates. | | +| generic_severities | No | | List of generic severity values. | | +| generic_vulnerabilities | No | | List of generic vulnerability ids. | | +| number_merged | No | | Number of vulnerabilities merged from different scans. | | +| number_vulnerabilities | No | | Number of vulnerabilities to return. | | +| parameter | No | | Application input that the vulnerability affects. | | +| path | No | | Path to the web page where the vulnerability was found. | | +| show_open | No | | Flag to show all open vulnerabilities. | | +| show_closed | No | | Flag to show all closed vulnerabilities. | | +| show_defect_open | No | | Flag to show any vulnerabilities with open defects. | | +| show_defect_closed | No | | Flag to show any vulnerabilities with closed defects. | | +| show_defect_present | No | | Flag to show any vulnerabilities with a defect. | | +| show_defect_not_present | No | | Flag to show any vulnerabilities without a defect. | | +| show_false_positive | No | | Flag to show any false positives from vulnerabilities. | | +| show_hidden | No | | Flag to show all hidden vulnerabilities. | | + +#### Example + +```python +tf = threadfix.ThreadFixAPI(host, api_key) +# Get all vulnerabilities +response = tf.get_vulnerabilities() +``` + +```python +tf = threadfix.ThreadFixAPI(host, api_key) +# Get open vulnerabilities +response = tf.get_vulnerabilities(show_open=True) +``` + +```python +tf = threadfix.ThreadFixAPI(host, api_key) +# Get vulnerabilities for specific applications +response = tf.get_vulnerabilities(applications=[4, 8, 15, 16, 23, 42]) +``` diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000000000000000000000000000000000000..ba9dc8423b62f8022c7a7b37504f36a1f8e1f94d --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,339 @@ +# -*- coding: utf-8 -*- +# +# DefectDojo API documentation build configuration file, created by +# sphinx-quickstart on Tue Nov 29 08:33:05 2016. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +import os +import sys +sys.path.insert(0, os.path.abspath('../..')) +sys.path.append(os.path.join(os.getcwd(),'../../defectdojo_api')) + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +# +# needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = ['sphinx.ext.autodoc'] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The encoding of source files. +# +# source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'DefectDojo API' +copyright = u'2016, Aaron Weaver' +author = u'Aaron Weaver' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = u'0.0.5' +# The full version, including alpha/beta/rc tags. +release = u'0.0.5' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +# +# today = '' +# +# Else, today_fmt is used as the format for a strftime call. +# +# today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This patterns also effect to html_static_path and html_extra_path +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +# +# default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +# +# add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +# +# add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +# +# show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +# modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +# keep_warnings = False + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = False + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = 'alabaster' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +# +# html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +# html_theme_path = [] + +# The name for this set of Sphinx documents. +# "<project> v<release> documentation" by default. +# +# html_title = u'DefectDojo API v0.0.5' + +# A shorter title for the navigation bar. Default is the same as html_title. +# +# html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +# +# html_logo = None + +# The name of an image file (relative to this directory) to use as a favicon of +# the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +# +# html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +# +# html_extra_path = [] + +# If not None, a 'Last updated on:' timestamp is inserted at every page +# bottom, using the given strftime format. +# The empty string is equivalent to '%b %d, %Y'. +# +# html_last_updated_fmt = None + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +# +# html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +# +# html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +# +# html_additional_pages = {} + +# If false, no module index is generated. +# +# html_domain_indices = True + +# If false, no index is generated. +# +# html_use_index = True + +# If true, the index is split into individual pages for each letter. +# +# html_split_index = False + +# If true, links to the reST sources are added to the pages. +# +# html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +# +# html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +# +# html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a <link> tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +# +# html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +# html_file_suffix = None + +# Language to be used for generating the HTML full-text search index. +# Sphinx supports the following languages: +# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' +# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr', 'zh' +# +# html_search_language = 'en' + +# A dictionary with options for the search language support, empty by default. +# 'ja' uses this config value. +# 'zh' user can custom change `jieba` dictionary path. +# +# html_search_options = {'type': 'default'} + +# The name of a javascript file (relative to the configuration directory) that +# implements a search results scorer. If empty, the default will be used. +# +# html_search_scorer = 'scorer.js' + +# Output file base name for HTML help builder. +htmlhelp_basename = 'DefectDojoAPIdoc' + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + # + # 'papersize': 'letterpaper', + + # The font size ('10pt', '11pt' or '12pt'). + # + # 'pointsize': '10pt', + + # Additional stuff for the LaTeX preamble. + # + # 'preamble': '', + + # Latex figure (float) alignment + # + # 'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'DefectDojoAPI.tex', u'DefectDojo API Documentation', + u'Aaron Weaver', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +# +# latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +# +# latex_use_parts = False + +# If true, show page references after internal links. +# +# latex_show_pagerefs = False + +# If true, show URL addresses after external links. +# +# latex_show_urls = False + +# Documents to append as an appendix to all manuals. +# +# latex_appendices = [] + +# It false, will not define \strong, \code, itleref, \crossref ... but only +# \sphinxstrong, ..., \sphinxtitleref, ... To help avoid clash with user added +# packages. +# +# latex_keep_old_macro_names = True + +# If false, no module index is generated. +# +# latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'defectdojoapi', u'DefectDojo API Documentation', + [author], 1) +] + +# If true, show URL addresses after external links. +# +# man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'DefectDojoAPI', u'DefectDojo API Documentation', + author, 'DefectDojoAPI', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +# +# texinfo_appendices = [] + +# If false, no module index is generated. +# +# texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +# +# texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +# +# texinfo_no_detailmenu = False diff --git a/docs/defectdojo_api.rst b/docs/defectdojo_api.rst new file mode 100644 index 0000000000000000000000000000000000000000..5c1d9181573559bd1dab7ef212dc2994d2f617ed --- /dev/null +++ b/docs/defectdojo_api.rst @@ -0,0 +1,22 @@ +defectdojo_api package +====================== + +Submodules +---------- + +defectdojo_api.defectdojo module +-------------------------------- + +.. automodule:: defectdojo_api.defectdojo + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: defectdojo_api + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000000000000000000000000000000000000..6ff26755d158addea245bbc77d5da50abfcbfc93 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,22 @@ +.. DefectDojo API documentation master file, created by + sphinx-quickstart on Tue Nov 29 08:33:05 2016. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to DefectDojo API's documentation! +========================================== + +Contents: + +.. toctree:: + :maxdepth: 2 + + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + diff --git a/docs/modules.rst b/docs/modules.rst new file mode 100644 index 0000000000000000000000000000000000000000..5666b421d11ed2cf6964266116745000d1de8e85 --- /dev/null +++ b/docs/modules.rst @@ -0,0 +1,7 @@ +defectdojo_api +============== + +.. toctree:: + :maxdepth: 4 + + defectdojo_api diff --git a/examples/dojo_product.py b/examples/dojo_product.py new file mode 100644 index 0000000000000000000000000000000000000000..413f0a882679d3759ae397e16144ef90b1fdc607 --- /dev/null +++ b/examples/dojo_product.py @@ -0,0 +1,67 @@ +from defectdojo_api import defectdojo + +import os + +# Setup DefectDojo connection information +host = 'http://localhost:8000' +api_key = os.environ['DOJO_API_KEY'] +user = 'admin' + +""" +#Optionally, specify a proxy +proxies = { + 'http': 'http://localhost:8080', + 'https': 'http://localhost:8080', +} +proxies=proxies +""" + +# Instantiate the DefectDojo api wrapper +dd = defectdojo.DefectDojoAPI(host, api_key, user, debug=False) + +# Create a product +prod_type = 1 #1 - Research and Development, product type +product = dd.create_product("API Product Test", "This is a detailed product description.", prod_type) + +if product.success: + # Get the product id + product_id = product.id() + print "Product successfully created with an id: " + str(product_id) + + # Retrieve the newly created product + product = dd.get_product(product_id) + if product.success: + print(product.data_json(pretty=True)) # Decoded JSON object + + # Update the product + product = dd.set_product(product_id, name="Newly Updated Name") + + if product.success: + print "Product successfully updated." + + # Retrieve the new product name + product = dd.get_product(product_id) + if product.success: + print "********************************" + print "Updated name:" + product.data['name'] + print "********************************" + +else: + print product.message + +# List Products +products = dd.list_products() + +if products.success: + #print(products.data_json(pretty=True)) # Decoded JSON object + print "********************************" + print "Total Number of Products: " + str(products.data["meta"]["total_count"]) + print "********************************" + + for product in products.data["objects"]: + print(product['id']) + print(product['name']) # Print the name of each product + print(product['description']) + print "******************" +else: + print products.message diff --git a/setup.py b/setup.py index c80e4fad1058518d2f782c83e5080d7bff3dda79..3e9ab3a138e2f1fa1cf7ae6cdd3130c1353672d5 100644 --- a/setup.py +++ b/setup.py @@ -13,21 +13,6 @@ from defectdojo_api import __version__ as version with open('README.rst', 'r') as f: readme = f.read() -""" -# Publish helper -if sys.argv[-1] == 'build': - os.system('python setup.py sdist bdist_wheel') - sys.exit(0) - -if sys.argv[-1] == 'publish': - os.system('python setup.py sdist bdist_wheel upload -r pypi') - sys.exit(0) - -if sys.argv[-1] == 'publish-test': - os.system('python setup.py sdist bdist_wheel upload -r pypitest') - sys.exit(0) -""" - # allow setup.py to be run from any path os.chdir(os.path.normpath(os.path.join(os.path.abspath(__file__), os.pardir))) @@ -35,22 +20,22 @@ setup( name='defectdojo_api', packages=['defectdojo_api'], version=version, - description='An API wrapper to for Defect Dojo.', + description='An API wrapper for DefectDojo.', long_description=readme, author='Aaron Weaver', author_email='aaron.weaver2@gmail.com', - url='https://github.com/aaronweaver/defect_dojo_api', - download_url='https://github.com/aaronweaver/defect_dojo_api/tarball/' + version, + url='https://github.com/aaronweaver/defectdojo_api', + download_url='https://github.com/aaronweaver/defectdojo_api/tarball/' + version, license='MIT', install_requires=['requests'], keywords=['dojo', 'api', 'security', 'software'], classifiers=[ - 'Development Status :: 1 - Beta', 'Intended Audience :: Developers', 'Natural Language :: English', 'License :: OSI Approved :: MIT License', 'Topic :: Software Development', 'Topic :: Software Development :: Libraries :: Python Modules', + 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.2', 'Programming Language :: Python :: 3.3', diff --git a/tests/defectdojo_api_unit_test.py b/tests/defectdojo_api_unit_test.py index 6803d538c5cd5440a3a7b1de0a8ec493ef88fad5..aa3ad815a2f8646fd16d6521671085b9c0afac30 100644 --- a/tests/defectdojo_api_unit_test.py +++ b/tests/defectdojo_api_unit_test.py @@ -7,7 +7,7 @@ class TestDefectDojoAPI(unittest.TestCase): def setUp(self): host = 'http://localhost:8000' - api_key = 'd76b707b48dbdca6222db7cd71c839ead6b1768e' + api_key = os.environ['DOJO_API_KEY'] user = 'admin' self.dd = defectdojo.DefectDojoAPI(host, api_key, user, debug=False) @@ -17,8 +17,8 @@ class TestDefectDojoAPI(unittest.TestCase): user = self.dd.get_user(1) self.assertIsNotNone(user.data['username']) - def test_02_get_users(self): - users = self.dd.get_users() + def test_02_list_users(self): + users = self.dd.list_users() #print users.data_json(pretty=True) #Test that the total count is not zero self.assertTrue(users.data["meta"]["total_count"]>0) @@ -39,8 +39,8 @@ class TestDefectDojoAPI(unittest.TestCase): #print product.data_json(pretty=True) self.assertEqual("Product Update Test", product.data['name']) - def test_06_get_products(self): - products = self.dd.get_products() + def test_06_list_products(self): + products = self.dd.list_products() #print products.data_json(pretty=True) #Test that the total count is not zero self.assertTrue(products.data["meta"]["total_count"]>0) @@ -57,8 +57,8 @@ class TestDefectDojoAPI(unittest.TestCase): #print engagement.data_json(pretty=True) self.assertIsNotNone(str(engagement.data["name"])) - def test_09_get_engagements(self): - engagements = self.dd.get_engagements() + def test_09_list_engagements(self): + engagements = self.dd.list_engagements() #print engagements.data_json(pretty=True) self.assertTrue(engagements.data["meta"]["total_count"]>0) @@ -81,8 +81,8 @@ class TestDefectDojoAPI(unittest.TestCase): #print test.data_json(pretty=True) self.assertIsNotNone(str(test.data["engagement"])) - def test_13_get_tests(self): - tests = self.dd.get_tests() + def test_13_list_tests(self): + tests = self.dd.list_tests() #print tests.data_json(pretty=True) self.assertTrue(tests.data["meta"]["total_count"]>0) @@ -107,8 +107,8 @@ class TestDefectDojoAPI(unittest.TestCase): #print finding.data_json(pretty=True) self.assertIsNotNone(str(finding.data["title"])) - def test_17_get_findings(self): - findings = self.dd.get_findings() + def test_17_list_findings(self): + findings = self.dd.list_findings() #print findings.data_json(pretty=True) self.assertTrue(findings.data["meta"]["total_count"]>0)