Skip to content

Commit d6f6e1f

Browse files
author
Alvaro Muñoz
authored
Merge pull request #18 from GitHubSecurityLab/triggers
feat(triggers): New query and support for trigger-based severity decisions
2 parents 4b9cec7 + 3d5567d commit d6f6e1f

13 files changed

+112
-54
lines changed

ql/lib/codeql/actions/Ast.qll

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,12 @@ class AstNode instanceof YamlNode {
2020
* A statement is a group of expressions and/or statements that you design to carry out a task or an action.
2121
* Any statement that can return a value is automatically qualified to be used as an expression.
2222
*/
23-
class Statement extends AstNode { }
23+
class Statement extends AstNode {
24+
/** Gets the workflow that this job is a part of. */
25+
WorkflowStmt getEnclosingWorkflowStmt() {
26+
this = result.getAChildNode*()
27+
}
28+
}
2429

2530
/**
2631
* An expression is any word or group of words or symbols that is a value. In programming, an expression is a value, or anything that executes and ends up being a value.
@@ -53,6 +58,14 @@ class WorkflowStmt extends Statement instanceof Actions::Workflow {
5358
JobStmt getAJobStmt() { result = super.getJob(_) }
5459

5560
JobStmt getJobStmt(string id) { result = super.getJob(id) }
61+
62+
predicate hasTriggerEvent(string trigger) {
63+
exists(YamlNode n | n = super.getOn().(YamlMappingLikeNode).getNode(trigger))
64+
}
65+
66+
string getATriggerEvent() {
67+
exists(YamlNode n | n = super.getOn().(YamlMappingLikeNode).getNode(result))
68+
}
5669
}
5770

5871
class ReusableWorkflowStmt extends WorkflowStmt {
@@ -122,9 +135,6 @@ class JobStmt extends Statement instanceof Actions::Job {
122135
*/
123136
string getId() { result = super.getId() }
124137

125-
/** Gets the workflow that this job is a part of. */
126-
WorkflowStmt getWorkflowStmt() { result = super.getWorkflow() }
127-
128138
/** Gets the step at the given index within this job. */
129139
StepStmt getStepStmt(int index) { result = super.getStep(index) }
130140

@@ -222,7 +232,7 @@ class StepUsesExpr extends StepStmt, UsesExpr {
222232
)
223233
or
224234
exists(Actions::WorkflowEnv env |
225-
env.getWorkflow() = this.getJobStmt().getWorkflowStmt() and
235+
env.getWorkflow() = this.getJobStmt().getEnclosingWorkflowStmt() and
226236
env.(YamlMapping).maps(any(YamlScalar s | s.getValue() = name), result)
227237
)
228238
}
@@ -287,7 +297,7 @@ class JobUsesExpr extends UsesExpr instanceof YamlMapping {
287297
)
288298
or
289299
exists(Actions::WorkflowEnv env |
290-
env.getWorkflow() = this.getJobStmt().getWorkflowStmt() and
300+
env.getWorkflow() = this.getJobStmt().getEnclosingWorkflowStmt() and
291301
env.(YamlMapping).maps(any(YamlScalar s | s.getValue() = name), result)
292302
)
293303
}
@@ -320,7 +330,7 @@ class RunExpr extends StepStmt, Expression {
320330
)
321331
or
322332
exists(Actions::WorkflowEnv env |
323-
env.getWorkflow() = this.getJobStmt().getWorkflowStmt() and
333+
env.getWorkflow() = this.getJobStmt().getEnclosingWorkflowStmt() and
324334
env.(YamlMapping).maps(any(YamlScalar s | s.getValue() = name), result)
325335
)
326336
}

ql/lib/codeql/actions/dataflow/ExternalFlow.qll

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,10 @@ predicate sinkModel(string action, string version, string input, string kind) {
3939
Extensions::sinkModel(action, version, input, kind)
4040
}
4141

42-
predicate externallyDefinedSource(DataFlow::Node source, string sourceType, string fieldName) {
43-
exists(UsesExpr uses, string action, string version, string trigger, string kind |
42+
predicate externallyDefinedSource(
43+
DataFlow::Node source, string sourceType, string fieldName, string trigger
44+
) {
45+
exists(UsesExpr uses, string action, string version, string kind |
4446
sourceModel(action, version, fieldName, trigger, kind) and
4547
uses.getCallee() = action.toLowerCase() and
4648
(

ql/lib/codeql/actions/dataflow/FlowSources.qll

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ abstract class RemoteFlowSource extends SourceNode {
1717
/** Gets a string that describes the type of this remote flow source. */
1818
abstract string getSourceType();
1919

20+
abstract string getATriggerEvent();
21+
2022
override string getThreatModel() { result = "remote" }
2123
}
2224

@@ -109,31 +111,47 @@ private predicate isExternalUserControlledWorkflowRun(string context) {
109111
}
110112

111113
private class EventSource extends RemoteFlowSource {
114+
string trigger;
115+
112116
EventSource() {
113117
exists(ExprAccessExpr e, string context | this.asExpr() = e and context = e.getExpression() |
114-
isExternalUserControlledIssue(context) or
115-
isExternalUserControlledPullRequest(context) or
116-
isExternalUserControlledReview(context) or
117-
isExternalUserControlledComment(context) or
118-
isExternalUserControlledGollum(context) or
119-
isExternalUserControlledCommit(context) or
120-
isExternalUserControlledDiscussion(context) or
121-
isExternalUserControlledWorkflowRun(context)
118+
trigger = ["issues", "issue_comment"] and isExternalUserControlledIssue(context)
119+
or
120+
trigger = ["pull_request_target", "pull_request_review", "pull_request_review_comment"] and
121+
isExternalUserControlledPullRequest(context)
122+
or
123+
trigger = ["pull_request_review"] and isExternalUserControlledReview(context)
124+
or
125+
trigger = ["pull_request_review_comment", "issue_comment", "discussion_comment"] and
126+
isExternalUserControlledComment(context)
127+
or
128+
trigger = ["gollum"] and isExternalUserControlledGollum(context)
129+
or
130+
trigger = ["push"] and isExternalUserControlledCommit(context)
131+
or
132+
trigger = ["discussion", "discussion_comment"] and isExternalUserControlledDiscussion(context)
133+
or
134+
trigger = ["workflow_run"] and isExternalUserControlledWorkflowRun(context)
122135
)
123136
}
124137

125138
override string getSourceType() { result = "User-controlled events" }
139+
140+
override string getATriggerEvent() { result = trigger }
126141
}
127142

128143
/**
129144
* A Source of untrusted data defined in a MaD specification
130145
*/
131146
private class ExternallyDefinedSource extends RemoteFlowSource {
132147
string sourceType;
148+
string trigger;
133149

134-
ExternallyDefinedSource() { externallyDefinedSource(this, sourceType, _) }
150+
ExternallyDefinedSource() { externallyDefinedSource(this, sourceType, _, trigger) }
135151

136152
override string getSourceType() { result = sourceType }
153+
154+
override string getATriggerEvent() { result = trigger }
137155
}
138156

139157
/**
@@ -145,4 +163,6 @@ private class CompositeActionInputSource extends RemoteFlowSource {
145163
CompositeActionInputSource() { c.getInputsStmt().getInputExpr(_) = this.asExpr() }
146164

147165
override string getSourceType() { result = "Composite action input" }
166+
167+
override string getATriggerEvent() { result = "*" }
148168
}

ql/lib/codeql/actions/dataflow/internal/DataFlowPrivate.qll

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) { ppos =
173173
*/
174174
predicate stepsCtxLocalStep(Node nodeFrom, Node nodeTo) {
175175
exists(UsesExpr astFrom, StepsCtxAccessExpr astTo |
176-
externallyDefinedSource(nodeFrom, _, "output." + astTo.getFieldName()) and
176+
externallyDefinedSource(nodeFrom, _, "output." + astTo.getFieldName(), _) and
177177
astFrom = nodeFrom.asExpr() and
178178
astTo = nodeTo.asExpr() and
179179
astTo.getRefExpr() = astFrom
@@ -190,7 +190,7 @@ predicate stepsCtxLocalStep(Node nodeFrom, Node nodeTo) {
190190
*/
191191
predicate needsCtxLocalStep(Node nodeFrom, Node nodeTo) {
192192
exists(UsesExpr astFrom, NeedsCtxAccessExpr astTo |
193-
externallyDefinedSource(nodeFrom, _, "output." + astTo.getFieldName()) and
193+
externallyDefinedSource(nodeFrom, _, "output." + astTo.getFieldName(), _) and
194194
astFrom = nodeFrom.asExpr() and
195195
astTo = nodeTo.asExpr() and
196196
astTo.getRefExpr() = astFrom
@@ -218,7 +218,7 @@ predicate envCtxLocalStep(Node nodeFrom, Node nodeTo) {
218218
astFrom = nodeFrom.asExpr() and
219219
astTo = nodeTo.asExpr() and
220220
(
221-
externallyDefinedSource(nodeFrom, _, "env." + astTo.getFieldName()) or
221+
externallyDefinedSource(nodeFrom, _, "env." + astTo.getFieldName(), _) or
222222
astTo.getRefExpr() = astFrom
223223
)
224224
)

ql/lib/ext/ahmadnassri_action-changed-files.model.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,5 @@ extensions:
33
pack: githubsecuritylab/actions-all
44
extensible: sourceModel
55
data:
6-
- ["ahmadnassri/action-changed-files", "*", "output.files", "pull_request", "PR changed files"]
76
- ["ahmadnassri/action-changed-files", "*", "output.files", "pull_request_target", "PR changed files"]
8-
- ["ahmadnassri/action-changed-files", "*", "output.json", "pull_request", "PR changed files"]
97
- ["ahmadnassri/action-changed-files", "*", "output.json", "pull_request_target", "PR changed files"]

ql/lib/ext/dorny_paths-filter.model.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,4 @@ extensions:
33
pack: githubsecuritylab/actions-all
44
extensible: sourceModel
55
data:
6-
- ["dorny/paths-filter", "*", "output.changes", "pull_request", "PR changed files"]
76
- ["dorny/paths-filter", "*", "output.changes", "pull_request_target", "PR changed files"]

ql/lib/ext/jitterbit_get-changed-files.model.yml

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,10 @@ extensions:
33
pack: githubsecuritylab/actions-all
44
extensible: sourceModel
55
data:
6-
- ["jitterbit/get-changed-files", "*", "output.all", "pull_request", "PR changed files"]
76
- ["jitterbit/get-changed-files", "*", "output.all", "pull_request_target", "PR changed files"]
8-
- ["jitterbit/get-changed-files", "*", "output.added", "pull_request", "PR changed files"]
97
- ["jitterbit/get-changed-files", "*", "output.added", "pull_request_target", "PR changed files"]
10-
- ["jitterbit/get-changed-files", "*", "output.modified", "pull_request", "PR changed files"]
118
- ["jitterbit/get-changed-files", "*", "output.modified", "pull_request_target", "PR changed files"]
12-
- ["jitterbit/get-changed-files", "*", "output.removed", "pull_request", "PR changed files"]
139
- ["jitterbit/get-changed-files", "*", "output.removed", "pull_request_target", "PR changed files"]
14-
- ["jitterbit/get-changed-files", "*", "output.renamed", "pull_request", "PR changed files"]
1510
- ["jitterbit/get-changed-files", "*", "output.renamed", "pull_request_target", "PR changed files"]
16-
- ["jitterbit/get-changed-files", "*", "output.added_modified", "pull_request", "PR changed files"]
1711
- ["jitterbit/get-changed-files", "*", "output.added_modified", "pull_request_target", "PR changed files"]
18-
- ["jitterbit/get-changed-files", "*", "output.deleted", "pull_request", "PR changed files"]
1912
- ["jitterbit/get-changed-files", "*", "output.deleted", "pull_request_target", "PR changed files"]
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
extensions:
2+
- addsTo:
3+
pack: githubsecuritylab/actions-all
4+
extensible: sourceModel
5+
data:
6+
# https://github.com/tj-actions/branch-names
7+
- ["tj-actions/branch-names", "*", "output.current_branch", "pull_request_target", "PR current branch"]
8+
- ["tj-actions/branch-names", "*", "output.head_ref_branch", "pull_request_target", "PR head branch"]
9+
- ["tj-actions/branch-names", "*", "output.ref_branch", "pull_request_target", "Branch tirggering workflow run"]
10+

ql/lib/ext/tj-actions_changed-files.model.yml

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,37 +3,20 @@ extensions:
33
pack: githubsecuritylab/actions-all
44
extensible: sourceModel
55
data:
6-
- ["tj-actions/changed-files", "*", "output.added_files", "pull_request", "PR changed files"]
76
- ["tj-actions/changed-files", "*", "output.added_files", "pull_request_target", "PR changed files"]
8-
- ["tj-actions/changed-files", "*", "output.copied_files", "pull_request", "PR changed files"]
97
- ["tj-actions/changed-files", "*", "output.copied_files", "pull_request_target", "PR changed files"]
10-
- ["tj-actions/changed-files", "*", "output.deleted_files", "pull_request", "PR changed files"]
118
- ["tj-actions/changed-files", "*", "output.deleted_files", "pull_request_target", "PR changed files"]
12-
- ["tj-actions/changed-files", "*", "output.modified_files", "pull_request", "PR changed files"]
139
- ["tj-actions/changed-files", "*", "output.modified_files", "pull_request_target", "PR changed files"]
14-
- ["tj-actions/changed-files", "*", "output.renamed_files", "pull_request", "PR changed files"]
1510
- ["tj-actions/changed-files", "*", "output.renamed_files", "pull_request_target", "PR changed files"]
16-
- ["tj-actions/changed-files", "*", "output.all_old_new_renamed_files", "pull_request", "PR changed files"]
1711
- ["tj-actions/changed-files", "*", "output.all_old_new_renamed_files", "pull_request_target", "PR changed files"]
18-
- ["tj-actions/changed-files", "*", "output.type_changed_files", "pull_request", "PR changed files"]
1912
- ["tj-actions/changed-files", "*", "output.type_changed_files", "pull_request_target", "PR changed files"]
20-
- ["tj-actions/changed-files", "*", "output.unmerged_files", "pull_request", "PR changed files"]
2113
- ["tj-actions/changed-files", "*", "output.unmerged_files", "pull_request_target", "PR changed files"]
22-
- ["tj-actions/changed-files", "*", "output.unknown_files", "pull_request", "PR changed files"]
2314
- ["tj-actions/changed-files", "*", "output.unknown_files", "pull_request_target", "PR changed files"]
24-
- ["tj-actions/changed-files", "*", "output.all_changed_and_modified_files", "pull_request", "PR changed files"]
2515
- ["tj-actions/changed-files", "*", "output.all_changed_and_modified_files", "pull_request_target", "PR changed files"]
26-
- ["tj-actions/changed-files", "*", "output.all_changed_files", "pull_request", "PR changed files"]
2716
- ["tj-actions/changed-files", "*", "output.all_changed_files", "pull_request_target", "PR changed files"]
28-
- ["tj-actions/changed-files", "*", "output.other_changed_files", "pull_request", "PR changed files"]
2917
- ["tj-actions/changed-files", "*", "output.other_changed_files", "pull_request_target", "PR changed files"]
30-
- ["tj-actions/changed-files", "*", "output.all_modified_files", "pull_request", "PR changed files"]
3118
- ["tj-actions/changed-files", "*", "output.all_modified_files", "pull_request_target", "PR changed files"]
32-
- ["tj-actions/changed-files", "*", "output.other_modified_files", "pull_request", "PR changed files"]
3319
- ["tj-actions/changed-files", "*", "output.other_modified_files", "pull_request_target", "PR changed files"]
34-
- ["tj-actions/changed-files", "*", "output.other_deleted_files", "pull_request", "PR changed files"]
3520
- ["tj-actions/changed-files", "*", "output.other_deleted_files", "pull_request_target", "PR changed files"]
36-
- ["tj-actions/changed-files", "*", "output.modified_keys", "pull_request", "PR changed files"]
3721
- ["tj-actions/changed-files", "*", "output.modified_keys", "pull_request_target", "PR changed files"]
38-
- ["tj-actions/changed-files", "*", "output.changed_keys", "pull_request", "PR changed files"]
3922
- ["tj-actions/changed-files", "*", "output.changed_keys", "pull_request_target", "PR changed files"]

ql/lib/ext/tj-actions_verify-changed-files.model.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,4 @@ extensions:
33
pack: githubsecuritylab/actions-all
44
extensible: sourceModel
55
data:
6-
- ["tj-actions/verify-changed-files", "*", "output.changed-files", "pull_request", "PR changed files"]
76
- ["tj-actions/verify-changed-files", "*", "output.changed-files", "pull_request_target", "PR changed files"]

0 commit comments

Comments
 (0)