/
PoetryAnalyzer.java
188 lines (167 loc) · 6.38 KB
/
PoetryAnalyzer.java
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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
/*
* This file is part of dependency-check-core.
*
* 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.
*
* Copyright (c) 2019 Nima Yahyazadeh. All Rights Reserved.
*/
package org.owasp.dependencycheck.analyzer;
import com.github.packageurl.MalformedPackageURLException;
import com.github.packageurl.PackageURL;
import com.github.packageurl.PackageURLBuilder;
import java.io.FileFilter;
import java.util.List;
import javax.annotation.concurrent.ThreadSafe;
import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
import org.owasp.dependencycheck.dependency.Confidence;
import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.dependency.EvidenceType;
import org.owasp.dependencycheck.exception.InitializationException;
import org.owasp.dependencycheck.utils.FileFilterBuilder;
import org.owasp.dependencycheck.utils.Settings;
import com.moandjiezana.toml.Toml;
import org.apache.commons.lang3.StringUtils;
import org.owasp.dependencycheck.data.nvd.ecosystem.Ecosystem;
import org.owasp.dependencycheck.dependency.naming.GenericIdentifier;
import org.owasp.dependencycheck.dependency.naming.Identifier;
import org.owasp.dependencycheck.dependency.naming.PurlIdentifier;
import org.owasp.dependencycheck.utils.Checksum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Poetry dependency analyzer.
*
* @author Ferdinand Niedermann
* @author Jeremy Long
*/
@ThreadSafe
@Experimental
public class PoetryAnalyzer extends AbstractFileTypeAnalyzer {
/**
* The logger.
*/
private static final Logger LOGGER = LoggerFactory.getLogger(PoetryAnalyzer.class);
/**
* A descriptor for the type of dependencies processed or added by this
* analyzer.
*/
public static final String DEPENDENCY_ECOSYSTEM = Ecosystem.PYTHON;
/**
* Lock file name.
*/
private static final String POETRY_LOCK = "poetry.lock";
/**
* The file filter for poetry.lock
*/
private static final FileFilter POETRY_LOCK_FILTER = FileFilterBuilder.newInstance()
.addFilenames(POETRY_LOCK)
.build();
/**
* Returns the name of the Poetry Analyzer.
*
* @return the name of the analyzer
*/
@Override
public String getName() {
return "Poetry Analyzer";
}
/**
* Tell that we are used for information collection.
*
* @return INFORMATION_COLLECTION
*/
@Override
public AnalysisPhase getAnalysisPhase() {
return AnalysisPhase.INFORMATION_COLLECTION;
}
/**
* Returns the key name for the analyzers enabled setting.
*
* @return the key name for the analyzers enabled setting
*/
@Override
protected String getAnalyzerEnabledSettingKey() {
return Settings.KEYS.ANALYZER_POETRY_ENABLED;
}
/**
* Returns the FileFilter
*
* @return the FileFilter
*/
@Override
protected FileFilter getFileFilter() {
return POETRY_LOCK_FILTER;
}
/**
* No-op initializer implementation.
*
* @param engine a reference to the dependency-check engine
*
* @throws InitializationException never thrown
*/
@Override
protected void prepareFileTypeAnalyzer(Engine engine) throws InitializationException {
// Nothing to do here.
}
/**
* Analyzes poetry packages and adds evidence to the dependency.
*
* @param dependency the dependency being analyzed
* @param engine the engine being used to perform the scan
*
* @throws AnalysisException thrown if there is an unrecoverable error
* analyzing the dependency
*/
@Override
protected void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
LOGGER.debug("Checking file {}", dependency.getActualFilePath());
//do not report on the build file itself
engine.removeDependency(dependency);
final Toml result = new Toml().read(dependency.getActualFile());
final List<Toml> projectsLocks = result.getTables("package");
if (projectsLocks == null) {
return;
}
projectsLocks.forEach((project) -> {
final String name = project.getString("name");
final String version = project.getString("version");
LOGGER.debug(String.format("package, version: %s %s", name, version));
final Dependency d = new Dependency(dependency.getActualFile(), true);
d.setName(name);
d.setVersion(version);
try {
final PackageURL purl = PackageURLBuilder.aPackageURL()
.withType("pypi")
.withName(name)
.withVersion(version)
.build();
d.addSoftwareIdentifier(new PurlIdentifier(purl, Confidence.HIGHEST));
} catch (MalformedPackageURLException ex) {
LOGGER.debug("Unable to build package url for pypi", ex);
d.addSoftwareIdentifier(new GenericIdentifier("pypi:" + name + "@" + version, Confidence.HIGH));
}
d.setPackagePath(String.format("%s:%s", name, version));
d.setEcosystem(PythonDistributionAnalyzer.DEPENDENCY_ECOSYSTEM);
final String filePath = String.format("%s:%s/%s", dependency.getFilePath(), name, version);
d.setFilePath(filePath);
d.setSha1sum(Checksum.getSHA1Checksum(filePath));
d.setSha256sum(Checksum.getSHA256Checksum(filePath));
d.setMd5sum(Checksum.getMD5Checksum(filePath));
d.addEvidence(EvidenceType.PRODUCT, POETRY_LOCK, "product", name, Confidence.HIGHEST);
d.addEvidence(EvidenceType.VERSION, POETRY_LOCK, "version", version, Confidence.HIGHEST);
d.addEvidence(EvidenceType.VENDOR, POETRY_LOCK, "vendor", name, Confidence.HIGHEST);
engine.addDependency(d);
});
}
}