PSA/ee/docs/extension-system/runner-s3-integration.md
Hermes 284313f908
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
Initial import of AlgaPSA codebase from PSA server
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz

Source: /opt/alga-psa on psa.joliet.tech
2026-06-22 16:12:17 -05:00

5.8 KiB
Raw Blame History

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:

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//. The Runner must only read from canonical locations and never mutate them.
  • If the server enforces declaredHash, the Runner should assume sha256//… 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 assets 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/
    • 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//bundle.tar.zst
  • sha256//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// 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 manifests 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