Skip to content

Commit

Permalink
feat:SP-1846 Adds sbom-format flag to inspect undeclared command
Browse files Browse the repository at this point in the history
* feat:SP-1846 Adds sbom-format flag to inspect undeclared command
  • Loading branch information
agustingroh authored Nov 15, 2024
1 parent 1512dc6 commit 43f3a76
Show file tree
Hide file tree
Showing 7 changed files with 149 additions and 18 deletions.
8 changes: 5 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed
- Fixed post processor being accesed if not set
### Added
- Add support for replace action when specifying a settings file
- Add replaced files as context to scan request
- Added support for replace action when specifying a settings file
- Added replaced files as context to scan request
- Added sbom format flag to define status output for undeclared policy

## [1.17.5] - 2024-11-12
### Fixed
Expand Down Expand Up @@ -401,4 +402,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
[1.17.2]: https://github.com/scanoss/scanoss.py/compare/v1.17.1...v1.17.2
[1.17.3]: https://github.com/scanoss/scanoss.py/compare/v1.17.2...v1.17.3
[1.17.4]: https://github.com/scanoss/scanoss.py/compare/v1.17.3...v1.17.4
[1.17.5]: https://github.com/scanoss/scanoss.py/compare/v1.17.4...v1.17.5
[1.17.5]: https://github.com/scanoss/scanoss.py/compare/v1.17.4...v1.17.5
[1.18.0]: https://github.com/scanoss/scanoss.py/compare/v1.17.5...v1.18.0
7 changes: 7 additions & 0 deletions CLIENT_HELP.md
Original file line number Diff line number Diff line change
Expand Up @@ -374,4 +374,11 @@ scanoss-py insp undeclared -i scan-results.json --status undeclared-status.md --
The following command can be used to inspect for undeclared components and save the results in Markdown format.
```bash
scanoss-py insp undeclared -i scan-results.json --status undeclared-status.md --output undeclared.json --format md
```

#### Inspect for undeclared components and save results in Markdown format and show status output as sbom.json (legacy)
The following command can be used to inspect for undeclared components and save the results in Markdown format.
Default sbom-format 'settings'
```bash
scanoss-py insp undeclared -i scan-results.json --status undeclared-status.md --output undeclared.json --format md --sbom-format legacy
```
4 changes: 3 additions & 1 deletion src/scanoss/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,8 @@ def setup_args() -> None:

# Inspect Sub-command: inspect undeclared
p_undeclared = p_inspect_sub.add_parser('undeclared', aliases=['un'],description="Inspect for undeclared components", help='Inspect for undeclared components')
p_undeclared.add_argument('--sbom-format',required=False ,choices=['legacy', 'settings'],
default="settings",help='Sbom format for status output')
p_undeclared.set_defaults(func=inspect_undeclared)

for p in [p_copyleft, p_undeclared]:
Expand Down Expand Up @@ -858,7 +860,7 @@ def inspect_undeclared(parser, args):
open(status_output, 'w').close()
i_undeclared = UndeclaredComponent(debug=args.debug, trace=args.trace, quiet=args.quiet,
filepath=args.input, format_type=args.format,
status=status_output, output=output)
status=status_output, output=output, sbom_format=args.sbom_format)
status, _ = i_undeclared.run()
sys.exit(status)

Expand Down
52 changes: 41 additions & 11 deletions src/scanoss/inspection/undeclared_component.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class UndeclaredComponent(PolicyCheck):
"""

def __init__(self, debug: bool = False, trace: bool = True, quiet: bool = False, filepath: str = None,
format_type: str = 'json', status: str = None, output: str = None):
format_type: str = 'json', status: str = None, output: str = None, sbom_format: str = 'settings'):
"""
Initialize the UndeclaredComponent class.
Expand All @@ -43,13 +43,15 @@ def __init__(self, debug: bool = False, trace: bool = True, quiet: bool = False,
:param format_type: Output format ('json' or 'md')
:param status: Path to save status output
:param output: Path to save detailed output
:param sbom_format: Sbom format for status output (default 'settings')
"""
super().__init__(debug, trace, quiet, filepath, format_type, status, output,
name='Undeclared Components Policy')
self.filepath = filepath
self.format = format
self.output = output
self.status = status
self.sbom_format = sbom_format

def _get_undeclared_component(self, components: list)-> list or None:
"""
Expand All @@ -59,7 +61,7 @@ def _get_undeclared_component(self, components: list)-> list or None:
:return: List of undeclared components
"""
if components is None:
self.print_stderr(f'WARNING: No components provided!')
self.print_debug(f'WARNING: No components provided!')
return None
undeclared_components = []
for component in components:
Expand All @@ -78,9 +80,14 @@ def _get_summary(self, components: list) -> str:
"""
summary = f'{len(components)} undeclared component(s) were found.\n'
if len(components) > 0:
if self.sbom_format == 'settings':
summary += (f'Add the following snippet into your `scanoss.json` file\n'
f'\n```json\n{json.dumps(self._generate_scanoss_file(components), indent=2)}\n```\n')
return summary

summary += (f'Add the following snippet into your `sbom.json` file\n'
f'\n```json\n{json.dumps(self._generate_sbom_file(components), indent=2)}\n```\n')
return summary
return summary

def _json(self, components: list) -> Dict[str, Any]:
"""
Expand Down Expand Up @@ -115,23 +122,46 @@ def _markdown(self, components: list) -> Dict[str,Any]:
'summary': self._get_summary(components),
}

def _generate_sbom_file(self, components: list) -> dict:
def _get_unique_components(self, components: list) -> list:
"""
Generate a list of PURLs for the SBOM file.
Generate a list of unique components.
:param components: List of undeclared components
:return: SBOM Dictionary with components
:return: list of unique components
"""

unique_components = {}
if components is None:
self.print_stderr(f'WARNING: No components provided!')
else:
for component in components:
unique_components[component['purl']] = { 'purl': component['purl'] }
return []

for component in components:
unique_components[component['purl']] = {'purl': component['purl']}
return list(unique_components.values())

def _generate_scanoss_file(self, components: list) -> dict:
"""
Generate a list of PURLs for the scanoss.json file.
:param components: List of undeclared components
:return: scanoss.json Dictionary
"""
scanoss_settings = {
'bom':{
'include': self._get_unique_components(components),
}
}

return scanoss_settings

def _generate_sbom_file(self, components: list) -> dict:
"""
Generate a list of PURLs for the SBOM file.
:param components: List of undeclared components
:return: SBOM Dictionary with components
"""
sbom = {
'components': list(unique_components.values())
'components': self._get_unique_components(components),
}

return sbom
Expand Down
File renamed without changes.
96 changes: 93 additions & 3 deletions tests/test_policy-inspect.py → tests/test_policy_inspect.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ def test_undeclared_policy(self):
script_dir = os.path.dirname(os.path.abspath(__file__))
file_name = "result.json"
input_file_name = os.path.join(script_dir,'data', file_name)
undeclared = UndeclaredComponent(filepath=input_file_name, format_type='json')
undeclared = UndeclaredComponent(filepath=input_file_name, format_type='json', sbom_format='legacy')
status, results = undeclared.run()
details = json.loads(results['details'])
summary = results['summary']
Expand Down Expand Up @@ -201,7 +201,7 @@ def test_undeclared_policy_markdown(self):
script_dir = os.path.dirname(os.path.abspath(__file__))
file_name = "result.json"
input_file_name = os.path.join(script_dir, 'data', file_name)
undeclared = UndeclaredComponent(filepath=input_file_name, format_type='md')
undeclared = UndeclaredComponent(filepath=input_file_name, format_type='md', sbom_format='legacy')
status, results = undeclared.run()
details = results['details']
summary = results['summary']
Expand Down Expand Up @@ -241,6 +241,96 @@ def test_undeclared_policy_markdown(self):
'', expected_details_output))
self.assertEqual(re.sub(r'\s|\\(?!`)|\\(?=`)', '', summary),
re.sub(r'\s|\\(?!`)|\\(?=`)', '', expected_summary_output))


"""
Undeclared component markdown scanoss summary output
"""
def test_undeclared_policy_markdown_scanoss_summary(self):
script_dir = os.path.dirname(os.path.abspath(__file__))
file_name = "result.json"
input_file_name = os.path.join(script_dir, 'data', file_name)
undeclared = UndeclaredComponent(filepath=input_file_name, format_type='md')
status, results = undeclared.run()
details = results['details']
summary = results['summary']
expected_details_output = """ ### Undeclared components
| Component | Version | License |
| - | - | - |
| pkg:github/scanoss/scanner.c | 1.3.3 | BSD-2-Clause - GPL-2.0-only |
| pkg:github/scanoss/scanner.c | 1.1.4 | GPL-2.0-only |
| pkg:github/scanoss/wfp | 6afc1f6 | Zlib - GPL-2.0-only |
| pkg:npm/%40electron/rebuild | 3.7.0 | MIT |
| pkg:npm/%40emotion/react | 11.13.3 | MIT | """

expected_summary_output = """5 undeclared component(s) were found.
Add the following snippet into your `scanoss.json` file
```json
{
"bom": {
"include": [
{
"purl": "pkg:github/scanoss/scanner.c"
},
{
"purl": "pkg:github/scanoss/wfp"
},
{
"purl": "pkg:npm/%40electron/rebuild"
},
{
"purl": "pkg:npm/%40emotion/react"
}
]
}
}
```"""

print(summary)
self.assertEqual(status, 0)
self.assertEqual(re.sub(r'\s|\\(?!`)|\\(?=`)', '', details), re.sub(r'\s|\\(?!`)|\\(?=`)',
'', expected_details_output))
self.assertEqual(re.sub(r'\s|\\(?!`)|\\(?=`)', '', summary),
re.sub(r'\s|\\(?!`)|\\(?=`)', '', expected_summary_output))

"""
Undeclared component sbom summary output
"""
def test_undeclared_policy_scanoss_summary(self):
script_dir = os.path.dirname(os.path.abspath(__file__))
file_name = "result.json"
input_file_name = os.path.join(script_dir, 'data', file_name)
undeclared = UndeclaredComponent(filepath=input_file_name)
status, results = undeclared.run()
details = json.loads(results['details'])
summary = results['summary']
expected_summary_output = """5 undeclared component(s) were found.
Add the following snippet into your `scanoss.json` file
```json
{
"bom": {
"include": [
{
"purl": "pkg:github/scanoss/scanner.c"
},
{
"purl": "pkg:github/scanoss/wfp"
},
{
"purl": "pkg:npm/%40electron/rebuild"
},
{
"purl": "pkg:npm/%40emotion/react"
}
]
}
}
```"""
self.assertEqual(status, 0)
self.assertEqual(len(details['components']), 5)
self.assertEqual(re.sub(r'\s|\\(?!`)|\\(?=`)', '', summary),
re.sub(r'\s|\\(?!`)|\\(?=`)', '', expected_summary_output))

if __name__ == '__main__':
unittest.main()
File renamed without changes.

0 comments on commit 43f3a76

Please sign in to comment.