|
64 | 64 | GITLAB_SCHEME_BY_PURL_TYPE = {v: k for k, v in PURL_TYPE_BY_GITLAB_SCHEME.items()} |
65 | 65 |
|
66 | 66 |
|
67 | | -def fork_and_get_dir(url): |
68 | | - """ |
69 | | - Fetch a clone of the gitlab repository at url and return the directory destination |
70 | | - """ |
71 | | - return fetch_via_vcs(url).dest_dir |
72 | | - |
73 | | - |
74 | 67 | class GitLabAPIImporter(GitImporter): |
75 | 68 | spdx_license_expression = "MIT" |
76 | 69 | license_url = "https://gitlab.com/gitlab-org/advisories-community/-/blob/main/LICENSE" |
77 | 70 |
|
78 | 71 | def __init__(self): |
79 | 72 | super().__init__(repo_url="git+https://gitlab.com/gitlab-org/advisories-community/") |
80 | 73 |
|
81 | | - def advisory_data(self) -> Iterable[AdvisoryData]: |
| 74 | + def advisory_data(self, _keep_clone=True) -> Iterable[AdvisoryData]: |
82 | 75 | try: |
83 | 76 | self.clone() |
84 | | - path = Path(self.vcs_response.dest_dir) |
85 | | - |
86 | | - glob = "**/*.yml" |
87 | | - files = (p for p in path.glob(glob) if p.is_file()) |
88 | | - for file in files: |
89 | | - # split a path according to gitlab conventions where package type and name are a part of path |
90 | | - # For example with this path: |
91 | | - # /tmp/tmpi1klhpmd/pypi/gradio/CVE-2021-43831.yml |
92 | | - # the package type is pypi and the package name is gradio |
93 | | - # to ('/', 'tmp', 'tmpi1klhpmd', 'pypi', 'gradio', 'CVE-2021-43831.yml') |
94 | | - purl_type = get_gitlab_package_type(path=file) |
95 | | - if not purl_type: |
96 | | - logger.error(f"Unknow gitlab directory structure {file!r}") |
97 | | - continue |
| 77 | + base_path = Path(self.vcs_response.dest_dir) |
| 78 | + |
| 79 | + for file_path in base_path.glob("**/*.yml"): |
| 80 | + gitlab_type, package_slug, vuln_id = parse_advisory_path( |
| 81 | + base_path=base_path, |
| 82 | + file_path=file_path, |
| 83 | + ) |
98 | 84 |
|
99 | | - if purl_type in PURL_TYPE_BY_GITLAB_SCHEME: |
100 | | - yield parse_gitlab_advisory(file) |
| 85 | + if gitlab_type in PURL_TYPE_BY_GITLAB_SCHEME: |
| 86 | + yield parse_gitlab_advisory(file_path) |
101 | 87 |
|
102 | 88 | else: |
103 | | - logger.error(f"Unknow package type {purl_type!r}") |
| 89 | + logger.error(f"Unknow package type {gitlab_type!r} in {file_path!r}") |
104 | 90 | continue |
105 | 91 | finally: |
106 | | - if self.vcs_response: |
| 92 | + if self.vcs_response and not _keep_clone: |
107 | 93 | self.vcs_response.delete() |
108 | 94 |
|
109 | 95 |
|
110 | | -def get_gitlab_package_type(path: Path): |
| 96 | +def parse_advisory_path(base_path: Path, file_path: Path) -> Optional[AdvisoryData]: |
111 | 97 | """ |
112 | | - Return a package type extracted from a gitlab advisory path or None |
113 | | - """ |
114 | | - parts = path.parts[-3:] |
| 98 | + Parse a gitlab advisory file and return a 3-tuple of: |
| 99 | + (gitlab_type, package_slug, vulnerability_id) |
115 | 100 |
|
116 | | - if len(parts) < 3: |
117 | | - return |
| 101 | + For example:: |
| 102 | +
|
| 103 | + >>> base_path = Path("/tmp/tmpi1klhpmd/checkout") |
| 104 | + >>> file_path=Path("/tmp/tmpi1klhpmd/checkout/pypi/gradio/CVE-2021-43831.yml") |
| 105 | + >>> parse_advisory_path(base_path=base_path, file_path=file_path) |
| 106 | + ('pypi', 'gradio', 'CVE-2021-43831') |
| 107 | +
|
| 108 | + >>> file_path=Path("/tmp/tmpi1klhpmd/checkout/nuget/github.com/beego/beego/v2/nuget/CVE-2021-43831.yml") |
| 109 | + >>> parse_advisory_path(base_path=base_path, file_path=file_path) |
| 110 | + ('nuget', 'github.com/beego/beego/v2/nuget', 'CVE-2021-43831') |
| 111 | +
|
| 112 | + >>> file_path = Path("/tmp/tmpi1klhpmd/checkout/npm/@express/beego/beego/v2/CVE-2021-43831.yml") |
| 113 | + >>> parse_advisory_path(base_path=base_path, file_path=file_path) |
| 114 | + ('npm', '@express/beego/beego/v2', 'CVE-2021-43831') |
| 115 | + """ |
| 116 | + relative_path_segments = str(file_path.relative_to(base_path)).strip("/").split("/") |
| 117 | + gitlab_type = relative_path_segments[0] |
| 118 | + vuln_id = relative_path_segments[-1].replace(".yml", "") |
| 119 | + package_slug = "/".join(relative_path_segments[1:-1]) |
118 | 120 |
|
119 | | - type, _name, _vid = parts |
120 | | - return type |
| 121 | + return gitlab_type, package_slug, vuln_id |
121 | 122 |
|
122 | 123 |
|
123 | 124 | def get_purl(package_slug): |
|
0 commit comments