Skip to content

Commit

Permalink
Merge pull request #45 from cultureamp/tfm/fef-1572-gh-auth
Browse files Browse the repository at this point in the history
Github App authentication
  • Loading branch information
burritobill authored Sep 6, 2024
2 parents 805d35b + 0c8993e commit 62b5dfd
Show file tree
Hide file tree
Showing 7 changed files with 252 additions and 116 deletions.
9 changes: 3 additions & 6 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,22 +39,19 @@ jobs:
- uses: actions/checkout@v3
- uses: jetify-com/[email protected]
- run: devbox run lint
e2e-install-hotel:
hotel-install-script:
strategy:
matrix:
# See: https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners/about-github-hosted-runners#standard-github-hosted-runners-for-public-repositories
# for the mapping of architecture to the runner type.
runs-on: [macos-13, macos-latest, ubuntu-latest] # TODO
runs-on: [macos-13, macos-latest, ubuntu-latest]
runs-on: ${{ matrix.runs-on }}
steps:
- uses: actions/checkout@v4
- name: run install script
shell: bash
run: |
export HOTEL_INSTALLER_GITHUB_TOKEN="${{ secrets.HOTEL_ACCESS_TOKEN }}"
# this syntax should match what we recommend in the readme
export INSTALLER_URL="https://raw.githubusercontent.com/cultureamp/devbox-extras/$GITHUB_SHA/scripts/install_hotel.sh"
sh -c "$(curl -fsSL "$INSTALLER_URL")"
./scripts/install_hotel.sh "${{ secrets.HOTEL_ACCESS_TOKEN }}"
- name: verify hotel executable is available and working
shell: bash
run: hotel --version
Expand Down
4 changes: 4 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# https://docs.rubocop.org/rubocop/configuration
AllCops:
Exclude:
- ".devbox/**/*"
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,19 @@ The recommended command to setup a Culture Amp macbook for working with LDEs/dev

```bash
# install hotel cli
sh -c "$(curl -fsSL "https://raw.githubusercontent.com/cultureamp/devbox-extras/main/scripts/install_hotel.sh")"
ruby -e "$(curl -fsSL https://github.com/cultureamp/devbox-extras/blob/main/scripts/github_auth.rb)"

# use hotel to setup LDEs
hotel setup ensure
```

Should this authentication flow not work, you can manually authenticate with the following script:
The github token should have read access to the `repository` scope and be enabled with SSO for Culture Amp.

```bash
sh -c "$(curl -fsSL https://raw.githubusercontent.com/cultureamp/devbox-extras/main/scripts/install_hotel.sh) {insert_pat_token_here}"
```

# devbox-plugins

Devbox is something we're trialing internally, we need some plugins. So putting them here for now, all in one place. Plugins are documented in their respective folders.
Expand Down
7 changes: 5 additions & 2 deletions devbox.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
"statix",
"shellcheck",
"shfmt",
"nodePackages.prettier"
"nodePackages.prettier",
"rubocop@latest"
],
"shell": {
"scripts": {
Expand All @@ -21,13 +22,15 @@
"shellcheck **/*.{sh,bats} &",
"shfmt --diff **/*.{sh,bats} &",
"prettier . --check &",
"rubocop &",
"wait"
],
"lint:fix": [
"nixpkgs-fmt .",
"statix fix --ignore .devbox",
"shfmt --write **/*.{sh,bats}",
"prettier . --write"
"prettier . --write",
"rubocop --autocorrect"
],
"test": [
"devbox run test-bash",
Expand Down
48 changes: 48 additions & 0 deletions devbox.lock
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,54 @@
"resolved": "github:NixOS/nixpkgs/75a52265bda7fd25e06e3a67dee3f0354e73243c#nodePackages.prettier",
"source": "nixpkg"
},
"rubocop@latest": {
"last_modified": "2024-08-31T19:22:30Z",
"resolved": "github:NixOS/nixpkgs/282e35e0762d64800d78e33ff225704baf9e5216#rubocop",
"source": "devbox-search",
"version": "1.65.1",
"systems": {
"aarch64-darwin": {
"outputs": [
{
"name": "out",
"path": "/nix/store/f7mjcpgy4kac87ygnwrc8zss4ps67x1w-ruby3.3-rubocop-1.65.1",
"default": true
}
],
"store_path": "/nix/store/f7mjcpgy4kac87ygnwrc8zss4ps67x1w-ruby3.3-rubocop-1.65.1"
},
"aarch64-linux": {
"outputs": [
{
"name": "out",
"path": "/nix/store/ls69blqq10hqadgn99v02qhdzfs99jkk-ruby3.3-rubocop-1.65.1",
"default": true
}
],
"store_path": "/nix/store/ls69blqq10hqadgn99v02qhdzfs99jkk-ruby3.3-rubocop-1.65.1"
},
"x86_64-darwin": {
"outputs": [
{
"name": "out",
"path": "/nix/store/xri9m3wj2zq4bwsszc9bkcn38664nl66-ruby3.3-rubocop-1.65.1",
"default": true
}
],
"store_path": "/nix/store/xri9m3wj2zq4bwsszc9bkcn38664nl66-ruby3.3-rubocop-1.65.1"
},
"x86_64-linux": {
"outputs": [
{
"name": "out",
"path": "/nix/store/358ycw2rdmyr26rxsxsszhsyfmxps29b-ruby3.3-rubocop-1.65.1",
"default": true
}
],
"store_path": "/nix/store/358ycw2rdmyr26rxsxsszhsyfmxps29b-ruby3.3-rubocop-1.65.1"
}
}
},
"shellcheck": {
"resolved": "github:NixOS/nixpkgs/75a52265bda7fd25e06e3a67dee3f0354e73243c#shellcheck",
"source": "nixpkg"
Expand Down
113 changes: 113 additions & 0 deletions scripts/github_auth.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
#!/usr/bin/env ruby
# frozen_string_literal: true

require 'net/http'
require 'json'
require 'uri'
require 'fileutils'

CLIENT_ID = 'Iv23liPv59QtSVurh6Fk'

def parse_response(response)
case response
when Net::HTTPOK, Net::HTTPCreated
JSON.parse(response.body)
when Net::HTTPUnauthorized
puts 'You are not authorized. Run the `login` command.'
exit 1
else
puts "An error occurred: #{response.code} #{response.message}"
exit 1
end
end

def request_device_code
uri = URI('https://github.com/login/device/code')
parameters = URI.encode_www_form('client_id' => CLIENT_ID)
headers = { 'Accept' => 'application/json' }

response = Net::HTTP.post(uri, parameters, headers)
parse_response(response)
end

def request_token(device_code)
uri = URI('https://github.com/login/oauth/access_token')
parameters = URI.encode_www_form({
'client_id' => CLIENT_ID,
'device_code' => device_code,
'grant_type' => 'urn:ietf:params:oauth:grant-type:device_code'
})
headers = { 'Accept' => 'application/json' }
response = Net::HTTP.post(uri, parameters, headers)
parse_response(response)
end
# rubocop:disable Metrics/MethodLength

def poll_for_token(device_code, interval)
loop do
response = request_token(device_code)
error, access_token, refresh_token = response.values_at('error', 'access_token', 'refresh_token')

if error
case error
when 'authorization_pending'
sleep interval
next
when 'slow_down'
sleep interval + 5
next
when 'expired_token'
puts 'The device code has expired. Please run `login` again.'
exit 1
when 'access_denied'
puts 'Login cancelled by user.'
exit 1
else
puts response
exit 1
end
else
return [access_token, refresh_token] unless error
end
end
end
# rubocop:enable Metrics/MethodLength

APP_SERVICE_NAME = 'com.cultureamp.hotel'
APP_ACCOUNT_NAME = 'github.app'

def set_tokens(access_token, refresh_token)
add_keychain_item(APP_SERVICE_NAME, APP_ACCOUNT_NAME, access_token)
add_keychain_item("#{APP_SERVICE_NAME}.refresh", APP_ACCOUNT_NAME, refresh_token)
end

def add_keychain_item(service_name, account_name, password)
`security add-generic-password -a #{account_name} -s #{service_name} -w "#{password}" -U`
rescue StandardError => e
puts "An error occurred while setting a token in the keychain: #{e.message}"
exit 1
end

# rubocop:disable Metrics/MethodLength
def main
os_name = `uname -s`
if os_name != "Darwin\n"
puts 'currently this script only supports MacOS'
exit 1
end
verification_uri, user_code, device_code, interval = request_device_code.values_at('verification_uri',
'user_code',
'device_code',
'interval')

puts "Please visit: #{verification_uri} and enter the following code: #{user_code}"

access_token, refresh_token = poll_for_token(device_code, interval)

set_tokens(access_token, refresh_token)

`sh -c "$(curl -fsSL https://raw.githubusercontent.com/cultureamp/devbox-extras/main/scripts/install_hotel.sh)"`
end
# rubocop:enable Metrics/MethodLength

main
Loading

0 comments on commit 62b5dfd

Please sign in to comment.