mirror of
https://github.com/github/codeql.git
synced 2026-04-27 09:45:15 +02:00
Merge pull request #297 from github/aibaars/alert-suppression
Alert suppression and file classifier query
This commit is contained in:
43
ql/lib/codeql/ruby/filters/GeneratedCode.qll
Normal file
43
ql/lib/codeql/ruby/filters/GeneratedCode.qll
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
/** Provides classes for detecting generated code. */
|
||||||
|
|
||||||
|
private import ruby
|
||||||
|
private import codeql.ruby.ast.internal.TreeSitter
|
||||||
|
|
||||||
|
/** A source file that contains generated code. */
|
||||||
|
abstract class GeneratedCodeFile extends RubyFile { }
|
||||||
|
|
||||||
|
/** A file contining comments suggesting it contains generated code. */
|
||||||
|
class GeneratedCommentFile extends GeneratedCodeFile {
|
||||||
|
GeneratedCommentFile() { this = any(GeneratedCodeComment c).getLocation().getFile() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A comment line that indicates generated code. */
|
||||||
|
abstract class GeneratedCodeComment extends Ruby::Comment { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A generic comment line that suggests that the file is generated.
|
||||||
|
*/
|
||||||
|
class GenericGeneratedCodeComment extends GeneratedCodeComment {
|
||||||
|
GenericGeneratedCodeComment() {
|
||||||
|
exists(string line, string entity, string was, string automatically | line = getValue() |
|
||||||
|
entity = "file|class|art[ei]fact|module|script" and
|
||||||
|
was = "was|is|has been" and
|
||||||
|
automatically = "automatically |mechanically |auto[- ]?" and
|
||||||
|
line.regexpMatch("(?i).*\\bThis (" + entity + ") (" + was + ") (" + automatically +
|
||||||
|
")?generated\\b.*")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A comment warning against modifications. */
|
||||||
|
class DontModifyMarkerComment extends GeneratedCodeComment {
|
||||||
|
DontModifyMarkerComment() {
|
||||||
|
exists(string line | line = getValue() |
|
||||||
|
line.regexpMatch("(?i).*\\bGenerated by\\b.*\\bDo not edit\\b.*") or
|
||||||
|
line.regexpMatch("(?i).*\\bAny modifications to this file will be lost\\b.*")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Holds if `file` looks like it contains generated code. */
|
||||||
|
predicate isGeneratedCode(GeneratedCodeFile file) { any() }
|
||||||
82
ql/src/AlertSuppression.ql
Normal file
82
ql/src/AlertSuppression.ql
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
/**
|
||||||
|
* @name Alert suppression
|
||||||
|
* @description Generates information about alert suppressions.
|
||||||
|
* @kind alert-suppression
|
||||||
|
* @id rb/alert-suppression
|
||||||
|
*/
|
||||||
|
|
||||||
|
import ruby
|
||||||
|
import codeql.ruby.ast.internal.TreeSitter
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An alert suppression comment.
|
||||||
|
*/
|
||||||
|
class SuppressionComment extends Ruby::Comment {
|
||||||
|
string annotation;
|
||||||
|
|
||||||
|
SuppressionComment() {
|
||||||
|
// suppression comments must be single-line
|
||||||
|
this.getLocation().getStartLine() = this.getLocation().getEndLine() and
|
||||||
|
exists(string text | text = commentText(this) |
|
||||||
|
// match `lgtm[...]` anywhere in the comment
|
||||||
|
annotation = text.regexpFind("(?i)\\blgtm\\s*\\[[^\\]]*\\]", _, _)
|
||||||
|
or
|
||||||
|
// match `lgtm` at the start of the comment and after semicolon
|
||||||
|
annotation = text.regexpFind("(?i)(?<=^|;)\\s*lgtm(?!\\B|\\s*\\[)", _, _).trim()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the text of this suppression comment.
|
||||||
|
*/
|
||||||
|
string getText() { result = commentText(this) }
|
||||||
|
|
||||||
|
/** Gets the suppression annotation in this comment. */
|
||||||
|
string getAnnotation() { result = annotation }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if this comment applies to the range from column `startcolumn` of line `startline`
|
||||||
|
* to column `endcolumn` of line `endline` in file `filepath`.
|
||||||
|
*/
|
||||||
|
predicate covers(string filepath, int startline, int startcolumn, int endline, int endcolumn) {
|
||||||
|
this.getLocation().hasLocationInfo(filepath, startline, _, endline, endcolumn) and
|
||||||
|
startcolumn = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Gets the scope of this suppression. */
|
||||||
|
SuppressionScope getScope() { this = result.getSuppressionComment() }
|
||||||
|
}
|
||||||
|
|
||||||
|
private string commentText(Ruby::Comment comment) { result = comment.getValue().suffix(1) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The scope of an alert suppression comment.
|
||||||
|
*/
|
||||||
|
class SuppressionScope extends @ruby_token_comment {
|
||||||
|
SuppressionScope() { this instanceof SuppressionComment }
|
||||||
|
|
||||||
|
/** Gets a suppression comment with this scope. */
|
||||||
|
SuppressionComment getSuppressionComment() { result = this }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if this element is at the specified location.
|
||||||
|
* The location spans column `startcolumn` of line `startline` to
|
||||||
|
* column `endcolumn` of line `endline` in file `filepath`.
|
||||||
|
* For more information, see
|
||||||
|
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||||
|
*/
|
||||||
|
predicate hasLocationInfo(
|
||||||
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
|
) {
|
||||||
|
this.(SuppressionComment).covers(filepath, startline, startcolumn, endline, endcolumn)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Gets a textual representation of this element. */
|
||||||
|
string toString() { result = "suppression range" }
|
||||||
|
}
|
||||||
|
|
||||||
|
from SuppressionComment c
|
||||||
|
select c, // suppression comment
|
||||||
|
c.getText(), // text of suppression comment (excluding delimiters)
|
||||||
|
c.getAnnotation(), // text of suppression annotation
|
||||||
|
c.getScope() // scope of suppression
|
||||||
20
ql/src/filters/ClassifyFiles.ql
Normal file
20
ql/src/filters/ClassifyFiles.ql
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
/**
|
||||||
|
* @name Classify files
|
||||||
|
* @description This query produces a list of all files in a database
|
||||||
|
* that are classified as generated code or test code.
|
||||||
|
*
|
||||||
|
* Used by LGTM.
|
||||||
|
* @kind file-classifier
|
||||||
|
* @id rb/file-classifier
|
||||||
|
*/
|
||||||
|
|
||||||
|
import ruby
|
||||||
|
import codeql.ruby.filters.GeneratedCode
|
||||||
|
|
||||||
|
predicate classify(File f, string category) {
|
||||||
|
f instanceof GeneratedCodeFile and category = "generated"
|
||||||
|
}
|
||||||
|
|
||||||
|
from File f, string category
|
||||||
|
where classify(f, category)
|
||||||
|
select f, category
|
||||||
1
ql/test/query-tests/AlertSuppression/.gitattributes
vendored
Normal file
1
ql/test/query-tests/AlertSuppression/.gitattributes
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
TestWindows.java eol=crlf
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
| Test.rb:1:16:1:21 | # lgtm | lgtm | lgtm | Test.rb:1:1:1:21 | suppression range |
|
||||||
|
| Test.rb:2:1:2:32 | # lgtm[rb/confusing-method-name] | lgtm[rb/confusing-method-name] | lgtm[rb/confusing-method-name] | Test.rb:2:1:2:32 | suppression range |
|
||||||
|
| Test.rb:3:1:3:65 | # lgtm[rb/confusing-method-name, rb/non-short-circuit-evaluation] | lgtm[rb/confusing-method-name, rb/non-short-circuit-evaluation] | lgtm[rb/confusing-method-name, rb/non-short-circuit-evaluation] | Test.rb:3:1:3:65 | suppression range |
|
||||||
|
| Test.rb:4:1:4:23 | # lgtm[@tag:exceptions] | lgtm[@tag:exceptions] | lgtm[@tag:exceptions] | Test.rb:4:1:4:23 | suppression range |
|
||||||
|
| Test.rb:5:1:5:48 | # lgtm[@tag:exceptions,rb/confusing-method-name] | lgtm[@tag:exceptions,rb/confusing-method-name] | lgtm[@tag:exceptions,rb/confusing-method-name] | Test.rb:5:1:5:48 | suppression range |
|
||||||
|
| Test.rb:6:1:6:27 | # lgtm[@expires:2017-06-11] | lgtm[@expires:2017-06-11] | lgtm[@expires:2017-06-11] | Test.rb:6:1:6:27 | suppression range |
|
||||||
|
| Test.rb:7:1:7:78 | # lgtm[rb/confusing-method-name] does not seem confusing despite alert by lgtm | lgtm[rb/confusing-method-name] does not seem confusing despite alert by lgtm | lgtm[rb/confusing-method-name] | Test.rb:7:1:7:78 | suppression range |
|
||||||
|
| Test.rb:8:1:8:17 | # lgtm: blah blah | lgtm: blah blah | lgtm | Test.rb:8:1:8:17 | suppression range |
|
||||||
|
| Test.rb:9:1:9:31 | # lgtm blah blah #falsepositive | lgtm blah blah #falsepositive | lgtm | Test.rb:9:1:9:31 | suppression range |
|
||||||
|
| Test.rb:10:1:10:33 | #lgtm [rb/confusing-method-name] | lgtm [rb/confusing-method-name] | lgtm [rb/confusing-method-name] | Test.rb:10:1:10:33 | suppression range |
|
||||||
|
| Test.rb:11:1:11:8 | # lgtm[] | lgtm[] | lgtm[] | Test.rb:11:1:11:8 | suppression range |
|
||||||
|
| Test.rb:13:1:13:5 | #lgtm | lgtm | lgtm | Test.rb:13:1:13:5 | suppression range |
|
||||||
|
| Test.rb:14:1:14:6 | #\tlgtm | \tlgtm | lgtm | Test.rb:14:1:14:6 | suppression range |
|
||||||
|
| Test.rb:15:1:15:33 | # lgtm\t[rb/confusing-method-name] | lgtm\t[rb/confusing-method-name] | lgtm\t[rb/confusing-method-name] | Test.rb:15:1:15:33 | suppression range |
|
||||||
|
| Test.rb:18:1:18:11 | # foo; lgtm | foo; lgtm | lgtm | Test.rb:18:1:18:11 | suppression range |
|
||||||
|
| Test.rb:19:1:19:37 | # foo; lgtm[rb/confusing-method-name] | foo; lgtm[rb/confusing-method-name] | lgtm[rb/confusing-method-name] | Test.rb:19:1:19:37 | suppression range |
|
||||||
|
| Test.rb:21:1:21:36 | # foo lgtm[rb/confusing-method-name] | foo lgtm[rb/confusing-method-name] | lgtm[rb/confusing-method-name] | Test.rb:21:1:21:36 | suppression range |
|
||||||
|
| Test.rb:23:1:23:40 | # foo lgtm[rb/confusing-method-name] bar | foo lgtm[rb/confusing-method-name] bar | lgtm[rb/confusing-method-name] | Test.rb:23:1:23:40 | suppression range |
|
||||||
|
| Test.rb:24:1:24:7 | # LGTM! | LGTM! | LGTM | Test.rb:24:1:24:7 | suppression range |
|
||||||
|
| Test.rb:25:1:25:32 | # LGTM[rb/confusing-method-name] | LGTM[rb/confusing-method-name] | LGTM[rb/confusing-method-name] | Test.rb:25:1:25:32 | suppression range |
|
||||||
|
| Test.rb:26:1:26:73 | #lgtm[rb/confusing-method-name] and lgtm[rb/non-short-circuit-evaluation] | lgtm[rb/confusing-method-name] and lgtm[rb/non-short-circuit-evaluation] | lgtm[rb/confusing-method-name] | Test.rb:26:1:26:73 | suppression range |
|
||||||
|
| Test.rb:26:1:26:73 | #lgtm[rb/confusing-method-name] and lgtm[rb/non-short-circuit-evaluation] | lgtm[rb/confusing-method-name] and lgtm[rb/non-short-circuit-evaluation] | lgtm[rb/non-short-circuit-evaluation] | Test.rb:26:1:26:73 | suppression range |
|
||||||
|
| Test.rb:27:1:27:37 | #lgtm[rb/confusing-method-name]; lgtm | lgtm[rb/confusing-method-name]; lgtm | lgtm | Test.rb:27:1:27:37 | suppression range |
|
||||||
|
| Test.rb:27:1:27:37 | #lgtm[rb/confusing-method-name]; lgtm | lgtm[rb/confusing-method-name]; lgtm | lgtm[rb/confusing-method-name] | Test.rb:27:1:27:37 | suppression range |
|
||||||
|
| TestWindows.rb:1:23:1:29 | # lgtm\r | lgtm\r | lgtm | TestWindows.rb:1:1:1:29 | suppression range |
|
||||||
|
| TestWindows.rb:2:1:2:33 | # lgtm[rb/confusing-method-name]\r | lgtm[rb/confusing-method-name]\r | lgtm[rb/confusing-method-name] | TestWindows.rb:2:1:2:33 | suppression range |
|
||||||
|
| TestWindows.rb:3:1:3:66 | # lgtm[rb/confusing-method-name, rb/non-short-circuit-evaluation]\r | lgtm[rb/confusing-method-name, rb/non-short-circuit-evaluation]\r | lgtm[rb/confusing-method-name, rb/non-short-circuit-evaluation] | TestWindows.rb:3:1:3:66 | suppression range |
|
||||||
|
| TestWindows.rb:4:1:4:24 | # lgtm[@tag:exceptions]\r | lgtm[@tag:exceptions]\r | lgtm[@tag:exceptions] | TestWindows.rb:4:1:4:24 | suppression range |
|
||||||
|
| TestWindows.rb:5:1:5:49 | # lgtm[@tag:exceptions,rb/confusing-method-name]\r | lgtm[@tag:exceptions,rb/confusing-method-name]\r | lgtm[@tag:exceptions,rb/confusing-method-name] | TestWindows.rb:5:1:5:49 | suppression range |
|
||||||
|
| TestWindows.rb:6:1:6:28 | # lgtm[@expires:2017-06-11]\r | lgtm[@expires:2017-06-11]\r | lgtm[@expires:2017-06-11] | TestWindows.rb:6:1:6:28 | suppression range |
|
||||||
|
| TestWindows.rb:7:1:7:79 | # lgtm[rb/confusing-method-name] does not seem confusing despite alert by lgtm\r | lgtm[rb/confusing-method-name] does not seem confusing despite alert by lgtm\r | lgtm[rb/confusing-method-name] | TestWindows.rb:7:1:7:79 | suppression range |
|
||||||
|
| TestWindows.rb:8:1:8:18 | # lgtm: blah blah\r | lgtm: blah blah\r | lgtm | TestWindows.rb:8:1:8:18 | suppression range |
|
||||||
|
| TestWindows.rb:9:1:9:32 | # lgtm blah blah #falsepositive\r | lgtm blah blah #falsepositive\r | lgtm | TestWindows.rb:9:1:9:32 | suppression range |
|
||||||
|
| TestWindows.rb:10:1:10:34 | #lgtm [rb/confusing-method-name]\r | lgtm [rb/confusing-method-name]\r | lgtm [rb/confusing-method-name] | TestWindows.rb:10:1:10:34 | suppression range |
|
||||||
|
| TestWindows.rb:11:1:11:9 | # lgtm[]\r | lgtm[]\r | lgtm[] | TestWindows.rb:11:1:11:9 | suppression range |
|
||||||
|
| TestWindows.rb:13:1:13:6 | #lgtm\r | lgtm\r | lgtm | TestWindows.rb:13:1:13:6 | suppression range |
|
||||||
|
| TestWindows.rb:14:1:14:7 | #\tlgtm\r | \tlgtm\r | lgtm | TestWindows.rb:14:1:14:7 | suppression range |
|
||||||
|
| TestWindows.rb:15:1:15:34 | # lgtm\t[rb/confusing-method-name]\r | lgtm\t[rb/confusing-method-name]\r | lgtm\t[rb/confusing-method-name] | TestWindows.rb:15:1:15:34 | suppression range |
|
||||||
|
| TestWindows.rb:18:1:18:12 | # foo; lgtm\r | foo; lgtm\r | lgtm | TestWindows.rb:18:1:18:12 | suppression range |
|
||||||
|
| TestWindows.rb:19:1:19:38 | # foo; lgtm[rb/confusing-method-name]\r | foo; lgtm[rb/confusing-method-name]\r | lgtm[rb/confusing-method-name] | TestWindows.rb:19:1:19:38 | suppression range |
|
||||||
|
| TestWindows.rb:21:1:21:37 | # foo lgtm[rb/confusing-method-name]\r | foo lgtm[rb/confusing-method-name]\r | lgtm[rb/confusing-method-name] | TestWindows.rb:21:1:21:37 | suppression range |
|
||||||
|
| TestWindows.rb:23:1:23:41 | # foo lgtm[rb/confusing-method-name] bar\r | foo lgtm[rb/confusing-method-name] bar\r | lgtm[rb/confusing-method-name] | TestWindows.rb:23:1:23:41 | suppression range |
|
||||||
|
| TestWindows.rb:24:1:24:8 | # LGTM!\r | LGTM!\r | LGTM | TestWindows.rb:24:1:24:8 | suppression range |
|
||||||
|
| TestWindows.rb:25:1:25:33 | # LGTM[rb/confusing-method-name]\r | LGTM[rb/confusing-method-name]\r | LGTM[rb/confusing-method-name] | TestWindows.rb:25:1:25:33 | suppression range |
|
||||||
|
| TestWindows.rb:26:1:26:74 | #lgtm[rb/confusing-method-name] and lgtm[rb/non-short-circuit-evaluation]\r | lgtm[rb/confusing-method-name] and lgtm[rb/non-short-circuit-evaluation]\r | lgtm[rb/confusing-method-name] | TestWindows.rb:26:1:26:74 | suppression range |
|
||||||
|
| TestWindows.rb:26:1:26:74 | #lgtm[rb/confusing-method-name] and lgtm[rb/non-short-circuit-evaluation]\r | lgtm[rb/confusing-method-name] and lgtm[rb/non-short-circuit-evaluation]\r | lgtm[rb/non-short-circuit-evaluation] | TestWindows.rb:26:1:26:74 | suppression range |
|
||||||
|
| TestWindows.rb:27:1:27:38 | #lgtm[rb/confusing-method-name]; lgtm\r | lgtm[rb/confusing-method-name]; lgtm\r | lgtm | TestWindows.rb:27:1:27:38 | suppression range |
|
||||||
|
| TestWindows.rb:27:1:27:38 | #lgtm[rb/confusing-method-name]; lgtm\r | lgtm[rb/confusing-method-name]; lgtm\r | lgtm[rb/confusing-method-name] | TestWindows.rb:27:1:27:38 | suppression range |
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
AlertSuppression.ql
|
||||||
28
ql/test/query-tests/AlertSuppression/Test.rb
Normal file
28
ql/test/query-tests/AlertSuppression/Test.rb
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
class Test end # lgtm
|
||||||
|
# lgtm[rb/confusing-method-name]
|
||||||
|
# lgtm[rb/confusing-method-name, rb/non-short-circuit-evaluation]
|
||||||
|
# lgtm[@tag:exceptions]
|
||||||
|
# lgtm[@tag:exceptions,rb/confusing-method-name]
|
||||||
|
# lgtm[@expires:2017-06-11]
|
||||||
|
# lgtm[rb/confusing-method-name] does not seem confusing despite alert by lgtm
|
||||||
|
# lgtm: blah blah
|
||||||
|
# lgtm blah blah #falsepositive
|
||||||
|
#lgtm [rb/confusing-method-name]
|
||||||
|
# lgtm[]
|
||||||
|
# lgtmfoo
|
||||||
|
#lgtm
|
||||||
|
# lgtm
|
||||||
|
# lgtm [rb/confusing-method-name]
|
||||||
|
# foolgtm[rb/confusing-method-name]
|
||||||
|
# foolgtm
|
||||||
|
# foo; lgtm
|
||||||
|
# foo; lgtm[rb/confusing-method-name]
|
||||||
|
# foo lgtm
|
||||||
|
# foo lgtm[rb/confusing-method-name]
|
||||||
|
# foo lgtm bar
|
||||||
|
# foo lgtm[rb/confusing-method-name] bar
|
||||||
|
# LGTM!
|
||||||
|
# LGTM[rb/confusing-method-name]
|
||||||
|
#lgtm[rb/confusing-method-name] and lgtm[rb/non-short-circuit-evaluation]
|
||||||
|
#lgtm[rb/confusing-method-name]; lgtm
|
||||||
|
|
||||||
28
ql/test/query-tests/AlertSuppression/TestWindows.rb
Normal file
28
ql/test/query-tests/AlertSuppression/TestWindows.rb
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
class TestWindows end # lgtm
|
||||||
|
# lgtm[rb/confusing-method-name]
|
||||||
|
# lgtm[rb/confusing-method-name, rb/non-short-circuit-evaluation]
|
||||||
|
# lgtm[@tag:exceptions]
|
||||||
|
# lgtm[@tag:exceptions,rb/confusing-method-name]
|
||||||
|
# lgtm[@expires:2017-06-11]
|
||||||
|
# lgtm[rb/confusing-method-name] does not seem confusing despite alert by lgtm
|
||||||
|
# lgtm: blah blah
|
||||||
|
# lgtm blah blah #falsepositive
|
||||||
|
#lgtm [rb/confusing-method-name]
|
||||||
|
# lgtm[]
|
||||||
|
# lgtmfoo
|
||||||
|
#lgtm
|
||||||
|
# lgtm
|
||||||
|
# lgtm [rb/confusing-method-name]
|
||||||
|
# foolgtm[rb/confusing-method-name]
|
||||||
|
# foolgtm
|
||||||
|
# foo; lgtm
|
||||||
|
# foo; lgtm[rb/confusing-method-name]
|
||||||
|
# foo lgtm
|
||||||
|
# foo lgtm[rb/confusing-method-name]
|
||||||
|
# foo lgtm bar
|
||||||
|
# foo lgtm[rb/confusing-method-name] bar
|
||||||
|
# LGTM!
|
||||||
|
# LGTM[rb/confusing-method-name]
|
||||||
|
#lgtm[rb/confusing-method-name] and lgtm[rb/non-short-circuit-evaluation]
|
||||||
|
#lgtm[rb/confusing-method-name]; lgtm
|
||||||
|
|
||||||
Reference in New Issue
Block a user