@@ -12,7 +12,11 @@ import * as api from "./api-client";
1212import * as diffUtils from "./diff-informed-analysis-utils" ;
1313import { Logger } from "./logging" ;
1414import * as sarif from "./sarif" ;
15- import { RecordingLogger , setupTests } from "./testing-utils" ;
15+ import {
16+ checkExpectedLogMessages ,
17+ RecordingLogger ,
18+ setupTests ,
19+ } from "./testing-utils" ;
1620import * as uploadLib from "./upload-lib" ;
1721import { UploadPayload } from "./upload-lib/types" ;
1822import { GitHubVariant , initializeEnvironment , withTmpDir } from "./util" ;
@@ -1014,12 +1018,62 @@ for (const analysisKind of analyses.supportedAnalysisKinds) {
10141018 ) ;
10151019}
10161020
1021+ function createMockSarifWithResults (
1022+ results : sarif . Result [ ] ,
1023+ ) : Partial < sarif . Log > {
1024+ return {
1025+ version : "2.1.0" ,
1026+ runs : [
1027+ {
1028+ tool : {
1029+ driver : {
1030+ name : "test tool" ,
1031+ } ,
1032+ } ,
1033+ results,
1034+ } ,
1035+ ] ,
1036+ } ;
1037+ }
1038+
1039+ function createMockResultWithUri (
1040+ uri : string ,
1041+ startLine = 2 ,
1042+ relatedUri ?: string ,
1043+ ) : sarif . Result {
1044+ return {
1045+ ruleId : "test-rule" ,
1046+ message : { text : "test message" } ,
1047+ locations : [
1048+ {
1049+ physicalLocation : {
1050+ artifactLocation : { uri } ,
1051+ region : { startLine } ,
1052+ } ,
1053+ } ,
1054+ ] ,
1055+ ...( relatedUri
1056+ ? {
1057+ relatedLocations : [
1058+ {
1059+ physicalLocation : {
1060+ artifactLocation : { uri : relatedUri } ,
1061+ region : { startLine } ,
1062+ } ,
1063+ } ,
1064+ ] ,
1065+ }
1066+ : { } ) ,
1067+ } ;
1068+ }
1069+
10171070function runFilterAlertsByDiffRange (
10181071 input : Partial < sarif . Log > ,
10191072 diffRanges : diffUtils . DiffThunkRange [ ] ,
1073+ logger : Logger = new RecordingLogger ( ) ,
10201074) : Partial < sarif . Log > {
10211075 sinon . stub ( diffUtils , "readDiffRangesJsonFile" ) . returns ( diffRanges ) ;
1022- return uploadLib . filterAlertsByDiffRange ( new RecordingLogger ( ) , input ) ;
1076+ return uploadLib . filterAlertsByDiffRange ( logger , input ) ;
10231077}
10241078
10251079test . serial (
@@ -1043,3 +1097,136 @@ test.serial(
10431097 t . deepEqual ( actualOutput , expectedOutput ) ;
10441098 } ,
10451099) ;
1100+
1101+ for ( const [ filePath , uri ] of [
1102+ [ "with space/board.js" , "with%20space/board.js" ] ,
1103+ [ "src/[id]/board.js" , "src/%5Bid%5D/board.js" ] ,
1104+ [ "src/file#1.js" , "src/file%231.js" ] ,
1105+ [ "src/100%.js" , "src/100%25.js" ] ,
1106+ [ "src/literal%20.js" , "src/literal%2520.js" ] ,
1107+ [ "src/foo:bar.js" , "src/foo%3Abar.js" ] ,
1108+ [ "src/caf\u00e9.js" , "src/caf%C3%A9.js" ] ,
1109+ [ "src/caf\u00e9.js" , "src/caf%c3%a9.js" ] ,
1110+ ] ) {
1111+ test . serial (
1112+ `filterAlertsByDiffRange matches percent-encoded URI ${ uri } ` ,
1113+ ( t ) => {
1114+ const matchingResult = createMockResultWithUri ( uri ) ;
1115+ const nonMatchingResult = createMockResultWithUri ( "other.js" ) ;
1116+ const input = createMockSarifWithResults ( [
1117+ matchingResult ,
1118+ nonMatchingResult ,
1119+ ] ) ;
1120+
1121+ const actualOutput = runFilterAlertsByDiffRange ( input , [
1122+ { path : filePath , startLine : 1 , endLine : 3 } ,
1123+ ] ) ;
1124+
1125+ t . deepEqual ( actualOutput . runs ?. [ 0 ] . results , [ matchingResult ] ) ;
1126+ } ,
1127+ ) ;
1128+ }
1129+
1130+ test . serial (
1131+ "filterAlertsByDiffRange filters out percent-encoded URI when outside diff line range" ,
1132+ ( t ) => {
1133+ const input = createMockSarifWithResults ( [
1134+ createMockResultWithUri ( "with%20space/board.js" , 2 ) ,
1135+ ] ) ;
1136+ const actualOutput = runFilterAlertsByDiffRange ( input , [
1137+ { path : "with space/board.js" , startLine : 10 , endLine : 20 } ,
1138+ ] ) ;
1139+
1140+ t . deepEqual ( actualOutput . runs ?. [ 0 ] . results , [ ] ) ;
1141+ } ,
1142+ ) ;
1143+
1144+ test . serial (
1145+ "filterAlertsByDiffRange filters out percent-encoded URI when path does not match" ,
1146+ ( t ) => {
1147+ const input = createMockSarifWithResults ( [
1148+ createMockResultWithUri ( "with%20space/board.js" ) ,
1149+ ] ) ;
1150+ const actualOutput = runFilterAlertsByDiffRange ( input , [
1151+ { path : "other/board.js" , startLine : 1 , endLine : 3 } ,
1152+ ] ) ;
1153+
1154+ t . deepEqual ( actualOutput . runs ?. [ 0 ] . results , [ ] ) ;
1155+ } ,
1156+ ) ;
1157+
1158+ test . serial (
1159+ "filterAlertsByDiffRange keeps alert when relatedLocations has a matching percent-encoded URI" ,
1160+ ( t ) => {
1161+ const matchingRelatedResult = createMockResultWithUri (
1162+ "src/promiseUtils.js" ,
1163+ 2 ,
1164+ "with%20space/ParseObject.js" ,
1165+ ) ;
1166+ const nonMatchingResult = createMockResultWithUri ( "other.js" ) ;
1167+ const input = createMockSarifWithResults ( [
1168+ matchingRelatedResult ,
1169+ nonMatchingResult ,
1170+ ] ) ;
1171+
1172+ const actualOutput = runFilterAlertsByDiffRange ( input , [
1173+ { path : "with space/ParseObject.js" , startLine : 1 , endLine : 3 } ,
1174+ ] ) ;
1175+
1176+ t . deepEqual ( actualOutput . runs ?. [ 0 ] . results , [ matchingRelatedResult ] ) ;
1177+ } ,
1178+ ) ;
1179+
1180+ for ( const uri of [ "dir%ZZ/board.js" , "src/bad%.js" , "src/bad%C3%28.js" ] ) {
1181+ test . serial (
1182+ `filterAlertsByDiffRange falls back to raw path for malformed URI ${ uri } ` ,
1183+ ( t ) => {
1184+ const logger = new RecordingLogger ( ) ;
1185+ const matchingResult = createMockResultWithUri ( uri ) ;
1186+ const input = createMockSarifWithResults ( [ matchingResult ] ) ;
1187+ const actualOutput = runFilterAlertsByDiffRange (
1188+ input ,
1189+ [ { path : uri , startLine : 1 , endLine : 3 } ] ,
1190+ logger ,
1191+ ) ;
1192+
1193+ t . deepEqual ( actualOutput . runs ?. [ 0 ] . results , [ matchingResult ] ) ;
1194+ checkExpectedLogMessages ( t , logger . messages , [
1195+ `Failed to decode location URI "${ uri } ", comparing it as a raw path` ,
1196+ ] ) ;
1197+ } ,
1198+ ) ;
1199+ }
1200+
1201+ test . serial (
1202+ "filterAlertsByDiffRange filters out malformed URI when raw path does not match" ,
1203+ ( t ) => {
1204+ const logger = new RecordingLogger ( ) ;
1205+ const input = createMockSarifWithResults ( [
1206+ createMockResultWithUri ( "dir%ZZ/board.js" ) ,
1207+ ] ) ;
1208+ const actualOutput = runFilterAlertsByDiffRange (
1209+ input ,
1210+ [ { path : "src/different.js" , startLine : 1 , endLine : 3 } ] ,
1211+ logger ,
1212+ ) ;
1213+
1214+ t . deepEqual ( actualOutput . runs ?. [ 0 ] . results , [ ] ) ;
1215+ checkExpectedLogMessages ( t , logger . messages , [
1216+ 'Failed to decode location URI "dir%ZZ/board.js", comparing it as a raw path' ,
1217+ ] ) ;
1218+ } ,
1219+ ) ;
1220+
1221+ test . serial (
1222+ "filterAlertsByDiffRange matches raw unencoded path containing valid percent-encoding sequence" ,
1223+ ( t ) => {
1224+ const matchingResult = createMockResultWithUri ( "dir/100%20done.js" ) ;
1225+ const input = createMockSarifWithResults ( [ matchingResult ] ) ;
1226+ const actualOutput = runFilterAlertsByDiffRange ( input , [
1227+ { path : "dir/100%20done.js" , startLine : 1 , endLine : 3 } ,
1228+ ] ) ;
1229+
1230+ t . deepEqual ( actualOutput . runs ?. [ 0 ] . results , [ matchingResult ] ) ;
1231+ } ,
1232+ ) ;
0 commit comments