Zum Inhalt springen

Sicherheit und Betrieb des Backport-Builders

Build-Werkzeuge — KEINE Laufzeitabhängigkeit. Diese Seite befasst sich mit dem Betrieb der Build-Pipeline und dem in sie gesetzten Vertrauen. Die Sicherheitshaltung der PDF-Engine selbst ist in der Engine-Dokumentation beschrieben, nicht hier.

Der Builder transformiert Quellcode, den er nicht selbst verfasst, und gibt eine Distribution aus, an der nicht entwickelt wird. Daraus ergibt sich sein Sicherheitsmodell. Die Vertrauensgrenze liegt beim Quell-Checkout und bei der Toolchain. Das ausgegebene Artefakt ist schreibgeschützt und maschinell erzeugt. Die Lizenzaufteilung zwischen öffentlichem Paket und Pro-Paket ist im Code festgelegt.

Die Eingaben des Builders sind die Quell-Repositorys und die fixierte Toolchain. Seine Ausgabe ist ein daraus abgeleitetes Artefakt. Drei Eigenschaften gelten:

  • Die generierte Distribution ist schreibgeschützt und maschinell erzeugt. Sie wird als Versions-Tags veröffentlicht, nicht als Branches dieses Repositorys. Entwicklung, Fehlerberichte und Feature-Anfragen gehen an die ursprünglichen nextpdf/*-Quell-Repositorys, niemals an den generierten Baum. Nachprüfbar anhand des Warnblocks in der README.md des Projekts und der .github/workflows/build.yml (das Release committet und taggt den generierten Baum von Grund auf neu).
  • Der Geltungsbereich des Release-Tokens ist eng gefasst. secrets.BACKPORT_TRIGGER_TOKEN autorisiert das Klonen der Quell-Repositorys am Release-Tag. Es wird ausschließlich in den Quell-Checkout-Schritten referenziert. Nachprüfbar anhand der build.yml (Verwendung von GH_TOKEN).
  • Die Aufteilung der CI-Runner ist bewusst gewählt. Vertrauenswürdige Ereignisse laufen auf selbst gehosteten PHP-Runnern; Fork-Pull-Requests und Dependabot-Läufe laufen zwingend auf GitHub-gehosteten Runnern. Nicht vertrauenswürdiger Code wird niemals im vertrauenswürdigen Runner-Pool ausgeführt. Nachprüfbar anhand der .github/workflows/0-ci.yml (die runs-on-Bedingung).
  • Die Toolchain ist in composer.json eingeschränkt. Rector ^2.0, PHPStan ^2.1, PHPUnit ^13.0 und das symfony/polyfill-*-Set. Der Builder hat keine NextPDF-Laufzeitabhängigkeit; deshalb kann eine Kompromittierung eines NextPDF-Laufzeitpakets den Builder nicht erreichen. Nachprüfbar anhand der composer.json.
  • Abhängigkeits-Updates sind bot-gesteuert und abgesichert. Es gibt eine Dependabot-Konfiguration und einen Auto-Merge-Workflow; Dependabot-Läufe sind auf GitHub-gehostete Runner festgelegt und durchlaufen vor dem Merge dennoch das vollständige CI-Gate (PHPStan, Tests, Dry-Run). Nachprüfbar anhand der .github/dependabot.yml und .github/workflows/0-ci.yml, 9-dependabot-auto-merge.yml.
  • Die Ausgabe schließt den Build-Zustand aus. Das Release-Archiv wird ohne vendor/ und .git/ gezippt, sodass das veröffentlichte Artefakt Quellcode und das generierte Manifest enthält, nicht den eigenen Abhängigkeitsbaum des Builders. Nachprüfbar anhand der build.yml (zip ... -x '*/vendor/*' '*/.git/*').
  • Statische Analyse sichert den Build-Code ab. composer analyse führt PHPStan auf Level 10 für rector/rules und scripts bei jedem Push und Pull-Request gegen einen der beiden permanenten Branches aus. Dies geschieht vor jedem Dry-Run. Nachprüfbar anhand der composer.json und der 0-ci.yml.

Das Build-Skript prüft die Ausgabe lokal nicht auf Syntaxfehler. Der Grund ist, dass der Build-Host ein neueres PHP ausführt als das Ziel. Das maßgebliche Gate befindet sich im Release-Workflow. Nach dem Build wechselt der Runner zum Ziel-PHP und führt php -l über output/src aus; bei jedem Parse- oder schwerwiegenden Fehler schlägt das Release fehl. Das Artefakt wird anschließend in der Validierungsmatrix installiert und ausgeführt — PHP 8.1 bis 8.4 für die PHP-8.1-Lane, PHP 7.4 und 8.0 für die PHP-7.4-Lane. Eine Distribution, die eine Ziel-Laufzeitumgebung ablehnen würde, erreicht kein Release. Nachprüfbar anhand von scripts/build.php (validateOutput()) und der .github/workflows/build.yml (die Syntax-Check- und validate-*-Jobs).

Dies ist eine auf beobachtetem Verhalten beruhende Garantie, beschränkt auf die Laufzeitumgebungen, die die Pipeline durchläuft. Sie stellt keine Konformitätszertifizierung dar. Sie sichert nicht zu, dass das transformierte Programm über die Syntaxakzeptanz und die projekteigene Test-Suite hinaus korrekt ist.

Die beiden erzeugten Pakete tragen unterschiedliche Lizenzen; festgelegt ist das in scripts/adjust-composer.php:

PaketLizenzfeldGesetzt durch
nextpdf/backportApache-2.0generatePublicComposer()
nextpdf/backport-proproprietarygenerateProComposer()

Das Builder-Repository selbst steht unter Apache-2.0 (composer.jsonlicense). Seine CHANGELOG.md dokumentiert eine frühere Umlizenzierung von LGPL-3.0-or-later auf Apache-2.0. Vor dieser Änderung veröffentlichte Versionen bleiben unter der älteren Lizenz und weiterhin abrufbar, während jede neue Version unter Apache-2.0 steht. Die Pro-Distribution ist proprietär, wird nur für das PHP-8.1-Ziel erzeugt und erfordert phpseclib/phpseclib ^3.0. Nachprüfbar anhand von CHANGELOG.md, composer.json und scripts/adjust-composer.php.

Die Pipeline garantiert nur, was der Code durchsetzt:

  • Abbruch beim ersten Fehler. Der Build bricht bei der ersten fehlgeschlagenen Stufe mit einem benannten Fehler ab. Eine unvollständige Distribution wird niemals veröffentlicht, da die Release-Jobs von einem erfolgreichen Build und einer erfolgreichen Validierung abhängen. Nachprüfbar anhand von scripts/build.php (step()) und dem build.yml-Job-needs.
  • Serialisierte Builds. Die Concurrency-Gruppe backport-build mit cancel-in-progress: false verhindert, dass zwei Quell-Releases um dasselbe Release-Tag konkurrieren. Nachprüfbar anhand der build.yml.
  • Reproduzierbare Eingaben. Die Pipeline klont vor dem Build jedes Quell-Repository am genauen Release-Tag. Nachprüfbar anhand der build.yml (--branch "${TAG}").

Was sie nicht für sich beansprucht:

  • Sie zertifiziert weder Standardkonformität noch vollständige PHP-Versionskompatibilität noch die Korrektheit des transformierten Programms über die Syntaxakzeptanz und die Test-Suite hinaus.
  • Das Downgrade entfernt die zur Laufzeit erzwungene Unveränderlichkeit (Entfernen von readonly). Code, der sich darauf verlassen hat, dass die Laufzeitumgebung einen Schreibzugriff auf eine readonly-Eigenschaft ablehnt, verliert diesen Schutz in der heruntergestuften Ausgabe. Dies ist ein dokumentierter, beabsichtigter Kompromiss zugunsten der clone-with-Sicherheit — siehe /integrations/backport/troubleshooting/.

Sicherheitsprobleme im Builder richten sich nach der SECURITY.md des Repositorys: Melden Sie sie über ein GitHub Security Advisory oder den Sicherheitskontakt, nicht über ein öffentliches Issue. Probleme im generierten Code werden bei den ursprünglichen Quell-Repositorys eingereicht, da der generierte Baum maschinell erzeugt wird und nicht als Entwicklungsbasis dient. Nachprüfbar anhand der SECURITY.md und der README.md des Projekts.

  • /integrations/backport/overview/ — was der Builder ist und was er produziert.
  • /integrations/backport/production-usage/ — Betrieb der Release-Pipeline.