Repository navigation
v0.47.0: self-owned grants refused; a stdlib ledger checker
Self-owned grants refused; a stdlib ledger checker. A minor: it refuses consent grants that worked before, adds an opt-in for one-user boxes, and adds a checker and a written ledger format.
Changed (refuses what worked before). SECURITY.md's hardened recipe put consent grants in /etc/proximo, mode 1770 root:proximo: the agent's group could create files there, and the gate never asked who placed a grant, so the agent could write its own and it was accepted. A grant owned by the agent's own user is now refused (consent: "self"). On an install where the human and the agent are one user, root included, consent refuses every mutation it guards until the agent runs as its own account. The recipe now gives grants their own directory, owned by the operator's account, that the agent can read and not create in; packaging/proximo.env.example shows it.
New: PROXIMO_CONSENT_SAME_USER=advisory. For a one-user box where consent is the agent stopping to ask, not a lock: same-user grants are accepted, still spent once and still bound by the TTL, and never called granted. The plan shows consent: "advisory" and says so in its reason, every such spend receipt carries "advisory": true, and DIAGNOSE flags the box. It trusts the agent not to write its own grant, which the default refuses to trust. Off unless exactly advisory; any other value refuses mutations; a blank value is unset.
Fixed: the spend. It was os.remove, so a root-placed grant in that sticky directory could never be spent: the agent's grants worked and the operator's did not. A grant now spends once by a marker beside the ledger (.proximo-consent-spent/), with a core.consent_spent row as the evidence. The grant is judged and spent on one lstat, the marker is keyed on that file (device, inode, mtime; re-writing the grant is a new approval, renaming it onto another plan is not), and the core removes the grant only if the path still holds that file. If the spend's receipt cannot be written, nothing reaches the wire and the grant is not used up. proximo_plan shows a used grant as consent: "spent".
New: the ledger format, written down, and a checker that needs no Proximo. docs/ledger-format.md (format ledger: 1) and scripts/verify_ledger.py, one file of standard-library Python: whoever is handed a log and its key can check it. Its tests hold it to the core on every planted break, file by file.
Fixed: Proximo's own ledger check. It read the log in text mode, so a lone \r the writer never writes was read as a row break, and the checker and audit_verify could give opposite verdicts on one file; every check that gives a verdict now reads the rows as the writer joined them. A row with a 5,000-digit number, deep nesting, a lone surrogate or bytes that are not UTF-8 crashed audit_verify; each is now a broken row at its line.
Tiers: the re-cut. VM start, shutdown, resume, snapshot create and snapshot description are restorable on their own lines (they shared the destructive qemu family with destroy); VM and container reboot and VM suspend are disruptive; container resume, snapshot create and snapshot description are restorable. vzdump, PBS sync jobs, PBS realm sync and pve:/access/users are destructive; the PBS notification test and S3 check are disruptive. Severity still gates nothing on its own: a tier is what a plan and its receipt say.
Security. opentelemetry-api, which mcp pulls in and uses to extract trace context, moves from 1.44.0 to 1.45.1, past CVE-2026-114603: a crafted tracestate header took quadratic time to parse. The lock and the hash-pinned requirements carry the fix; CI's pip-audit refused the release until they did.
1,858 tests on Python 3.12 and 3.13; the mcp 1.x leg runs 1,856 and skips the two 2.x-only seams.
Full history for this release, commit by commit, is on the internal mirror; this public branch carries one squashed commit per release by design. Every change here is described in CHANGELOG.md.
Where to read more
- Consent, the owner check and the same-user opt-in, and what each control honestly holds: SECURITY.md
- The ledger format, and checking a log without Proximo: docs/ledger-format.md and scripts/verify_ledger.py
- What each threat is met by, and the residual risks said plainly: docs/THREAT_MODEL.md
- The tiers and their sentences: records/README.md
- Verifying the image signature, the SBOM and the provenance yourself: VERIFY.md
- Full change detail: CHANGELOG.md
Install: uvx proximo-proxmox · pip install proximo-proxmox · ghcr.io/john-broadway/proximo:0.47.0