Skip to content

Commit

Permalink
Merge pull request #8247 from ulyssessouza/scan-suggestion
Browse files Browse the repository at this point in the history
Add Snyk scan suggestion when building
  • Loading branch information
aiordache authored Apr 6, 2021
2 parents 84afa51 + e496c64 commit 3c9ee67
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 0 deletions.
85 changes: 85 additions & 0 deletions compose/cli/scan_suggest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
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, d):
self.optin = False
vars(self).update(d)


def display_scan_suggest_msg():
if environment_scan_avoid_suggest() or \
scan_available() is None or \
scan_already_invoked():
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

try:
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)
except Exception: # pylint:disable=broad-except
return True


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

if IS_WINDOWS_PLATFORM:
program_data_scan_bin = os.path.join('C:\\', 'ProgramData', 'Docker', 'cli-plugins',
SCAN_BINARY_NAME)
if os.path.isfile(program_data_scan_bin) or os.path.islink(program_data_scan_bin):
return program_data_scan_bin
else:
lib_scan_bin = os.path.join('/usr', 'local', 'lib', 'docker', 'cli-plugins', SCAN_BINARY_NAME)
if os.path.isfile(lib_scan_bin) or os.path.islink(lib_scan_bin):
return lib_scan_bin
lib_exec_scan_bin = os.path.join('/usr', 'local', 'libexec', 'docker', 'cli-plugins',
SCAN_BINARY_NAME)
if os.path.isfile(lib_exec_scan_bin) or os.path.islink(lib_exec_scan_bin):
return lib_exec_scan_bin
lib_scan_bin = os.path.join('/usr', 'lib', 'docker', 'cli-plugins', SCAN_BINARY_NAME)
if os.path.isfile(lib_scan_bin) or os.path.islink(lib_scan_bin):
return lib_scan_bin
lib_exec_scan_bin = os.path.join('/usr', 'libexec', 'docker', 'cli-plugins', SCAN_BINARY_NAME)
if os.path.isfile(lib_exec_scan_bin) or os.path.islink(lib_exec_scan_bin):
return lib_exec_scan_bin
return None


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 3c9ee67

Please sign in to comment.