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
25 changes: 12 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -344,20 +344,15 @@ idempotencia y límites de PDF. No hay batch ni emisión como fallback.
## Integraciones SEP: un cliente y una credencial distintos

```go
import sepmodel "github.com/unkcode-org/gofip-sdk-go/v2/modelos/sep"

clienteSEP, err := gofip.NuevoClienteSEP(gofip.OpcionesClienteSEP{
ClaveIntegracion: os.Getenv("GOFIP_SEP_KEY"),
URLBase: os.Getenv("GOFIP_API_URL"), // obligatoria, sin valor por defecto
ClienteHTTP: &http.Client{Timeout: 15 * time.Second},
})
if err != nil { return err }
solicitud := sepmodel.SolicitudCrearSesionEmbedded{
Permisos: []sepmodel.PermisoEmbedded{sepmodel.PermisoFacturasLeer},
}
sesion, err := clienteSEP.CrearSesion(ctx, solicitud)
sesion, err := clienteSEP.CrearSesion(ctx)
// Ante una recuperación, solicitar un bootstrap nuevo:
bootstrap, err := clienteSEP.CrearBootstrap(ctx, solicitud)
bootstrap, err := clienteSEP.CrearBootstrap(ctx)
```

| Credencial | Cliente | Uso |
Expand All @@ -366,9 +361,8 @@ bootstrap, err := clienteSEP.CrearBootstrap(ctx, solicitud)
| `GOFIP_SEP_KEY` | `NuevoClienteSEP` | IntegrationKey; iniciar y recuperar acceso Embedded |

SEP envía exclusivamente `Authorization: IntegrationKey ...`, sin ambiente ARCA.
Crea requests `data` y decodifica responses `data`. Los permisos se validan contra
los doce valores de OpenAPI: no admite listas vacías, valores desconocidos ni
duplicados. Sólo el backend decide si caben dentro del techo autorizado.
Envía POST sin cuerpo y decodifica responses `data`. El backend carga todos los permisos
Embedded de la credencial autenticada; el consumidor no replica ni selecciona permisos.
`invoices:create` es un valor del enum y no agrega un endpoint de emisión Embedded.

`CrearSesion` devuelve URL de documento, vencimientos y bootstrap. Todavía no es
Expand Down Expand Up @@ -411,8 +405,13 @@ go test -race ./...
```

Ver [arquitectura](docs/arquitectura.md) y [validación manual](docs/validacion.md).
El contrato de referencia es OpenAPI 3.0.0 del backend. No se publica una versión
como parte de estas pruebas. La secuencia prevista es `v2.0.0-rc.1` → `v2.0.0`,
El contrato de referencia es OpenAPI 4.0.0 del backend. No se publica una versión
como parte de estas pruebas. El siguiente prerelease recomendado es `v2.0.0-rc.4` (breaking frente a rc.3),
con imports `/v2`, validación externa y aprobación de publicación.

SEP deriva el emisor exclusivamente de la Integration Key. CrearSesion y CrearBootstrap reciben solo permisos; la integración pertenece a un único emisor.
SEP deriva el emisor exclusivamente de la Integration Key. CrearSesion y CrearBootstrap no reciben cuerpo ni permisos. Ambas heredan todos los permisos Embedded de la credencial autenticada; la integración pertenece a un único emisor.

Cambio incompatible desde v2.0.0-rc.3: quitar SolicitudCrearSesionEmbedded y su lista Permisos.
La Integration Key configura la autorización en GOFIP; no replicar permisos en código ni variables de entorno.
Sin permisos configurados, ambas operaciones reciben 403. Las capacidades ya emitidas conservan su snapshot y TTL;
los cambios de permisos sólo afectan capacidades nuevas. No hay publicación/tag desde este cambio; siguiente prerelease sugerido v2.0.0-rc.4.
4 changes: 2 additions & 2 deletions contrato_importacion_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ func TestContratoImportacionYProcedenciaExacta(t *testing.T) {
t.Fatal(err)
}
hash := fmt.Sprintf("%x", sha256.Sum256(yaml))
if !strings.Contains(string(provenance), hash) || !strings.Contains(string(provenance), "Versión: 3.0.0.") {
if !strings.Contains(string(provenance), hash) || !strings.Contains(string(provenance), "Versión: 4.0.0.") {
t.Fatal("copia OpenAPI sin procedencia o checksum actualizado")
}
for _, token := range []string{`version: "3.0.0"`, "/api/v2/facturas/importaciones:", "mismo emisor y punto de venta", "emisor_id+credencial_id+punto_venta_id", "legacy_import", "SolicitudImportarFactura:", "RespuestaImportarFactura:", "DecimalHistorico:", "VerificacionImportacion:", "CompletitudDocumental:"} {
for _, token := range []string{`version: "4.0.0"`, "/api/v2/facturas/importaciones:", "mismo emisor y punto de venta", "emisor_id+credencial_id+punto_venta_id", "legacy_import", "SolicitudImportarFactura:", "RespuestaImportarFactura:", "DecimalHistorico:", "VerificacionImportacion:", "CompletitudDocumental:"} {
if !strings.Contains(string(yaml), token) {
t.Fatalf("contrato sin %s", token)
}
Expand Down
10 changes: 5 additions & 5 deletions docs/CONTRATO.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

- Repositorio canónico: unkcode-org/gofip-backend.
- Archivo: backend/docs/openapi.yaml.
- Versión: 3.0.0.
- Commit de implementación SEP en backend: 0fbb4e9f60b61eb2857b259b5766bbcec99d5a8b.
- Rama de revisión: codex/sep-emisor-directo.
- Base auditada de develop: dae24d3.
- SHA-256 de los bytes YAML copiados: b9580c0245564ce8cf3d11930b36650b8b6e8934b3910c492b4c9a5ae0557238.
- Versión: 4.0.0.
- Commit de implementación SEP en backend: 1fe864b7f451a96015d1d9bfa92020aa5c13f69b.
- Rama de revisión: codex/sep-permisos-por-credencial.
- Base auditada de develop: 02d3982.
- SHA-256 de los bytes YAML copiados: 9e22af0a501e7f39648100b9d10dfe043b778562eb45e172fc6f7de847337316.

La copia se verificó byte a byte después de estabilizar Backend/OpenAPI. Incluye
importación Legacy verificada en Producción y no agrega ambiente a documentos o
Expand Down
32 changes: 32 additions & 0 deletions docs/PLAN_SEP_PERMISOS_CREDENCIAL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Cambio SEP propuesto: permisos determinados por Integration Key

Fecha: 2026-10-18. Registro del plan previo, aprobado explícitamente por el usuario. Implementación completada; ver README y procedencia en CONTRATO.md.

Rama: `codex/sep-permisos-por-credencial`, creada desde `origin/main` actualizado (`bc407552513560fa921b4bc637bac416239f2e33`); no existe develop en este repositorio.

## Hallazgo

El SDK sólo expone SEP M2M mediante CrearSesion/CrearBootstrap. Antes del cambio ambas funciones recibían SolicitudCrearSesionEmbedded, validaban Permisos y serializaban `{"data":{"permissions":[...]}}`. No implementa administración SEP ni canje de navegador. El catálogo tiene doce permisos, incluido invoices:create; no existe invoices:write.

## API propuesta

```go
sesion, err := clienteSEP.CrearSesion(ctx)
bootstrap, err := clienteSEP.CrearBootstrap(ctx)
```

Eliminar DTO público vacío y validación de permisos del consumidor. El transporte enviará POST sin cuerpo; la clave configurada determina integración, emisor, credencial y todos sus permisos. Mantener tipos legítimos del catálogo y toda la seguridad de capacidades, redacción, no redirects, no cookies y no retry de POST. No agregar administración al SDK.

Actualizar modelos/cliente/transporte/tests/ejemplos/README, consumidor externo anidado y procedencia del OpenAPI. Contrato propuesto 4.0.0, mismo /api/v2, YAML idéntico byte a byte al backend/frontend. El YAML actual sigue en 3.0.0, SHA-256 b9580c0245564ce8cf3d11930b36650b8b6e8934b3910c492b4c9a5ae0557238.

La auditoría completa y el plan TDD están en backend/docs/AUDITORIA_SEP_PERMISOS_CREDENCIAL.md y backend/docs/PLAN_TDD_SEP_PERMISOS_CREDENCIAL.md del repositorio canónico gofip-backend. El frontend guarda también el plan en .harness/tasks/sep-permisos-por-credencial/tdd-test-plan.md. El usuario aprobó el plan antes de implementar.

## Versionado y Elixir

Propuesta de siguiente prerelease: v2.0.0-rc.4. Es incompatible a nivel de API Go con v2.0.0-rc.3, dentro de una serie prerelease; no crear tag ni release. Un SDK major estable requeriría respetar SemVer y evaluar v3 si correspondiera.

Elixir deberá actualizar posteriormente el SDK y quitar SolicitudCrearSesionEmbedded{Permisos: ...} en ambas llamadas. GOFIP_SEP_INTEGRATION_KEY basta; no agregar env vars para permisos. No se modifica Elixir en esta tarea.

## Verificación previa

`go test ./...` pasó sobre la base oficial. No incluye el módulo anidado integration/consumer. Race/vet, módulo externo, pruebas del contrato nuevo y validación completa se ejecutarán después de implementar. No se publicó ningún cambio.
Loading
Loading