Skip to content

Commit bf33ace

Browse files
SONARJAVA-4634 Test for duplicates in credential method json file (#5132)
1 parent fe1934b commit bf33ace

3 files changed

Lines changed: 95 additions & 0 deletions

File tree

java-checks-aws/src/test/java/org/sonar/java/checks/security/HardCodedCredentialsShouldNotBeUsedCheckTest.java

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,16 @@
1717
package org.sonar.java.checks.security;
1818

1919

20+
import java.io.IOException;
2021
import java.util.List;
22+
import java.util.Map;
2123
import org.junit.jupiter.api.Test;
2224
import org.junit.jupiter.api.extension.RegisterExtension;
2325
import org.slf4j.event.Level;
2426
import org.sonar.api.testfixtures.log.LogAndArguments;
2527
import org.sonar.api.testfixtures.log.LogTesterJUnit5;
28+
import org.sonar.java.checks.helpers.CredentialMethod;
29+
import org.sonar.java.checks.helpers.CredentialMethodsLoader;
2630
import org.sonar.java.checks.verifier.CheckVerifier;
2731
import org.sonar.java.checks.verifier.TestUtils;
2832

@@ -45,6 +49,85 @@ void uses_empty_collection_when_methods_cannot_be_loaded() {
4549
.containsOnly("Could not load methods from \"non-existing-file.json\".");
4650
}
4751

52+
private enum ComparisonResult {
53+
DISTINCT {
54+
@Override
55+
public ComparisonResult and(ComparisonResult other) {
56+
return DISTINCT;
57+
}
58+
}, SAME {
59+
@Override
60+
public ComparisonResult and(ComparisonResult other) {
61+
return other;
62+
}
63+
}, MAY_INTERSECT {
64+
@Override
65+
public ComparisonResult and(ComparisonResult other) {
66+
if (other == DISTINCT) {
67+
return DISTINCT;
68+
}
69+
return MAY_INTERSECT;
70+
}
71+
};
72+
73+
/**
74+
* This is kind of a three valued logic, where and describe how the combination of two parts compares to another combination of two parts, given that we know how the small
75+
* parts compare.
76+
*/
77+
public abstract ComparisonResult and(ComparisonResult other);
78+
}
79+
80+
private ComparisonResult compareMethodDescriptors(CredentialMethod method, CredentialMethod other) {
81+
if (!method.cls.equals(other.cls) || !method.name.equals(other.name)) {
82+
return ComparisonResult.DISTINCT;
83+
}
84+
if (method.args.size() != other.args.size()) {
85+
return ComparisonResult.DISTINCT;
86+
}
87+
ComparisonResult result = ComparisonResult.SAME;
88+
for (int i = 0; i < method.args.size(); i++) {
89+
if (method.args.get(i).equals(other.args.get(i))) {
90+
result = result.and(ComparisonResult.SAME);
91+
} else if (method.args.get(i).equals("*") || other.args.get(i).equals("*")) {
92+
result = result.and(ComparisonResult.MAY_INTERSECT);
93+
} else {
94+
return ComparisonResult.DISTINCT;
95+
}
96+
}
97+
return result;
98+
}
99+
100+
/**
101+
* Count the number of method that may intersect. Assert that no two descriptor are exactly the same.
102+
*/
103+
private int countIntersectingMethodsDescriptors(List<CredentialMethod> methods) {
104+
int count = 0;
105+
for (int i = 0; i < methods.size(); i++) {
106+
for (int j = i + 1; j < methods.size(); j++) {
107+
var comparisonResult = compareMethodDescriptors(methods.get(i), methods.get(j));
108+
assertThat(comparisonResult)
109+
.as("credential method entries " + methods.get(i) + " and " + methods.get(j) + " are not the same")
110+
.isNotEqualTo(ComparisonResult.SAME);
111+
if (comparisonResult == ComparisonResult.MAY_INTERSECT) {
112+
count++;
113+
}
114+
}
115+
}
116+
return count;
117+
}
118+
119+
@Test
120+
void test_credential_file_content() throws IOException {
121+
Map<String, List<CredentialMethod>> methods = CredentialMethodsLoader
122+
.load(HardCodedCredentialsShouldNotBeUsedCheck.CREDENTIALS_METHODS_FILE);
123+
Integer intersectCount =
124+
methods.values().stream().map(this::countIntersectingMethodsDescriptors)
125+
.reduce(Integer::sum)
126+
.orElse(0);
127+
// There are three potential intersections we know of. We have checked manually that there are no actual method in the intersection.
128+
assertThat(intersectCount).isEqualTo(3);
129+
assertThat(methods).hasSize(2730);
130+
}
48131

49132
@Test
50133
void test() {

java-checks-common/src/main/java/org/sonar/java/checks/helpers/CredentialMethod.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,4 +57,10 @@ public MethodMatchers methodMatcher() {
5757
.build();
5858
return methodMatcher;
5959
}
60+
61+
/** This is intended for debugging and testing. */
62+
@Override
63+
public String toString() {
64+
return cls + "#" + name + args + "@" + indices ;
65+
}
6066
}

java-checks-common/src/test/java/org/sonar/java/checks/helpers/CredentialMethodTest.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,10 @@ void methodMatcher_is_recycled() {
4747
MethodMatchers methodMatcher = equalsMatcher.methodMatcher();
4848
assertThat(equalsMatcher.methodMatcher()).isSameAs(methodMatcher);
4949
}
50+
51+
/** Since toString is only used for debugging, we don't need strong guarantees on it. */
52+
@Test
53+
void test_toString() {
54+
assertThat(new CredentialMethod("Foo", "bar", List.of("java.lang.String"), List.of(1)).toString()).isNotEmpty();
55+
}
5056
}

0 commit comments

Comments
 (0)