Skip to content

Commit

Permalink
Merge pull request #70 from sonatype-nexus-community/feat/conda-support
Browse files Browse the repository at this point in the history
FEATURE: `conda` support + fixes
  • Loading branch information
madpah committed Oct 22, 2021
2 parents b1cfcb4 + 286ea27 commit 93bc03d
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 45 deletions.
79 changes: 65 additions & 14 deletions README.md
Expand Up @@ -22,9 +22,9 @@

# Jake

![GitHub Workflow Status](https://img.shields.io/github/workflow/status/sonatype-nexus-community/jake/Python%20CI)
[![CircleCI](https://circleci.com/gh/sonatype-nexus-community/jake/tree/main.svg?style=svg)](https://circleci.com/gh/sonatype-nexus-community/jake/tree/main)
![Python Version Support](https://img.shields.io/badge/python-3.6+-blue)
![PyPI Version](https://img.shields.io/pypi/v/jake?label=PyPI&logo=pypi)
[![PyPI Version](https://img.shields.io/pypi/v/jake?label=PyPI&logo=pypi)](https://pypi.org/project/jake)
[![GitHub license](https://img.shields.io/github/license/sonatype-nexus-community/jake)](https://github.com/sonatype-nexus-community/jake/blob/main/LICENSE)
[![GitHub issues](https://img.shields.io/github/issues/sonatype-nexus-community/jake)](https://github.com/sonatype-nexus-community/jake/issues)
[![GitHub forks](https://img.shields.io/github/forks/sonatype-nexus-community/jake)](https://github.com/sonatype-nexus-community/jake/network)
Expand Down Expand Up @@ -63,27 +63,78 @@ _Other Python package managers are available._

```
> jake --help
usage: jake [-h] [-v] [-X] ...
usage: jake [-h] [-v] [-w] [-X] ...
Put your Python dependencies in a chokehold
optional arguments:
-h, --help show this help message and exit
-v, --version show which version of jake you are running
-w, --warn-only prevents exit with non-zero code when issues have been
detected
-X enable debug output
-h, --help show this help message and exit
-v, --version show which version of jake you are running
-w, --warn-only prevents exit with non-zero code when issues have been
detected
-X enable debug output
Jake sub-commands:
iq perform a scan backed by Nexus Lifecycle
ddt perform a scan backed by OSS Index
sbom generate a CycloneDX software-bill-of-materials (no vulnerabilities)
iq perform a scan backed by Nexus Lifecycle
ddt perform a scan backed by OSS Index
sbom generate a CycloneDX software-bill-of-materials (no
vulnerabilities)
```

`jake` will exit with code `0` under normal operation and `1` if vulnerabilities are found (OssIndex) or Policy
Violations are detected (Nexus IQ), unless you pass the `-w` flag in which case `jake` will always exit with code `0`....

### Generating an SBOM

`jake` can take data from various inputs (or just look at your current Python environment) and produce a CycloneDX for
you.

```
> jake sbom --help
usage: jake sbom [-h] [-i FILE_PATH] [-t TYPE] [-o PATH/TO/FILE]
[--output-format {json,xml}]
[--schema-version {1.0,1.1,1.2,1.3}]
optional arguments:
-h, --help show this help message and exit
-i FILE_PATH, --input FILE_PATH
Where to get input data from. If a path to a file is
not specified directly here,then we will attempt to
read data from STDIN. If there is no data on STDIN, we
will then fall back to looking for standard files in
the current directory that relate to the type of input
indicated by the -t flag.
-t TYPE, --type TYPE, -it TYPE, --input-type TYPE
how jake should find the packages from which to
generate your SBOM.ENV = Read from the current Python
Environment; CONDA = Read output from `conda list
--explicit`; CONDA_JSON = Read output from `conda list
--json`; PIP = read from a requirements.txt; PIPENV =
read from Pipfile.lock; POETRY = read from a
poetry.lock. (Default = ENV)
-o PATH/TO/FILE, --output-file PATH/TO/FILE
Specify a file to output the SBOM to
--output-format {json,xml}
SBOM output format (default = xml)
--schema-version {1.0,1.1,1.2,1.3}
CycloneDX schema version to use (default = 1.3)
```

Check out these examples using STDIN:
```
conda list --explicit --md5 | jake sbom -t CONDA
conda list --json | jake sbom -t CONDA_JSON
cat /path/to/Pipfile.lock | python -m jake.app sbom -t PIPENV
```

Check out these examples specifying a manifest:
```
jake sbom -t PIP -i /path/to/requirements.txt
jake sbom -t PIPENV -i /path/to/Pipfile.lock
```

### Check for vulnerabilities using OSS Index

`jake` will look at the packaged installed in your current Python environment and check these against OSS Index for you.
Expand Down Expand Up @@ -129,7 +180,7 @@ So you can quickly get a report by running:
Jake Version: 1.0.0
Jake Version: 1.1.0
Put your Python dependencies in a chokehold.
🐍 Collected 42 packages from your environment (0:00:00.10)
Expand Down Expand Up @@ -189,7 +240,7 @@ So passing parameters that suit your Nexus Lifecycle environment you can get a r
Jake Version: 1.0.0
Jake Version: 1.0.1
Put your Python dependencies in a chokehold
🐍 IQ Server at https://my-nexus-lifecyle is up and accessible (0:00:00.14)
Expand Down
69 changes: 54 additions & 15 deletions jake/command/sbom.py
Expand Up @@ -15,16 +15,18 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#

import argparse
import sys

from cyclonedx.model.bom import Bom
from cyclonedx.output import BaseOutput, get_instance, OutputFormat, SchemaVersion, DEFAULT_SCHEMA_VERSION
from cyclonedx.parser import BaseParser
from cyclonedx.parser.conda import CondaListJsonParser, CondaListExplicitParser
from cyclonedx.parser.environment import EnvironmentParser
from cyclonedx.parser.pipenv import PipEnvFileParser
from cyclonedx.parser.poetry import PoetryFileParser
from cyclonedx.parser.requirements import RequirementsFileParser
from cyclonedx.parser.pipenv import PipEnvParser, PipEnvFileParser
from cyclonedx.parser.poetry import PoetryParser, PoetryFileParser
from cyclonedx.parser.requirements import RequirementsParser, RequirementsFileParser

from . import BaseCommand


Expand Down Expand Up @@ -59,13 +61,26 @@ def setup_argument_parser(self, subparsers: argparse._SubParsersAction):
help='generate a CycloneDX software-bill-of-materials (no vulnerabilities)',
)

parser.add_argument('-it', '--input-type',
parser.add_argument('-i', '--input', action='store', metavar='FILE_PATH',
type=argparse.FileType('r'), default=(None if sys.stdin.isatty() else sys.stdin),
help='Where to get input data from. If a path to a file is not specified directly here,'
'then we will attempt to read data from STDIN. If there is no data on STDIN, we will '
'then fall back to looking for standard files in the current directory that relate '
'to the type of input indicated by the -t flag.', dest='sbom_input_source',
required=False)

parser.add_argument('-t', '--type', '-it', '--input-type',
help='how jake should find the packages from which to generate your SBOM.'
'ENV = Read from the current Python Environment; PIP = read from a requirements.txt; '
'PIPENV = read from Pipfile.lock; POETRY = read from a poetry.lock. '
'ENV = Read from the current Python Environment; '
'CONDA = Read output from `conda list --explicit`; '
'CONDA_JSON = Read output from `conda list --json`; '
'PIP = read from a requirements.txt; '
'PIPENV = read from Pipfile.lock; '
'POETRY = read from a poetry.lock. '
'(Default = ENV)',
metavar='TYPE', choices={'ENV', 'PIP', 'PIPENV', 'POETRY'}, default='ENV',
dest='sbom_input_type')
metavar='TYPE', choices={'CONDA', 'CONDA_JSON', 'ENV', 'PIP', 'PIPENV', 'POETRY'},
default='ENV', dest='sbom_input_type')

parser.add_argument('-o', '--output-file', help='Specify a file to output the SBOM to', metavar='PATH/TO/FILE',
dest='sbom_output_file')
parser.add_argument('--output-format', help='SBOM output format (default = xml)', choices={'json', 'xml'},
Expand All @@ -78,13 +93,37 @@ def _get_parser(self) -> BaseParser:
if self._arguments.sbom_input_type == 'ENV':
return EnvironmentParser()

if self._arguments.sbom_input_type == 'PIP':
return RequirementsFileParser(requirements_file='requirements.txt')
# All other input types require INPUT - let's grab it now if provided via STDIN or supplied FILE
input_data_fh = self._arguments.sbom_input_source
if input_data_fh:
with input_data_fh:
input_data = input_data_fh.read()
input_data_fh.close()

if self._arguments.sbom_input_type == 'CONDA':
return CondaListExplicitParser(conda_data=input_data)

if self._arguments.sbom_input_type == 'CONDA_JSON':
return CondaListJsonParser(conda_data=input_data)

if self._arguments.sbom_input_type == 'PIP':
return RequirementsParser(requirements_content=input_data)

if self._arguments.sbom_input_type == 'PIPENV':
return PipEnvParser(pipenv_contents=input_data)

if self._arguments.sbom_input_type == 'POETRY':
return PoetryParser(poetry_lock_contents=input_data)

else:
# No data available on STDIN or the supplied FILE, so we'll try standard filenames in the current directory
if self._arguments.sbom_input_type == 'PIP':
return RequirementsFileParser(requirements_file='requirements.txt')

if self._arguments.sbom_input_type == 'PIPENV':
return PipEnvFileParser(pipenv_lock_filename='Pipfile.lock')
if self._arguments.sbom_input_type == 'PIPENV':
return PipEnvFileParser(pipenv_lock_filename='Pipfile.lock')

if self._arguments.sbom_input_type == 'POETRY':
return PoetryFileParser(poetry_lock_filename='poetry.lock')
if self._arguments.sbom_input_type == 'POETRY':
return PoetryFileParser(poetry_lock_filename='poetry.lock')

raise NotImplementedError
31 changes: 16 additions & 15 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pyproject.toml
Expand Up @@ -50,7 +50,7 @@ tinydb = "^4.5.1"
PyYAML = "^5.4.1"
requests = "^2.26.0"
terminaltables = "^3.1.0"
cyclonedx-python-lib = "^0.8.0"
cyclonedx-python-lib = "^0.10.2"
polling2 = "^0.5.0"
ossindex-lib = "^0.2.1"

Expand Down

0 comments on commit 93bc03d

Please sign in to comment.