Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ Cada operación es una subclase de `Operador` que se construye con métodos de c
| api / operaciones (RFC-003) | — | **n/a** — consumer-only, sin superficie HTTP/CLI/eventos propia |
| errores (RFC-020) | — | **n/a** — no define excepciones propias; propaga `Savon::*`/`JSON` (ver `consumed §d`) |
| eventos (RFC-005) | — | **n/a** — no produce eventos |
| seguridad (RFC-017) | | **n/a** — sin Pundit/Current; auth es la credencial de comercio (ver `consumed §a`) |
| seguridad (RFC-017) | [`docs/security/security.md`](docs/security/security.md) | **presente** — sin authz propia (§c/§d/§e n/a); superficie real = secrets-semántica §f (sanitización de logs sid+PII) + confianza §g (auth saliente al WS) |
| multi-tenancy (RFC-023) | — | **n/a** — el tenant es el `id_comercio` por llamada, no hay scoping server-side |
| data-lifecycle (RFC-026) | — | **n/a** — sin persistencia propia |
| release (RFC-014) | [`docs/release/release.md`](docs/release/release.md) | **presente** (estructural + §b deploy/rollback/ambientes/dueño) — publicación tag-driven a RubyGems vía `/gem-release` |
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ Detalle: [`docs/config/configuracion.md`](docs/config/configuracion.md).
| test | [`docs/test/testing.md`](docs/test/testing.md) | suite RSpec |
| comportamiento | [`docs/behavior/behavior.md`](docs/behavior/behavior.md) | flujos: operación simple · batch meta |
| glosario | [`docs/glossary/glossary.md`](docs/glossary/glossary.md) | términos del dominio (pagador, boleta, transacción…) |
| datos · api · errores · eventos · seguridad · multi-tenancy · data-lifecycle | n/a | ver Mapa de conocimiento en [`AGENTS.md`](AGENTS.md) |
| seguridad | [`docs/security/security.md`](docs/security/security.md) | secrets-semántica: sanitización de logs (sid + PII) y auth saliente al WS |
| datos · api · errores · eventos · multi-tenancy · data-lifecycle | n/a | ver Mapa de conocimiento en [`AGENTS.md`](AGENTS.md) |
| release | [`docs/release/release.md`](docs/release/release.md) | publicación a RubyGems tag-driven (`v*`) vía `/gem-release` |

## Uso
Expand Down
76 changes: 76 additions & 0 deletions docs/security/security.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# Seguridad — cobro_digital

> meta: artefacto · RFC-017 · generado arch-structure + arch-enrich · anclado a v1.9.0 · estructural (§a-§e) + §f secrets-semántica / §g confianza enriquecidos · NO contiene valores ni vulnerabilidades

## 1. Resumen

Gema cliente de un WS de pago. No tiene authn/authz propia (no recibe requests): su superficie de seguridad es **saliente** — autentica contra el WS de CobroDigital con la credencial de comercio (`id_comercio` + `sid`) y toma una decisión deliberada de **sanitización de logs** para no filtrar esa credencial ni la PII del pagador. Sin roles, policies, endpoints ni audit trail propios.

## 2. Seguridad

### §a Conteos (auth · roles · policies · secrets)

| dimensión | conteo | nota |
|---|---|---|
| mecanismos de auth | 1 | credencial de comercio (`id_comercio` + `sid`) por argumento, saliente |
| roles | 0 | sin RBAC |
| policies | 0 | sin Pundit/authorization |
| secrets manejados | 2 | `id_comercio`, `sid` (credencial del comercio; transitan, no se persisten) |

### §b Auth por dirección

| dirección | mecanismo | fuente | nota |
|---|---|---|---|
| entrante | n/a | — | la gema no expone superficie; no recibe requests autenticables |
| saliente (→ WS CobroDigital) | credencial de comercio `id_comercio` + `sid` | argumento de `#call(id_comercio, sid)` — NO env, NO archivo | el host custodia la credencial y la pasa por llamada (`lib/cobro_digital.rb:51`) |
| saliente — handshake | `MD5(Time.now)` por request | generado en cada request | identifica el request; se regenera automáticamente (ver `docs/behavior`) |

### §c Authz (roles · modelo · claims)

**Veredicto: n/a** — la gema no implementa modelo de autorización (sin roles, sin claims, sin Pundit/Current). La autorización efectiva la resuelve el WS de CobroDigital contra la credencial de comercio.

### §d Endpoint → authz

**Veredicto: n/a** — la gema no expone endpoints propios (RFC-003 `docs/api` = n/a). No hay mapeo endpoint→authz que documentar.

### §e Audit

**Veredicto: n/a** — la gema no mantiene audit trail propio. El logging del cliente SOAP (§f) es diagnóstico, no auditoría; su default no registra el body.

### §f Secrets-semántica (enrich)

> cobertura: 1/1 superficie de secrets enriquecida.

| aspecto | decisión | binding |
|---|---|---|
| custodia de credencial | `id_comercio`/`sid` se pasan por argumento en cada `#call`, **no** por env ni archivo de config → la gema no persiste ni cachea la credencial; el host es el custodio | `lib/cobro_digital.rb:51` · `consumed §a` |
| sanitización de log | `LOG_FILTERS = [:parametros_de_entrada]` → Savon enmascara el nodo SOAP con `sid` + PII del pagador como `***FILTERED***` en el log | `lib/cobro_digital.rb:35-36` |
| default seguro | `LOG_LEVEL` default `:error` (no loguea el body del request); configurable vía `ENV['COBRODIGITAL_LOG_LEVEL']` | `lib/cobro_digital.rb:26-31` |
| accessors sensibles | comentario explícito: no loguear `sid` ni `request_xml` (credencial + XML con sid + PII) | `lib/cobro_digital.rb:45-47` |
| failure-mode de seguridad | **`COBRODIGITAL_LOG_LEVEL=debug` en producción expone el `sid` en claro** en el XML formateado → no habilitar debug en prod | `lib/cobro_digital.rb:68-70` · `docs/config §f` |

### §g Confianza + zona de red (enrich)

> cobertura: 1/1 frontera enriquecida.

| frontera | zona | confianza |
|---|---|---|
| gema → WS CobroDigital (`cobro.digital:14365`) | saliente a internet (proveedor externo, no fleet) | transporte SOAP (default, vía `savon`) o HTTPS; la credencial de comercio viaja en el payload → depende del cifrado de transporte del endpoint |
| host → gema | in-process (misma VM Ruby) | el host inyecta la credencial por argumento; la gema confía en que el host la custodia de forma segura (fuera del alcance de la gema) |

## 3. Inferencias

| afirmación | confianza | a verificar |
|---|---|---|
| El cifrado en tránsito de la credencial depende del endpoint del comercio (`ENDPOINT_COBRODIGITAL`); la gema no fuerza TLS | inferido | confirmar que el endpoint de prod usa HTTPS/SOAP sobre TLS |
| El host es responsable de la custodia de `id_comercio`/`sid` (rotación, almacenamiento) | declarado | la gema solo los recibe por arg; la custodia es contrato del consumidor |
| `***FILTERED***` cubre el nodo `:parametros_de_entrada`; otros nodos con datos sensibles (si los hubiera) no estarían filtrados | inferido | confirmar que toda PII/credencial viaja solo en `:parametros_de_entrada` |

## 4. Cobertura y fronteras

- **§a/§b estructural + §f/§g enriquecidos:** cubiertos (la superficie real de la gema es secrets-semántica + frontera de confianza saliente).
- **§c/§d/§e `n/a`:** la gema no tiene authz/endpoints/audit propios — declarado con motivo, no es deuda.
- **Custodia de la credencial** (rotación, vault, almacenamiento del `sid`): **fuera de alcance** — es responsabilidad del host consumidor, no de la gema.
- **TLS/cifrado de transporte:** lo provee el endpoint del comercio, no la gema; queda fuera de su control.
- **NO contiene** valores reales de credenciales ni descripción de vulnerabilidades explotables (RFC-017 §3).
- **Frontera con config (RFC-012):** las env vars de log (`COBRODIGITAL_LOG_LEVEL`) viven en `docs/config §f`; acá se documenta su consecuencia de seguridad, no se redefine el inventario.
3 changes: 2 additions & 1 deletion skill/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ se pasan por argumento en cada `#call`, no por env.
| test | [`docs/test/testing.md`](../docs/test/testing.md) | RSpec (suite mínima) |
| comportamiento | [`docs/behavior/behavior.md`](../docs/behavior/behavior.md) | operación simple · batch meta |
| glosario | [`docs/glossary/glossary.md`](../docs/glossary/glossary.md) | términos del dominio |
| datos · api · errores · eventos · seguridad · multi-tenancy · data-lifecycle | — | n/a (ver Mapa de conocimiento en `AGENTS.md`) |
| seguridad | [`docs/security/security.md`](../docs/security/security.md) | secrets-semántica §f (sanitización logs sid+PII) + confianza §g (auth saliente) |
| datos · api · errores · eventos · multi-tenancy · data-lifecycle | — | n/a (ver Mapa de conocimiento en `AGENTS.md`) |
| release | [`docs/release/release.md`](../docs/release/release.md) | presente — publicación tag-driven a RubyGems vía `/gem-release` |

## Uso correcto / gotchas
Expand Down