Skip to content

Commit

Permalink
Add an API endpoint for building an extension asset
Browse files Browse the repository at this point in the history
  • Loading branch information
demillir committed Oct 26, 2021
1 parent 918514a commit 12848b2
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 1 deletion.
60 changes: 59 additions & 1 deletion app/controllers/extensions_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ class ExtensionsController < ApplicationController
before_action :store_location_then_authenticate_user!, only: [:follow, :unfollow, :adoption]
before_action :authenticate_user!, only: [:new, :create]

skip_before_action :verify_authenticity_token, only: [:webhook]
skip_before_action :verify_authenticity_token, only: [:webhook, :build]

#
# GET /extensions
Expand Down Expand Up @@ -388,6 +388,31 @@ def webhook
head :ok
end

#
# POST /assets/:username/:id/build
#
# Triggers a release build of the specified asset.
# Returns one of the following HTTP status codes:
# 2XX - Success
# 401 - Invalid or missing X-GitHub-Token header
# 403 - GitHub user not authorized for the specified asset
# 404 - Unknown GitHub repo for the asset
#
# Requires an +X-GitHub-Token+ header containing a GitHub personal access token (PAT)
# belonging to a user who is a collaborator on the project.
# See https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token.
# The header must use the +token+ auth method, as in:
# X-GitHub-Token: ${GITHUB_PERSONAL_ACCESS_TOKEN}
#
def build
github_token = request.headers['X-GitHub-Token']
status_code_symbol = with_collaborator_authorization(github_token, @extension) do
CollectExtensionMetadataWorker.perform_async(@extension.id, [])
end

head status_code_symbol
end

def select_default_version
version = @extension.extension_versions.find_by(id: params[:extension_version_id])
version_id = version.present? ? version.id : nil
Expand Down Expand Up @@ -508,4 +533,37 @@ def render_follow_button
format.html { render partial: partial_template, locals: { extension: @extension } }
end
end

# Attempts to authorize GitHub user corresponding to the given GitHub token
# as having GitHub collaborator permissions for the given +Extension+ object.
#
# If the authorization succeeds, this method calls the given code block.
#
# Returns an HTTP status code symbol representing the success or failure of the authorization.
#
def with_collaborator_authorization(github_token, extension, &block)
return :unknown unless extension
return :unauthorized unless github_token.present?

repo_name = extension.github_repo
return :unknown unless repo_name.present?

github_client = Octokit::Client.new(access_token: github_token)
github_login_name = begin
github_client.user.login
rescue Octokit::Unauthorized
return :unauthorized
rescue
nil
end
return :not_found unless github_login_name.present?

# The GitHub user corresponding to the auth token must be a collaborator on the GitHub repo.
is_collaborator = github_client.collaborator?(repo_name, github_login_name) rescue false
return :forbidden unless is_collaborator

# If this point is reached, we can call the given code block.
block.call
return :ok
end
end
1 change: 1 addition & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
delete :deprecate, action: 'undeprecate'
put :toggle_featured
get :deprecate_search
post :build
post :webhook
put :disable
put :enable
Expand Down

0 comments on commit 12848b2

Please sign in to comment.