A1 — Runtime-Loader (Disk-Install + Aktivierung), Main-only#28
Merged
Conversation
…Main-only Plan für Phase A1 (frisch von master nach A0/3-Merge #27). Fünf Schritte: .mgxplugin einlesen → verifyPluginArtifact() → atomarer Install + Rollback → Registry-Aktivierung von main.js → Neustart-/Fehler-/Manipulations-Tests. Vorschläge: Install nach userData/plugins/<id>/<version>/ (atomar via rename, kein Teil-Install); Re-Verify beim Laden (persistierte integrity.json+.sig) gegen Manipulation; gepinnter Prod-Keyring (leer bis Maintainer-Freischaltung → real inert) + Dev-Keyring-Escape nur in Dev-Builds; Disk- Quellen in dieselbe PluginRegistry. Renderer-Plugins = separater zweiter Spike. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Re-Verify bei jedem Start (fail-closed, Installation unangetastet); Layout store/<id>/<version>/ + atomarer Aktivierungsindex active.json außerhalb der Versionsordner, Discovery lädt nur die aktive Version; Dev-Keyring nur bei !app.isPackaged + MINDGRAPH_PLUGIN_DEV_KEYRING_PATH (kein stiller Fallback, Tests per DI); mehrere Versionen installiert/genau eine aktiv, Upgrade schaltet erst nach Verify+Load atomar um (Vorgänger bleibt für Rollback); minimale UI; ID-Kollisionsschutz (gebündelt/reserviert nie überschreibbar, Ablehnung bei Install+Load); Idempotenz nur bei byte-identischem Artefakt. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…on/Idempotenz) verify.ts refaktoriert: Kern-Prüfungen als verifyFileMap() herausgezogen; neue verifyInstalledDir() re-verifiziert ein installiertes Verzeichnis (fail-closed, ohne Archiv); writeQuarantine persistiert jetzt auch integrity.json + .sig → Quarantäne ist ein vollständiges, re-verifizierbares Verzeichnis. Neue ArtifactErrorCodes: id-collision, version-conflict, load-failed. runtime/: - paths.ts: store/<id>/<version>/ + active.json (außerhalb der Versionsordner) + .quarantine. - activeIndex.ts: atomarer (temp+rename) Aktivierungsindex; kaputt/fehlend → leer. - keyring.ts: buildKeyring (offizielle Prod-Keys LEER bis Freischaltung; Dev-Keys NUR bei !isPackaged + explizitem MINDGRAPH_PLUGIN_DEV_KEYRING_PATH, kein stiller Fallback); RESERVED_PLUGIN_IDS. - install.ts: verify → ID-Kollision/Idempotenz(byte-identisch)/version-conflict → atomar nach store/<id>/<version> → Re-Verify + Load-Smoke → erst dann active.json atomar. Rollback lässt nie ein Teil-Install zurück; Vorgänger-Version bleibt. - discover.ts: liest active.json, re-verifiziert NUR die aktive Version (fail-closed), baut MainPluginSource; Re-Verify-Fehler/ID-Kollision → kein Source, Fehler gemeldet. 11 Tests (install/idempotenz/version-conflict/id-collision/incompat-rollback/sig-mismatch + discover/manipulation/unknown-key/kollision). typecheck + 362 Tests + build grün. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
P1.1 Symlink/Traversal-Schutz: neuer safepath.ts (assertSafeStoreVersionDir) validiert id/version (auch aus untrusted active.json) strikt und prüft die reale Pfadkette store/<id>/<version> auf Symlinkfreiheit + Store-Containment. Install + Discover nutzen ihn statt blindem join. P1.2 Idempotenz repariert: bestehende Version wird vollständig re-verifiziert (fail-closed) UND integrity.json + .sig byte-verglichen; nur dann idempotent — und die gewünschte Version wird atomar AKTIVIERT (auch wenn sie vorher inaktiv war). Manipulierte Installation → version-conflict. P1.3 Keine Code-Ausführung beim Install: loadEntry-Smoke (require) entfernt; main.js wird im Install NICHT mehr ausgeführt (kein Cache-Poisoning, keine Nebenwirkungen vor Aktivierung). Laden passiert nur im Registry-Aktivierungspfad; install gibt previousVersion für Rollback zurück. setActiveVersion exportiert. P1.4 Manifest-Entrypoint respektiert: nicht mehr hartcodiert 'main.js' — Install/Discover nutzen manifest.entrypoints.main; Renderer-only-Manifeste werden im Main-only-Loader abgelehnt (entrypoint-unsupported). +7 Regressionstests (Symlink-Store, untrusted-Index, Manipulation-nicht-idempotent, inaktiv→aktiv, keine Ausführung beim Install, dist/main.js-Entrypoint, Renderer-only-Reject). typecheck + 369 Tests + build grün. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… live + UI) Verdrahtet den A1-Install/Discover-Kern in die laufende App: Disk-Plugins werden signaturgeprüft installiert, aktiviert, deinstalliert und in der Verwaltungs-UI gelistet. Transaktional gehärtet über mehrere Review-Runden. Kern (manage.ts, DI-testbar): - discoverAndRegisterInstalled (Startup), installAndActivate, uninstallPlugin - Index-Commit ZULETZT (ADR): installPluginArtifact materialisiert/verifiziert nur; active.json wird erst nach erfolgreicher Aktivierung committet (kein Crash-Loop bei Abbruch waehrend start()). discoverVersion entdeckt den Kandidaten ohne den Index. - Aktivierungs- UND Index-Commit-Fehler teilen eine Recovery-Transaktion (rollbackStartedVersion): neue Version sauber stoppen + Vorgaenger live; bei Stop-Doppelfehler PluginRestartRequiredError (keine zwei Versionen gleichzeitig, kein Reaktivieren unter geleakten Timern). Uninstall-Commit- Fehler stellt die noch persistierte aktive Version wieder her. - Workflow-Action-Kollision = TERMINALE Ablehnung (Install + Startup): findWorkflowActionCollisions, neuer Code 'workflow-collision'; Owner-Tracking entfernt beim Uninstall nur EIGENE Actions. - require-Cache-Purge (realpath, macOS /var->/private/var) bei Load + Uninstall. - Archiv-Groessen-Gate vor dem Lesen (readArchiveFileCapped, ArchiveFs-DI). Registry: unregister() wirft + behaelt den Entry bei stop-Fehler (kein Zombie, keine Two-Versions-Race). Workflow-Registry: strikter Owner-Guard gegen Action-Shadowing. index.ts: pluginsRoot=userData/plugins, blockedIds=gebuendelt+RESERVED, buildKeyring via app.isPackaged+MINDGRAPH_PLUGIN_DEV_KEYRING_PATH; Startup- Discovery vor activateAll; IPC plugin:install/uninstall/installed/installErrors (isTrustedSender, serialisiert gegen active.json-Lost-Update). UI (Settings -> Module): Plugin installieren, Liste installierter Disk-Plugins mit Version/Status (lokalisiert) + Uninstall mit Bestaetigung, abgewiesene Plugins. preload + shared/types erweitert. Bewusst KEIN Startup-GC dormanter Versionen (fail-closed Index haette den Store geloescht); sicheres GC via Tombstones offen (ADR F5). ADR um Runde-1/2 + Follow-ups F1-F5 ergaenzt. typecheck + 412 Tests + build gruen. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
plugin:installErrors berechnete nur die reinen Artefakt-Re-Verify-Fehler neu (discoverInstalledPlugins().errors). Ein beim Startup erzeugter workflow-collision-Fehler (eine Plugin-Action kollidiert mit einer Kern-/ fremden Action) tauchte dadurch in der Verwaltungs-UI nicht auf. Neuer Helper computeInstalledErrors(env): Artefaktfehler PLUS workflow-collision (gegen den live registrierten Stand), genutzt vom IPC. discoverAndRegisterInstalled teilt sich die Kollisions-Fehlerkonstruktion (workflowCollisionError). Read-only, keine Seiteneffekte. Test: computeInstalledErrors meldet die Startup-Kollision ebenfalls. typecheck + 412 Tests + build gruen. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
bydb
marked this pull request as ready for review
June 29, 2026 12:34
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Phase A1 der Plugin-Roadmap (folgt auf #27, A0/3). Draft — startet mit dem ADR; Implementierung läuft nach Review schrittweise in diesen PR. ADR:
docs/plugin-runtime-loader-plan.md.Ziel
Externe
.mgxpluginzur Laufzeit laden — die neue Vertrauensgrenze. Fünf Schritte: einlesen →verifyPluginArtifact()(A0/3) → atomarer Install + Rollback → Registry-Aktivierung vonmain.js→ Neustart-/Fehler-/Manipulations-Tests. Main-only; Renderer-Plugins = separater zweiter Spike.Vorgeschlagene Entscheidungen (Review)
userData/plugins/<id>/<version>/, atomar viarename, kein Teil-Install; id/version nur aus dem verifizierten Manifest.integrity.json+.sig) → erkennt On-Disk-Manipulation.PluginRegistry(erneute Manifest-/Gate-Prüfung, Fehler-Isolation pro Plugin).Offene Punkte (im ADR)
Re-Verify-on-Load vs Trust-on-Install · Install-Layout/Persistenz · Dev-Keyring-Form · Multi-Version nebeneinander vs ersetzen · UI-Umfang dieses Spikes.
Sicherheitslage
Unverändert: Sicherheit aus Signatur + Autorvertrauen; echte Isolation (
utilityProcess) bleibt Roadmap #10. Realer Fremd-Load erst nach Prod-Key-Provisionierung.🤖 Generated with Claude Code