2.3 KiB · text 5af55d9
defmodule GitGudWeb.WorkflowArtifactController do
@moduledoc """
Browser-side artifact download for the workflow UI.
The runner-side `ActionsArtifactController` is JWT-gated and lives
under `/api/actions/_apis/...`; this is the user-facing equivalent
at `/r/:owner/:name/actions/:number/artifacts/:id` that gates on
repo read access from `current_scope`.
"""
use GitGudWeb, :controller
alias GitGud.Repositories
alias GitGud.Repositories.Repository
alias GitGud.Storage
alias GitGud.Workflows
alias GitGud.Workflows.WorkflowArtifact
@bucket "gitgud-artifacts"
def download(conn, %{"owner" => owner, "name" => name, "number" => num, "id" => id}) do
repo =
Repositories.get_repository_by_path!(owner, name)
|> GitGud.Repo.preload([:owner, :organization])
user = conn.assigns[:current_scope] && conn.assigns.current_scope.user
cond do
not can_read?(user, repo) ->
conn |> put_status(:not_found) |> text("")
true ->
run = Workflows.get_run!(repo, String.to_integer(num))
artifact = GitGud.Repo.get!(WorkflowArtifact, String.to_integer(id))
if artifact.workflow_run_id != run.id do
conn |> put_status(:not_found) |> text("")
else
serve(conn, artifact)
end
end
end
defp serve(conn, %WorkflowArtifact{} = artifact) do
case Storage.get(@bucket, artifact.storage_key) do
{:ok, body} ->
conn
|> put_resp_content_type(artifact.content_type || "application/octet-stream", nil)
|> put_resp_header(
"content-disposition",
~s(attachment; filename="#{filename_safe(artifact.name)}")
)
|> send_resp(200, body)
_ ->
conn |> put_status(:not_found) |> text("")
end
end
defp can_read?(_user, %Repository{visibility: vis}) when vis in ["public", "internal"], do: true
defp can_read?(%{id: uid}, %Repository{owner_id: uid}), do: true
defp can_read?(%{id: uid}, %Repository{organization_id: oid}) when not is_nil(oid),
do:
GitGud.Organizations.org_admin?(
%GitGud.Organizations.Organization{id: oid},
%GitGud.Accounts.User{id: uid}
)
defp can_read?(_, _), do: false
defp filename_safe(name) do
String.replace(name, ~r/[^A-Za-z0-9._\- ]/, "_")
end
end