fix(security): remote-upgrade doc drift + fail-closed throttle (#321)#324
Merged
Conversation
VijitSingh97
force-pushed
the
claude/321-security-doc-drift
branch
from
July 19, 2026 20:00
36ca23d to
7bcdb9c
Compare
Found reviewing v1.11.2 as the pithead#597 consumer — on a security surface, docs-vs-code drift is the bug. - SECURITY.md claimed the remote-upgrade path is verified "by SHA256SUMS hash only"; it never was. The real anchor (ADR 0002 D5, per-spec in the code) is a git checkout of the release tag over TLS to GitHub, origin/main ancestry, and immutable releases — checksums play no role on that path. The doc now states that. - ADR 0002 D8 claimed "a flock serializes concurrent triggers"; the only flock guards the D6 throttle stamp, released before the build. Amended in place to name the real mechanism (Type=oneshot + newest- wins spool draining) and the upgrade path if it's ever not enough. - _control_upgrade_throttle_ok fails CLOSED (rc 2) when it can't take its lock: the guard bounds how often a compromised trigger can make the rig dial out, and fail-open inverted that on exactly the degraded box an attacker might arrange. The caller reports a failed status naming the throttle state — distinct from throttled, so a consumer doesn't retry-later forever against a broken rig. Tests: the fail-open unit test flipped to fail-closed (rc 2, via a dangling-symlink lock that defeats any uid), plus a caller-level assert that the status is failed with the real cause, never "throttled". Closes #321 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
VijitSingh97
force-pushed
the
claude/321-security-doc-drift
branch
from
July 19, 2026 20:05
7bcdb9c to
e930366
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #321. Stacked on #323 (the #320 status-contract PR) — merge that first; GitHub will retarget this to
developautomatically.Found reviewing v1.11.2's control-upgrade as the pithead#597 consumer. The security posture is settled (ADR 0002 D5, signed off as D-OPEN-2); the bug was that the docs and one ADR claim didn't match the shipped code, plus one real posture fix.
What changed
SHA256SUMShash only" — no checksum is fetched or checked on that path, by design. The real anchor is now stated: git checkout of the release tag over TLS to GitHub,origin/mainancestry (D10), immutable releases locking the tag→commit binding. Checksums play no role there.flockserializes concurrent triggers" overstated it — the only flock guards the D6 throttle stamp and is released before the build. The amendment names the real serialization (systemdType=oneshot+ newest-wins spool draining) and the upgrade path if that's ever not enough (verb-scoped lock spanning fetch/build)._control_upgrade_throttle_okused to proceed unthrottled (with a warn) when it couldn't take its lock — for a guard whose purpose is bounding how often a compromised trigger can make the rig dial out, fail-open inverted the posture on exactly the degraded box an attacker might arrange. It now returns rc 2 and the verb refuses with afailedstatus naming the throttle state — deliberately distinct fromthrottled(which means retry-later) so a consumer doesn't poll forever against a broken rig.Testing
failedwith a reason naming the throttle state, neverthrottled.make lint+make lint-mdclean.🤖 Generated with Claude Code