Documentation / Exploitation / Guides pratiques / Set up a plugin registry

Set up a plugin registry

A registry is the store your instance reads at boot to download the plugins it declares, and the store plugin authors publish to with meridian-plugin publish. This recipe stands up one registry — either a GCS bucket or a filesystem directory — and wires the IAM so the API can read and authors can publish.

For what to put in the manifest once the registry exists, see Declare and install plugins. For the publishing side, see Publish to the registry.

Choose a backend

The store backend is chosen from the URL prefix (libs/plugin-cli/src/registry/store.ts, openStore):

  • gs://bucket[/prefix] — a Google Cloud Storage bucket, accessed over the GCS JSON API with an ADC token. Use this for shared and production deployments.
  • A local path (/srv/plugins, ./plugins, or file:///srv/plugins) — a directory on disk or an NFS mount. Use this for development, tests, or a single-host deployment where all components share the filesystem.

Both backends implement the same layout and immutability rules (libs/plugin-cli/src/registry/registry.ts): a published version lives under @publisher/name/<version>/… and is immutable — re-publishing an existing version is refused, so you bump the version instead.

Option A — GCS bucket

1. Create the bucket

gcloud storage buckets create gs://meridian-plugins \
  --location=europe-west1 \
  --uniform-bucket-level-access

Pick any name; the manifest and CLI reference the bucket by its gs:// URL. A prefix is supported (gs://meridian-plugins/prod) if you want to share a bucket across environments.

2. Grant read to the instance identity

At boot the API resolves each declared plugin against the registry and downloads missing versions (apps/api/src/registry.ts, ensureInstancePlugins). The process identity — a service account, typically via workload identity — only ever reads the bucket, so roles/storage.objectViewer is sufficient:

gcloud storage buckets add-iam-policy-binding gs://meridian-plugins \
  --member="serviceAccount:sa-clinical-api@PROJECT.iam.gserviceaccount.com" \
  --role="roles/storage.objectViewer"

Authentication uses ADC: the store requests the devstorage.read_write scope and calls GoogleAuth.getAccessToken() (store.ts, gcsStore). The granted IAM role — not the requested scope — is what bounds actual access, so read-only viewer is correct for the API.

3. Grant publish to plugin authors

meridian-plugin publish writes objects but never overwrites: every put uses ifGenerationMatch: 0 (create-if-absent), which fails with HTTP 412 if the object already exists (store.ts, gcsStore.put). So authors need object create, not full object admin:

gcloud storage buckets add-iam-policy-binding gs://meridian-plugins \
  --member="group:plugin-authors@posos.fr" \
  --role="roles/storage.objectCreator"

roles/storage.objectCreator lets them add new versions but not delete or replace existing ones, which matches the immutability guarantee.

Option B — local directory

1. Create the directory

mkdir -p /srv/plugins

The directory backend (store.ts, dirStore) creates nested paths on write and enforces the same create-if-absent rule, so no further layout setup is needed.

2. Grant filesystem access

  • The API process must be able to read and traverse the tree — mount it read-only if you want to enforce that the instance never writes.
  • Plugin authors need write access to publish. If the registry is an NFS share, mount it read-write on author hosts and read-only on the API host.

Everything that touches this path (API endpoint and proxy processes) must see the same directory, so a shared/NFS mount is required for multi-host setups.

Point the instance at the registry

Set the registry in the instance manifest, or fall back to the MERIDIAN_REGISTRY environment variable — the manifest's registry: key wins, the env var is the default (apps/api/src/registry.ts, ensureInstancePlugins):

# instance manifest (INSTANCE_CONFIG)
registry: gs://meridian-plugins    # or /srv/plugins, or file:///srv/plugins
plugins:
  "@posos/demo": "^0.1.0"

Or, without a manifest key:

export MERIDIAN_REGISTRY=gs://meridian-plugins

A relative local path in either place is resolved from the repo root; gs:// and file:// URLs are used as-is. See registry and MERIDIAN_REGISTRY for the full resolution rules, and note that downloaded versions are cached under MERIDIAN_PLUGIN_CACHE (default .data/plugins) — mount it as a volume so restarts do not re-download.

Verify

Point the CLI at the registry and list a plugin's published versions (libs/plugin-cli/src/commands/publish.ts, versionsCommand). An empty registry prints "no published versions", which still confirms the store is reachable and the credentials work:

export MERIDIAN_REGISTRY=gs://meridian-plugins   # or pass --registry <url>
meridian-plugin versions @posos/demo

To confirm the read path end to end, declare a published plugin in the manifest and boot the instance: a plugin that is listed but cannot be resolved (no registry configured, version not found, download failed) fails the boot loudly — this is treated as a configuration error, the same as an invalid manifest.

75 documents11 sectionssource : /docs · généré au build