-
-
Notifications
You must be signed in to change notification settings - Fork 67
Expand file tree
/
Copy pathutils.py
More file actions
92 lines (76 loc) · 3.19 KB
/
Copy pathutils.py
File metadata and controls
92 lines (76 loc) · 3.19 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# This file is part of CycloneDX Python Library
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) OWASP Foundation. All Rights Reserved.
"""Bom related utilities"""
__all__ = ['BomRefDiscriminator']
from collections.abc import Iterable
from itertools import chain
from random import random
from typing import TYPE_CHECKING, Any
if TYPE_CHECKING: # pragma: no cover
from ...model.bom import Bom
from ...model.bom_ref import BomRef
class BomRefDiscriminator:
"""
Ensure that a collection of BomRef objects has unique, non‑empty values.
The discriminator inspects the provided BomRef instances and assigns new,
automatically generated identifiers to any BomRef whose value is missing
or duplicates another. Original values are preserved so they can be
restored later via `reset()` or by using this class as a context manager.
"""
def __init__(self, bomrefs: Iterable['BomRef'], prefix: str = 'BomRef') -> None:
# do not use dict/set here, different BomRefs with same value have same hash and would shadow each other
self._bomrefs = tuple((bomref, bomref.value) for bomref in bomrefs)
self._prefix = prefix
def __enter__(self) -> None:
self.discriminate()
def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
self.reset()
def discriminate(self) -> None:
"""
Enforce uniqueness across all BomRef values.
Any BomRef whose value is `None` or duplicates a previously encountered
value is assigned a newly generated unique identifier.
"""
known_values = []
for bomref, _ in self._bomrefs:
value = bomref.value
if value is None or value in known_values:
value = self._make_unique()
bomref.value = value
known_values.append(value)
def reset(self) -> None:
"""
Restore all BomRef values to their original state.
"""
for bomref, original_value in self._bomrefs:
bomref.value = original_value
def _make_unique(self) -> str:
return f'{self._prefix}{str(random())[1:]}{str(random())[1:]}' # nosec B311
@classmethod
def from_bom(cls, bom: 'Bom', prefix: str = 'BomRef') -> 'BomRefDiscriminator':
"""
Create a discriminator for all BomRefs contained within a BOM.
This includes BomRefs from
- components
- services
- vulnerabilities
"""
return cls(chain(
map(lambda c: c.bom_ref, bom._get_all_components()),
map(lambda s: s.bom_ref, bom.services),
map(lambda v: v.bom_ref, bom.vulnerabilities)
), prefix)