diff --git a/docs/reference/parameters.rst b/docs/reference/parameters.rst index 196c01fa2..ebb32eb3a 100644 --- a/docs/reference/parameters.rst +++ b/docs/reference/parameters.rst @@ -96,9 +96,17 @@ project level ~~~~~ - The `SCM level`_ associated with this tree. - -.. _SCM level: https://www.mozilla.org/en-US/about/governance/policies/commit/access-policy/ + The trust level associated with this task group. Trust levels provide a + convenient way to segregate resources such as worker-pools, secrets and + caches based on how the task group was triggered. This creates security + boundaries between various degrees of trust. + + The meaning of a trust level can vary from project to project, but typically + level 1 is the lowest trust and corresponds to pull requests from external + contributors. Level 2 is a degree higher and denotes pull requests from repo + collaborators or pushes to unprotected branches. Level 3 is the highest + degree of trust and is reserved for pushes to protected branches and + releases. Target Set ---------- diff --git a/docs/tutorials/connecting-taskcluster.rst b/docs/tutorials/connecting-taskcluster.rst index 1f2cbc1ad..e1eceae75 100644 --- a/docs/tutorials/connecting-taskcluster.rst +++ b/docs/tutorials/connecting-taskcluster.rst @@ -79,7 +79,7 @@ here is the recommended method: version: 1 reporting: checks-v1 policy: - pullRequests: collaborators + pullRequests: public_restricted tasks: - @@ -109,7 +109,7 @@ here is the recommended method: $if: 'tasks_for == "github-push"' then: '${event.pusher.email}' else: - $if: 'tasks_for == "github-pull-request"' + $if: 'tasks_for[:19] == "github-pull-request"' then: '${event.pull_request.user.login}@users.noreply.github.com' else: $if: 'tasks_for == "github-release"' @@ -118,22 +118,22 @@ here is the recommended method: $if: 'tasks_for == "github-push"' then: '${event.repository.html_url}' else: - $if: 'tasks_for == "github-pull-request"' + $if: 'tasks_for[:19] == "github-pull-request"' then: '${event.pull_request.base.repo.html_url}' repoUrl: $if: 'tasks_for == "github-push"' then: '${event.repository.html_url}' else: - $if: 'tasks_for == "github-pull-request"' + $if: 'tasks_for[:19] == "github-pull-request"' then: '${event.pull_request.head.repo.html_url}' project: $if: 'tasks_for == "github-push"' then: '${event.repository.name}' else: - $if: 'tasks_for == "github-pull-request"' + $if: 'tasks_for[:19] == "github-pull-request"' then: '${event.pull_request.head.repo.name}' headBranch: - $if: 'tasks_for == "github-pull-request"' + $if: 'tasks_for[:19] == "github-pull-request"' then: ${event.pull_request.head.ref} else: $if: 'tasks_for == "github-push"' @@ -142,7 +142,7 @@ here is the recommended method: $if: 'tasks_for == "github-push"' then: '${event.after}' else: - $if: 'tasks_for == "github-pull-request"' + $if: 'tasks_for[:19] == "github-pull-request"' then: '${event.pull_request.head.sha}' This isn't strictly necessary, but the format of the various Github events @@ -165,7 +165,7 @@ here is the recommended method: in: $if: > tasks_for == "github-push" && headBranch == "main" - || (tasks_for == "github-pull-request" && ${event.action} in ["opened", "reopened", "synchronize"]) + || (tasks_for[:19] == "github-pull-request" && ${event.action} in ["opened", "reopened", "synchronize"]) then: # Task definition goes here. Since there is no "else" clause, if # the above if statement evaluates to false, there will be no @@ -236,9 +236,11 @@ here is the recommended method: # while ${headBranch[11:]} strips out 'refs/heads/' - 'assume:repo:${repoUrl[8:]}:branch:${headBranch[11:]}' else: - $if: 'tasks_for == "github-pull-request"' + $if: 'tasks_for[:19] == "github-pull-request"' then: - - 'assume:repo:github.com/${event.pull_request.base.repo.full_name}:pull-request' + # ${tasks_for[7:]} strips the 'github-' prefix, leaving + # either 'pull-request' or 'pull-request-untrusted'. + - 'assume:repo:github.com/${event.pull_request.base.repo.full_name}:${tasks_for[7:]}' Notice how we assume different roles depending on whether the task is coming from a push or a pull request. This is useful when you have tasks @@ -246,6 +248,17 @@ here is the recommended method: accidentally running on a pull request! By using different scopes, you can ensure it won't ever happen. + With the ``public_restricted`` policy set above, Github reports pull + requests from repository collaborators with ``tasks_for == + "github-pull-request"`` and pull requests from everyone else with + ``tasks_for == "github-pull-request-untrusted"``. Slicing ``tasks_for[7:]`` + turns those into the role names ``pull-request`` and + ``pull-request-untrusted``, so you can grant non-collaborator pull + requests a more restricted set of scopes than collaborator ones. This + matters because collapsing that distinction (e.g. by using the ``public`` + policy) means any external contributor's pull request gets the same + scopes as a trusted collaborator's. + The roles assumed above may vary depending on the Taskcluster configuration. @@ -310,7 +323,7 @@ here is the recommended method: # running your command MYREPO_PIP_REQUIREMENTS: taskcluster/requirements.txt REPOSITORIES: {$json: {myrepo: "MyRepo"}} - - $if: 'tasks_for in ["github-pull-request"]' + - $if: 'tasks_for[:19] == "github-pull-request"' then: MYREPO_PULL_REQUEST_NUMBER: '${event.pull_request.number}' command: diff --git a/docs/tutorials/example-taskcluster.yml b/docs/tutorials/example-taskcluster.yml index dde858852..c214344bd 100644 --- a/docs/tutorials/example-taskcluster.yml +++ b/docs/tutorials/example-taskcluster.yml @@ -2,7 +2,7 @@ version: 1 reporting: checks-v1 policy: - pullRequests: collaborators + pullRequests: public_restricted tasks: - $let: # Variable definitions @@ -13,7 +13,7 @@ tasks: $if: 'tasks_for == "github-push"' then: '${event.pusher.email}' else: - $if: 'tasks_for == "github-pull-request"' + $if: 'tasks_for[:19] == "github-pull-request"' then: '${event.pull_request.user.login}@users.noreply.github.com' else: $if: 'tasks_for == "github-release"' @@ -22,22 +22,22 @@ tasks: $if: 'tasks_for == "github-push"' then: '${event.repository.html_url}' else: - $if: 'tasks_for == "github-pull-request"' + $if: 'tasks_for[:19] == "github-pull-request"' then: '${event.pull_request.base.repo.html_url}' repoUrl: $if: 'tasks_for == "github-push"' then: '${event.repository.html_url}' else: - $if: 'tasks_for == "github-pull-request"' + $if: 'tasks_for[:19] == "github-pull-request"' then: '${event.pull_request.head.repo.html_url}' project: $if: 'tasks_for == "github-push"' then: '${event.repository.name}' else: - $if: 'tasks_for == "github-pull-request"' + $if: 'tasks_for[:19] == "github-pull-request"' then: '${event.pull_request.head.repo.name}' headBranch: - $if: 'tasks_for == "github-pull-request"' + $if: 'tasks_for[:19] == "github-pull-request"' then: ${event.pull_request.head.ref} else: $if: 'tasks_for == "github-push"' @@ -46,13 +46,13 @@ tasks: $if: 'tasks_for == "github-push"' then: '${event.after}' else: - $if: 'tasks_for == "github-pull-request"' + $if: 'tasks_for[:19] == "github-pull-request"' then: '${event.pull_request.head.sha}' in: # Guard that controls when to schedule tasks. $if: > tasks_for == "github-push" && headBranch == "main" - || (tasks_for == "github-pull-request" && ${event.action} in ["opened", "reopened", "synchronize"]) + || (tasks_for[:19] == "github-pull-request" && ${event.action} in ["opened", "reopened", "synchronize"]) then: # Task Definition taskId: '${ownTaskId}' @@ -74,9 +74,14 @@ tasks: # while ${headBranch[11:]} strips out 'refs/heads/' - 'assume:repo:${repoUrl[8:]}:branch:${headBranch[11:]}' else: - $if: 'tasks_for == "github-pull-request"' + $if: 'tasks_for[:19] == "github-pull-request"' then: - - 'assume:repo:github.com/${event.pull_request.base.repo.full_name}:pull-request' + # ${tasks_for[7:]} strips the 'github-' prefix, leaving + # 'pull-request' or 'pull-request-untrusted'. With the + # 'public_restricted' policy these map to two separate + # roles, so pull requests from collaborators get more + # scopes than those from non-collaborators. + - 'assume:repo:github.com/${event.pull_request.base.repo.full_name}:${tasks_for[7:]}' payload: image: mozillareleases/taskgraph:decision-cf4b4b4baff57d84c1f9ec8fcd70c9839b70a7d66e6430a6c41ffe67252faa19@sha256:425e07f6813804483bc5a7258288a7684d182617ceeaa0176901ccc7702dfe28 @@ -97,7 +102,7 @@ tasks: # bootstrapped MYREPO_PIP_REQUIREMENTS: taskcluster/requirements.txt REPOSITORIES: {$json: {myrepo: "MyRepo"}} - - $if: 'tasks_for in ["github-pull-request"]' + - $if: 'tasks_for[:19] == "github-pull-request"' then: MYREPO_PULL_REQUEST_NUMBER: '${event.pull_request.number}' command: diff --git a/src/taskgraph/target_tasks.py b/src/taskgraph/target_tasks.py index 7f44b6ab6..b93363848 100644 --- a/src/taskgraph/target_tasks.py +++ b/src/taskgraph/target_tasks.py @@ -53,7 +53,7 @@ def filter_for_git_branch(task, parameters): return True # Pull requests usually have arbitrary names, let's not filter git branches on them. - if parameters["tasks_for"] == "github-pull-request": + if parameters["tasks_for"].startswith("github-pull-request"): return True run_on_git_branches = set(task.attributes.get("run_on_git_branches", ["all"])) diff --git a/template/{{cookiecutter.project_name}}/taskcluster.github.yml b/template/{{cookiecutter.project_name}}/taskcluster.github.yml index a626d2ed9..a039d4fde 100644 --- a/template/{{cookiecutter.project_name}}/taskcluster.github.yml +++ b/template/{{cookiecutter.project_name}}/taskcluster.github.yml @@ -8,7 +8,7 @@ version: 1 reporting: checks-v1 autoCancelPreviousChecks: true policy: - pullRequests: public + pullRequests: public_restricted tasks: - $let: trustDomain: "{{cookiecutter.trust_domain}}"