Skip to content

v0.39.1: an allowlist refusal names the store that fed it

Latest

Choose a tag to compare

@john-broadway john-broadway released this 04 Sep 05:02

An allowlist refusal names the store that fed it.

ct_exec and its siblings refused a CTID with "not in PROXIMO_CT_ALLOWLIST, add it there", and "there" was a variable, not a store. The variable can be fed from two of them: the MCP client's mcpServers.<name>.env block, and ~/.config/proximo/proximo.env. The loader fills from the file only the keys the block has not already set. So an operator who edits the file's copy of a key the block also holds edits a line nothing reads, and sees the same refusal again after a reconnect. That happened live on 2026-09-02.

0.39.1 makes the refusal tell you where to go:

  • The loader names what it skipped. Every file key the process environment shadows with a different value is printed at load time, keys only, never values. A same-value shadow is the documented setup flow (export the file, then run proximo doctor) and stays silent. The CLI verbs whose stderr is a pinned contract, badge and reach-audit among them, do not get these lines in front of their own output; the server and daemon entries still announce.
  • The config records its source. ct_allowlist_source and agent_allowlist_source are set per constructor, with a neutral phrase for a directly built config.
  • Every refusal names that source. At the server and backend layers both, for both launch shapes: the client's env block for a stdio server, the unit's EnvironmentFile for the daemon. Each refusal says whether the file's copy is shadowed, and says a restart or reconnect is required, because the value is fixed at launch.
  • proximo doctor reports it. The source, plus a flag on any shadowed key whose value differs.

Refusing to start on a disagreement was considered and rejected: it would break the loader's non-breaking contract for inline-config deployments. Off-box safety is kept, so the messages name the default file unexpanded or by PROXIMO_ENV_FILE, never an expanded local path.

Also in this release:

  • The base image moves to the python:3.13-slim tag head. Both build stages pin the same digest, and tests/test_dockerfile_pins.py now refuses a Dockerfile whose two stages disagree, a partial bump no suite had caught. scripts/base_image_digest_check.py verifies the pin against the registry byte for byte. The reason is the fold law for a curated mirror, not a red gate: the runtime stage has run apt-get upgrade at build time since 0.21.1, so the built image has carried fixed packages regardless of the pin, and the public Trivy gate, which scans the built image, has read zero.
  • The allow-all warning knows when the mirror is on. With PROXIMO_CT_ALLOWLIST=* and a reach privilege named, least-privilege has moved to PVE's table rather than being disabled, and the warning now says so and names the privilege.
  • The public release commit subject carries the reason. Four releases read as a bare release: vX.Y.Z in the one place GitHub shows text beside files. The subject is now built from this changelog entry's opening thesis, and a missing, empty or overlong thesis refuses at release time.

908 tools, unchanged. No breaking change, no new tool surface.

Where to read more

  • What the allowlist stores are and which one wins: docs/SETUP.md
  • Every tool with typed inputs: docs/TOOLS.md
  • Verifying the artifacts you just pulled (image signature, SBOM, PEP 740 provenance): VERIFY.md
  • Full change detail: CHANGELOG.md

Install: uvx proximo-proxmox · pip install proximo-proxmox · ghcr.io/john-broadway/proximo:0.39.1