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/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