Skip to content

[Security] Reapprove changed plugin artifacts and minimize MCP child environments - #372

Open
fettpl wants to merge 18 commits into
sybil-solutions:devfrom
fettpl:fix/233-plugin-artifact-reapproval
Open

[Security] Reapprove changed plugin artifacts and minimize MCP child environments#372
fettpl wants to merge 18 commits into
sybil-solutions:devfrom
fettpl:fix/233-plugin-artifact-reapproval

Conversation

@fettpl

@fettpl fettpl commented Aug 7, 2026

Copy link
Copy Markdown

Summary

  • Bind plugin approval to a bounded canonical artifact digest and manifest-derived launch identity.
  • Execute approved code from immutable owner-only snapshots with a minimal explicit child environment.
  • Revoke changed grants and pooled processes, then collect obsolete snapshot roots without racing active execution or path replacement.

Root cause

Plugin approval originally covered metadata rather than the complete executable identity, and immutable execution snapshots had no complete lifecycle. Same-version artifact or launch drift could outlive approval, while removed, revoked, or superseded snapshots accumulated indefinitely. Cleanup also needed to prove that every pooled, creating, closing, or probing child had stopped before deleting its executable snapshot.

Solution design

Artifact hashing uses a deterministic bounded walk, streamed reads, symlink containment, race detection, and special-file rejection. Enabling a stdio plugin records the artifact, runtime, and launch identities of an owner-read-only snapshot. Refresh reconstructs the launch plan and atomically disables changed connectors with empty grants.

A typed Effect lifecycle lease serializes snapshot preparation, durable connector mutation, child shutdown, and garbage collection. Connector mutation remains in the same Effect fiber, so cancellation cannot leave detached state changes running. Per-ID single-flight generations cover creation, use, closure, direct probes, and persisted connector-test probes; queued cancellation is observed before launch, and close drains late generations before reporting empty. Failed shutdowns remain quarantined and retryable.

Storage roots and ancestors are owner-private and revalidated through no-follow directory descriptors. Retained paths stay stationary; stale entries are individually quarantined for deletion. Existing digest snapshots are reused only after identity and content verification, while no-clobber publication and retained-identity recovery close publisher/collector and crash-recovery races. The current connector ID, grants, configuration, and snapshot are re-read under the lifecycle lease before execution.

Google connector reconciliation runs outside the account-mutation permit, removing the inverse account/snapshot lock order. Garbage collection derives retention from the verified active identity and cannot run ahead of a pooled, creating, closing, probing, or persisted-test child.

Validation

  • Exact head: ba91a40e63c96ed0cd4a3444af40215e637b9824.
  • Focused lifecycle suite: 46/46 with 149 assertions.
  • Independent file-lifecycle suite: 43/43; randomized stress: 215/215.
  • Retained-content and publication-recovery stress: 50/50.
  • npm run check passed with frontend 123, controller 90, and agent runtime 149 tests.
  • npm run test:integration passed with 149/149 agent-runtime tests.
  • npm --prefix frontend run desktop:dist completed and produced the macOS app, ZIP, DMG, and updater metadata.
  • Direct packaged smoke passed with desktop health 200, healthy runtime, embedded browser, and PTY checks.
  • The keychain reported zero valid Developer ID identities. The supported installer correctly refused at its strict signature gate before changing /Applications; signing and Gatekeeper were not bypassed.
  • Two independent exact-head P0/P1 reviews are READY with no P0/P1 findings.

Current-dev refresh (2026-08-15)

  • Exact repaired head: e3eb719a7bd179522ee0fcb92c1707e9fd45da7b, based directly on current dev a765eb27bca4baffabc6dc84c553fc6d8be5590d.
  • Current-dev review found and repaired two lifecycle gaps: approved HTTP plugins no longer enter the stdio-only snapshot path, and remote tool/list/probe execution no longer holds the global snapshot writer lease.
  • Connector execution now uses generation-bound admissions. Revocation is persisted first, aborts and drains only the affected generation, closes its transport, waits for the underlying remote operation to settle, and then permits snapshot collection; unrelated connectors remain available.
  • Failed stdio-exit waits remain retryable instead of replaying one cached rejected close promise.
  • Exact-head gates passed: release 12, frontend 130 plus production build, controller 90, agent runtime 157 (312 assertions), and integration 157/157.
  • Agent-runtime coverage is 40.50% functions / 48.35% lines, up from 40.34% / 48.21% on the first repaired head.
  • An independent exact-head P0/P1 review is READY with no findings. The repair touched no frontend or packaged-desktop behavior, so a new desktop reinstall was not applicable; the earlier packaged acceptance evidence remains unchanged.
  • GitHub Actions for this fork head require maintainer approval before jobs register; this is an external action_required gate, not a reported test failure.
  • Dependent PR [Maintenance] Replace the deprecated unpinned GitHub MCP package #379 must still be rebased and revalidated after this PR merges.

Acceptance criteria

  • Approval changes whenever artifact content, source location, runtime, manifest, command, arguments, environment, or launch configuration changes.
  • Approved code executes only from immutable, verified snapshots with a minimal child environment.
  • Changed, revoked, or disabled grants close and await pooled, creating, closing, queued, direct-probe, and persisted-test children.
  • Active, shared, and disabled-but-approved snapshot identities are retained and recoverable across interrupted publication or cleanup.
  • Snapshot publication is no-clobber; roots and ancestors are private and descriptor-revalidated; cleanup cannot follow a swapped path outside the storage root.
  • Cleanup cannot precede durable state or successful affected-process shutdown; failures remain visible and retryable.
  • Exact-head checks, integration tests, package build, packaged smoke, and two independent P0/P1 reviews pass.

Closes #233

Maintainer review requested in the PR discussion.

@fettpl

fettpl commented Aug 7, 2026

Copy link
Copy Markdown
Author

@0xSero, #372 has been refreshed on current dev and is ready for maintainer review at exact head e3eb719a7bd179522ee0fcb92c1707e9fd45da7b.

The current-dev repair preserves immutable artifact-bound execution while replacing the global remote-call lease with generation-scoped connector admissions. Approved HTTP plugins bypass the stdio-only snapshot verifier; revocation persists first, aborts and drains only the affected generation, closes its transport, waits for the underlying operation to settle, and only then permits collection. Unrelated connectors continue running, and failed stdio-exit waits remain retryable.

Exact-head evidence: release 12, frontend 130 plus production build, controller 90, agent runtime 157 (312 assertions), integration 157/157, and runtime coverage 40.50% functions / 48.35% lines. Independent exact-head P0/P1 review is READY with no findings. The repair touched no frontend/packaged behavior, so no new desktop reinstall was applicable. GitHub Actions is currently an external action_required approval gate rather than a test failure. #379 remains ordered after this PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant