320 lines
16 KiB
Markdown
320 lines
16 KiB
Markdown
---
|
|
created: 2026-09-10
|
|
status: done
|
|
requirements:
|
|
- REQ-PLUGINS-ISOLATED-WEB-APPS-007
|
|
- REQ-PLUGINS-ISOLATED-WEB-APPS-012
|
|
- REQ-CANVASES-LOCAL-CREATION-001
|
|
- REQ-CANVASES-AGENT-WEB-APPS-001
|
|
- REQ-CANVASES-AGENT-WEB-APPS-003
|
|
- REQ-CANVASES-AGENT-WEB-APPS-006
|
|
- REQ-CANVASES-AGENT-WEB-APPS-007
|
|
system_design:
|
|
- ../../specs/plugins/system-design/isolated-web-app-contributions.md
|
|
- ../../specs/canvases/system-design/local-creation-authority.md
|
|
- ../../specs/canvases/system-design/agent-authored-web-apps.md
|
|
legacy_specs: []
|
|
---
|
|
|
|
# Implementation Plan: Canvas runtime and permission fixes
|
|
|
|
## Overview
|
|
|
|
Make the published canvas load through any same-origin Kandev hostname, remove
|
|
duplicate consent for owner-authorized first publication, show accurate startup
|
|
state, and make release review readable on desktop and phone.
|
|
|
|
Execute four work orders sequentially. Correct the confirmed hosting blocker
|
|
first. Add initial creation authority next, then startup detection, then the
|
|
review surface. Each order has its own regression evidence; this package does
|
|
not authorize implementation, deployment, or changes to the reported live task.
|
|
|
|
## Evidence and conformance
|
|
|
|
The investigation used task `00d2d513-3601-4413-9fe2-024b0b23cb17`, canvas
|
|
`65421ec3-89ad-4886-a5d6-750c217d26b5`, release
|
|
`cf3b3eb8-a562-4dfb-83c6-ef44072f7364`. On 2026-09-10, the public runtime
|
|
document returned HTTP 200 but allowed only localhost and Tauri ancestors.
|
|
The actual parent, `https://kandev.cfl.tools`, was absent. Approval succeeded
|
|
at 20:32:30 UTC; context, task, workflow, and step endpoints then returned
|
|
successfully. No end-to-end success after a policy fix has yet been observed.
|
|
The retained diagnostic bundle has truncated historical logs; absence of a log
|
|
entry was not used to infer success.
|
|
|
|
| Finding | Classification | Authoritative criteria |
|
|
| --- | --- | --- |
|
|
| Custom public origin blocked | Implementation/design gap | `AC-PLUGINS-ISOLATED-WEB-APPS-007.8`, `.10` |
|
|
| Initial owner permission gate | Intended behavior change | `AC-CANVASES-LOCAL-CREATION-001.1` through `.7`; amended canvas `.003.4/.5` |
|
|
| URL/load event reported Ready | Missing startup contract | `AC-PLUGINS-ISOLATED-WEB-APPS-012.1` through `.4`; canvas `.007.5/.6` |
|
|
| UUIDs, duplication, hidden actions | Existing UX gap plus measurable criteria | canvas `.006.8/.9`, `.007.4/.7/.8` |
|
|
|
|
The plugin system owns shared runtime policy and lifecycle signalling.
|
|
Canvases owns local creation authority and release-review outcomes. The paired
|
|
designs link these boundaries instead of creating a separate UI specification.
|
|
|
|
## Scope
|
|
|
|
### In scope
|
|
|
|
- Host-owned `frame-ancestors 'self'` plus existing exact launcher/Tauri origins.
|
|
- Two custom HTTPS hostnames, localhost, and unrelated-parent browser evidence.
|
|
- Single-use recorded owner authority for a new draft's first release.
|
|
- Exact initial grants for supported task data, events, state, and HTTPS origins.
|
|
- Preserved later review, revocation, migration, and promotion behavior.
|
|
- Host-provided startup detection for retained and new packages.
|
|
- Readable release/source labels, grouped permissions, and fixed review actions.
|
|
- Desktop and phone verification, authoring guidance, and public documentation
|
|
updates during implementation.
|
|
|
|
### Out of scope
|
|
|
|
- Marketplace/import implementation, package export, or cross-instance sharing.
|
|
- A public-origin setting or automatic trust of forwarded request headers.
|
|
- Unlimited framing, `allow-same-origin`, or a privileged iframe SDK.
|
|
- Ongoing automatic approval for later permission increases.
|
|
- Repairing, republishing, or changing permissions on the reported live canvas.
|
|
- Workflow-wide data access for task canvases or historical transition APIs.
|
|
- Feature-flag identities, profile defaults, and rollout changes.
|
|
|
|
## Technical approach
|
|
|
|
### 01: Same-origin embedding
|
|
|
|
`webapp.BuildContentSecurityPolicy` adds the CSP keyword separately from the
|
|
exact-origin normalizer. Keep `FrameAncestorsForConfig` and provider wiring for
|
|
explicit development/desktop exceptions. The public browser origin comes from
|
|
the response URL through CSP semantics, not request-header parsing. Reuse the
|
|
runtime's relative capability URLs. No database change is involved.
|
|
|
|
### 02: Owner-authorized first publication
|
|
|
|
Implement the new [creation design](../../specs/canvases/system-design/local-creation-authority.md).
|
|
The adapter records creation authority in the canvas creation transaction.
|
|
The first publish consumes it with grants and activation in the existing
|
|
authority-fenced transaction. Existing drafts have no authority row. Neither
|
|
source metadata nor workspace ownership of an import is sufficient.
|
|
|
|
This is a deliberate initial delegation, including exact HTTPS origins. Later
|
|
changes remain reviewable. Retain legacy/manual approval fixtures and add
|
|
separate real owner-created fixtures; do not delete approval coverage just
|
|
because the creation happy path no longer needs it.
|
|
|
|
### 03: Runtime startup
|
|
|
|
Insert a bounded host bootstrap into the served entry representation without
|
|
changing stored artifacts. `WebAppFrame` uses a per-mount probe/result exchange
|
|
with exact-window and nonce checks. Its 15-second deadline is distinct from
|
|
capability expiry. `CanvasHostSurface` mounts during `loading_runtime`; a
|
|
descriptor alone must not set Ready. Failed startup tears down the frame and
|
|
shows recovery. Preserve theme-before-reveal and immediate authority teardown.
|
|
|
|
### 04: Release review
|
|
|
|
Extend authorized HTTP projections with optional readable source labels.
|
|
Keep IDs as action identities, not visible copy. Use one selected release,
|
|
defaulting to pending then active, one permission summary, and fixed actions.
|
|
Distinguish Active, Previous, Pending review, Invalid, and Unavailable.
|
|
Promotion reuses permission/provenance copy without changing confirmation
|
|
preconditions. Reuse localization catalogs for all host copy.
|
|
|
|
## ASCII UI preview
|
|
|
|
Structural requirements are selection, hierarchy, scroll ownership, and fixed
|
|
actions. Text and spacing below are illustrative; all UI copy is localized.
|
|
|
|
### UI-01: Canvas startup, task panel or focused route
|
|
|
|
Desktop and phone share the state sequence. Phone keeps its existing focused
|
|
route and visible Back/overflow controls.
|
|
|
|
```text
|
|
Before: Live workflow | Ready
|
|
[ browser error page inside frame ]
|
|
|
|
After: Live workflow | Loading...
|
|
[ covered frame awaiting startup ]
|
|
| acknowledgement | deadline/failure
|
|
v v
|
|
Ready Canvas could not start
|
|
[ application ] [Retry] [Releases]
|
|
```
|
|
|
|
`AC-CANVASES-AGENT-WEB-APPS-007.5/.6` and plugin `.012.1-.4`.
|
|
Host controls remain outside the failed frame. Do not diagnose CSP from timeout
|
|
alone. Offline and permission-review states keep their existing meanings.
|
|
|
|
### UI-02: Desktop Releases and permissions, pending release selected
|
|
|
|
Entry: canvas host Releases and permissions, or the equivalent workspace action.
|
|
|
|
```text
|
|
Before: [ release UUID Pending ]
|
|
[ Declared permissions ]
|
|
[ Missing permissions, repeated ] <- 288px scroller
|
|
[ source UUIDs ... Approve/Reject below ]
|
|
|
|
After: +-------------------------------------------------------+
|
|
| Live workflow: Releases and permissions [X] | fixed
|
|
| Release [10 Sep, 21:27 v] Pending review |
|
|
| Created by your agent |
|
|
| From: Recreate live workflow diagram canvas |
|
|
|-------------------------------------------------------|
|
|
| Requested access in this task | single
|
|
| Read tasks New | scroll
|
|
| Read workflows New | region
|
|
| [Additional details, if needed] |
|
|
|-------------------------------------------------------|
|
|
| [Reject] [Approve and open] | fixed
|
|
+-------------------------------------------------------+
|
|
```
|
|
|
|
Target maximum width 48rem, bounded by available width and height. At
|
|
1280x720, the simple two-permission case needs no scroll. Selecting a previous
|
|
release replaces the footer with Roll back; the current active release has
|
|
Close. Empty history and failed fetch have readable states; failed mutations
|
|
keep selection and show an inline error. Pending review is not a red validation
|
|
failure. Missing source labels say unavailable, never a UUID.
|
|
|
|
### UI-03: Phone review, pending release selected
|
|
|
|
```text
|
|
+----------------------------------+
|
|
| < Back Releases and permissions| fixed
|
|
| Live workflow |
|
|
| Release [10 Sep, 21:27 v] |
|
|
| Pending review |
|
|
|----------------------------------|
|
|
| Created by your agent | single
|
|
| From: Recreate live workflow... | scroll
|
|
| | region
|
|
| Access in this task |
|
|
| Read tasks New |
|
|
| Read workflows New |
|
|
| ... additional permissions ... |
|
|
|----------------------------------|
|
|
| [Reject] [Approve and open] | fixed, >=44px targets
|
|
| bottom safe area |
|
|
+----------------------------------+
|
|
```
|
|
|
|
This review is a full-height mobile surface because it can contain detailed
|
|
permissions and release history. The existing host action chooser remains an
|
|
inset drawer. Reuse `task-layout.tsx`'s focused composition and
|
|
`mobile-menu-sheet.tsx`'s fixed header/internal scroll/safe-area mechanics.
|
|
Shared selection and mutations prevent desktop/mobile behavior drift.
|
|
Test at 390x844, 767px, and 768px widths; focus returns to the opener.
|
|
UI-02/03 map to canvas `.006.8/.9`, `.007.4/.7/.8`.
|
|
|
|
## Tests
|
|
|
|
Proposed regression names are implementation targets, not existing evidence.
|
|
|
|
| Work order / criteria | Regression and location |
|
|
| --- | --- |
|
|
| 01 / plugin `.007.8/.10` | `TestBuildContentSecurityPolicyIncludesSelf` in `policy_test.go`; runtime headers in `runtime_test.go` |
|
|
| 02 / local creation `.001.1-.7` | `TestCanvasCreationAuthorityFirstPublish`, identity/migration/rollback/race variants in canvas `authoring_test.go`, `canvas_test.go`, backendapp `services_canvas_test.go`, instance `store_test.go` |
|
|
| 02 / preserved canvas `.003.4/.5` | Keep `TestPublishPackageFirstReleaseRequiresMatchingGrants` for no-authority instances and later-expansion approval tests |
|
|
| 03 / plugin `.012.1-.4`, canvas `.007.5/.6` | `TestRuntimeStartupBootstrapPreservesArtifact` in `runtime_test.go`; nonce/timeout tests in new `web-app-startup.test.ts`; host loading/retry tests in existing component suites |
|
|
| 04 / canvas `.006.8/.9`, `.007.4/.7/.8` | Label authorization in backendapp canvas tests; copy/view-model tests and `canvas-lifecycle-dialogs.test.tsx`; viewport assertions in desktop/mobile E2E |
|
|
|
|
## E2E tests
|
|
|
|
- New `tests/canvas/canvas-host-origins.spec.ts` (`chromium`): an isolated TLS
|
|
reverse proxy serves actual runtime responses through `canvas-a.example.test`
|
|
and `canvas-b.example.test`; same-origin frames execute under each host.
|
|
`unrelated.example.test` framing canvas A is blocked, including a nested
|
|
foreign ancestor. Header forwarding must not alter trust. Preserve CSP in
|
|
the proxy and assert actual rendered content. Use scoped test certificates
|
|
and browser-local routing/proxy configuration; never edit system DNS or
|
|
contact those names externally. Reuse TLS fixture mechanics from
|
|
`helpers/plugin-git-credentials.ts`, without its Git or Docker machinery.
|
|
- `tests/canvas/plugin-canvas.spec.ts` (`chromium`): first owner publication
|
|
opens without approval; a later permission increase still requires review;
|
|
startup failure, retry, retained package, and desktop dialog geometry.
|
|
- `tests/canvas/mobile-plugin-canvas.spec.ts` (`mobile-chrome`): automatic
|
|
first open, startup recovery, full-height review, long permissions, fixed
|
|
44px actions, source fallback, focus return, and no horizontal overflow.
|
|
- Preserve promotion, rollback, task scope, live data, theme, and revocation
|
|
scenarios already in both files. The managed runner rebuilds product code.
|
|
|
|
Run commands are in each work order. Fresh worktree prerequisite:
|
|
`(cd apps && pnpm install --frozen-lockfile)`. Run desktop and mobile commands
|
|
separately with one worker per shard and retries disabled. Start observers
|
|
before stimuli; use causal waits and fake clocks for deadline tests.
|
|
|
|
## Work orders
|
|
|
|
- [x] [Task 01: Support same-origin canvas embedding](task-01-same-origin-embedding.md)
|
|
- [x] [Task 02: Authorize initial owner publication](task-02-initial-owner-publication.md)
|
|
- [x] [Task 03: Detect canvas startup](task-03-runtime-startup.md)
|
|
- [x] [Task 04: Make release review readable](task-04-release-review.md)
|
|
|
|
## Related delivery records
|
|
|
|
The [original package](../plugin-backed-canvases/plan.md) is historical completed
|
|
work. This repair supersedes its framing, load-as-ready, initial-approval, and
|
|
review-layout assumptions, not its recorded test results. The
|
|
[UX follow-up](../plugin-backed-canvases-ux-follow-up/plan.md) retains its pending
|
|
external ACP evaluation; this repair changes appearance reveal timing but does
|
|
not complete that evaluation. The
|
|
[MCP prompt package](../mcp-discovery-canvas-prompts/plan.md) retains its discovery
|
|
scope. Its conditional permission-review wording remains valid.
|
|
|
|
## Verification results
|
|
|
|
Design validation on 2026-09-10:
|
|
|
|
- `python3 scripts/lint-spec-files.test.py`: passed, 36 tests.
|
|
- `python3 scripts/lint-spec-files.py --all`: passed.
|
|
- Package link/reference check: all local Markdown targets exist; all 40
|
|
frontmatter requirement/acceptance references exist in the specification set.
|
|
- `git diff --check`: passed.
|
|
- `git status --short -- docs/plans/canvas-runtime-permission-fixes`: confirmed
|
|
the new manifest and all four work orders are present for staging.
|
|
|
|
Task 01 implementation verification completed on 2026-09-10:
|
|
|
|
- `(cd apps/backend && go test ./internal/plugins/webapp/...)`: passed, 30 tests.
|
|
- `(cd apps/web && pnpm e2e:run --project chromium tests/canvas/canvas-host-origins.spec.ts -- --retries=0)`: passed, 1 test.
|
|
- `node --test scripts/validate-public-docs.test.mjs`: passed, 62 tests.
|
|
- `node scripts/validate-public-docs.mjs`: passed, 46 published docs pages.
|
|
- `git diff --check`: passed.
|
|
|
|
Task 02 implementation verification completed on 2026-09-10:
|
|
|
|
- `(cd apps/backend && go test ./internal/canvas/... ./internal/plugins/instances/...)`: passed, 49 tests.
|
|
- `(cd apps/backend && go test ./internal/backendapp -run 'Canvas' -count=1)`: passed, 23 tests.
|
|
- `(cd apps/backend && go test ./internal/mcp/canvasskill ./internal/mcp/handlers -run 'Canvas|Bundle|Scaffold' -count=1)`: passed, 12 tests.
|
|
- `(cd apps/web && pnpm e2e:run --host --no-build --project chromium tests/canvas/plugin-canvas.spec.ts -- --retries=0)`: passed, 2 tests.
|
|
- `(cd apps/web && pnpm e2e:run --host --no-build --project mobile-chrome tests/canvas/mobile-plugin-canvas.spec.ts -- --retries=0)`: passed, 3 tests.
|
|
- Public-doc tests/validator, specification lint, and `git diff --check`: passed.
|
|
|
|
Tasks 03 and 04 implementation verification completed on 2026-09-11:
|
|
|
|
- `(cd apps/backend && go test ./internal/canvas ./internal/plugins/webapp ./internal/backendapp ./internal/plugins/instances)`: passed, 955 tests.
|
|
- `(cd apps/web && pnpm exec vitest run components/plugins/web-app-frame.test.tsx components/plugins/web-app-startup.test.ts components/settings/canvas-lifecycle-dialogs.test.tsx lib/canvas-permission-copy.test.ts)`: passed, 30 tests.
|
|
- `(cd apps/web && pnpm run typecheck)`: passed.
|
|
- `(cd apps/web && pnpm run i18n:check)`: passed.
|
|
- Scoped frontend ESLint and `git diff --check`: passed.
|
|
|
|
## Risks
|
|
|
|
- Initial local code receives declared writes and network access through the
|
|
owner's creation delegation. A wrong authority source can expand access.
|
|
- Grant insertion and authority consumption must share the existing publication
|
|
transaction; retention or retry must not recreate authority.
|
|
- HTML bootstrap insertion can break doctype, nested paths, encoding, or length
|
|
headers. Stored artifact bytes must remain unchanged.
|
|
- A startup acknowledgement proves document/context startup, not application
|
|
correctness. It must not become a privileged message bridge.
|
|
- Review source labels need current authorization and graceful deletion fallback.
|
|
- Concurrent branches may touch the shared canvas E2E fixture or spec pair;
|
|
reconcile current base before implementation and final delivery.
|
|
|
|
## Same-origin follow-up
|
|
|
|
The [trusted same-origin package](../canvas-same-origin-auth/plan.md) supersedes
|
|
this package's opaque-origin and cookie-isolation assumptions. Existing results
|
|
record the earlier implementation. They do not verify the new runtime behavior.
|
|
The follow-up work orders own the replacement tests and documentation.
|