Skip to content

feat: [TESIS-30] add integrations endpoints with encrypted credentials - #33

Open
TomasMartin2004 wants to merge 3 commits into
masterfrom
TESIS-30-integrations-endpoints
Open

feat: [TESIS-30] add integrations endpoints with encrypted credentials#33
TomasMartin2004 wants to merge 3 commits into
masterfrom
TESIS-30-integrations-endpoints

Conversation

@TomasMartin2004

@TomasMartin2004 TomasMartin2004 commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

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 incluye service_id, service_name, type, uri, http_method, configured, is_active e integration_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 PORO Integrations::UpsertIntegration. El company_id sale exclusivamente del JWT (current_user.company); cualquier valor en URL/body se ignora. Un service_id inexistente responde 404.
  • Cifrado (AES-256-GCM): se usa ActiveRecord Encryption nativo de Rails (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 columna credentials de jsonb a text (el ciphertext no es JSON) + serialize coder: JSON para seguir operando con Hash en Ruby. Claves vía ENCRYPTION_KEY / ENCRYPTION_KEY_DERIVATION_SALT con fallback a secret_key_base en dev/test. support_unencrypted_data = true permite leer filas legacy en texto plano (p. ej. seeds previos) mientras todo lo nuevo se escribe cifrado.

Decisiones/limitaciones:

  • Sin Pundit en esta card: no existen roles todavía; la autorización real es el aislamiento por tenant (queda para cuando se introduzcan roles).
  • El down de la migración revierte el tipo de columna, pero filas ya cifradas no son casteables de vuelta a jsonb (documentado, esperable en cifrado at-rest).

Evidencia visual

image image image

Cómo probar

  1. bundle exec rails db:migrate
  2. bundle exec rspec spec/requests/api/v1/integrations_spec.rb spec/poros/integrations/ spec/models/company_integration_spec.rb
  3. Manual:
    • Login: curl -s -X POST http://localhost:3000/api/v1/auth/login -H "Content-Type: application/json" -d '{"email":"admin@norte.com","password":"password123"}' → copiar token.
    • 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.
    • En psql: SELECT credentials FROM company_integrations; → texto cifrado ilegible (no aparece APP_USR-123).

Impacto y consideraciones

¿Introduce breaking changes?
No en la API. La columna credentials cambia de jsonb a text cifrado: cualquier query SQL directa sobre ese campo deja de poder inspeccionarlo (ese es el objetivo).

¿Requiere nuevas variables de entorno?
Sí — ENCRYPTION_KEY y ENCRYPTION_KEY_DERIVATION_SALT (generar con rails secret). En dev/test caen por defecto a secret_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).


TomasMartin2004 and others added 3 commits July 9, 2026 20:12
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants