A0/3 — Plugin-Artefaktformat, integrity.json & Signierung#27
Merged
Conversation
Implementierungsreifer ADR für den letzten A0-Baustein (Repo-Template, deterministisches Artefakt, Build-Action, .sig-Signierworkflow). Festgezurrt: - Signaturwurzel = separate integrity.json (Manifest bleibt clean, kein API-Bump); .sig als versionierte Hülle (formatVersion/algorithm/keyId/signature), signiert die rohen integrity.json-Bytes. - Voraussetzung: @mindgraph/plugin-api 0.2.0 public auf npm (JS+.d.ts), externe Repos konsumieren npm-dist, App weiter via TS-Quell-Alias. - Bundle-ABI = Main-only, main.js self-contained CommonJS (module.exports), via require/createRequire; keine externen Imports, Node-/Electron-Built-ins beim Build verboten. Renderer-ABI bewusst A1. - Container: deterministisches tar.gz .mgxplugin (Node-Writer, Node/zlib/Params gepinnt). - Signatur Ed25519 via Node crypto (PKCS#8-Secret, SPKI in App), Verifier mit injiziertem Keyring. - Harte Archivlimits + strenge Pfad-/Integrity-Normalisierung; Verifier prüft Signatur, Hashes, Manifest + Kompat-Gates + entrypoint-Existenz NOCH in Quarantäne, Install zuletzt. - CI-Keyschutz: signieren nur auf geschützten Release-Tags, nie in pull_request, Environment mit Freigabe, Prod-Key nie lokal. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- CJS-Sicherheitsaussage korrigiert: ctx.host ist die vorgesehene API, NICHT technisch der einzige Draht (process/dyn. require bleiben); Built-in-Bann = Lint/Defense-in-depth. Sicherheit in Phase A nur aus Signatur + Autorvertrauen. - Verifier vs Installer getrennt: A0/3 = verify() → VerifiedPluginPackage (Quarantäne), KEIN Install (atomar erst A1/A2; in der Reihenfolge als spätere Pflicht markiert). - Kanonische JSON-Bytes festgelegt: JSON.stringify(v,null,2)+'\n', UTF-8/LF/kein BOM/feste Feldreihenfolge — für manifest.json, integrity.json, .sig. - USTAR/PAX-Widerspruch geschlossen: ≤100 ASCII-Bytes pro Pfadsegment; Writer + Verifier identische Pfadregeln. - Toolchain konkret: Node exakt 20.x (.nvmrc/engines, kein floating), node-tar v7 (portable:true) gepinnt, fixe gzip-Stufe; npm-Publish via Trusted Publishing/OIDC + --provenance, kein langlebiger Token. - Redaktion: doppelte Akzeptanzkriterium-Nr. behoben (jetzt 1–6). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- private entfernt; publishConfig (access public, provenance, main/types/exports → dist).
- tsconfig.build.json: CommonJS + .d.ts-Emit nach dist/; build-Script schreibt
dist/package.json {"type":"commonjs"} (CJS-Marker trotz type:module im Root).
- exports bleibt auf TS-Quelle → In-Repo-Konsumption (App-Alias, vitest) unverändert;
externe Repos konsumieren das npm-dist. prepublishOnly baut dist.
- dist/ gitignored (nur via Publish gebaut). Smoke-Test: require(dist/index.js) +
require(dist/validation.js) liefern definePluginMain + Gate-Funktionen.
Paket-/App-typecheck + 315 Tests + build grün; exports/In-Repo-Auflösung unverändert.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sicherheitsfundament des Plugin-Artefakts (ADR docs/plugin-artifact-format-plan.md), geteilt von Verifier UND (Test-)Packer — identische Writer/Verifier-Regeln: - limits.ts: ARTIFACT_LIMITS (ADR-Tabelle) + ArtifactError/ArtifactErrorCode-Taxonomie. - format.ts: kanonische JSON-Bytes (JSON.stringify(v,null,2)+LF, BOM-Reject beim Parsen); strenge Pfadregeln (lowercase ASCII POSIX, kein .././/absolut/Backslash, ≤100 Byte/Segment, ≤8 Tiefe, ≤240 Länge); validateIntegrityDoc (formatVersion/sha256/strikt sortiert+eindeutig, size = Safe-Int, keine Fremd-Keys); validateSigEnvelope (ed25519-Hülle, kanonisches Base64 → exakt 64 Bytes). - 19 adversariale Unit-Tests; reine Logik, noch nicht in den Main-Prozess verdrahtet. typecheck + 334 Tests grün. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…PluginPackage)
- verify.ts: verifyPluginArtifact(archive, {keyring, appVersion, quarantineDir}) — bomb-sicheres
Gunzip (Byte-Cap) → tar-Parse (nur reguläre Files, Limits/Pfadregeln) → Ed25519-Verify über
EXAKTE integrity.json-Bytes (injizierter Keyring) → Dateimenge/Größe/sha256 → Manifest
(validateManifest/Semantics) + API/App-Gates (A0/2) → entrypoint-Existenz → Schreiben in
Quarantäne. Gibt VerifiedPluginPackage zurück, INSTALLIERT NICHT (atomar erst A1/A2).
- pack.ts: deterministischer Packer (node-tar portable + gzip), Build-Reihenfolge laut ADR;
geteilt von Tests/Template, gleiche Pfad-/Formatregeln wie der Verifier.
- tar als direkte Dependency (node-tar v7, dyn. import — Repo-Muster für ESM-only im Main).
- limits.ts: ArtifactLimits als Interface (Test-Override) statt as-const-Literale.
- 15 Integrationstests: Happy-Path + sig-mismatch/unknown-key/getamperte integrity/hash-/
size-mismatch/fileset/Symlink/manifest-invalid/incompatible-api/-app/entrypoint-missing/Limits.
typecheck + 349 Tests + build grün.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…(Scaffold) Template (plugin-template/): v2-Manifest (entrypoints.main), src/main.ts (definePluginMain), build.mjs + geteilte esbuild.config.mjs (CJS-Bundle, footer → module.exports = entry, Built-in-Bann), scripts/keygen-dev.mjs (git-ignorierter Dev-Key, nie auto-genutzt), .nvmrc (20.18.1), README (Doku + nur Secret-NAMEN, keine Werte). E2E-Test (artifact/e2e.test.ts): baut das Template mit derselben esbuild-Config (alias auf Workspace-Quelle), signiert mit Dev-Key, verifiziert mit Test-Keyring und lädt das verifizierte main.js per createRequire aus einem Ordner OHNE package.json → PluginMainEntry (ADR-Kriterien 2–4); plus Negativtest: Built-in-Import bricht den Build ab. Workflows (Actions auf volle SHAs gepinnt, minimale Permissions): - plugin-artifact-ci.yml: PR/Push → typecheck + Artefakt-Pipeline (build→sign(dev)→verify) via Tests. - plugin-api-publish.yml: manuell, Trusted Publishing (OIDC) + --provenance, id-token:write NUR in diesem Job, Dry-run-Default, kein npm-Token. - plugin-release-sign.yml: manuell + geschütztes Environment 'release-signing', Dry-run prüft nur Key-Form; echter Prod-Sign bleibt Maintainer-Schritt. Nur Secret-Name PLUGIN_SIGNING_KEY. typecheck + 351 Tests + build grün. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
bydb
marked this pull request as ready for review
June 29, 2026 08:28
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.
A0 · Schritt 3 der Plugin-System-Roadmap (folgt auf #26, A0/2). Draft — startet mit dem ADR; Implementierung (npm-publish-fähiges
@mindgraph/plugin-api, Main-only-Template, Pack/Verify-Logik, Signier-Workflow) läuft schrittweise in diesen PR.ADR:
docs/plugin-artifact-format-plan.mdFestgezurrter Vertrag für ein deterministisches, signiertes Plugin-Artefakt:
integrity.json(Manifest v2 bleibt clean, kein API-Bump)..sig= versionierte Hülle (formatVersion/algorithm/keyId/signature), signiert die rohenintegrity.json-Bytes.JSON.stringify(v,null,2)+'\n', UTF-8/LF/kein BOM/feste Feldreihenfolge.@mindgraph/plugin-api@0.2.0public auf npm (JS+.d.ts), via Trusted Publishing/OIDC +--provenance(kein langlebiger Token). App konsumiert weiter via TS-Quell-Alias.module.exports, viarequire/createRequire); keine externen/dyn. Imports, Node-/Electron-Built-ins beim Build verboten. Sicherheit kommt in Phase A nur aus Signatur + Autorvertrauen —ctx.hostist die vorgesehene, nicht die technisch einzige Grenze; echte Isolation erstutilityProcess(Roadmap Bump react-window and @types/react-window in /app #10). Renderer-ABI bewusst A1..mgxplugin— Node 20.x exakt, node-tar v7portable:true, fixe gzip-Stufe. Signatur hängt anintegrity.json, nicht an den Archivbytes.crypto(PKCS#8-Secret, SPKI in App), Verifier mit injiziertem Keyring.verify(archive, keyring) → VerifiedPluginPackageprüft alles in Quarantäne (Signatur → Hashes → Manifest + Kompat-Gates A0/2 → entrypoint-Existenz). A0/3 installiert nicht — atomarer Install erst A1/A2.pull_request, Environment mit Freigabe, Prod-Key nie lokal (lokalespacknur mit injiziertem Dev-Key).Scope-Grenze
Kein Loader/Install, kein Renderer-ABI, kein Multi-Key-Trust-Store, keine Laufzeit-Isolation — siehe ADR.
Status
Nur ADR-Commits; noch keine Implementierung. Offen für externe Aktionen: npm-Org/Scope-Berechtigung für
@mindgraph+ Hinterlegen des Prod-Signierschlüssels (PKCS#8-Secret +keyId) durch den Maintainer.🤖 Generated with Claude Code
Umgesetzt (Implementierung, alles grün: typecheck + 351 Tests + build + CI)
@mindgraph/plugin-apipublish-fähig —privateraus,publishConfig(OIDC/provenance, main/types/exports→dist), CJS-dist-Build;exportsbleibt auf TS-Quelle (In-Repo-Auflösung unverändert).app/src/main/plugins/artifact/{limits,format}.ts) — kanonische JSON-Bytes, strenge Pfadregeln (≤100 B/Segment, ≤8 Tiefe),integrity.json/.sig-Parsing,ArtifactError-Taxonomie. 19 Tests.{verify,pack}.ts) —verifyPluginArtifact() → VerifiedPluginPackage: bomb-sicheres Gunzip → tar (nur reguläre Files) → Ed25519 über exakteintegrity.json-Bytes → Hash/Größe → Manifest + A0/2-Gates → entrypoint-Existenz → Quarantäne. Kein Install. 15 Integrationstests.plugin-template/) + E2E-Test (build→sign(dev)→verify→createRequireohnepackage.json) + Workflows (CI / OIDC-Publish / gated Release-Sign), Actions SHA-gepinnt,id-tokenisoliert.Scope / Vorbehalt (wichtig)
A0/3 schließt den verifizierten Format- und Pipeline-Kern ab (Format, Verifier, Determinismus, Template, CI build→sign(dev)→verify). Noch ausstehend — vor einem realen Store-Release nötig, blockiert diesen Grundlagen-Merge aber NICHT:
PLUGIN_SIGNING_KEY(Ed25519 PKCS#8) im geschützten Environmentrelease-signing; der Release-Sign-Workflow ist bewusst noch nicht scharf.@mindgraph+ Trusted-Publishing-Eintrag für den realen Publish (Workflow läuft bis dahin nur als Dry-run).Nächster Schritt nach Merge: A1 (Runtime-Loader, der
verifyPluginArtifact()aufruft + atomar installiert), zunächst Main-only.