Skip to content

Plugin manifest trust and signing policy #194

Description

@Hey-Yetunde

Problem

There is currently no way to verify that a plugin manifest was produced by a trusted publisher. Any manifest that passes structural validation is accepted as-is. This issue investigates and implements an optional trust mechanism so operators can require verification where they want it, without making signing mandatory for the basic plugin architecture.

Context

  • app/services/plugins.py::PluginManifest.from_dict validates format but not authenticity. The manifest has no signature/trust fields today.
  • plugins/plugin.schema.json - additionalProperties: false; adding a trust-related field (e.g. signature) requires a coordinated schema update and runtime validation update (see Validate plugin manifests against plugins/plugin.schema.json in code #165 for schema/runtime consistency).
  • cryptography is already a dependency (used for Fernet token encryption in the GitHub integration), so established primitives are available without a new dependency.

Scope and intent

This issue is optional / future-facing. It must not block local or trusted plugins unless the operator explicitly configures the app to require verification. The default behavior (unverified plugins load) stays unchanged.

This issue does NOT:

  • Invent a proprietary cryptographic protocol.
  • Make signing mandatory.
  • Redesign the plugin system.

Technical requirements

  • Design a trust mechanism with clear, disjoint trust states:
    • Trusted - the manifest carries a valid signature from a configured trusted publisher/key.
    • Unverified - the manifest has no signature, or no trusted publisher is configured (the default).
    • Invalid - the manifest claims a signature but verification fails.
  • Implementation guidance:
    • Signature metadata on the manifest (signed over the canonical manifest body, e.g. a signature field using an established scheme).
    • Trusted publisher/key configuration (list of trusted public keys / publisher ids).
    • Verification using established primitives from the existing cryptography dependency (e.g. Ed25519); no new proprietary scheme.
    • A policy switch: "verify required" (strict) vs "verify if present" (lenient/default). In strict mode, unverified manifests are rejected; in the default mode, unverified is allowed and clearly labeled.
  • Update plugins/plugin.schema.json and the runtime validator together (consistent with Validate plugin manifests against plugins/plugin.schema.json in code #165) if any manifest field is added.
  • Surface the trust state (Trusted/Unverified/Invalid) in plugin metadata and in the plugin management layer (Plugin management API: install, enable, disable #163) so operators can see it.

Security considerations

  • Verification failures must fail closed in strict mode and be visible (labeled) in default mode.
  • Keys/publisher configuration lives in server configuration, never in manifests.
  • Do not weaken existing validation; signing is additive.

Acceptance criteria

  • Trust states are clearly distinguished and exposed (Trusted/Unverified/Invalid).
  • Default behavior: unverified plugins still load (no regression); strict mode rejects them.
  • Invalid signatures are rejected (or at minimum flagged) in both modes.
  • No proprietary crypto; implementation uses established primitives from the existing dependency set.
  • Security tests cover: valid signature -> Trusted, no signature (default) -> loads as Unverified, tampered signature -> Invalid/rejected in strict mode.

Testing requirements

  • Unit tests for verification (valid/tampered/missing signatures) and for the strict vs default policy modes.
  • Schema/runtime consistency tests if a new field is added.

Dependencies

Difficulty

Hard

Priority

Low

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

    difficulty/hardphase-8Work scoped for Phase 8: Plugins & ExtensionspluginPlugin system: manifests, registry, capabilities, eventspriority/lowsecurity

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions