Track HiveGrid Cloud planning reference
This commit is contained in:
1 parent
b3d5ea6764
commit
e341c5938a
5784 files changed
+1104929
-3
No files matched your search
@@ -0,0 +1,83 @@
|
||||
# Capability Matrix
|
||||
|
||||
Every host function exposed to a plugin sits behind a capability. The
|
||||
manifest must declare a capability before the runtime binds the
|
||||
corresponding host functions; calling an undeclared host-fn throws
|
||||
`CapabilityDeniedError` and audits as `outcome=denied`.
|
||||
|
||||
## Closed enum
|
||||
|
||||
The runtime maintains a closed enum of capability names in
|
||||
`packages/plugin-runtime/src/capabilities.ts`. Anything outside this
|
||||
list is rejected at manifest parse time.
|
||||
|
||||
| Capability | Risk | Host binding availability | Unlocks / intended binding | Scope shape |
|
||||
| ---------------- | -------- | ------------------------- | --------------------------------------------------------------- | ----------------------------------------- |
|
||||
| `log` | none | available | `ctx.log.{info,warn,error}` - structured logging into host pino | none |
|
||||
| `audit` | none | available | `ctx.audit.record({ action, target?, meta? })` | none |
|
||||
| `tenant.info` | low | reserved / fail-closed | Reserved tenant metadata binding; not bound today | none |
|
||||
| `secret.read` | medium | reserved / fail-closed | Reserved per-tenant secret reads; not bound today | `{ keyPattern: "^slack-" }` planned |
|
||||
| `storage.read` | medium | reserved / fail-closed | Reserved tenant-scoped key/value reads; not bound today | per-prefix locking planned |
|
||||
| `storage.write` | medium | reserved / fail-closed | Reserved tenant-scoped key/value writes; not bound today | per-prefix locking planned |
|
||||
| `http.outbound` | high | reserved / fail-closed | Reserved outbound fetch binding; not bound today | `{ allowedHosts: ["hooks.slack.com"] }` |
|
||||
| `db.read` | high | reserved / fail-closed | Reserved DB binding for marketplace work; not bound today | `{ tablePrefix: "tx_" }` planned |
|
||||
| `db.write` | critical | reserved / fail-closed | Reserved DB binding for marketplace work; not bound today | `{ tablePrefix: "tx_" }` planned |
|
||||
|
||||
`PLUGIN_CAPABILITY_NAMES` is intentionally broader than the production host
|
||||
binding set. As of this foundation, `PLUGIN_AVAILABLE_HOST_CAPABILITY_NAMES`
|
||||
contains only `log` and `audit`; declaring higher-risk capabilities parses, but
|
||||
production install/grant/enable paths reject them until their bindings, tests,
|
||||
and security review ship.
|
||||
|
||||
## Risk legend
|
||||
|
||||
- **none** — no tenant data, no outbound — safe for any plugin.
|
||||
- **low** — tenant identity only; no payload exposure.
|
||||
- **medium** — touches per-tenant data inside the host; operator
|
||||
review recommended.
|
||||
- **high** — issues network requests OR reads tenant business data;
|
||||
audit-trail required and operator must explicitly approve at install.
|
||||
- **critical** — mutates tenant business data; install requires
|
||||
out-of-band operator sign-off; auto-disable on the slightest
|
||||
anomaly.
|
||||
|
||||
## Common pitfalls
|
||||
|
||||
- **Declaring `http.outbound` without `allowedHosts`** is the most
|
||||
common authoring mistake. The runtime denies every request unless
|
||||
the host appears in the allowlist. The lint command warns on this
|
||||
shape.
|
||||
- **Assuming `db.read` is bound today** — the DB capability is
|
||||
reserved-only in the foundation. A plugin that declares it parses
|
||||
fine but the host returns `no_host_implementation` on call.
|
||||
- **Using `audit` as a payload queue** — see the async-task example;
|
||||
the audit body has a cap. Pass identifiers, not blobs.
|
||||
|
||||
## How to request a new capability
|
||||
|
||||
1. Propose the name (lowercase, dot-separated).
|
||||
2. Write a one-paragraph threat model: what data can leak, what
|
||||
privileges are gained, what reverse-direction trust does the
|
||||
capability imply?
|
||||
3. Add to `PLUGIN_CAPABILITY_NAMES` in `capabilities.ts`.
|
||||
4. Add the host-fn implementation in `capability-gateway.ts` via the
|
||||
provided `hostFns` map; never bypass the gateway.
|
||||
5. Update this table.
|
||||
6. Operator-side: external security review when the new capability
|
||||
ships in production (Phase 06 #23 sign-off — see audit-docs.md).
|
||||
|
||||
## Audit trail mapping
|
||||
|
||||
Every successful or failed call to a host-fn produces one row in
|
||||
`PluginCapabilityUse`:
|
||||
|
||||
| Column | Meaning |
|
||||
| ------------------- | ---------------------------------------------------- |
|
||||
| `capability` | Capability name (e.g. `http.outbound`) |
|
||||
| `outcome` | `success` / `denied` / `error` |
|
||||
| `payloadHash` | SHA-256 of stable call descriptor; never the body |
|
||||
| `durationMs` | Time spent in the host-fn (excluding gateway frame) |
|
||||
| `errorCode` | Short code on `denied` / `error` (e.g. `not_declared_in_manifest`) |
|
||||
|
||||
Tenant admins see this list under
|
||||
`/app/:tenant/settings/plugins/:id/audit`.
|
||||
Reference in new issue
Block a user