vert-core 1.0.0 → 1.0.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 802f4618d6763aeb190d05eb6bd29218d07ae0b3c229e968366a7c200bc08fb3
4
- data.tar.gz: cf5140dd8bfb233db4163479ca714ac30049c69524a1139c36140b0046bc3091
3
+ metadata.gz: 3cd14af74495d17174f61ed390691b90f01b5897ffc368e804cc6155ffc7e70d
4
+ data.tar.gz: 0fdad12a722f1f876349b3a1f93cef84a1307a34fb96f2587ab429d0b6d4320f
5
5
  SHA512:
6
- metadata.gz: 9e1afa0a09e98a12da919ab46ee34535eacc15d4e74e47edfe7da199b3b3f36895375abd360e7efb0ff87421bece811e0488ca7ddb10ed0dfffceb0f63387e57
7
- data.tar.gz: ef379164049f6887b3748fdaa06b481e18c1836fa81172c5a63e28d8999d77c58bf08aaeda418f1ccf7be9cbcf94bf2f9b0c37cf3ad6a9d6df0b7bc43f9e3b88
6
+ metadata.gz: ca0ffeea71830f7f2f26028bd4b8bf269ed7d15138f7971846c72d15bb8b70ef9dfedc6afa118e98f7ecbbe63ff1dc8bdf15782836ffb62b216086e87006772d
7
+ data.tar.gz: 8427a308b31890c81df7cc7bcbd2ba7a867e8067bede7e45ad5e16c19f6880d9a3f27be033863467ad960dc98e901708c27b86277d6d7b65d79ef9cdda538d9b
data/README.md CHANGED
@@ -4,10 +4,10 @@ Gem genérica de padrões para aplicações Rails: contexto de request, RLS, Out
4
4
 
5
5
  ## Instalação
6
6
 
7
- Adicione ao `Gemfile`:
7
+ Adicione ao `Gemfile` (nome da gem no RubyGems é `vert-core`; o módulo continua `Vert`):
8
8
 
9
9
  ```ruby
10
- gem "vert"
10
+ gem "vert-core"
11
11
  ```
12
12
 
13
13
  Execute:
@@ -121,6 +121,12 @@ class MyJob < ApplicationJob
121
121
  end
122
122
  ```
123
123
 
124
+ ## Produção e segurança
125
+
126
+ - Defina sempre via **variáveis de ambiente** em produção: `RABBITMQ_URL`, `DOCUMENT_SERVICE_URL`, `REDIS_URL`. Os valores padrão (guest/localhost) são apenas para desenvolvimento.
127
+ - Serviços que publicam mensagens nas filas consumidas com `Vert::Rls::ConsumerContext` podem definir o contexto (tenant_id, user_id) via headers; garanta que apenas serviços confiáveis publiquem nessas filas.
128
+ - Para mais detalhes, veja `SECURITY_AND_QUALITY_AUDIT.md` no repositório.
129
+
124
130
  ## Licença
125
131
 
126
132
  MIT.
@@ -0,0 +1,98 @@
1
+ # Auditoria de Qualidade e Segurança — Gem vert-core
2
+
3
+ **Data:** 2025-03
4
+ **Escopo:** `services/00-gems/vert` (publicada no RubyGems como `vert-core`)
5
+ **Objetivo:** Garantir segurança e confiabilidade para uso em produção.
6
+
7
+ ---
8
+
9
+ ## 1. Resumo executivo
10
+
11
+ | Categoria | Status | Observação |
12
+ |------------------|--------|------------|
13
+ | Segurança | ✅ Aprovado com ressalvas | Sem vulnerabilidades críticas; ver itens 2.x |
14
+ | Qualidade | ✅ Bom | Código consistente; ver itens 3.x |
15
+ | Dependências | ✅ OK | Rails 7–9, Sidekiq, Bunny, Discard — versões declaradas |
16
+ | Publicação | ⚠️ Ajuste | CI usa Ruby 2.6; gemspec exige >= 3.2 |
17
+
18
+ ---
19
+
20
+ ## 2. Segurança
21
+
22
+ ### 2.1 Pontos positivos
23
+
24
+ - **SQL:** Uso de `ActiveRecord::Base.sanitize_sql` em `ConnectionHandler` para `SET LOCAL` (tenant_id, company_id, user_id). Nenhuma concatenação direta de input em SQL.
25
+ - **Autorização:** Queries em `PermissionResolver` usam placeholders (`?`). Nenhum `eval`, `YAML.load` ou `Marshal.load` em dados de usuário ou mensagens.
26
+ - **Contexto de job:** `Vert::Current.serialize/deserialize` só manipula Hash com atributos primitivos (tenant_id, user_id, company_id, request_id). Não há deserialização insegura.
27
+ - **Constantes:** `Object.const_get` em `PolicyFinder` e `OutboxEvent` usa apenas nomes derivados do modelo/record da aplicação, não de input do usuário.
28
+ - **Secrets:** Nenhuma senha, token ou API key hardcoded. URLs e credenciais vêm de `Vert.config` ou `ENV`.
29
+
30
+ ### 2.2 Riscos e recomendações
31
+
32
+ | Risco | Severidade | Recomendação |
33
+ |-------|------------|--------------|
34
+ | **Defaults de conexão** | Baixo | `Configuration` usa `ENV.fetch(..., "amqp://guest:guest@localhost:5672/")` e `redis://localhost:6379/0`. Em produção, garantir sempre variáveis de ambiente; considerar remover defaults “guest” em doc ou comentar que são apenas para desenvolvimento. |
35
+ | **Document service** | Baixo | `DocumentServiceClient` não valida `base_url`. Garantir que `document_service_url` não seja controlada por usuário (evitar SSRF). Em produção usar HTTPS. |
36
+ | **Health / rotas** | Baixo | `Vert::Health::Routes.mount(router, path: nil)` usa `path` em `scope path`. O valor vem de `Vert.config.health_check_path` (default `/health`). Se a app permitir config dinâmico a partir de input, poderia haver path traversal; uso normal é seguro. |
37
+ | **Resposta 403** | Info | `render_forbidden` expõe `permission` (nome do método da policy) e `resource` (nome da classe). Pode ser desejável em APIs internas; em APIs públicas considerar resposta genérica para não revelar estrutura. |
38
+ | **Cache de permissões (Redis)** | Baixo | `invalidate_user_cache(user_id)` monta a chave `vert:permissions:#{user_id}:*`. Se `user_id` puder conter `*` ou `?`, o padrão Redis poderia invalidar mais chaves. Recomendação: usar apenas IDs válidos (UUID/integer) ou escapar/sanitizar. |
39
+ | **Consumers RabbitMQ** | Médio (contexto) | `ConsumerContext` define contexto (tenant_id, user_id, company_id) a partir dos headers da mensagem. Qualquer produtor da fila pode “personificar” um tenant. Garantir que apenas serviços confiáveis publiquem nessas filas e que a rede do broker seja controlada. |
40
+
41
+ ### 2.3 O que não foi encontrado
42
+
43
+ - Uso de `eval`, `exec`, `system`, backticks ou `Kernel#open` com input externo.
44
+ - `YAML.load` ou `Marshal.load` em dados de request ou mensagens.
45
+ - Exposição de stack trace ou detalhes internos em respostas de erro (apenas mensagens controladas).
46
+ - Credenciais ou tokens fixos no código.
47
+
48
+ ---
49
+
50
+ ## 3. Qualidade
51
+
52
+ ### 3.1 Estrutura e convenções
53
+
54
+ - `# frozen_string_literal: true` e estilo consistente.
55
+ - Separação clara: concerns, clients, RLS, outbox, health, authorization.
56
+ - Entry point único: `vert_core.rb` → `vert.rb`; Railtie condicional.
57
+
58
+ ### 3.2 Tratamento de erros
59
+
60
+ - `ConnectionHandler`: `rescue StandardError` com log e re-raise em `set_context`; em `reset_context` apenas log (evita mascarar falhas de reset).
61
+ - `DocumentServiceClient`: `execute_request` retorna hash `{ success:, error:, ... }`; não propaga exceção para o caller, adequado para cliente HTTP.
62
+ - `Publisher#publish`: `rescue StandardError` → `mark_as_failed!` e retorno `false`.
63
+ - Health checks: cada check em `check_all` em bloco próprio com `rescue` para não derrubar os demais.
64
+
65
+ ### 3.3 Configuração
66
+
67
+ - Flags explícitas (enable_rls, enable_outbox, etc.) com default seguro (maioria `false`; health `true`).
68
+ - Documentação no README e no template do initializer.
69
+
70
+ ### 3.4 Melhorias sugeridas
71
+
72
+ - **Configuração sensível:** Considerar um método `Vert.config.to_s` ou inspetor que oculte `rabbitmq_url` e `document_service_url` em logs (ex.: mostrar só host/scheme).
73
+ - **Versão do Ruby no CI:** Alinhar o workflow ao `required_ruby_version` (>= 3.2) para evitar publicar com Ruby incompatível.
74
+
75
+ ---
76
+
77
+ ## 4. Gemspec e publicação
78
+
79
+ - **Nome:** `vert-core` (require: `vert_core`); módulo: `Vert`. Consistente.
80
+ - **Licença:** MIT. Adequado.
81
+ - **Dependências:** activesupport/activerecord 7–9, bunny ~> 2.22, discard ~> 1.3, sidekiq 7–9. Ranges claros.
82
+ - **CI:** `.github/workflows/gem-push.yml` usa Ruby 2.6; o gemspec exige `>= 3.2.0`. **Correção necessária:** usar Ruby 3.2 (ou 3.3) no workflow.
83
+
84
+ ---
85
+
86
+ ## 5. Checklist pós-auditoria
87
+
88
+ - [ ] Atualizar workflow para Ruby 3.2+.
89
+ - [ ] Documentar na README que defaults de RabbitMQ/Redis são apenas para desenvolvimento.
90
+ - [ ] (Opcional) Sanitizar/validar `user_id` em chaves de cache no `PermissionResolver`.
91
+ - [ ] (Opcional) Resposta 403 mais genérica em ambientes públicos.
92
+ - [ ] Manter dependências atualizadas (`bundle audit` / Dependabot).
93
+
94
+ ---
95
+
96
+ ## 6. Conclusão
97
+
98
+ A gem **vert-core** está em bom estado para uso em produção do ponto de vista de segurança e qualidade. Não foram identificadas vulnerabilidades críticas ou altas. As recomendações são sobretudo de configuração (ENV em produção, confiança em produtores de mensagens), alinhamento do CI ao Ruby 3.2+ e pequenos ajustes opcionais de hardening e documentação.
@@ -51,7 +51,10 @@ module Vert
51
51
  end
52
52
 
53
53
  def invalidate_user_cache(user_id)
54
- pattern = "#{CACHE_PREFIX}:#{user_id}:*"
54
+ return if user_id.blank?
55
+ # Sanitize to avoid Redis KEYS pattern injection (e.g. * or ? in user_id)
56
+ safe_id = user_id.to_s.gsub(%r{[*?\[\]\{\}\\]}, "")
57
+ pattern = "#{CACHE_PREFIX}:#{safe_id}:*"
55
58
  redis_delete_pattern(pattern)
56
59
  end
57
60
 
@@ -50,6 +50,7 @@ module Vert
50
50
  @enable_company_scoped = false
51
51
  @enable_document_storeable = false
52
52
 
53
+ # Production: set RABBITMQ_URL, DOCUMENT_SERVICE_URL, REDIS_URL via ENV; do not rely on defaults.
53
54
  @rls_user = ENV.fetch("RLS_USER", "app_user")
54
55
  @rabbitmq_url = ENV.fetch("RABBITMQ_URL", "amqp://guest:guest@localhost:5672/")
55
56
  @exchange_name = ENV.fetch("RABBITMQ_EXCHANGE", "vert.events")
data/lib/vert/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Vert
4
- VERSION = "1.0.0"
4
+ VERSION = "1.0.2"
5
5
  end
data/lib/vert_core.rb ADDED
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Entry point for gem "vert-core". Bundler requires this file by name (vert_core),
4
+ # so the Vert constant is available when config/initializers/vert.rb runs.
5
+ require_relative "vert"
data/vert.gemspec CHANGED
@@ -15,13 +15,14 @@ Gem::Specification.new do |spec|
15
15
  spec.required_ruby_version = ">= 3.2.0"
16
16
 
17
17
  spec.metadata["homepage_uri"] = spec.homepage
18
- spec.metadata["source_code_uri"] = spec.homepage
18
+ spec.metadata["source_code_uri"] = "#{spec.homepage}/tree/main"
19
19
  spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/main/CHANGELOG.md"
20
20
 
21
21
  spec.files = Dir.chdir(__dir__) do
22
22
  Dir.glob("**/*").reject do |f|
23
23
  File.directory?(f) ||
24
24
  (File.expand_path(f) == __FILE__) ||
25
+ f.end_with?(".gem") ||
25
26
  f.start_with?(*%w[bin/ test/ spec/ features/ .git .circleci appveyor Gemfile])
26
27
  end
27
28
  end
@@ -29,11 +30,11 @@ Gem::Specification.new do |spec|
29
30
  spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
30
31
  spec.require_paths = ["lib"]
31
32
 
32
- spec.add_dependency "activesupport", ">= 7.0"
33
- spec.add_dependency "activerecord", ">= 7.0"
34
- spec.add_dependency "discard", "~> 1.3"
35
- spec.add_dependency "bunny", "~> 2.22"
36
- spec.add_dependency "sidekiq", ">= 7.0"
33
+ spec.add_runtime_dependency "activesupport", ">= 7.0", "< 9.0"
34
+ spec.add_runtime_dependency "activerecord", ">= 7.0", "< 9.0"
35
+ spec.add_runtime_dependency "bunny", "~> 2.22"
36
+ spec.add_runtime_dependency "discard", "~> 1.3"
37
+ spec.add_runtime_dependency "sidekiq", ">= 7.0", "< 9.0"
37
38
 
38
39
  spec.add_development_dependency "rake", "~> 13.0"
39
40
  spec.add_development_dependency "rspec", "~> 3.0"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vert-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vert Team
@@ -16,6 +16,9 @@ dependencies:
16
16
  - - ">="
17
17
  - !ruby/object:Gem::Version
18
18
  version: '7.0'
19
+ - - "<"
20
+ - !ruby/object:Gem::Version
21
+ version: '9.0'
19
22
  type: :runtime
20
23
  prerelease: false
21
24
  version_requirements: !ruby/object:Gem::Requirement
@@ -23,6 +26,9 @@ dependencies:
23
26
  - - ">="
24
27
  - !ruby/object:Gem::Version
25
28
  version: '7.0'
29
+ - - "<"
30
+ - !ruby/object:Gem::Version
31
+ version: '9.0'
26
32
  - !ruby/object:Gem::Dependency
27
33
  name: activerecord
28
34
  requirement: !ruby/object:Gem::Requirement
@@ -30,6 +36,9 @@ dependencies:
30
36
  - - ">="
31
37
  - !ruby/object:Gem::Version
32
38
  version: '7.0'
39
+ - - "<"
40
+ - !ruby/object:Gem::Version
41
+ version: '9.0'
33
42
  type: :runtime
34
43
  prerelease: false
35
44
  version_requirements: !ruby/object:Gem::Requirement
@@ -37,34 +46,37 @@ dependencies:
37
46
  - - ">="
38
47
  - !ruby/object:Gem::Version
39
48
  version: '7.0'
49
+ - - "<"
50
+ - !ruby/object:Gem::Version
51
+ version: '9.0'
40
52
  - !ruby/object:Gem::Dependency
41
- name: discard
53
+ name: bunny
42
54
  requirement: !ruby/object:Gem::Requirement
43
55
  requirements:
44
56
  - - "~>"
45
57
  - !ruby/object:Gem::Version
46
- version: '1.3'
58
+ version: '2.22'
47
59
  type: :runtime
48
60
  prerelease: false
49
61
  version_requirements: !ruby/object:Gem::Requirement
50
62
  requirements:
51
63
  - - "~>"
52
64
  - !ruby/object:Gem::Version
53
- version: '1.3'
65
+ version: '2.22'
54
66
  - !ruby/object:Gem::Dependency
55
- name: bunny
67
+ name: discard
56
68
  requirement: !ruby/object:Gem::Requirement
57
69
  requirements:
58
70
  - - "~>"
59
71
  - !ruby/object:Gem::Version
60
- version: '2.22'
72
+ version: '1.3'
61
73
  type: :runtime
62
74
  prerelease: false
63
75
  version_requirements: !ruby/object:Gem::Requirement
64
76
  requirements:
65
77
  - - "~>"
66
78
  - !ruby/object:Gem::Version
67
- version: '2.22'
79
+ version: '1.3'
68
80
  - !ruby/object:Gem::Dependency
69
81
  name: sidekiq
70
82
  requirement: !ruby/object:Gem::Requirement
@@ -72,6 +84,9 @@ dependencies:
72
84
  - - ">="
73
85
  - !ruby/object:Gem::Version
74
86
  version: '7.0'
87
+ - - "<"
88
+ - !ruby/object:Gem::Version
89
+ version: '9.0'
75
90
  type: :runtime
76
91
  prerelease: false
77
92
  version_requirements: !ruby/object:Gem::Requirement
@@ -79,6 +94,9 @@ dependencies:
79
94
  - - ">="
80
95
  - !ruby/object:Gem::Version
81
96
  version: '7.0'
97
+ - - "<"
98
+ - !ruby/object:Gem::Version
99
+ version: '9.0'
82
100
  - !ruby/object:Gem::Dependency
83
101
  name: rake
84
102
  requirement: !ruby/object:Gem::Requirement
@@ -160,6 +178,7 @@ extra_rdoc_files: []
160
178
  files:
161
179
  - CHANGELOG.md
162
180
  - README.md
181
+ - SECURITY_AND_QUALITY_AUDIT.md
163
182
  - lib/vert.rb
164
183
  - lib/vert/authorization/controller_methods.rb
165
184
  - lib/vert/authorization/dynamic_policy.rb
@@ -195,13 +214,14 @@ files:
195
214
  - lib/vert/rls/context_middleware.rb
196
215
  - lib/vert/rls/job_context.rb
197
216
  - lib/vert/version.rb
217
+ - lib/vert_core.rb
198
218
  - vert.gemspec
199
219
  homepage: https://github.com/edinaldo-novti/vert
200
220
  licenses:
201
221
  - MIT
202
222
  metadata:
203
223
  homepage_uri: https://github.com/edinaldo-novti/vert
204
- source_code_uri: https://github.com/edinaldo-novti/vert
224
+ source_code_uri: https://github.com/edinaldo-novti/vert/tree/main
205
225
  changelog_uri: https://github.com/edinaldo-novti/vert/blob/main/CHANGELOG.md
206
226
  rdoc_options: []
207
227
  require_paths: