etna 0.1.14 → 0.1.20

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.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/bin/etna +18 -0
  3. data/etna.completion +1001 -0
  4. data/etna_app.completion +133 -0
  5. data/ext/completions/extconf.rb +20 -0
  6. data/lib/commands.rb +395 -0
  7. data/lib/etna.rb +7 -0
  8. data/lib/etna/application.rb +46 -22
  9. data/lib/etna/client.rb +82 -48
  10. data/lib/etna/clients.rb +4 -0
  11. data/lib/etna/clients/enum.rb +9 -0
  12. data/lib/etna/clients/janus.rb +2 -0
  13. data/lib/etna/clients/janus/client.rb +73 -0
  14. data/lib/etna/clients/janus/models.rb +78 -0
  15. data/lib/etna/clients/magma.rb +4 -0
  16. data/lib/etna/clients/magma/client.rb +80 -0
  17. data/lib/etna/clients/magma/formatting.rb +1 -0
  18. data/lib/etna/clients/magma/formatting/models_csv.rb +354 -0
  19. data/lib/etna/clients/magma/models.rb +630 -0
  20. data/lib/etna/clients/magma/workflows.rb +10 -0
  21. data/lib/etna/clients/magma/workflows/add_project_models_workflow.rb +67 -0
  22. data/lib/etna/clients/magma/workflows/attribute_actions_from_json_workflow.rb +62 -0
  23. data/lib/etna/clients/magma/workflows/create_project_workflow.rb +123 -0
  24. data/lib/etna/clients/magma/workflows/crud_workflow.rb +85 -0
  25. data/lib/etna/clients/magma/workflows/ensure_containing_record_workflow.rb +44 -0
  26. data/lib/etna/clients/magma/workflows/file_attributes_blank_workflow.rb +68 -0
  27. data/lib/etna/clients/magma/workflows/file_linking_workflow.rb +115 -0
  28. data/lib/etna/clients/magma/workflows/json_converters.rb +81 -0
  29. data/lib/etna/clients/magma/workflows/json_validators.rb +452 -0
  30. data/lib/etna/clients/magma/workflows/model_synchronization_workflow.rb +306 -0
  31. data/lib/etna/clients/magma/workflows/record_synchronization_workflow.rb +63 -0
  32. data/lib/etna/clients/magma/workflows/update_attributes_from_csv_workflow.rb +246 -0
  33. data/lib/etna/clients/metis.rb +3 -0
  34. data/lib/etna/clients/metis/client.rb +239 -0
  35. data/lib/etna/clients/metis/models.rb +313 -0
  36. data/lib/etna/clients/metis/workflows.rb +2 -0
  37. data/lib/etna/clients/metis/workflows/metis_download_workflow.rb +37 -0
  38. data/lib/etna/clients/metis/workflows/metis_upload_workflow.rb +137 -0
  39. data/lib/etna/clients/polyphemus.rb +3 -0
  40. data/lib/etna/clients/polyphemus/client.rb +33 -0
  41. data/lib/etna/clients/polyphemus/models.rb +68 -0
  42. data/lib/etna/clients/polyphemus/workflows.rb +1 -0
  43. data/lib/etna/clients/polyphemus/workflows/set_configuration_workflow.rb +47 -0
  44. data/lib/etna/command.rb +243 -5
  45. data/lib/etna/controller.rb +4 -0
  46. data/lib/etna/csvs.rb +159 -0
  47. data/lib/etna/directed_graph.rb +56 -0
  48. data/lib/etna/environment_scoped.rb +19 -0
  49. data/lib/etna/errors.rb +6 -0
  50. data/lib/etna/generate_autocompletion_script.rb +131 -0
  51. data/lib/etna/json_serializable_struct.rb +37 -0
  52. data/lib/etna/logger.rb +24 -2
  53. data/lib/etna/multipart_serializable_nested_hash.rb +50 -0
  54. data/lib/etna/route.rb +1 -1
  55. data/lib/etna/server.rb +3 -0
  56. data/lib/etna/spec/vcr.rb +99 -0
  57. data/lib/etna/templates/attribute_actions_template.json +43 -0
  58. data/lib/etna/test_auth.rb +3 -1
  59. data/lib/etna/user.rb +11 -1
  60. data/lib/helpers.rb +90 -0
  61. metadata +70 -5
@@ -0,0 +1,50 @@
1
+ module Etna
2
+ module MultipartSerializableNestedHash
3
+ def self.included(cls)
4
+ cls.instance_eval do
5
+ def self.encode_multipart_pairs(value, base_key, is_root, &block)
6
+ if value.is_a? Hash
7
+ value.each do |k, v|
8
+ encode_multipart_pairs(v, is_root ? k : "#{base_key}[#{k}]", false, &block)
9
+ end
10
+ elsif value.is_a? Array
11
+ value.each_with_index do |v, i|
12
+ # This is necessary to ensure that arrays of hashes that have hetergenous keys still get parsed correctly
13
+ # Since the only way to indicate a new entry in the array of hashes is by re-using a key that existed in
14
+ # the previous hash.
15
+ if v.is_a? Hash
16
+ encode_multipart_pairs(i, "#{base_key}[][_idx]", false, &block)
17
+ end
18
+
19
+ encode_multipart_pairs(v, "#{base_key}[]", false, &block)
20
+ end
21
+ else
22
+ raise "base_key cannot be empty for a scalar value!" if base_key.length == 0
23
+
24
+ if value.respond_to?(:read)
25
+ yield [base_key, UploadIO.new(value, 'application/octet-stream'), {filename: 'blob'}]
26
+ else
27
+ yield [base_key, value.to_s]
28
+ end
29
+ end
30
+ end
31
+
32
+
33
+ def self.encode_multipart_content(value, base_key = '', is_root = true)
34
+ result = []
35
+ self.encode_multipart_pairs(value, base_key, is_root) { |pair| result << pair }
36
+ result
37
+ end
38
+ end
39
+ end
40
+
41
+ def encode_multipart_content(base_key = '')
42
+ value = self
43
+ if value.respond_to? :as_json
44
+ value = value.as_json
45
+ end
46
+
47
+ self.class.encode_multipart_content(value, base_key)
48
+ end
49
+ end
50
+ end
@@ -118,7 +118,7 @@ module Etna
118
118
 
119
119
  def hmac_authorized?(request)
120
120
  # either there is no hmac requirement, or we have a valid hmac
121
- !@auth[:hmac] || request.env['etna.hmac'].valid?
121
+ !@auth[:hmac] || request.env['etna.hmac']&.valid?
122
122
  end
123
123
 
124
124
  def route_name(options)
@@ -66,6 +66,9 @@ module Etna
66
66
  end
67
67
 
68
68
  [404, {}, ["There is no such path '#{request.path}'"]]
69
+ rescue => e
70
+ application.logger.log_error(e)
71
+ raise
69
72
  end
70
73
 
71
74
  def initialize
@@ -0,0 +1,99 @@
1
+ require 'webmock/rspec'
2
+ require 'vcr'
3
+ require 'openssl'
4
+ require 'digest/sha2'
5
+ require 'base64'
6
+
7
+ def setup_base_vcr(spec_helper_dir)
8
+ VCR.configure do |c|
9
+ c.hook_into :webmock
10
+ c.cassette_serializers
11
+ c.cassette_library_dir = ::File.join(spec_helper_dir, 'fixtures', 'cassettes')
12
+ c.allow_http_connections_when_no_cassette = true
13
+
14
+ c.register_request_matcher :try_body do |request_1, request_2|
15
+ if request_1.headers['Content-Type'].first =~ /application\/json/
16
+ if request_2.headers['Content-Type'].first =~ /application\/json/
17
+ request_1_json = begin
18
+ JSON.parse(request_1.body) rescue 'not-json'
19
+ end
20
+ request_2_json = begin
21
+ JSON.parse(request_2.body) rescue 'not-json'
22
+ end
23
+
24
+ request_1_json == request_2_json
25
+ else
26
+ false
27
+ end
28
+ else
29
+ request_1.body == request_2.body
30
+ end
31
+ end
32
+
33
+ c.default_cassette_options = {
34
+ serialize_with: :compressed,
35
+ record: if ENV['IS_CI'] == '1'
36
+ :none
37
+ else
38
+ ENV['RERECORD'] ? :all : :once
39
+ end,
40
+ match_requests_on: [:method, :uri, :try_body]
41
+ }
42
+
43
+ # Filter the authorization headers of any request by replacing any occurrence of that request's
44
+ # Authorization value with <AUTHORIZATION>
45
+ c.filter_sensitive_data('<AUTHORIZATION>') do |interaction|
46
+ interaction.request.headers['Authorization'].first
47
+ end
48
+
49
+ c.before_record do |interaction|
50
+ key = prepare_vcr_secret
51
+
52
+ if interaction.response.body && !interaction.response.body.empty?
53
+ cipher = OpenSSL::Cipher.new("AES-256-CBC")
54
+ iv = cipher.random_iv
55
+
56
+ cipher.encrypt
57
+ cipher.key = key
58
+ cipher.iv = iv
59
+
60
+ encrypted = cipher.update(interaction.response.body)
61
+ encrypted << cipher.final
62
+
63
+ interaction.response.body = [iv, encrypted].pack('mm')
64
+ end
65
+ end
66
+
67
+ c.before_playback do |interaction|
68
+ key = prepare_vcr_secret
69
+
70
+ if interaction.response.body && !interaction.response.body.empty?
71
+ iv, encrypted = interaction.response.body.unpack('mm')
72
+
73
+ cipher = OpenSSL::Cipher.new("AES-256-CBC")
74
+ cipher.decrypt
75
+ cipher.key = key
76
+ cipher.iv = iv
77
+
78
+ plain = cipher.update(encrypted)
79
+ plain << cipher.final
80
+
81
+ interaction.response.body = plain
82
+ end
83
+ end
84
+ end
85
+ end
86
+
87
+ def prepare_vcr_secret
88
+ secret = ENV["CI_SECRET"]
89
+
90
+ if (secret.nil? || secret.empty?) && ENV['IS_CI'] != '1'
91
+ current_example = RSpec.current_example
92
+ RSpec::Core::Pending.mark_pending! current_example, 'CI_SECRET must be set to run this test'
93
+ raise "CI_SECRET must be set to run this test"
94
+ end
95
+
96
+ digest = Digest::SHA256.new
97
+ digest.update(secret)
98
+ digest.digest
99
+ end
@@ -0,0 +1,43 @@
1
+ // Make sure to remove all comments before using -- JSON doesn't allow comments!
2
+ [
3
+ // Attribute actions can be "add_attribute", "update_attribute", "rename_attribute", or "add_link".
4
+ // These are all executed at the same time -- so you can't "update" an attribute that you "add"
5
+ // in the same file -- everything must already exist on the server."
6
+ {
7
+ "action_name": "add_attribute",
8
+ "model_name": "assay_name", // Each action must include a model_name that it applies to.
9
+ "attribute_type": "string", // When adding, you must include attribute_type, attribute_name, desc, and display_name.
10
+ "attribute_name": "notes",
11
+ "display_name": "Notes",
12
+ "desc": "for notes that you have."
13
+ },
14
+ {
15
+ "action_name": "update_attribute",
16
+ "model_name": "document",
17
+ "attribute_name": "version", // When updating, you must include model_name and attribute_name, but any additional values are optional.
18
+ "read_only": true
19
+ },
20
+ {
21
+ "action_name": "rename_attribute",
22
+ "model_name": "assay_name",
23
+ "attribute_name": "vendor",
24
+ "new_attribute_name": "e_vendor" // When renaming an attribute, you need to include a "new_attribute_name" value.
25
+ },
26
+ {
27
+ // Links require two hashes inside of a "links" attribute.
28
+ "action_name": "add_link",
29
+ "links": [
30
+ {
31
+ "model_name": "assay_name",
32
+ "attribute_name": "document",
33
+ "attribute_type": "link" // One link must be of type "link". This has a one-to-one relationship with the other model.
34
+ // In this case, each assay_name has one document record, but document records can point to zero-or-more assay_name records.
35
+ },
36
+ {
37
+ "model_name": "document",
38
+ "attribute_name": "assay_name",
39
+ "attribute_type": "collection" // The other link must be of type "collection". This is a one-to-many relationship with the other model.
40
+ }
41
+ ]
42
+ }
43
+ ]
@@ -43,7 +43,9 @@ module Etna
43
43
  end
44
44
 
45
45
  def approve_hmac(request)
46
- hmac_signature = etna_param(request, :signature) || 'invalid'
46
+ hmac_signature = etna_param(request, :signature)
47
+
48
+ return false unless hmac_signature
47
49
 
48
50
  headers = (etna_param(request, :headers)&.split(/,/) || []).map do |header|
49
51
  [ header.to_sym, etna_param(request, header) ]
@@ -7,7 +7,9 @@ module Etna
7
7
  }
8
8
 
9
9
  def initialize params, token=nil
10
- @first, @last, @email, @encoded_permissions = params.values_at(:first, :last, :email, :perm)
10
+ @first, @last, @email, @encoded_permissions, encoded_flags = params.values_at(:first, :last, :email, :perm, :flags)
11
+
12
+ @flags = encoded_flags&.split(/;/) || []
11
13
  @token = token unless !token
12
14
  raise ArgumentError, "No email given!" unless @email
13
15
  end
@@ -30,6 +32,10 @@ module Etna
30
32
  end.inject([],:+).to_h
31
33
  end
32
34
 
35
+ def has_flag?(flag)
36
+ @flags.include?(flag)
37
+ end
38
+
33
39
  def name
34
40
  "#{first} #{last}"
35
41
  end
@@ -75,5 +81,9 @@ module Etna
75
81
  def is_admin? project
76
82
  is_superuser? || has_roles(project, :admin)
77
83
  end
84
+
85
+ def active? project=nil
86
+ permissions.keys.length > 0
87
+ end
78
88
  end
79
89
  end
@@ -0,0 +1,90 @@
1
+ require_relative './etna/clients'
2
+ require_relative './etna/environment_scoped'
3
+
4
+ module WithEtnaClients
5
+ def environment
6
+ EtnaApp.instance.environment
7
+ end
8
+
9
+ def token(ignore_environment: false)
10
+ unless ignore_environment
11
+ if environment == :many
12
+ raise "You have multiple environments configured, please specify your environment by adding --environment <staging|production|development>"
13
+ elsif environment == :none
14
+ raise "You do not have a successfully configured environment, please run #{program_name} config set https://polyphemus.ucsf.edu"
15
+ end
16
+ end
17
+
18
+ env_token = ENV['TOKEN']
19
+ if !env_token
20
+ puts "No environment variable TOKEN is set. You should set your token with `export TOKEN=<your.janus.token>` before running."
21
+ redirect = EtnaApp.instance.config(:auth_redirect)
22
+
23
+ if redirect.nil? && EtnaApp.instance.environment == :production
24
+ redirect = 'https://janus.ucsf.edu/'
25
+ end
26
+
27
+ unless redirect.nil?
28
+ puts "Open your browser to #{redirect} to complete login and copy your token."
29
+ end
30
+
31
+ exit
32
+ end
33
+
34
+ env_token
35
+ end
36
+
37
+ def magma_client
38
+ @magma_client ||= Etna::Clients::Magma.new(
39
+ token: token,
40
+ ignore_ssl: EtnaApp.instance.config(:ignore_ssl),
41
+ # Persistent connections cause problem with magma restarts, until we can fix that we should force them
42
+ # to close + reopen each request.
43
+ persistent: false,
44
+ **EtnaApp.instance.config(:magma, environment) || {})
45
+ end
46
+
47
+ def metis_client
48
+ @metis_client ||= Etna::Clients::Metis.new(
49
+ token: token,
50
+ ignore_ssl: EtnaApp.instance.config(:ignore_ssl),
51
+ **EtnaApp.instance.config(:metis, environment) || {})
52
+ end
53
+
54
+ def janus_client
55
+ @janus_client ||= Etna::Clients::Janus.new(
56
+ token: token,
57
+ ignore_ssl: EtnaApp.instance.config(:ignore_ssl),
58
+ **EtnaApp.instance.config(:janus, environment) || {})
59
+ end
60
+
61
+ def polyphemus_client
62
+ @polyphemus_client ||= Etna::Clients::Polyphemus.new(
63
+ token: token,
64
+ ignore_ssl: EtnaApp.instance.config(:ignore_ssl),
65
+ **EtnaApp.instance.config(:polyphemus, environment) || {})
66
+ end
67
+ end
68
+
69
+ module WithLogger
70
+ def logger
71
+ EtnaApp.instance.logger
72
+ end
73
+ end
74
+
75
+ module StrongConfirmation
76
+ def confirm
77
+ puts "Confirm Y/n:"
78
+ input = STDIN.gets.chomp
79
+ if input.downcase != "y"
80
+ puts "Bailing..."
81
+ return false
82
+ end
83
+
84
+ true
85
+ end
86
+ end
87
+
88
+ WithEtnaClientsByEnvironment = EnvironmentScoped.new do
89
+ include WithEtnaClients
90
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: etna
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.14
4
+ version: 0.1.20
5
5
  platform: ruby
6
6
  authors:
7
7
  - Saurabh Asthana
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-08-03 00:00:00.000000000 Z
11
+ date: 2020-12-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -66,37 +66,102 @@ dependencies:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rollbar
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
69
83
  description: See summary
70
84
  email: Saurabh.Asthana@ucsf.edu
71
- executables: []
72
- extensions: []
85
+ executables:
86
+ - etna
87
+ extensions:
88
+ - ext/completions/extconf.rb
73
89
  extra_rdoc_files: []
74
90
  files:
91
+ - bin/etna
92
+ - etna.completion
93
+ - etna_app.completion
94
+ - ext/completions/extconf.rb
95
+ - lib/commands.rb
75
96
  - lib/etna.rb
76
97
  - lib/etna/application.rb
77
98
  - lib/etna/auth.rb
78
99
  - lib/etna/client.rb
100
+ - lib/etna/clients.rb
101
+ - lib/etna/clients/enum.rb
102
+ - lib/etna/clients/janus.rb
103
+ - lib/etna/clients/janus/client.rb
104
+ - lib/etna/clients/janus/models.rb
105
+ - lib/etna/clients/magma.rb
106
+ - lib/etna/clients/magma/client.rb
107
+ - lib/etna/clients/magma/formatting.rb
108
+ - lib/etna/clients/magma/formatting/models_csv.rb
109
+ - lib/etna/clients/magma/models.rb
110
+ - lib/etna/clients/magma/workflows.rb
111
+ - lib/etna/clients/magma/workflows/add_project_models_workflow.rb
112
+ - lib/etna/clients/magma/workflows/attribute_actions_from_json_workflow.rb
113
+ - lib/etna/clients/magma/workflows/create_project_workflow.rb
114
+ - lib/etna/clients/magma/workflows/crud_workflow.rb
115
+ - lib/etna/clients/magma/workflows/ensure_containing_record_workflow.rb
116
+ - lib/etna/clients/magma/workflows/file_attributes_blank_workflow.rb
117
+ - lib/etna/clients/magma/workflows/file_linking_workflow.rb
118
+ - lib/etna/clients/magma/workflows/json_converters.rb
119
+ - lib/etna/clients/magma/workflows/json_validators.rb
120
+ - lib/etna/clients/magma/workflows/model_synchronization_workflow.rb
121
+ - lib/etna/clients/magma/workflows/record_synchronization_workflow.rb
122
+ - lib/etna/clients/magma/workflows/update_attributes_from_csv_workflow.rb
123
+ - lib/etna/clients/metis.rb
124
+ - lib/etna/clients/metis/client.rb
125
+ - lib/etna/clients/metis/models.rb
126
+ - lib/etna/clients/metis/workflows.rb
127
+ - lib/etna/clients/metis/workflows/metis_download_workflow.rb
128
+ - lib/etna/clients/metis/workflows/metis_upload_workflow.rb
129
+ - lib/etna/clients/polyphemus.rb
130
+ - lib/etna/clients/polyphemus/client.rb
131
+ - lib/etna/clients/polyphemus/models.rb
132
+ - lib/etna/clients/polyphemus/workflows.rb
133
+ - lib/etna/clients/polyphemus/workflows/set_configuration_workflow.rb
79
134
  - lib/etna/command.rb
80
135
  - lib/etna/controller.rb
81
136
  - lib/etna/cross_origin.rb
137
+ - lib/etna/csvs.rb
82
138
  - lib/etna/describe_routes.rb
139
+ - lib/etna/directed_graph.rb
140
+ - lib/etna/environment_scoped.rb
83
141
  - lib/etna/errors.rb
84
142
  - lib/etna/ext.rb
143
+ - lib/etna/generate_autocompletion_script.rb
85
144
  - lib/etna/hmac.rb
145
+ - lib/etna/json_serializable_struct.rb
86
146
  - lib/etna/logger.rb
147
+ - lib/etna/multipart_serializable_nested_hash.rb
87
148
  - lib/etna/parse_body.rb
88
149
  - lib/etna/route.rb
89
150
  - lib/etna/server.rb
90
151
  - lib/etna/sign_service.rb
91
152
  - lib/etna/spec.rb
92
153
  - lib/etna/spec/auth.rb
154
+ - lib/etna/spec/vcr.rb
93
155
  - lib/etna/symbolize_params.rb
156
+ - lib/etna/templates/attribute_actions_template.json
94
157
  - lib/etna/test_auth.rb
95
158
  - lib/etna/user.rb
159
+ - lib/helpers.rb
96
160
  homepage: http://github.com/mountetna/etna
97
161
  licenses: []
98
162
  metadata: {}
99
- post_install_message:
163
+ post_install_message: "\n\n\e[1;31mAdd 'source ~/etna.completion' to your .bashrc
164
+ to get etna command line completions!\e[0m\n\n"
100
165
  rdoc_options: []
101
166
  require_paths:
102
167
  - lib