Skip to content

Commit 39a1cf5

Browse files
committed
Ruby: Allow custom edges in API graph EntryPoints
1 parent 0f74674 commit 39a1cf5

File tree

1 file changed

+41
-0
lines changed

1 file changed

+41
-0
lines changed

ruby/ql/lib/codeql/ruby/ApiGraphs.qll

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,10 @@ module API {
378378
*
379379
* Anything in the global scope is considered to be an entry point, but
380380
* additional entry points may be added by extending this class.
381+
*
382+
* By default, instances of this class will have a single edge from the root
383+
* of the API graph. If you wish to construct more complex paths to an entry
384+
* point, override the `edge` predicate.
381385
*/
382386
abstract class EntryPoint extends string {
383387
bindingset[this]
@@ -400,6 +404,41 @@ module API {
400404

401405
/** Gets an API-node for this entry point. */
402406
API::Node getANode() { result = root().getASuccessor(Label::entryPoint(this)) }
407+
408+
/**
409+
* Holds if there is an edge from `pred` to this entry point, with label
410+
* `lbl`. Override this predicate to define new paths to this entry point.
411+
*
412+
* For example, to define an entry point for `ActiveStorage::Attachment` we
413+
* can use an intermediate entry point for `ActiveStorage`:
414+
*
415+
* ```ql
416+
* class ActiveStorage extends EntryPoint {
417+
* ActiveStorage() { this = "ActiveStorage" }
418+
*
419+
* override predicate edge(Node pred, Label::ApiLabel lbl) {
420+
* pred = root() and lbl = Label::member("ActiveStorage")
421+
* }
422+
* }
423+
*
424+
* class Attachment extends EntryPoint {
425+
* Attachment() { this = "ActiveStorage::Attachment" }
426+
*
427+
* override predicate edge(Node pred, Label::ApiLabel lbl) {
428+
* pred = getTopLevelMember("ActiveStorage") and
429+
* lbl = Label::member("Attachment")
430+
* }
431+
*
432+
* override DataFlow::LocalSourceNode getAUse() { result = customAttachmentPredicate() }
433+
* }
434+
* ```
435+
*
436+
* This means that
437+
* `getTopLevelMember("ActiveStorage").getMember("Attachment")` will return
438+
* results from `customAttachmentPredicate()`, even if there are no
439+
* references to `ActiveStorage` or `Attachment` in the codebase.
440+
*/
441+
predicate edge(API::Node pred, Label::ApiLabel lbl) { none() }
403442
}
404443

405444
// Ensure all entry points are imported from ApiGraphs.qll
@@ -718,6 +757,8 @@ module API {
718757
exists(EntryPoint entry |
719758
pred = root() and
720759
lbl = Label::entryPoint(entry)
760+
or
761+
entry.edge(pred, lbl)
721762
|
722763
succ = MkDef(entry.getASink())
723764
or

0 commit comments

Comments
 (0)