Co-authored-by: ayattara <alassane.yattara@savoirfairelinux.com> Co-authored-by: Carlos Florencio <carlosmflorencio@gmail.com>
4.1 KiB
created, status, requirements, system_design, legacy_specs
| created | status | requirements | system_design | legacy_specs | |||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| 2026-09-07 | done |
|
|
Implementation Plan: Generic Plugin Capability Approval and Audit (H6)
Overview
Add the generic plugin capability-approval substrate as one vertical work
order: host-minted installation identity, the workspace-scoped approval ledger
with exact-revision admission, the append-only event trail, the fail-closed
authorization decision with typed deny reasons, uninstall tombstones with
reinstall identity, the legacy v1 fence, and the audit receipt primitives.
Scope is the substrate only: no approval UI, no coordinator surface, and no
host receipt persistence.
Scope
In scope
installation_idminting and persistence on the plugin store record.- One current
CapabilityApprovalper(installation_id, workspace_id). - Grant, narrow, revoke, and upgrade-review events in an append-only ledger.
- Exact-revision admission and audit-id idempotency.
- Fail-closed
AuthorizeCapabilitywith stable typed deny reasons. - Uninstall tombstone and reinstall identity mints.
- The
host.v2exact-capability fence for legacyv1declarations. ApprovalReceiptand canonical digest primitives.
Out of scope
- Approval or review UI, coordinator surfaces, dashboards.
- Host adapter persistence of audit or read/write receipts.
- Changes to legacy
v1runtime behavior beyond fencing it from approval authority. - H1-H5 plugin capabilities; this initiative is substrate only.
No UI changes
This package does not create or change rendered UI, so no ASCII UI preview is included.
Technical approach
The ledger (approvals.json under the plugins directory) owns approvals,
events, tombstones, and idempotency inputs. One current approval per
installation/workspace pair is stored keyed by the pair with exact next
revision admission; every mutation appends an event carrying before/after
revisions and digests. installation_id is minted at install time and
attached to the store record; reinstall mints fresh identity and tombstones
block the old identity permanently.
The authorization path (approval_service.go) is a pure decision function
that evaluates in a fixed order — malformed request, human-reserved, missing
approval (including the foreign-workspace alias), revoked or tombstoned,
stale revision, manifest intersection, approved list — and returns a typed
decision carrying the audit identity and a bounded receipt. Legacy v1
declarations keep their behavior but are fenced from approval admission and
authorization.
Tests
approval_test.go,approval_store_test.go,approval_service_test.go: canonicalization, exact-revision admission, idempotency, tombstone, and reinstall-identity coverage.approval_api_test.go,approval_query_test.go: API list/get, grant, and revoke flows including conflict semantics.approval_dto_test.go: DTO shape and receipt bounds.- Store install/sync tests:
installation_idminting and persistence.
E2E tests
No new E2E is required: the substrate exposes no UI surface. Go unit and integration tests exercise the full ledger and decision matrix; a browser duplicate of that matrix would add cost without observable UI coverage.
Work orders
Verification results
cd apps/backend && go build ./...passed on the H6 head and was re-verified on the merged head.cd apps/backend && go test ./internal/plugins/...passed in 10 packages on the H6 head and was re-verified on the merged head.
Risks
- Ledger file corruption must not grant authority: unknown fields decode forward-compatibly and missing maps initialize empty, but any decode failure must fail closed at lookup.
- A future policy revision must not silently reinterpret stored approvals: the per-row human policy version is the stability point.