Skip to content

Manifest schema rejects multiInstance, so no app can opt into multiple instances #148

Description

@pofallon

Summary

The Hola server reads multiInstance from manifest.json, but this repo's schema forbids it. Any bundle that declares the flag fails validate-catalog, so no app can opt into multiple instances — the flag added in try-hola/hola#246 is unreachable from the catalog.

The drift

Three facts that only bite in combination:

  1. The server expects the field in the manifest. packages/server/src/services/core/catalog.ts:616:

    const multiInstance = manifest.multiInstance === true ? true : undefined;

    and it drives the singleton guard in packages/server/src/services/core/deployment.ts:2751:

    if (multiInstance || allowMultiple) return;
    // ...otherwise ConflictError: "This app is single-instance; pass --allow-multiple"
  2. This repo's schema forbids it. schemas/manifest.schema.json is additionalProperties: false at root, and multiInstance is not among its 18 declared properties.

  3. CI enforces the schema on every manifest. The validate-catalog job (.github/workflows/build-and-publish.yml:148-160) runs node bin/validate-manifest.mjs with no arguments, which discovers and validates every src/*/src/manifest.json on every PR and every push to main.

bin/validate-manifest.mjs passes --strict=false to ajv-cli, but that only relaxes schema-authoring strictness — additionalProperties is a validation keyword and is still enforced. A manifest carrying multiInstance: true fails with must NOT have additional properties.

Confirming the consequence: grep -rln multiInstance src/ returns nothing. Zero of 17 bundles declare it.

Impact

Every app in the catalog is single-instance, including the ones that most obviously shouldn't be. Running two Ubuntu Webtops today requires the --allow-multiple / "install another" override — the same deliberate escape hatch you'd use to force a second Vaultwarden. The server has a first-class way to express "multiples are expected here"; the catalog can't reach it.

Fix

Add multiInstance to the root properties of schemas/manifest.schema.json:

"multiInstance": {
  "type": "boolean",
  "description": "Whether multiple deployments of this app are expected. Default (omitted) is single-instance: the server rejects a second install unless the operator passes the per-install `allowMultiple` override. Declare true only when concurrent instances are genuinely independent — separate data roots and no shared external identity or singleton capability role."
}

Then set "multiInstance": true on the apps that warrant it.

Audit while we're in here

  • webtop — the clear case. Independent /config volumes, accepts: ["backup@1"] only, no provides/consumes/push.
  • guacamole, running-man — plausible; worth a look.
  • backrest — must stay single-instance. It declares provides: ["backup@1"], whose provider grant is a read-only mount of every app's data (ADR 0004). Two providers is both ambiguous and a doubled blast radius.
  • calibre-web — probably should not get the flag. Its push target is mode: mirror, quiesce: stop, so hola app data push calibre-web library against the wrong instance deletes files. Multi-instance here needs a --deployment selector first.
  • homepageconsumes: "app-registry" is not a conflict (two readers are harmless), but low value.

Verification

node bin/validate-manifest.mjs should pass with the flag set on webtop, and a second webtop install should then succeed without --allow-multiple.

Related

A broader guard worth considering separately: the server's accepted manifest fields and this schema have no automated agreement check, which is how this drifted. #417 would add a second field across the same seam.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions