Skip to content

Commit b3c6ca5

Browse files
authored
Merge pull request #1515 from WebFuzzing/faul-existing-endpoints
Fault existing endpoints
2 parents 66e194a + 21b7975 commit b3c6ca5

4 files changed

Lines changed: 41 additions & 22 deletions

File tree

core/src/main/kotlin/org/evomaster/core/problem/rest/service/CallGraphService.kt

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,16 @@ class CallGraphService {
2424
*/
2525
private val deleteDependencies = mutableMapOf<Endpoint, RestCallAction>()
2626

27+
private lateinit var endpointsInUse: Set<Endpoint>
2728

2829
@PostConstruct
2930
private fun init() {
3031

3132
val calls = sampler.seeAvailableActions()
3233
.filterIsInstance<RestCallAction>()
3334

35+
endpointsInUse = calls.map{it.endpoint}.toSet()
36+
3437
val deletes = calls.filter { it.verb == HttpVerb.DELETE }
3538
val creates = calls.filter { it.verb == HttpVerb.POST || it.verb == HttpVerb.PUT }
3639

@@ -63,14 +66,25 @@ class CallGraphService {
6366
}
6467

6568
fun endpointsForPath(path: RestPath): List<Endpoint> {
66-
return sampler.seeAvailableActions()
67-
.filterIsInstance<RestCallAction>()
69+
return endpointsInUse
6870
.filter { it.path == path }
69-
.map { Endpoint(it.verb, it.path) }
7071
}
7172

73+
/**
74+
* Check if the given endpoint(verb,path) is declared in the schema.
75+
* This is regardless of whether some endpoints were marked as ignored/to-skip
76+
* during the fuzzing
77+
*/
7278
fun isDeclared(verb: HttpVerb, path: RestPath): Boolean {
73-
return endpointsForPath(path).any{it.verb == verb}
79+
return isInUse(verb, path) || sampler.skippedEndpoints.contains(Endpoint(verb, path))
80+
}
81+
82+
/**
83+
* When fuzzing an API with N endpoint, we might select a subset K of endpoints in use.
84+
* Check if input endpoint is among those.
85+
*/
86+
fun isInUse(verb: HttpVerb, path: RestPath): Boolean {
87+
return endpointsInUse.any { it.path == path && it.verb == verb }
7488
}
7589

7690
fun findStrictTopGETResourceAncestor(path: RestPath) : RestCallAction?{
@@ -346,4 +360,4 @@ class CallGraphService {
346360
*/
347361
return deletes.find { action.path.isSameOrAncestorOf(it.path) }
348362
}
349-
}
363+
}

core/src/main/kotlin/org/evomaster/core/problem/rest/service/fitness/AbstractRestFitness.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -804,7 +804,11 @@ abstract class AbstractRestFitness : HttpWsFitness<RestIndividual>() {
804804
rcr: RestCallResult,
805805
fv: FitnessValue
806806
) {
807-
if (!config.schemaOracles || !schemaOracle.canValidate() || a.id == CALL_TO_SWAGGER_ID) {
807+
if (!config.schemaOracles
808+
|| !schemaOracle.canValidate()
809+
|| a.id == CALL_TO_SWAGGER_ID
810+
|| !callGraphService.isDeclared(a.verb,a.path)
811+
) {
808812
return
809813
}
810814

core/src/main/kotlin/org/evomaster/core/problem/rest/service/sampler/AbstractRestSampler.kt

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import org.evomaster.core.problem.httpws.service.HttpWsSampler
1919
import org.evomaster.core.problem.rest.*
2020
import org.evomaster.core.problem.rest.builder.RestActionBuilderV3
2121
import org.evomaster.core.problem.rest.builder.RestActionBuilderV3.buildActionBasedOnUrl
22+
import org.evomaster.core.problem.rest.data.Endpoint
2223
import org.evomaster.core.problem.rest.data.HttpVerb
2324
import org.evomaster.core.problem.rest.data.RestCallAction
2425
import org.evomaster.core.problem.rest.data.RestIndividual
@@ -55,25 +56,26 @@ abstract class AbstractRestSampler : HttpWsSampler<RestIndividual>() {
5556
@Inject
5657
protected lateinit var configuration: EMConfig
5758

58-
@Inject
59-
protected lateinit var partialOracles: PartialOracles
60-
6159
@Inject
6260
protected lateinit var builder: RestIndividualBuilder
6361

6462
@Inject
6563
protected lateinit var responseClassifier: AIResponseClassifier
6664

65+
// TODO: This will moved under ApiWsSampler once RPC and GraphQL support is completed
66+
@Inject
67+
protected lateinit var externalServiceHandler: HttpWsExternalServiceHandler
68+
6769
protected val adHocInitialIndividuals: MutableList<RestIndividual> = mutableListOf()
6870

6971
lateinit var schemaHolder: RestSchema
7072
protected set
7173

7274
private lateinit var infoDto: SutInfoDto
7375

74-
// TODO: This will moved under ApiWsSampler once RPC and GraphQL support is completed
75-
@Inject
76-
protected lateinit var externalServiceHandler: HttpWsExternalServiceHandler
76+
lateinit var skippedEndpoints : List<Endpoint>
77+
private set
78+
7779

7880
@PostConstruct
7981
open fun initialize() {
@@ -120,8 +122,8 @@ abstract class AbstractRestSampler : HttpWsSampler<RestIndividual>() {
120122

121123
// The code should never reach this line without a valid swagger.
122124
actionCluster.clear()
123-
val skip = EndpointFilter.getEndpointsToSkip(config, schemaHolder, infoDto)
124-
val messages = RestActionBuilderV3.addActionsFromSwagger(schemaHolder, actionCluster, skip, RestActionBuilderV3.Options(config))
125+
skippedEndpoints = EndpointFilter.getEndpointsToSkip(config, schemaHolder, infoDto)
126+
val messages = RestActionBuilderV3.addActionsFromSwagger(schemaHolder, actionCluster, skippedEndpoints, RestActionBuilderV3.Options(config))
125127
printMessages(messages)
126128

127129
if(config.extraQueryParam){
@@ -321,16 +323,14 @@ abstract class AbstractRestSampler : HttpWsSampler<RestIndividual>() {
321323

322324
actionCluster.clear()
323325
// Add all paths to list of paths to ignore except endpointFocus
324-
val endpointsToSkip = EndpointFilter.getEndpointsToSkip(config,schemaHolder)
325-
val messages = RestActionBuilderV3.addActionsFromSwagger(schemaHolder, actionCluster, endpointsToSkip, RestActionBuilderV3.Options(config))
326+
skippedEndpoints = EndpointFilter.getEndpointsToSkip(config,schemaHolder)
327+
val messages = RestActionBuilderV3.addActionsFromSwagger(schemaHolder, actionCluster, skippedEndpoints, RestActionBuilderV3.Options(config))
326328
printMessages(messages)
327329

328330
initAdHocInitialIndividuals()
329-
if (config.seedTestCases)
331+
if (config.seedTestCases) {
330332
initSeededTests()
331-
332-
333-
//partialOracles.setupForRest(swagger, config)
333+
}
334334

335335
log.debug("Done initializing {}", AbstractRestSampler::class.simpleName)
336336
}

core/src/main/kotlin/org/evomaster/core/search/service/Statistics.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -566,10 +566,11 @@ class Statistics : SearchListener {
566566
return solution.individuals
567567
.flatMap { it.evaluatedMainActions() }
568568
.filter {
569-
it.result is HttpWsCallResult && (it.result as HttpWsCallResult).getStatusCode()?.let { c -> c in 200..299 } ?: false
569+
it.result is HttpWsCallResult &&
570+
(it.result).getStatusCode()?.let { c -> c in 200..299 } ?: false
570571
}
571572
// in phases like Security we might create calls that do not exist in schema
572-
.filter{ it.action is RestCallAction && callGraphService.isDeclared(it.action.verb,it.action.path)}
573+
.filter{ it.action is RestCallAction && callGraphService.isInUse(it.action.verb,it.action.path)}
573574
.map { it.action.getName() }
574575
.distinct()
575576
.count()

0 commit comments

Comments
 (0)