Lightning.Policies.ProjectUsers (Lightning v2.20.1)

Copy Markdown View Source

The Bodyguard Policy module for project members' roles.

Two steps, deliberately separate.

Lightning.Scope establishes the facts: which project, and what standing this actor has in it, including whether the project is scheduled for deletion.

authorize/3 on a %Scope{} makes the judgement, in the order Lightning.Policies.Decision sets. It never mentions Project.scheduled_deletion or Project.requires_mfa. Both reach it as facts on the scope.

Adding an action means adding an atom to @admin_actions or @editor_actions. It inherits the guards; there is nothing to remember.

We deny by default: an action in none of the lists is refused.

Summary

Functions

Every action this policy decides. Read by the recurrence test, so a new action is covered the day it is added rather than the day someone remembers.

Whether the caller may perform action, where the subject is anything that identifies a project — see Lightning.Scope.subject/0.

Whether this actor would have standing on the project if not for the project's MFA requirement.

Decide an action against an already-resolved %Scope{}, as a boolean.

Types

actions()

@type actions() ::
  :access_project
  | :list_project_credentials
  | :delete_project
  | :publish_template
  | :run_workflow
  | :edit_workflow
  | :delete_workflow
  | :create_workflow
  | :create_project_credential
  | :initiate_github_sync
  | :create_channel
  | :delete_channel
  | :update_channel
  | :edit_project
  | :edit_data_retention
  | :edit_run_settings
  | :add_project_user
  | :remove_project_user
  | :write_webhook_auth_method
  | :write_github_connection
  | :edit_digest_alerts
  | :edit_failure_alerts

Functions

actions()

@spec actions() :: [actions()]

Every action this policy decides. Read by the recurrence test, so a new action is covered the day it is added rather than the day someone remembers.

authorize(action, scope, subject)

Whether the caller may perform action, where the subject is anything that identifies a project — see Lightning.Scope.subject/0.

Given a %Scope{}, the subject must be the scope's own project or one of its membership rows.

blocked_by_mfa?(scope)

@spec blocked_by_mfa?(Lightning.Scope.t()) :: boolean()

Whether this actor would have standing on the project if not for the project's MFA requirement.

Lets a caller distinguish "no access at all" from "access except MFA" — LightningWeb.Hooks sends the first to not-found and the second to /mfa_required — without duplicating what counts as standing. It cannot ask permitted?(:access_project, ...) for that, since that answers false for both cases. A project scheduled for deletion is not-found for everyone, so it is never "blocked by MFA".

permitted?(action, scope)

@spec permitted?(actions(), Lightning.Scope.t()) :: boolean()

Decide an action against an already-resolved %Scope{}, as a boolean.

Public so a caller needing several answers about one project resolves once rather than once per question. It is false when the scope lacks the action's grant, and on a project scheduled for deletion.