Add queries
This commit is contained in:
parent
121fd331cd
commit
d88fa5cef6
2 changed files with 144 additions and 0 deletions
93
queries/required-action-input.ql
Normal file
93
queries/required-action-input.ql
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
/**
|
||||
* @name Required action input
|
||||
* @description For action inputs the core.input represents input with no value as the emptystring.
|
||||
* This doesn't promote good type checking. Instead, use either actions-util.getOptionalInput or
|
||||
* actions-util.getRequiredInput depending on if the input always has a value or not. The input
|
||||
* will always have a value if it is required or has a default value.
|
||||
* @kind problem
|
||||
* @problem.severity error
|
||||
* @id javascript/codeql-action/required-action-input
|
||||
*/
|
||||
|
||||
import javascript
|
||||
|
||||
/**
|
||||
* A declaration of a github action.
|
||||
*/
|
||||
class ActionDeclaration extends File {
|
||||
ActionDeclaration() {
|
||||
getRelativePath().matches("%/action.yml")
|
||||
}
|
||||
|
||||
YAMLDocument getRootNode() {
|
||||
result.getFile() = this
|
||||
}
|
||||
|
||||
/**
|
||||
* The name of any input to this action.
|
||||
*/
|
||||
string getAnInput() {
|
||||
result = getRootNode().(YAMLMapping).lookup("inputs").(YAMLMapping).getKey(_).(YAMLString).getValue()
|
||||
}
|
||||
|
||||
/**
|
||||
* The given input always has a value, either because it is required,
|
||||
* or because it has a default value.
|
||||
*/
|
||||
predicate inputAlwaysHasValue(string input) {
|
||||
exists(YAMLMapping value |
|
||||
value = getRootNode().(YAMLMapping).lookup("inputs").(YAMLMapping).lookup(input) and
|
||||
(exists(value.lookup("default")) or
|
||||
value.lookup("required").(YAMLBool).getBoolValue() = true))
|
||||
}
|
||||
|
||||
/**
|
||||
* The function that is the entrypoint to this action.
|
||||
*/
|
||||
FunctionDeclStmt getEntrypoint() {
|
||||
result.getFile().getRelativePath() = getRootNode().
|
||||
(YAMLMapping).lookup("runs").
|
||||
(YAMLMapping).lookup("main").
|
||||
(YAMLString).getValue().regexpReplaceAll("\\.\\./lib/(.*)\\.js", "src/$1.ts") and
|
||||
result.getName() = "run"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An import from "@actions/core"
|
||||
*/
|
||||
class ActionsLibImport extends ImportDeclaration {
|
||||
ActionsLibImport() {
|
||||
getImportedPath().getValue() = "@actions/core"
|
||||
}
|
||||
|
||||
Variable getAProvidedVariable() {
|
||||
result = getASpecifier().getLocal().getVariable()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to the core.getInput method.
|
||||
*/
|
||||
class CoreGetInputMethodCallExpr extends MethodCallExpr {
|
||||
CoreGetInputMethodCallExpr() {
|
||||
getMethodName() = "getInput" and
|
||||
exists(ActionsLibImport libImport |
|
||||
this.getReceiver() = libImport.getAProvidedVariable().getAnAccess() or
|
||||
this.getReceiver().(PropAccess).getBase() = libImport.getAProvidedVariable().getAnAccess())
|
||||
}
|
||||
|
||||
/**
|
||||
* The name of the input being accessed.
|
||||
*/
|
||||
string getInputName() {
|
||||
result = getArgument(0).(StringLiteral).getValue()
|
||||
}
|
||||
}
|
||||
|
||||
from ActionDeclaration action, CoreGetInputMethodCallExpr getInputCall, string inputName, string alternateFunction
|
||||
where action.getAnInput() = inputName
|
||||
and getInputCall.getInputName() = inputName
|
||||
and ((action.inputAlwaysHasValue(inputName) and alternateFunction = "getRequiredInput")
|
||||
or (not action.inputAlwaysHasValue(inputName) and alternateFunction = "geOptionalInput"))
|
||||
select getInputCall, "This input may be undefined. Please use actions-util.$@ instead.", alternateFunction, alternateFunction
|
||||
Loading…
Add table
Add a link
Reference in a new issue