6.6 KiB
id, title, status, system, owners, created, last_updated, requirements
| id | title | status | system | owners | created | last_updated | requirements | ||
|---|---|---|---|---|---|---|---|---|---|
| canvases-local-creation-authority-design | Owner-authorized canvas creation design | draft | canvases |
|
2026-09-10 | 2026-09-23 |
|
Owner-authorized canvas creation design
Boundary and mapping
Canvases owns the creation workflow and its recorded authorization. Plugins
owns grant storage, release activation, and runtime enforcement. This design
implements REQ-CANVASES-LOCAL-CREATION-001; the authority, transaction, and
compatibility sections map to criteria .1-.3, .4-.5, and .6-.7 respectively.
See the creation authority decision, its workspace-data amendment, and plugin grants.
Trusted creation authority
canvasAuthoringService.CreateCanvas is the only production issuer. Resolve
the execution and session through existing trusted MCP context. Resolve the
workspace owner through the task service and retain current access checks.
Do not use workspaceOwner's lookup-error fallback as authorization. An actual
auth-disabled workspace can use its persisted default-user owner; an absent
owner or failed lookup cannot mint authority.
Add a canvas-owned canvas_creation_authority table through
canvas.Repository.SchemaSQL initialization:
| Field | Contract |
|---|---|
canvas_id |
Primary key, references the canvas lifecycle identity |
owner_user_id |
Trusted workspace owner at creation |
creating_session_id |
Trusted source session |
policy_version |
Integer 1 for historical task-data grants; version 2 for new workspace-data grants |
consumed_at |
Empty until the first release transaction consumes it |
Create the row in the canvas/instance creation transaction. No agent-facing tool input can write these fields. Scope and task remain in the existing canvas and instance records. Installation or future import paths do not write this table, even when the resulting package belongs to the same user. Existing databases acquire the empty table; do not backfill authority.
At publication require every predicate: a nonzero captured PublishAuthority,
local-canvas instance source, task scope, matching task and workspace, matching
creating session, unchanged current owner, pending instance, no active or
persisted release, no previous grant changes, and an unconsumed supported
policy version. New authority uses version 2; historical version-1 authority
keeps its task data ceiling and is never upgraded by publication alone.
Check the full instance snapshot again inside the transaction. Re-read the
current task/workspace ownership through the same transaction and serialize
against ownership changes; the adapter's earlier lookup alone is insufficient.
A changed
owner or stale execution fails rather than falling back to inferred ownership.
The trusted adapter supplies the freshly resolved owner; caller-controlled
SourceUserID and SourceActorKind alone are not sufficient.
Grant derivation and transaction
Derive grants from ManifestPermissions and the existing static web-app
capability vocabulary. Version-2 authority binds the approved data scope to
the recorded workspace while the canvas remains task-placed. Historical
version-1 authority retains task data scope. See the
workspace preview design. Normalize each
declared external origin through NormalizeNetworkOrigins; initial external
grants count as delegated owner approval, with that owner as ApprovedBy. A locally
requested app can contact its declared HTTPS service on its first run.
Unsupported capabilities and backend/native contributions cannot gain access
through this path. Do not add a generic manifest-controlled auto-approve flag.
Extend the existing persistAuthorityRelease transaction. Insert the release
with the current CreateReleaseIfAuthorityTx guard, insert only declared
initial grants through a narrow transaction helper in instances.Store, set
the plugin identity, activate through ActivateReleaseTx, and consume the
creation record. Reuse grant normalization and declaration validation. Do not
call the separate public approval transaction after publication.
The zero-permission first release consumes authority too. A transaction failure rolls back all writes. Invalid source rejected before persistence leaves the draft eligible. Grant generation advances through the normal instance writes; authority changes still invalidate issued capabilities. Publish one activation event after commit. Retention and artifact cleanup retain their existing post-commit and failed-publication contracts.
Later publications follow existing permissionsFit behavior. They cannot use
creation authority to restore revoked grants. Consumed rows remain until canvas
removal, so pruning releases cannot restore first-publication eligibility.
Archive/restore never creates a row. Canvas/task/workspace removal deletes the
associated row in its existing cleanup transaction. SQLite and PostgreSQL
schema replay and backup enumeration must include this table.
API and compatibility
Return an additive initial_permission_policy field in the create response:
the policy version, eligibility, placement task, data scope, supported
permission kinds, and exact HTTPS-origin constraint. This is descriptive
output, never a publish input.
It must not claim a permission ceiling that the backend does not enforce.
Keep the existing activated and permission_required publish result fields.
Update the versioned bundled authoring guidance during implementation. Local, Docker, and remote executors use the same trusted path. Existing releases and drafts remain unchanged on upgrade and can still use manual review. Operators do not need to republish an already valid release for the separate embedding policy correction.
Validation and observability
Use authoring_test.go and services_canvas_test.go for owner, session,
source-kind, no-identity, initial grant, subsequent increase, and legacy cases.
Retain TestPublishPackageFirstReleaseRequiresMatchingGrants for canvases
without recorded authority. Add mixed eligible/ineligible instances, concurrent
publication, owner/scope drift, transaction rollback, and revoke/retry cases.
Keep runtime denial tests for foreign tasks and undeclared origins.
Diagnostics can record the policy version and safe result code. They must not record capability URLs, source, network payloads, or grant request bodies.