Skip to content

Commit e5b5a0d

Browse files
author
Alvaro Muñoz
authored
Merge pull request #39 from github/externally_triggereable_jobs
externally triggereable jobs
2 parents d3bff87 + 5d32071 commit e5b5a0d

File tree

87 files changed

+850
-546
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

87 files changed

+850
-546
lines changed

ql/lib/codeql/actions/Ast.qll

Lines changed: 10 additions & 156 deletions
Original file line numberDiff line numberDiff line change
@@ -1,160 +1,6 @@
11
private import codeql.actions.ast.internal.Ast
22
private import codeql.Locations
3-
4-
module Utils {
5-
bindingset[expr]
6-
string normalizeExpr(string expr) {
7-
result =
8-
expr.regexpReplaceAll("\\['([a-zA-Z0-9_\\*\\-]+)'\\]", ".$1")
9-
.regexpReplaceAll("\\[\"([a-zA-Z0-9_\\*\\-]+)\"\\]", ".$1")
10-
.regexpReplaceAll("\\s*\\.\\s*", ".")
11-
}
12-
13-
bindingset[regex]
14-
string wrapRegexp(string regex) {
15-
result =
16-
[
17-
"\\b" + regex + "\\b", "fromJSON\\(\\s*" + regex + "\\s*\\)",
18-
"toJSON\\(\\s*" + regex + "\\s*\\)"
19-
]
20-
}
21-
22-
bindingset[str]
23-
private string trimQuotes(string str) {
24-
result = str.trim().regexpReplaceAll("^(\"|')", "").regexpReplaceAll("(\"|')$", "")
25-
}
26-
27-
bindingset[line, var]
28-
predicate extractLineAssignment(string line, string var, string key, string value) {
29-
exists(string assignment |
30-
// single line assignment
31-
assignment =
32-
line.regexpCapture("(echo|Write-Output)\\s+(.*)>>\\s*(\"|')?\\$(\\{)?GITHUB_" +
33-
var.toUpperCase() + "(\\})?(\"|')?", 2) and
34-
count(assignment.splitAt("=")) = 2 and
35-
key = trimQuotes(assignment.splitAt("=", 0)) and
36-
value = trimQuotes(assignment.splitAt("=", 1))
37-
or
38-
// workflow command assignment
39-
assignment =
40-
line.regexpCapture("(echo|Write-Output)\\s+(\"|')?::set-" + var.toLowerCase() +
41-
"\\s+name=(.*)(\"|')?", 3).regexpReplaceAll("^\"", "").regexpReplaceAll("\"$", "") and
42-
key = trimQuotes(assignment.splitAt("::", 0)) and
43-
value = trimQuotes(assignment.splitAt("::", 1))
44-
)
45-
}
46-
47-
bindingset[var]
48-
private string multilineAssignmentRegex(string var) {
49-
// eg:
50-
// echo "PR_TITLE<<EOF" >> $GITHUB_ENV
51-
// echo "$TITLE" >> $GITHUB_ENV
52-
// echo "EOF" >> $GITHUB_ENV
53-
result =
54-
".*(echo|Write-Output)\\s+(.*)<<[\\-]*\\s*([A-Z]*)EOF(.+)(echo|Write-Output)\\s+(\"|')?([A-Z]*)EOF(\"|')?\\s*>>\\s*(\"|')?\\$(\\{)?GITHUB_"
55-
+ var.toUpperCase() + "(\\})?(\"|')?.*"
56-
}
57-
58-
bindingset[var]
59-
private string multilineBlockAssignmentRegex(string var) {
60-
// eg:
61-
// {
62-
// echo 'JSON_RESPONSE<<EOF'
63-
// echo "$TITLE" >> "$GITHUB_ENV"
64-
// echo EOF
65-
// } >> "$GITHUB_ENV"
66-
result =
67-
".*\\{(\\s|::NEW_LINE::)*(echo|Write-Output)\\s+(.*)<<[\\-]*\\s*([A-Z]*)EOF(.+)(echo|Write-Output)\\s+(\"|')?([A-Z]*)EOF(\"|')?(\\s|::NEW_LINE::)*\\}\\s*>>\\s*(\"|')?\\$(\\{)?GITHUB_"
68-
+ var.toUpperCase() + "(\\})?(\"|')?.*"
69-
}
70-
71-
bindingset[var]
72-
private string multilineHereDocAssignmentRegex(string var) {
73-
// eg:
74-
// cat <<-EOF >> "$GITHUB_ENV"
75-
// echo "FOO=$TITLE"
76-
// EOF
77-
result =
78-
".*cat\\s*<<[\\-]*\\s*[A-Z]*EOF\\s*>>\\s*[\"']*\\$[\\{]*GITHUB_.*" + var.toUpperCase() +
79-
"[\\}]*[\"']*.*(echo|Write-Output)\\s+([^=]+)=(.*)::NEW_LINE::.*EOF.*"
80-
}
81-
82-
bindingset[script, var]
83-
predicate extractMultilineAssignment(string script, string var, string key, string value) {
84-
// multiline assignment
85-
exists(string flattenedScript |
86-
flattenedScript = script.replaceAll("\n", "::NEW_LINE::") and
87-
value =
88-
"$(" +
89-
trimQuotes(flattenedScript.regexpCapture(multilineAssignmentRegex(var), 4))
90-
.regexpReplaceAll("\\s*>>\\s*(\"|')?\\$(\\{)?GITHUB_" + var.toUpperCase() +
91-
"(\\})?(\"|')?", "")
92-
.replaceAll("::NEW_LINE::", "\n")
93-
.trim()
94-
.splitAt("\n") + ")" and
95-
key = trimQuotes(flattenedScript.regexpCapture(multilineAssignmentRegex(var), 2))
96-
)
97-
or
98-
// multiline block assignment
99-
exists(string flattenedScript |
100-
flattenedScript = script.replaceAll("\n", "::NEW_LINE::") and
101-
value =
102-
"$(" +
103-
trimQuotes(flattenedScript.regexpCapture(multilineBlockAssignmentRegex(var), 5))
104-
.regexpReplaceAll("\\s*>>\\s*(\"|')?\\$(\\{)?GITHUB_" + var.toUpperCase() +
105-
"(\\})?(\"|')?", "")
106-
.replaceAll("::NEW_LINE::", "\n")
107-
.trim()
108-
.splitAt("\n") + ")" and
109-
key = trimQuotes(flattenedScript.regexpCapture(multilineBlockAssignmentRegex(var), 3))
110-
)
111-
or
112-
// multiline heredoc assignment
113-
exists(string flattenedScript |
114-
flattenedScript = script.replaceAll("\n", "::NEW_LINE::") and
115-
value =
116-
trimQuotes(flattenedScript.regexpCapture(multilineHereDocAssignmentRegex(var), 3))
117-
.regexpReplaceAll("\\s*>>\\s*(\"|')?\\$(\\{)?GITHUB_" + var.toUpperCase() +
118-
"(\\})?(\"|')?", "")
119-
.replaceAll("::NEW_LINE::", "\n")
120-
.trim()
121-
.splitAt("\n") and
122-
key = trimQuotes(flattenedScript.regexpCapture(multilineHereDocAssignmentRegex(var), 2))
123-
)
124-
}
125-
126-
bindingset[line]
127-
predicate extractPathAssignment(string line, string value) {
128-
exists(string path |
129-
// single path assignment
130-
path =
131-
line.regexpCapture("(echo|Write-Output)\\s+(.*)>>\\s*(\"|')?\\$(\\{)?GITHUB_PATH(\\})?(\"|')?",
132-
2) and
133-
value = trimQuotes(path)
134-
or
135-
// workflow command assignment
136-
path =
137-
line.regexpCapture("(echo|Write-Output)\\s+(\"|')?::add-path::(.*)(\"|')?", 3)
138-
.regexpReplaceAll("^\"", "")
139-
.regexpReplaceAll("\"$", "") and
140-
value = trimQuotes(path)
141-
)
142-
}
143-
144-
predicate writeToGitHubEnv(Run run, string key, string value) {
145-
extractLineAssignment(run.getScript().splitAt("\n"), "ENV", key, value) or
146-
extractMultilineAssignment(run.getScript(), "ENV", key, value)
147-
}
148-
149-
predicate writeToGitHubOutput(Run run, string key, string value) {
150-
extractLineAssignment(run.getScript().splitAt("\n"), "OUTPUT", key, value) or
151-
extractMultilineAssignment(run.getScript(), "OUTPUT", key, value)
152-
}
153-
154-
predicate writeToGitHubPath(Run run, string value) {
155-
extractPathAssignment(run.getScript().splitAt("\n"), value)
156-
}
157-
}
3+
import codeql.actions.Helper
1584

1595
class AstNode instanceof AstNodeImpl {
1606
AstNode getAChildNode() { result = super.getAChildNode() }
@@ -193,7 +39,7 @@ class Expression extends AstNode instanceof ExpressionImpl {
19339

19440
string getRawExpression() { result = rawExpression }
19541

196-
string getNormalizedExpression() { result = Utils::normalizeExpr(expression) }
42+
string getNormalizedExpression() { result = normalizeExpr(expression) }
19743
}
19844

19945
/** A common class for `env` in workflow, job or step. */
@@ -227,6 +73,10 @@ class CompositeAction extends AstNode instanceof CompositeActionImpl {
22773
Input getAnInput() { result = super.getAnInput() }
22874

22975
Input getInput(string inputName) { result = super.getInput(inputName) }
76+
77+
LocalJob getACaller() { result = super.getACaller() }
78+
79+
predicate isPrivileged() { super.isPrivileged() }
23080
}
23181

23282
/**
@@ -273,6 +123,8 @@ class ReusableWorkflow extends Workflow instanceof ReusableWorkflowImpl {
273123
Input getAnInput() { result = super.getAnInput() }
274124

275125
Input getInput(string inputName) { result = super.getInput(inputName) }
126+
127+
ExternalJob getACaller() { result = super.getACaller() }
276128
}
277129

278130
class Input extends AstNode instanceof InputImpl { }
@@ -348,6 +200,8 @@ abstract class Job extends AstNode instanceof JobImpl {
348200

349201
predicate isPrivileged() { super.isPrivileged() }
350202

203+
predicate isExternallyTriggerable() { super.isExternallyTriggerable() }
204+
351205
string getARunsOnLabel() { result = super.getARunsOnLabel() }
352206
}
353207

0 commit comments

Comments
 (0)