Härtung von npm-Paketveröffentlichungen
Ziel
Ein npm-Paket vom Status "funktioniert lokal" zu "ehrlich, überprüfbar und sicher zu veröffentlichen" bringen. Priorisieren Sie echte Überprüfung gegenüber Bauchgefühl: Paket-Tarball-Inhalte, Laufzeitvertrag, CI, GitHub-Einstellungen und Sauberkeit der Abhängigkeitsaktualisierungen.
Los geht's
- Bestätigen Sie das exakte Repository:
pwd
git status --short --branch
git remote -v
- Überprüfen Sie die Paketoberfläche:
cat package.json
ls -la
find .github -maxdepth 3 -type f -print 2>/dev/null
- Erkennen Sie den Paketmanager anhand der Lockfiles:
package-lock.json-> npmpnpm-lock.yaml-> pnpmyarn.lock-> yarn
Verwenden Sie untenstehende npm-Befehle als Standard, übersetzen Sie sie aber bei Bedarf in den erkannten Paketmanager.
Paketvertrag
Stellen Sie sicher, dass package.json die Wahrheit sagt:
name: Das Veröffentlichungsziel ist beabsichtigt und verfügbarversion: Aktuelle, beabsichtigte Veröffentlichungsversiondescription,keywords: Nützlich genug für die Registrierungssuchelicense: Vorhanden und stimmt mitLICENSEübereinrepository,homepage,bugs: Zeigen auf das öffentliche Repository. Wenn die öffentliche Repository-URL noch nicht endgültig ist, markieren Sie diese explizit als TODO vor der Veröffentlichung, anstatt sie stillschweigend wegzulassentype,exports,main,bin: Stimmen mit dem überein, was Benutzer importieren oder ausführen werdenfiles: Begrenzt den Tarball auf veröffentlichbare Artefakteengines.node: Minimale Laufzeit, die das Paket tatsächlich unterstütztprepublishOnlyoder Äquivalent: Verhindert die Veröffentlichung von veraltetem Build-Output
Bestätigen Sie bei CLI-Paketen, dass das bin-Ziel gebaut, gegebenenfalls ausführbar und durch den Befehl, den Benutzer ausführen werden, rauchgetestet ist.
Laufzeit-Boden-Regel
Die Node-Engine ist ein Versprechen, keine Dekoration.
- Wenn
engines.node>=20sagt, muss CI Node 20 testen. - Halten Sie
@types/nodeauf der gleichen Hauptversionszeile wie die minimale unterstützte Laufzeit. - Bevorzugen Sie exaktes Pinnen von
@types/nodeauf den neuesten Patch auf dieser Laufzeitzeile. - Führen Sie keine Hauptversionssprünge von
@types/nodeüber den Laufzeit-Boden hinaus zusammen, es sei denn, Sie erhöhen auchengines.node. engines.nodeist beratend: npm warnt nur und blockiert die Installation nicht hart, es sei denn, der Benutzer setztengine-strict, daher setzt CI auf der Bodenversion das Versprechen tatsächlich durch.
Warum: Node-Typen sind reine Entwicklungsabhängigkeiten, aber sie ändern, was TypeScript erlaubt. @types/node@26 kann Code kompilieren lassen, der APIs verwendet, die für Benutzer auf Node 20 fehlschlagen.
Verifikationsbefehle
Für npm-Projekte:
npm ci
npm run build --if-present
npm test --if-present
npm audit --omit=dev
npm pack --dry-run
Verwenden Sie für pnpm/yarn die entsprechenden Install-/Build-/Test-/Audit-/Pack-Befehle. Wenn sich die Audit-Unterstützung unterscheidet, sagen Sie dies, anstatt so zu tun, als wäre sie gleich.
Führen Sie für CLIs auch mindestens einen Outside-In-Rauchtest durch:
node dist/path/to/cli.js --help
npm pack --dry-run
Installieren Sie, wenn praktikabel, das gepackte .tgz in einem temporären Verzeichnis und führen Sie die Binärdatei genau so aus, wie es ein Benutzer tun würde.
Tarball-Überprüfung
npm pack --dry-run ist die Wahrheitsoberfläche der Registry. Prüfen Sie auf:
- enthält gebauten Output
- enthält
README.mdundLICENSE - schließt source-only-Müll, temporäre Dateien, Tests, private Dokumente, Fixtures, lokale Datenbanken, Geheimnisse aus
- Paketgröße ist angemessen
- CLI-
bin-Pfad erscheint im Tarball
Wenn files fehlt, fügen Sie es hinzu. Verlassen Sie sich nicht auf .gitignore als Veröffentlichungsrichtlinie.
GitHub-Baseline
Hinzufügen oder überprüfen:
.github/workflows/ci.yml.github/dependabot.yml.github/CODEOWNERS.github/pull_request_template.mdSECURITY.md
Verwenden Sie aktuelle unterstützte Hauptversionen für GitHub-eigene Aktionen. Wenn Actions warnt, dass eine Aktionslaufzeit veraltet ist, aktualisieren Sie die Aktionen-Hauptversion, nachdem CI bestanden hat.
CI sollte normalerweise Folgendes beinhalten:
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
Passen Sie node-version an die minimal unterstützte Laufzeit des Pakets an und ersetzen Sie jedes @CURRENT_MAJOR durch den aktuellen Hauptversions-Tag der Aktion (z. B. actions/checkout@v4) – pinnen Sie auf eine echte Hauptversion, committen Sie niemals den Platzhalter.
Dependabot-Baseline
Konfigurieren Sie sowohl Paket- als auch GitHub-Aktionsaktualisierungen:
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
Wenn Dependabot unmittelbar nach der Konfiguration PRs öffnet, behandeln Sie dies als Beweis, dass die Konfiguration aktiv ist. Triage die PRs; führen Sie nicht blind alle grünen Checks zusammen.
Dependabot-Triage
Verwenden Sie diese Faustregel:
- Laufzeitabhängigkeit Patch/Minor: zusammenführen, wenn Checks bestanden und Release-Notes langweilig sind.
- Laufzeitabhängigkeit Major: Release-Notes prüfen und das tatsächliche Paketverhalten rauchtesten.
- Entwicklerwerkzeug Major: zusammenführen, wenn Build/Test/Pack bestanden und der Laufzeitvertrag nicht geändert wird.
@types/nodeüber dem Laufzeit-Boden: schließen oder durch einen Pin auf den Laufzeit-Boden ersetzen.- GitHub-Aktionen Major: zusammenführen, wenn CI bestanden und Deprecation-Warnungen entfernt werden.
Wenn zwei PRs in einer kleinen Konfigurationsdatei in Konflikt stehen, führen Sie einen zusammen und aktualisieren den anderen, oder wenden Sie den zweiten direkt mit einem klaren Kommentar an, der erklärt, dass er ersetzt wurde.
GitHub-Remote-Härtung
Wenden Sie an, was das Repository/Konto unterstützt, und überprüfen Sie dann die tatsächlichen Einstellungen mit gh oder API-Reads.
Nützliche Einstellungen:
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
Verwenden Sie für Actions-Allowlists nur GitHub-eigene Aktionen, wenn der Workflow nur GitHub-eigene Aktionen verwendet. Wenn Drittanbieter-Aktionen erforderlich sind, erlauben Sie explizit die kleinste Menge.
Öffentliche Repos schalten normalerweise mehr Sicherheitskontrollen frei. Private Repos in kostenlosen Plänen können Folgendes blockieren:
- Branch-Schutz oder Regelsätze
- Code-Scanning
- Secret-Scanning
- Push-Schutz
Sprechen Sie Blockaden direkt an. Melden Sie nicht verfügbare Kontrollen nicht als aktiviert.
Branch-Schutz
Schützen Sie, wenn verfügbar, den Standard-Branch mit:
- Pull-Request vor dem Zusammenführen erforderlich
- CI-Status-Checks erforderlich
- Branches müssen auf dem neuesten Stand sein, falls dies zum Projekt passt
- Auflösung von Unterhaltungen erforderlich
- Force-Pushes blockieren
- Löschungen blockieren
- Lineare Historie erforderlich, wenn nur Squash-Zusammenführungen verwendet werden
Stellen Sie nach Aktivierung des Schutzes das direkte Pushen auf main ein, es sei denn, der Benutzer fragt explizit danach und versteht den Workaround.
Gated-PR-Werkzeuge
Wenn Sie ein automatisiertes Überprüfungs-/Gate-Werkzeug verwenden, stellen Sie sicher, dass das Remote einen Standard-/Basis-Branch hat, bevor Sie das Gate bitten, einen PR zu erstellen. Leere neue Remotes benötigen oft zuerst einen initialen main-Push; andernfalls kann das Gate einen Feature-Branch validieren und pushen, aber die PR-Erstellung schlägt fehl, weil es keinen Basis-Ref gibt.
Veröffentlichungs-Checkliste
Vor npm publish:
npm whoamizeigt das beabsichtigte Konto annpm view PACKAGE_NAME name versionbestätigt den Namenstatus- CI ist grün auf dem Commit, der veröffentlicht wird
npm pack --dry-runwurde überprüft- README-Installations-/Verwendungsbeispiele stimmen mit dem tatsächlichen Verhalten überein
repository,homepageundbugslösen auf das echte öffentliche Repository auf (oder sind explizit als TODO markiert, wenn die URL noch nicht endgültig ist)- Es gibt keine veröffentlichungsblockierenden Dependabot-/Sicherheitswarnungen mehr
- Der Versionssprung ist beabsichtigt, in Git getaggt (
git tag vX.Y.Z && git push --tags) und in einem CHANGELOG oder GitHub-Release widergespiegelt - Bereichspakete (
@scope/name) werden mit--access publicveröffentlicht (Bereichspakete standardmäßig auf eingeschränkt/privat)
Für Konten mit Web-/Passkey-/2FA-Auth:
npm publish --auth-type=web
Bevorzugen Sie das Veröffentlichen von CI mit Provenienz für eine überprüfbare Lieferkettenverknüpfung. Provenienz erfordert ein öffentliches Paket, ein unterstütztes CI wie GitHub Actions und id-token: write-Berechtigung auf dem Job:
npm publish --provenance --access public
Nach der Veröffentlichung:
npm view PACKAGE_NAME version
npm view PACKAGE_NAME bin files engines repository --json
npx -y PACKAGE_NAME --help
Wenn mit Provenienz veröffentlicht, bestätigen Sie, dass die Registry die Provenienz / den "Gebaut und signiert"-Nachweis auf der Paketseite anzeigt.
Abschließende Antwort
Melden Sie nur, was tatsächlich überprüft wurde:
- Paketchecks ausgeführt
- Tarball-Ergebnis
- Abhängigkeits-PR-Entscheidungen
- Erstellte oder zusammengeführte Commits/PRs
- Bestätigte GitHub-Einstellungen
- Durch Plan/Sichtbarkeit blockierte Kontrollen
- Release-Tag und Provenienz-Status, falls veröffentlicht
- Veröffentlichungsbefehl oder Post-Release-Verifikation, falls noch im Besitz des Benutzers