Lightning.Policies.ProjectUsers (Lightning v2.19.0-pre)

View Source

The Bodyguard Policy module for project members' roles.

Two steps, deliberately separate.

Lightning.Projects.Scope establishes the facts: which project, and what standing this actor has in it. It refuses outright for a project that does not exist or is scheduled for deletion, so nothing downstream can be handed a standing in a wound-down project.

permitted?/2 makes the judgement: given that standing, is this action allowed. It decides on role and mfa_satisfied?, and never mentions Project.scheduled_deletion or Project.requires_mfa — there is no shut-down project left for it to see, and the MFA rule reaches it as a fact on the scope.

Adding an action means adding an atom to @admin_actions or @editor_actions. It inherits the guard; 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 user may perform action, where the subject is anything that identifies a project — see Lightning.Projects.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{}.

Types

actions()

@type actions() ::
  :access_project
  | :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, user, project_user)

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

blocked_by_mfa?(scope)

@spec blocked_by_mfa?(Lightning.Projects.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 the guard above answers false for both cases.

permitted?(action, scope)

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

Decide an action against an already-resolved %Scope{}.

Public so a caller needing several answers about one project resolves once rather than once per question.