diff --git a/actions/ql/lib/change-notes/2026-07-22-environment-check-sanitizer-mad.md b/actions/ql/lib/change-notes/2026-07-22-environment-check-sanitizer-mad.md new file mode 100644 index 000000000000..ef901cdc7603 --- /dev/null +++ b/actions/ql/lib/change-notes/2026-07-22-environment-check-sanitizer-mad.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Added an option to `EnvironmentCheck` to become specified by a MaD model, otherwise it will continue as the default it previously was. Without adding models to `actions/ql/lib/ext/config/deployment_environment.yml` the behavior of every query will be unchanged. When models are added queries using `ControlCheck` may find more results in cases where an enironment is no longer a sufficient sanitizer. \ No newline at end of file diff --git a/actions/ql/lib/codeql/actions/config/Config.qll b/actions/ql/lib/codeql/actions/config/Config.qll index e6359c142582..27e24514c091 100644 --- a/actions/ql/lib/codeql/actions/config/Config.qll +++ b/actions/ql/lib/codeql/actions/config/Config.qll @@ -164,3 +164,12 @@ predicate untrustedGhCommandDataModel(string cmd_regex, string flag) { predicate actionsPermissionsDataModel(string action, string permission) { Extensions::actionsPermissionsDataModel(action, permission) } + +/** + * MaD models for deployment environments + * Fields: + * - name: deployment environment name, e.g. `Public CI` + */ +predicate enabledDeploymentEnvironmentDataModel(string name) { + Extensions::enabledDeploymentEnvironmentDataModel(name) +} diff --git a/actions/ql/lib/codeql/actions/config/ConfigExtensions.qll b/actions/ql/lib/codeql/actions/config/ConfigExtensions.qll index 87a919359404..4ee438fc63cb 100644 --- a/actions/ql/lib/codeql/actions/config/ConfigExtensions.qll +++ b/actions/ql/lib/codeql/actions/config/ConfigExtensions.qll @@ -88,3 +88,12 @@ extensible predicate untrustedGhCommandDataModel(string cmd_regex, string flag); * - see https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/controlling-permissions-for-github_token for documentation of token permissions. */ extensible predicate actionsPermissionsDataModel(string action, string permission); + +/** + * Holds for deployment environments that exist with `name` for a given repository. + * * - 'name' is the name of the environment defined. + * E.g. for the deployment environment `environment: EnvironmentInRepo`, `name` is `EnvironmentInRepo`. + * Requires this to be externally supplied but once done can be used to + * toggle precision of whether that suffices or not as a control check by contributing to `EnvironmentCheck`. + */ +extensible predicate enabledDeploymentEnvironmentDataModel(string name); diff --git a/actions/ql/lib/codeql/actions/security/ControlChecks.qll b/actions/ql/lib/codeql/actions/security/ControlChecks.qll index 4d3dbc38c657..7bde120e432a 100644 --- a/actions/ql/lib/codeql/actions/security/ControlChecks.qll +++ b/actions/ql/lib/codeql/actions/security/ControlChecks.qll @@ -277,6 +277,13 @@ abstract class LabelCheck extends ControlCheck { } class EnvironmentCheck extends ControlCheck instanceof Environment { + EnvironmentCheck() { + // if there are any custom tuples use those + if enabledDeploymentEnvironmentDataModel(_) + then enabledDeploymentEnvironmentDataModel(this.(Environment).getName()) + else this instanceof Environment + } + // Environment checks are not effective against any mutable attacks // they do actually protect against untrusted code execution (sha) override predicate protectsCategoryAndEvent(string category, string event) { diff --git a/actions/ql/lib/ext/config/deployment_environment.yml b/actions/ql/lib/ext/config/deployment_environment.yml new file mode 100644 index 000000000000..eed2911c2758 --- /dev/null +++ b/actions/ql/lib/ext/config/deployment_environment.yml @@ -0,0 +1,5 @@ +extensions: + - addsTo: + pack: codeql/actions-all + extensible: enabledDeploymentEnvironmentDataModel + data: [] \ No newline at end of file diff --git a/actions/ql/test/library-tests/basic/.github/workflows/controlcheck.yml b/actions/ql/test/library-tests/basic/.github/workflows/controlcheck.yml new file mode 100644 index 000000000000..bd8ba15784b4 --- /dev/null +++ b/actions/ql/test/library-tests/basic/.github/workflows/controlcheck.yml @@ -0,0 +1,16 @@ +on: + pull_request_target: + types: [Created] +jobs: + test1: + environment: EnvironmentInRepo + runs-on: ubuntu-latest + steps: + - name: Test 1 + run: echo "test1" + test2: + environment: EnvironmentNotInRepo + runs-on: ubuntu-latest + steps: + - name: Test 2 + run: echo "test2" \ No newline at end of file diff --git a/actions/ql/test/library-tests/basic/commands.expected b/actions/ql/test/library-tests/basic/commands.expected index 82ea1739b28a..adbcdb5a40a7 100644 --- a/actions/ql/test/library-tests/basic/commands.expected +++ b/actions/ql/test/library-tests/basic/commands.expected @@ -16,6 +16,8 @@ | .github/workflows/commands.yml:28:9:31:2 | Run Step | wc -l | | .github/workflows/commands.yml:34:9:37:6 | Run Step | command1 | | .github/workflows/commands.yml:34:9:37:6 | Run Step | command2 | +| .github/workflows/controlcheck.yml:9:9:11:2 | Run Step | echo "test1" | +| .github/workflows/controlcheck.yml:15:9:16:25 | Run Step | echo "test2" | | .github/workflows/expression_nodes.yml:7:9:8:6 | Run Step | LINE 1echo '${{ github.event.comment.body }}' | | .github/workflows/expression_nodes.yml:8:9:10:6 | Run Step | LINE 1 echo '${{ github.event.comment.body }}' | | .github/workflows/expression_nodes.yml:10:9:13:6 | Run Step | LINE 1 echo '${{ github.event.comment.body }}' | diff --git a/actions/ql/test/library-tests/basic/controlchecktest.expected b/actions/ql/test/library-tests/basic/controlchecktest.expected new file mode 100644 index 000000000000..ac2f7ac38aa1 --- /dev/null +++ b/actions/ql/test/library-tests/basic/controlchecktest.expected @@ -0,0 +1 @@ +| .github/workflows/controlcheck.yml:6:18:6:34 | EnvironmentInRepo | diff --git a/actions/ql/test/library-tests/basic/controlchecktest.ext.yml b/actions/ql/test/library-tests/basic/controlchecktest.ext.yml new file mode 100644 index 000000000000..96ded8ff2b2c --- /dev/null +++ b/actions/ql/test/library-tests/basic/controlchecktest.ext.yml @@ -0,0 +1,8 @@ +extensions: + - addsTo: + pack: codeql/actions-all + extensible: enabledDeploymentEnvironmentDataModel + data: + # assumed to exist in a repo where controlcheck.yml exists + # realistically would need to be manually/externally provided + - ["EnvironmentInRepo"] \ No newline at end of file diff --git a/actions/ql/test/library-tests/basic/controlchecktest.ql b/actions/ql/test/library-tests/basic/controlchecktest.ql new file mode 100644 index 000000000000..1daba58fe749 --- /dev/null +++ b/actions/ql/test/library-tests/basic/controlchecktest.ql @@ -0,0 +1,5 @@ +import actions +import codeql.actions.security.ControlChecks + +from ControlCheck c +select c diff --git a/actions/ql/test/library-tests/basic/test.expected b/actions/ql/test/library-tests/basic/test.expected index 4de3336aba7b..7c1c560c87e1 100644 --- a/actions/ql/test/library-tests/basic/test.expected +++ b/actions/ql/test/library-tests/basic/test.expected @@ -1,5 +1,6 @@ files | .github/workflows/commands.yml:0:0:0:0 | .github/workflows/commands.yml | +| .github/workflows/controlcheck.yml:0:0:0:0 | .github/workflows/controlcheck.yml | | .github/workflows/expression_nodes.yml:0:0:0:0 | .github/workflows/expression_nodes.yml | | .github/workflows/many_strings.yml:0:0:0:0 | .github/workflows/many_strings.yml | | .github/workflows/multiline2.yml:0:0:0:0 | .github/workflows/multiline2.yml | @@ -7,8 +8,10 @@ files | .github/workflows/poisonable_steps.yml:0:0:0:0 | .github/workflows/poisonable_steps.yml | | .github/workflows/shell.yml:0:0:0:0 | .github/workflows/shell.yml | | .github/workflows/test.yml:0:0:0:0 | .github/workflows/test.yml | +| controlchecktest.ext.yml:0:0:0:0 | controlchecktest.ext.yml | workflows | .github/workflows/commands.yml:1:1:39:30 | on: push | +| .github/workflows/controlcheck.yml:1:1:16:25 | on: | | .github/workflows/expression_nodes.yml:1:1:21:47 | on: issue_comment | | .github/workflows/many_strings.yml:1:1:18:1211 | on: | | .github/workflows/multiline2.yml:1:1:89:35 | on: | @@ -21,6 +24,8 @@ compositeActions jobs | .github/workflows/commands.yml:9:5:31:2 | Job: local_commands | | .github/workflows/commands.yml:32:5:39:30 | Job: local_commands2 | +| .github/workflows/controlcheck.yml:6:5:11:2 | Job: test1 | +| .github/workflows/controlcheck.yml:12:5:16:25 | Job: test2 | | .github/workflows/expression_nodes.yml:5:5:21:47 | Job: echo-chamber | | .github/workflows/many_strings.yml:9:5:18:1211 | Job: Test | | .github/workflows/multiline2.yml:9:5:89:35 | Job: Test | @@ -35,6 +40,8 @@ jobs localJobs | .github/workflows/commands.yml:9:5:31:2 | Job: local_commands | | .github/workflows/commands.yml:32:5:39:30 | Job: local_commands2 | +| .github/workflows/controlcheck.yml:6:5:11:2 | Job: test1 | +| .github/workflows/controlcheck.yml:12:5:16:25 | Job: test2 | | .github/workflows/expression_nodes.yml:5:5:21:47 | Job: echo-chamber | | .github/workflows/many_strings.yml:9:5:18:1211 | Job: Test | | .github/workflows/multiline2.yml:9:5:89:35 | Job: Test | @@ -57,6 +64,8 @@ steps | .github/workflows/commands.yml:28:9:31:2 | Run Step | | .github/workflows/commands.yml:34:9:37:6 | Run Step | | .github/workflows/commands.yml:37:9:39:30 | Run Step | +| .github/workflows/controlcheck.yml:9:9:11:2 | Run Step | +| .github/workflows/controlcheck.yml:15:9:16:25 | Run Step | | .github/workflows/expression_nodes.yml:7:9:8:6 | Run Step | | .github/workflows/expression_nodes.yml:8:9:10:6 | Run Step | | .github/workflows/expression_nodes.yml:10:9:13:6 | Run Step | @@ -180,6 +189,10 @@ runStepChildren | .github/workflows/commands.yml:34:9:37:6 | Run Step | .github/workflows/commands.yml:35:14:36:30 | command1 ; command2\n | | .github/workflows/commands.yml:37:9:39:30 | Run Step | .github/workflows/commands.yml:37:16:37:19 | pwsh | | .github/workflows/commands.yml:37:9:39:30 | Run Step | .github/workflows/commands.yml:38:14:39:30 | command3 \| command4\n | +| .github/workflows/controlcheck.yml:9:9:11:2 | Run Step | .github/workflows/controlcheck.yml:9:15:9:20 | Test 1 | +| .github/workflows/controlcheck.yml:9:9:11:2 | Run Step | .github/workflows/controlcheck.yml:10:14:10:25 | echo "test1" | +| .github/workflows/controlcheck.yml:15:9:16:25 | Run Step | .github/workflows/controlcheck.yml:15:15:15:20 | Test 2 | +| .github/workflows/controlcheck.yml:15:9:16:25 | Run Step | .github/workflows/controlcheck.yml:16:14:16:25 | echo "test2" | | .github/workflows/expression_nodes.yml:7:9:8:6 | Run Step | .github/workflows/expression_nodes.yml:7:14:7:58 | LINE 1echo '${{ github.event.comment.body }}' | | .github/workflows/expression_nodes.yml:8:9:10:6 | Run Step | .github/workflows/expression_nodes.yml:8:14:9:57 | LINE 1 echo '${{ github.event.comment.body }}'\n | | .github/workflows/expression_nodes.yml:10:9:13:6 | Run Step | .github/workflows/expression_nodes.yml:10:14:12:53 | LINE 1 echo '${{ github.event.comment.body }}'\nLINE 2 echo '${{github.event.issue.body}}'\n | @@ -347,6 +360,43 @@ parentNodes | .github/workflows/commands.yml:38:14:39:30 | command3 \| command4\n | .github/workflows/commands.yml:1:1:39:30 | on: push | | .github/workflows/commands.yml:38:14:39:30 | command3 \| command4\n | .github/workflows/commands.yml:32:5:39:30 | Job: local_commands2 | | .github/workflows/commands.yml:38:14:39:30 | command3 \| command4\n | .github/workflows/commands.yml:37:9:39:30 | Run Step | +| .github/workflows/controlcheck.yml:2:3:2:21 | pull_request_target | .github/workflows/controlcheck.yml:2:3:3:21 | pull_request_target: | +| .github/workflows/controlcheck.yml:2:3:3:21 | pull_request_target: | .github/workflows/controlcheck.yml:1:1:16:25 | on: | +| .github/workflows/controlcheck.yml:3:13:3:19 | Created | .github/workflows/controlcheck.yml:1:1:16:25 | on: | +| .github/workflows/controlcheck.yml:3:13:3:19 | Created | .github/workflows/controlcheck.yml:2:3:2:21 | pull_request_target | +| .github/workflows/controlcheck.yml:3:13:3:19 | Created | .github/workflows/controlcheck.yml:2:3:3:21 | pull_request_target: | +| .github/workflows/controlcheck.yml:6:5:11:2 | Job: test1 | .github/workflows/controlcheck.yml:1:1:16:25 | on: | +| .github/workflows/controlcheck.yml:6:18:6:34 | EnvironmentInRepo | .github/workflows/controlcheck.yml:1:1:16:25 | on: | +| .github/workflows/controlcheck.yml:6:18:6:34 | EnvironmentInRepo | .github/workflows/controlcheck.yml:1:1:16:25 | on: | +| .github/workflows/controlcheck.yml:6:18:6:34 | EnvironmentInRepo | .github/workflows/controlcheck.yml:6:5:11:2 | Job: test1 | +| .github/workflows/controlcheck.yml:6:18:6:34 | EnvironmentInRepo | .github/workflows/controlcheck.yml:6:5:11:2 | Job: test1 | +| .github/workflows/controlcheck.yml:6:18:6:34 | EnvironmentInRepo | .github/workflows/controlcheck.yml:6:18:6:34 | EnvironmentInRepo | +| .github/workflows/controlcheck.yml:6:18:6:34 | EnvironmentInRepo | .github/workflows/controlcheck.yml:6:18:6:34 | EnvironmentInRepo | +| .github/workflows/controlcheck.yml:7:14:7:26 | ubuntu-latest | .github/workflows/controlcheck.yml:1:1:16:25 | on: | +| .github/workflows/controlcheck.yml:7:14:7:26 | ubuntu-latest | .github/workflows/controlcheck.yml:6:5:11:2 | Job: test1 | +| .github/workflows/controlcheck.yml:9:9:11:2 | Run Step | .github/workflows/controlcheck.yml:6:5:11:2 | Job: test1 | +| .github/workflows/controlcheck.yml:9:15:9:20 | Test 1 | .github/workflows/controlcheck.yml:1:1:16:25 | on: | +| .github/workflows/controlcheck.yml:9:15:9:20 | Test 1 | .github/workflows/controlcheck.yml:6:5:11:2 | Job: test1 | +| .github/workflows/controlcheck.yml:9:15:9:20 | Test 1 | .github/workflows/controlcheck.yml:9:9:11:2 | Run Step | +| .github/workflows/controlcheck.yml:10:14:10:25 | echo "test1" | .github/workflows/controlcheck.yml:1:1:16:25 | on: | +| .github/workflows/controlcheck.yml:10:14:10:25 | echo "test1" | .github/workflows/controlcheck.yml:6:5:11:2 | Job: test1 | +| .github/workflows/controlcheck.yml:10:14:10:25 | echo "test1" | .github/workflows/controlcheck.yml:9:9:11:2 | Run Step | +| .github/workflows/controlcheck.yml:12:5:16:25 | Job: test2 | .github/workflows/controlcheck.yml:1:1:16:25 | on: | +| .github/workflows/controlcheck.yml:12:18:12:37 | EnvironmentNotInRepo | .github/workflows/controlcheck.yml:1:1:16:25 | on: | +| .github/workflows/controlcheck.yml:12:18:12:37 | EnvironmentNotInRepo | .github/workflows/controlcheck.yml:1:1:16:25 | on: | +| .github/workflows/controlcheck.yml:12:18:12:37 | EnvironmentNotInRepo | .github/workflows/controlcheck.yml:12:5:16:25 | Job: test2 | +| .github/workflows/controlcheck.yml:12:18:12:37 | EnvironmentNotInRepo | .github/workflows/controlcheck.yml:12:5:16:25 | Job: test2 | +| .github/workflows/controlcheck.yml:12:18:12:37 | EnvironmentNotInRepo | .github/workflows/controlcheck.yml:12:18:12:37 | EnvironmentNotInRepo | +| .github/workflows/controlcheck.yml:12:18:12:37 | EnvironmentNotInRepo | .github/workflows/controlcheck.yml:12:18:12:37 | EnvironmentNotInRepo | +| .github/workflows/controlcheck.yml:13:14:13:26 | ubuntu-latest | .github/workflows/controlcheck.yml:1:1:16:25 | on: | +| .github/workflows/controlcheck.yml:13:14:13:26 | ubuntu-latest | .github/workflows/controlcheck.yml:12:5:16:25 | Job: test2 | +| .github/workflows/controlcheck.yml:15:9:16:25 | Run Step | .github/workflows/controlcheck.yml:12:5:16:25 | Job: test2 | +| .github/workflows/controlcheck.yml:15:15:15:20 | Test 2 | .github/workflows/controlcheck.yml:1:1:16:25 | on: | +| .github/workflows/controlcheck.yml:15:15:15:20 | Test 2 | .github/workflows/controlcheck.yml:12:5:16:25 | Job: test2 | +| .github/workflows/controlcheck.yml:15:15:15:20 | Test 2 | .github/workflows/controlcheck.yml:15:9:16:25 | Run Step | +| .github/workflows/controlcheck.yml:16:14:16:25 | echo "test2" | .github/workflows/controlcheck.yml:1:1:16:25 | on: | +| .github/workflows/controlcheck.yml:16:14:16:25 | echo "test2" | .github/workflows/controlcheck.yml:12:5:16:25 | Job: test2 | +| .github/workflows/controlcheck.yml:16:14:16:25 | echo "test2" | .github/workflows/controlcheck.yml:15:9:16:25 | Run Step | | .github/workflows/expression_nodes.yml:1:5:1:17 | issue_comment | .github/workflows/expression_nodes.yml:1:1:21:47 | on: issue_comment | | .github/workflows/expression_nodes.yml:1:5:1:17 | issue_comment | .github/workflows/expression_nodes.yml:1:1:21:47 | on: issue_comment | | .github/workflows/expression_nodes.yml:1:5:1:17 | issue_comment | .github/workflows/expression_nodes.yml:1:5:1:17 | issue_comment | @@ -905,6 +955,16 @@ cfgNodes | .github/workflows/commands.yml:35:14:36:30 | command1 ; command2\n | | .github/workflows/commands.yml:37:9:39:30 | Run Step | | .github/workflows/commands.yml:38:14:39:30 | command3 \| command4\n | +| .github/workflows/controlcheck.yml:1:1:16:25 | enter on: | +| .github/workflows/controlcheck.yml:1:1:16:25 | exit on: | +| .github/workflows/controlcheck.yml:1:1:16:25 | exit on: (normal) | +| .github/workflows/controlcheck.yml:1:1:16:25 | on: | +| .github/workflows/controlcheck.yml:6:5:11:2 | Job: test1 | +| .github/workflows/controlcheck.yml:9:9:11:2 | Run Step | +| .github/workflows/controlcheck.yml:10:14:10:25 | echo "test1" | +| .github/workflows/controlcheck.yml:12:5:16:25 | Job: test2 | +| .github/workflows/controlcheck.yml:15:9:16:25 | Run Step | +| .github/workflows/controlcheck.yml:16:14:16:25 | echo "test2" | | .github/workflows/expression_nodes.yml:1:1:21:47 | enter on: issue_comment | | .github/workflows/expression_nodes.yml:1:1:21:47 | exit on: issue_comment | | .github/workflows/expression_nodes.yml:1:1:21:47 | exit on: issue_comment (normal) | @@ -1140,6 +1200,12 @@ dfNodes | .github/workflows/commands.yml:35:14:36:30 | command1 ; command2\n | | .github/workflows/commands.yml:37:9:39:30 | Run Step | | .github/workflows/commands.yml:38:14:39:30 | command3 \| command4\n | +| .github/workflows/controlcheck.yml:6:5:11:2 | Job: test1 | +| .github/workflows/controlcheck.yml:9:9:11:2 | Run Step | +| .github/workflows/controlcheck.yml:10:14:10:25 | echo "test1" | +| .github/workflows/controlcheck.yml:12:5:16:25 | Job: test2 | +| .github/workflows/controlcheck.yml:15:9:16:25 | Run Step | +| .github/workflows/controlcheck.yml:16:14:16:25 | echo "test2" | | .github/workflows/expression_nodes.yml:5:5:21:47 | Job: echo-chamber | | .github/workflows/expression_nodes.yml:7:9:8:6 | Run Step | | .github/workflows/expression_nodes.yml:7:14:7:58 | LINE 1echo '${{ github.event.comment.body }}' | @@ -1353,6 +1419,12 @@ nodeLocations | .github/workflows/commands.yml:35:14:36:30 | command1 ; command2\n | .github/workflows/commands.yml:35:14:36:30 | .github/workflows/commands.yml@35:14:36:30 | | .github/workflows/commands.yml:37:9:39:30 | Run Step | .github/workflows/commands.yml:37:9:39:30 | .github/workflows/commands.yml@37:9:39:30 | | .github/workflows/commands.yml:38:14:39:30 | command3 \| command4\n | .github/workflows/commands.yml:38:14:39:30 | .github/workflows/commands.yml@38:14:39:30 | +| .github/workflows/controlcheck.yml:6:5:11:2 | Job: test1 | .github/workflows/controlcheck.yml:6:5:11:2 | .github/workflows/controlcheck.yml@6:5:11:2 | +| .github/workflows/controlcheck.yml:9:9:11:2 | Run Step | .github/workflows/controlcheck.yml:9:9:11:2 | .github/workflows/controlcheck.yml@9:9:11:2 | +| .github/workflows/controlcheck.yml:10:14:10:25 | echo "test1" | .github/workflows/controlcheck.yml:10:14:10:25 | .github/workflows/controlcheck.yml@10:14:10:25 | +| .github/workflows/controlcheck.yml:12:5:16:25 | Job: test2 | .github/workflows/controlcheck.yml:12:5:16:25 | .github/workflows/controlcheck.yml@12:5:16:25 | +| .github/workflows/controlcheck.yml:15:9:16:25 | Run Step | .github/workflows/controlcheck.yml:15:9:16:25 | .github/workflows/controlcheck.yml@15:9:16:25 | +| .github/workflows/controlcheck.yml:16:14:16:25 | echo "test2" | .github/workflows/controlcheck.yml:16:14:16:25 | .github/workflows/controlcheck.yml@16:14:16:25 | | .github/workflows/expression_nodes.yml:5:5:21:47 | Job: echo-chamber | .github/workflows/expression_nodes.yml:5:5:21:47 | .github/workflows/expression_nodes.yml@5:5:21:47 | | .github/workflows/expression_nodes.yml:7:9:8:6 | Run Step | .github/workflows/expression_nodes.yml:7:9:8:6 | .github/workflows/expression_nodes.yml@7:9:8:6 | | .github/workflows/expression_nodes.yml:7:14:7:58 | LINE 1echo '${{ github.event.comment.body }}' | .github/workflows/expression_nodes.yml:7:14:7:58 | .github/workflows/expression_nodes.yml@7:14:7:58 | @@ -1541,6 +1613,7 @@ nodeLocations | .github/workflows/test.yml:40:20:40:53 | needs.job1.outputs.job_output | .github/workflows/test.yml:40:20:40:53 | .github/workflows/test.yml@40:20:40:53 | scopes | .github/workflows/commands.yml:1:1:39:30 | on: push | +| .github/workflows/controlcheck.yml:1:1:16:25 | on: | | .github/workflows/expression_nodes.yml:1:1:21:47 | on: issue_comment | | .github/workflows/many_strings.yml:1:1:18:1211 | on: | | .github/workflows/multiline2.yml:1:1:89:35 | on: |