feat: schemas Maraca revisitados e extendidos - #149
Conversation
|
@coderabbitai summary |
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. WalkthroughEste PR adiciona o serviço Maraca com autenticação, autorização e isolamento por Tekoa: novos módulos e tabelas para Permissions e AccessRequests; amplia Taina.Maraca.Ava com campos e fluxos de convite/confirmação/reset (hash de senha, tokens, invited_by); converte public_id para um tipo PublicId autogerado; atualiza Taina.Maraca.Tekoa para cotas em bytes; adiciona Taina.Repo.PublicId, helpers de Repo ( Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related issues
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 10
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
lib/taina/maraca/tekoa.ex (1)
11-15: Docs e exemplo ainda referemstorage_quota_gbA documentação e o exemplo seguem no formato antigo. Que tal atualizar para
storage_quota_bytespara manter o contexto limpo?✏️ Sugestão de ajuste
- * `storage_quota_gb` - Limite de armazenamento em gigabytes + * `storage_quota_bytes` - Limite de armazenamento em bytes - iex> changeset(%Tekoa{}, %{name: "Minha Comunidade", storage_quota: 500}) + iex> changeset(%Tekoa{}, %{name: "Minha Comunidade", storage_quota_bytes: 500 * 1024 * 1024 * 1024})Also applies to: 45-45
priv/repo/migrations/20251007182041_create_maraca_schema.exs (1)
7-13: Quotas semdefault/NOT NULLComo o changeset exige
storage_quota_bytesestorage_used_bytesassume 0, o DB aceitar NULLs pode gerar inconsistências em consultas e políticas. Faz sentido alinhar o schema?🧩 Sugestão de ajuste
- add :storage_quota_bytes, :bigint - add :storage_used_bytes, :bigint + add :storage_quota_bytes, :bigint, null: false + add :storage_used_bytes, :bigint, null: false, default: 0
🤖 Fix all issues with AI agents
In `@lib/taina/maraca/access_request.ex`:
- Around line 118-123: O atual changeset(%__MODULE__{} = request, %{} = attrs)
permite que o requester forneça :status; add um novo creation-specific changeset
(e.g., create_changeset/2) that does not cast or validate :status and instead
sets status to :pending via put_change(request, :status, "pending") (or :pending
atom if code uses atoms), reuse the same
cast/validate_length/validate_different_avas logic, and keep the existing
changeset/2 for updates/decisions where :status may be allowed; update callers
that create requests to use create_changeset/2.
In `@lib/taina/maraca/ava.ex`:
- Around line 154-163: The invitation_changeset (and the other places that set
reset_token/email_confirmation_token) currently store raw tokens in the DB;
instead generate a random raw token (using generate_token()), compute a secure
hash (e.g., SHA256 or bcrypt) of that raw token, store only the hash in the DB
(use a field like email_confirmation_token_hash or reset_token_hash via
put_change), and return or pass the raw token only to the caller that sends the
email; update the corresponding reset token generation sites (the code around
the other token puts at the referenced locations) to follow the same pattern and
update any verification logic to compare the hash of the presented token to the
stored hash (using a constant-time compare).
In `@lib/taina/maraca/permission.ex`:
- Around line 104-108: Remova granted_by_id e tekoa_id dos campos aceitos pelo
cast/validate_required dentro da função changeset/2 (evitando que fields
derivados de contexto sejam settados via params) e deixe apenas [:resource_id,
:resource_type, :action, :ava_id] ali; em vez disso, garanta que o service que
chama Permission.changeset (ou a função que cria a permission) atribua
explicitamente permission.granted_by_id e permission.tekoa_id antes de persistir
para evitar spoofing e preservar rastreabilidade.
- Around line 84-88: The changeset currently documents uniqueness of (ava_id,
resource_type, resource_id, action) but doesn't call unique_constraint; update
the changeset function (changeset/2) in permission.ex to add a
unique_constraint/3 for that DB constraint (pick a relevant field like :action
or :resource_id as the target) with name set to the actual DB constraint/index
name from your migration and an appropriate message option; ensure the
constraint name matches the migration so the changeset returns a friendly error
when the combination already exists.
In `@lib/taina/maraca/README.md`:
- Line 55: The README links for "Guia de Contribuição" and "Código de Conduta"
currently point to the tekoa repository; confirm whether this is intentional
and, if not, update the two URLs in lib/taina/maraca/README.md so they reference
the corresponding CONTRIBUTING.md and CODE_OF_CONDUCT.md in the Tainá repository
(replace the existing https://github.com/taina-labs/tekoa/... links with the
correct Tainá repo URLs or local relative paths), ensuring link text remains the
same.
In `@lib/taina/repo.ex`:
- Around line 124-202: The Taina.Repo.PublicId module is declared alongside
other modules in the same file; move it to its own file to follow the
single-module-per-file guideline by creating lib/taina/repo/public_id.ex
containing the defmodule Taina.Repo.PublicId with its use Ecto.Type, callbacks
(type/0, cast/1, load/1, dump/1, autogenerate/0) and Nanoid.generate(12) logic;
update any references/imports if necessary and remove the duplicated module
definition from the original file so only one module definition remains per
file.
- Around line 64-73: O uso de transact/1 em with_tekoa/2 não existe em Ecto.Repo
e quebrará a compilação; replace ou implement wrapper: change the call in
with_tekoa (the transact(fn -> ... end) block that runs SQL.query! and cb.()) to
Ecto's transaction/1 (i.e., transaction(fn -> ... end)) or add a private
transact/1 that delegates to transaction/1 to preserve existing API — update the
call site in with_tekoa to use that chosen approach.
- Around line 36-52: The docs and behavior mismatch: with_tekoa/2 sets
app.current_tekoa_id (used by RLS) so it must receive the Tekoa.public_id
(string), not the numeric database id; update the examples to call
Repo.with_tekoa(tekoa.public_id, ...) and clarify the docs that the function
expects the public_id (String.Chars). Optionally harden Repo.with_tekoa/2: if
the first arg is an integer or a Tekoa struct, resolve the public_id (e.g.,
fetch Tekoa by id or read struct.public_id) before setting the context so
callers can pass id/structs transparently; keep the function name with_tekoa/2
and ensure it always assigns the public_id to the current_setting used by RLS.
In `@lib/taina/ybira.ex`:
- Line 11: Remova o código comentado e as declarações não utilizadas para
reduzir ruído: elimine a atribuição comentada `@root_path` e remova o
cálculo/atributo relacionado a mime_type (ou converta em
configuração/funcionalidade real se necessário) dentro do módulo Ybira para
evitar código morto; se o valor for necessário, mova para
Application.get_env/uma função pública (por exemplo mantendo nome
mime_type/@root_path) para uso explícito, caso contrário delete-os completamente
e rode mix compile para garantir que não restem warnings de variável não usada.
In `@priv/repo/migrations/20251007182041_create_maraca_schema.exs`:
- Around line 79-84: The access_requests table defines the :status column
without a default or NOT NULL, while business logic assumes a default of
"pending"; update the migration that creates table(:access_requests, prefix:
"maraca") so the add :status column includes null: false and a default of
"pending" (e.g., add :status, :string, null: false, default: "pending") to
enforce the domain rule at the DB level and keep multi‑tenancy behavior
deterministic.
✅ Actions performedSummary regeneration triggered. |
|
@coderabbitai summary |
✅ Actions performedSummary regeneration triggered. |
There was a problem hiding this comment.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
lib/taina/ybira/file.ex (1)
117-126: Typo crítico::filehashdeveria ser:file_hashParece que há um erro de digitação na linha 121: o campo declarado no schema é
:file_hash(linha 59), mas novalidate_requiredestá:filehash. Isso fará com que o changeset sempre seja inválido, pois o Ecto não encontrará o campo esperado.🐛 Correção sugerida
|> validate_required([ :filename, :original_filename, :filepath, - :filehash, + :file_hash, :mime_type, :file_size_bytes, :ava_id, :tekoa_id ])lib/taina/ybira/folder.ex (1)
67-76: Inconsistência entre schema e changeset::parent_idvs:folder_idO schema na linha 45 define
belongs_to :folder, __MODULE__, que gera automaticamente o campo:folder_id. Porém, o changeset usa:parent_idnocast(linha 69) e noforeign_key_constraint(linha 74). Isso causará problemas, pois o campo:parent_idnão existe no schema.Será que a intenção era usar
:folder_idconsistentemente, ou seria interessante renomear a associação parabelongs_to :parent, __MODULE__?🐛 Opção 1: Usar :folder_id (alinhado ao schema atual)
def changeset(folder, attrs) do folder - |> cast(attrs, [:name, :public_id, :ava_id, :tekoa_id, :parent_id]) + |> cast(attrs, [:name, :public_id, :ava_id, :tekoa_id, :folder_id]) |> validate_required([:name, :ava_id, :tekoa_id]) |> validate_length(:name, min: 1, max: 255) |> foreign_key_constraint(:ava_id) |> foreign_key_constraint(:tekoa_id) - |> foreign_key_constraint(:parent_id) + |> foreign_key_constraint(:folder_id) |> unique_constraint(:public_id) end🐛 Opção 2: Renomear associação para :parent (semântica mais clara)
- belongs_to :folder, __MODULE__ + belongs_to :parent, __MODULE__E atualizar o tipo
t()para usar:parent_ide:parentao invés de:folder_ide:folder.
🤖 Fix all issues with AI agents
In `@lib/taina/maraca/permission.ex`:
- Around line 161-169: Add a helper in the Permission module named
prepare_for_insert(changeset) that validates the context fields not present in
cast/params (validate_required for :granted_by_id and :tekoa_id) and document
it; keep the existing changeset/2 as-is, and update callers to call
Permission.changeset(attrs) → Ecto.Changeset.put_change(:granted_by_id, ...) /
put_change(:tekoa_id, ...) → Permission.prepare_for_insert() before Repo.insert
so the presence of granted_by_id and tekoa_id is enforced.
In `@lib/taina/maraca/tekoa.ex`:
- Around line 56-62: Update the documentation examples in the Tekoa module so
they use the new storage_quota_bytes field instead of storage_quota: change the
sample call to changeset(%Tekoa{}, %{name: "Minha Comunidade",
storage_quota_bytes: 5_368_709_120}) (or another appropriate byte value like
5_000_000_000) and keep the invalid-name example as-is; this touches the
examples around the changeset/0 usage in the Tekoa module.
In `@priv/repo/migrations/20251007182041_create_maraca_schema.exs`:
- Around line 69-72: Add a database index on the permissions.tekoa_id column to
speed up RLS-filtered queries: after the permissions table definition where you
add :tekoa_id, add a create index for :permissions on [:tekoa_id] using the same
schema prefix "maraca" (i.e., create index(:permissions, [:tekoa_id], prefix:
"maraca")). This ensures queries filtering by current_tekoa_id under RLS use the
index for better performance.
- Around line 86-89: Add a B-tree index on access_requests.tekoa_id to speed up
RLS/organization filtering: inside the migration where access_requests is
created (after the add :tekoa_id line and before or after timestamps()), add
create index(:access_requests, [:tekoa_id], prefix: "maraca") to create the
index in the maraca schema; ensure the name/arguments match other indices in
this migration if you need consistent naming.
- Around line 60-77: O esquema da tabela permissions define resource_type,
resource_id e action como nullable apesar de fazerem parte do índice único
permissions_unique_grant; atualize a migração alterando as definições em create
table(:permissions, ...) para adicionar null: false em resource_type,
resource_id e action (ou, se desejar permitir NULLs deliberadamente, documente e
use um índice parcial), garantindo que a constraint única em
permissions_unique_grant funcione como esperado; localize as chamadas add
:resource_type, :resource_id, :action na definição da tabela e torne-as
non-null.
♻️ Duplicate comments (1)
priv/repo/migrations/20251007182041_create_maraca_schema.exs (1)
83-83:statusainda semnull: falseO campo
statusaparece sem a constraintnull: falseque foi discutida anteriormente. Conforme o alinhamento no review passado (default:pendingno changeset, restrição estrutural no banco), a migração deveria ter:add :status, :string, null: false
Problem
O PR adiciona suporte a autenticação (convites, confirmação por email e reset de senha), um modelo explícito de permissões e um fluxo de requisição de acesso, além de tornar o isolamento por organização (RLS) aplicável a novas tabelas. O repositório carecia desses schemas e políticas para gerenciar acesso, segurança e isolamento de dados a nível de tekoa/organização.
Solution
Rationale
Problema
Maraca não tinha suporte completo para autenticação (convites, confirmação por email, reset de senha), nem um modelo explícito de permissões e falta de isolamento por organização (tekoa) no banco, dificultando segurança, auditoria e multi-tenancy.
Solução
Adiciona autenticação e autorização completas ao Maraca:
Explicação
A implementação centraliza autenticação em Ava para fluxos unificados (convite, confirmação, reset), torna permissões explícitas e auditáveis (granted_by + constraint única), adota PublicId e quotas em bytes para interoperabilidade entre serviços, e aplica isolamento robusto combinando RLS no banco com Repo.with_tekoa/2 no app — reduzindo risco de vazamento entre organizações. Tokens são armazenados como hashes e senhas são bcryptadas para minimizar exposição em caso de comprometimento.