Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions repository_hub/lib/internal_api/user.pb.ex
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ defmodule InternalApi.User.User.CreationSource do

field :NOT_SET, 0
field :OKTA, 1
field :SERVICE_ACCOUNT, 2
end

defmodule InternalApi.User.ListFavoritesRequest do
Expand Down
15 changes: 12 additions & 3 deletions repository_hub/lib/repository_hub/adapters/bitbucket_adapter.ex
Original file line number Diff line number Diff line change
Expand Up @@ -81,12 +81,21 @@ defmodule RepositoryHub.BitbucketAdapter do
end

def fetch_token(user_id) do
[integration_type] = integration_types()
with {:ok, user} <- UserClient.describe(user_id),
:ok <- validate_not_service_account(user, "Bitbucket") do
[integration_type] = integration_types()

integration_type
|> UserClient.get_repository_token(user_id)
integration_type
|> UserClient.get_repository_token(user_id)
end
end

defp validate_not_service_account(%{user: %{creation_source: :SERVICE_ACCOUNT}}, provider_name) do
error("Service accounts cannot use #{provider_name} OAuth tokens.")
end

defp validate_not_service_account(_user, _provider_name), do: :ok

def context(_adapter, repository_id, stream \\ nil) do
with {:ok, context} <- UniversalAdapter.context(repository_id, stream),
{:ok, bitbucket_token} <- BitbucketAdapter.fetch_token(context.project.metadata.owner_id) do
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@ defimpl RepositoryHub.Server.CreateAction, for: RepositoryHub.GithubAdapter do
import Toolkit
@impl true
def execute(adapter, request) do
with {:ok, git_repository} <- GitRepository.from_github(request.repository_url),
with {:ok, user} <- UserClient.describe(request.user_id),
{:ok, git_repository} <- GitRepository.from_github(request.repository_url),
{:ok, github_token} <- GithubAdapter.token(adapter, request.user_id, git_repository),
{:ok, github_repository} <- get_github_repository(git_repository, github_token),
{:ok, permissions} <- get_permissions(adapter, github_repository, request.user_id, github_token),
{:ok, permissions} <- get_permissions(adapter, github_repository, user, github_token),
{:ok, _} <- valid?(adapter, github_repository, request.only_public, permissions),
{:ok, repository} <- insert_repository(adapter, request, git_repository, github_repository),
grpc_repository <- Repositories.to_grpc_model(repository) do
Expand Down Expand Up @@ -98,11 +99,21 @@ defimpl RepositoryHub.Server.CreateAction, for: RepositoryHub.GithubAdapter do
|> wrap()
end

defp get_permissions(%{integration_type: "github_oauth_token"}, repo, _, _),
defp get_permissions(%{integration_type: "github_oauth_token"}, repo, _user, _github_token),
do: repo.permissions |> wrap

defp get_permissions(%{integration_type: "github_app"}, repo, user_id, github_token) do
{:ok, [username | _]} = UserClient.get_repository_provider_logins(:GITHUB, user_id)
defp get_permissions(
%{integration_type: "github_app"},
_repo,
%{user: %{creation_source: :SERVICE_ACCOUNT}},
_github_token
) do
%{"admin" => true, "push" => true}
|> wrap()
end

defp get_permissions(%{integration_type: "github_app"}, repo, user, github_token) do
{:ok, [username | _]} = UserClient.get_repository_provider_logins(:GITHUB, user.user_id)

GithubClient.repository_permissions(
%{
Expand Down
13 changes: 11 additions & 2 deletions repository_hub/lib/repository_hub/adapters/github_adapter.ex
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,19 @@ defmodule RepositoryHub.GithubAdapter do
end

def fetch_token_by_user_id(adapter, user_id) do
adapter.integration_type
|> UserClient.get_repository_token(user_id)
with {:ok, user} <- UserClient.describe(user_id),
:ok <- validate_not_service_account(user, "GitHub") do
adapter.integration_type
|> UserClient.get_repository_token(user_id)
end
end

defp validate_not_service_account(%{user: %{creation_source: :SERVICE_ACCOUNT}}, provider_name) do
error("Service accounts cannot use #{provider_name} OAuth tokens. Please use the appropriate integration type.")
end

defp validate_not_service_account(_user, _provider_name), do: :ok

def fetch_token_by_slug(adapter, slug) do
adapter.integration_type
|> to_integration_type
Expand Down
15 changes: 12 additions & 3 deletions repository_hub/lib/repository_hub/adapters/gitlab_adapter.ex
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,21 @@ defmodule RepositoryHub.GitlabAdapter do
end

def fetch_token(user_id) do
[integration_type] = integration_types()
with {:ok, user} <- UserClient.describe(user_id),
:ok <- validate_not_service_account(user, "GitLab") do
[integration_type] = integration_types()

integration_type
|> UserClient.get_repository_token(user_id)
integration_type
|> UserClient.get_repository_token(user_id)
end
end

defp validate_not_service_account(%{user: %{creation_source: :SERVICE_ACCOUNT}}, provider_name) do
error("Service accounts cannot use #{provider_name} OAuth tokens.")
end

defp validate_not_service_account(_user, _provider_name), do: :ok

def context(_adapter, repository_id, stream \\ nil) do
with {:ok, context} <- UniversalAdapter.context(repository_id, stream),
{:ok, gitlab_token} <- GitlabAdapter.fetch_token(context.project.metadata.owner_id) do
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,26 @@ defmodule RepositoryHub.Server.Github.CreateActionTest do
[
{RepositoryHub.UserClient, [:passthrough],
[
get_repository_provider_logins: fn _, _ -> {:ok, ["radwo"]} end
describe: fn user_id ->
# Return regular user by default, service account for specific test user
if user_id == "service-account-user-id" do
{:ok,
%{
user_id: user_id,
user: %{creation_source: :SERVICE_ACCOUNT}
}}
else
{:ok,
%{
user_id: user_id,
user: %{creation_source: :NOT_SET}
}}
end
end,
get_repository_provider_logins: fn _, _ -> {:ok, ["radwo"]} end,
get_repository_token: fn _integration_type, _user_id ->
{:ok, "mock-oauth-token"}
end
]}
]
) do
Expand Down Expand Up @@ -104,5 +123,28 @@ defmodule RepositoryHub.Server.Github.CreateActionTest do
)
end
end

test "should succeed for service account with github_app integration", %{github_app_adapter: adapter} do
request =
InternalApiFactory.create_request(
integration_type: :GITHUB_APP,
user_id: "service-account-user-id"
)

assert {:ok, %CreateResponse{repository: _repository}} = CreateAction.execute(adapter, request)
end

test "should fail with clear error for service account with github_oauth_token", %{
github_oauth_adapter: adapter
} do
request =
InternalApiFactory.create_request(
integration_type: :GITHUB_OAUTH_TOKEN,
user_id: "service-account-user-id"
)

assert {:error, error_message} = CreateAction.execute(adapter, request)
assert error_message =~ "Service accounts cannot use GitHub OAuth tokens"
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ defmodule RepositoryHub.Server.Github.ListAccessibleRepositoriesActionTest do
setup_with_mocks([
{RepositoryHub.UserClient, [],
[
describe: fn user_id ->
{:ok,
%{
user_id: user_id,
user: %{creation_source: :NOT_SET}
}}
end,
get_repository_token: fn integration_type, user_id ->
token = "#{user_id}-#{integration_type}-token"
expires_at = %Google.Protobuf.Timestamp{seconds: 0, nanos: 0}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,19 @@ defmodule RepositoryHub.BitbucketClientFactory do
remove_deploy_key: &remove_deploy_key_mock/2,
create_webhook: &create_webhook_mock/2,
remove_webhook: &remove_webhook_mock/2
]},
{RepositoryHub.UserClient, [:passthrough],
[
describe: fn user_id ->
{:ok,
%{
user_id: user_id,
user: %{creation_source: :NOT_SET}
}}
end,
get_repository_token: fn _integration_type, _user_id ->
{:ok, "mock-bitbucket-token"}
end
]}
]
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,19 @@ defmodule RepositoryHub.GitlabClientFactory do
find_webhook: &find_webhook_mock/2,
find_user: &find_user_mock/2,
fork: &fork_mock/2
]},
{RepositoryHub.UserClient, [:passthrough],
[
describe: fn user_id ->
{:ok,
%{
user_id: user_id,
user: %{creation_source: :NOT_SET}
}}
end,
get_repository_token: fn _integration_type, _user_id ->
{:ok, "mock-gitlab-token"}
end
]}
]
end
Expand Down