# Publicación segura de netpay3ds

Este paquete ya existe públicamente en `https://registry.npmjs.org/` con el
nombre `netpay3ds`. No cambies el nombre ni publiques variantes por versión de
Angular.

## Preflight local

Desde `netpay-3ds-lib`:

```bash
nvm use
npm ci
npm run test:coverage
npm run release:dry-run
npm run release:validate:technical
```

El dry-run crea `artifacts/netpay3ds-<version>.tgz`, su SHA-256 y SBOM,
inspecciona el contenido y simula todos los tags requeridos por el plan. Para
1.0.1 ejecuta dry-run tanto con `latest` como con `legacy` mientras no exista
2.x estable. No publica.

## Artefacto inmutable

El `package.json` de la raíz Angular es un workspace privado
(`netpay-3ds@0.0.0`) y nunca es el paquete publicable. El manifest público es
`projects/netpay3ds/package.json`; no ejecutes `npm publish` sin pasar la ruta
del tarball validado.

El pipeline construye una sola vez con Angular 13 y entrega `dist/netpay3ds`
al job de packaging. Ese job genera el `.tgz`, su sidecar `.sha256` y el SBOM.
Todos los consumer tests, verificadores y dry-runs utilizan ese mismo archivo.
`netpay-3ds-sample` instala también ese `.tgz` y ejecuta build, smoke y mocks
funcionales antes de habilitar publicación.

El job de publicación descarga el artifact, vuelve a verificar checksum,
contenido, versión y tag, y publica exactamente el mismo `.tgz`. No ejecuta
`npm ci`, no instala dependencias Angular, no reconstruye y no recompila.

El flujo tiene responsabilidades separadas:

```text
package_library
  -> verify_readme               # README real dentro del tarball
  -> verify_publish              # checksum/package/README/SBOM + npm dry-run
  -> publish_npm                 # único npm publish real
  -> verify_npm_publication      # versión pública + primary dist-tag
```

Un push a `release/1.x`, `main` o un merge request llega hasta
`verify_publish`, pero nunca crea los dos jobs posteriores.

## Matriz de consumidores

El paquete 1.x se construye siempre con Angular 13, pero su tarball final debe
instalar y compilar en consumers Angular 13.2–21. Los fixtures se generan en un
directorio temporal, importan desde `netpay3ds` y nunca usan `npm link`,
`--force` o `--legacy-peer-deps`.

| Angular | Node | RxJS | Resultado esperado |
| ---: | ---: | ---: | --- |
| 13–14 | 16.20.2 | 7.5.7 | PASS |
| 15 | 18.20.8 | 7.5.7 | PASS |
| 16 | 18.20.8 | 7.8.2 | PASS |
| 17–21 | 20.19.5 | 7.8.2 | PASS |
| 22 | 24.18.0 | 7.8.2 | FAIL_INSTALL controlado con el manifest final |

La exploración Angular 13–22 usa exclusivamente un tarball `private` marcado
`TEST-ONLY`. Después se genera el tarball final con peers `>=13.2.0 <22.0.0`,
se repite 13–21 y se comprueba que Angular 22 sea rechazado por npm. El job de
publicación depende de la matriz completa y de esta prueba negativa.

Terminología de aprobación:

- **Package compatibility validated:** instalación, peer resolution, linker,
  build y API aprobados para Angular 13.2–21.
- **Official sample validation:** build, arranque y mocks funcionales del
  consumer Angular `netpay-3ds-sample`.
- **External environment validation:** Sandbox real y rollout posterior en
  `hosted-checkout`; no bloquean la preparación técnica reproducible.
- **Official support:** decisión corporativa separada; 1.x permanece
  Maintenance / Legacy con EOL TBD.

## Cambio de versión

La versión publicable vive en `projects/netpay3ds/package.json`. Usa el comando
estándar para mantener sincronizado su lockfile:

```bash
cd projects/netpay3ds
npm version 1.0.1 --no-git-tag-version
cd ../..
```

Actualiza también `CHANGELOG.md`, ejecuta las validaciones, crea un commit y
sólo después crea el tag Git exacto, por ejemplo `v1.0.1`. El pipeline rechaza
un tag que no coincida con la versión del tarball o una versión ya existente.

## Política automática y eras

El pipeline consulta `npm view netpay3ds versions --json` y falla si el registro
no puede responder. No interpreta una falla de red como ausencia de 2.x.

| Condición | Tag de publicación | Tag adicional |
| --- | --- | --- |
| 1.x y aún no existe 2.x estable | `latest` | `legacy` |
| 1.x y ya existe 2.x estable | `legacy` | ninguno |
| 2.x prerelease | `next` | ninguno |
| 2.x estable | `latest` | ninguno |

`publishConfig` no fija un tag. El algoritmo está probado por
`npm run verify:release-policy` y bloquea que 1.x mueva `latest` después de una
2.x estable.

## Patch documental 1.0.1

`netpay3ds@1.0.0` se publicó el 18 de agosto de 2026 y es inmutable. La
restauración del README se prepara como 1.0.1 y la publica exclusivamente
`publish_npm` con el tarball validado y el primary tag calculado:

```bash
npm publish artifacts/netpay3ds-1.0.1.tgz \
  --tag latest \
  --access public \
  --registry=https://registry.npmjs.org/
```

Después un maintainer autenticado agrega el alias legacy:

```bash
npm dist-tag add netpay3ds@1.0.1 legacy --otp=<OTP>
npm dist-tag ls netpay3ds
```

No se vuelve a compilar ni a publicar el paquete para agregar `legacy`.

No se elimina, sobrescribe ni reutiliza 1.0.0. El tag nuevo debe ser `v1.0.1` y
debe crearse sólo después de revisar, aprobar y fusionar esta corrección.

## Trusted Publishing

Configura en npmjs.com un Trusted Publisher para este proyecto GitLab y permite
`npm publish` sólo desde tags protegidos. La configuración incluida solicita un
`NPM_ID_TOKEN` con audience `npm:registry.npmjs.org` y un
`SIGSTORE_ID_TOKEN` con audience `sigstore`. Publica con Node 22.14.0 y npm
11.5.1, sin almacenar tokens.

Configuración exacta del Trusted Publisher:

```text
Provider: GitLab CI/CD
Namespace: netpaymx/ecommerce
Project: netpay-3ds
Top-level CI file: .gitlab-ci.yml
Environment: npm-production
Allowed action: npm publish
```

Con npm 11.15.0 o posterior, un maintainer autenticado puede revisar y aplicar
esa relación mediante:

```bash
npm trust gitlab netpay3ds \
  --project netpaymx/ecommerce/netpay-3ds \
  --file .gitlab-ci.yml \
  --environment npm-production \
  --allow-publish \
  --dry-run

# Sólo después de revisar el dry-run:
npm trust gitlab netpay3ds \
  --project netpaymx/ecommerce/netpay-3ds \
  --file .gitlab-ci.yml \
  --environment npm-production \
  --allow-publish
```

Trusted Publishing requiere un runner compartido de GitLab.com. Si el proyecto
usa un runner self-hosted, la alternativa preferida es publicación manual por
un maintainer con 2FA. Un token granular, con alcance sólo a `netpay3ds`,
expiración y variable protected/masked, es el último recurso.

OIDC de npm autentica `npm publish`, pero no `npm dist-tag add`. Por ello, el
pipeline genera `release-plan.json` y publica el tag principal; cualquier tag
adicional se completa con autenticación npm tradicional y 2FA. No se almacena
un token sólo para ocultar esta limitación.

Estado para el patch 1.0.1:

```text
GitLab.com: confirmed
Runner type: GitLab.com shared SaaS Linux runner (confirmed in CI metadata)
Trusted Publisher: pending
```

Los patrones `v1.*`/`v2.*` y el environment `npm-production` deben estar
protegidos en GitLab. `NPM_TRUSTED_PUBLISHING_APPROVED=true` sólo debe
establecerse después de confirmar la relación de confianza en npm. El job sigue
apareciendo para un tag SemVer cuando falta esa aprobación y falla con un
mensaje explícito; no permite que el pipeline quede verde sin publicar.

Si OIDC no está disponible, el fallback es un maintainer npm autorizado con
2FA. Un granular access token de alcance mínimo sólo puede utilizarse si la
política corporativa lo permite; nunca se guardan tokens en el repositorio y
no se permiten tokens legacy.

Staged publishing es una mejora futura opcional: CI podría ejecutar
`npm stage publish` y un maintainer revisar/aprobar después con 2FA. Antes de
adoptarlo se debe usar, como mínimo, npm 11.15.0 y Node.js 22.14.0, además de
validar permisos y política corporativa. No bloquea 1.0.1 ni sustituye el flujo
actual.

## Gates externos obligatorios

- Conservar la licencia MIT incluida en el tarball y `license: MIT` en el
  manifest. Su presencia es un gate técnico verificable.
- Proteger los tags `v1.*` y `v2.*` y limitar quién puede crearlos.
- Configurar `SONAR_HOST_URL`, `SONAR_TOKEN` y `SONAR_PROJECT_KEY` para ejecutar
  el Quality Gate.
- Proteger el environment `npm-production` y exigir su aprobación cuando la
  edición de GitLab lo permita.
- Configurar `NPM_TRUSTED_PUBLISHING_APPROVED`, `NPM_PUBLISH_APPROVED` y
  `RELEASE_OWNER_APPROVED` como variables protected; para 1.x también
  `ANGULAR13_RISK_ACCEPTED`.
- Obtener aceptación formal del riesgo del toolchain Angular 13 descrito en
  `SECURITY.md`.
- Completar los gates corporativos de publicación aplicables. Checkout Plus no
  consume este paquete Angular y no forma parte del release gate.

La validación se divide explícitamente:

```bash
npm run release:validate:technical
npm run release:validate:publish -- artifacts/netpay3ds-1.0.1.tgz v1.0.1
```

La primera no requiere credenciales administrativas. La segunda valida el tag,
que la versión no exista, el mecanismo npm, release owner, aceptación del
riesgo legacy y las aprobaciones de ambiente aplicables. Sonar y Secret
Detection son jobs obligatorios del mismo DAG; no se duplican como booleanos.

## Verificación posterior

```bash
npm view netpay3ds version dist-tags maintainers --json
npm view netpay3ds@1.0.1 version
npm dist-tag ls netpay3ds
npm install netpay3ds
npm install netpay3ds@legacy
```

Antes de 2.x estable ambos comandos instalan 1.x. Después, la instalación sin
tag usa 2.x y `@legacy` conserva la línea 1.x. Para probar la Fase 2 se usa
`@next`; un RC nunca mueve `latest`.

## Plan de reversa

No se sobrescribe ni se vuelve a publicar una versión existente. Cada
corrección posterior incrementa PATCH y repite todo el release gate.

- **npm/dist-tag:** un maintainer puede mover temporalmente `latest` a una
  versión aprobada anterior y conservar `legacy`, únicamente con autorización
  y 2FA. No se automatiza este movimiento.
- **Aplicación:** cada consumer debe conservar su lockfile/artefacto anterior,
  procedimiento de redeploy y responsable de rollback.
- **CDN/package:** si algún producto replica el paquete en CDN o repositorio
  interno, debe restaurar el artefacto inmutable aprobado anterior y purgar
  caches según su runbook.

Todo rollback debe registrar motivo, versión, dist-tags antes/después,
consumidores afectados y autorización.
