mirror of
https://github.com/github/codeql.git
synced 2025-12-16 08:43:11 +01:00
Merge pull request #19931 from michaelnebel/ql4ql/qualitytagcheck
Ql4ql: Quality query tagging.
This commit is contained in:
@@ -63,3 +63,8 @@ class File extends Container, Impl::File {
|
||||
/** Holds if this file was extracted from ordinary source code. */
|
||||
predicate fromSource() { any() }
|
||||
}
|
||||
|
||||
/** A test file. */
|
||||
class TestFile extends File {
|
||||
TestFile() { this.getRelativePath().matches("%/" + ["experimental", "examples", "test"] + "/%") }
|
||||
}
|
||||
|
||||
@@ -202,25 +202,43 @@ class QueryDoc extends QLDoc {
|
||||
|
||||
override string getAPrimaryQlClass() { result = "QueryDoc" }
|
||||
|
||||
/** Gets the @kind for the query */
|
||||
/** Gets the @kind for the query. */
|
||||
string getQueryKind() {
|
||||
result = this.getContents().regexpCapture("(?s).*@kind ([\\w-]+)\\s.*", 1)
|
||||
}
|
||||
|
||||
/** Gets the @name for the query */
|
||||
/** Gets the @name for the query. */
|
||||
string getQueryName() {
|
||||
result = this.getContents().regexpCapture("(?s).*@name (.+?)(?=\\n).*", 1)
|
||||
}
|
||||
|
||||
/** Gets the id part (without language) of the @id */
|
||||
/** Gets the id part (without language) of the @id. */
|
||||
string getQueryId() {
|
||||
result = this.getContents().regexpCapture("(?s).*@id (\\w+)/([\\w\\-/]+)\\s.*", 2)
|
||||
}
|
||||
|
||||
/** Gets the language of the @id */
|
||||
/** Gets the language of the @id. */
|
||||
string getQueryLanguage() {
|
||||
result = this.getContents().regexpCapture("(?s).*@id (\\w+)/([\\w\\-/]+)\\s.*", 1)
|
||||
}
|
||||
|
||||
/** Gets the @precision for the query. */
|
||||
string getQueryPrecision() {
|
||||
result = this.getContents().regexpCapture("(?s).*@precision ([\\w\\-]+)\\s.*", 1)
|
||||
}
|
||||
|
||||
/** Gets the @security-severity for the query. */
|
||||
string getQuerySecuritySeverity() {
|
||||
result = this.getContents().regexpCapture("(?s).*@security\\-severity ([\\d\\.]+)\\s.*", 1)
|
||||
}
|
||||
|
||||
/** Gets the individual @tags for the query, if any. */
|
||||
string getAQueryTag() {
|
||||
exists(string tags | tags = this.getContents().regexpCapture("(?s).*@tags ([^@]+)", 1) |
|
||||
result = tags.splitAt("*").trim() and
|
||||
result.regexpMatch("[\\w\\s\\-]+")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class BlockComment extends TBlockComment, Comment {
|
||||
|
||||
52
ql/ql/src/queries/style/MissingQualityMetadata.ql
Normal file
52
ql/ql/src/queries/style/MissingQualityMetadata.ql
Normal file
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* @name Missing quality metadata
|
||||
* @description Quality queries should have exactly one top-level category and if sub-categories are used, the appropriate top-level category should be used.
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @precision very-high
|
||||
* @id ql/missing-quality-metadata
|
||||
* @tags correctness
|
||||
*/
|
||||
|
||||
import ql
|
||||
|
||||
private predicate hasQualityTag(QueryDoc doc) { doc.getAQueryTag() = "quality" }
|
||||
|
||||
private predicate correctTopLevelCategorisation(QueryDoc doc) {
|
||||
strictcount(string s | s = doc.getAQueryTag() and s = ["maintainability", "reliability"]) = 1
|
||||
}
|
||||
|
||||
private predicate reliabilitySubCategory(QueryDoc doc) {
|
||||
doc.getAQueryTag() = ["correctness", "performance", "concurrency", "error-handling"]
|
||||
}
|
||||
|
||||
private predicate maintainabilitySubCategory(QueryDoc doc) {
|
||||
doc.getAQueryTag() = ["readability", "useless-code", "complexity"]
|
||||
}
|
||||
|
||||
from TopLevel t, QueryDoc doc, string msg
|
||||
where
|
||||
doc = t.getQLDoc() and
|
||||
not t.getLocation().getFile() instanceof TestFile and
|
||||
hasQualityTag(doc) and
|
||||
(
|
||||
not correctTopLevelCategorisation(doc) and
|
||||
msg =
|
||||
"This query file has incorrect top-level categorisation. It should have exactly one top-level category, either `@tags maintainability` or `@tags reliability`."
|
||||
or
|
||||
correctTopLevelCategorisation(doc) and
|
||||
(
|
||||
doc.getAQueryTag() = "reliability" and
|
||||
not reliabilitySubCategory(doc) and
|
||||
maintainabilitySubCategory(doc) and
|
||||
msg =
|
||||
"This query file has a sub-category of maintainability but has the `@tags reliability` tag."
|
||||
or
|
||||
doc.getAQueryTag() = "maintainability" and
|
||||
not maintainabilitySubCategory(doc) and
|
||||
reliabilitySubCategory(doc) and
|
||||
msg =
|
||||
"This query file has a sub-category of reliability but has the `@tags maintainability` tag."
|
||||
)
|
||||
)
|
||||
select doc, msg
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @name Missing security metadata
|
||||
* @description Security queries should have both a `@tag security` and a `@security-severity` tag.
|
||||
* @description Security queries should have both a `@tags security` and a `@security-severity` tag.
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @precision very-high
|
||||
@@ -10,45 +10,26 @@
|
||||
|
||||
import ql
|
||||
|
||||
predicate missingSecuritySeverity(QLDoc doc) {
|
||||
exists(string s | s = doc.getContents() |
|
||||
exists(string securityTag | securityTag = s.splitAt("@") |
|
||||
securityTag.matches("tags%security%")
|
||||
) and
|
||||
exists(string precisionTag | precisionTag = s.splitAt("@") |
|
||||
precisionTag.matches("precision %")
|
||||
) and
|
||||
not exists(string securitySeverity | securitySeverity = s.splitAt("@") |
|
||||
securitySeverity.matches("security-severity %")
|
||||
)
|
||||
)
|
||||
predicate missingSecuritySeverity(QueryDoc doc) {
|
||||
doc.getAQueryTag() = "security" and
|
||||
exists(doc.getQueryPrecision()) and
|
||||
not exists(doc.getQuerySecuritySeverity())
|
||||
}
|
||||
|
||||
predicate missingSecurityTag(QLDoc doc) {
|
||||
exists(string s | s = doc.getContents() |
|
||||
exists(string securitySeverity | securitySeverity = s.splitAt("@") |
|
||||
securitySeverity.matches("security-severity %")
|
||||
) and
|
||||
exists(string precisionTag | precisionTag = s.splitAt("@") |
|
||||
precisionTag.matches("precision %")
|
||||
) and
|
||||
not exists(string securityTag | securityTag = s.splitAt("@") |
|
||||
securityTag.matches("tags%security%")
|
||||
)
|
||||
)
|
||||
predicate missingSecurityTag(QueryDoc doc) {
|
||||
exists(doc.getQuerySecuritySeverity()) and
|
||||
exists(doc.getQueryPrecision()) and
|
||||
not doc.getAQueryTag() = "security"
|
||||
}
|
||||
|
||||
from TopLevel t, string msg
|
||||
from TopLevel t, QueryDoc doc, string msg
|
||||
where
|
||||
t.getLocation().getFile().getBaseName().matches("%.ql") and
|
||||
not t.getLocation()
|
||||
.getFile()
|
||||
.getRelativePath()
|
||||
.matches("%/" + ["experimental", "examples", "test"] + "/%") and
|
||||
doc = t.getQLDoc() and
|
||||
not t.getLocation().getFile() instanceof TestFile and
|
||||
(
|
||||
missingSecuritySeverity(t.getQLDoc()) and
|
||||
missingSecuritySeverity(doc) and
|
||||
msg = "This query file is missing a `@security-severity` tag."
|
||||
or
|
||||
missingSecurityTag(t.getQLDoc()) and msg = "This query file is missing a `@tag security`."
|
||||
missingSecurityTag(doc) and msg = "This query file is missing a `@tags security`."
|
||||
)
|
||||
select t, msg
|
||||
select doc, msg
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
| testcases/BadQualityMaintainabilityWrongToplevel.ql:1:1:11:3 | QueryDoc | This query file has a sub-category of reliability but has the `@tags maintainability` tag. |
|
||||
| testcases/BadQualityMultipleTopLevel.ql:1:1:11:3 | QueryDoc | This query file has incorrect top-level categorisation. It should have exactly one top-level category, either `@tags maintainability` or `@tags reliability`. |
|
||||
| testcases/BadQualityNoToplevel.ql:1:1:10:3 | QueryDoc | This query file has incorrect top-level categorisation. It should have exactly one top-level category, either `@tags maintainability` or `@tags reliability`. |
|
||||
| testcases/BadQualityReliabilityWrongToplevel.ql:1:1:11:3 | QueryDoc | This query file has a sub-category of maintainability but has the `@tags reliability` tag. |
|
||||
@@ -0,0 +1 @@
|
||||
queries/style/MissingQualityMetadata.ql
|
||||
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* @name Some query
|
||||
* @description Some description
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @precision very-high
|
||||
* @id ql/quality-query-test
|
||||
* @tags quality
|
||||
* maintainability
|
||||
* error-handling
|
||||
*/
|
||||
|
||||
import ql
|
||||
|
||||
from Class c
|
||||
where none()
|
||||
select c, ""
|
||||
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* @name Some query
|
||||
* @description Some description
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @precision very-high
|
||||
* @id ql/quality-query-test
|
||||
* @tags quality
|
||||
* maintainability
|
||||
* reliability
|
||||
*/
|
||||
|
||||
import ql
|
||||
|
||||
from Class c
|
||||
where none()
|
||||
select c, ""
|
||||
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* @name Some query
|
||||
* @description Some description
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @precision very-high
|
||||
* @id ql/quality-query-test
|
||||
* @tags quality
|
||||
* someothertag
|
||||
*/
|
||||
|
||||
import ql
|
||||
|
||||
from Class c
|
||||
where none()
|
||||
select c, ""
|
||||
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* @name Some query
|
||||
* @description Some description
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @precision very-high
|
||||
* @id ql/quality-query-test
|
||||
* @tags quality
|
||||
* reliability
|
||||
* readability
|
||||
*/
|
||||
|
||||
import ql
|
||||
|
||||
from Class c
|
||||
where none()
|
||||
select c, ""
|
||||
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* @name Some query
|
||||
* @description Some description
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @security-severity 10.0
|
||||
* @precision very-high
|
||||
* @id ql/quality-query-test
|
||||
* @tags security
|
||||
*/
|
||||
|
||||
import ql
|
||||
|
||||
from Class c
|
||||
where none()
|
||||
select c, ""
|
||||
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* @name Some query
|
||||
* @description Some description
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @security-severity 10.0
|
||||
* @precision very-high
|
||||
* @id ql/quality-query-test
|
||||
* @tags quality
|
||||
* maintainability
|
||||
*/
|
||||
|
||||
import ql
|
||||
|
||||
from Class c
|
||||
where none()
|
||||
select c, ""
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* @name Some query
|
||||
* @description Some description
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @precision very-high
|
||||
* @id ql/quality-query-test
|
||||
* @tags quality
|
||||
* maintainability
|
||||
* readability
|
||||
* correctness
|
||||
*/
|
||||
|
||||
import ql
|
||||
|
||||
from Class c
|
||||
where none()
|
||||
select c, ""
|
||||
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* @name Some query
|
||||
* @description Some description
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @precision very-high
|
||||
* @id ql/quality-query-test
|
||||
* @tags quality
|
||||
* maintainability
|
||||
* readability
|
||||
*/
|
||||
|
||||
import ql
|
||||
|
||||
from Class c
|
||||
where none()
|
||||
select c, ""
|
||||
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* @name Some query
|
||||
* @description Some description
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @precision very-high
|
||||
* @id ql/quality-query-test
|
||||
* @tags quality
|
||||
* reliability
|
||||
*/
|
||||
|
||||
import ql
|
||||
|
||||
from Class c
|
||||
where none()
|
||||
select c, ""
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* @name Some query
|
||||
* @description Some description
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @precision very-high
|
||||
* @id ql/quality-query-test
|
||||
* @tags quality
|
||||
* reliability
|
||||
* correctness
|
||||
* readability
|
||||
*/
|
||||
|
||||
import ql
|
||||
|
||||
from Class c
|
||||
where none()
|
||||
select c, ""
|
||||
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* @name Some query
|
||||
* @description Some description
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @precision very-high
|
||||
* @id ql/quality-query-test
|
||||
* @tags quality
|
||||
* reliability
|
||||
* correctness
|
||||
*/
|
||||
|
||||
import ql
|
||||
|
||||
from Class c
|
||||
where none()
|
||||
select c, ""
|
||||
@@ -1,2 +1,2 @@
|
||||
| testcases/BadNoSecurity.ql:1:1:16:9 | TopLevel | This query file is missing a `@tag security`. |
|
||||
| testcases/BadNoSeverity.ql:1:1:16:9 | TopLevel | This query file is missing a `@security-severity` tag. |
|
||||
| testcases/BadNoSecurity.ql:1:1:10:3 | QueryDoc | This query file is missing a `@tags security`. |
|
||||
| testcases/BadNoSeverity.ql:1:1:10:3 | QueryDoc | This query file is missing a `@security-severity` tag. |
|
||||
|
||||
Reference in New Issue
Block a user