defmodule GitGud.Workflows.JobTokenGrant do
@moduledoc """
One repository letting another's CI jobs in.
A job's `${{ github.token }}` is limited to its own repository. A grant
on repository B names a source — one repository, or every repository of
an organization — whose job tokens may additionally:
* `read` B's container images and packages, and
* `dispatch` B's workflows (`workflow_dispatch`).
It is GitLab's job-token allowlist: the repository being reached into
decides, not the one reaching.
"""
use Ecto.Schema
import Ecto.Changeset
alias GitGud.Organizations.Organization
alias GitGud.Repositories.Repository
schema "job_token_grants" do
field :read, :boolean, default: true
field :dispatch, :boolean, default: false
belongs_to :repository, Repository
belongs_to :source_repository, Repository
belongs_to :source_organization, Organization
timestamps(type: :utc_datetime)
end
@doc false
def changeset(grant, attrs) do
grant
|> cast(attrs, [
:repository_id,
:source_repository_id,
:source_organization_id,
:read,
:dispatch
])
|> validate_required([:repository_id])
|> validate_one_source()
|> validate_grants_something()
|> check_constraint(:source_repository_id, name: :exactly_one_source)
|> unique_constraint(:source_repository_id,
name: :job_token_grants_repo_source_repo_index,
message: "already has a grant"
)
|> unique_constraint(:source_organization_id,
name: :job_token_grants_repo_source_org_index,
message: "already has a grant"
)
end
defp validate_one_source(changeset) do
case {get_field(changeset, :source_repository_id),
get_field(changeset, :source_organization_id)} do
{nil, nil} ->
add_error(changeset, :source_repository_id, "name a repository or an organization")
{_, nil} ->
validate_not_self(changeset)
{nil, _} ->
changeset
_ ->
add_error(
changeset,
:source_repository_id,
"name a repository or an organization, not both"
)
end
end
# A repository's own jobs already have full access to it.
defp validate_not_self(changeset) do
if get_field(changeset, :source_repository_id) == get_field(changeset, :repository_id) do
add_error(
changeset,
:source_repository_id,
"is this repository; its jobs already have access"
)
else
changeset
end
end
defp validate_grants_something(changeset) do
if get_field(changeset, :read) or get_field(changeset, :dispatch) do
changeset
else
add_error(changeset, :read, "grant at least one of read or dispatch")
end
end
end
neiam
/gitgud
Git Gud
public · Issues · Pulls · Labels · Forks · Compare · Actions success · Badges · Packages
⭐
1
Log in to mark this repository.
2.7 KiB · text
History
b868907