1717package org .sonar .java .checks .security ;
1818
1919
20+ import java .io .IOException ;
2021import java .util .List ;
22+ import java .util .Map ;
2123import org .junit .jupiter .api .Test ;
2224import org .junit .jupiter .api .extension .RegisterExtension ;
2325import org .slf4j .event .Level ;
2426import org .sonar .api .testfixtures .log .LogAndArguments ;
2527import org .sonar .api .testfixtures .log .LogTesterJUnit5 ;
28+ import org .sonar .java .checks .helpers .CredentialMethod ;
29+ import org .sonar .java .checks .helpers .CredentialMethodsLoader ;
2630import org .sonar .java .checks .verifier .CheckVerifier ;
2731import 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 () {
0 commit comments