From 5014cca014056cfc9d3ac64adf20794e0505315c Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 30 Oct 2026 00:13:34 +0000 Subject: [PATCH 1/4] =?UTF-8?q?docs(adr):=20ADR-0025=20v2=20says=20what=20?= =?UTF-8?q?M1=20shipped=20=E2=80=94=20the=20local=20install=20loop,=20the?= =?UTF-8?q?=20trusted-key=20store,=20the=20native-addon=20refusal,=20manif?= =?UTF-8?q?est-deps=20retired?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Slices 1-3 of the M1 local T0 install loop landed, and the record still described the code before them. Corrected in place, history kept: - Status line: M1 moves from "not yet built" to what landed; the cloud fetch stays M2, tier dispatch beyond node stays M3. - 3.2: the packaging comment names bundled as the one strategy. - 3.3: os plugin build refuses a native addon; PluginPackagingSchema refuses manifest-deps by name; the build-side half is gone. - 3.4 step 2: install and every boot verify the signature against the environment's trusted keys; plugin-loader refuses an unverified one. - 3.5: step 5 runs no package manager; steps 4-7 exist for a local artifact; the M1 bullet is a landed line, its cloud-sample acceptance run still open. - 3.6: the boot-time loader dispatches on the tier (node imported, sandbox / worker / undeclared refused by name). - 5: the native-addon risk no longer names a manifest-deps mitigation. - 7: the dated note the B-prime ruling ordered — the trusted-key store landed in M1 in its minimal form; rotation and platform / cloud sources stay M3. Co-authored-by: Claude Claude-Session: https://claude.ai/code/session_016WV4d1j1VPnYjVUvuUMHjc --- docs/adr/0025-plugin-package-distribution.md | 80 +++++++++++--------- 1 file changed, 46 insertions(+), 34 deletions(-) diff --git a/docs/adr/0025-plugin-package-distribution.md b/docs/adr/0025-plugin-package-distribution.md index 74bf2ee4a38..f1ea4fc6aad 100644 --- a/docs/adr/0025-plugin-package-distribution.md +++ b/docs/adr/0025-plugin-package-distribution.md @@ -1,6 +1,6 @@ # ADR-0025: Plugin Package Distribution (Code + Dependencies) -**Status**: Accepted — 2026-10-28 (ruled on objectstack#26553, ADR batch 4; proposed 2026-05, revised 2026-06-01, audited 2026-07-16 and 2026-09-12). Narrowed to what landed: Phase 1 (the `.osplugin` artifact, the compiled-manifest schema, `os plugin build` / `sign` / `publish`, cloud review and counter-signing) and install-time permission consent for package installs (console disclosure, `sys_package_installation.granted_permissions`, re-consent on a widening upgrade, the artifact → enforcer binding at load). Not yet built, carried by the M0–M3 programme on objectstack#27108: the code-plugin half of the install flow (§3.5 steps 4–7: `os plugin install`, download / verify / materialize / load — M1 local T0, M2 cloud fetch), runtime enforcement of the granted set (registered only today, §3.7 — M2), tier dispatch (T1 sandbox — M3), publish-side scans and secret-refs (M3). This revision (v2, 2026-10-28) corrects §3.3, §3.4, §3.8 and §3.10 to the code and records the maintainer's decisions Q1–Q8. +**Status**: Accepted — 2026-10-28 (ruled on objectstack#26553, ADR batch 4; proposed 2026-05, revised 2026-06-01, audited 2026-07-16 and 2026-09-12). Narrowed to what landed: Phase 1 (the `.osplugin` artifact, the compiled-manifest schema, `os plugin build` / `sign` / `publish`, cloud review and counter-signing), install-time permission consent for package installs (console disclosure, `sys_package_installation.granted_permissions`, re-consent on a widening upgrade, the artifact → enforcer binding at load), and M1, the local T0 install loop (2026-10-29, §3.5: `os plugin install ./x.osplugin` against the environment's trusted keys, the boot-time loader with the tier dispatch point, disable / enable / uninstall; its cloud-sample acceptance run is still open). Not yet built, carried by the M0–M3 programme on objectstack#27108: the cloud fetch of a code plugin (§3.5 — M2), runtime enforcement of the granted set (registered only today, §3.7 — M2), tier dispatch beyond `node` (T1 sandbox — M3), publish-side scans and secret-refs (M3). This revision (v2, 2026-10-28) corrects §3.3, §3.4, §3.8 and §3.10 to the code and records the maintainer's decisions Q1–Q8; amended 2026-10-30 to what M1 shipped (§3.3, §3.4, §3.5, §3.6, §7). **Deciders**: ObjectStack Protocol Architects **Builds on**: [ADR-0003](./0003-package-as-first-class-citizen.md) (package + versioned releases), [ADR-0004](./0004-cloud-multi-kernel.md) (cloud multi-kernel), [ADR-0010](./0010-metadata-protection-model.md) (L1/L2/L3 protection), [ADR-0016](./0016-studio-package-authoring-and-publish.md) (package authoring & publish, local export/import) **Consumers**: `@objectstack/core` (kernel, plugin-loader, security), `@objectstack/runtime` (sandbox, marketplace install), `@objectstack/cli`, `@objectstack/spec/system` (ObjectStackManifest), `@objectstack/spec/cloud`, `../objectui` (Studio) @@ -156,7 +156,7 @@ Extends the existing `ObjectStackManifest` with three new blocks "type": "plugin", "engines": { "platform": ">=4.0 <5", "protocol": ">=1.0" }, "runtime": "node", // node | sandbox | worker (see §3.6) - "packaging": "bundled", // bundled | manifest-deps (see §3.3) + "packaging": "bundled", // bundled, the one strategy (see §3.3) "permissions": { // explicitly requested capabilities "services": ["object", "http"], "hooks": ["record.beforeInsert"], @@ -182,13 +182,15 @@ checks the existing `PluginPermissionEnforcer` already implements the manifest against `ManifestSchema` and writing per-file `integrity` into the compiled manifest. Install = unpack + verify; **no npm/toolchain at install time**. This is the closest analog to the JSON flow and keeps the security - surface minimal. Native (`.node`) addons are disallowed by rule; the build does - not yet refuse them mechanically (M1 adds the refusal). + surface minimal. Native (`.node`) addons are disallowed by rule, and since M1 + `os plugin build` refuses one before writing anything (a `.node` module or a + native package the bundle reaches, or a `.node` file under `assets/`). - **manifest-deps — RETIRED (v2, maintainer decision Q6, 2026-10-28; ADR-0049 enforce-or-remove).** The strategy existed on the build side only (it shipped `package.json` + `pnpm-lock.yaml` and nothing ever installed them); it had zero - consumers and no install path. `PluginPackagingSchema` keeps `bundled` as its - only live value; the build-side half is removed in M1. Plugins that need native + consumers and no install path. `PluginPackagingSchema` accepts `bundled` only + and refuses `manifest-deps` by name with its migration prescription; the + build-side half was removed in M1 (#27679). Plugins that need native addons or very large dependencies are a fresh decision for M3, with this retirement as the starting evidence. @@ -214,9 +216,9 @@ os plugin build → os plugin sign → os plugin publish `-.osplugin` (ustar + gzip) with a placeholder `SIGNATURE` entry. 2. **sign** — Ed25519 over the raw artifact bytes, written as `ed25519::` to a `.sig` sidecar (`sign.ts`); the publisher - key stays with the publisher. Verification (`verifyPluginArtifact`) exists in - core and has **no production caller until M1** (the loader checks only that a - signature is well-formed, `plugin-loader.ts`). + key stays with the publisher. Since M1 the host verifies it against the + environment's trusted keys (§7) at `os plugin install` and again at every boot + (`verifyPluginArtifact`); `plugin-loader.ts` refuses a signature no host verified. 3. **publish** — extends `os package publish` and **reuses the package registry** (the `/cloud/plugins` endpoints of the original text were never built): - `POST /cloud/packages` → ensure the `sys_package` row (reverse-domain `id`, @@ -264,8 +266,8 @@ resolve → compat check → permission consent → download+verify → material trusted publisher + marketplace keys; verify each file against `integrity`. Reject on any mismatch. 5. **Materialize.** Unpack to a per-environment, per-plugin dir - `/plugins////`. For manifest-deps, run - `pnpm install --frozen-lockfile --ignore-scripts` here. + `/plugins////`. *v2:* nothing is installed there; + `bundled` is the one strategy (§3.3), so install runs no package manager. 6. **Register.** Write the installation record — `sys_package_installation` (`env_id`, `version_id`, `granted_permissions`, `status`; v2 §3.8, the `sys_plugin_installation` of the original text was never created). Persist to a local store so installs survive @@ -290,21 +292,23 @@ explicit `--trust-unsigned` dev override). code-bearing package, `sys_package_installation.granted_permissions`, and a 409 `PERMISSION_RECONSENT_REQUIRED` on a widening upgrade. The granted set always equals the declared set — there is no partial grant. -- **Steps 4–7 do not exist** for code plugins: there is no `os plugin install`, - nothing reads a `.osplugin` back except `publish`, no `/plugins/…` - path, no `--trust-unsigned`, and an environment artifact carries - `sys_package_version.manifest_json` — metadata only, never the blob. -- **M1 — local T0 loop, first-party / self-signed only** (`os plugin install - ./x.osplugin`): verify the whole-artifact Ed25519 signature against the host's - trusted keys (`verifyPluginArtifact` gets its first production caller) and - re-verify every file against `integrity` at unpack; materialize to - `/plugins////`; write the installation record - (§3.8); `--trust-unsigned` as the explicit dev override. The loader scans - installed plugins **at boot** (hot reload was retired with #12587), - dynamic-imports `dist/index.mjs`, reuses `plugin-loader.ts` dependency - ordering, and carries a tier dispatch point that M1 wires for `node` only. - Disable / uninstall reuse the package disable-state store. Acceptance: the - cloud `plugins/connector-stripe` sample installs, loads and disables cleanly. +- **Steps 4–7 exist for a local artifact only** (M1, below). For a code plugin + in the cloud they do not: nothing serves the `.osplugin` back (§3.4), and an + environment artifact carries `sys_package_version.manifest_json` — metadata + only, never the blob. +- ✅ **M1 — local T0 loop, first-party / self-signed only — landed 2026-10-29** + (objectstack#27123: #27335, #27374, #27679). `os plugin install ./x.osplugin` + verifies the `.sig` over the raw bytes against the environment's trusted keys + (§7) before inflating anything, re-verifies every file against `integrity`, + materializes to `/plugins////` and records the + install in a local store (the stand-in for the §3.8 row); `--trust-unsigned` + admits only an unsigned artifact, loudly. At **boot** (hot reload was retired + with #12587) `os serve` re-verifies each install (artifact sha, signature, + byte-equal tree), dispatches on the tier (§3.6) and hands what passed to + `kernel.use`, which orders dependencies. `os plugin disable` / `enable` use the + package disable-state store; `uninstall` takes effect at the next boot. Still + open: the acceptance run on the cloud `plugins/connector-stripe` sample + (objectstack#27570). ⛔ **M1 is first-party / self-signed only and is listed on no marketplace surface**: T0 is author code in the host process (§3.6). - **M2 — cloud fetch**: the artifact download route serves the `.osplugin` with @@ -333,13 +337,16 @@ enforces this at publish time (an unverified publisher cannot ship `runtime: *v2 — as built and as phased (maintainer decision Q3):* `PluginRuntimeSchema` holds the three values, the cloud refuses `node` from an unverified publisher at -publish, and **nothing dispatches on the tier at load** — every plugin that -loads today loads in-process. The QuickJS runner serves hook / action script +publish, and since M1 the boot-time loader dispatches on an installed plugin's +tier (`dispatchPluginRuntime`): `node` is imported in process, `sandbox` / +`worker` and an undeclared tier are refused by name — every plugin that loads +today loads in-process. The QuickJS runner serves hook / action script bodies (§3.10 L1) and is never reached from a plugin's declared tier; `PluginSandboxRuntime` has no production construction site; T2 has no code. -M1 wires the dispatch point for T0 only; **M3** routes `runtime: 'sandbox'` to -QuickJS and decides the T2 RPC surface (§7). Until M3, the publish-time refusal -is the only tier gate, which is why M1 stays first-party / self-signed. +M1 wired the dispatch point for T0 only; **M3** routes `runtime: 'sandbox'` to +QuickJS and decides the T2 RPC surface (§7). Until M3 nothing loads isolated +(those tiers are refused, not confined), which is why M1 stays first-party / +self-signed. ### 3.7 Security model (reuses existing components) @@ -592,8 +599,8 @@ its download / scan half is M2 / M3; Phase 4 (sandbox tier) = M3; Phase 5 JSON-only flow never needed. - Permission consent + tiering add UX and lifecycle surface (re-consent on permission widening, tier enforcement). -- Bundled packaging excludes native addons by default (mitigated by the opt-in - manifest-deps strategy in Phase 5). +- Bundled packaging excludes native addons, and `os plugin build` refuses them; + with manifest-deps retired (Q6), a plugin that needs one waits for M3 (§3.3). ### Neutral @@ -628,7 +635,12 @@ its download / scan half is M2 / M3; Phase 4 (sandbox tier) = M3; Phase 5 on the next boot. - **Key management & rotation** — deferred to **M3** (publisher keys stay with the publisher; the host's trusted root set and its rotation / revocation are - designed with the T1 tier). + designed with the T1 tier). *Note (2026-10-30, ruling `6467932167` on + objectstack#27123, letter B′):* the host's trusted-key **store** landed in M1 + in its minimal form — `sys_trusted_key` (public keys only, `source: 'local'`), + `os plugin keygen` and `os plugin trust add | list | revoke`; install and boot + refuse an unknown or revoked key id by name. Rotation policy and the + `platform` / `cloud` sources stay M3. - **T2 RPC surface** — deferred to **M3** (T2 stays reserved; the minimal host-service RPC contract is designed when the sandbox tier lands). - **Cross-plugin dependency conflicts** — deferred to **M3** (M1 and M2 install From c49a117fc4e5231719a6eb2a1e52dd3ea7539b8c Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 30 Oct 2026 00:22:33 +0000 Subject: [PATCH 2/4] docs(adr): ADR-0025 v2 3.5 names step 7's per-plugin enforcer as M2 beside the local steps 4-7 Co-authored-by: Claude Claude-Session: https://claude.ai/code/session_016WV4d1j1VPnYjVUvuUMHjc --- docs/adr/0025-plugin-package-distribution.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/adr/0025-plugin-package-distribution.md b/docs/adr/0025-plugin-package-distribution.md index f1ea4fc6aad..2afcd20db2b 100644 --- a/docs/adr/0025-plugin-package-distribution.md +++ b/docs/adr/0025-plugin-package-distribution.md @@ -292,10 +292,10 @@ explicit `--trust-unsigned` dev override). code-bearing package, `sys_package_installation.granted_permissions`, and a 409 `PERMISSION_RECONSENT_REQUIRED` on a widening upgrade. The granted set always equals the declared set — there is no partial grant. -- **Steps 4–7 exist for a local artifact only** (M1, below). For a code plugin - in the cloud they do not: nothing serves the `.osplugin` back (§3.4), and an - environment artifact carries `sys_package_version.manifest_json` — metadata - only, never the blob. +- **Steps 4–7 exist for a local artifact only** (M1, below; step 7's per-plugin + enforcer is M2, §3.7). For a code plugin in the cloud they do not: nothing + serves the `.osplugin` back (§3.4), and an environment artifact carries + `sys_package_version.manifest_json` — metadata only, never the blob. - ✅ **M1 — local T0 loop, first-party / self-signed only — landed 2026-10-29** (objectstack#27123: #27335, #27374, #27679). `os plugin install ./x.osplugin` verifies the `.sig` over the raw bytes against the environment's trusted keys From dd3bde2965ebb6143ce769fdfa3d2255a3340179 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 30 Oct 2026 00:48:06 +0000 Subject: [PATCH 3/4] =?UTF-8?q?docs(adr):=20ADR-0025=20v2=20=E2=80=94=20th?= =?UTF-8?q?e=207=20key-source=20schedule,=20the=20amendment=20list,=20the?= =?UTF-8?q?=20M1=20references,=20and=20three=20original-design=20sentences?= =?UTF-8?q?=20M1=20made=20stale?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From the contract review of the first two commits: the 7 note now says rotation stays M3 and the platform / cloud source values are reserved for the keys M2 / M3 cache from the platform chain, as the ruling body and the sys_trusted_key docblock say; the status line lists every section this amendment edits; 8 names the M1 files. Also corrected: 3.5 local-first parity as built (a CLI act, no endpoint), 3.5 step 7's hot activation (retired), and 3.7's lockfile (none ships). Co-authored-by: Claude Claude-Session: https://claude.ai/code/session_016WV4d1j1VPnYjVUvuUMHjc --- docs/adr/0025-plugin-package-distribution.md | 26 ++++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/docs/adr/0025-plugin-package-distribution.md b/docs/adr/0025-plugin-package-distribution.md index 2afcd20db2b..f1075e2d0e2 100644 --- a/docs/adr/0025-plugin-package-distribution.md +++ b/docs/adr/0025-plugin-package-distribution.md @@ -1,6 +1,6 @@ # ADR-0025: Plugin Package Distribution (Code + Dependencies) -**Status**: Accepted — 2026-10-28 (ruled on objectstack#26553, ADR batch 4; proposed 2026-05, revised 2026-06-01, audited 2026-07-16 and 2026-09-12). Narrowed to what landed: Phase 1 (the `.osplugin` artifact, the compiled-manifest schema, `os plugin build` / `sign` / `publish`, cloud review and counter-signing), install-time permission consent for package installs (console disclosure, `sys_package_installation.granted_permissions`, re-consent on a widening upgrade, the artifact → enforcer binding at load), and M1, the local T0 install loop (2026-10-29, §3.5: `os plugin install ./x.osplugin` against the environment's trusted keys, the boot-time loader with the tier dispatch point, disable / enable / uninstall; its cloud-sample acceptance run is still open). Not yet built, carried by the M0–M3 programme on objectstack#27108: the cloud fetch of a code plugin (§3.5 — M2), runtime enforcement of the granted set (registered only today, §3.7 — M2), tier dispatch beyond `node` (T1 sandbox — M3), publish-side scans and secret-refs (M3). This revision (v2, 2026-10-28) corrects §3.3, §3.4, §3.8 and §3.10 to the code and records the maintainer's decisions Q1–Q8; amended 2026-10-30 to what M1 shipped (§3.3, §3.4, §3.5, §3.6, §7). +**Status**: Accepted — 2026-10-28 (ruled on objectstack#26553, ADR batch 4; proposed 2026-05, revised 2026-06-01, audited 2026-07-16 and 2026-09-12). Narrowed to what landed: Phase 1 (the `.osplugin` artifact, the compiled-manifest schema, `os plugin build` / `sign` / `publish`, cloud review and counter-signing), install-time permission consent for package installs (console disclosure, `sys_package_installation.granted_permissions`, re-consent on a widening upgrade, the artifact → enforcer binding at load), and M1, the local T0 install loop (2026-10-29, §3.5: `os plugin install ./x.osplugin` against the environment's trusted keys, the boot-time loader with the tier dispatch point, disable / enable / uninstall; its cloud-sample acceptance run is still open). Not yet built, carried by the M0–M3 programme on objectstack#27108: the cloud fetch of a code plugin (§3.5 — M2), runtime enforcement of the granted set (registered only today, §3.7 — M2), tier dispatch beyond `node` (T1 sandbox — M3), publish-side scans and secret-refs (M3). This revision (v2, 2026-10-28) corrects §3.3, §3.4, §3.8 and §3.10 to the code and records the maintainer's decisions Q1–Q8; amended 2026-10-30 to what M1 shipped (§3.2, §3.3, §3.4, §3.5, §3.6, §3.7, §5, §7, §8). **Deciders**: ObjectStack Protocol Architects **Builds on**: [ADR-0003](./0003-package-as-first-class-citizen.md) (package + versioned releases), [ADR-0004](./0004-cloud-multi-kernel.md) (cloud multi-kernel), [ADR-0010](./0010-metadata-protection-model.md) (L1/L2/L3 protection), [ADR-0016](./0016-studio-package-authoring-and-publish.md) (package authoring & publish, local export/import) **Consumers**: `@objectstack/core` (kernel, plugin-loader, security), `@objectstack/runtime` (sandbox, marketplace install), `@objectstack/cli`, `@objectstack/spec/system` (ObjectStackManifest), `@objectstack/spec/cloud`, `../objectui` (Studio) @@ -272,7 +272,7 @@ resolve → compat check → permission consent → download+verify → material (`env_id`, `version_id`, `granted_permissions`, `status`; v2 §3.8, the `sys_plugin_installation` of the original text was never created). Persist to a local store so installs survive restarts (reuse the ADR-0016 §9.7 `package-state-store.ts` pattern). -7. **Load + activate.** On next boot (or hot, when `hotReloadable`), the loader +7. **Load + activate.** On next boot (*v2:* boot only, `hotReloadable` retired), the loader scans installed plugins, dynamic-imports the entry, wraps `PluginContext` with the enforcer scoped to the granted set, and runs `init → start` in dependency order. If the plugin also has `contributes` metadata, that JSON is @@ -282,7 +282,9 @@ resolve → compat check → permission consent → download+verify → material plugin" upload both hit a `marketplace/install-local`-style endpoint (inline artifact, register-before-persist per ADR-0016 §9.3). Local artifacts need no cloud account; signature verification is still performed (publisher key or an -explicit `--trust-unsigned` dev override). +explicit `--trust-unsigned` dev override). *v2 — as built in M1:* no endpoint and +no Studio upload; `os plugin install` is a CLI act at the host that persists at +install (under `OS_HOME`) and registers the plugin at the next boot. *v2 — where the flow stands and how it lands (maintainer decisions Q1–Q2, 2026-10-28):* @@ -394,9 +396,11 @@ self-signed. lands, with #11982's zero-caller measurement as its starting evidence — the manifest `configuration` block below records the design intent, not a live validator. -- **Supply chain.** Lockfile + per-file `integrity`; server-side scan for - secrets and known-vuln deps; SBOM stored on the version row; **always** - `--ignore-scripts` (no `postinstall`). +- **Supply chain.** Per-file `integrity`; server-side scan for secrets and + known-vuln deps; SBOM stored on the version row; **always** `--ignore-scripts` + (no `postinstall`). *v2:* no lockfile ships (bundled only, §3.3), so install + runs no package manager at all; `integrity` is re-verified at install and at + every boot (M1); the scans are M3 (§3.4). - **Reversible disable.** Reuse the package enable/disable + disable-state-store (ADR-0016 §9.5/§9.7): disabling a plugin stops loading its code and unregisters its contributions on next boot. @@ -639,8 +643,10 @@ its download / scan half is M2 / M3; Phase 4 (sandbox tier) = M3; Phase 5 objectstack#27123, letter B′):* the host's trusted-key **store** landed in M1 in its minimal form — `sys_trusted_key` (public keys only, `source: 'local'`), `os plugin keygen` and `os plugin trust add | list | revoke`; install and boot - refuse an unknown or revoked key id by name. Rotation policy and the - `platform` / `cloud` sources stay M3. + refuse an unknown or revoked key id by name. Rotation policy stays M3; the + `platform` / `cloud` values of `source` are reserved for the keys M2 / M3 cache + from the platform chain (M2's `cloud` rows: root key → platform + counter-signature → publisher key). - **T2 RPC surface** — deferred to **M3** (T2 stays reserved; the minimal host-service RPC contract is designed when the sandbox tier lands). - **Cross-plugin dependency conflicts** — deferred to **M3** (M1 and M2 install @@ -666,6 +672,10 @@ its download / scan half is M2 / M3; Phase 4 (sandbox tier) = M3; Phase 5 - `packages/core/src/security/granted-permissions-not-enforced.pin.test.ts` — the registered-not-enforced measurement pin (deleted by M2) - `packages/core/src/security/plugin-artifact-signature.ts` — Ed25519 sign / verify / counter-sign (v2 §3.4) - `packages/cli/src/commands/plugin/{build,sign,publish}.ts`, `packages/cli/src/utils/osplugin.ts` — the Phase 1 pipeline as built (v2 §3.3–3.4) +- `packages/cli/src/commands/plugin/{install,keygen,disable,enable,uninstall}.ts`, `packages/cli/src/commands/plugin/trust/{add,list,revoke}.ts` — the M1 install loop and the trusted-key commands (v2 §3.5, §7) +- `packages/runtime/src/installed-plugin-loader.ts`, `packages/runtime/src/plugin-installation-store.ts`, `packages/cli/src/utils/installed-plugins-boot.ts` — the boot-time loader with the tier dispatch point, the local installation records, and `os serve`'s registration of what passed (v2 §3.5, §3.6) +- `packages/core/src/security/plugin-artifact-verdict.ts` — the host's verdict `plugin-loader.ts` reads before it accepts a `signature` (v2 §3.4) +- `packages/platform-objects/src/system/sys-trusted-key.object.ts` — `sys_trusted_key`, the environment's trusted publisher public keys (v2 §7) - `packages/runtime/src/security/artifact-granted-permissions.ts` — the artifact → enforcer binding at load (v2 §3.7) - `packages/spec/src/kernel/manifest.zod.ts` — `PluginPermissionsSchema`, `PluginEnginesSchema`, `PluginRuntimeSchema`, `PluginPackagingSchema`, `PluginIntegritySchema` (v2 §3.2) - objectstack#27108 — the M0–M3 programme (v2 §4) From f26a4b361302b2a0a053cf28025d5e8a055d4e53 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 30 Oct 2026 01:03:06 +0000 Subject: [PATCH 4/4] =?UTF-8?q?docs(adr):=20ADR-0025=20v2=203.7=20?= =?UTF-8?q?=E2=80=94=20integrity=20is=20re-verified=20at=20install;=20at?= =?UTF-8?q?=20boot=20the=20tree=20is=20held=20byte-equal=20to=20the=20sign?= =?UTF-8?q?ed=20artifact?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Claude Claude-Session: https://claude.ai/code/session_016WV4d1j1VPnYjVUvuUMHjc --- docs/adr/0025-plugin-package-distribution.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/adr/0025-plugin-package-distribution.md b/docs/adr/0025-plugin-package-distribution.md index f1075e2d0e2..125f6060e45 100644 --- a/docs/adr/0025-plugin-package-distribution.md +++ b/docs/adr/0025-plugin-package-distribution.md @@ -399,8 +399,9 @@ self-signed. - **Supply chain.** Per-file `integrity`; server-side scan for secrets and known-vuln deps; SBOM stored on the version row; **always** `--ignore-scripts` (no `postinstall`). *v2:* no lockfile ships (bundled only, §3.3), so install - runs no package manager at all; `integrity` is re-verified at install and at - every boot (M1); the scans are M3 (§3.4). + runs no package manager at all; `integrity` is re-verified at install, and at + every boot the install directory is held byte-equal to the signed artifact + (M1); the scans are M3 (§3.4). - **Reversible disable.** Reuse the package enable/disable + disable-state-store (ADR-0016 §9.5/§9.7): disabling a plugin stops loading its code and unregisters its contributions on next boot.