Skip to content

Commit

Permalink
Merge branch 'master' into SM-989-create-build-and-publish-pipelines-…
Browse files Browse the repository at this point in the history
…for-the-python-language-wrapper
  • Loading branch information
tangowithfoxtrot authored Nov 30, 2023
2 parents b238851 + b6c6532 commit 1558df2
Show file tree
Hide file tree
Showing 24 changed files with 822 additions and 0 deletions.
7 changes: 7 additions & 0 deletions .github/workflows/generate_schemas.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,13 @@ jobs:
path: ${{ github.workspace }}/languages/python/bitwarden_sdk/schemas.py
if-no-files-found: error

- name: Upload ruby schemas artifact
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
with:
name: schemas.rb
path: ${{ github.workspace }}/languages/ruby/bitwarden_sdk/lib/schemas.rb
if-no-files-found: error

- name: Upload json schemas artifact
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
with:
Expand Down
88 changes: 88 additions & 0 deletions .github/workflows/publish-ruby.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
name: Publish Ruby SDK

on:
pull_request:
branches:
- master

jobs:
generate_schemas:
uses: ./.github/workflows/generate_schemas.yml

build_rust:
uses: ./.github/workflows/build-rust-cross-platform.yml

build_ruby:
name: Build Ruby
runs-on: ubuntu-22.04
needs:
- generate_schemas
- build_rust
steps:
- name: Checkout Repository
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3

- name: Set up Ruby
uses: ruby/setup-ruby@54a18e26dbbb1eabc604f317ade9a5788dddef81 # v1.159.0
with:
ruby-version: 3.2

- name: Download Ruby schemas artifact
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: schemas.rb
path: languages/ruby/bitwarden_sdk/lib

- name: Download x86_64-apple-darwin files
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: libbitwarden_c_files-x86_64-apple-darwin
path: temp/macos-x64

- name: Download aarch64-apple-darwin files
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: libbitwarden_c_files-aarch64-apple-darwin
path: temp/macos-arm64

- name: Download x86_64-unknown-linux-gnu files
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: libbitwarden_c_files-x86_64-unknown-linux-gnu
path: temp/ubuntu-x64

- name: Download x86_64-pc-windows-msvc files
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: libbitwarden_c_files-x86_64-pc-windows-msvc
path: temp/windows-x64

- name: Copy lib files
run: |
mkdir -p languages/ruby/bitwarden_sdk/lib/macos-arm64
mkdir -p languages/ruby/bitwarden_sdk/lib/ubuntu-x64
mkdir -p languages/ruby/bitwarden_sdk/lib/macos-x64
mkdir -p languages/ruby/bitwarden_sdk/lib/windows-x64
platforms=("macos-arm64" "ubuntu-x64" "macos-x64" "windows-x64")
files=("libbitwarden_c.dylib" "libbitwarden_c.so" "libbitwarden_c.dylib" "bitwarden_c.dll")
for ((i=0; i<${#platforms[@]}; i++)); do
cp "temp/${platforms[$i]}/${files[$i]}" "languages/ruby/bitwarden_sdk/lib/${platforms[$i]}/${files[$i]}"
done
shell: bash

- name: Build gem
run: gem build bitwarden-sdk.gemspec
working-directory: languages/ruby/bitwarden_sdk

- name: Push gem to Rubygems
run: |
mkdir -p $HOME/.gem
touch $HOME/.gem/credentials
chmod 0600 $HOME/.gem/credentials
printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
gem push *.gem
env:
GEM_HOST_API_KEY: ${{ secrets.GEM_HOST_API_KEY }}
working-directory: languages/ruby/bitwarden_sdk
3 changes: 3 additions & 0 deletions languages/ruby/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
*.lock
*.gem
bitwarden_sdk/lib/schemas.rb
5 changes: 5 additions & 0 deletions languages/ruby/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
## [Unreleased]

## [0.1.0] - 2023-09-19

- Initial release
95 changes: 95 additions & 0 deletions languages/ruby/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# Bitwarden Secrets Manager SDK

Ruby bindings for interacting with the [Bitwarden Secrets Manager]. This is a beta release and might be missing some functionality.

## Installation

Requirements: Ruby >= 3.0

Install gem: `gem install bitwarden-sdk`

Import it: require 'bitwarden-sdk'


## Usage

To interact with client first you need to obtain access token from Bitwarden.
Client will be initialized with default client settings if they are not provided
via env variables.

```ruby
require 'bitwarden-sdk'

# then you can initialize BitwardenSettings:
bitwarden_settings = BitwardenSDK::BitwardenSettings.new(
'https://api.bitwarden.com',
'https://identity.bitwarden.com'
)

# By passing these setting you can initialize BitwardenClient

bw_client = BitwardenSDK::BitwardenClient.new(bitwarden_settings)
response = bw_client.access_token_login(token)
puts response
```

After successful authorization you can interact with client to manage your projects and secrets.
```ruby

# CREATE project
project_name = 'Test project 1'
response = bw_client.project_client.create_project(project_name, organization_id)
puts response
project_id = response['id']

# GET project
response = bw_client.project_client.get(project_id)
puts response

# LIST projects
response = bw_client.project_client.list_projects(organization_id)
puts response

# UPDATE projects
name = 'Updated test project 1'
response = bw_client.project_client.update_project(project_id, name, organization_id)
puts response

# DELETE project
response = bw_client.project_client.delete_projects([project_id])
puts response
```

Similarly, you interact with secrets:
```ruby
# CREATE secret
key = 'AWS-SES'
note = 'Private account'
value = '8t27.dfj;'
response = bw_client.secrets_client.create(key, note, organization_id, [project_id], value)
puts response
secret_id = response['id']

# GET secret
response = bw_client.secrets_client.get(secret_id)
puts response

# GET secret by ids
response = bw_client.secrets_client.get_by_ids([secret_id])
puts response

# LIST secrets
response = bw_client.secrets_client.list(organization_id)
puts response

# UPDATE secret
note = 'updated password'
value = '7I.ert10AjK'
response = bw_client.secrets_client.update(secret_id, key, note,organization_id, [project_id], value)
puts response

# DELETE secret
response = bw_client.secrets_client.delete_secret([secret_id])
puts response
```
[Bitwarden Secrets Manager]: https://bitwarden.com/products/secrets-manager/
8 changes: 8 additions & 0 deletions languages/ruby/bitwarden_sdk/Rakefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# frozen_string_literal: true

require "bundler/gem_tasks"
require "rubocop/rake_task"

RuboCop::RakeTask.new

task default: :rubocop
47 changes: 47 additions & 0 deletions languages/ruby/bitwarden_sdk/bitwarden-sdk.gemspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# frozen_string_literal: true

require_relative 'lib/version'

Gem::Specification.new do |spec|
spec.name = 'bitwarden-sdk'
spec.version = BitwardenSDK::VERSION
spec.authors = ['Bitwarden Inc.']
spec.email = ['hello@bitwarden_sdk.com']

spec.summary = 'Bitwarden Secrets Manager SDK.'
spec.description = 'Ruby wrapper for Bitwarden secrets manager SDK.'
spec.homepage = 'https://bitwarden.com/products/secrets-manager/'
spec.required_ruby_version = '>= 3.0.0'

spec.metadata['homepage_uri'] = spec.homepage
spec.metadata['source_code_uri'] = 'https://github.com/bitwarden/sdk'
spec.metadata['changelog_uri'] = 'https://github.com/bitwarden/sdk/blob/master/languages/ruby/CHANGELOG.md'

# Specify which files should be added to the gem when it is released.
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
spec.files = Dir.chdir(__dir__) do
`git ls-files -z`.split("\x0").reject do |f|
(File.expand_path(f) == __FILE__) || f.start_with?(*%w[bin/ test/ spec/ features/ .git .circleci appveyor])
end
end

spec.files += Dir.glob('lib/ubuntu-x64/**/*')
spec.files += Dir.glob('lib/macos-x64/**/*')
spec.files += Dir.glob('lib/windows-x64/**/*')
spec.files += Dir.glob('lib/macos-arm64/**/*')
spec.files += Dir.glob('lib/schemas.rb')

spec.bindir = 'exe'
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
spec.require_paths = ['lib']

# Uncomment to register a new dependency of your gem
# spec.add_dependency "example-gem", "~> 1.0"
spec.add_dependency 'dry-struct', '~> 1.6'
spec.add_dependency 'dry-types', '~> 1.7'
spec.add_dependency 'ffi', '~> 1.15'
spec.add_dependency 'json', '~> 2.6'
spec.add_dependency 'rake', '~> 13.0'
spec.add_dependency 'rubocop', '~> 1.21'

end
56 changes: 56 additions & 0 deletions languages/ruby/bitwarden_sdk/lib/bitwarden-sdk.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# frozen_string_literal: true

require 'json'
require 'dry-types'

require_relative 'schemas'
require_relative 'extended_schemas/schemas'
require_relative 'command_runner'
require_relative 'bitwarden_lib'
require_relative 'bitwarden_error'
require_relative 'projects'
require_relative 'secrets'

module BitwardenSDK
class BitwardenSettings
attr_accessor :api_url, :identity_url

def initialize(api_url, identity_url)
# if api_url.nil? || identity_url.nil?
# raise ArgumentError, "api_url and identity_url cannot be nil"
# end

@api_url = api_url
@identity_url = identity_url
end
end

class BitwardenClient
attr_reader :bitwarden, :project_client, :secrets_client

def initialize(bitwarden_settings)
client_settings = ClientSettings.new(
api_url: bitwarden_settings.api_url,
identity_url: bitwarden_settings.identity_url,
user_agent: 'Bitwarden RUBY-SDK',
device_type: nil
)

@bitwarden = BitwardenLib
@handle = @bitwarden.init(client_settings.to_json)
@command_runner = CommandRunner.new(@bitwarden, @handle)
@project_client = ProjectsClient.new(@command_runner)
@secrets_client = SecretsClient.new(@command_runner)
end

def access_token_login(access_token)
access_token_request = AccessTokenLoginRequest.new(access_token: access_token)
@command_runner.run(SelectiveCommand.new(access_token_login: access_token_request))
nil
end

def free_mem
@bitwarden.free_mem(@handle)
end
end
end
9 changes: 9 additions & 0 deletions languages/ruby/bitwarden_sdk/lib/bitwarden_error.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# frozen_string_literal: true

module BitwardenSDK
class BitwardenError < StandardError
def initialize(message = 'Error getting response')
super(message)
end
end
end
35 changes: 35 additions & 0 deletions languages/ruby/bitwarden_sdk/lib/bitwarden_lib.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# frozen_string_literal: true

require 'ffi'

module BitwardenSDK
module BitwardenLib
extend FFI::Library

def self.mac_with_intel?
`uname -m`.strip == 'x86_64'
end

ffi_lib case RUBY_PLATFORM
when /darwin/
local_file = if mac_with_intel?
File.expand_path('macos-x64/libbitwarden_c.dylib', __dir__)
else
File.expand_path('macos-arm64/libbitwarden_c.dylib', __dir__)
end
File.exist?(local_file) ? local_file : File.expand_path('../../../../target/debug/libbitwarden_c.dylib', __dir__)
when /linux/
local_file = File.expand_path('ubuntu-x64/libbitwarden_c.so', __dir__)
File.exist?(local_file) ? local_file : File.expand_path('../../../../target/debug/libbitwarden_c.so', __dir__)
when /mswin|mingw/
local_file = File.expand_path('windows-x64/bitwarden_c.dll', __dir__)
File.exist?(local_file) ? local_file : File.expand_path('../../../../target/debug/bitwarden_c.dll', __dir__)
else
raise "Unsupported platform: #{RUBY_PLATFORM}"
end

attach_function :init, [:string], :pointer
attach_function :run_command, %i[string pointer], :string
attach_function :free_mem, [:pointer], :void
end
end
15 changes: 15 additions & 0 deletions languages/ruby/bitwarden_sdk/lib/command_runner.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# frozen_string_literal: true

module BitwardenSDK
class CommandRunner
def initialize(bitwarden_sdk, handle)
@bitwarden_sdk = bitwarden_sdk
@handle = handle
end

# @param [Dry-Struct] cmd
def run(cmd)
@bitwarden_sdk.run_command(cmd.to_json, @handle)
end
end
end
Loading

0 comments on commit 1558df2

Please sign in to comment.