Skip to content

Commit f92a680

Browse files
add query to detect use of actions libs
1 parent e9efcf1 commit f92a680

1 file changed

Lines changed: 108 additions & 0 deletions

File tree

queries/unguarded-action-lib.ql

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/**
2+
* @name Unguarded actions library use
3+
* @description Code that runs outside of GitHub Actions tries to use a library that should only be used when running on actions.
4+
* @kind problem
5+
* @problem.severity error
6+
* @id javascript/codeql-action/unguarded-action-lib
7+
*/
8+
9+
import javascript
10+
11+
/**
12+
* An import from a library that is meant for GitHub Actions and
13+
* we do not want to be using outside of actions.
14+
*/
15+
class ActionsLibImport extends ImportDeclaration {
16+
ActionsLibImport() {
17+
getImportedPath().getValue().matches("@actions/%")
18+
}
19+
20+
string getName() {
21+
result = getImportedPath().getValue()
22+
}
23+
24+
Variable getAProvidedVariable() {
25+
result = getASpecifier().getLocal().getVariable()
26+
}
27+
}
28+
29+
/**
30+
* An entrypoint to the CLI.
31+
*/
32+
class ClIEntrypoint extends Function {
33+
ClIEntrypoint() {
34+
getFile().getAbsolutePath().matches("%/cli.ts")
35+
}
36+
}
37+
38+
/**
39+
* A check of whether we are in actions mode or CLI mode.
40+
*/
41+
class ModeGuard extends IfStmt {
42+
ModeGuard() {
43+
getCondition().(EqualityTest).getAnOperand().(StringLiteral).getValue() = "actions" or
44+
getCondition().(EqualityTest).getAnOperand().(StringLiteral).getValue() = "cli"
45+
}
46+
47+
string getOperand() {
48+
result = getCondition().(EqualityTest).getAnOperand().(StringLiteral).getValue()
49+
}
50+
51+
predicate isPositive() {
52+
getCondition().(EqualityTest).getPolarity() = true
53+
}
54+
55+
/**
56+
* Get the then or else block that is the "actions" path.
57+
*/
58+
Stmt getActionsBlock() {
59+
(getOperand() = "actions" and isPositive() and result = getThen())
60+
or
61+
(getOperand() = "cli" and not isPositive() and result = getThen())
62+
or
63+
(getOperand() = "actions" and not isPositive() and result = getElse())
64+
or
65+
(getOperand() = "cli" and isPositive() and result = getElse())
66+
}
67+
68+
/**
69+
* Get an expr that is only executed on actions
70+
*/
71+
Expr getAnActionsExpr() {
72+
getActionsBlock().getAChildStmt*().getAChildExpr*() = result
73+
}
74+
}
75+
76+
/**
77+
* Any expr that is a transitive child of the given function
78+
* and is not only called on actions.
79+
*/
80+
Expr getAFunctionChildExpr(Function f) {
81+
not exists(ModeGuard guard | guard.getAnActionsExpr() = result) and
82+
result.getContainer() = f
83+
}
84+
85+
/*
86+
* Result is a function that is called from the body of the given function `f`
87+
* and is not only called on actions.
88+
*/
89+
Function calledBy(Function f) {
90+
exists(InvokeExpr invokeExpr |
91+
invokeExpr = getAFunctionChildExpr(f) and
92+
invokeExpr.getResolvedCallee() = result and
93+
not exists(ModeGuard guard | guard.getAnActionsExpr() = invokeExpr)
94+
)
95+
or
96+
// Assume outer function causes inner function to be called
97+
(result instanceof Expr and
98+
result.getEnclosingContainer() = f and
99+
not exists(ModeGuard guard | guard.getAnActionsExpr() = result))
100+
}
101+
102+
from VarAccess v, ActionsLibImport actionsLib, ClIEntrypoint cliEntry
103+
where actionsLib.getAProvidedVariable() = v.getVariable()
104+
and getAFunctionChildExpr(calledBy*(cliEntry)) = v
105+
select v, "$@ is imported from $@ and this code can be called from $@",
106+
v, v.getName(),
107+
actionsLib, actionsLib.getName(),
108+
cliEntry, "the CLI"

0 commit comments

Comments
 (0)