nucleus 0.1.0 → 0.2.0

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 (39) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +3 -0
  3. data/CHANGELOG.md +18 -4
  4. data/README.md +28 -40
  5. data/Rakefile +137 -137
  6. data/config/nucleus_config.rb +0 -4
  7. data/lib/nucleus/adapter_resolver.rb +115 -115
  8. data/lib/nucleus/adapters/buildpack_translator.rb +79 -79
  9. data/lib/nucleus/adapters/v1/cloud_control/application.rb +108 -108
  10. data/lib/nucleus/adapters/v1/cloud_control/authentication.rb +27 -27
  11. data/lib/nucleus/adapters/v1/cloud_control/cloud_control.rb +153 -153
  12. data/lib/nucleus/adapters/v1/cloud_control/domains.rb +68 -68
  13. data/lib/nucleus/adapters/v1/cloud_control/logs.rb +103 -103
  14. data/lib/nucleus/adapters/v1/cloud_control/vars.rb +88 -88
  15. data/lib/nucleus/adapters/v1/cloud_foundry_v2/domains.rb +149 -149
  16. data/lib/nucleus/adapters/v1/cloud_foundry_v2/logs.rb +303 -303
  17. data/lib/nucleus/adapters/v1/cloud_foundry_v2/services.rb +286 -286
  18. data/lib/nucleus/adapters/v1/heroku/heroku.rb +2 -2
  19. data/lib/nucleus/adapters/v1/heroku/logs.rb +108 -108
  20. data/lib/nucleus/core/adapter_authentication_inductor.rb +0 -2
  21. data/lib/nucleus/core/adapter_extensions/auth/http_basic_auth_client.rb +37 -37
  22. data/lib/nucleus/core/adapter_extensions/http_client.rb +177 -177
  23. data/lib/nucleus/core/common/files/archive_extractor.rb +112 -112
  24. data/lib/nucleus/core/common/files/archiver.rb +91 -91
  25. data/lib/nucleus/core/common/logging/request_log_formatter.rb +48 -48
  26. data/lib/nucleus/core/error_messages.rb +127 -127
  27. data/lib/nucleus/core/models/abstract_model.rb +29 -29
  28. data/lib/nucleus/scripts/load_dependencies.rb +0 -1
  29. data/lib/nucleus/scripts/setup_config.rb +28 -28
  30. data/lib/nucleus/version.rb +3 -3
  31. data/nucleus.gemspec +10 -12
  32. data/spec/factories/models.rb +63 -61
  33. data/spec/integration/api/auth_spec.rb +58 -58
  34. data/spec/test_suites.rake +31 -31
  35. data/spec/unit/common/helpers/auth_helper_spec.rb +73 -73
  36. data/spec/unit/common/oauth2_auth_client_spec.rb +1 -1
  37. data/tasks/compatibility.rake +113 -113
  38. data/tasks/evaluation.rake +162 -162
  39. metadata +16 -30
@@ -1,127 +1,127 @@
1
- module Nucleus
2
- # The {ErrorMessages} module groups all error definitions that can be returned by the RESTful API.
3
- # With its constants, it provides the skeleton to create error messages that comply with the error schema of Nucleus.
4
- module ErrorMessages
5
- #################
6
- # CLIENT ERRORS #
7
- #################
8
-
9
- ENDPOINT_BAD_REQUEST = {
10
- status: 400,
11
- error_code: 400_001,
12
- message: 'Bad Request'
13
- }
14
-
15
- AUTH_BAD_REQUEST = {
16
- status: 400,
17
- error_code: 400_002,
18
- message: 'Bad Authentication Request'
19
- }
20
-
21
- BAD_REQUEST_VALIDATION = {
22
- status: 400,
23
- error_code: 400_003,
24
- message: 'Bad Request: Parameter validation failed'
25
- }
26
-
27
- BAD_REQUEST_APP_ARCHIVE = {
28
- status: 400,
29
- error_code: 400_004,
30
- message: 'Bad Request: Application archive is damaged or did not match the declared file format'
31
- }
32
-
33
- AUTH_UNAUTHORIZED = {
34
- status: 401,
35
- error_code: 401_000,
36
- message: 'Unauthorized: Authentication failed'
37
- }
38
-
39
- ENDPOINT_AUTH_FAILED = {
40
- status: 401,
41
- error_code: 401_001,
42
- message: 'Authentication failed, endpoint rejected authentication attempt'
43
- }
44
-
45
- NOT_FOUND = {
46
- status: 404,
47
- error_code: 404_000,
48
- message: 'The resource could not be found'
49
- }
50
-
51
- ENDPOINT_NOT_FOUND = {
52
- status: 404,
53
- error_code: 404_001,
54
- message: 'The resource could not be found'
55
- }
56
-
57
- INVALID_ACCEPT_HEADER = {
58
- status: 406,
59
- error_code: 406_000,
60
- message: 'Invalid Accept header, vendor or version not found'
61
- }
62
-
63
- BAD_REQUEST_ENTITY = {
64
- status: 422,
65
- error_code: 422_000,
66
- message: 'Unprocessable Entity: Request was valid, but has been rejected by the endpoint, '\
67
- 'saying the message was semantically false. Check the dev_message for detailed error analysis'
68
- }
69
-
70
- # All platform specific semantic errors should have a unique error code!
71
- PLATFORM_SPECIFIC_ERROR_ENTITY = {
72
- status: 422,
73
- error_code: 422_001,
74
- message: 'Unprocessable Entity: Request format was valid, but has been rejected by the endpoint, '\
75
- 'saying the message contains data that can not be processed by this specific platform.'
76
- }
77
-
78
- # Quota violations are a common issue and therefore deserve their own message ;)
79
- PLATFORM_QUOTA_ERROR = {
80
- status: 422,
81
- error_code: 422_002,
82
- message: 'Unprocessable Entity: Request format was valid, but has been rejected by the endpoint. '\
83
- 'Your account would exceed its quota limits. Please check your account and its billing status.'
84
- }
85
-
86
- #################
87
- # SERVER ERRORS #
88
- #################
89
-
90
- RESCUED = {
91
- status: 500,
92
- error_code: 500_000,
93
- message: 'Oops, something went terribly wrong here :/'
94
- }
95
-
96
- RESCUED_ADAPTER_CALL = {
97
- status: 500,
98
- error_code: 500_001,
99
- message: 'Endpoint call failed with unforeseen cause'
100
- }
101
-
102
- RESCUED_ADAPTER_CALL_SERVER = {
103
- status: 500,
104
- error_code: 500_002,
105
- message: 'Endpoint crashed with server error'
106
- }
107
-
108
- MISSING_IMPLEMENTATION = {
109
- status: 501,
110
- error_code: 501_000,
111
- message: 'Not Implemented'
112
- }
113
-
114
- UNAVAILABLE = {
115
- status: 503,
116
- error_code: 503_000,
117
- message: 'Service Unavailable'
118
- }
119
-
120
- PLATFORM_GATEWAY_TIMEOUT = {
121
- status: 504,
122
- error_code: 504_000,
123
- message: 'Gateway Timeout. The platform raised an internal Timeout error. We don\'t know to what '\
124
- 'degree the request has been processed, or if it wasn\'t executed at all.'
125
- }
126
- end
127
- end
1
+ module Nucleus
2
+ # The {ErrorMessages} module groups all error definitions that can be returned by the RESTful API.
3
+ # With its constants, it provides the skeleton to create error messages that comply with the error schema of Nucleus.
4
+ module ErrorMessages
5
+ #################
6
+ # CLIENT ERRORS #
7
+ #################
8
+
9
+ ENDPOINT_BAD_REQUEST = {
10
+ status: 400,
11
+ error_code: 400_001,
12
+ message: 'Bad Request'
13
+ }
14
+
15
+ AUTH_BAD_REQUEST = {
16
+ status: 400,
17
+ error_code: 400_002,
18
+ message: 'Bad Authentication Request'
19
+ }
20
+
21
+ BAD_REQUEST_VALIDATION = {
22
+ status: 400,
23
+ error_code: 400_003,
24
+ message: 'Bad Request: Parameter validation failed'
25
+ }
26
+
27
+ BAD_REQUEST_APP_ARCHIVE = {
28
+ status: 400,
29
+ error_code: 400_004,
30
+ message: 'Bad Request: Application archive is damaged or did not match the declared file format'
31
+ }
32
+
33
+ AUTH_UNAUTHORIZED = {
34
+ status: 401,
35
+ error_code: 401_000,
36
+ message: 'Unauthorized: Authentication failed'
37
+ }
38
+
39
+ ENDPOINT_AUTH_FAILED = {
40
+ status: 401,
41
+ error_code: 401_001,
42
+ message: 'Authentication failed, endpoint rejected authentication attempt'
43
+ }
44
+
45
+ NOT_FOUND = {
46
+ status: 404,
47
+ error_code: 404_000,
48
+ message: 'The resource could not be found'
49
+ }
50
+
51
+ ENDPOINT_NOT_FOUND = {
52
+ status: 404,
53
+ error_code: 404_001,
54
+ message: 'The resource could not be found'
55
+ }
56
+
57
+ INVALID_ACCEPT_HEADER = {
58
+ status: 406,
59
+ error_code: 406_000,
60
+ message: 'Invalid Accept header, vendor or version not found'
61
+ }
62
+
63
+ BAD_REQUEST_ENTITY = {
64
+ status: 422,
65
+ error_code: 422_000,
66
+ message: 'Unprocessable Entity: Request was valid, but has been rejected by the endpoint, '\
67
+ 'saying the message was semantically false. Check the dev_message for detailed error analysis'
68
+ }
69
+
70
+ # All platform specific semantic errors should have a unique error code!
71
+ PLATFORM_SPECIFIC_ERROR_ENTITY = {
72
+ status: 422,
73
+ error_code: 422_001,
74
+ message: 'Unprocessable Entity: Request format was valid, but has been rejected by the endpoint, '\
75
+ 'saying the message contains data that can not be processed by this specific platform.'
76
+ }
77
+
78
+ # Quota violations are a common issue and therefore deserve their own message ;)
79
+ PLATFORM_QUOTA_ERROR = {
80
+ status: 422,
81
+ error_code: 422_002,
82
+ message: 'Unprocessable Entity: Request format was valid, but has been rejected by the endpoint. '\
83
+ 'Your account would exceed its quota limits. Please check your account and its billing status.'
84
+ }
85
+
86
+ #################
87
+ # SERVER ERRORS #
88
+ #################
89
+
90
+ RESCUED = {
91
+ status: 500,
92
+ error_code: 500_000,
93
+ message: 'Oops, something went terribly wrong here :/'
94
+ }
95
+
96
+ RESCUED_ADAPTER_CALL = {
97
+ status: 500,
98
+ error_code: 500_001,
99
+ message: 'Endpoint call failed with unforeseen cause'
100
+ }
101
+
102
+ RESCUED_ADAPTER_CALL_SERVER = {
103
+ status: 500,
104
+ error_code: 500_002,
105
+ message: 'Endpoint crashed with server error'
106
+ }
107
+
108
+ MISSING_IMPLEMENTATION = {
109
+ status: 501,
110
+ error_code: 501_000,
111
+ message: 'Not Implemented'
112
+ }
113
+
114
+ UNAVAILABLE = {
115
+ status: 503,
116
+ error_code: 503_000,
117
+ message: 'Service Unavailable'
118
+ }
119
+
120
+ PLATFORM_GATEWAY_TIMEOUT = {
121
+ status: 504,
122
+ error_code: 504_000,
123
+ message: 'Gateway Timeout. The platform raised an internal Timeout error. We don\'t know to what '\
124
+ 'degree the request has been processed, or if it wasn\'t executed at all.'
125
+ }
126
+ end
127
+ end
@@ -1,29 +1,29 @@
1
- module Nucleus
2
- #
3
- # @author Cedric Roeck (cedric.roeck@gmail.com)
4
- # @since 0.1.0
5
- class AbstractModel
6
- include Kwalify::Util::HashLike
7
-
8
- attr_accessor :id
9
- attr_accessor :name
10
- attr_accessor :created_at
11
- attr_accessor :updated_at
12
-
13
- def initialize(hash = nil)
14
- return if hash.nil?
15
- @name = hash['name']
16
- @id = hash['id']
17
- end
18
-
19
- def to_s
20
- return name if self.respond_to?('name')
21
- return id if id
22
- super.to_s
23
- end
24
-
25
- def inspect
26
- to_s
27
- end
28
- end
29
- end
1
+ module Nucleus
2
+ #
3
+ # @author Cedric Roeck (cedric.roeck@gmail.com)
4
+ # @since 0.1.0
5
+ class AbstractModel
6
+ include Kwalify::Util::HashLike
7
+
8
+ attr_accessor :id
9
+ attr_accessor :name
10
+ attr_accessor :created_at
11
+ attr_accessor :updated_at
12
+
13
+ def initialize(hash = nil)
14
+ return if hash.nil?
15
+ @name = hash['name']
16
+ @id = hash['id']
17
+ end
18
+
19
+ def to_s
20
+ return name if respond_to?('name')
21
+ return id if id
22
+ super.to_s
23
+ end
24
+
25
+ def inspect
26
+ to_s
27
+ end
28
+ end
29
+ end
@@ -9,7 +9,6 @@ require 'logger'
9
9
 
10
10
  # database
11
11
  require 'moneta'
12
- require 'daybreak'
13
12
  require 'lmdb'
14
13
 
15
14
  # schema
@@ -1,28 +1,28 @@
1
- # configuration
2
- require 'logger'
3
- require 'configatron/core'
4
- require 'nucleus/ext/kernel'
5
- require 'nucleus/os'
6
-
7
- # import the configuration file that resides in the user's home directory as initial choice
8
- if OS.windows?
9
- home_dir_config = File.expand_path(File.join(Dir.home, 'nucleus', 'nucleus_config.rb'))
10
- else
11
- home_dir_config = File.expand_path(File.join(Dir.home, '.nucleus', 'nucleus_config.rb'))
12
- end
13
- if File.exist?(home_dir_config)
14
- puts "Applying configuration from: #{home_dir_config}"
15
- require home_dir_config
16
- end
17
-
18
- # include the configuration of the project to overwrite the home dir config
19
- project_dir_config = '../../../config/nucleus_config.rb'
20
- if File.exist?(File.expand_path(project_dir_config, File.dirname(__FILE__)))
21
- puts "Applying configuration from: #{File.expand_path(project_dir_config, File.dirname(__FILE__))}"
22
- require_relative project_dir_config
23
- end
24
-
25
- # make sure we have a logging directory
26
- unless nucleus_config.logging.key?(:path)
27
- nucleus_config.logging.path = File.join(__dir__, '..', '..', '..', 'log')
28
- end
1
+ # configuration
2
+ require 'logger'
3
+ require 'configatron/core'
4
+ require 'nucleus/ext/kernel'
5
+ require 'nucleus/os'
6
+
7
+ # import the configuration file that resides in the user's home directory as initial choice
8
+ home_dir_config = if OS.windows?
9
+ File.expand_path(File.join(Dir.home, 'nucleus', 'nucleus_config.rb'))
10
+ else
11
+ File.expand_path(File.join(Dir.home, '.nucleus', 'nucleus_config.rb'))
12
+ end
13
+ if File.exist?(home_dir_config)
14
+ puts "Applying configuration from: #{home_dir_config}"
15
+ require home_dir_config
16
+ end
17
+
18
+ # include the configuration of the project to overwrite the home dir config
19
+ project_dir_config = '../../../config/nucleus_config.rb'
20
+ if File.exist?(File.expand_path(project_dir_config, File.dirname(__FILE__)))
21
+ puts "Applying configuration from: #{File.expand_path(project_dir_config, File.dirname(__FILE__))}"
22
+ require_relative project_dir_config
23
+ end
24
+
25
+ # make sure we have a logging directory
26
+ unless nucleus_config.logging.key?(:path)
27
+ nucleus_config.logging.path = File.join(__dir__, '..', '..', '..', 'log')
28
+ end
@@ -1,3 +1,3 @@
1
- module Nucleus
2
- VERSION = '0.1.0'
3
- end
1
+ module Nucleus
2
+ VERSION = '0.2.0'.freeze
3
+ end
@@ -17,16 +17,14 @@ Gem::Specification.new do |spec|
17
17
  spec.required_ruby_version = '>= 2.0'
18
18
 
19
19
  # we ignore the test files and icons as they tremendously increase the gem size (up to 43MB)
20
- spec.files = `git ls-files -z --exclude-standard`.split("\x0").reject do |f|
20
+ spec.files = `git ls-files -z --exclude-standard`.split("\x0").reject do |f|
21
21
  f[%r{^(lib/nucleus_api|spec/adapter|icons)/}]
22
22
  end
23
23
  # again only unit and integration, but no adapter test files
24
- spec.test_files = spec.files.grep(%r{^(spec)/})
24
+ spec.test_files = spec.files.grep(%r{^(spec)/})
25
25
 
26
26
  # used as global configuration
27
27
  spec.add_runtime_dependency 'configatron', '~> 4.5'
28
- # DB store (1)
29
- spec.add_runtime_dependency 'daybreak', '~> 0.3'
30
28
  # Required for log tailing against HTTP endpoints
31
29
  spec.add_runtime_dependency 'em-http-request', '~> 1.1'
32
30
  # Used as main HTTP / REST client
@@ -36,24 +34,24 @@ Gem::Specification.new do |spec|
36
34
  # Application data handling
37
35
  spec.add_runtime_dependency 'git', '~> 1.2'
38
36
  # Used to build the API
39
- spec.add_runtime_dependency 'grape', '~> 0.12'
40
- spec.add_runtime_dependency 'grape-entity', '~> 0.4', '>= 0.4.5'
37
+ spec.add_runtime_dependency 'grape', '~> 0.13.0'
38
+ spec.add_runtime_dependency 'grape-entity', '~> 0.4.8', '>= 0.4.5'
41
39
  # Used to document the API
42
- spec.add_runtime_dependency 'grape-swagger', '~> 0.10', '>= 0.10.1'
40
+ spec.add_runtime_dependency 'grape-swagger', '~> 0.10.2', '>= 0.10.1'
43
41
  # Used to import the vendor, provider & adapter setup from configuration with schema validation
44
42
  spec.add_runtime_dependency 'kwalify', '~> 0.7'
45
- # DB store (2)
43
+ # DB store
46
44
  spec.add_runtime_dependency 'lmdb', '~> 0.4'
47
45
  # Logging
48
46
  spec.add_runtime_dependency 'logger', '~> 1.2'
49
47
  # Application archive handling, detect unsupported uploads
50
- spec.add_runtime_dependency 'mime-types', '~> 2.4'
48
+ spec.add_runtime_dependency 'mime-types', '~> 2.6'
51
49
  # Generic interface for DB store implementations
52
50
  spec.add_runtime_dependency 'moneta', '~> 0.8'
53
51
  # Openshift logging access and direct Git SSH requests
54
52
  spec.add_runtime_dependency 'net-ssh', '~> 3.0'
55
53
  # Used for JSON / Hash conversion and test cassette serialization (is way faster than other JSON libs)
56
- spec.add_runtime_dependency 'oj', '~> 2.12'
54
+ spec.add_runtime_dependency 'oj', '~> 2.14'
57
55
  # Required for Cloud Foundry log messages
58
56
  spec.add_runtime_dependency 'protobuf', '~> 3.4'
59
57
  # To make sure HTTPS is used instead of HTTP
@@ -81,8 +79,8 @@ Gem::Specification.new do |spec|
81
79
  spec.add_development_dependency 'guard-yard'
82
80
  spec.add_development_dependency 'inch', '~> 0.7'
83
81
  spec.add_development_dependency 'rake', '~> 10.4'
84
- spec.add_development_dependency 'rubocop', '~> 0.34'
85
- spec.add_development_dependency 'vcr', '~> 2.9'
82
+ spec.add_development_dependency 'rubocop', '~> 0.36.0'
83
+ spec.add_development_dependency 'vcr', '~> 3.0'
86
84
  spec.add_development_dependency 'webmock', '~> 1.20'
87
85
  spec.add_development_dependency 'yard', '~> 0.8'
88
86
  end
@@ -1,61 +1,63 @@
1
- FactoryGirl.define do
2
- sequence :uuid do |_|
3
- SecureRandom.uuid
4
- end
5
-
6
- factory :adapter, class: Nucleus::AdapterIndexEntry do
7
- url { Faker::Internet.url }
8
- id nil
9
- adapter_clazz nil
10
- end
11
-
12
- factory :endpoint, class: Nucleus::Endpoint do
13
- id { generate(:uuid) }
14
- name { Faker::Internet.slug }
15
- url { Faker::Internet.url }
16
- created_at { (Faker::Date.between(180.days.ago, 90.days.ago)).iso8601 }
17
- updated_at { (Faker::Date.between(90.days.ago, Date.today)).iso8601 }
18
- provider nil
19
-
20
- after(:create) do |endpoint|
21
- # associate with provider
22
- unless endpoint.provider.nil?
23
- # TODO: find a solution how to test when multiple API versions are to be supported
24
- dao = Nucleus::API::DB::ProviderDao.instance('v1')
25
- provider = dao.get endpoint.provider
26
- provider.endpoints = [] if provider.endpoints.nil?
27
- provider.endpoints << endpoint.id
28
- # save updated association
29
- dao.set provider
30
- end
31
- end
32
- end
33
-
34
- factory :provider, class: Nucleus::Provider do
35
- id { generate(:uuid) }
36
- name { Faker::App.name }
37
- created_at { (Faker::Date.between(180.days.ago, 90.days.ago)).iso8601 }
38
- updated_at { (Faker::Date.between(90.days.ago, Date.today)).iso8601 }
39
- vendor nil
40
-
41
- after(:create) do |provider|
42
- # associate with vendor
43
- unless provider.vendor.nil?
44
- # TODO: find a solution how to test when multiple API versions are to be supported
45
- dao = Nucleus::API::DB::VendorDao.instance('v1')
46
- vendor = dao.get provider.vendor
47
- vendor.providers = [] if vendor.providers.nil?
48
- vendor.providers << provider.id
49
- # save updated association
50
- dao.set vendor
51
- end
52
- end
53
- end
54
-
55
- factory :vendor, class: Nucleus::Vendor do
56
- id { generate(:uuid) }
57
- name { Faker::App.name }
58
- created_at { (Faker::Date.between(180.days.ago, 90.days.ago)).iso8601 }
59
- updated_at { (Faker::Date.between(90.days.ago, Date.today)).iso8601 }
60
- end
61
- end
1
+ require 'active_support/core_ext'
2
+
3
+ FactoryGirl.define do
4
+ sequence :uuid do |_|
5
+ SecureRandom.uuid
6
+ end
7
+
8
+ factory :adapter, class: Nucleus::AdapterIndexEntry do
9
+ url { Faker::Internet.url }
10
+ id nil
11
+ adapter_clazz nil
12
+ end
13
+
14
+ factory :endpoint, class: Nucleus::Endpoint do
15
+ id { generate(:uuid) }
16
+ name { Faker::Internet.slug }
17
+ url { Faker::Internet.url }
18
+ created_at { Faker::Date.between(180.days.ago, 90.days.ago).iso8601 }
19
+ updated_at { Faker::Date.between(90.days.ago, Date.today).iso8601 }
20
+ provider nil
21
+
22
+ after(:create) do |endpoint|
23
+ # associate with provider
24
+ unless endpoint.provider.nil?
25
+ # TODO: find a solution how to test when multiple API versions are to be supported
26
+ dao = Nucleus::API::DB::ProviderDao.instance('v1')
27
+ provider = dao.get endpoint.provider
28
+ provider.endpoints = [] if provider.endpoints.nil?
29
+ provider.endpoints << endpoint.id
30
+ # save updated association
31
+ dao.set provider
32
+ end
33
+ end
34
+ end
35
+
36
+ factory :provider, class: Nucleus::Provider do
37
+ id { generate(:uuid) }
38
+ name { Faker::App.name }
39
+ created_at { Faker::Date.between(180.days.ago, 90.days.ago).iso8601 }
40
+ updated_at { Faker::Date.between(90.days.ago, Date.today).iso8601 }
41
+ vendor nil
42
+
43
+ after(:create) do |provider|
44
+ # associate with vendor
45
+ unless provider.vendor.nil?
46
+ # TODO: find a solution how to test when multiple API versions are to be supported
47
+ dao = Nucleus::API::DB::VendorDao.instance('v1')
48
+ vendor = dao.get provider.vendor
49
+ vendor.providers = [] if vendor.providers.nil?
50
+ vendor.providers << provider.id
51
+ # save updated association
52
+ dao.set vendor
53
+ end
54
+ end
55
+ end
56
+
57
+ factory :vendor, class: Nucleus::Vendor do
58
+ id { generate(:uuid) }
59
+ name { Faker::App.name }
60
+ created_at { Faker::Date.between(180.days.ago, 90.days.ago).iso8601 }
61
+ updated_at { Faker::Date.between(90.days.ago, Date.today).iso8601 }
62
+ end
63
+ end