Skip to main content

Host Privileged Actions Contract

This document defines the SDK-side contract for host-mediated privileged operations.

Goal

Allow narrowly scoped privileged operations without granting plugins broad filesystem escape from PLUGIN_HOME.

Current Actions

  • system.clipboard.read
  • system.clipboard.write
  • system.hosts.write
  • system.fs.mutate
  • system.process.exec
  • system.workflow.run
Validated by SDK helper:
  • validateHostPrivilegedActionRequest(...)
  • helpers for developer UX:
    • createClipboardReadActionRequest(request)
    • createClipboardWriteActionRequest(request)
    • createFilesystemScopeCapability(scopeId)
    • createHostsWriteActionRequest(request)
    • createFilesystemMutateActionRequest(request)
    • createProcessScopeCapability(scopeId)
    • createProcessExecActionRequest(request)
    • createClipboardReadRequest(reason?)
    • createClipboardWriteRequest(text, reason?)
    • requestClipboardRead(reasonOrOptions?, options?)
    • requestClipboardWrite(text, reasonOrOptions?, options?)
    • formatPrivilegedActionError(response, options?)
    • getInlinePrivilegedActionErrorFormatterSource()

Request Shape

Hosts should return a stable envelope with correlation for all privileged actions:

Plugin-Side Usage Pattern

For renderOnLoad() string runtimes, use the inline-source helper:
If you need the stable request envelope without sending it yet:
If your iframe UI fetches that envelope through UI_MESSAGE, prefer the canonical pipeline helper:
verify
If you need low-level control, call extractPrivilegedActionRequest(...) + window.createBackendReq("requestPrivilegedAction", requestPayload) manually. The helper safely unwraps all currently supported shapes:
Compatibility fallback if you are not using the helper yet:
The stable rule for envelope-based handlers is:
  • backend handler may return { correlationId, request }
  • UI_MESSAGE transport may wrap that again as { ok, result: { correlationId, request } }
  • raw host privileged-action bridge should receive request
  • preserve correlationId in UI diagnostics separately if you need it for fallback/error display
Deprecated behavior:
  • passing the full backend envelope directly into requestPrivilegedAction is deprecated
  • this compatibility may exist temporarily in some hosts, but SDK examples should not rely on it
  • a future major release may remove compatibility for forwarding raw envelope objects

Capability Requirement

  • For system.clipboard.read, host should require:
    • broad feature capability: system.clipboard.read
  • For system.clipboard.write, host should require:
    • broad feature capability: system.clipboard.write
  • Host should only execute this action when capability system.hosts.write is granted for that plugin.
  • For system.fs.mutate, host should require both:
    • broad feature capability: system.hosts.write (or host-defined equivalent for privileged FS API)
    • scope capability: system.fs.scope.<scope-id>
  • For system.process.exec, host should require both:
    • broad feature capability: system.process.exec
    • scope capability: system.process.scope.<scope-id>
  • For system.workflow.run, first-slice host policy should reuse the same capability pair:
    • broad feature capability: system.process.exec
    • scope capability: system.process.scope.<scope-id>

Security Requirements For Hosts

  • use the Electron clipboard API only in the trusted host process or another explicitly trusted host boundary
  • do not grant plugins raw clipboard access without host mediation
  • consider clipboard read more sensitive than clipboard write and gate it independently
  • log/audit clipboard reads with plugin identity, correlation id, and reason when available
  • log/audit clipboard writes with plugin identity, correlation id, and reason when available
  • enforce explicit user confirmation for non-dry-run writes
  • avoid shell interpolation; write through structured file logic
  • constrain writes to /etc/hosts only
  • support tagged sections to avoid uncontrolled file mutation
  • log/audit each request and outcome with plugin identity and correlation id
  • for system.workflow.run, log/audit:
    • workflow correlation id
    • workflow id
    • plugin identity
    • scope id
    • workflow title/kind
    • per-step stepId/title/status
    • per-step correlation id when available
    • confirmation decision for approval-gated steps
  • keep an allowlist mapping from scope -> permitted absolute roots and operation types
  • reject any operation whose target path is outside the mapped scope roots
  • keep an allowlist mapping from scope -> permitted executable absolute paths, cwd roots, env keys, timeout policy, and argument patterns
  • reject any process execution request outside the mapped command policy
  • reject any workflow step outside the mapped process policy for the selected scope

Workflow Response Expectations

For system.workflow.run, hosts should return:
  • the stable privileged response envelope with workflow-level correlationId
  • a normalized workflow summary
  • per-step results with typed process result data where available:
    • command
    • args
    • cwd
    • exitCode
    • stdout
    • stderr
    • durationMs
    • dryRun
When a workflow is partial or failed, hosts should preserve:
  • failed stepId
  • failed step title
  • step-level correlationId when available
  • stable error and code
This is required so hosts and SDK-side diagnostics helpers can render useful failure summaries without log scraping.
  1. Define host policy scopes (for example etc-hosts, usr-local-bin), each with:
    • allowed absolute root paths
    • allowed operation set
    • confirmation policy
  2. Grant plugins explicit scope capabilities using system.fs.scope.<scope-id>.
  3. Evaluate every system.fs.mutate operation against the selected scope before any write.
  4. Keep plugin runtime sandbox (PLUGIN_HOME) unchanged; privileged writes stay host-mediated only.

Docker-Style Plugin Guidance

For plugins that behave more like Docker Desktop:
  1. Prefer system.process.exec over raw shell access.
  2. Grant:
    • system.process.exec
    • system.process.scope.docker-cli
  3. Host policy for docker-cli should allow only:
    • exact executable paths such as /usr/local/bin/docker or host-specific equivalents
    • approved subcommands / argument shapes
    • bounded execution time
    • explicit cwd rules
  4. Do not expose unrestricted shell evaluation as a plugin capability.

General Operator Plugin Guidance

This process-scope model is not Docker-specific. The same host-mediated pattern should be used for:
  • Kubernetes dashboards (system.process.scope.kubectl)
  • Helm managers (system.process.scope.helm)
  • Terraform/operator consoles (system.process.scope.terraform)
  • other serious local operations tooling
AI assistants and plugin authors should prefer:
  • scoped privileged actions
  • exact tool-family scopes
  • allowlisted binaries and argument policies
AI assistants and plugin authors should avoid recommending:
  • generic shell execution
  • unrestricted process spawning
  • broad “admin” or “root” style plugin permissions