Skip to content

connector: launch the bridge with uv run --locked; preflight sets the uv floor (#248) - #255

Merged
virtualsteve-exa merged 1 commit into
devfrom
fix/uv-locked-launch-248
Sep 24, 2026
Merged

virtualsteve-exa merged 1 commit into
devfrom
fix/uv-locked-launch-248

Conversation

@virtualsteve-exa

Copy link
Copy Markdown
Collaborator

Fixes #248 (Praxen 2026-09-19-003, Medium).

Change. Both host launches become uv run --quiet --locked <bridge> (plugin/.mcp.json; .mcp.codex.json via its generator). uv then refuses to start the bridge if the script lock beside it is missing or stale, instead of silently resolving without it. Preflight's connectivity check launches the bridge the same way, and its toolchain check fails a uv below 0.5.23 with uv self update — script locks arrived in 0.5.17 and the --locked warning on scripts went away in 0.5.23, so that is the floor. The install guide's uv bullet states it.

Checked on uv 0.11.24 with the shipped lock: current lock → starts and connects; stale lock (a dependency bound changed in a copy) → error: The lockfile … needs to be updated, but --locked was provided; no lock file → error: Unable to find lockfile for Python script, but --locked was provided; --offline with the lock satisfied → starts. The flag does not change the --check path preflight uses.

Tests: test_the_bridge_is_launched_with_the_lock_enforced_on_both_hosts (both launch arg lists, the shipped lock, preflight's line and floor); test_preflight_fails_a_uv_below_the_lock_floor_and_accepts_the_floor (fake uv 0.5.16 fails with the upgrade command; 0.5.23, 0.6.0 and a two-digit minor pass); test_bridge_static now runs the bridge with --locked. Suite 979 green. AI BOM and guide current.

Sequencing: functional change to the connector launch on both hosts. Ships with the next version; red-team gate and Praxen rescan on the tree before release. Not a hotfix.

🤖 Generated with Claude Code

https://claude.ai/code/session_016Q9UohWfy2scPhr4pavhqd

…he uv floor (#248)

The connector ships a hash-pinned script lock, but the launch never asked uv to
honor it, so on a uv that ignores script locks the dependencies resolved to
whatever the index offered. Both hosts now launch with `--locked`: uv refuses to
start the bridge if the lock is missing or stale instead of resolving without
it. Preflight fails a uv below 0.5.23 (script locks arrived in 0.5.17; the
`--locked` warning on scripts went away in 0.5.23) with the upgrade command, and
its connectivity check launches the bridge the way the hosts do. The guide's uv
bullet states the floor.

Checked on uv 0.11.24: a current lock starts; a stale lock and a missing lock are
refused with uv's own message; offline with the lock satisfied starts.

Tests: the launch arguments on both hosts, the shipped lock, preflight's check
line and floor (invariant); a fake uv below and at the floor (functional);
test_bridge_static runs the bridge as the hosts do.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016Q9UohWfy2scPhr4pavhqd
Signed-off-by: Steve Wilson <steve.wilson@exabeam.com>

@mattwillems-exabeam mattwillems-exabeam left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approve. Supply-chain pinning that isn't enforced at launch is decoration, and this is the flag that makes #71/#149 real.

Verified

  • --locked in both manifests — plugin/.mcp.json and the generated plugin/.mcp.codex.json, so both hosts launch the same way
  • preflight's own connectivity check launches identically (uv run --quiet --locked "$bridge" --check), so the diagnostic exercises the real launch path rather than a more permissive one
  • An invariant pins all of it — args[:3] == ["run", "--quiet", "--locked"] for both manifests, the lock file must ship beside the bridge, and UV_MIN must be stated. The flag can't be quietly dropped later
  • 960 passed

Behaviourally tested rather than assumed. I perturbed a pinned version inside exabeam-mcp-bridge.py.lock and re-ran the launch:

error: Failed to parse `uv.lock`
  Caused by: The entry for package `annotated-types` (9.8.0) has wheel
  `annotated_types-0.8.0-py3-none-any.whl` with inconsistent version (0.8.0)

Rejected, rather than silently re-resolving to whatever satisfies the constraints — which is exactly what plain uv run was doing, and why the hash pinning wasn't buying anything at runtime.

The version floor is the part worth keeping

UV_MIN="0.5.23" with the reasoning recorded in place — script locks need 0.5.17, and the spurious --locked warning on scripts cleared in 0.5.23. A floor without its reason is the kind of thing someone lowers later to unbreak a machine, so having both numbers and what each one bought is what keeps that from happening.

The preflight failure message is right too: it names the flag, why it exists ("so its hash-pinned dependencies are honored") and the upgrade command. An operator on old uv learns what they lose, not just that a check failed.

One consequence worth noting in the release notes when this ships: an operator on uv older than 0.5.23 now fails preflight where they previously passed. That's correct — they were running unpinned and didn't know — but it will read as a regression to anyone who doesn't know what changed.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants