lex-github
GitHub integration for LegionIO. Provides runners for interacting with the GitHub REST API including repositories, issues, pull requests, labels, comments, commits, users, organizations, gists, search, Actions workflows, checks, releases, deployments, webhooks, and full GitHub App + OAuth authentication.
Installation
gem install lex-github
Authentication
Personal Access Token (PAT)
client = Legion::Extensions::Github::Client.new(token: 'ghp_your_token')
GitHub App (JWT + Installation Token)
# Set in Legion::Settings
# github.app.app_id: '12345'
# github.app.private_key_path: '/path/to/private-key.pem'
# github.app.installation_id: '67890'
client = Legion::Extensions::Github::Client.new
# Credentials resolved automatically from settings
Or via Vault:
vault write secret/github/app/app_id value='12345'
vault write secret/github/app/private_key value='-----BEGIN RSA PRIVATE KEY-----...'
vault write secret/github/app/installation_id value='67890'
OAuth Delegated (browser-based login)
# CLI login
legion lex exec github auth login
# Programmatic (using the CLI::Auth mixin)
auth = Object.new.extend(Legion::Extensions::Github::CLI::Auth)
result = auth.login(client_id: 'Iv1.abc', client_secret: 'secret')
# Opens browser → PKCE flow; token can be stored in Vault if Vault integration is configured
Credential Resolution Chain
lex-github resolves credentials automatically in priority order:
- Vault OAuth delegated token
- Settings OAuth access token
- Vault GitHub App installation token (auto-generates on miss)
- Settings GitHub App installation token
- Vault PAT
- Settings PAT (
github.token) ghCLI token (gh auth token)GITHUB_TOKENenvironment variable
Rate-limited credentials are skipped automatically. Scope-denied credentials (403) are skipped for the specific owner/repo and retried with the next source.
Standalone Usage
require 'legion/extensions/github'
client = Legion::Extensions::Github::Client.new(token: 'ghp_your_token')
# Repositories
client.list_repos(username: 'octocat')
client.get_repo(owner: 'octocat', repo: 'Hello-World')
client.create_repo(name: 'my-new-repo', private: true)
# Issues
client.list_issues(owner: 'octocat', repo: 'Hello-World')
client.create_issue(owner: 'octocat', repo: 'Hello-World', title: 'Bug report')
# Pull Requests
client.list_pull_requests(owner: 'octocat', repo: 'Hello-World')
client.create_pull_request(owner: 'octocat', repo: 'Hello-World', title: 'Fix', head: 'fix-branch', base: 'main')
client.merge_pull_request(owner: 'octocat', repo: 'Hello-World', pull_number: 42)
# GitHub Actions
client.list_workflows(owner: 'octocat', repo: 'Hello-World')
client.trigger_workflow(owner: 'octocat', repo: 'Hello-World', workflow_id: 'ci.yml', ref: 'main')
client.get_workflow_run(owner: 'octocat', repo: 'Hello-World', run_id: 12345)
# Check Runs (CI status)
client.create_check_run(owner: 'octocat', repo: 'Hello-World', name: 'CI', head_sha: 'abc123')
client.update_check_run(owner: 'octocat', repo: 'Hello-World', check_run_id: 1,
status: 'completed', conclusion: 'success')
# Releases
client.list_releases(owner: 'octocat', repo: 'Hello-World')
client.create_release(owner: 'octocat', repo: 'Hello-World', tag_name: 'v1.0.0')
# Deployments
client.create_deployment(owner: 'octocat', repo: 'Hello-World', ref: 'main', environment: 'production')
client.create_deployment_status(owner: 'octocat', repo: 'Hello-World', deployment_id: 1, state: 'success')
# Webhooks
client.list_webhooks(owner: 'octocat', repo: 'Hello-World')
client.create_webhook(owner: 'octocat', repo: 'Hello-World',
config: { url: 'https://example.com/webhook', content_type: 'json' })
# GitHub App
jwt_token = client.generate_jwt(app_id: '12345', private_key: File.read('private-key.pem'))
client.create_installation_token(jwt: jwt_token, installation_id: '67890')
client.list_installations(jwt: jwt_token)
# Webhook verification
client.verify_signature(payload: request.body.read, signature: request.env['HTTP_X_HUB_SIGNATURE_256'],
secret: 'webhook_secret')
Functions
Repositories
list_repos,get_repo,create_repo,update_repo,delete_repo,list_branches,list_tags
Issues
list_issues,get_issue,create_issue,update_issue,list_issue_comments,create_issue_comment
Pull Requests
list_pull_requests,get_pull_request,create_pull_request,update_pull_request,merge_pull_requestlist_pull_request_commits,list_pull_request_files,list_pull_request_reviews,create_review
Labels
list_labels,get_label,create_label,update_label,delete_labeladd_labels_to_issue,remove_label_from_issue
Comments
list_comments,get_comment,create_comment,update_comment,delete_comment
Users
get_authenticated_user,get_user,list_followers,list_following
Organizations
list_user_orgs,get_org,list_org_repos,list_org_members
Gists
list_gists,get_gist,create_gist,update_gist,delete_gist
Search
search_repositories,search_issues,search_users,search_code
Commits
list_commits,get_commit,compare_commits
Branches
create_branch
Contents
commit_files
GitHub Actions
list_workflows,get_workflow,list_workflow_runs,get_workflow_run,trigger_workflowcancel_workflow_run,rerun_workflow,rerun_failed_jobslist_workflow_run_jobs,download_workflow_run_logs,list_workflow_run_artifacts
Checks
create_check_run,update_check_run,get_check_runlist_check_runs_for_ref,list_check_suites_for_ref,get_check_suitererequest_check_suite,list_check_run_annotations
Releases
list_releases,get_release,get_latest_release,get_release_by_tagcreate_release,update_release,delete_releaselist_release_assets,delete_release_asset
Deployments
list_deployments,get_deployment,create_deployment,delete_deploymentlist_deployment_statuses,create_deployment_status,get_deployment_status
Repository Webhooks
list_webhooks,get_webhook,create_webhook,update_webhook,delete_webhookping_webhook,test_webhook,list_webhook_deliveries
GitHub App Auth
generate_jwt,create_installation_token,list_installations,get_installationgenerate_manifest,exchange_manifest_code,manifest_urlverify_signature,parse_event,receive_event
OAuth
generate_pkce,authorize_url,exchange_code,refresh_tokenrequest_device_code,poll_device_code,revoke_token
Error Handling
begin
client.get_repo(owner: 'org', repo: 'private-repo')
rescue Legion::Extensions::Github::RateLimitError => e
puts "Rate limited, resets at: #{e.reset_at}"
rescue Legion::Extensions::Github::ScopeDeniedError => e
puts "No credential authorized for #{e.owner}/#{e.repo}"
rescue Legion::Extensions::Github::AuthorizationError => e
puts "All credentials exhausted: #{e.attempted_sources}"
end
Requirements
- Ruby >= 3.4
- LegionIO framework (optional for standalone client usage)
faraday>= 2.0jwt~> 2.7 (for GitHub App authentication)base64>= 0.1 (for OAuth PKCE)
License
MIT