¿Qué hace Endurecimiento de lanzamiento de paquetes npm?
Objetivo
Llevar un paquete npm de "funciona localmente" a "honesto, inspeccionable y seguro de publicar". Priorizar la verificación real sobre las sensaciones subjetivas: contenido del tarball del paquete, contrato de tiempo de ejecución, CI, configuración de GitHub e higiene de actualización de dependencias.
Comenzar aquí
- Confirmar el repositorio exacto:
pwd
git status --short --branch
git remote -v
- Inspeccionar la superficie del paquete:
cat package.json
ls -la
find .github -maxdepth 3 -type f -print 2>/dev/null
- Detectar el gestor de paquetes a partir de los archivos de bloqueo:
package-lock.json-> npmpnpm-lock.yaml-> pnpmyarn.lock-> yarn
Usar los comandos npm a continuación como valores predeterminados, pero traducir al gestor de paquetes detectado cuando sea necesario.
Contrato del paquete
Hacer que package.json diga la verdad:
name: el destino de publicación es intencional y está disponibleversion: la versión de publicación prevista actualdescription,keywords: lo suficientemente útiles para la búsqueda en el registrolicense: presente y coincide conLICENSErepository,homepage,bugs: apuntan al repositorio público. Si la URL del repositorio público aún no es definitiva, marcar estos como una tarea TODO previa a la publicación explícita en lugar de omitirlos silenciosamentetype,exports,main,bin: coinciden con lo que los usuarios importarán o ejecutaránfiles: limita el tarball a los artefactos publicablesengines.node: tiempo de ejecución mínimo que el paquete realmente admiteprepublishOnlyo equivalente: evita publicar resultados de compilación obsoletos
Para paquetes CLI, confirmar que el destino bin está compilado, es ejecutable cuando corresponda y se haya probado mediante el comando que los usuarios ejecutarán.
Regla del piso de tiempo de ejecución
El motor Node es una promesa, no un adorno.
- Si
engines.nodedice>=20, CI debe probar Node 20. - Mantener
@types/nodeen la misma línea principal que el tiempo de ejecución mínimo compatible. - Preferir fijar exactamente
@types/nodeal último parche en esa línea de tiempo de ejecución. - No fusionar aumentos principales de
@types/nodepor encima del piso de tiempo de ejecución a menos que también se subaengines.node. engines.nodees informativo: npm solo advierte y no bloquea la instalación a menos que el usuario establezcaengine-strict, por lo que CI en la versión de piso es lo que realmente hace cumplir la promesa.
Por qué: los tipos de Node son solo de desarrollo, pero cambian lo que TypeScript permite. @types/node@26 puede permitir que el código compile mientras usa APIs que fallan para usuarios en Node 20.
Comandos de verificación
Para proyectos npm:
npm ci
npm run build --if-present
npm test --if-present
npm audit --omit=dev
npm pack --dry-run
Para pnpm/yarn, usar los comandos equivalentes de instalación/compilación/prueba/auditoría/empaquetado. Si el soporte de auditoría difiere, decirlo en lugar de fingir.
Para CLI, también ejecutar al menos una prueba de humo externa:
node dist/path/to/cli.js --help
npm pack --dry-run
Si es práctico, instalar el .tgz empaquetado en un directorio temporal y ejecutar el binario exactamente como lo haría un usuario.
Revisión del tarball
npm pack --dry-run es la superficie de verdad del registro. Verificar:
- incluye la salida compilada
- incluye
README.mdyLICENSE - excluye solo basura fuente, archivos temporales, pruebas, documentos privados, fixtures, bases de datos locales, secretos
- el tamaño del paquete es razonable
- la ruta
binde CLI aparece en el tarball
Si falta files, agregarlo. No confiar en .gitignore como política de publicación.
Línea base de GitHub
Agregar o verificar:
.github/workflows/ci.yml.github/dependabot.yml.github/CODEOWNERS.github/pull_request_template.mdSECURITY.md
Usar las versiones principales compatibles actuales para las acciones propiedad de GitHub. Si Actions advierte que un tiempo de ejecución de acción está obsoleto, actualizar la acción principal después de que CI pase.
CI generalmente debe incluir:
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
test:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@CURRENT_MAJOR
- uses: actions/setup-node@CURRENT_MAJOR
with:
node-version: 20
cache: npm
- run: npm ci
- run: npm run build --if-present
- run: npm test --if-present
Ajustar node-version al tiempo de ejecución mínimo compatible del paquete y reemplazar cada @CURRENT_MAJOR con la etiqueta principal actual de la acción (por ejemplo, actions/checkout@v4) — fijar a una versión principal real, nunca confirmar el marcador de posición.
Línea base de Dependabot
Configurar tanto las actualizaciones del paquete como de las Acciones de GitHub:
version: 2
updates:
- package-ecosystem: npm
directory: /
schedule:
interval: weekly
open-pull-requests-limit: 5
commit-message:
prefix: deps
include: scope
- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
open-pull-requests-limit: 5
commit-message:
prefix: deps
include: scope
Cuando Dependabot abre PRs inmediatamente después de que la configuración aterrice, tratar eso como prueba de que la configuración está activa. Triar los PRs; no fusionar ciegamente todas las comprobaciones verdes.
Triaje de Dependabot
Usar esta regla general:
- Parche/menor de dependencia de tiempo de ejecución: fusionar si las comprobaciones pasan y las notas de la versión son aburridas.
- Mayor de dependencia de tiempo de ejecución: inspeccionar las notas de la versión y probar el comportamiento real del paquete.
- Mayor de herramienta de desarrollo: fusionar si la compilación/prueba/empaquetado pasan y no altera el contrato de tiempo de ejecución.
@types/nodepor encima del piso de tiempo de ejecución: cerrar o reemplazar con una fijación al piso de tiempo de ejecución.- Mayor de Acciones de GitHub: fusionar si CI pasa y elimina las advertencias de obsolescencia.
Si dos PRs entran en conflicto en un archivo de configuración pequeño, fusionar uno y actualizar el otro, o aplicar el segundo directamente con un comentario claro explicando que fue reemplazado.
Endurecimiento remoto de GitHub
Aplicar lo que el repositorio/cuenta admita, luego verificar la configuración real con gh o lecturas de API.
Configuraciones útiles:
gh repo edit OWNER/REPO \
--delete-branch-on-merge \
--enable-squash-merge \
--enable-merge-commit=false \
--enable-rebase-merge=false \
--allow-update-branch
gh api --method PUT repos/OWNER/REPO/vulnerability-alerts --silent
gh api --method PUT repos/OWNER/REPO/automated-security-fixes --silent
gh api --method PUT repos/OWNER/REPO/actions/permissions/workflow \
-f default_workflow_permissions=read \
-F can_approve_pull_request_reviews=false --silent
Para listas de permitidos de Actions, preferir solo acciones propiedad de GitHub cuando el flujo de trabajo use solo acciones propiedad de GitHub. Si se requieren acciones de terceros, permitir explícitamente el conjunto más pequeño.
Los repositorios públicos generalmente desbloquean más controles de seguridad. Los repositorios privados en planes gratuitos pueden bloquear:
- protección de rama o conjuntos de reglas
- escaneo de código
- escaneo de secretos
- protección de push
Señalar claramente los bloqueadores. No informar controles no disponibles como habilitados.
Protección de rama
Cuando esté disponible, proteger la rama predeterminada con:
- requerir pull request antes de fusionar
- requerir comprobaciones de estado de CI
- requerir que las ramas estén actualizadas si se ajusta al proyecto
- requerir resolución de conversación
- bloquear fuerzas de push
- bloquear eliminaciones
- requerir historial lineal si se usan fusiones solo squash
Después de habilitar la protección, dejar de hacer push directo a main a menos que el usuario lo solicite explícitamente y entienda la omisión.
Herramientas de PR con compuerta
Si se usa una herramienta de revisión/compuerta automatizada, asegurarse de que el remoto tenga una rama predeterminada/base antes de pedirle a la compuerta que cree un PR. Los nuevos remotos vacíos a menudo necesitan un push inicial a main primero; de lo contrario, la compuerta puede validar y hacer push a una rama de características pero fallar la creación del PR porque no hay una ref base.
Lista de verificación de publicación
Antes de npm publish:
npm whoamimuestra la cuenta previstanpm view PACKAGE_NAME name versionconfirma el estado del nombre- CI está verde en el commit que se está publicando
npm pack --dry-runha sido revisado- los ejemplos de instalación/uso de README coinciden con el comportamiento real
repository,homepageybugsresuelven al repositorio público real (o están marcados explícitamente como TODO si la URL no es definitiva)- no quedan alertas de seguridad/Dependabot que bloqueen el lanzamiento
- el aumento de versión es intencional, etiquetado en git (
git tag vX.Y.Z && git push --tags) y reflejado en un CHANGELOG o lanzamiento de GitHub - los paquetes con ámbito (
@scope/name) se publican con--access public(los paquetes con ámbito son privados/restringidos por defecto)
Para cuentas que usan autenticación web/passkey/2FA:
npm publish --auth-type=web
Preferir publicar desde CI con procedencia para un enlace verificable de la cadena de suministro. La procedencia requiere un paquete público, un CI compatible como GitHub Actions y el permiso id-token: write en el trabajo:
npm publish --provenance --access public
Después de publicar:
npm view PACKAGE_NAME version
npm view PACKAGE_NAME bin files engines repository --json
npx -y PACKAGE_NAME --help
Si se publicó con procedencia, confirmar que el registro muestra la atestación de procedencia / "Built and signed" en la página del paquete.
Respuesta final
Informar solo lo que realmente se verificó:
- comprobaciones del paquete ejecutadas
- resultado del tarball
- decisiones sobre PRs de dependencias
- commits/PRs creados o fusionados
- configuración de GitHub confirmada
- controles bloqueados por plan/visibilidad
- etiqueta de lanzamiento y estado de procedencia, si se publicó
- comando de publicación o verificación posterior a la publicación si aún es propiedad del usuario