class GithubSnapBuilder::Application

Constants

APP_IDENTIFIER

The GitHub App's identifier (type integer) set when registering an app.

PRIVATE_KEY

Converts the newlines. Expects that the private key has been set as an environment variable in PEM format.

WEBHOOK_SECRET

Your registered app must have a secret set. The secret is used to verify that webhooks are sent by GitHub.

Public Instance Methods

authenticate_app() click to toggle source

Instantiate an Octokit client authenticated as a GitHub App. GitHub App authentication requires that you construct a JWT (jwt.io/introduction/) signed with the app's private key, so GitHub can be sure that it came from the app an not altererd by a malicious third party.

# File lib/github_snap_builder/server.rb, line 160
def authenticate_app
        payload = {
                # The time that this JWT was issued, _i.e._ now.
                iat: Time.now.to_i,

                # JWT expiration time (10 minute maximum)
                exp: Time.now.to_i + (10 * 60),

                # Your GitHub App's identifier number
                iss: APP_IDENTIFIER
        }

        # Cryptographically sign the JWT.
        jwt = JWT.encode(payload, PRIVATE_KEY, 'RS256')

        # Create the Octokit client, using the JWT as the auth token.
        @app_client ||= Octokit::Client.new(bearer_token: jwt)
end
authenticate_installation(payload) click to toggle source

Instantiate an Octokit client, authenticated as an installation of a GitHub App, to run API operations.

# File lib/github_snap_builder/server.rb, line 181
def authenticate_installation(payload)
        @installation_id = payload['installation']['id']
        @installation_token = @app_client.create_app_installation_access_token(@installation_id)[:token]
        @installation_client = Octokit::Client.new(bearer_token: @installation_token)
end
get_payload_request(request) click to toggle source

Saves the raw payload and converts the payload to JSON format

# File lib/github_snap_builder/server.rb, line 142
def get_payload_request(request)
        # request.body is an IO or StringIO object
        # Rewind in case someone already read it
        request.body.rewind
        # The raw text of the body is required for webhook signature verification
        @payload_raw = request.body.read
        begin
                @payload = JSON.parse @payload_raw
        rescue => e
                fail  "Invalid JSON (#{e}): #{@payload_raw}"
        end
end
handle_pull_request_updated_event(payload) click to toggle source
# File lib/github_snap_builder/server.rb, line 83
def handle_pull_request_updated_event(payload)
        pull_request = payload['pull_request']
        repo = pull_request['base']['repo']['full_name']
        head_url = pull_request['head']['repo']['html_url']
        base_url = pull_request['base']['repo']['html_url']
        commit_sha = pull_request['head']['sha']
        pr_number = pull_request['number']

        repo_config = CONFIG.repo(repo) || raise("Config missing repo definition for '#{repo}'")
        channel = repo_config.channel
        token = repo_config.token || raise("'#{repo}' config missing token")

        relative_logfile_path = File.join repo, "#{commit_sha}.log"
        logfile_path = File.join(logdir, relative_logfile_path)
        FileUtils.mkpath File.dirname(logfile_path)
        FileUtils.chmod_R 0755, File.dirname(logfile_path)
        build_logger = Logger.new(logfile_path)
        log_url = request.url.gsub 'event_handler', "logs/#{relative_logfile_path}"
        status_reporter = GithubStatusReporter.new(@installation_client, repo, commit_sha, log_url)

        begin
                begin
                        status_reporter.pending("Currently building a snap...")

                        builder = SnapBuilder.new(build_logger, base_url, head_url, commit_sha, CONFIG.build_type)
                        logger.info "Building snap for '#{repo}'"
                        snap_path = builder.build
                rescue Error => e
                        logger.error "Failed to build snap: #{e.message}"
                        status_reporter.error("Snap failed to build.")
                        return
                end

                begin
                        status_reporter.pending("Currently uploading/releasing snap...")

                        full_channel = "#{channel}/pr-#{pr_number}"
                        logger.info "Pushing and releasing snap into '#{full_channel}'"
                        builder.release(snap_path, token, full_channel)
                rescue Error => e
                        logger.error "Failed to push/release snap: #{e.message}"
                        status_reporter.error("Snap failed to upload/release.")
                        return
                end

                logger.info 'Built and released snap, all done'
                status_reporter.success("Snap built and released to '#{full_channel}'")
        rescue => e
                logger.error "Unknown error: #{e.message}"
                status_reporter.error("Encountered an error.")
                raise
        ensure
                if !snap_path.nil? and File.file? snap_path
                        File.delete snap_path
                end
        end
end
logdir() click to toggle source
# File lib/github_snap_builder/server.rb, line 210
def logdir
        ENV.fetch("SNAP_BUILDER_LOG_DIR", "log")
end
logfile_path(repo, commit_sha) click to toggle source
# File lib/github_snap_builder/server.rb, line 214
def logfile_path(repo, commit_sha)
end
verify_webhook_signature() click to toggle source

Check X-Hub-Signature to confirm that this webhook was generated by GitHub, and not a malicious third party.

GitHub uses the WEBHOOK_SECRET, registered to the GitHub App, to create the hash signature sent in the `X-HUB-Signature` header of each webhook. This code computes the expected hash signature and compares it to the signature sent in the `X-HUB-Signature` header. If they don't match, this request is an attack, and you should reject it. GitHub uses the HMAC hexdigest to compute the signature. The `X-HUB-Signature` looks something like this: “sha1=123456”. See developer.github.com/webhooks/securing/ for details.

# File lib/github_snap_builder/server.rb, line 198
def verify_webhook_signature
        their_signature_header = request.env['HTTP_X_HUB_SIGNATURE'] || 'sha1='
        method, their_digest = their_signature_header.split('=')
        our_digest = OpenSSL::HMAC.hexdigest(method, WEBHOOK_SECRET, @payload_raw)
        halt 401 unless their_digest == our_digest

        # The X-GITHUB-EVENT header provides the name of the event.
        # The action value indicates the which action triggered the event.
        logger.debug "---- received event #{request.env['HTTP_X_GITHUB_EVENT']}"
        logger.debug "----    action #{@payload['action']}" unless @payload['action'].nil?
end