Skip to content

Commit 3859c06

Browse files
committed
feat: support both exhortignore and trustify-da-ignore
1 parent fd95b33 commit 3859c06

9 files changed

Lines changed: 204 additions & 51 deletions

File tree

README.md

Lines changed: 45 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -177,14 +177,22 @@ public class TrustifyExample {
177177

178178
<h3>Excluding Packages</h3>
179179
<p>
180-
Excluding a package from any analysis can be achieved by marking the package for exclusion.
180+
Excluding a package from any analysis can be achieved by marking the package for exclusion using either the <code>trustify-da-ignore</code> syntax or the legacy <code>exhortignore</code>.
181181
</p>
182182

183183
<ul>
184184
<li>
185185
<em>Java Maven</em> users can add a comment in <em>pom.xml</em>
186186

187187
```xml
188+
<!-- Using trustify-da-ignore syntax -->
189+
<dependency> <!--trustify-da-ignore-->
190+
<groupId>...</groupId>
191+
<artifactId>...</artifactId>
192+
<version>0.0.9-SNAPSHOT</version>
193+
</dependency>
194+
195+
<!-- Using legacy exhortignore syntax -->
188196
<dependency> <!--exhortignore-->
189197
<groupId>...</groupId>
190198
<artifactId>...</artifactId>
@@ -193,10 +201,8 @@ Excluding a package from any analysis can be achieved by marking the package for
193201
```
194202
</li>
195203

196-
</ul>
197-
<ul>
198204
<li>
199-
<em>Javascript NPM </em> users can add a root (key, value) pair with value of list of names (strings) to be ignored (without versions), and key called <b>exhortignore</b> in <em>package.json</em>, example:
205+
<em>Javascript NPM</em> users can add ignore arrays in <em>package.json</em>:
200206

201207
```json
202208
{
@@ -213,14 +219,21 @@ Excluding a package from any analysis can be achieved by marking the package for
213219
"jsonwebtoken": "^8.5.1",
214220
"mongoose": "^5.9.18"
215221
},
222+
"trustify-da-ignore": [
223+
"mongoose"
224+
],
216225
"exhortignore": [
217226
"jsonwebtoken"
218227
]
219228
}
220-
221229
```
222230

223-
<em>Golang</em> users can add in go.mod a comment with //exhortignore next to the package to be ignored, or to "piggyback" on existing comment ( e.g - //indirect) , for example:
231+
Both arrays can coexist in the same package.json file.
232+
</li>
233+
234+
<li>
235+
<em>Golang</em> users can add comments in <em>go.mod</em>:
236+
224237
```go
225238
module github.com/RHEcosystemAppEng/SaaSi/deployer
226239

@@ -230,7 +243,7 @@ require (
230243
github.com/gin-gonic/gin v1.9.1
231244
github.com/google/uuid v1.1.2
232245
github.com/jessevdk/go-flags v1.5.0 //exhortignore
233-
github.com/kr/pretty v0.3.1
246+
github.com/kr/pretty v0.3.1 //trustify-da-ignore
234247
gopkg.in/yaml.v2 v2.4.0
235248
k8s.io/apimachinery v0.26.1
236249
k8s.io/client-go v0.26.1
@@ -239,12 +252,14 @@ require (
239252
require (
240253
github.com/davecgh/go-spew v1.1.1 // indirect exhortignore
241254
github.com/emicklei/go-restful/v3 v3.9.0 // indirect
242-
github.com/go-logr/logr v1.2.3 // indirect //exhortignore
243-
255+
github.com/go-logr/logr v1.2.3 // indirect trustify-da-ignore
244256
)
245257
```
258+
</li>
259+
260+
<li>
261+
<em>Python pip</em> users can add comments in <em>requirements.txt</em>:
246262

247-
<em>Python pip</em> users can add in requirement text a comment with #exhortignore(or # exhortignore) to the right of the same artifact to be ignored, for example:
248263
```properties
249264
anyio==3.6.2
250265
asgiref==3.4.1
@@ -262,9 +277,9 @@ importlib-metadata==4.8.3
262277
itsdangerous==2.0.1
263278
Jinja2==3.0.3
264279
MarkupSafe==2.0.1
265-
pydantic==1.9.2 # exhortignore
280+
pydantic==1.9.2 # trustify-da-ignore
266281
requests==2.25.1
267-
six==1.16.0
282+
six==1.16.0
268283
sniffio==1.2.0
269284
soupsieve==2.3.2.post1
270285
starlette==0.17.1
@@ -273,12 +288,15 @@ urllib3==1.26.16
273288
uvicorn==0.17.0
274289
Werkzeug==2.0.3
275290
zipp==3.6.0
276-
277291
```
278-
<em>Gradle</em> users can add in build.gradle a comment with //exhortignore next to the package to be ignored:
279-
```build.gradle
292+
</li>
293+
294+
<li>
295+
<em>Gradle</em> users can add comments in <em>build.gradle</em>:
296+
297+
```groovy
280298
plugins {
281-
id 'java'
299+
id 'java'
282300
}
283301
284302
group = 'groupName'
@@ -290,24 +308,27 @@ repositories {
290308
291309
dependencies {
292310
implementation "groupId:artifactId:version" // exhortignore
311+
implementation "anotherGroup:anotherArtifact:version" // trustify-da-ignore
293312
}
313+
294314
test {
295315
useJUnitPlatform()
296316
}
297317
```
318+
</li>
319+
298320
</ul>
299-
All of the 5 above examples are valid for marking a package to be ignored
321+
322+
#### Migration from exhortignore to trustify-da-ignore
323+
Both `exhortignore` and `trustify-da-ignore` patterns work identically and can be used interchangeably. The `trustify-da-ignore` syntax is recommended for new projects, while `exhortignore` continues to be supported for backwards compatibility. You can gradually migrate your projects or use both patterns in the same manifest.
300324

301325
#### Ignore Strategies - experimental
302-
You can specify the method to ignore dependencies in manifest (globally), by setting the environment variable `TRUSTIFY_DA_IGNORE_METHOD` to one of the following values: \
303-
**_Possible values:_**
304-
- `insensitive` - ignoring the dependency and all of its subtree(all transitives) - default.
305-
- `sensitive` - ignoring the dependency but let its transitives remain if they are also transitive of another dependency in the tree or if they're direct dependency of root in the dependency tree.
306-
307326

308-
</li>
327+
You can specify the method to ignore dependencies in manifest (globally), by setting the environment variable `TRUSTIFY_DA_IGNORE_METHOD` to one of the following values:
309328

310-
</ul>
329+
**Possible values:**
330+
- `insensitive` - ignoring the dependency and all of its subtree(all transitives) - default.
331+
- `sensitive` - ignoring the dependency but let its transitives remain if they are also transitive of another dependency in the tree or if they're direct dependency of root in the dependency tree.
311332

312333
<h3>Customization</h3>
313334
<p>

src/main/java/io/github/guacsec/trustifyda/providers/GoModulesProvider.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import io.github.guacsec.trustifyda.tools.Ecosystem.Type;
2929
import io.github.guacsec.trustifyda.tools.Operations;
3030
import io.github.guacsec.trustifyda.utils.Environment;
31+
import io.github.guacsec.trustifyda.utils.IgnorePatternDetector;
3132
import io.github.guacsec.trustifyda.vcs.GitVersionControlSystemImpl;
3233
import io.github.guacsec.trustifyda.vcs.TagInfo;
3334
import io.github.guacsec.trustifyda.vcs.VersionControlSystem;
@@ -459,15 +460,16 @@ private String extractPackageName(String line) {
459460

460461
public boolean IgnoredLine(String line) {
461462
boolean result = false;
462-
if (line.contains("exhortignore")) {
463-
// if exhortignore is alone in a comment or is in a comment together with indirect or as a
463+
if (IgnorePatternDetector.containsIgnorePattern(line)) {
464+
// if exhortignore or trustify-da-ignore is alone in a comment or is in a comment together
465+
// with indirect or as a
464466
// comment inside a
465467
// comment ( e.g // indirect //exhort)
466468
// then this line is to be checked if it's a comment after a package name.
467-
if (Pattern.matches(".+//\\s*exhortignore", line)
468-
|| Pattern.matches(".+//\\sindirect (//)?\\s*exhortignore", line)) {
469+
if (Pattern.matches(".+//\\s*(exhortignore|trustify-da-ignore)", line)
470+
|| Pattern.matches(".+//\\sindirect (//)?\\s*(exhortignore|trustify-da-ignore)", line)) {
469471
String trimmedRow = line.trim();
470-
// filter out lines where exhortignore has no meaning
472+
// filter out lines where exhortignore or trustify-da-ignore has no meaning
471473
if (!trimmedRow.startsWith("module ")
472474
&& !trimmedRow.startsWith("go ")
473475
&& !trimmedRow.startsWith("require (")

src/main/java/io/github/guacsec/trustifyda/providers/GradleProvider.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import io.github.guacsec.trustifyda.sbom.SbomFactory;
2828
import io.github.guacsec.trustifyda.tools.Ecosystem.Type;
2929
import io.github.guacsec.trustifyda.tools.Operations;
30+
import io.github.guacsec.trustifyda.utils.IgnorePatternDetector;
3031
import java.io.IOException;
3132
import java.nio.file.Files;
3233
import java.nio.file.Path;
@@ -202,7 +203,7 @@ private boolean depHasLibsNotation(String depToBeIgnored) {
202203
}
203204

204205
private boolean isIgnoredLine(String line) {
205-
return line.contains("exhortignore");
206+
return IgnorePatternDetector.containsIgnorePattern(line);
206207
}
207208

208209
private String extractPackageName(String line) {

src/main/java/io/github/guacsec/trustifyda/providers/JavaMavenProvider.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import io.github.guacsec.trustifyda.tools.Ecosystem.Type;
2929
import io.github.guacsec.trustifyda.tools.Operations;
3030
import io.github.guacsec.trustifyda.utils.Environment;
31+
import io.github.guacsec.trustifyda.utils.IgnorePatternDetector;
3132
import java.io.IOException;
3233
import java.nio.file.Files;
3334
import java.nio.file.Path;
@@ -277,7 +278,7 @@ private List<DependencyAggregator> getDependencies(final Path manifestPath) thro
277278
if (!Objects.isNull(dependencyAggregator)) {
278279
// if we hit an ignore comment, mark aggregator to be ignored
279280
if (reader.getEventType() == XMLStreamConstants.COMMENT
280-
&& "exhortignore".equals(reader.getText().strip())) {
281+
&& IgnorePatternDetector.isIgnoreComment(reader.getText())) {
281282
dependencyAggregator.ignored = true;
282283
continue;
283284
}

src/main/java/io/github/guacsec/trustifyda/providers/JavaScriptProvider.java

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,8 @@
3636
import java.nio.charset.StandardCharsets;
3737
import java.nio.file.Files;
3838
import java.nio.file.Path;
39-
import java.util.ArrayList;
4039
import java.util.Collections;
4140
import java.util.Iterator;
42-
import java.util.List;
4341
import java.util.Map;
4442
import java.util.Map.Entry;
4543
import java.util.TreeMap;
@@ -240,18 +238,6 @@ protected String parseDepTreeOutput(String output) {
240238
return output;
241239
}
242240

243-
protected List<String> getIgnoredDeps(JsonNode manifest) {
244-
var ignored = new ArrayList<String>();
245-
var ignoredNode = manifest.withArray("exhortignore");
246-
if (ignoredNode == null) {
247-
return ignored;
248-
}
249-
for (JsonNode n : ignoredNode) {
250-
ignored.add(n.asText());
251-
}
252-
return ignored;
253-
}
254-
255241
protected Map<String, String> getExecEnv() {
256242
String pathEnv = Environment.get(pathEnv());
257243
if (pathEnv != null && !pathEnv.isBlank()) {

src/main/java/io/github/guacsec/trustifyda/providers/PythonPipProvider.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import io.github.guacsec.trustifyda.tools.Ecosystem;
3030
import io.github.guacsec.trustifyda.tools.Operations;
3131
import io.github.guacsec.trustifyda.utils.Environment;
32+
import io.github.guacsec.trustifyda.utils.IgnorePatternDetector;
3233
import io.github.guacsec.trustifyda.utils.PythonControllerBase;
3334
import io.github.guacsec.trustifyda.utils.PythonControllerRealEnv;
3435
import io.github.guacsec.trustifyda.utils.PythonControllerVirtualEnv;
@@ -173,7 +174,7 @@ private Set<PackageURL> getIgnoredDependencies(String requirementsDeps) {
173174
String[] requirementsLines = requirementsDeps.split(System.lineSeparator());
174175
Set<PackageURL> collected =
175176
Arrays.stream(requirementsLines)
176-
.filter(line -> line.contains("#exhortignore") || line.contains("# exhortignore"))
177+
.filter(IgnorePatternDetector::containsPythonIgnorePattern)
177178
.map(PythonPipProvider::extractDepFull)
178179
.map(this::splitToNameVersion)
179180
.map(dep -> toPurl(dep[0], dep[1]))

src/main/java/io/github/guacsec/trustifyda/providers/javascript/model/Manifest.java

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,16 @@ private Set<String> loadDependencies(JsonNode content) {
7070
private Set<String> loadIgnored(JsonNode content) {
7171
var names = new HashSet<String>();
7272
if (content != null) {
73-
var ignore = (ArrayNode) content.get("exhortignore");
74-
if (ignore == null || ignore.isEmpty()) {
75-
return Collections.emptySet();
76-
}
73+
processIgnoreArray(content, "exhortignore", names);
74+
processIgnoreArray(content, "trustify-da-ignore", names);
75+
}
76+
return names.isEmpty() ? Collections.emptySet() : Collections.unmodifiableSet(names);
77+
}
78+
79+
private void processIgnoreArray(JsonNode content, String key, Set<String> names) {
80+
var ignore = (ArrayNode) content.get(key);
81+
if (ignore != null && !ignore.isEmpty()) {
7782
ignore.forEach(n -> names.add(n.asText()));
7883
}
79-
return Collections.unmodifiableSet(names);
8084
}
8185
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
* Copyright 2023-2025 Trustify Dependency Analytics Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
*
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package io.github.guacsec.trustifyda.utils;
18+
19+
/**
20+
* Utility class for detecting ignore patterns in dependency manifests. Supports both legacy
21+
* 'exhortignore' and new 'trustify-da-ignore' patterns for backwards compatibility.
22+
*/
23+
public class IgnorePatternDetector {
24+
25+
public static final String LEGACY_IGNORE_PATTERN = "exhortignore";
26+
public static final String NEW_IGNORE_PATTERN = "trustify-da-ignore";
27+
28+
/**
29+
* Checks if a text line contains any ignore pattern (exhortignore or trustify-da-ignore). Used
30+
* for inline comment detection in requirements.txt, go.mod, build.gradle, etc.
31+
*
32+
* @param text the text to check
33+
* @return true if the text contains any ignore pattern
34+
*/
35+
public static boolean containsIgnorePattern(String text) {
36+
return text.contains(LEGACY_IGNORE_PATTERN) || text.contains(NEW_IGNORE_PATTERN);
37+
}
38+
39+
/**
40+
* Checks if a comment text exactly matches an ignore pattern. Used for XML comment detection in
41+
* pom.xml files.
42+
*
43+
* @param commentText the comment text to check (will be stripped of whitespace)
44+
* @return true if the comment exactly matches an ignore pattern
45+
*/
46+
public static boolean isIgnoreComment(String commentText) {
47+
String stripped = commentText.strip();
48+
return LEGACY_IGNORE_PATTERN.equals(stripped) || NEW_IGNORE_PATTERN.equals(stripped);
49+
}
50+
51+
/**
52+
* Checks if a text line contains a Python pip ignore pattern. Handles both '#exhortignore' and
53+
* '#trustify-da-ignore' with optional spacing.
54+
*
55+
* @param line the line to check
56+
* @return true if the line contains a Python pip ignore pattern
57+
*/
58+
public static boolean containsPythonIgnorePattern(String line) {
59+
return line.contains("#" + LEGACY_IGNORE_PATTERN)
60+
|| line.contains("# " + LEGACY_IGNORE_PATTERN)
61+
|| line.contains("#" + NEW_IGNORE_PATTERN)
62+
|| line.contains("# " + NEW_IGNORE_PATTERN);
63+
}
64+
}

0 commit comments

Comments
 (0)