Transitional acceptance of legacy v1 plugin signature envelopes (MOB-287).
Every first-party plugin published before mob_dev shipped envelope v2
(MOB-74) is v1-signed. v1 signatures cover the evaluated manifest map,
so verifying one means running Code.eval_file on priv/mob_plugin.exs
first — arbitrary code execution for a malicious manifest. This module
therefore evaluates a v1 manifest only after its provenance is established
without evaluating anything:
- The plugin is a Hex dependency from the public
hexpmrepository: Mix resolves it throughHex.SCMright now (not a path or git dependency, including a path override pointing intodeps/), the project'smix.lockpins it tohexpm, and its directory is the Hex checkout in the project's deps path. Hex package-name ownership fixes who published it; Hex verifies the tarball checksum on fetch; and the package's ownmix.exsand compile step already execute duringmix compile, so evaluating its manifest grants it nothing it did not already have. - The public key in
priv/mob_plugin.pubhas the fingerprint trusted for that plugin name inconfig :mob, :trusted_plugins.
Only then is the manifest evaluated and the v1 signature checked against
it (3). Any failure reports :envelope_v1_unsupported, the same refusal
every other v1 envelope gets.
Delete this module — and its two call sites in Verify.load_verified/2
and SignatureGate — once every first-party plugin is republished with a
v2 signature. See decisions/2026-09-30-v1-envelope-transition.md.
Summary
Functions
Whether an already-loaded manifest for a v1-signed plugin satisfies the
transition rule. Never evaluates anything — used by SignatureGate, which
receives manifests MobDev.Plugin.activated/0 already loaded.
Loads the manifest of a v1-signed plugin when the transition rule allows it.
The one-line build notice for an accepted v1 plugin.
Types
@type opts() :: [ scms: %{optional(atom()) => module()}, lock: map(), deps_path: Path.t(), trust_map: MobDev.Plugin.TrustStore.trust_map() ]
Provenance inputs. Each defaults to the current Mix project's value:
:scms— each dependency's active SCM (Mix.Project.deps_scms/0).:lock— the parsedmix.lockmap (Mix.Dep.Lock.read/0).:deps_path— the project's deps directory (Mix.Project.deps_path/0).:trust_map—config :mob, :trusted_plugins(TrustStore.load_trusted_plugins/0).
Functions
Whether an already-loaded manifest for a v1-signed plugin satisfies the
transition rule. Never evaluates anything — used by SignatureGate, which
receives manifests MobDev.Plugin.activated/0 already loaded.
Loads the manifest of a v1-signed plugin when the transition rule allows it.
The manifest is evaluated only after the plugin passes the Hex-provenance
and trusted-fingerprint checks; a plugin failing either is refused without
evaluation. Returns {:error, :envelope_v1_unsupported} on any failure.
The one-line build notice for an accepted v1 plugin.