Skip to content

Commit 2c42e2a

Browse files
authored
Merge pull request #27 from CycloneDX/feat/add-pipenv-support
FEATURE: Add `Pipfile.lock` (pipenv) support
2 parents e68fbc2 + 2c66834 commit 2c42e2a

File tree

4 files changed

+122
-0
lines changed

4 files changed

+122
-0
lines changed

README.md

+10
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ You can use one of the parsers to obtain information about your project or envir
5050
| Parser | Class / Import | Description |
5151
| ------- | ------ | ------ |
5252
| Environment | `from cyclonedx.parser.environment import EnvironmentParser` | Looks at the packaged installed in your current Python environment. |
53+
| PipEnvParser | `from cyclonedx.parser.pipenv import PipEnvParser` | Parses `Pipfile.lock` content passed in as a string. |
54+
| PipEnvFileParser | `from cyclonedx.parser.pipenv import PipEnvFileParser` | Parses the `Pipfile.lock` file at the supplied path. |
5355
| PoetryParser | `from cyclonedx.parser.poetry import PoetryParser` | Parses `poetry.lock` content passed in as a string. |
5456
| PoetryFileParser | `from cyclonedx.parser.poetry import PoetryFileParser` | Parses the `poetry.lock` file at the supplied path. |
5557
| RequirementsParser | `from cyclonedx.parser.requirements import RequirementsParser` | Parses a multiline string that you provide that conforms to the `requirements.txt` [PEP-508](https://www.python.org/dev/peps/pep-0508/) standard. |
@@ -192,6 +194,14 @@ _Note: We refer throughout using XPath, but the same is true for both XML and JS
192194
<td>Y</td><td>Y</td><td>Y</td><td>Y</td>
193195
<td>&nbsp;</td>
194196
</tr>
197+
<tr>
198+
<td><code>./hashes</code></td>
199+
<td>Y</td><td>Y</td><td>Y</td><td>Y</td>
200+
<td>
201+
These are supported when programmatically creating a <code>Bom</code> - these will not currently be
202+
automatically populated when using a <code>Parser</code>.
203+
</td>
204+
</tr>
195205
</tbody>
196206
</table>
197207

cyclonedx/parser/pipenv.py

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# encoding: utf-8
2+
3+
# This file is part of CycloneDX Python Lib
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
#
17+
# SPDX-License-Identifier: Apache-2.0
18+
# Copyright (c) OWASP Foundation. All Rights Reserved.
19+
import json
20+
21+
from . import BaseParser
22+
from ..model.component import Component
23+
24+
25+
class PipEnvParser(BaseParser):
26+
27+
def __init__(self, pipenv_contents: str):
28+
super().__init__()
29+
pipfile_lock_contents = json.loads(pipenv_contents)
30+
31+
for package_name in pipfile_lock_contents['default'].keys():
32+
print('Processing {}'.format(package_name))
33+
package_data = pipfile_lock_contents['default'][package_name]
34+
c = Component(
35+
name=package_name, version=str(package_data['version']).strip('='),
36+
)
37+
38+
# @todo: Add hashes
39+
40+
self._components.append(c)
41+
42+
43+
class PipEnvFileParser(PipEnvParser):
44+
45+
def __init__(self, pipenv_lock_filename: str):
46+
with open(pipenv_lock_filename) as r:
47+
super(PipEnvFileParser, self).__init__(pipenv_contents=r.read())
48+
r.close()
+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"_meta": {
3+
"hash": {
4+
"sha256": "8ca3da46acf801a7780c6781bed1d6b7012664226203447640cda114b13aa8aa"
5+
},
6+
"pipfile-spec": 6,
7+
"requires": {
8+
"python_version": "3.9"
9+
},
10+
"sources": [
11+
{
12+
"name": "pypi",
13+
"url": "https://pypi.org/simple",
14+
"verify_ssl": true
15+
}
16+
]
17+
},
18+
"default": {
19+
"toml": {
20+
"hashes": [
21+
"sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b",
22+
"sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"
23+
],
24+
"index": "pypi",
25+
"version": "==0.10.2"
26+
}
27+
},
28+
"develop": {}
29+
}

tests/test_parser_pipenv.py

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# encoding: utf-8
2+
3+
# This file is part of CycloneDX Python Lib
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
#
17+
# SPDX-License-Identifier: Apache-2.0
18+
# Copyright (c) OWASP Foundation. All Rights Reserved.
19+
20+
import os
21+
from unittest import TestCase
22+
23+
from cyclonedx.parser.pipenv import PipEnvFileParser
24+
25+
26+
class TestPipEnvParser(TestCase):
27+
28+
def test_simple(self):
29+
tests_pipfile_lock = os.path.join(os.path.dirname(__file__), 'fixtures/pipfile-lock-simple.txt')
30+
31+
parser = PipEnvFileParser(pipenv_lock_filename=tests_pipfile_lock)
32+
self.assertEqual(1, parser.component_count())
33+
components = parser.get_components()
34+
self.assertEqual('toml', components[0].get_name())
35+
self.assertEqual('0.10.2', components[0].get_version())

0 commit comments

Comments
 (0)