Skip to content

Commit 755e78b

Browse files
owen-mcCopilot
andcommitted
Actions: ensure CFG callable scopes are unique
Prefer the composite-action interpretation when a YAML document is recognized as both a workflow and a composite action, ensuring each CFG node has a unique enclosing callable. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 95efef3 commit 755e78b

4 files changed

Lines changed: 54 additions & 2 deletions

File tree

‎actions/ql/lib/codeql/actions/controlflow/internal/Cfg.qll‎

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,14 +93,26 @@ module CfgImpl {
9393
AstNode getChild(AstNode node, int index) { result = getCfgChild(node, index) }
9494

9595
class Callable extends AstNode {
96-
Callable() { this instanceof Workflow or this instanceof CompositeAction }
96+
Callable() {
97+
this instanceof CompositeAction
98+
or
99+
this instanceof Workflow and
100+
not exists(CompositeAction action | action.getLocation() = this.getLocation())
101+
}
97102
}
98103

99104
AstNode callableGetBody(Callable callable) { result = callable }
100105

106+
/**
107+
* Gets the unique callable containing `node`.
108+
*
109+
* An Actions AST node may have multiple parent paths, but they converge on
110+
* the same root.
111+
*/
101112
Callable getEnclosingCallable(AstNode node) {
102-
result = node.(Callable)
113+
result = node
103114
or
115+
not node instanceof Callable and
104116
result = getEnclosingCallable(node.getParentNode())
105117
}
106118

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
name: Ambiguous root
2+
3+
runs:
4+
using: composite
5+
steps:
6+
- run: echo "${{ github.actor }}"
7+
8+
jobs:
9+
unexpected:
10+
runs-on: ubuntu-latest
11+
steps:
12+
- run: echo "This must not make action.yml a workflow"
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
roots
2+
| 1 | 1 |
3+
cfgScopes
4+
| action.yml:1:1:12:61 | name: Ambiguous root | composite action |
5+
cfgConsistency
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import codeql.actions.Ast
2+
import codeql.actions.Cfg as Cfg
3+
4+
query predicate roots(int workflows, int compositeActions) {
5+
workflows =
6+
strictcount(Workflow workflow | workflow.getLocation().getFile().getBaseName() = "action.yml") and
7+
compositeActions =
8+
strictcount(CompositeAction action | action.getLocation().getFile().getBaseName() = "action.yml")
9+
}
10+
11+
query predicate cfgScopes(Cfg::CfgScope scope, string kind) {
12+
scope.getLocation().getFile().getBaseName() = "action.yml" and
13+
(
14+
scope instanceof Cfg::WorkflowScope and kind = "workflow"
15+
or
16+
scope instanceof Cfg::CompositeActionScope and kind = "composite action"
17+
)
18+
}
19+
20+
query predicate cfgConsistency(string query, int results) {
21+
Cfg::Consistency::consistencyOverview(query, results) and
22+
results != 0
23+
}

0 commit comments

Comments
 (0)