Skip to content

Instantly share code, notes, and snippets.

@chtzvt
Created September 13, 2024 15:45
Show Gist options
  • Save chtzvt/4761b10fff06b003e01a0f30b97342cd to your computer and use it in GitHub Desktop.
Save chtzvt/4761b10fff06b003e01a0f30b97342cd to your computer and use it in GitHub Desktop.
Blackbeard Copilot Agent Reference Implementation, Ported to Ruby
require "sinatra"
require "openssl"
require "faraday"
require "json"
require "base64"
require "octokit"
set :port, 3000
COPILOT_API_KEYS_URL = "https://api.github.com/meta/public_keys/copilot_api"
COPILOT_API_COMPLETIONS_URL = "https://api.githubcopilot.com/chat/completions"
post "/" do
signature = request.env["HTTP_GITHUB_PUBLIC_KEY_SIGNATURE"]
key_id = request.env["HTTP_GITHUB_PUBLIC_KEY_IDENTIFIER"]
token_for_user = request.env["HTTP_X_GITHUB_TOKEN"]
payload = request.body.read
begin
public_key_object = fetch_public_key(token_for_user, key_id)
if public_key_object.nil?
halt 401, {error: "No public key found matching key identifier"}.to_json
end
public_key = public_key_object["key"]
unless verify_signature(payload, signature, public_key)
halt 401, {error: "Invalid signature"}.to_json
end
rescue => e
halt 500, {error: "Signature verification failed: #{e.message}"}.to_json
end
client = Octokit::Client.new(access_token: token_for_user)
json_payload = JSON.parse(payload, symbolize_names: true)
puts "-- Message Payload Received --"
puts JSON.pretty_generate(json_payload)
puts "------------------------------"
messages = json_payload[:messages]
messages.unshift({role: "system", content: "You are a helpful assistant that replies to user messages as if you were the Blackbeard Pirate."})
messages.unshift({role: "system", content: "Start every response with the user's name, which is @#{client.login}"})
conn = Faraday.new do |faraday|
faraday.adapter Faraday.default_adapter
end
begin
stream do |out|
conn.post do |req|
req.url COPILOT_API_COMPLETIONS_URL
req.headers["Authorization"] = "Bearer #{token_for_user}"
req.headers["Content-Type"] = "application/json"
req.body = {
messages: messages,
model: "gpt-3.5-turbo",
stream: true
}.to_json
end.on_complete do |response|
response.body.each_line do |line|
out << line
end
end
end
rescue => e
halt 500, {error: "Error while streaming response: #{e.message}"}.to_json
end
end
# Helpers for signature verification
def fetch_public_key(token_for_user, key_id)
conn = Faraday.new(url: COPILOT_API_KEYS_URL) do |faraday|
faraday.adapter Faraday.default_adapter
end
response = conn.get do |req|
req.headers["Authorization"] = "Bearer #{token_for_user}" unless token_for_user.nil?
end
keys = JSON.parse(response.body)["public_keys"]
keys.find { |key| key["key_identifier"] == key_id }
end
def verify_signature(payload, signature, public_key)
openssl_key = OpenSSL::PKey::EC.new(public_key)
digest = OpenSSL::Digest.new("SHA256")
decoded_signature = Base64.decode64(signature)
openssl_key.verify(digest, decoded_signature, payload.chomp)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment