Skip to content

Commit 7b3897b

Browse files
Add SCANOSS settings skip support
* bug:ES-199 Keeps lines on results on replace rule * chore:ES-200 Adds local profile on pom.xml file * chore:SP-2071 Add skip support * bug:SP-2070 Throws error on scanner failure * chore: SP-2072 add Skip class on Settings * chore:SP-2077 Adds documentation to filters package * chore SP-2074: Add test with GitIgnore & AntPattern * chore:SP-2078 Downgrade JGit version to v6.10.0 * chore:SP-2079 Renames Settings class to ScanossSettings * chore:SP-2103 Avoids repeated lowercase conversion of filenames in filter * chore:SP-2108 Updates CHANGELOG.md --------- Co-authored-by: Agustin Groh <[email protected]>
1 parent 3b8a121 commit 7b3897b

25 files changed

+4655
-124
lines changed

CHANGELOG.md

+6-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111

1212
- Upcoming changes...
1313

14+
## [0.10.0] - 2025-02-17
15+
### Added
16+
- Add support to skip rule
17+
- Improve file filtering
1418

1519
## [0.9.0] - 2025-02-03
1620
### Added
@@ -104,4 +108,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
104108
[0.7.1]: https://github.com/scanoss/scanoss.java/compare/v0.7.0...v0.7.1
105109
[0.8.0]: https://github.com/scanoss/scanoss.java/compare/v0.7.1...v0.8.0
106110
[0.8.1]: https://github.com/scanoss/scanoss.java/compare/v0.8.0...v0.8.1
107-
[0.9.0]: https://github.com/scanoss/scanoss.java/compare/v0.8.1...v0.9.0
111+
[0.9.0]: https://github.com/scanoss/scanoss.java/compare/v0.8.1...v0.9.0
112+
[0.10.0]: https://github.com/scanoss/scanoss.java/compare/v0.9.0...v0.10.0

pom.xml

+40-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>com.scanoss</groupId>
88
<artifactId>scanoss</artifactId>
9-
<version>0.9.0</version>
9+
<version>0.10.0</version>
1010
<packaging>jar</packaging>
1111
<name>scanoss.java</name>
1212
<url>https://github.com/scanoss/scanoss.java</url>
@@ -114,7 +114,19 @@
114114
<optional>true</optional>
115115
<scope>compile</scope>
116116
</dependency>
117+
<dependency>
118+
<groupId>org.eclipse.jgit</groupId>
119+
<artifactId>org.eclipse.jgit</artifactId>
120+
<version>6.10.0.202406032230-r</version>
121+
<scope>compile</scope>
122+
</dependency>
123+
<dependency>
124+
<groupId>org.apache.ant</groupId>
125+
<artifactId>ant</artifactId>
126+
<version>1.10.15</version>
127+
<scope>compile</scope>
117128

129+
</dependency>
118130

119131
<!-- Test dependencies -->
120132
<dependency>
@@ -301,5 +313,32 @@
301313
</plugins>
302314
</build>
303315
</profile>
316+
<profile>
317+
<id>local</id>
318+
<distributionManagement>
319+
<repository>
320+
<id>local-repo</id>
321+
<name>Local Repository</name>
322+
<url>file://${user.home}/.m2/repository</url>
323+
</repository>
324+
</distributionManagement>
325+
<build>
326+
<plugins>
327+
<plugin>
328+
<groupId>org.apache.maven.plugins</groupId>
329+
<artifactId>maven-install-plugin</artifactId>
330+
<version>${native.maven.plugin.version}</version>
331+
<configuration>
332+
<skip>false</skip>
333+
</configuration>
334+
</plugin>
335+
</plugins>
336+
</build>
337+
<properties>
338+
<gpg.skip>true</gpg.skip>
339+
<maven.javadoc.skip>true</maven.javadoc.skip>
340+
<maven.source.skip>true</maven.source.skip>
341+
</properties>
342+
</profile>
304343
</profiles>
305344
</project>

src/main/java/com/scanoss/Scanner.java

+66-94
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,14 @@
2525
import com.scanoss.dto.ScanFileResult;
2626
import com.scanoss.exceptions.ScannerException;
2727
import com.scanoss.exceptions.WinnowingException;
28-
import com.scanoss.processor.FileProcessor;
29-
import com.scanoss.processor.ScanFileProcessor;
30-
import com.scanoss.processor.WfpFileProcessor;
28+
import com.scanoss.filters.FilterConfig;
29+
import com.scanoss.filters.factories.FileFilterFactory;
30+
import com.scanoss.filters.factories.FolderFilterFactory;
31+
import com.scanoss.processor.*;
3132
import com.scanoss.rest.ScanApi;
32-
import com.scanoss.settings.Settings;
33+
import com.scanoss.settings.ScanossSettings;
3334
import com.scanoss.utils.JsonUtils;
34-
import lombok.Builder;
35-
import lombok.Getter;
36-
import lombok.NonNull;
35+
import lombok.*;
3736
import lombok.extern.slf4j.Slf4j;
3837

3938
import java.io.File;
@@ -49,6 +48,7 @@
4948
import java.util.concurrent.ExecutorService;
5049
import java.util.concurrent.Executors;
5150
import java.util.concurrent.Future;
51+
import java.util.function.Predicate;
5252

5353
import static com.scanoss.ScanossConstants.*;
5454

@@ -64,36 +64,59 @@
6464
public class Scanner {
6565
@Builder.Default
6666
private Boolean skipSnippets = Boolean.FALSE; // Skip snippet generations
67+
6768
@Builder.Default
6869
private Boolean allExtensions = Boolean.FALSE; // Fingerprint all file extensions
70+
6971
@Builder.Default
7072
private Boolean obfuscate = Boolean.FALSE; // Obfuscate file path
73+
7174
@Builder.Default
7275
private Boolean hpsm = Boolean.FALSE; // Enable High Precision Snippet Matching data collection
76+
7377
@Builder.Default
7478
private Boolean hiddenFilesFolders = Boolean.FALSE; // Enable Scanning of hidden files/folders
79+
7580
@Builder.Default
7681
private Boolean allFolders = Boolean.FALSE; // Enable Scanning of all folders (except hidden)
82+
7783
@Builder.Default
7884
private Integer numThreads = DEFAULT_WORKER_THREADS; // Number of parallel threads to use when processing a folder
85+
7986
@Builder.Default
8087
private Duration timeout = Duration.ofSeconds(DEFAULT_TIMEOUT); // API POST timeout
88+
8189
@Builder.Default
8290
private Integer retryLimit = DEFAULT_HTTP_RETRY_LIMIT; // Retry limit for posting scan requests
83-
private String url; // Alternative scanning URL
84-
private String apiKey; // API key
85-
private String scanFlags; // Scan flags to pass to the API
86-
private String sbomType; // SBOM type (identify/ignore)
87-
private String sbom; // SBOM to supply while scanning
88-
private int snippetLimit; // Size limit for a single line of generated snippet
89-
private String customCert; // Custom certificate
90-
private Proxy proxy; // Proxy
91-
private Winnowing winnowing;
92-
private ScanApi scanApi;
93-
private ScanFileProcessor scanFileProcessor;
94-
private WfpFileProcessor wfpFileProcessor;
95-
private Settings settings;
96-
private ScannerPostProcessor postProcessor;
91+
92+
private final String url; // Alternative scanning URL
93+
private final String apiKey; // API key
94+
private final String scanFlags; // Scan flags to pass to the APIç
95+
private final String sbomType; // SBOM type (identify/ignore)
96+
private final String sbom; // SBOM to supply while scanning
97+
private final int snippetLimit; // Size limit for a single line of generated snippet
98+
private final String customCert; // Custom certificate
99+
private final Proxy proxy; // Proxy
100+
private final Winnowing winnowing;
101+
private final ScanApi scanApi;
102+
private final ScanFileProcessor scanFileProcessor;
103+
private final WfpFileProcessor wfpFileProcessor;
104+
private final ScanossSettings settings;
105+
private final ScannerPostProcessor postProcessor;
106+
private final FilterConfig filterConfig;
107+
private Predicate<Path> fileFilter;
108+
private Predicate<Path> folderFilter;
109+
110+
//TODO: Once this Lombok PR is merged https://github.com/projectlombok/lombok/pull/3723#pullrequestreview-2617412643
111+
// Update Lombok dependency
112+
public static class ScannerBuilder {
113+
private ScannerBuilder folderFilter(Predicate<Path> folderFilter) {
114+
return this;
115+
}
116+
private ScannerBuilder fileFilter(Predicate<Path> fileFilter) {
117+
return this;
118+
}
119+
}
97120

98121
@SuppressWarnings("unused")
99122
private Scanner(Boolean skipSnippets, Boolean allExtensions, Boolean obfuscate, Boolean hpsm,
@@ -102,7 +125,9 @@ private Scanner(Boolean skipSnippets, Boolean allExtensions, Boolean obfuscate,
102125
Integer snippetLimit, String customCert, Proxy proxy,
103126
Winnowing winnowing, ScanApi scanApi,
104127
ScanFileProcessor scanFileProcessor, WfpFileProcessor wfpFileProcessor,
105-
Settings settings, ScannerPostProcessor postProcessor
128+
ScanossSettings settings, ScannerPostProcessor postProcessor, FilterConfig filterConfig,
129+
Predicate<Path> fileFilter,
130+
Predicate<Path> folderFilter
106131
) {
107132
this.skipSnippets = skipSnippets;
108133
this.allExtensions = allExtensions;
@@ -134,9 +159,20 @@ private Scanner(Boolean skipSnippets, Boolean allExtensions, Boolean obfuscate,
134159
this.wfpFileProcessor = Objects.requireNonNullElseGet(wfpFileProcessor, () -> WfpFileProcessor.builder()
135160
.winnowing(this.winnowing)
136161
.build());
137-
this.settings = Objects.requireNonNullElseGet(settings, () -> Settings.builder().build());
162+
this.settings = Objects.requireNonNullElseGet(settings, () -> ScanossSettings.builder().build());
138163
this.postProcessor = Objects.requireNonNullElseGet(postProcessor, () ->
139-
ScannerPostProcessor.builder().build()); }
164+
ScannerPostProcessor.builder().build());
165+
166+
this.filterConfig = Objects.requireNonNullElseGet(filterConfig, () -> FilterConfig.builder()
167+
.allFolders(allFolders)
168+
.allExtensions(allExtensions)
169+
.hiddenFilesFolders(hiddenFilesFolders)
170+
.gitIgnorePatterns(this.settings.getScanningIgnorePattern())
171+
.build());
172+
173+
this.fileFilter = Objects.requireNonNullElseGet(fileFilter , () -> FileFilterFactory.build(this.filterConfig));
174+
this.folderFilter = Objects.requireNonNullElseGet(folderFilter, () -> FolderFilterFactory.build(this.filterConfig));
175+
}
140176

141177
/**
142178
* Generate a WFP/Fingerprint for the given file
@@ -157,70 +193,6 @@ public String wfpFile(@NonNull String filename) throws ScannerException, Winnowi
157193
return this.winnowing.wfpForFile(filename, filename);
158194
}
159195

160-
/**
161-
* Determine if a folder should be processed or not
162-
*
163-
* @param name folder/directory to review
164-
* @return <code>true</code> if the folder should be skipped, <code>false</code> otherwise
165-
*/
166-
private Boolean filterFolder(String name) {
167-
String nameLower = name.toLowerCase();
168-
if (!hiddenFilesFolders && name.startsWith(".") && !name.equals(".")) {
169-
log.trace("Skipping hidden folder: {}", name);
170-
return true;
171-
}
172-
boolean ignore = false;
173-
if (!allFolders) { // skip this check if all folders is selected
174-
for (String ending : ScanossConstants.FILTERED_DIRS) {
175-
if (nameLower.endsWith(ending)) {
176-
log.trace("Skipping folder due to ending: {} - {}", name, ending);
177-
ignore = true;
178-
}
179-
}
180-
if(!ignore){
181-
for (String ending : ScanossConstants.FILTERED_DIR_EXT) {
182-
if (nameLower.endsWith(ending)) {
183-
log.trace("Skipping folder due to ending: {} - {}", name, ending);
184-
ignore = true;
185-
}
186-
}
187-
}
188-
}
189-
return ignore;
190-
}
191-
192-
/**
193-
* Determine if a file should be processed or not
194-
*
195-
* @param name filename to review
196-
* @return <code>true</code> if the file should be skipped, <code>false</code> otherwise
197-
*/
198-
private Boolean filterFile(String name) {
199-
// Skip hidden files unless explicitly asked to read them
200-
if (!hiddenFilesFolders && name.startsWith(".")) {
201-
log.trace("Skipping hidden file: {}", name);
202-
return true;
203-
}
204-
// Process all file extensions if requested
205-
if (this.allExtensions) {
206-
log.trace("Processing all file extensions: {}", name);
207-
return false;
208-
}
209-
// Skip some specific files
210-
if (ScanossConstants.FILTERED_FILES.contains(name)) {
211-
log.trace("Skipping specific file: {}", name);
212-
return true;
213-
}
214-
// Skip specific file endings/extensions
215-
for (String ending : ScanossConstants.FILTERED_EXTENSIONS) {
216-
if (name.endsWith(ending)) {
217-
log.trace("Skipping file due to ending: {} - {}", name, ending);
218-
return true;
219-
}
220-
}
221-
return false;
222-
}
223-
224196
/**
225197
* Strip the leading string from the specified path
226198
*
@@ -262,17 +234,16 @@ public List<String> processFolder(@NonNull String folder, FileProcessor processo
262234
Files.walkFileTree(Paths.get(folder), new SimpleFileVisitor<>() {
263235
@Override
264236
public FileVisitResult preVisitDirectory(Path file, BasicFileAttributes attrs) {
265-
String nameLower = file.getFileName().toString().toLowerCase();
266-
if (attrs.isDirectory() && filterFolder(nameLower)) {
237+
if(folderFilter.test(file)) {
238+
log.debug("Processing file: {}", file.getFileName().toString());
267239
return FileVisitResult.SKIP_SUBTREE; // Skip the rest of this directory tree
268240
}
269241
return FileVisitResult.CONTINUE;
270242
}
271243

272244
@Override
273245
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
274-
String nameLower = file.getFileName().toString().toLowerCase();
275-
if (attrs.isRegularFile() && !filterFile(nameLower) && attrs.size() > 0) {
246+
if (attrs.isRegularFile() && !fileFilter.test(file) && attrs.size() > 0) {
276247
String filename = file.toString();
277248
Future<String> future = executorService.submit(() -> processor.process(filename, stripDirectory(folder, filename)));
278249
futures.add(future);
@@ -321,7 +292,8 @@ public List<String> processFileList(@NonNull String root, @NonNull List<String>
321292
Path path = Path.of(file);
322293
boolean skipDir = false;
323294
for (Path p : path) {
324-
if (filterFolder(p.toString().toLowerCase())) { // should we skip this folder or not
295+
// should we skip this folder or not
296+
if (this.folderFilter.test(p)) { // should we skip this folder or not
325297
skipDir = true;
326298
break;
327299
}
@@ -330,7 +302,7 @@ public List<String> processFileList(@NonNull String root, @NonNull List<String>
330302
continue; // skip this file as the folder is not allowed
331303
}
332304
String nameLower = path.getFileName().toString().toLowerCase();
333-
if (!filterFile(nameLower)) {
305+
if (!this.fileFilter.test(path)) {
334306
Path fullPath = Path.of(root, file);
335307
File f = fullPath.toFile();
336308
if (f.exists() && f.isFile() && f.length() > 0 && ! Files.isSymbolicLink(fullPath)) {

src/main/java/com/scanoss/ScannerPostProcessor.java

+1
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,7 @@ private ScanFileDetails createUpdatedResultDetails(ScanFileDetails existingCompo
247247
.file(existingComponent.getFile())
248248
.fileHash(existingComponent.getFileHash())
249249
.fileUrl(existingComponent.getFileUrl())
250+
.lines(existingComponent.getLines())
250251
.purls(new String[]{newPurl.toString()})
251252
.component(newPurl.getName())
252253
.vendor(newPurl.getNamespace())

src/main/java/com/scanoss/ScanossConstants.java

+5-5
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public class ScanossConstants {
5353
static final int MAX_LONG_LINE_CHARS = 1000; // Maximum length of a single source line to be considered source code
5454

5555
// File extensions to ignore snippets for
56-
static final List<String> SKIP_SNIPPET_EXT = Arrays.asList(
56+
public static final List<String> SKIP_SNIPPET_EXT = Arrays.asList(
5757
".exe", ".zip", ".tar", ".tgz", ".gz", ".7z", ".rar", ".jar", ".war", ".ear", ".class", ".pyc",
5858
".o", ".a", ".so", ".obj", ".dll", ".lib", ".out", ".app", ".bin",
5959
".lst", ".dat", ".json", ".htm", ".html", ".xml", ".md", ".txt",
@@ -62,17 +62,17 @@ public class ScanossConstants {
6262
);
6363

6464
// Folders to skip
65-
static final List<String> FILTERED_DIRS = Arrays.asList(
65+
public static final List<String> FILTERED_DIRS = Arrays.asList(
6666
"nbproject", "nbbuild", "nbdist", "__pycache__", "venv", "_yardoc", "eggs", "wheels", "htmlcov",
6767
"__pypackages__", "target"
6868
);
6969

7070
// Folder endings to skip
71-
static final List<String> FILTERED_DIR_EXT = List.of(".egg-info");
71+
public static final List<String> FILTERED_DIR_EXT = List.of(".egg-info");
7272

7373

7474
// File extensions to skip
75-
static final List<String> FILTERED_EXTENSIONS = Arrays.asList(
75+
public static final List<String> FILTERED_EXTENSIONS = Arrays.asList(
7676
".1", ".2", ".3", ".4", ".5", ".6", ".7", ".8", ".9", ".ac", ".adoc", ".am",
7777
".asciidoc", ".bmp", ".build", ".cfg", ".chm", ".class", ".cmake", ".cnf",
7878
".conf", ".config", ".contributors", ".copying", ".crt", ".csproj", ".css",
@@ -95,7 +95,7 @@ public class ScanossConstants {
9595
);
9696

9797
// Files to skip
98-
static final List<String> FILTERED_FILES = Arrays.asList(
98+
public static final List<String> FILTERED_FILES = Arrays.asList(
9999
"gradlew", "gradlew.bat", "mvnw", "mvnw.cmd", "gradle-wrapper.jar", "maven-wrapper.jar",
100100
"thumbs.db", "babel.config.js", "license.txt", "license.md", "copying.lib", "makefile"
101101
);

0 commit comments

Comments
 (0)