Skip to content

Commit 39fa9c7

Browse files
committed
chore: add utilities to deduplicate the generated and base suppression rules
1 parent 3adb7f5 commit 39fa9c7

File tree

5 files changed

+1638
-0
lines changed

5 files changed

+1638
-0
lines changed

SUPPRESSION_DEDUPLICATION.md

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
# Suppression File Synchronization
2+
3+
## Overview
4+
5+
DependencyCheck maintains two suppression files:
6+
- **Base Suppression File**: `core/src/main/resources/dependencycheck-base-suppression.xml` - Manually curated suppressions that ship with releases
7+
- **Generated Suppressions File**: Maintained on the `generatedSuppressions` branch - Auto-generated suppressions from GitHub issue reports
8+
9+
## Strategy
10+
11+
The two files serve different purposes and should remain separate:
12+
- The **generated file** is automatically maintained via GitHub Actions when issues are reported
13+
- The **base file** should contain only manually curated suppressions that are NOT in the generated file
14+
- Both files are loaded at runtime, so suppressions in either file will be applied
15+
16+
## Synchronization Tools
17+
18+
Two tools are available to help keep the files in sync in case of overlap (current situation as of Nov 10, 2025):
19+
20+
### 1. Git History Analyzer
21+
22+
The `SuppressionSyncAnalyzer` analyzes git history of the generated suppressions file to find suppressions that were **modified or deleted**:
23+
24+
- ✅ Focuses on intentional changes (not just duplicates)
25+
- ✅ Provides git commit context (why was it changed?)
26+
- ✅ Catches consolidations (e.g., 20 individual rules → 1 broad rule)
27+
- ✅ Shows GitHub commit links for review
28+
- ✅ Handles the "V" option to view commits in browser
29+
30+
**Interactive mode** (recommended):
31+
```bash
32+
./deduplicate-suppressions.sh
33+
# or explicitly:
34+
./deduplicate-suppressions.sh analyzer
35+
```
36+
37+
This will:
38+
1. Fetch the latest from the `generatedSuppressions` branch
39+
2. Analyze git history for modifications/deletions
40+
3. Check if old versions exist in base file
41+
4. Interactively show each one with:
42+
- What's currently in base
43+
- What happened in generated (modified/deleted)
44+
- Git commit info with clickable GitHub link
45+
5. Let you decide: Remove, Keep, View commit, Quit, or Auto-remove all
46+
47+
**Non-interactive mode**:
48+
```bash
49+
./deduplicate-suppressions.sh analyzer --non-interactive
50+
```
51+
52+
This automatically removes ALL obsolete suppressions from base.
53+
54+
### 2. Duplicate Detector (Legacy)
55+
56+
The `SuppressionDeduplicator` finds exact duplicates between the two files. This is less sophisticated but faster for simple cases.
57+
58+
**Interactive mode**:
59+
```bash
60+
./deduplicate-suppressions.sh deduplicator
61+
```
62+
63+
**Non-interactive mode**:
64+
```bash
65+
./deduplicate-suppressions.sh deduplicator --non-interactive
66+
```
67+
68+
### Backup
69+
70+
The tool automatically creates a backup of the base suppression file before making changes:
71+
- Backup location: `dependencycheck-base-suppression.xml.backup`
72+
73+
## How Issues Are Detected
74+
75+
### Git History Analyzer
76+
Finds suppressions in base that match the OLD version from git history where:
77+
1. The suppression was **deleted** from generated
78+
2. OR the suppression was **modified** in generated (indicating consolidation or correction)
79+
80+
### Duplicate Detector
81+
Two suppressions are considered duplicates if:
82+
1. They have matching **key fields** (packageUrl, gav, filePath, or sha1)
83+
2. AND they have overlapping **CPEs**, **CVEs**, or **vulnerability names**
84+
85+
## Implementation Details
86+
87+
- `utils/src/main/java/org/owasp/dependencycheck/utils/SuppressionSyncAnalyzer.java` - Git history analyzer
88+
- `utils/src/main/java/org/owasp/dependencycheck/utils/SuppressionDeduplicator.java` - Duplicate detector
89+
- `utils/src/test/java/org/owasp/dependencycheck/utils/SuppressionSyncAnalyzerTest.java` - Tests for git diff parsing
90+
91+
### Running Tests
92+
93+
To verify the git diff parsing logic works correctly:
94+
95+
```bash
96+
mvn -pl utils test -Dtest=SuppressionSyncAnalyzerTest
97+
```

deduplicate-suppressions.sh

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#!/bin/bash
2+
# Script to synchronize suppressions between base and generated files
3+
4+
set -e
5+
6+
BASE_SUPPRESSION="core/src/main/resources/dependencycheck-base-suppression.xml"
7+
MODE="${1:-analyzer}"
8+
9+
if [ "$MODE" = "--help" ] || [ "$MODE" = "-h" ]; then
10+
echo "Usage: $0 [analyzer|deduplicator] [--non-interactive]"
11+
echo ""
12+
echo "Modes:"
13+
echo " analyzer - Analyze git history for modified/deleted suppressions (recommended)"
14+
echo " deduplicator - Find exact duplicates between files"
15+
echo ""
16+
echo "Options:"
17+
echo " --non-interactive - Remove all without prompting"
18+
echo ""
19+
echo "Examples:"
20+
echo " $0 # Run analyzer in interactive mode"
21+
echo " $0 analyzer --non-interactive # Run analyzer and auto-remove all"
22+
echo " $0 deduplicator # Run old duplicate detection"
23+
exit 0
24+
fi
25+
26+
# Determine which tool to run
27+
if [ "$MODE" = "deduplicator" ]; then
28+
MAIN_CLASS="org.owasp.dependencycheck.utils.SuppressionDeduplicator"
29+
shift # Remove 'deduplicator' from args
30+
elif [ "$MODE" = "analyzer" ] || [ "$MODE" = "--non-interactive" ]; then
31+
MAIN_CLASS="org.owasp.dependencycheck.utils.SuppressionSyncAnalyzer"
32+
if [ "$MODE" = "analyzer" ]; then
33+
shift # Remove 'analyzer' from args
34+
fi
35+
else
36+
echo "Unknown mode: $MODE"
37+
echo "Run '$0 --help' for usage"
38+
exit 1
39+
fi
40+
41+
echo "Building utils module..."
42+
mvn -pl utils clean compile -q
43+
44+
echo ""
45+
echo "Running synchronization tool..."
46+
mvn -pl utils exec:java \
47+
-Dexec.mainClass="$MAIN_CLASS" \
48+
-Dexec.args="$BASE_SUPPRESSION $*"
49+
50+
echo ""
51+
echo "Done!"

0 commit comments

Comments
 (0)