================================== Permissions for workflow templates ================================== This blueprint covers the design for a permission system for workflow templates. The general idea is that workflow templates are something like method calls on workspaces, defining their API, and some of that API can be a public interface for the workspace, or a limited internal API. We need a permission system to define who can access such APIs. Use cases ========= 1. "Publish to proposed-updates": users do not have write access to a workspace but can invoke one of its workflow templates to publish packages to a hardcoded collection. The target collection has index files that get properly generated and signed. 2. "Maintenance": workspace owners can set up workflow templates to use as workspace maintenance tasks, which only workspace owners can run Current situation ================= Starting a workflow ------------------- Currently, workflow templates have a ``can_display`` permission which is granted to users who have the ``VIEWER`` role on the containing workspace. Workflow templates also have a ``can_run`` permission which is granted to users who have the ``CONTRIBUTOR`` role on the containing workspace. This distinction is too coarse grained and too limited: it does not allow to grant a group of users ``can_run`` access without making them ``CONTRIBUTOR`` on the workspace, and it doesn't allow to limit ``can_run`` to a more restricted set of users. Permissions while running the workflow -------------------------------------- Currently, when permission checks are performed while running a workflow or one of its work requests, they are done as the user who started the workflow. This is going to change soon to be more restrictive, that is, running with a subset of the permissions that the user who started the workflow would have, so that only permissions relevant to workflow activities are granted. For example, running code for a work request is not going to be granted permissions to affect a group membership, or create workspaces. The actual permissions checks currently being done are: * accessing build environments and other artifacts: ``ExternalTask.fetch_artifact`` calls ``ArtifactView``/``WorkspaceArtifactView``, which need ``can_display`` on the workspace * ``can_display`` checks when serving APT repositories from private workspaces * using assets to sign releases Adding results to collections is performed by event reactions, that currently do not perform permission checks. They are however set up by workspace code, which can validate inputs and perform the appropriate gatekeeping. The rest of workflow code currently runs without permission checks. There is currently no way to grant a user permission to sign the release files on a collection, even if they could start a workflow template that published to that collection. Proposed updates to starting a workflow ======================================= Define roles for ``WorkflowTemplate`` ------------------------------------- Define possible roles that users can have on ``WorkflowTemplate``: * ``OWNER``: people who can edit and run the workflow template * ``STARTER``: people who can use (display and run) the workflow template, but not modify it * ``VIEWER``: people who can display, but not run, the workflow template Add explicit role assignments to ``WorkflowTemplate`` ----------------------------------------------------- Add a ``WorkflowTemplateRole`` model to explicitly grant roles to a group for a ``WorkflowTemplate`` instance. Add role inferences ------------------- To handle the common cases as they are now, we can have these role inferences: * ``OWNER`` implied by ``Workspace.Roles.OWNER`` * ``STARTER`` implied by ``Workspace.Roles.CONTRIBUTOR`` * ``VIEWER`` implied by ``Workspace.Roles.VIEWER`` This implements the status quo, and allows granting extra roles to groups of people, addressing the starting side of the "Publish to proposed-updates" use case for users that are not part of the ``WorkflowTemplate``'s workspace. This is not sufficient to handle the "Maintenance" use case. Add a ``restricted`` flag to ``WorkflowTemplate`` ------------------------------------------------- We can add a ``restricted`` flag to ``WorkflowTemplate``, which changes the implications: when set to ``True``, the implications become: * ``OWNER`` implied by ``Workspace.Roles.OWNER`` * ``STARTER`` implied by ``Workspace.Roles.OWNER`` * ``VIEWER`` implied by ``Workspace.Roles.VIEWER`` This would address the "Maintenance" use case: the workflow templates in question can be configured with ``restricted=True``, and access would be restricted to workspace owners, handling the "Maintenance" use case. It is still possible to have a group for helpers of the workspace owners, who can be allowed to start some such maintenance workflow templates. Starting workflows on private repositories ------------------------------------------ These changes would allow to grant users the ability to start a workflow on a private repository that they cannot access. While we currently have no use cases for this, it could become a useful tool for modeling embargoed workspaces with a limited public API. This would however not be easily supported by the UI, which treats an inaccessible private workspace as a workspace that does not exist. While we could consider changing the UI to treat private workspaces with viewable workflow templates differently, the problem could be sidestepped by setting up "proxy" workflow templates in different, accessible workspaces that, when started, start designated workflow templates in the private workspaces. We may need special care to see if and how we want to allow the person who created such a workflow to see its progress even if it is in a workspace they cannot access. Proposed updates to permission checking while running a workflow ================================================================ Permission checking during the workflow execution ------------------------------------------------- We can allow a workflow template to optionally be configured with additional groups. If that is present, all permission checks run as part of the workflow execution consider the user as if it were also a member of those groups. The user is never effectively added to the group, though, and their membership is unchanged for all operations outside of that workflow execution. This would solve the signing permission issue of the "Publish to proposed-updates" use case: one can define a group for signers with the appropriate roles, and configure it as an additional group for the workflow template. Alternatively, one can assign the workspace owners group as additional group, which would be a simpler setup that is adequate for most organizational needs. Refactor permission predicates ------------------------------ Recent changes around permission predicates have led to various special casing for checks running as part of workflows or work requests, and this would add another one. We can refactor permission predicates to take an argument which contains the user to check, the work request or workflow if executing for a worker, extra groups to be granted, and possibly more as will be needed. Such argument could be an object that is typed as a superclass of ``debusine.db.context.Context``, or something easily constructed from the same: this would allow to pass the current application context, or to construct alternate inputs for other kinds of permission checking. Permission check and predicate decorators can then access the structure being passed instead of using the application context, avoiding the risk of broken assumptions when checking permissions of users other than the current one.