From c7c1aa8045d6c11d82914607b7ed8675e9070930 Mon Sep 17 00:00:00 2001 From: Robert Brignull Date: Thu, 16 Jul 2020 14:54:15 +0100 Subject: [PATCH] fix undeclared action inputs --- analyze/action.yml | 4 +++ queries/undeclared-action-input.ql | 42 ++++++++++++++++++++++++++++-- 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/analyze/action.yml b/analyze/action.yml index fa21a7515..9b950f6fa 100644 --- a/analyze/action.yml +++ b/analyze/action.yml @@ -20,6 +20,10 @@ inputs: description: The number of threads to be used by CodeQL. required: false default: "1" + checkout_path: + description: "The path at which the analyzed repository was checked out. Used to relativeize any absolute paths in the uploaded SARIF file." + required: false + default: ${{ github.workspace }} token: default: ${{ github.token }} matrix: diff --git a/queries/undeclared-action-input.ql b/queries/undeclared-action-input.ql index a8ec7c3f4..71cc9527e 100644 --- a/queries/undeclared-action-input.ql +++ b/queries/undeclared-action-input.ql @@ -9,11 +9,17 @@ import javascript +/** + * A declaration of a github action, including its inputs and entrypoint. + */ class ActionDeclaration extends File { ActionDeclaration() { getRelativePath().matches("%/action.yml") } + /** + * The name of the action. + */ string getName() { result = getRelativePath().regexpCapture("(.*)/action.yml", 1) } @@ -22,10 +28,16 @@ class ActionDeclaration extends File { result.getFile() = this } + /** + * The name of any input to this action. + */ string getAnInput() { result = getRootNode().(YAMLMapping).lookup("inputs").(YAMLMapping).getKey(_).(YAMLString).getValue() } + /** + * The function that is the entrypoint to this action. + */ FunctionDeclStmt getEntrypoint() { result.getFile().getRelativePath() = getRootNode(). (YAMLMapping).lookup("runs"). @@ -35,6 +47,21 @@ class ActionDeclaration extends File { } } +/** + * A function declared on CodeQL interface from codeql.ts + */ +class CodeQLFunction extends Function { + CodeQLFunction() { + exists(Function getCodeQLForCmd, ObjectExpr obj | + getCodeQLForCmd.getName() = "getCodeQLForCmd" and + obj = getCodeQLForCmd.getAStmt().(ReturnStmt).getExpr() and + obj.getAProperty().getInit() = this) + } +} + +/** + * Any expr that is a transitive child of the given function. + */ Expr getAFunctionChildExpr(Function f) { result.getContainer() = f } @@ -45,14 +72,25 @@ Expr getAFunctionChildExpr(Function f) { Function calledBy(Function f) { result = getAFunctionChildExpr(f).(InvokeExpr).getResolvedCallee() or - result.getEnclosingContainer() = f // assume outer function causes inner function to be called + // Assume outer function causes inner function to be called, + // except for the special case of the CodeQL functions. + (result.getEnclosingContainer() = f and not result instanceof CodeQLFunction) + or + // Handle calls to CodeQL functions by name + getAFunctionChildExpr(f).(InvokeExpr).getCalleeName() = result.(CodeQLFunction).getName() } +/** + * A call to the core.getInput method. + */ class GetInputMethodCallExpr extends MethodCallExpr { GetInputMethodCallExpr() { getMethodName() = "getInput" } + /** + * The name of the input being accessed. + */ string getInputName() { result = getArgument(0).(StringLiteral).getValue() } @@ -62,4 +100,4 @@ from ActionDeclaration action, GetInputMethodCallExpr getInputCall, string input where getAFunctionChildExpr(calledBy*(action.getEntrypoint())) = getInputCall and inputName = getInputCall.getInputName() and not inputName = action.getAnInput() -select getInputCall, "The $@ input is not defined for the $@ action", inputName, inputName, action, action.getName() +select getInputCall, "The $@ input is not defined for the $@ action", inputName, inputName, action, action.getName() \ No newline at end of file