Skip to content

Commit e7a4453

Browse files
authored
Merge subcommand (#8)
* Merge subcommand * Change documention
1 parent 3130659 commit e7a4453

25 files changed

+400
-280
lines changed

.travis.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@ python:
44
- "2.7"
55
- "3.6"
66
- "3.7"
7+
- "3.8"
78
# command to install dependencies
89
install:
9-
- pip install coveralls
10+
- pip install coveralls tox
1011
- pip install --upgrade setuptools wheel twine
11-
- pip install -r test-requirements.txt
1212
# command to run tests
1313
script:
14-
- pytest -v --cov-report term --cov=claircli tests/ --cov-report html
14+
- tox -e py,pylint,style
1515
- python setup.py sdist bdist_wheel
1616
- twine check dist/*
1717
after_success:

README.md

100755100644
Lines changed: 61 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,85 @@
11
[![Build Status](https://travis-ci.com/joelee2012/claircli.svg?branch=master)](https://travis-ci.com/joelee2012/claircli)
22
[![Coverage Status](https://coveralls.io/repos/github/joelee2012/claircli/badge.svg?branch=master)](https://coveralls.io/github/joelee2012/claircli?branch=master)
33
# claircli
4-
## claircli is a simple command line tool to interact with [CoreOS Clair](https://github.com/coreos/clair)
5-
- analyze loacl/remote docker image with [clair](https://github.com/coreos/clair)
4+
## claircli is a command line tool to interact with [CoreOS Clair](https://github.com/quay/clair)
5+
- analyze loacl/remote docker image with [Clair](https://github.com/quay/clair)
66
- 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)
77

88
# Installation
99

1010
```bash
1111
pip install claircli
12-
```
12+
```
1313

1414
# Commands
1515

1616
```
1717
claircli -h
18-
usage: claircli [-h] [-V] {batch-analyze,fuzzy-analyze} ...
18+
usage: claircli [-h] [-V] [-c CLAIR] [-w WHITE_LIST] [-T THRESHOLD]
19+
[-f {html,json}] [-L LOG_FILE] [-d] [-l LOCAL_IP | -r]
20+
images [images ...]
21+
22+
Command line tool to interact with CoreOS Clair, analyze docker image with
23+
clair in different ways
1924
20-
Simple command line tool to interact with CoreOS Clair
25+
positional arguments:
26+
images docker images or regular expression
2127
2228
optional arguments:
2329
-h, --help show this help message and exit
2430
-V, --version show program's version number and exit
31+
-c CLAIR, --clair CLAIR
32+
clair url, default: http://localhost:6060
33+
-w WHITE_LIST, --white-list WHITE_LIST
34+
path to the whitelist file
35+
-T THRESHOLD, --threshold THRESHOLD
36+
cvd severity threshold, if any servity of
37+
vulnerability above of threshold, will return non-
38+
zero, default: Unknown, choices are: ['Defcon1',
39+
'Critical', 'High', 'Medium', 'Low', 'Negligible',
40+
'Unknown']
41+
-f {html,json}, --formats {html,json}
42+
output report file with give format, default: ['html']
43+
-L LOG_FILE, --log-file LOG_FILE
44+
save log to file
45+
-d, --debug print more logs
46+
-l LOCAL_IP, --local-ip LOCAL_IP
47+
ip address of local host
48+
-r, --regex if set, repository and tag of images will be treated
49+
as regular expression
50+
51+
Examples:
52+
53+
# analyze and output report to html
54+
# clair is running at http://localhost:6060
55+
claircli example.reg.com/myimage1:latest example.reg.com/myimage2:latest
56+
57+
# analyze and output report to html
58+
# clair is running at https://example.clair.com:6060
59+
claircli -c https://example.clair.com:6060 example.reg.com/myimage1:latest
60+
61+
# analyze and output report to html, json
62+
claircli -f html -f json example.reg.com/myimage1:latest
63+
64+
# analyze with threshold and white list
65+
claircli -t High -w white_list_file.yml example.reg.com/myimage1:latest
66+
67+
# analyze image on local host
68+
claircli -l <local ip address> myimage1:latest myimage2:latest
69+
70+
# analyze image on other host foo
71+
export DOCKER_HOST=tcp://<ip of foo>:<port of docker listen>
72+
claircli -l <local ip address> myimage1:latest
73+
74+
# analyze with regular expression, following will match
75+
# example.reg.com/myimage1:latest
76+
# and example.reg.com/myimage2:latest
77+
claircli -r example.reg.com/myimage:latest
2578
26-
subcommands:
27-
Subcommands of claircli
79+
# analyze with regular expression, following will match
80+
# example.reg.com/myimage1:latest only
81+
claircli -r example.reg.com/^myimage1$:^latest$
2882
29-
{batch-analyze,fuzzy-analyze}
30-
batch-analyze Batch analyze docker images with clair
31-
fuzzy-analyze Fuzzy analyze docker images with clair
3283
```
3384

3485
## Optional whitelist yaml file

claircli/__init__.py

100755100644
File mode changed.

claircli/__version__.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# -*- coding: utf-8 -*-
2+
__version__ = '1.0'
3+
__title__ = 'claircli'
4+
__description__ = 'Command line tool to interact with Clair'
5+
__url__ = 'https://github.com/joelee2012/claircli'
6+
__author__ = 'Joe Lee'
7+
__author_email__ = '[email protected]'
8+
__license__ = 'Apache 2.0'
9+
__copyright__ = 'Copyright 2019 Joe Lee'

claircli/clair.py

100755100644
Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33

44
import logging
55
from pprint import pformat
6+
67
from .report import Report
7-
from .utils import request_and_check, request
8+
from .utils import request, request_and_check
89

910
logger = logging.getLogger(__name__)
1011

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

1415
def __init__(self, url):
1516
self.url = url
16-
self._v1_analyze_url = '{}/v1/layers'.format(url)
17+
self.api_v1_url = '{}/v1/layers'.format(url)
1718

1819
def _make_layer_data(self, layer, parent, image):
1920
data = {'Layer': {
@@ -27,27 +28,22 @@ def _make_layer_data(self, layer, parent, image):
2728
return data
2829

2930
def analyze_image(self, image):
30-
logger.info('Analyze image %s', image.name)
31-
layers = image.layers
32-
logger.info('Remove old analysis data for %s from clair',
33-
image.name)
34-
request('DELETE', '{}/{}'.format(self._v1_analyze_url, layers[0]))
35-
layers_length = len(layers)
31+
logger.info('Analyzing %s', image)
32+
request('DELETE', '{}/{}'.format(self.api_v1_url, image.layers[0]))
33+
layers_length = len(image)
3634
parent = ''
37-
for index, layer in enumerate(layers, start=1):
35+
for index, layer in enumerate(image.layers, start=1):
3836
logger.info('Push layer [%s/%s]: %s', index, layers_length, layer)
3937
layer_data = self._make_layer_data(layer, parent, image)
4038
parent = layer
41-
logger.debug('Layer data: %s', pformat(layer_data))
42-
request_and_check('POST', self._v1_analyze_url, json=layer_data)
43-
return layers
39+
request_and_check('POST', self.api_v1_url, json=layer_data)
40+
return image.layers
4441

4542
def get_report(self, image):
46-
logger.info('Fetch vulnerabilities for %s', image.name)
43+
logger.info('Fetch vulnerabilities for %s', image)
4744
report_url = '{}/{}?features&vulnerabilities'.format(
48-
self._v1_analyze_url, image.layers[-1])
49-
resp = request_and_check('GET', report_url)
50-
vulnerabilities = resp.json()
45+
self.api_v1_url, image.layers[-1])
46+
vulnerabilities = request_and_check('GET', report_url).json()
5147
features = vulnerabilities.get('Layer', {}).get('Features')
5248
if features:
5349
vulnerabilities['ImageName'] = image.name

0 commit comments

Comments
 (0)