Skip to content

Commit

Permalink
Used HTTPS by default
Browse files Browse the repository at this point in the history
  • Loading branch information
tysmith committed Oct 14, 2023
1 parent eb1b796 commit 1ae12eb
Show file tree
Hide file tree
Showing 11 changed files with 146 additions and 14 deletions.
4 changes: 2 additions & 2 deletions grizzly/args.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,9 +181,9 @@ def __init__(self):
f" (default: '--test-limit' + {TIMEOUT_DELAY}s)",
)
self.launcher_grp.add_argument(
"--use-https",
"--use-http",
action="store_true",
help="Enable HTTPS. (default: %(default)s)",
help="Use HTTP instead of HTTPS.",
)
self.launcher_grp.add_argument(
"--version",
Expand Down
8 changes: 6 additions & 2 deletions grizzly/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,8 @@ def main(args):
else:
relaunch = args.relaunch

if args.use_https:
if not args.use_http:
certs = CertificateBundle.create()
LOG.info("HTTPS enabled")

LOG.debug("initializing the Target %r", args.platform)
target = load_plugin(args.platform, "grizzly_targets", Target)(
Expand All @@ -88,6 +87,11 @@ def main(args):
target.process_assets()
adapter.monitor = target.monitor

if certs and not target.https():
LOG.warning("Target does not support HTTPS, using HTTP")
certs.cleanup()
certs = None

LOG.debug("initializing the Reporter")
if args.fuzzmanager:
reporter = FuzzManagerReporter(args.tool or f"grizzly-{adapter.name}")
Expand Down
9 changes: 7 additions & 2 deletions grizzly/reduce/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -824,9 +824,8 @@ def main(cls, args):
args.repeat = max(args.min_crashes, args.repeat)
relaunch = min(args.relaunch, args.repeat)

if args.use_https or any(x.https for x in testcases):
if not args.use_http:
certs = CertificateBundle.create()
LOG.info("HTTPS enabled")

LOG.debug("initializing the Target")
target = load_plugin(args.platform, "grizzly_targets", Target)(
Expand All @@ -850,6 +849,12 @@ def main(cls, args):
# prioritize specified assets over included
target.assets.add_batch(args.asset)
target.process_assets()

if certs and not target.https():
LOG.warning("Target does not support HTTPS, using HTTP")
certs.cleanup()
certs = None

LOG.debug("starting sapphire server")
# launch HTTP server used to serve test cases
with Sapphire(auto_close=1, timeout=timeout, certs=certs) as server:
Expand Down
32 changes: 31 additions & 1 deletion grizzly/reduce/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

from ..common.storage import TestCase, TestCaseLoadFailure
from ..common.utils import ConfigError, Exit
from ..target import AssetManager, TargetLaunchError, TargetLaunchTimeout
from ..target import AssetManager, Target, TargetLaunchError, TargetLaunchTimeout
from . import ReduceManager
from .args import ReduceArgs, ReduceFuzzManagerIDArgs, ReduceFuzzManagerIDQualityArgs
from .exceptions import GrizzlyReduceBaseException
Expand Down Expand Up @@ -217,3 +217,33 @@ def test_main_launch_error(mocker, exc_type):
assert report is exc_obj.report
else:
assert reporter.return_value.submit.call_count == 0


@mark.parametrize("https_supported", [True, False])
def test_main_https_support(mocker, tmp_path, https_supported):
"""test ReduceManager.main() - Target HTTPS support"""
mocker.patch("grizzly.reduce.core.FuzzManagerReporter", autospec=True)
mocker.patch("grizzly.reduce.core.ReduceManager.run", autospec=True, return_value=0)
mocker.patch("grizzly.reduce.core.ReductionStatus", autospec=True)
mocker.patch("grizzly.reduce.core.Sapphire", autospec=True)
(tmp_path / "test.html").touch()
# setup args
args = mocker.Mock(
ignore=["fake"],
input=tmp_path / "test.html",
min_crashes=1,
relaunch=1,
repeat=1,
sig=None,
test_index=None,
use_http=False,
time_limit=1,
timeout=1,
)

target_cls = mocker.MagicMock(spec_set=Target)
target = target_cls.return_value
target.https.return_value = https_supported
mocker.patch("grizzly.reduce.core.load_plugin", return_value=target_cls)
assert ReduceManager.main(args) == 0
assert target.https.call_count == 1
8 changes: 6 additions & 2 deletions grizzly/replay/replay.py
Original file line number Diff line number Diff line change
Expand Up @@ -631,9 +631,8 @@ def main(cls, args):
args.min_crashes,
relaunch,
)
if args.use_https or any(x.https for x in testcases):
if not args.use_http:
certs = CertificateBundle.create()
LOG.info("HTTPS enabled")
LOG.debug("initializing the Target")
target = load_plugin(args.platform, "grizzly_targets", Target)(
args.binary,
Expand All @@ -656,6 +655,11 @@ def main(cls, args):
target.assets.add_batch(args.asset)
target.process_assets()

if certs and not target.https():
LOG.warning("Target does not support HTTPS, using HTTP")
certs.cleanup()
certs = None

LOG.debug("starting sapphire server")
# launch HTTP server used to serve test cases
with Sapphire(auto_close=1, timeout=timeout, certs=certs) as server:
Expand Down
28 changes: 28 additions & 0 deletions grizzly/replay/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -443,3 +443,31 @@ def test_main_07(mocker, server, tmp_path):
assert target.assets.add.call_count == 0
assert target.assets.is_empty.call_count == 1
assert reporter.return_value.submit.call_count == 1


@mark.parametrize("https_supported", [True, False])
def test_main_08(mocker, tmp_path, https_supported):
"""test ReplayManager.main() - Target HTTPS support"""
(tmp_path / "test.html").touch()
args = mocker.MagicMock(
adapter="fake",
binary=Path("bin"),
input=tmp_path / "test.html",
fuzzmanager=False,
launch_attempts=1,
min_crashes=1,
relaunch=1,
repeat=1,
sig=None,
use_http=False,
time_limit=1,
timeout=1,
)

target_cls = mocker.MagicMock(spec_set=Target)
target = target_cls.return_value
target.https.return_value = https_supported
mocker.patch("grizzly.replay.replay.load_plugin", return_value=target_cls)
mocker.patch("grizzly.replay.replay.ReplayManager.run", return_value=[])
assert ReplayManager.main(args) == Exit.FAILURE
assert target.https.call_count == 1
20 changes: 15 additions & 5 deletions grizzly/target/puppet_target.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from time import sleep, time

from ffpuppet import BrowserTimeoutError, Debugger, FFPuppet, LaunchError, Reason
from ffpuppet.helpers import certutil_available, certutil_find
from ffpuppet.sanitizer_util import SanitizerOptions
from prefpicker import PrefPicker
from psutil import AccessDenied, NoSuchProcess, Process, process_iter, wait_procs
Expand Down Expand Up @@ -85,14 +86,23 @@ class PuppetTarget(Target):
__slots__ = ("use_valgrind", "_debugger", "_extension", "_prefs", "_puppet")

def __init__(self, binary, launch_timeout, log_limit, memory_limit, **kwds):
certs = kwds.pop("certs", None)
# only pass certs to FFPuppet if certutil is available
# otherwise certs can't be used
if certs and not certutil_available(certutil_find(binary)):
LOG.warning("HTTPS support requires NSS certutil.")
certs = None

super().__init__(
binary,
launch_timeout,
log_limit,
memory_limit,
assets=kwds.pop("assets", None),
certs=kwds.pop("certs", None),
certs=certs,
)
self._https = certs is not None

# TODO: clean up handling debuggers
self._debugger = Debugger.NONE
if kwds.pop("pernosco", False):
Expand All @@ -111,10 +121,7 @@ def __init__(self, binary, launch_timeout, log_limit, memory_limit, **kwds):
headless=kwds.pop("headless", None),
working_path=str(grz_tmp("target")),
)
if kwds:
LOG.warning(
"PuppetTarget ignoring unsupported arguments: %s", ", ".join(kwds)
)
LOG.debug("PuppetTarget ignoring unsupported arguments: %s", ", ".join(kwds))

def _cleanup(self):
# prevent parallel calls to FFPuppet.close() and/or FFPuppet.clean_up()
Expand Down Expand Up @@ -223,6 +230,9 @@ def handle_hang(self, ignore_idle=True, ignore_timeout=False):
self.close()
return was_idle

def https(self):
return self._https

def dump_coverage(self, timeout=5):
if system() != "Linux":
LOG.debug("dump_coverage() only supported on Linux")
Expand Down
6 changes: 6 additions & 0 deletions grizzly/target/target.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ class Target(metaclass=ABCMeta):

__slots__ = (
"_assets",
"_https",
"_lock",
"_monitor",
"binary",
Expand All @@ -74,6 +75,7 @@ def __init__(
assert assets is None or isinstance(assets, AssetManager)
assert certs is None or isinstance(certs, CertificateBundle)
self._assets = assets if assets else AssetManager(base_path=grz_tmp("target"))
self._https = False
self._lock = Lock()
self._monitor = None
self.binary = binary
Expand Down Expand Up @@ -136,6 +138,10 @@ def filtered_environ(self):
def handle_hang(self, ignore_idle=True, ignore_timeout=False):
pass

@abstractmethod
def https(self):
pass

# TODO: move to monitor?
def is_idle(self, _threshold):
LOG.debug("Target.is_idle() not implemented! returning False")
Expand Down
27 changes: 27 additions & 0 deletions grizzly/target/test_puppet_target.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from ffpuppet import BrowserTerminatedError, BrowserTimeoutError, Debugger, Reason
from pytest import mark, raises

from ..common.utils import CertificateBundle
from .puppet_target import PuppetTarget
from .target import AssetManager, Result, TargetLaunchError, TargetLaunchTimeout

Expand All @@ -27,6 +28,7 @@ def test_puppet_target_01(mocker, tmp_path):
assert target.log_limit == 25
assert target.memory_limit == 5000
assert target.check_result([]) == Result.NONE
assert not target.https()
assert target.log_size() == 1124
fake_ffp.return_value.log_length.assert_any_call("stderr")
fake_ffp.return_value.log_length.assert_any_call("stdout")
Expand Down Expand Up @@ -473,3 +475,28 @@ def test_puppet_target_14(mocker, tmp_path):
fake_file.touch()
with PuppetTarget(fake_file, 300, 25, 5000) as target:
target.dump_coverage()


@mark.parametrize(
"certutil, certs",
[
# certutil and cert bundle available
(True, True),
# missing certutil
(False, True),
# no cert bundle
(True, False),
],
)
def test_puppet_target_15(mocker, tmp_path, certutil, certs):
"""test PuppetTarget - HTTPS support"""
mocker.patch(
"grizzly.target.puppet_target.certutil_available", return_value=certutil
)

fake_file = tmp_path / "fake"
fake_file.touch()

certs_bundle = mocker.Mock(spec_set=CertificateBundle) if certs else None
with PuppetTarget(fake_file, 300, 25, 5000, certs=certs_bundle) as target:
assert target.https() == (certutil and certs)
3 changes: 3 additions & 0 deletions grizzly/target/test_target.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ def create_report(self, is_hang=False):
def handle_hang(self, ignore_idle=True, ignore_timeout=False):
pass

def https(self):
return self._https

def launch(self, location):
pass

Expand Down
15 changes: 15 additions & 0 deletions grizzly/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,3 +151,18 @@ def test_main_04(
assert target_cls.call_args[-1]["pernosco"] == pernosco
assert target_cls.call_args[-1]["rr"] == rr
assert target_cls.call_args[-1]["valgrind"] == valgrind


def test_main_05(mocker, session_setup):
"""test target does not support https"""
target_cls = session_setup[3]
target_cls.return_value.https.return_value = False
args = mocker.MagicMock(
adapter="fake",
binary=Path("bin"),
use_http=False,
time_limit=1,
timeout=1,
)
assert main(args) == Exit.SUCCESS
assert target_cls.return_value.https.call_count == 1

0 comments on commit 1ae12eb

Please sign in to comment.