feat: [TESIS-30] add integrations endpoints with encrypted credentials - #33
Open
TomasMartin2004 wants to merge 3 commits into
Open
feat: [TESIS-30] add integrations endpoints with encrypted credentials#33TomasMartin2004 wants to merge 3 commits into
TomasMartin2004 wants to merge 3 commits into
Conversation
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…oints Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…at rest Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Ticket de Jira
https://proyectofinalfrlp.atlassian.net/browse/TESIS-30
Descripción
Endpoints para que una empresa consulte el catálogo de servicios externos y administre sus credenciales de acceso, con cifrado at-rest de los tokens.
GET /api/v1/integrations— unifica el catálogo global (services) con el estado de integración de la empresa autenticada: cada fila incluyeservice_id,service_name,type,uri,http_method,configured,is_activeeintegration_id. Nunca devuelve credenciales (ni enteras ni parciales).PUT /api/v1/integrations/:service_id— upsert de la integración (crea si no existe, actualiza si existe) vía POROIntegrations::UpsertIntegration. Elcompany_idsale exclusivamente del JWT (current_user.company); cualquier valor en URL/body se ignora. Unservice_idinexistente responde 404.encrypts :credentials) en lugar de un cipher artesanal con OpenSSL — mismo algoritmo que pide la card, pero con el mecanismo battle-tested del framework (manejo de claves, IV y auth tag incluidos). Requirió migrar la columnacredentialsdejsonbatext(el ciphertext no es JSON) +serialize coder: JSONpara seguir operando con Hash en Ruby. Claves víaENCRYPTION_KEY/ENCRYPTION_KEY_DERIVATION_SALTcon fallback asecret_key_baseen dev/test.support_unencrypted_data = truepermite leer filas legacy en texto plano (p. ej. seeds previos) mientras todo lo nuevo se escribe cifrado.Decisiones/limitaciones:
downde la migración revierte el tipo de columna, pero filas ya cifradas no son casteables de vuelta ajsonb(documentado, esperable en cifrado at-rest).Evidencia visual
Cómo probar
bundle exec rails db:migratebundle exec rspec spec/requests/api/v1/integrations_spec.rb spec/poros/integrations/ spec/models/company_integration_spec.rbcurl -s -X POST http://localhost:3000/api/v1/auth/login -H "Content-Type: application/json" -d '{"email":"admin@norte.com","password":"password123"}'→ copiartoken.curl -s http://localhost:3000/api/v1/integrations -H "Authorization: Bearer <token>"→ catálogo con estado por servicio.curl -s -X PUT http://localhost:3000/api/v1/integrations/<service_id> -H "Authorization: Bearer <token>" -H "Content-Type: application/json" -d '{"credentials":{"access_token":"APP_USR-123"}}'→ 200, integración creada/actualizada.SELECT credentials FROM company_integrations;→ texto cifrado ilegible (no apareceAPP_USR-123).Impacto y consideraciones
¿Introduce breaking changes?
No en la API. La columna
credentialscambia dejsonbatextcifrado: cualquier query SQL directa sobre ese campo deja de poder inspeccionarlo (ese es el objetivo).¿Requiere nuevas variables de entorno?
Sí —
ENCRYPTION_KEYyENCRYPTION_KEY_DERIVATION_SALT(generar conrails secret). En dev/test caen por defecto asecret_key_base; en producción deben setearse explícitamente.¿Afecta la arquitectura o genera un nuevo patrón?
Sí — primer uso de ActiveRecord Encryption para datos sensibles; patrón a repetir para cualquier secreto futuro. No requiere ADR nuevo (decisión local al dominio integrations).