Plugin-Sandbox

Auf dieser Seite

Sandboxed Plugins laufen in einer isolierten Laufzeitumgebung, die ein Sandbox-Runner bereitstellt. Marketplace- und Registry-Installationen laufen immer sandboxed, ebenso die unter sandboxed: [] in der emdash()-Integration aufgelisteten Plugins. Plugins unter plugins: [] laufen im Serverprozess und verwenden den Runner nicht.

Der Runner hängt von der Deployment-Plattform ab. Auf Cloudflare Workers läuft jedes Plugin als Dynamic Worker, der über das Worker-Loader-Binding erstellt wird. Auf Node.js startet der Server workerd, die Open-Source-Workers-Runtime, als Kindprozess und führt jedes Plugin als Service darin aus. Die sandboxRunner-Option von emdash() wählt den Runner. Ohne sie werden die Plugins unter sandboxed: [] nie geladen, und ein konfigurierter marketplace lässt den Build mit „Marketplace requires sandboxRunner to be configured” fehlschlagen.

Die folgende Tabelle fasst zusammen, was jeder Runner benötigt und durchsetzt.

Cloudflare WorkersNode.js
sandboxRunnersandbox() von @emdash-cms/cloudflare"@emdash-cms/sandbox-workerd/sandbox"
AnforderungenWorkers Paid Plan, ein worker_loaders-Binding, PluginBridge exportiert vom Worker-EinstiegspunktDas workerd-Paket
DatenbankzugriffDas DB D1-Binding, unabhängig vom konfigurierten AdapterDie konfigurierte Datenbank
Durchgesetzte LimitsCPU-Zeit, Subrequests, Wall-TimeWall-Time

Cloudflare Workers

Dynamic Workers sind im Workers Paid Plan verfügbar. Der Runner benötigt das Binding und den Entry-Point-Export unten; die *-cloudflare-Templates liefern beides mit.

  1. Fügen Sie das Worker-Loader-Binding zu wrangler.jsonc hinzu. Der Runner liest es unter dem Namen LOADER:

    {
    	"worker_loaders": [
    		{
    			"binding": "LOADER",
    		},
    	],
    }
  2. Exportieren Sie PluginBridge vom Worker-Einstiegspunkt und verweisen Sie main auf diese Datei. PluginBridge ist der Einstiegspunkt, über den sandboxed Plugins auf Content, Medien, Storage und E-Mail zugreifen; der Runner sucht es in den Exports des Eingangsmoduls:

    import handler, { createScheduledHandler, PluginBridge } from "@emdash-cms/cloudflare/worker";
    
    export { PluginBridge };
    
    export default {
    	...handler,
    	scheduled: createScheduledHandler(),
    } satisfies ExportedHandler;
    {
    	"main": "./src/worker.ts",
    }
  3. Wählen Sie den Runner in der emdash()-Integration:

    import { d1, r2, sandbox } from "@emdash-cms/cloudflare";
    
    emdash({
    	database: d1({ binding: "DB" }),
    	storage: r2({ binding: "MEDIA" }),
    	sandboxRunner: sandbox(),
    });

Node.js

  1. Installieren Sie den Runner zusammen mit workerd, das eine Peer-Abhängigkeit ist:

    npm install @emdash-cms/sandbox-workerd workerd

    Das workerd-Paket installiert die Binärdatei für die aktuelle Plattform (Linux, macOS und Windows auf x64; Linux und macOS auf arm64) über eine optionale Abhängigkeit. Installieren Sie mit aktivierten optionalen Abhängigkeiten auf der Plattform, auf der der Server läuft. Bei einem mehrstufigen Docker-Build führen Sie die Installation in einer Stufe mit derselben Plattform wie die Laufzeitstufe aus.

  2. Wählen Sie den Runner in der emdash()-Integration:

    import { sqlite } from "emdash/db";
    
    emdash({
    	database: sqlite({ url: "file:./data/emdash.db" }),
    	sandboxRunner: "@emdash-cms/sandbox-workerd/sandbox",
    });
  3. Für die Entwicklung installieren Sie miniflare als Dev-Abhängigkeit:

    npm install -D miniflare

    Wenn NODE_ENV development ist, was astro dev setzt, und miniflare installiert ist, übergibt der Runner die Plugins an Miniflare, das seinen eigenen workerd-Prozess verwaltet; die untenstehende Absturzrichtlinie gilt nicht. astro preview setzt NODE_ENV auf production und node ./dist/server/entry.mjs lässt es ungesetzt; beide verwenden workerd.

Wie der workerd-Prozess läuft

EmDash startet workerd während der Initialisierung bei der ersten Anfrage an die Website, sobald die sandboxed Plugins geladen sind, und wartet bis zu 10 Sekunden, bis die Plugin-Services antworten. Das Installieren oder Aktualisieren eines Plugins über den Admin startet ihn neu. Alles, was workerd auf stdout oder stderr schreibt, erscheint in der Serverausgabe mit dem Präfix [emdash:workerd].

Plugin-Services hören auf 127.0.0.1, und der Kanal zurück zum Server ist ein Unix-Domain-Socket (ein 127.0.0.1-TCP-Port unter Windows). Es muss kein eingehender Port geöffnet werden.

Der Kindprozess erhält nur PATH, HOME, TMPDIR, TMP, TEMP, LANG und LC_ALL aus der Umgebung des Servers, sodass Geheimnisse in der Serverumgebung nicht in die Sandbox gelangen. Um mehr Variablen zu übergeben, setzen Sie EMDASH_WORKERD_PASSTHROUGH_ENV auf eine kommagetrennte Liste von Variablennamen.

Wenn workerd unerwartet beendet wird, protokolliert der Runner [emdash:workerd] workerd exited with <reason> und startet ihn beim nächsten Aufruf neu, mit einer Verzögerung, die bei 1 Sekunde beginnt und sich bis auf 30 Sekunden verdoppelt. Wenn workerd innerhalb von 60 Sekunden mehr als fünf Mal abstürzt, stoppt der Runner das Neustarten und protokolliert [emdash:workerd] workerd crashed 5 times in 60 seconds, giving up. Ab dann schlägt jeder sandboxed Plugin-Hook und jede Route mit Plugin sandbox unavailable for <plugin>: workerd is not running fehl, bis der Server neu gestartet wird. Ein SIGTERM an den Server beendet auch workerd.

Ressourcenlimits

Jeder Runner wendet denselben Satz von Limits pro Plugin-Aufruf an. Die Limits sind fest; die emdash()-Integration hat keine Option dafür.

LimitWertCloudflare WorkersNode.js
CPU-Zeit50 msDurchgesetzt vom Worker Loader; das Plugin wirft, wenn es das Limit erreichtNicht durchgesetzt
Subrequests10Durchgesetzt vom Worker Loader; das Plugin wirft, wenn es das Limit erreichtNicht durchgesetzt
Speicher128 MBNicht pro Plugin durchgesetzt; die Isolate-Speichergrenze der Plattform giltNicht durchgesetzt
Wall-Time30 sDurchgesetzt vom RunnerDurchgesetzt vom Runner

Wenn ein Hook oder eine Route das Wall-Time-Limit überschreitet, schlägt der Aufruf mit Plugin <id> exceeded wall-time limit of 30000ms during hook:<name> (oder route:<name>) fehl. Für einen Hook protokolliert EmDash den Fehler mit dem Präfix EmDash: Sandboxed plugin <id> und setzt die Anfrage ohne das Ergebnis dieses Plugins fort. Eine Plugin-Route, die das Limit überschreitet, schlägt für ihren Aufrufer fehl.

Wenn der Runner nicht verfügbar ist

Ein konfigurierter Runner kann dennoch nicht verfügbar sein: auf Cloudflare Workers, wenn das worker_loaders-Binding oder der PluginBridge-Export fehlt, auf Node.js, wenn workerd nicht installiert ist oder seine Binärdatei nicht läuft. EmDash protokolliert dann die folgende Warnung beim Start der Laufzeit:

EmDash: Plugin sandbox is configured but not available on this platform. Sandboxed plugins will not be loaded. If using @emdash-cms/sandbox-workerd/sandbox, ensure workerd is installed.

Plugins unter sandboxed: [] werden nicht geladen, installierte Marketplace- und Registry-Plugins laufen nicht, und eine neue Installation über den Admin schlägt mit dem Fehlercode SANDBOX_NOT_AVAILABLE fehl. Der Rest der Website ist nicht betroffen.

Sandboxed Plugins im Prozess ausführen

Setzen Sie sandbox: false in emdash(), um die Plugins unter sandboxed: [] und installierte Marketplace-Plugins im Serverprozess ohne Isolation oder Limits auszuführen. Es ist eine Debugging-Option, die einen Bug in einem Plugin von einem Bug in der Sandbox unterscheidet. Die folgende Konfiguration schaltet die Sandbox auf einer Node.js-Website ab:

emdash({
	sandboxRunner: "@emdash-cms/sandbox-workerd/sandbox",
	sandbox: false,
});

Auf Cloudflare Workers verweigert die Laufzeit den Start mit sandbox: false is not supported in Cloudflare Workers.

Fehlerbehebung

Jeder Eintrag wird von der Nachricht angeführt, wie der Server sie protokolliert, oder von dem Fehlercode, den der Admin zurückgibt.

”Plugin sandbox is configured but not available on this platform”

Auf Cloudflare Workers überprüfen Sie beide Anforderungen: wrangler.jsonc hat ein worker_loaders-Binding namens LOADER, und main zeigt auf eine Datei, die PluginBridge exportiert. Das Deployen des Bindings erfordert den Workers Paid Plan.

Auf Node.js führen Sie die Binärdatei aus, die der Runner verwendet:

npx workerd --version

Wenn der Befehl fehlschlägt, fehlt workerd in node_modules oder die installierte Binärdatei läuft nicht auf dieser Plattform. Installieren Sie auf der Zielplattform mit aktivierten optionalen Abhängigkeiten neu.

”workerd failed to start within 10 seconds”

Der Kindprozess wurde gestartet, aber seine Plugin-Services haben nicht innerhalb von 10 Sekunden geantwortet. Die Zeilen mit dem Präfix [emdash:workerd] vor dieser Nachricht enthalten die Ausgabe von workerd selbst, einschließlich Konfigurations- und Startfehler. Der Runner versucht es beim nächsten Aufruf erneut.

”workerd crashed 5 times in 60 seconds, giving up”

Der Runner hat das Neustarten von workerd eingestellt. Die Zeilen [emdash:workerd] workerd exited with <reason> vor dieser Nachricht nennen den Exit-Code oder das Signal jedes Absturzes. Beheben Sie die Ursache und starten Sie dann den Server neu.

SANDBOX_NOT_AVAILABLE bei der Installation eines Plugins

Die Installationsanfrage des Admins wurde abgelehnt, weil der Runner fehlt oder nicht verfügbar ist. Konfigurieren Sie den Runner für die Plattform oder beheben Sie die Ursache der obigen Startwarnung und deployen Sie erneut.