Skip to content

Commit

Permalink
use an absolute report url (handle IQ 104+) (#48)
Browse files Browse the repository at this point in the history
* use an absolute report url (handle IQ 104+)
  • Loading branch information
bhamail committed Jan 27, 2021
1 parent 5377f24 commit 2cac53e
Show file tree
Hide file tree
Showing 6 changed files with 171 additions and 35 deletions.
71 changes: 40 additions & 31 deletions jake/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -334,37 +334,46 @@ def __iq_control_flow(args: dict, bom_str: bytes):
spinner.text = "Reticulating splines..."
iq_requests.poll_report(status_url)

if iq_requests.get_policy_action() == 'Failure':
spinner.fail("💥 ")
__toggle_stdout(on=True)
print(Fore.YELLOW +
"Snakes on the plane! There are policy failures from Sonatype IQ.")
print(Fore.YELLOW +
"Your IQ Server Report is available here: {}".format(iq_requests.get_report_url()))
_exit(1)
elif iq_requests.get_policy_action() == 'Warning':
spinner.ok("🧨 ")
__toggle_stdout(on=True)
print(Fore.GREEN +
"Something slithers around your ankle! There are policy warnings from Sonatype IQ.")
print(Fore.GREEN +
"Your IQ Server Report is available here: {}".format(iq_requests.get_report_url()))
_exit(0)
elif iq_requests.get_policy_action() == 'None':
spinner.ok("🐍 ")
__toggle_stdout(on=True)
print(Fore.GREEN +
"Smooth slithering there bud! No policy failures from Sonatype IQ.")
print(Fore.GREEN +
"Your IQ Server Report is available here: {}".format(iq_requests.get_report_url()))
_exit(0)
else:
spinner.fail("🐍 ")
__toggle_stdout(on=True)
print(Fore.RED +
"Received an error response from IQ Server, please check logs. policy action: {}"
.format(iq_requests.get_policy_action()))
_exit(3)
_exit(_show_summary(iq_requests, spinner))


def _show_summary(iq_requests, spinner):
if iq_requests.get_policy_action() == 'Failure':
spinner.fail("💥 ")
__toggle_stdout(on=True)
print(Fore.RED +
"Snakes on the plane! There are policy failures from Sonatype IQ.")
print(Fore.RED + "Your IQ Server Report is available here: {}"
.format(iq_requests.get_absolute_report_url()))
exit_status_code = 1
elif iq_requests.get_policy_action() == 'Warning':
spinner.ok("🧨 ")
__toggle_stdout(on=True)
print(Fore.YELLOW +
"Something slithers around your ankle! There are policy warnings from Sonatype IQ.")
print(Fore.YELLOW + "Your IQ Server Report is available here: {}"
.format(iq_requests.get_absolute_report_url()))
exit_status_code = 0
elif iq_requests.get_policy_action() == 'None':
spinner.ok("🐍 ")
__toggle_stdout(on=True)
print(Fore.GREEN +
"Smooth slithering there bud! No policy failures from Sonatype IQ.")
print(Fore.GREEN + "Your IQ Server Report is available here: {}"
.format(iq_requests.get_absolute_report_url()))
exit_status_code = 0
else:
spinner.fail("🐍 ")
__toggle_stdout(on=True)
print(Fore.RED +
"Received an error response from IQ Server, please check logs. policy action: {}"
.format(iq_requests.get_policy_action()))
exit_status_code = 3

# reset console colors, etc
print(Fore.RESET)
return exit_status_code


def __sbom_control_flow(conda: bool, target: str) -> (bytes):
"""
Expand Down
6 changes: 6 additions & 0 deletions jake/iq/iq.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
# pylint: disable=too-many-instance-attributes
import json
import logging
import urllib

from json import JSONDecodeError

Expand Down Expand Up @@ -78,6 +79,11 @@ def get_report_url(self):
"""gets report url from IQ Server result"""
return self._report_url

def get_absolute_report_url(self):
"""get full (non-relative) url to IQ Server report"""
# urljoin() will ignore the first parameter (base) if the second parameter (url) is absolute
return urllib.parse.urljoin(self._iq_url, self._report_url)

def get_public_application_id(self) -> (str):
"""gets public application id to use for IQ Server request"""
return self._public_application_id
Expand Down
16 changes: 16 additions & 0 deletions jake/test/iqresponse_absolute_report_url.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"policyAction": "Warning",
"reportHtmlUrl": "http://localhost:8070/ui/links/application/my-app/report/95c4c14e",
"isError": false,
"componentsAffected": {
"critical": 1,
"severe": 0,
"moderate": 0
},
"openPolicyViolations": {
"critical": 2,
"severe": 1,
"moderate": 0
},
"grandfatheredPolicyViolations": 0
}
16 changes: 16 additions & 0 deletions jake/test/iqresponse_relative_report_url.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"policyAction": "Warning",
"reportHtmlUrl": "ui/links/application/my-app/report/95c4c14e",
"isError": false,
"componentsAffected": {
"critical": 1,
"severe": 0,
"moderate": 0
},
"openPolicyViolations": {
"critical": 2,
"severe": 1,
"moderate": 0
},
"grandfatheredPolicyViolations": 0
}
47 changes: 43 additions & 4 deletions jake/test/test_iq.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,6 @@
import responses

from ..iq.iq import IQ
# from ..types.coordinates import Coordinates
# from ..types.coordinateresults import CoordinateResults
# from ..types.results_decoder import ResultsDecoder
# from ..types.vulnerabilities import Vulnerabilities

class TestIQ(unittest.TestCase):
"""TestIQ audits the call to IQ"""
Expand Down Expand Up @@ -136,3 +132,46 @@ def test_call_poll_report_warning_policy_action(self):

self.func.poll_report(self.status_url)
self.assertEqual(self.func.get_policy_action(), 'Warning')

@responses.activate
def test_call_poll_report_absolute_result_url(self):
"""test_call_poll_report_relative_result_url mocks a call to IQ
and ensures an absolute report URL is returned,
and ensure that same absolute report URL is returned from get_absolute_report_url()"""
file = Path(__file__).parent / "iqresponse_absolute_report_url.json"
with open(file, "r") as stdin:
mock_json = json.loads(stdin.read())
responses.add(responses.GET,
self.full_status_url,
json=mock_json, status=200)

self.func.poll_report(self.status_url)
# pylint: disable=W0212
self.assertEqual(self.func._iq_url, 'http://afakeurlthatdoesnotexist.com:8081')
self.assertEqual(self.func.get_report_url(),
'http://localhost:8070/ui/links/application/my-app/report/95c4c14e')
# ensure we use the IQ provided absolute URL
self.assertEqual(self.func.get_absolute_report_url(),
'http://localhost:8070/ui/links/application/my-app/report/95c4c14e')

@responses.activate
def test_call_poll_report_relative_result_url(self):
"""test_call_poll_report_relative_result_url mocks a call to IQ
and ensures a relative report URL is returned,
and ensure get_absolute_report_url() returns an absolute URL
built from the _iq_url and relative report URL"""
file = Path(__file__).parent / "iqresponse_relative_report_url.json"
with open(file, "r") as stdin:
mock_json = json.loads(stdin.read())
responses.add(responses.GET,
self.full_status_url,
json=mock_json, status=200)

self.func.poll_report(self.status_url)
# pylint: disable=W0212
self.assertEqual(self.func._iq_url, 'http://afakeurlthatdoesnotexist.com:8081')
self.assertEqual(self.func.get_report_url(),
'ui/links/application/my-app/report/95c4c14e')
# build the absolute URL from the IQ Server base url
self.assertEqual(self.func.get_absolute_report_url(),
'http://afakeurlthatdoesnotexist.com:8081/ui/links/application/my-app/report/95c4c14e')
50 changes: 50 additions & 0 deletions jake/test/test_main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#
# Copyright 2019-Present Sonatype Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

"""test_main.py test stuff in __main__.py"""
import unittest

from yaspin import yaspin

from jake.__main__ import _show_summary
from jake.iq.iq import IQ


class TestMain(unittest.TestCase):
"""TestMain tests stuff in __main__"""

def setUp(self):
iq_args = {}
self.func = IQ(args=iq_args)

def test_show_summary(self):
"""test_show_summary verifies exit code is correct for a given IQ Policy Action"""
spinner = yaspin(text="Loading", color="magenta")

# pylint: disable=W0212
self.func._report_url = 'myRelativeReportURL'

self.func._policy_action = None
self.assertEqual(3, _show_summary(self.func, spinner))

self.func._policy_action = "Failure"
self.assertEqual(1, _show_summary(self.func, spinner))

self.func._policy_action = "Warning"
self.assertEqual(0, _show_summary(self.func, spinner))

self.func._policy_action = "None"
self.assertEqual(0, _show_summary(self.func, spinner))

0 comments on commit 2cac53e

Please sign in to comment.