Some checks are pending
Bidi Control Character Guard / bidi-control-guard (push) Waiting to run
Circular Dependency Check / Check for new circular dependencies (push) Waiting to run
Citus Migration Smoke / Combined migrations on single-node Citus (push) Waiting to run
E2E Fresh Install Tests / fresh-install-e2e (push) Waiting to run
ext-v2 guardrails / Run ext-v2 guard and ESLint (push) Waiting to run
Integration Tests / Check for relevant changes (push) Waiting to run
Integration Tests / ${{ (github.event_name == 'schedule' || github.event.inputs.suite == 'full') && 'Full integration suite' || 'Tier-1 integration subset' }} (push) Blocked by required conditions
Mobile checks / Mobile lint + typecheck (push) Waiting to run
Mobile checks / Mobile unit tests (push) Waiting to run
Mobile checks / Mobile dependency audit (report) (push) Waiting to run
Mobile checks / Mobile reproducibility checks (push) Waiting to run
Secrets guard (env backups) / Ensure no tracked env backup files (push) Waiting to run
Temporal Readiness / fast-readiness (push) Waiting to run
Temporal Readiness / docker-parity (push) Waiting to run
TypeScript Type Check / Nx affected typecheck (push) Waiting to run
Unit Tests / Skipped-test budget (push) Waiting to run
Unit Tests / Nx affected unit tests (push) Waiting to run
Unit Tests / Server unit coverage (informational) (push) Waiting to run
Validate Tenant Management Schema / Check for relevant changes (push) Waiting to run
Validate Tenant Management Schema / Validate Tenant Management Schema (push) Blocked by required conditions
EE Workflows Build Guard / ee-workflows-build-guard (push) Waiting to run
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz Source: /opt/alga-psa on psa.joliet.tech
118 lines
5.8 KiB
Markdown
118 lines
5.8 KiB
Markdown
# Runner S3 Integration Guide
|
||
|
||
This document specifies how the Runner integrates with S3-compatible storage (e.g., MinIO) to fetch extension bundles by content hash and serve static UI assets.
|
||
|
||
Links:
|
||
- Overview: [ee/docs/extension-system/overview.md](ee/docs/extension-system/overview.md:1)
|
||
- Serving system: [ee/docs/extension-system/serving-system.md](ee/docs/extension-system/serving-system.md:1)
|
||
|
||
## Responsibilities
|
||
|
||
- Fetch and cache extension bundle by content hash:
|
||
- Download canonical object from S3 at:
|
||
- sha256/<content_hash>/bundle.tar.zst
|
||
- sha256/<content_hash>/manifest.json
|
||
- Verify integrity (content hash, size if provided), and only accept immutable artifacts.
|
||
- Serve extension UI assets:
|
||
- Public base: ${RUNNER_PUBLIC_BASE}/ext-ui/{extensionId}/{content_hash}/…
|
||
- Static assets resolved from the unpacked bundle according to manifest.json (e.g., index.html, JS/CSS assets, media).
|
||
- Execution API:
|
||
- Expose an HTTP endpoint to execute extension handlers when invoked by Gateway:
|
||
- POST /v1/execute
|
||
- Ensure runtime fetches entry.wasm (or equivalent) mapped by content_hash and reuses local cache.
|
||
|
||
## Configuration Parity with Server
|
||
|
||
The Runner should use the same S3 settings as the server for consistent access and path semantics.
|
||
|
||
Required environment variables:
|
||
- STORAGE_S3_ENDPOINT: S3/MinIO endpoint (e.g., http://localhost:9000 for MinIO).
|
||
- STORAGE_S3_BUCKET: Bucket name used to store/read bundles.
|
||
- STORAGE_S3_REGION: Region string; for MinIO use a placeholder like us-east-1 unless configured otherwise.
|
||
- STORAGE_S3_ACCESS_KEY: Access key.
|
||
- STORAGE_S3_SECRET_KEY: Secret key.
|
||
- STORAGE_S3_FORCE_PATH_STYLE: true to force path-style addressing for MinIO.
|
||
- STORAGE_S3_BUNDLE_BUCKET: optional override for the bundles bucket (if server publishes to a separate bucket).
|
||
- STORAGE_TLS: Optional; set true if using HTTPS and the cert is trusted (otherwise provide appropriate trust settings).
|
||
|
||
Runner-specific:
|
||
- RUNNER_PUBLIC_BASE: Base URL path to serve UI (e.g., /runner).
|
||
- RUNNER_CACHE_DIR: Filesystem directory for caching fetched bundles (e.g., /var/cache/alga-runner or ./.cache/runner for local).
|
||
- RUNNER_MAX_CACHE_SIZE_BYTES: Optional LRU cap for cache eviction.
|
||
- RUNNER_OFFLINE: Optional; if true, disables network fetches and requires bundles to be pre-cached.
|
||
|
||
Server parity notes:
|
||
- The server writes bundles to canonical S3 paths under sha256/<hash>/. The Runner must only read from canonical locations and never mutate them.
|
||
- If the server enforces declaredHash, the Runner should assume sha256/<hash>/… objects are immutable.
|
||
|
||
## Cache Behavior and Integrity
|
||
|
||
- On first request for {extensionId, content_hash}:
|
||
- Fetch sha256/<content_hash>/manifest.json, validate basic fields (extension, version, entry paths).
|
||
- Fetch sha256/<content_hash>/bundle.tar.zst, verify sha256(content) equals content_hash.
|
||
- Unpack into RUNNER_CACHE_DIR/<content_hash>/… with a marker indicating successful extraction (e.g., .ready).
|
||
- Subsequent requests:
|
||
- Serve from cache if .ready is present.
|
||
- For HTTP GETs of UI assets, set ETag to the content hash or the asset’s digest.
|
||
- Respect If-None-Match and return 304 when ETag matches for immutable assets.
|
||
- Eviction:
|
||
- If RUNNER_MAX_CACHE_SIZE_BYTES is set, implement LRU eviction of least-recently-used content hashes.
|
||
|
||
## HTTP Flows
|
||
|
||
- Execution (from Gateway to Runner):
|
||
- POST /v1/execute
|
||
- Body includes { extensionId, content_hash, handler, payload, tenant, … }.
|
||
- Runner ensures bundle for content_hash is present (fetch+cache if missing), loads entry.wasm, and executes handler.
|
||
|
||
- UI (from Browser to Runner):
|
||
- GET ${RUNNER_PUBLIC_BASE}/ext-ui/{extensionId}/{content_hash}/index.html
|
||
- GET ${RUNNER_PUBLIC_BASE}/ext-ui/{extensionId}/{content_hash}/assets/<file>
|
||
- The Runner maps the path to RUNNER_CACHE_DIR/<content_hash>/ui/… (or equivalent layout from the bundle).
|
||
- Set headers:
|
||
- Cache-Control: public, max-age=31536000, immutable (safe for immutable paths)
|
||
- ETag: "<content_hash>" or strong per-asset digest
|
||
- Content-Type: resolved from file extension
|
||
|
||
## Expected S3 Paths
|
||
|
||
Canonical objects written by the server:
|
||
- sha256/<hash>/bundle.tar.zst
|
||
- sha256/<hash>/manifest.json
|
||
|
||
The Runner must not depend on non-canonical staging keys; only canonical content-hash keys are considered valid.
|
||
|
||
## Immutability and Conditional Requests
|
||
|
||
- All content under sha256/<hash>/ is immutable.
|
||
- For GET of UI assets, use ETag based on content hash (or a per-file digest within the bundle).
|
||
- Honor If-None-Match to enable 304 responses and reduce bandwidth.
|
||
- Do not attempt to overwrite or delete S3 objects; cache management is local.
|
||
|
||
## Acceptance Checks (Local Runner with MinIO)
|
||
|
||
- With MinIO configured via STORAGE_* and path-style:
|
||
- Given a content hash H from a finalized upload:
|
||
- Runner fetches sha256/H/manifest.json and sha256/H/bundle.tar.zst.
|
||
- Runner unpacks and serves UI at:
|
||
- ${RUNNER_PUBLIC_BASE}/ext-ui/{extensionId}/H/index.html returns 200
|
||
- Subsequent GETs with If-None-Match: "H" return 304
|
||
- Execute flow:
|
||
- POST /v1/execute with content_hash H executes against entry.wasm and returns a handler result or structured error.
|
||
|
||
## Notes
|
||
|
||
- entry.wasm resolution:
|
||
- The manifest’s entry.wasm path is relative to the bundle root; ensure it is present after unpacking.
|
||
- Security:
|
||
- Validate manifest format and restrict file types and paths during unpack to avoid path traversal.
|
||
- Consider running Wasm in a sandbox with appropriate capabilities.
|
||
- Timeouts and retries:
|
||
- On transient S3 errors, implement exponential backoff for fetches.
|
||
- Fail closed if content hash validation fails.
|
||
|
||
## References
|
||
|
||
- Overview: [ee/docs/extension-system/overview.md](ee/docs/extension-system/overview.md:1)
|
||
- Serving system: [ee/docs/extension-system/serving-system.md](ee/docs/extension-system/serving-system.md:1)
|