Files
kandev/docs/plans/canvas-runtime-permission-fixes/plan.md
T
2026-09-20 11:33:30 +01:00

16 KiB

created, status, requirements, system_design, legacy_specs
created status requirements system_design legacy_specs
2026-09-10 done
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
../../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

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. 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.

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.

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

+----------------------------------+
| < 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

The original package 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 retains its pending external ACP evaluation; this repair changes appearance reveal timing but does not complete that evaluation. The MCP prompt package 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 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.