chore: consolidate platform split checks
This commit is contained in:
161
docs/REMOTE_WEBUI_BUNDLES.md
Normal file
161
docs/REMOTE_WEBUI_BUNDLES.md
Normal file
@@ -0,0 +1,161 @@
|
||||
# Remote WebUI Bundle Loading
|
||||
|
||||
GovOPlaN WebUI modules normally ship through the core WebUI package graph:
|
||||
install a tagged npm/git dependency, run `npm install`, rebuild the shell, and
|
||||
restart or reload the served assets. Remote WebUI bundles are an experimental
|
||||
future path for controlled deployments where a backend-enabled module is not in
|
||||
the local WebUI package graph and the operator wants the shell to load its
|
||||
frontend without rebuilding core.
|
||||
|
||||
This design defines the target guardrails. The current rebuild/reload path
|
||||
remains the default production path.
|
||||
|
||||
## Current Rebuild Path
|
||||
|
||||
The supported release path is:
|
||||
|
||||
1. Install or remove backend and WebUI package dependencies through the trusted
|
||||
installer CLI/daemon.
|
||||
2. Snapshot package state before mutation.
|
||||
3. Run `npm install` and optionally `npm run build`.
|
||||
4. Restart or reload the served WebUI assets.
|
||||
5. Use installer rollback if package apply, restart, or health checks fail.
|
||||
|
||||
Strengths:
|
||||
|
||||
- package manager and lockfile semantics stay conventional
|
||||
- CSP can stay strict because all code is served as built assets
|
||||
- rollback restores package files and lockfiles
|
||||
- local development uses sibling workspace dependencies naturally
|
||||
|
||||
Costs:
|
||||
|
||||
- frontend changes require a rebuild/reload
|
||||
- hot enabling a module with frontend code is not possible in the running shell
|
||||
- failed rebuilds happen at install time, not at lazy module-load time
|
||||
|
||||
## Remote Bundle Path
|
||||
|
||||
Remote loading is only for modules that are enabled by the backend and absent
|
||||
from `virtual:govoplan-installed-modules`. The backend manifest exposes:
|
||||
|
||||
- `FrontendModule.asset_manifest`
|
||||
- `asset_manifest_integrity`
|
||||
- `asset_manifest_signature`
|
||||
- `asset_manifest_public_key_id`
|
||||
- `asset_manifest_contract_version`
|
||||
|
||||
The WebUI shell fetches the asset manifest, verifies manifest integrity and/or
|
||||
signature, validates the manifest contract, fetches the entry bundle, verifies
|
||||
the entry integrity, imports the bundle, validates the exported
|
||||
`PlatformWebModule`, and applies backend metadata before registering routes,
|
||||
navigation, and UI capabilities.
|
||||
|
||||
Unsigned and unhashed manifests are skipped. Entries without integrity are
|
||||
skipped. A module id mismatch is skipped.
|
||||
|
||||
## Asset Manifest Contract
|
||||
|
||||
Contract version `1`:
|
||||
|
||||
```json
|
||||
{
|
||||
"contractVersion": "1",
|
||||
"moduleId": "files",
|
||||
"entry": "./files-webui.remote.js",
|
||||
"entryIntegrity": "SHA-256-<base64-or-hex-digest>",
|
||||
"moduleExport": "default"
|
||||
}
|
||||
```
|
||||
|
||||
The backend manifest carries the manifest-level trust metadata. The remote
|
||||
asset manifest carries the concrete entry URL and entry digest.
|
||||
|
||||
## Compatibility Checks
|
||||
|
||||
Before a remote bundle is accepted:
|
||||
|
||||
- backend module must be enabled
|
||||
- local WebUI module with the same id must be absent
|
||||
- manifest contract must be supported by the shell
|
||||
- manifest `moduleId`, exported module `id`, and backend module id must match
|
||||
- backend metadata remains authoritative for label, version, dependencies,
|
||||
nav, and runtime UI capability exposure
|
||||
- future contract versions must declare required shell capabilities so old
|
||||
shells fail closed
|
||||
|
||||
Remote bundles must not broaden backend permissions. They can only contribute
|
||||
routes/nav/capabilities that the backend metadata and existing permission
|
||||
checks allow.
|
||||
|
||||
## CSP
|
||||
|
||||
The current implementation imports verified entry bytes through a blob URL. A
|
||||
production CSP for this mode must explicitly allow:
|
||||
|
||||
- `connect-src` for the approved asset-manifest and bundle origins
|
||||
- `script-src` for `blob:` only when remote loading is enabled
|
||||
- no `unsafe-inline` requirement for remote modules
|
||||
|
||||
If an installation cannot allow `blob:` scripts, the follow-up implementation
|
||||
should use signed same-origin module assets with static URLs instead of blob
|
||||
imports. Remote loading must be disableable by configuration so strict-CSP
|
||||
deployments can keep the rebuild path only.
|
||||
|
||||
## Cache Invalidation
|
||||
|
||||
The shell cache key is:
|
||||
|
||||
```text
|
||||
<module-id>:<asset-manifest-url>:<backend-module-version>
|
||||
```
|
||||
|
||||
Release catalogs should publish immutable manifest and entry URLs or change at
|
||||
least one cache-key component on every release. Emergency rollback can point the
|
||||
backend manifest at a previous immutable manifest URL or lower the enabled
|
||||
module version after the backend package rollback.
|
||||
|
||||
Browsers may still cache remote responses. Approved asset servers should use:
|
||||
|
||||
- long cache lifetimes only for content-addressed immutable assets
|
||||
- short cache lifetimes or explicit revalidation for channel/latest manifest
|
||||
aliases
|
||||
- `Cache-Control: no-store` for emergency override manifests
|
||||
|
||||
## Rollback
|
||||
|
||||
Remote WebUI rollback is metadata rollback, not package-manager rollback:
|
||||
|
||||
- if the backend package install rolls back, the previous backend frontend
|
||||
metadata returns
|
||||
- if only remote assets are bad, publish a new manifest URL or revert the
|
||||
backend/frontend metadata to the last known good manifest
|
||||
- failed remote loading must degrade by omitting the remote module frontend,
|
||||
not by breaking the shell
|
||||
|
||||
Installer run records should eventually include remote asset manifest URLs,
|
||||
integrity, signature key ids, and load-test results when a plan enables a
|
||||
remote frontend.
|
||||
|
||||
## Local And Development Behavior
|
||||
|
||||
Local development should keep using workspace/file dependencies and Vite. Remote
|
||||
loading is useful for integration testing release artifacts, not for day-to-day
|
||||
module UI development.
|
||||
|
||||
Development deployments may use unsigned catalogs and local asset servers only
|
||||
when signature/integrity enforcement is intentionally disabled. The remote
|
||||
loader itself still requires an integrity hash or a verifiable signature.
|
||||
|
||||
## Follow-Up Slices
|
||||
|
||||
1. Add a server-side remote-bundle policy flag and surface whether remote
|
||||
loading is enabled in platform metadata.
|
||||
2. Add CSP documentation/config generation for strict rebuild-only mode versus
|
||||
controlled remote-bundle mode.
|
||||
3. Add an installer/catalog preflight that validates remote WebUI asset
|
||||
manifests and records verified identity in installer run records.
|
||||
4. Add Playwright coverage for a signed test remote bundle, failed digest, bad
|
||||
module id, cache-key refresh, and fallback when the module is unavailable.
|
||||
5. Add release tooling to emit immutable remote asset manifests with digest,
|
||||
signature, key id, and rollback metadata.
|
||||
Reference in New Issue
Block a user