From a5b228bfc5db84935e1e6f935d9f305ee03737ef Mon Sep 17 00:00:00 2001 From: miverso2 Date: Fri, 4 Jun 2021 17:27:50 -0500 Subject: [PATCH] moving data from https://bitbucket.org/legion-io/legion-crypt.git --- .gitignore | 15 ++++ .rubocop.yml | 26 +++++++ CHANGELOG.md | 4 + CONTRIBUTING.md | 3 +- Gemfile | 10 +++ README.md | 63 ++++++++++----- SECURITY.md | 9 +++ legion-crypt.gemspec | 32 ++++++++ lib/legion/crypt.rb | 40 ++++++++++ lib/legion/crypt/cipher.rb | 54 +++++++++++++ lib/legion/crypt/cluster_secret.rb | 119 +++++++++++++++++++++++++++++ lib/legion/crypt/settings.rb | 44 +++++++++++ lib/legion/crypt/vault.rb | 94 +++++++++++++++++++++++ lib/legion/crypt/vault_renewer.rb | 33 ++++++++ lib/legion/crypt/version.rb | 7 ++ sonar-project.properties | 11 +++ spec/legion/cipher_spec.rb | 32 ++++++++ spec/legion/cluster_secret_spec.rb | 71 +++++++++++++++++ spec/legion/crypt_spec.rb | 19 +++++ spec/legion/settings_spec.rb | 13 ++++ spec/legion/vault_renewer_spec.rb | 43 +++++++++++ spec/legion/vault_spec.rb | 62 +++++++++++++++ spec/legion/version_spec.rb | 10 +++ spec/spec_helper.rb | 29 +++++++ 24 files changed, 823 insertions(+), 20 deletions(-) create mode 100644 .gitignore create mode 100644 .rubocop.yml create mode 100644 CHANGELOG.md create mode 100644 Gemfile create mode 100644 SECURITY.md create mode 100644 legion-crypt.gemspec create mode 100644 lib/legion/crypt.rb create mode 100644 lib/legion/crypt/cipher.rb create mode 100644 lib/legion/crypt/cluster_secret.rb create mode 100644 lib/legion/crypt/settings.rb create mode 100644 lib/legion/crypt/vault.rb create mode 100644 lib/legion/crypt/vault_renewer.rb create mode 100644 lib/legion/crypt/version.rb create mode 100644 sonar-project.properties create mode 100644 spec/legion/cipher_spec.rb create mode 100644 spec/legion/cluster_secret_spec.rb create mode 100644 spec/legion/crypt_spec.rb create mode 100644 spec/legion/settings_spec.rb create mode 100644 spec/legion/vault_renewer_spec.rb create mode 100644 spec/legion/vault_spec.rb create mode 100644 spec/legion/version_spec.rb create mode 100644 spec/spec_helper.rb diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..54781f1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +/.bundle/ +/.yardoc +/Gemfile.lock +/_yardoc/ +/coverage/ +/doc/ +/pkg/ +/spec/reports/ +/tmp/ +/legion/.idea/ +/.idea/ +*.key +# rspec failure tracking +.rspec_status +legionio.key diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 0000000..b9e47c1 --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,26 @@ +Layout/LineLength: + Max: 140 +Metrics/MethodLength: + Max: 50 +Metrics/ClassLength: + Max: 1500 +Metrics/BlockLength: + Max: 50 +Metrics/CyclomaticComplexity: + Max: 14 +Metrics/AbcSize: + Max: 17 +Metrics/PerceivedComplexity: + Max: 16 +Naming/MethodParameterName: + Enabled: false +Style/Documentation: + Enabled: false +AllCops: + TargetRubyVersion: 2.6 + NewCops: enable + SuggestExtensions: false +Style/FrozenStringLiteralComment: + Enabled: false +Gemspec/RequiredRubyVersion: + Enabled: false \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..fa62b9f --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,4 @@ +# Legion::Crypt + +## v1.2.0 +Moving from BitBucket to GitHub inside the Optum org. All git history is reset from this point on diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 67d7542..b0c397d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -15,10 +15,11 @@ We track our work using Issues in GitHub. Feel free to open up your own issue to ## Coding Standards We have some general guidelines towards contributing to this project. +Please run RSpec and Rubocop while developing code for LegionIO ### Languages -*Lua* +*Ruby* ## Pull Requests diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..edaf657 --- /dev/null +++ b/Gemfile @@ -0,0 +1,10 @@ +source 'https://rubygems.org' + +gemspec +group :test do + gem 'rake' + gem 'rspec' + gem 'rspec_junit_formatter' + gem 'rubocop' + gem 'simplecov' +end diff --git a/README.md b/README.md index bc2c0c2..4b76b44 100644 --- a/README.md +++ b/README.md @@ -1,31 +1,56 @@ -# Welcome to your new OSS project +Legion::Crypt +===== -This project currently has the base documentation files required. Replace this -file with your own README.md. +Legion::Crypt is the class responsible for encryption, managing secrets and connecting with Vault -## Files included +Supported Ruby versions and implementations +------------------------------------------------ -**CODE_OF_CONDUCT.md** +Legion::Crypt should work identically on: -Use without changes +* JRuby 9.2+ +* Ruby 2.4+ -**INDIVIDUAL_CONTRIBUTOR_LICENSE.md** -Use without changes +Installation and Usage +------------------------ -**CONTRIBUTING.md** +You can verify your installation using this piece of code: -This file has some portions that are required and others that can be customized. -Customize the Coding Standards section to mention the languages used by your project. -Feel free to add any rules and requirements that you would like people to follow -when contributing to your project. +```bash +gem install legion-crypt +``` -**NOTICE.txt** +```ruby +require 'legion/crypt' -This file is needed if your project is licensed under the Apache 2.0 license. -If you are using this license, fill it out according to the prompts. Otherwise, -delete this file. +Legion::Crypt.start +Legion::Crypt.encrypt('this is my string') +Legion::Crypt.decrypt(message) +``` -## Additional Repo Updates +Settings +---------- -Make sure that you have a project description and appropriate repository topics. +```json +{ + "vault": { + "enabled": false, + "protocol": "http", + "address": "localhost", + "port": 8200, + "token": null, + "connected": false + }, + "cs_encrypt_ready": false, + "dynamic_keys": true, + "cluster_secret": null, + "save_private_key": false, + "read_private_key": false +} +``` + +Authors +---------- + +* [Matthew Iverson](https://github.com/Esity) - current maintainer diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..acc4d53 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,9 @@ +# Security Policy + +## Supported Versions +| Version | Supported | +| ------- | ------------------ | +| 1.x.x | :white_check_mark: | + +## Reporting a Vulnerability +To be added diff --git a/legion-crypt.gemspec b/legion-crypt.gemspec new file mode 100644 index 0000000..f1bb1e5 --- /dev/null +++ b/legion-crypt.gemspec @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +require_relative 'lib/legion/crypt/version' + +Gem::Specification.new do |spec| + spec.name = 'legion-crypt' + spec.version = Legion::Crypt::VERSION + spec.authors = ['Esity'] + spec.email = %w[matthewdiverson@gmail.com ruby@optum.com] + spec.summary = 'Handles requests for encrypt, decrypting, connecting to Vault, among other things' + spec.description = 'A gem used by the LegionIO framework for encryption' + spec.homepage = 'https://github.com/Optum/legion-crypt' + spec.license = 'Apache-2.0' + spec.require_paths = ['lib'] + spec.required_ruby_version = '>= 2.4' + spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) } + spec.test_files = spec.files.select { |p| p =~ %r{^test/.*_test.rb} } + spec.extra_rdoc_files = %w[README.md LICENSE CHANGELOG.md] + spec.metadata = { + 'bug_tracker_uri' => 'https://github.com/Optum/legion-crypt/issues', + 'changelog_uri' => 'https://github.com/Optum/legion-crypt/src/main/CHANGELOG.md', + 'documentation_uri' => 'https://github.com/Optum/legion-crypt', + 'homepage_uri' => 'https://github.com/Optum/LegionIO', + 'source_code_uri' => 'https://github.com/Optum/legion-crypt', + 'wiki_uri' => 'https://github.com/Optum/legion-crypt/wiki' + } + + spec.add_dependency 'vault', '>= 0.15.0' + + spec.add_development_dependency 'legion-logging' + spec.add_development_dependency 'legion-settings' +end diff --git a/lib/legion/crypt.rb b/lib/legion/crypt.rb new file mode 100644 index 0000000..fe72c1e --- /dev/null +++ b/lib/legion/crypt.rb @@ -0,0 +1,40 @@ +require 'openssl' +require 'base64' +require 'legion/crypt/version' +require 'legion/crypt/settings' +require 'legion/crypt/cipher' + +module Legion + module Crypt + class << self + attr_reader :sessions + + include Legion::Crypt::Cipher + + unless Gem::Specification.find_by_name('vault').nil? + require 'legion/crypt/vault' + include Legion::Crypt::Vault + end + + def start + Legion::Logging.debug 'Legion::Crypt is running start' + ::File.write('./legionio.key', private_key) if settings[:save_private_key] + + connect_vault unless settings[:vault][:token].nil? + end + + def settings + if Legion.const_defined?('Settings') + Legion::Settings[:crypt] + else + Legion::Crypt::Settings.default + end + end + + def shutdown + shutdown_renewer + close_sessions + end + end + end +end diff --git a/lib/legion/crypt/cipher.rb b/lib/legion/crypt/cipher.rb new file mode 100644 index 0000000..256c7fa --- /dev/null +++ b/lib/legion/crypt/cipher.rb @@ -0,0 +1,54 @@ +require 'securerandom' +require 'legion/crypt/cluster_secret' + +module Legion + module Crypt + module Cipher + include Legion::Crypt::ClusterSecret + + def encrypt(message) + cipher = OpenSSL::Cipher.new('aes-256-cbc') + cipher.encrypt + cipher.key = cs + iv = cipher.random_iv + { enciphered_message: Base64.encode64(cipher.update(message) + cipher.final), iv: Base64.encode64(iv) } + end + + def decrypt(message, iv) + until cs.is_a?(String) || Legion::Settings[:client][:shutting_down] + Legion::Logging.debug('sleeping Legion::Crypt.decrypt due to CS not being set') + sleep(0.5) + end + + decipher = OpenSSL::Cipher.new('aes-256-cbc') + decipher.decrypt + decipher.key = cs + decipher.iv = Base64.decode64(iv) + message = Base64.decode64(message) + decipher.update(message) + decipher.final + end + + def encrypt_from_keypair(message:, pub_key: public_key) + rsa_public_key = OpenSSL::PKey::RSA.new(pub_key) + + Base64.encode64(rsa_public_key.public_encrypt(message)) + end + + def decrypt_from_keypair(message:, **_opts) + private_key.private_decrypt(Base64.decode64(message)) + end + + def public_key + @public_key ||= private_key.public_key.to_s + end + + def private_key + @private_key ||= if Legion::Settings[:crypt][:read_private_key] && File.exist?('./legionio.key') + OpenSSL::PKey::RSA.new File.read './legionio.key' + else + OpenSSL::PKey::RSA.new 2048 + end + end + end + end +end diff --git a/lib/legion/crypt/cluster_secret.rb b/lib/legion/crypt/cluster_secret.rb new file mode 100644 index 0000000..ae081ac --- /dev/null +++ b/lib/legion/crypt/cluster_secret.rb @@ -0,0 +1,119 @@ +require 'securerandom' + +module Legion + module Crypt + module ClusterSecret + def find_cluster_secret + %i[from_settings from_vault from_transport generate_secure_random].each do |method| + result = send(method) + next if result.nil? + + unless validate_hex(result) + Legion::Logging.warn("Legion::Crypt.#{method} gave a value but it isn't a valid hex") + next + end + + set_cluster_secret(result, method != :from_vault) + return result + end + return unless only_member? + + key = generate_secure_random + set_cluster_secret(key) + key + end + + def from_vault + return nil unless method_defined? :get + return nil unless Legion::Settings[:crypt][:vault][:read_cluster_secret] + return nil unless Legion::Settings[:crypt][:vault][:connected] + return nil unless Legion::Crypt.exist?('crypt') + + get('crypt')[:cluster_secret] + rescue StandardError + nil + end + + def from_settings + Legion::Settings[:crypt][:cluster_secret] + end + alias cluster_secret from_settings + + def from_transport # rubocop:disable Metrics/AbcSize + require 'legion/transport/messages/request_cluster_secret' + Legion::Logging.info 'Requesting cluster secret via public key' + Legion::Logging.warn 'cluster_secret already set but we are requesting a new value' unless from_settings.nil? + start = Time.now + Legion::Transport::Messages::RequestClusterSecret.new.publish + sleep_time = 0.001 + until !Legion::Settings[:crypt][:cluster_secret].nil? || (Time.now - start) > cluster_secret_timeout + sleep(sleep_time) + sleep_time *= 2 unless sleep_time > 0.5 + end + + unless from_settings.nil? + Legion::Logging.info "Received cluster secret in #{((Time.new - start) * 1000.0).round}ms" + from_settings + end + + Legion::Logging.error 'Cluster secret is still unknown!' + rescue StandardError => e + Legion::Logging.error e.message + Legion::Logging.error e.backtrace[0..10] + end + + def force_cluster_secret + Legion::Settings[:crypt][:force_cluster_secret] || true + end + + def settings_push_vault + Legion::Settings[:crypt][:vault][:push_cs_to_vault] || true + end + + def only_member? + Legion::Transport::Queue.new('node.crypt', passive: true).consumer_count.zero? + rescue StandardError + nil + end + + def set_cluster_secret(value, push_to_vault = true) # rubocop:disable Style/OptionalBooleanParameter + raise TypeError unless value.to_i(32).to_s(32) == value.downcase + + Legion::Settings[:crypt][:cs_encrypt_ready] = true + push_cs_to_vault if push_to_vault && settings_push_vault + + Legion::Settings[:crypt][:cluster_secret] = value + end + + def push_cs_to_vault + return false unless Legion::Settings[:crypt][:vault][:connected] && Legion::Settings[:crypt][:cluster_secret] + + Legion::Logging.info 'Pushing Cluster Secret to Vault' + Legion::Crypt.write('cluster', secret: Legion::Settings[:crypt][:cluster_secret]) + end + + def cluster_secret_timeout + Legion::Settings[:crypt][:cluster_secret_timeout] || 5 + end + + def secret_length + Legion::Settings[:crypt][:cluster_lenth] || 32 + end + + def generate_secure_random(length = secret_length) + SecureRandom.hex(length) + end + + def cs + @cs ||= Digest::SHA256.digest(find_cluster_secret) + rescue StandardError => e + Legion::Logging.error e.message + Legion::Logging.error e.backtrace[0..10] + end + + def validate_hex(value, length = secret_length) + value.to_i(length).to_s(length) == value.downcase + end + end + end +end diff --git a/lib/legion/crypt/settings.rb b/lib/legion/crypt/settings.rb new file mode 100644 index 0000000..ea984f2 --- /dev/null +++ b/lib/legion/crypt/settings.rb @@ -0,0 +1,44 @@ +module Legion + module Crypt + module Settings + def self.default + { + vault: vault, + cs_encrypt_ready: false, + dynamic_keys: true, + cluster_secret: nil, + save_private_key: true, + read_private_key: true + } + end + + def self.vault + { + enabled: !Gem::Specification.find_by_name('vault').nil?, + protocol: 'http', + address: 'localhost', + port: 8200, + token: ENV['VAULT_DEV_ROOT_TOKEN_ID'] || ENV['VAULT_TOKEN_ID'] || nil, + connected: false, + renewer_time: 5, + renewer: true, + push_cluster_secret: true, + read_cluster_secret: true, + kv_path: ENV['LEGION_VAULT_KV_PATH'] || 'legion' + } + end + end + end +end + +begin + Legion::Settings.merge_settings('crypt', Legion::Crypt::Settings.default) if Legion.const_defined?('Settings') +rescue StandardError => e + if Legion.const_defined?('Logging') && Legion::Logging.method_defined?(:fatal) + Legion::Logging.fatal(e.message) + Legion::Logging.fatal(e.backtrace) + else + puts e.message + puts e.backtrace + end +end diff --git a/lib/legion/crypt/vault.rb b/lib/legion/crypt/vault.rb new file mode 100644 index 0000000..e59569d --- /dev/null +++ b/lib/legion/crypt/vault.rb @@ -0,0 +1,94 @@ +require 'vault' + +module Legion + module Crypt + module Vault + attr_accessor :sessions + + def settings + Legion::Settings[:crypt][:vault] + end + + def connect_vault # rubocop:disable Metrics/AbcSize + @sessions = [] + ::Vault.address = "#{Legion::Settings[:crypt][:vault][:protocol]}://#{Legion::Settings[:crypt][:vault][:address]}:#{Legion::Settings[:crypt][:vault][:port]}" # rubocop:disable Layout/LineLength + + Legion::Settings[:crypt][:vault][:token] = ENV['VAULT_DEV_ROOT_TOKEN_ID'] if ENV.key? 'VAULT_DEV_ROOT_TOKEN_ID' + return nil if Legion::Settings[:crypt][:vault][:token].nil? + + ::Vault.token = Legion::Settings[:crypt][:vault][:token] + Legion::Settings[:crypt][:vault][:connected] = true if ::Vault.sys.health_status.initialized? + return unless Legion.const_defined? 'Extensions::Actors::Every' + + require_relative 'vault_renewer' + @renewer = Legion::Crypt::Vault::Renewer.new + rescue StandardError => e + Legion::Logging.error e.message + Legion::Settings[:crypt][:vault][:connected] = false + false + end + + def read(path, type = 'legion') + full_path = type.nil? || type.empty? ? "#{type}/#{path}" : path + lease = ::Vault.logical.read(full_path) + add_session(path: lease.lease_id) if lease.respond_to? :lease_id + lease.data + end + + def get(path) + result = ::Vault.kv(settings[:vault][:kv_path]).read(path) + return nil if result.nil? + + result.data + end + + def write(path, **hash) + ::Vault.kv(settings[:vault][:kv_path]).write(path, **hash) + end + + def exist?(path) + !::Vault.kv(settings[:vault][:kv_path]).read_metadata(path).nil? + end + + def add_session(path:) + @sessions.push(path) + end + + def close_sessions + return if @sessions.nil? + + Legion::Logging.info 'Closing all Legion::Crypt vault sessions' + + @sessions.each do |session| + close_session(session: session) + end + end + + def shutdown_renewer + return unless Legion::Settings[:crypt][:vault][:connected] + return if @renewer.nil? + + Legion::Logging.debug 'Shutting down Legion::Crypt::Vault::Renewer' + @renewer.cancel + end + + def close_session(session:) + ::Vault.sys.revoke(session) + end + + def renew_session(session:) + ::Vault.sys.renew(session) + end + + def renew_sessions(**_opts) + @sessions.each do |session| + renew_session(session: session) + end + end + + def vault_exists?(name) + ::Vault.sys.mounts.key?(name.to_sym) + end + end + end +end diff --git a/lib/legion/crypt/vault_renewer.rb b/lib/legion/crypt/vault_renewer.rb new file mode 100644 index 0000000..f6ef30b --- /dev/null +++ b/lib/legion/crypt/vault_renewer.rb @@ -0,0 +1,33 @@ +require 'legion/extensions/actors/every' + +module Legion + module Crypt + module Vault + class Renewer < Legion::Extensions::Actors::Every + def runner_function + 'renew_sessions' + end + + def runner_class + Legion::Crypt + end + + def time + 5 + end + + def check_subtask? + false + end + + def generate_task? + false + end + + def use_runner? + false + end + end + end + end +end diff --git a/lib/legion/crypt/version.rb b/lib/legion/crypt/version.rb new file mode 100644 index 0000000..b59e061 --- /dev/null +++ b/lib/legion/crypt/version.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +module Legion + module Crypt + VERSION = '0.3.0' + end +end diff --git a/sonar-project.properties b/sonar-project.properties new file mode 100644 index 0000000..3591d34 --- /dev/null +++ b/sonar-project.properties @@ -0,0 +1,11 @@ +sonar.projectKey=legion-io_legion-crypt +sonar.organization=legion-io +sonar.sources=. +sonar.exclusions=vendor/** +sonar.coverage.exclusions=spec/** +sonar.ruby.coverage.reportPath=coverage/.resultset.json +sonar.ruby.file.suffixes=rb,ruby +sonar.ruby.coverage.framework=RSpec +sonar.ruby.rubocopConfig=.rubocop.yml +sonar.ruby.rubocop.reportPath=rubocop-result.json +sonar.ruby.rubocop.filePath=. \ No newline at end of file diff --git a/spec/legion/cipher_spec.rb b/spec/legion/cipher_spec.rb new file mode 100644 index 0000000..04562c1 --- /dev/null +++ b/spec/legion/cipher_spec.rb @@ -0,0 +1,32 @@ +require 'spec_helper' +require 'legion/crypt' + +RSpec.describe Legion::Crypt::Cipher do + before { Legion::Settings[:crypt][:cluster_secret] = Legion::Crypt.generate_secure_random } + before { @crypt = Legion::Crypt } + before { @crypt.start } + + it 'can encrypt' do + expect(@crypt.encrypt('test')).to be_a Hash + expect(@crypt.encrypt('test')).to have_key :enciphered_message + expect(@crypt.encrypt('test')).to have_key :iv + end + + it 'can decrypt' do + message = @crypt.encrypt('foobar') + expect(@crypt.decrypt(message[:enciphered_message], message[:iv])).to eq 'foobar' + end + + it 'can encrypt from keypair' do + expect(@crypt.private_key).to be_a OpenSSL::PKey::RSA + expect(@crypt.public_key).to be_a String + expect(Base64.encode64(@crypt.private_key.public_key.to_s)).to be_a String + expect(@crypt.encrypt_from_keypair(message: 'test')).to be_a String + expect(@crypt.encrypt_from_keypair(message: 'test', pub_key: @crypt.public_key)).to be_a String + end + + it 'can decrypt from keypair' do + encrypt = @crypt.encrypt_from_keypair(message: 'test long message') + expect(@crypt.decrypt_from_keypair(message: encrypt)).to eq 'test long message' + end +end diff --git a/spec/legion/cluster_secret_spec.rb b/spec/legion/cluster_secret_spec.rb new file mode 100644 index 0000000..fcf57f7 --- /dev/null +++ b/spec/legion/cluster_secret_spec.rb @@ -0,0 +1,71 @@ +require 'spec_helper' + +require 'legion/crypt/cluster_secret' + +RSpec.describe Legion::Crypt::ClusterSecret do + before do + @cs = Class.new + @cs.extend Legion::Crypt::ClusterSecret + + @vault_mock = Module.new do + def self.get(_) + { cluster_secret: SecureRandom.hex(32) } + end + end + end + + it '.find_cluster_secret' do + expect(@cs.find_cluster_secret).not_to be_nil + end + + it 'can from_vault without Vault being loaded' do + expect(@cs.from_vault).to be_nil + end + + # it '.from_settings' do + # expect(@cs.from_settings).to be_nil + # end + + it '.force_cluster_secret' do + expect(@cs.force_cluster_secret).to eq true + end + + it '.settings_push_vault' do + expect(@cs.settings_push_vault).to eq true + end + + it '.only_member?' do + expect(@cs.only_member?).to eq true + end + + it '.push_cs_to_vault' do + expect(@cs.push_cs_to_vault).to eq false + end + + it '.cluster_secret_timeout' do + expect(@cs.cluster_secret_timeout).to eq 5 + end + + it '.secret_length' do + expect(@cs.secret_length).to eq 32 + end + + it '.generate_secure_random' do + expect(@cs.generate_secure_random).to be_a String + end + + it '.validate_hex' do + expect(@cs.validate_hex(@cs.find_cluster_secret)).to be_truthy + end + + it 'complains when it doesn\'t find a valid hex' do + Legion::Settings[:crypt][:cluster_secret] = 'not valid' + expect(@cs.validate_hex(Legion::Settings[:crypt][:cluster_secret])).to be_falsey + expect(@cs.find_cluster_secret).not_to eq 'not valid' + expect(@cs.validate_hex(@cs.cluster_secret)).to be_truthy + end + + it 'can do magic things with vault(fake)' do + expect(@cs.from_vault).to be_nil + end +end diff --git a/spec/legion/crypt_spec.rb b/spec/legion/crypt_spec.rb new file mode 100644 index 0000000..781e404 --- /dev/null +++ b/spec/legion/crypt_spec.rb @@ -0,0 +1,19 @@ +require 'spec_helper' + +require 'legion/crypt' +# require 'legion/transport' +# Legion::Transport::Connection.setup + +RSpec.describe Legion::Crypt do + it 'has a version number' do + expect(Legion::Crypt::VERSION).not_to be nil + end + + it 'can start' do + expect { Legion::Crypt.start }.not_to raise_exception + end + + it 'can stop' do + expect { Legion::Crypt.shutdown }.not_to raise_exception + end +end diff --git a/spec/legion/settings_spec.rb b/spec/legion/settings_spec.rb new file mode 100644 index 0000000..c0fec75 --- /dev/null +++ b/spec/legion/settings_spec.rb @@ -0,0 +1,13 @@ +require 'spec_helper' +require 'legion/crypt/settings' + +RSpec.describe Legion::Crypt::Settings do + it 'has default settings' do + expect(Legion::Crypt::Settings.default[:vault]).to be_a Hash + expect(Legion::Crypt::Settings.default[:cs_encrypt_ready]).to eq false + expect(Legion::Crypt::Settings.default[:dynamic_keys]).to eq true + expect(Legion::Crypt::Settings.default[:vault][:protocol]).to eq 'http' + expect(Legion::Crypt::Settings.default[:vault][:address]).to eq 'localhost' + expect(Legion::Crypt::Settings.vault).to be_a Hash + end +end diff --git a/spec/legion/vault_renewer_spec.rb b/spec/legion/vault_renewer_spec.rb new file mode 100644 index 0000000..8869eb3 --- /dev/null +++ b/spec/legion/vault_renewer_spec.rb @@ -0,0 +1,43 @@ +# # require 'spec_helper' +# # +# require 'legion/extensions/helpers/core' +# require 'legion/extensions/helpers/logger' +# require 'legion/extensions/helpers/lex' +# require 'legion/extensions/actors/every' +# require 'legion/crypt/vault_renewer' +# +# RSpec.describe Legion::Crypt::Vault::Renewer do +# it 'can init' do +# expect { Legion::Crypt::Vault::Renewer.new }.not_to raise_exception +# end +# +# before do +# @renewer = Legion::Crypt::Vault::Renewer.new +# end +# it 'is an actor' do +# expect(@renewer).to be_a Legion::Extensions::Actors::Every +# end +# +# it 'has settings set for the actor' do +# expect(@renewer.runner_function).to eq 'renew_sessions' +# expect(@renewer.class).to eq Legion::Crypt::Vault::Renewer +# expect(@renewer.time).to eq 5 +# expect(@renewer.use_runner?).to eq false +# end +# +# it 'can cancel' do +# expect { @renewer.cancel }.not_to raise_exception +# end +# +# it '.generate_task?' do +# expect(@renewer.generate_task?).to eq false +# end +# +# it '.check_subtask?' do +# expect(@renewer.check_subtask?).to eq false +# end +# +# it 'uses the correct class' do +# expect(@renewer.runner_class).to eq Legion::Crypt +# end +# end diff --git a/spec/legion/vault_spec.rb b/spec/legion/vault_spec.rb new file mode 100644 index 0000000..82e604b --- /dev/null +++ b/spec/legion/vault_spec.rb @@ -0,0 +1,62 @@ +require 'spec_helper' + +require 'legion/crypt/vault' + +RSpec.describe Legion::Crypt::Vault do + before do + @vault = Class.new + @vault.extend Legion::Crypt::Vault + @vault.sessions = [] + end + + it('.settings') { expect(@vault.settings).to be_a Hash } + + it '.connect_vault' do + expect { @vault.connect_vault }.not_to raise_exception + end + + before do + Legion::Crypt.connect_vault + end + + it '.write' do + # expect { @vault.write('test', 'key', 'value') }.not_to raise_exception + end + + it '.read' do + # expect(@vault.read('creds/legion', 'rabbitmq')).to be_a Hash + end + + it '.get' do + # expect(@vault.get('test')).to be_a Hash + # expect(@vault.get('test')).to eq({ key: 'value' }) + end + + it '.add_session' do + expect(@vault.add_session(path: '/test')).to be_a Array + end + + it 'exist?' do + # expect(@vault.exist?('test')).to eq true + end + + it '.close_sessions' do + expect(@vault.close_sessions).to be_a Array + end + + it '.shutdown_renewer' do + expect(@vault.shutdown_renewer).to eq nil + end + + it '.close_session' do + expect(Legion::Crypt.close_sessions).to be_a Array + end + + it '.renew_session' do + # empty block + end + + it '.renew_sessions' do + expect(Legion::Crypt.renew_sessions).to eq [] + end +end diff --git a/spec/legion/version_spec.rb b/spec/legion/version_spec.rb new file mode 100644 index 0000000..9a6db89 --- /dev/null +++ b/spec/legion/version_spec.rb @@ -0,0 +1,10 @@ +require 'spec_helper' + +require 'legion/crypt/version' + +RSpec.describe Legion::Crypt do + it 'has a version number' do + expect(Legion::Crypt::VERSION).not_to be nil + expect(Legion::Crypt::VERSION).to be_a String + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 0000000..62d66dd --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,29 @@ +begin + require 'simplecov' + SimpleCov.start do + use_merging true + add_filter '/spec/' + formatter SimpleCov::Formatter::Codecov if ENV.key?('CODECOV_TOKEN') + formatter SimpleCov::Formatter::SimpleFormatter if ENV.key? 'SONAR_TOKEN' + end +rescue LoadError + puts 'Failed to load file for coverage reports, continuing without it' +end + +require 'bundler/setup' +require 'legion/logging' +require 'legion/settings' + +Legion::Logging.setup(level: 'fatal') +Legion::Settings.load +Legion::Settings[:transport][:connection] = { vhost: '/' } + +require 'legion/crypt' + +RSpec.configure do |config| + config.example_status_persistence_file_path = '.rspec_status' + config.disable_monkey_patching! + config.expect_with :rspec do |c| + c.syntax = :expect + end +end