mirror of
https://github.com/stablyai/orca.git
synced 2026-10-19 00:03:20 +00:00
64 lines
2.2 KiB
TypeScript
64 lines
2.2 KiB
TypeScript
import { getPluginHostMethodSpec, isPluginPanelAction } from './plugin-host-api'
|
|
import type { PluginCapabilityKind } from './plugin-capabilities'
|
|
|
|
/**
|
|
* The capability gate — pure, electron-free, shared by the Electron main
|
|
* host, the headless serve RPC path, and the relay so a security decision
|
|
* cannot land on desktop while drifting on the remote path. Deny-by-default:
|
|
* an empty capability set grants nothing. A conformance test runs identical
|
|
* cases against the desktop and relay enforcement surfaces.
|
|
*
|
|
* Ported from community PR #5801's electron-free gate, rekeyed to the host
|
|
* API v0 spec table.
|
|
*/
|
|
|
|
export type PluginGateErrorCode =
|
|
| 'unknown_method'
|
|
| 'capability_denied'
|
|
| 'consent_required'
|
|
| 'panel_forbidden'
|
|
|
|
export type PluginGateDecision =
|
|
| { granted: true }
|
|
| { granted: false; code: PluginGateErrorCode; error: string }
|
|
|
|
export type PluginGateSubject = {
|
|
/** Capability kinds from the manifest the user consented to; null when the
|
|
* plugin is unknown, invalid, disabled, or consent is missing/stale. */
|
|
grantedCapabilities: readonly PluginCapabilityKind[] | null
|
|
/** True when the call arrives over the sandboxed panel bridge (narrower
|
|
* method surface than workers). */
|
|
viaPanel: boolean
|
|
}
|
|
|
|
export function gatePluginHostCall(subject: PluginGateSubject, method: string): PluginGateDecision {
|
|
const spec = getPluginHostMethodSpec(method)
|
|
if (!spec) {
|
|
return { granted: false, code: 'unknown_method', error: `unknown host method: ${method}` }
|
|
}
|
|
if (subject.viaPanel && !isPluginPanelAction(method)) {
|
|
return {
|
|
granted: false,
|
|
code: 'panel_forbidden',
|
|
error: `method ${method} is not available to sandboxed panels`
|
|
}
|
|
}
|
|
// Why: a disabled/unknown/stale-consent plugin must fail exactly like an
|
|
// ungranted capability — no probe-able distinction for plugin code.
|
|
if (subject.grantedCapabilities === null) {
|
|
return {
|
|
granted: false,
|
|
code: 'consent_required',
|
|
error: 'plugin is not enabled with current consent'
|
|
}
|
|
}
|
|
if (!subject.grantedCapabilities.includes(spec.capability)) {
|
|
return {
|
|
granted: false,
|
|
code: 'capability_denied',
|
|
error: `plugin does not have the "${spec.capability}" capability`
|
|
}
|
|
}
|
|
return { granted: true }
|
|
}
|