Skip to content

Commit

Permalink
Add Snyk scan suggestion when building
Browse files Browse the repository at this point in the history
Signed-off-by: Ulysses Souza <[email protected]>
  • Loading branch information
ulyssessouza committed Apr 1, 2021
1 parent 84afa51 commit 5773a11
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 0 deletions.
59 changes: 59 additions & 0 deletions compose/cli/scan_suggest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import json
import logging
import os
from distutils.util import strtobool

from docker.constants import IS_WINDOWS_PLATFORM
from docker.utils.config import find_config_file


SCAN_BINARY_NAME = "docker-scan" + (".exe" if IS_WINDOWS_PLATFORM else "")

log = logging.getLogger(__name__)


class ScanConfig:
def __init__(self, dict):
self.optin = False
vars(self).update(dict)


def display_scan_suggest_msg():
if environment_scan_avoid_suggest() or \
scan_already_invoked() or \
not scan_available():
return
log.info("Use 'docker scan' to run Snyk tests against images to find vulnerabilities "
"and learn how to fix them")


def environment_scan_avoid_suggest():
return os.getenv('DOCKER_SCAN_SUGGEST', 'true').lower() == 'false'


def scan_already_invoked():
docker_folder = docker_config_folder()
if docker_folder is None:
return False

scan_config_file = os.path.join(docker_folder, 'scan', "config.json")
if not os.path.exists(scan_config_file):
return False

data = ''
with open(scan_config_file) as f:
data = f.read()
scan_config = json.loads(data, object_hook=ScanConfig)
return scan_config.optin if isinstance(scan_config.optin, bool) else strtobool(scan_config.optin)


def scan_available():
docker_folder = docker_config_folder()
scan_config_file = os.path.join(docker_folder, 'cli-plugins', SCAN_BINARY_NAME)
return os.path.isfile(scan_config_file) or os.path.islink(scan_config_file)


def docker_config_folder():
docker_config_file = find_config_file()
return None if not docker_config_file \
else os.path.dirname(os.path.abspath(docker_config_file))
11 changes: 11 additions & 0 deletions compose/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

from . import parallel
from .cli.errors import UserError
from .cli.scan_suggest import display_scan_suggest_msg
from .config import ConfigurationError
from .config.config import V1
from .config.sort_services import get_container_name_from_network_mode
Expand Down Expand Up @@ -518,6 +519,9 @@ def build_service(service):
for service in services:
build_service(service)

if services:
display_scan_suggest_msg()

def create(
self,
service_names=None,
Expand Down Expand Up @@ -660,8 +664,15 @@ def up(self,
service_names,
include_deps=start_deps)

must_build = False
for svc in services:
if svc.must_build(do_build=do_build):
must_build = True
svc.ensure_image_exists(do_build=do_build, silent=silent, cli=cli)

if must_build:
display_scan_suggest_msg()

plans = self._get_convergence_plans(
services,
strategy,
Expand Down
18 changes: 18 additions & 0 deletions compose/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,24 @@ def ensure_image_exists(self, do_build=BuildAction.none, silent=False, cli=False
"rebuild this image you must use `docker-compose build` or "
"`docker-compose up --build`.".format(self.name))

def must_build(self, do_build=BuildAction.none):
if self.can_be_built() and do_build == BuildAction.force:
return True

try:
self.image()
return False
except NoSuchImageError:
pass

if not self.can_be_built():
return False

if do_build == BuildAction.skip:
return False

return True

def get_image_registry_data(self):
try:
return self.client.inspect_distribution(self.image_name)
Expand Down

0 comments on commit 5773a11

Please sign in to comment.