Lightning.Policies.Sandboxes (Lightning v2.19.0-pre)
View SourceThe Bodyguard Policy module for sandbox project operations.
Sandbox authorization mirrors regular projects: access is decided by the
acting user's role on the project they're acting on (or the workspace
root, where the cascade applies). User.role (:user / :superuser)
is a user-type for global user-management screens; it is not a
project-access bypass and has no effect on sandbox policy decisions, in
line with Lightning.Policies.ProjectUsers.
- Sandbox owners/admins can manage their own sandboxes
- Root project owners/admins can manage any sandbox in their workspace
- Editors (and above) on the parent project can provision sandboxes
Every action except provisioning and merging acts on a sandbox, and a workspace root is not one. A root is refused before any role is considered, which is what keeps the root cascade from admitting the root itself.
Destructive actions on a sandbox (delete, update, merge) are scoped to
admin/owner on the sandbox itself (or the root cascade above). This
matches the rest of Lightning, where destructive actions are admin/owner
scoped, and it keeps the merge button on the sandboxes list aligned with
the cleanup step that runs after merge submission (which calls
:delete_sandbox and so requires admin/owner on the source).
Summary
Functions
Authorize sandbox operations based on the user's role on the project involved.
Bulk manage check for multiple sandboxes, avoiding N+1 queries.
Types
Functions
@spec authorize( actions(), Lightning.Accounts.User.t(), Lightning.Projects.Project.t() ) :: boolean()
Authorize sandbox operations based on the user's role on the project involved.
Authorization Rules
:delete_sandbox, :update_sandbox and :cancel_scheduled_deletion
The subject must be a sandbox: a project with no parent is refused outright, whoever is asking. Beyond that the user must be one of:
- Owner/admin of the sandbox itself
- Owner/admin of the root project (workspace)
:provision_sandbox
User must be editor/admin/owner of the parent project they're creating the sandbox under.
:merge_sandbox
This check authorises the target side of a merge: the user must be
editor/admin/owner on the target project (the project being merged
into). The merge flow also requires admin/owner on the source
sandbox itself, enforced by manage_permissions/3 (button
gate) and by the post-merge cleanup, which calls :delete_sandbox
to retire the source and so requires admin/owner there.
Support access
No sandbox action honours it: every clause decides on role alone, so a
support user with no membership row is refused even on a consenting project.
Inherited behaviour, not a ruling.
Parameters
action- The action being attempteduser- The user attempting the actionproject- The sandbox project (for delete/update), parent project (for provision), or target project (for merge)
@spec manage_permissions( [Lightning.Projects.Project.t()], Lightning.Accounts.User.t(), Lightning.Projects.Project.t() ) :: %{required(binary()) => boolean()}
Bulk manage check for multiple sandboxes, avoiding N+1 queries.
Returns a map sandbox_id => boolean() where true means the user can
perform the destructive actions the sandbox list offers on that row: they are
an owner/admin on the sandbox itself, or an owner/admin on the root project
(cascade). The workspace root is always false, which is what the list relies
on to withhold edit, delete and merge from the root. Note this is the merge
source side; :merge_sandbox authorises the target and a root is a legal
target.
Assumes root_project.project_users and each sandbox.project_users
are preloaded (as ensured by Projects.list_workspace_projects/2).
Reads those preloaded rows rather than resolving a Scope, so it does not
hold the actor to the project's MFA requirement. Nothing reaches it that has
not already been held to it: the list it feeds mounts
LightningWeb.Hooks.:project_scope, which redirects an unenrolled member to
/mfa_required before the page renders, and every action a true enables
refuses on its own.