Skip to content

Commit

Permalink
Merge subcommand (#8)
Browse files Browse the repository at this point in the history
* Merge subcommand
* Change documention
  • Loading branch information
joelee2012 authored Dec 3, 2019
1 parent 3130659 commit e7a4453
Show file tree
Hide file tree
Showing 25 changed files with 400 additions and 280 deletions.
6 changes: 3 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ python:
- "2.7"
- "3.6"
- "3.7"
- "3.8"
# command to install dependencies
install:
- pip install coveralls
- pip install coveralls tox
- pip install --upgrade setuptools wheel twine
- pip install -r test-requirements.txt
# command to run tests
script:
- pytest -v --cov-report term --cov=claircli tests/ --cov-report html
- tox -e py,pylint,style
- python setup.py sdist bdist_wheel
- twine check dist/*
after_success:
Expand Down
71 changes: 61 additions & 10 deletions README.md
100755 → 100644
Original file line number Diff line number Diff line change
@@ -1,34 +1,85 @@
[![Build Status](https://travis-ci.com/joelee2012/claircli.svg?branch=master)](https://travis-ci.com/joelee2012/claircli)
[![Coverage Status](https://coveralls.io/repos/github/joelee2012/claircli/badge.svg?branch=master)](https://coveralls.io/github/joelee2012/claircli?branch=master)
# claircli
## claircli is a simple command line tool to interact with [CoreOS Clair](https://github.com/coreos/clair)
- analyze loacl/remote docker image with [clair](https://github.com/coreos/clair)
## claircli is a command line tool to interact with [CoreOS Clair](https://github.com/quay/clair)
- analyze loacl/remote docker image with [Clair](https://github.com/quay/clair)
- generate HTML/JSON report, the html report template is from [analysis-template.html](https://github.com/jgsqware/clairctl/blob/master/clair/templates/analysis-template.html)

# Installation

```bash
pip install claircli
```
```

# Commands

```
claircli -h
usage: claircli [-h] [-V] {batch-analyze,fuzzy-analyze} ...
usage: claircli [-h] [-V] [-c CLAIR] [-w WHITE_LIST] [-T THRESHOLD]
[-f {html,json}] [-L LOG_FILE] [-d] [-l LOCAL_IP | -r]
images [images ...]
Command line tool to interact with CoreOS Clair, analyze docker image with
clair in different ways
Simple command line tool to interact with CoreOS Clair
positional arguments:
images docker images or regular expression
optional arguments:
-h, --help show this help message and exit
-V, --version show program's version number and exit
-c CLAIR, --clair CLAIR
clair url, default: http://localhost:6060
-w WHITE_LIST, --white-list WHITE_LIST
path to the whitelist file
-T THRESHOLD, --threshold THRESHOLD
cvd severity threshold, if any servity of
vulnerability above of threshold, will return non-
zero, default: Unknown, choices are: ['Defcon1',
'Critical', 'High', 'Medium', 'Low', 'Negligible',
'Unknown']
-f {html,json}, --formats {html,json}
output report file with give format, default: ['html']
-L LOG_FILE, --log-file LOG_FILE
save log to file
-d, --debug print more logs
-l LOCAL_IP, --local-ip LOCAL_IP
ip address of local host
-r, --regex if set, repository and tag of images will be treated
as regular expression
Examples:
# analyze and output report to html
# clair is running at http://localhost:6060
claircli example.reg.com/myimage1:latest example.reg.com/myimage2:latest
# analyze and output report to html
# clair is running at https://example.clair.com:6060
claircli -c https://example.clair.com:6060 example.reg.com/myimage1:latest
# analyze and output report to html, json
claircli -f html -f json example.reg.com/myimage1:latest
# analyze with threshold and white list
claircli -t High -w white_list_file.yml example.reg.com/myimage1:latest
# analyze image on local host
claircli -l <local ip address> myimage1:latest myimage2:latest
# analyze image on other host foo
export DOCKER_HOST=tcp://<ip of foo>:<port of docker listen>
claircli -l <local ip address> myimage1:latest
# analyze with regular expression, following will match
# example.reg.com/myimage1:latest
# and example.reg.com/myimage2:latest
claircli -r example.reg.com/myimage:latest
subcommands:
Subcommands of claircli
# analyze with regular expression, following will match
# example.reg.com/myimage1:latest only
claircli -r example.reg.com/^myimage1$:^latest$
{batch-analyze,fuzzy-analyze}
batch-analyze Batch analyze docker images with clair
fuzzy-analyze Fuzzy analyze docker images with clair
```

## Optional whitelist yaml file
Expand Down
Empty file modified claircli/__init__.py
100755 → 100644
Empty file.
9 changes: 9 additions & 0 deletions claircli/__version__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# -*- coding: utf-8 -*-
__version__ = '1.0'
__title__ = 'claircli'
__description__ = 'Command line tool to interact with Clair'
__url__ = 'https://github.com/joelee2012/claircli'
__author__ = 'Joe Lee'
__author_email__ = '[email protected]'
__license__ = 'Apache 2.0'
__copyright__ = 'Copyright 2019 Joe Lee'
28 changes: 12 additions & 16 deletions claircli/clair.py
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@

import logging
from pprint import pformat

from .report import Report
from .utils import request_and_check, request
from .utils import request, request_and_check

logger = logging.getLogger(__name__)

Expand All @@ -13,7 +14,7 @@ class Clair(object):

def __init__(self, url):
self.url = url
self._v1_analyze_url = '{}/v1/layers'.format(url)
self.api_v1_url = '{}/v1/layers'.format(url)

def _make_layer_data(self, layer, parent, image):
data = {'Layer': {
Expand All @@ -27,27 +28,22 @@ def _make_layer_data(self, layer, parent, image):
return data

def analyze_image(self, image):
logger.info('Analyze image %s', image.name)
layers = image.layers
logger.info('Remove old analysis data for %s from clair',
image.name)
request('DELETE', '{}/{}'.format(self._v1_analyze_url, layers[0]))
layers_length = len(layers)
logger.info('Analyzing %s', image)
request('DELETE', '{}/{}'.format(self.api_v1_url, image.layers[0]))
layers_length = len(image)
parent = ''
for index, layer in enumerate(layers, start=1):
for index, layer in enumerate(image.layers, start=1):
logger.info('Push layer [%s/%s]: %s', index, layers_length, layer)
layer_data = self._make_layer_data(layer, parent, image)
parent = layer
logger.debug('Layer data: %s', pformat(layer_data))
request_and_check('POST', self._v1_analyze_url, json=layer_data)
return layers
request_and_check('POST', self.api_v1_url, json=layer_data)
return image.layers

def get_report(self, image):
logger.info('Fetch vulnerabilities for %s', image.name)
logger.info('Fetch vulnerabilities for %s', image)
report_url = '{}/{}?features&vulnerabilities'.format(
self._v1_analyze_url, image.layers[-1])
resp = request_and_check('GET', report_url)
vulnerabilities = resp.json()
self.api_v1_url, image.layers[-1])
vulnerabilities = request_and_check('GET', report_url).json()
features = vulnerabilities.get('Layer', {}).get('Features')
if features:
vulnerabilities['ImageName'] = image.name
Expand Down
Loading

0 comments on commit e7a4453

Please sign in to comment.