infisical-sdk 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 76ccc0dbd846bf88995c037fca57e95d0e4bb170920fb671c5647e0fe65a4db9
4
+ data.tar.gz: a4af651d6824cf8978cb20f15d7ad9bf04df88a1c050d99ef4d5fb3042f12062
5
+ SHA512:
6
+ metadata.gz: 6f9b107f069c6c566e9cc27da137a7565866eb18ccd7f4bd39711fe0dd0195a294361084c6131d5eb4738f1549f0f5b344e9d3762aadcad8f96875c9fb7829d3
7
+ data.tar.gz: 57ebffb40d22abd61c4d06ce65d4880eab45959bfdbfb1e8dfa171936a449ef77e9f436b7c8eb8715db28c77af1a09137510d9beb236725d5403c557ea7f8ed0
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rubocop/rake_task'
5
+ require 'rspec/core/rake_task'
6
+
7
+ RSpec::Core::RakeTask.new
8
+
9
+ RuboCop::RakeTask.new
10
+
11
+ task default: :rubocop
data/Steepfile ADDED
@@ -0,0 +1,46 @@
1
+ D = Steep::Diagnostic
2
+ #
3
+ # target :lib do
4
+ # signature "sig"
5
+ #
6
+ # check "lib" # Directory name
7
+ # check "Gemfile" # File name
8
+ # check "app/models/**/*.rb" # Glob
9
+ # # ignore "lib/templates/*.rb"
10
+ #
11
+ # # library "pathname" # Standard libraries
12
+ # # library "strong_json" # Gems
13
+ #
14
+ # # configure_code_diagnostics(D::Ruby.default) # `default` diagnostics setting (applies by default)
15
+ # # configure_code_diagnostics(D::Ruby.strict) # `strict` diagnostics setting
16
+ # # configure_code_diagnostics(D::Ruby.lenient) # `lenient` diagnostics setting
17
+ # # configure_code_diagnostics(D::Ruby.silent) # `silent` diagnostics setting
18
+ # # configure_code_diagnostics do |hash| # You can setup everything yourself
19
+ # # hash[D::Ruby::NoMethod] = :information
20
+ # # end
21
+ # end
22
+
23
+ # target :test do
24
+ # signature "sig", "sig-private"
25
+ #
26
+ # check "test"
27
+ #
28
+ # # library "pathname" # Standard libraries
29
+ # end
30
+
31
+ target :app do
32
+ check 'lib'
33
+ signature 'sig'
34
+
35
+ library 'set', 'pathname'
36
+ ignore(
37
+ 'lib/schemas.rb',
38
+ 'lib/infisical_lib.rb',
39
+ 'lib/extended_schemas/schemas.rb'
40
+ )
41
+
42
+ configure_code_diagnostics do |hash| # You can setup everything yourself
43
+
44
+ hash[D::Ruby::UnknownConstant] = :information
45
+ end
46
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'infisical-sdk'
7
+ spec.version = InfisicalSDK::VERSION
8
+ spec.authors = ['Infisical Inc.']
9
+ spec.email = ['team@infisical.com']
10
+
11
+ spec.summary = 'Ruby SDK for interacting with the Infisical platform.'
12
+ spec.description = 'The official Infisical Ruby SDK.'
13
+ spec.homepage = 'https://infisical.com'
14
+ spec.required_ruby_version = '>= 2.7'
15
+
16
+ spec.metadata['homepage_uri'] = spec.homepage
17
+ spec.metadata['source_code_uri'] = 'https://github.com/infisical/sdk'
18
+ spec.metadata['changelog_uri'] = 'https://infisical.com/docs/changelog/overview'
19
+
20
+ # Specify which files should be added to the gem when it is released.
21
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
22
+ spec.files = Dir.chdir(__dir__) do
23
+ `git ls-files -z`.split("\x0").reject do |f|
24
+ (File.expand_path(f) == __FILE__) || f.start_with?(*%w[bin/ test/ spec/ features/ .git Gemfile])
25
+ end
26
+ end
27
+
28
+ spec.files += Dir.glob('lib/linux-x64/**/*')
29
+ spec.files += Dir.glob('lib/linux-arm64/**/*')
30
+ spec.files += Dir.glob('lib/macos-x64/**/*')
31
+ spec.files += Dir.glob('lib/windows-x64/**/*')
32
+ spec.files += Dir.glob('lib/macos-arm64/**/*')
33
+ spec.files += Dir.glob('lib/schemas.rb')
34
+
35
+ spec.bindir = 'exe'
36
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
37
+ spec.require_paths = ['lib']
38
+
39
+ # Uncomment to register a new dependency of your gem
40
+ # spec.add_dependency "example-gem", "~> 1.0"
41
+ spec.add_dependency 'dry-struct', '~> 1.6'
42
+ spec.add_dependency 'dry-types', '~> 1.7'
43
+ spec.add_dependency 'ffi', '~> 1.15'
44
+ spec.add_dependency 'json', '~> 2.6'
45
+ spec.add_dependency 'rake', '~> 13.0'
46
+ spec.add_dependency 'rubocop', '~> 1.21'
47
+
48
+ end
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require_relative '../extended_schemas/schemas'
5
+
6
+ module InfisicalSDK
7
+ # Manage Infisical secrets.
8
+ class AuthClient
9
+ def initialize(command_runner)
10
+ @command_runner = command_runner
11
+ end
12
+
13
+ def universal_auth(client_id:, client_secret:)
14
+ response = run_command(universal_auth_login: UniversalAuthMethod.new(
15
+ client_id: client_id,
16
+ client_secret: client_secret
17
+ ))
18
+
19
+ handle_auth_response(response)
20
+ end
21
+
22
+ def kubernetes_auth(identity_id:, service_account_token_path:)
23
+
24
+ response = run_command(kubernetes_auth_login: KubernetesAuthMethod.new(
25
+ identity_id: identity_id,
26
+ service_account_token_path: service_account_token_path
27
+ ))
28
+
29
+ handle_auth_response(response)
30
+ end
31
+
32
+ def azure_auth(identity_id:)
33
+
34
+ response = run_command(azure_auth_login: AzureAuthMethod.new(
35
+ identity_id: identity_id
36
+ ))
37
+
38
+ handle_auth_response(response)
39
+ end
40
+
41
+ def gcp_id_token_auth(identity_id:)
42
+
43
+ response = run_command(gcp_id_token_auth_login: GCPIDTokenAuthMethod.new(
44
+ identity_id: identity_id
45
+ ))
46
+
47
+ handle_auth_response(response)
48
+ end
49
+
50
+ def gcp_iam_auth(identity_id:, service_account_key_file_path:)
51
+
52
+ response = run_command(gcp_iam_auth_login: GCPIamAuthMethod.new(
53
+ identity_id: identity_id,
54
+ service_account_key_file_path: service_account_key_file_path
55
+ ))
56
+
57
+ handle_auth_response(response)
58
+ end
59
+
60
+ def aws_iam_auth(identity_id:)
61
+
62
+ response = run_command(aws_iam_auth_login: AWSIamAuthMethod.new(
63
+ identity_id: identity_id
64
+ ))
65
+
66
+ handle_auth_response(response)
67
+ end
68
+
69
+ private
70
+
71
+ def error_handler(response)
72
+
73
+ # If the response is successful, we return without raising errors.
74
+ if response.key?('success') && response['success'] == true && response.key?('data')
75
+ return
76
+ end
77
+
78
+ if response['errorMessage']
79
+ raise InfisicalError, response['errorMessage'] if response.key?('errorMessage')
80
+ else
81
+ raise InfisicalError, 'Error while getting response'
82
+ end
83
+ end
84
+
85
+ def handle_auth_response(response)
86
+ auth_response = ResponseForAccessTokenSuccessResponse.from_json!(response).to_dynamic
87
+ error_handler(auth_response)
88
+
89
+ auth_response['data']
90
+ end
91
+
92
+ def run_command(command)
93
+ response = @command_runner.run(InfisicalCommands.new(command))
94
+ raise InfisicalError, 'Error getting response' if response.nil?
95
+
96
+ response
97
+ end
98
+ end
99
+ end
100
+
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rubocop:disable Metrics/MethodLength
4
+ # rubocop:disable Naming/MethodParameterName
5
+
6
+
7
+
8
+ require 'json'
9
+ require_relative '../extended_schemas/schemas'
10
+
11
+
12
+ module InfisicalSDK
13
+ # Perform encryption
14
+ class EncryptionClient
15
+ def initialize(command_runner)
16
+ @command_runner = command_runner
17
+ end
18
+
19
+ def encrypt_symmetric(data:, key:)
20
+ response = run_command(encrypt_symmetric: EncryptSymmetricOptions.new(
21
+ key: key,
22
+ plaintext: data,
23
+ ))
24
+
25
+ encrypt_response = ResponseForEncryptSymmetricResponse.from_json!(response).to_dynamic
26
+ error_handler(encrypt_response)
27
+
28
+
29
+ encrypt_response['data']
30
+ end
31
+
32
+ def decrypt_symmetric(
33
+ ciphertext:,
34
+ iv:,
35
+ tag:,
36
+ key:
37
+ )
38
+
39
+ response = run_command(decrypt_symmetric: DecryptSymmetricOptions.new(
40
+ ciphertext: ciphertext,
41
+ iv: iv,
42
+ tag: tag,
43
+ key: key
44
+ ))
45
+
46
+ decrypt_response = ResponseForDecryptSymmetricResponse.from_json!(response).to_dynamic
47
+ error_handler(decrypt_response)
48
+
49
+ decrypt_response['data']['decrypted']
50
+ end
51
+
52
+ def create_symmetric_key
53
+ response = run_command(create_symmetric_key: ArbitraryOptions.new(
54
+ data: ''
55
+ ))
56
+
57
+ key_response = ResponseForCreateSymmetricKeyResponse.from_json!(response).to_dynamic
58
+ error_handler(key_response)
59
+
60
+ key_response['data']['key']
61
+ end
62
+
63
+ private
64
+
65
+ def error_handler(response)
66
+
67
+ # If the response is successful, we return without raising errors.
68
+ if response.key?('success') && response['success'] == true && response.key?('data')
69
+ return
70
+ end
71
+
72
+ if response['errorMessage']
73
+ raise InfisicalError, response['errorMessage'] if response.key?('errorMessage')
74
+ else
75
+ raise InfisicalError, 'Error while getting response'
76
+ end
77
+ end
78
+
79
+ def run_command(command)
80
+ response = @command_runner.run(InfisicalCommands.new(command))
81
+ raise InfisicalError, 'Error getting response' if response.nil?
82
+
83
+ response
84
+ end
85
+ end
86
+ end
87
+
88
+ # rubocop:enable Metrics/MethodLength
89
+ # rubocop:enable Naming/MethodParameterName
90
+
@@ -0,0 +1,169 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
5
+ require_relative '../extended_schemas/schemas'
6
+
7
+ module InfisicalSDK
8
+ # Manage Infisical secrets.
9
+ class SecretsClient
10
+ def initialize(command_runner)
11
+ @command_runner = command_runner
12
+ end
13
+
14
+ # rubocop:disable Metrics/ParameterLists
15
+ # rubocop:disable Metrics/MethodLength
16
+ def get(
17
+ secret_name:,
18
+ project_id:,
19
+ environment:,
20
+ path: nil,
21
+ include_imports: nil,
22
+ type: nil
23
+ )
24
+
25
+ response = run_command(get_secret: GetSecretOptions.new(
26
+ secret_name: secret_name,
27
+ project_id: project_id,
28
+ environment: environment,
29
+ path: path,
30
+ include_imports: include_imports,
31
+ get_secret_options_type: type
32
+ ))
33
+
34
+ secrets_response = ResponseForGetSecretResponse.from_json!(response).to_dynamic
35
+ error_handler(secrets_response)
36
+
37
+
38
+ secrets_response['data']['secret']
39
+ end
40
+
41
+ def list(
42
+ project_id:,
43
+ environment:,
44
+ path: nil ,
45
+ attach_to_process_env: nil,
46
+ expand_secret_references: nil,
47
+ recursive: nil,
48
+ include_imports: nil
49
+ )
50
+ response = run_command(list_secrets: ListSecretsOptions.new(
51
+ project_id: project_id,
52
+ environment: environment,
53
+ path: path,
54
+ include_imports: include_imports,
55
+ recursive: recursive,
56
+ attach_to_process_env: attach_to_process_env,
57
+ expand_secret_references: expand_secret_references,
58
+ ))
59
+
60
+ secrets_response = ResponseForListSecretsResponse.from_json!(response).to_dynamic
61
+ error_handler(secrets_response)
62
+
63
+ secrets_response['data']['secrets']
64
+ end
65
+
66
+ def update(
67
+ secret_name:,
68
+ secret_value:,
69
+ project_id:,
70
+ environment:,
71
+ path: nil,
72
+ skip_multiline_encoding: nil,
73
+ type: nil
74
+ )
75
+ response = run_command(update_secret: UpdateSecretOptions.new(
76
+ secret_name: secret_name,
77
+ secret_value: secret_value,
78
+ project_id: project_id,
79
+ environment: environment,
80
+ path: path,
81
+ skip_multiline_encoding: skip_multiline_encoding,
82
+ update_secret_options_type: type
83
+ ))
84
+
85
+ secrets_response = ResponseForUpdateSecretResponse.from_json!(response).to_dynamic
86
+ error_handler(secrets_response)
87
+
88
+
89
+ secrets_response['data']['secret']
90
+ end
91
+
92
+ def create(
93
+ secret_name:,
94
+ secret_value:,
95
+ project_id:,
96
+ environment:,
97
+ secret_comment: nil,
98
+ path: nil,
99
+ skip_multiline_encoding: nil,
100
+ type: nil
101
+
102
+ )
103
+
104
+ response = run_command(create_secret: CreateSecretOptions.new(
105
+ secret_name: secret_name,
106
+ secret_value: secret_value,
107
+ secret_comment: secret_comment,
108
+ project_id: project_id,
109
+ environment: environment,
110
+ skip_multiline_encoding: skip_multiline_encoding,
111
+ path: path,
112
+ create_secret_options_type: type
113
+ ))
114
+
115
+ secrets_response = ResponseForCreateSecretResponse.from_json!(response).to_dynamic
116
+ error_handler(secrets_response)
117
+
118
+
119
+ secrets_response['data']['secret']
120
+ end
121
+
122
+ def delete(
123
+ secret_name:,
124
+ project_id:,
125
+ environment:,
126
+ path: nil,
127
+ type: nil
128
+ )
129
+ response = run_command(delete_secret: DeleteSecretOptions.new(
130
+ secret_name: secret_name,
131
+ project_id: project_id,
132
+ environment: environment,
133
+ path: path,
134
+ delete_secret_options_type: type
135
+ ))
136
+
137
+ secrets_response = ResponseForDeleteSecretResponse.from_json!(response).to_dynamic
138
+ error_handler(secrets_response)
139
+
140
+ secrets_response['data']['secret']
141
+ end
142
+
143
+ private
144
+
145
+ def error_handler(response)
146
+
147
+ # If the response is successful, we return without raising errors.
148
+ if response.key?('success') && response['success'] == true && response.key?('data')
149
+ return
150
+ end
151
+
152
+ if response['errorMessage']
153
+ raise InfisicalError, response['errorMessage'] if response.key?('errorMessage')
154
+ else
155
+ raise InfisicalError, 'Error while getting response'
156
+ end
157
+ end
158
+
159
+ def run_command(command)
160
+ response = @command_runner.run(InfisicalCommands.new(command))
161
+ raise InfisicalError, 'Error getting response' if response.nil?
162
+
163
+ response
164
+ end
165
+ end
166
+ end
167
+
168
+ # rubocop:enable Metrics/ParameterLists
169
+ # rubocop:enable Metrics/MethodLength
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module InfisicalSDK
4
+ # Run base SDK commands
5
+ class CommandRunner
6
+ def initialize(infisical_sdk, handle)
7
+ @infisical_sdk = infisical_sdk
8
+ @handle = handle
9
+ end
10
+
11
+ # @param [Dry-Struct] cmd
12
+ def run(cmd)
13
+ @infisical_sdk.run_command(cmd.to_json, @handle)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require 'dry-types'
5
+
6
+ require_relative 'schemas'
7
+ require_relative 'extended_schemas/schemas'
8
+ require_relative 'infisical_lib'
9
+ require_relative 'infisical_error'
10
+ require_relative 'command_runner'
11
+ require_relative 'clients/secrets'
12
+ require_relative 'clients/auth'
13
+ require_relative 'clients/encryption'
14
+
15
+ module InfisicalSDK
16
+ class InfisicalClient
17
+ attr_reader :infisical, :command_runner, :secrets, :auth, :encryption
18
+
19
+ def initialize(site_url = nil, cache_ttl = 300)
20
+ settings = ClientSettings.new(
21
+ # We preset these values or we'll get type validation errors (thanks Quicktype!)
22
+ access_token: nil,
23
+ client_secret: nil,
24
+ client_id: nil,
25
+ auth: nil,
26
+ user_agent: 'infisical-ruby-sdk',
27
+ cache_ttl: cache_ttl,
28
+ site_url: site_url
29
+ )
30
+
31
+
32
+ @infisical = InfisicalLib
33
+ @handle = @infisical.init(settings.to_dynamic.compact.to_json)
34
+ @command_runner = CommandRunner.new(@infisical, @handle)
35
+ @secrets = SecretsClient.new(@command_runner)
36
+ @auth = AuthClient.new(@command_runner)
37
+ @encryption = EncryptionClient.new(@command_runner)
38
+ end
39
+
40
+ def free_mem
41
+ @infisical.free_mem(@handle)
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module InfisicalSDK
4
+ # Infisical Error
5
+ class InfisicalError < StandardError
6
+ def initialize(message = 'Failed to get get response')
7
+ super(message)
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ffi'
4
+
5
+ module InfisicalSDK
6
+ # C wrapper for Ruby SDK
7
+ module InfisicalLib
8
+ extend FFI::Library
9
+
10
+ def self.mac_with_intel?
11
+ `uname -m`.strip == 'x86_64'
12
+ end
13
+
14
+ def self.linux_arm64?
15
+ RUBY_PLATFORM.include?('linux') && %w[aarch64 arm64].any? { |arch| RUBY_PLATFORM.include?(arch) }
16
+ end
17
+
18
+ ffi_lib case RUBY_PLATFORM
19
+ when /darwin/
20
+ local_file = if mac_with_intel?
21
+ File.expand_path('macos-x64/libinfisical_c.dylib', __dir__)
22
+ else
23
+ File.expand_path('macos-arm64/libinfisical_c.dylib', __dir__)
24
+ end
25
+ File.exist?(local_file) ? local_file : File.expand_path('../../../../target/debug/libinfisical_c.dylib', __dir__)
26
+ when /linux/
27
+ local_file = if linux_arm64?
28
+ File.expand_path('linux-arm64/libinfisical_c.so', __dir__)
29
+ else
30
+ File.expand_path('linux-x64/libinfisical_c.so', __dir__)
31
+ end
32
+ File.exist?(local_file) ? local_file : File.expand_path('../../../../target/debug/libinfisical_c.so', __dir__)
33
+ when /mswin|mingw/
34
+ local_file = File.expand_path('windows-x64/infisical_c.dll', __dir__)
35
+ File.exist?(local_file) ? local_file : File.expand_path('../../../../target/debug/infisical_c.dll', __dir__)
36
+ else
37
+ raise "Unsupported platform: #{RUBY_PLATFORM}"
38
+ end
39
+
40
+ attach_function :init, [:string], :pointer
41
+ attach_function :run_command, %i[string pointer], :string
42
+ attach_function :free_mem, [:pointer], :void
43
+ end
44
+ end
Binary file
Binary file
Binary file