Repository navigation
Add executor mode that binds a call to its allow - #38
Conversation
The signer derives effect and target from a known call and puts call_digest on the receipt. A witness Nova does not hold the key for recomputes that digest, consumes the allow, and only then sends the call. A mismatch, replay, or proposal-time lie is refused and recorded. This does not prove observed effect. Co-authored-by: Jon Halstead <warheart1984@gmail.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f3048c5ace
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| receipt = self._find_receipt(allow_receipt_id) | ||
| if receipt is None or receipt.get("verdict") != "allow": | ||
| return self._diverge("unauthorized", digest, allow_receipt_id) | ||
| if derived is None or digest != receipt.get("call_digest"): | ||
| return self._diverge("mismatch", digest, allow_receipt_id) |
There was a problem hiding this comment.
Reject legacy receipts before trusting call_digest
When the receipt log contains a signed v1 allow, an attacker who can edit the log but lacks the signing key can add any call_digest and refresh issued_at; v1 verification deliberately hashes neither field, so the receipt signature, chain, and anchor still verify. Because this path checks only the verdict and injected digest, the attacker can turn an old harmless allow into authorization for an arbitrary matching call and bypass the TTL. Require a receipt version whose digest and timestamp are covered before dispatching.
Useful? React with 👍 / 👎.
| body=None, | ||
| error=str(exc), | ||
| ) | ||
| completed = self._append(self._execution("completed", digest, allow_receipt_id)) |
There was a problem hiding this comment.
Bind the response bytes into completed entries
When dispatch succeeds, body is returned to the caller but the signed completed entry contains only the call digest and status. Two executions receiving completely different bytes therefore produce indistinguishable witness evidence, so the log cannot support the documented claim that it records or proves the bytes received. Include a response digest in the completed entry and its signed material.
Useful? React with 👍 / 👎.
The Unix socket server was created at import time, so Windows test collection died before any skip could run. The class is now defined only where Unix sockets exist. Co-authored-by: Jon Halstead <warheart1984@gmail.com>
What this is
Executor mode, from the execution-binding design. A witness Nova does not hold the key for recomputes
call_digest, checks the allow, consumes it, and only then sends the call. This does not prove observed effect.What a reviewer can check
call, deriveseffectandtargetforhttps_requestandlocal_model_tool, computescall_digest, and denies a disagreement (DESCRIPTION_DISAGREEMENT) or an unknown shape (UNKNOWN_CALL_SHAPE). The deny records the derived call, not the lie.call_digestis hashed into the proposal and, when present, into the receipt. Older receipts that omit it keep their ids.infinityctl evaluatecopies the field; it does not derive it. The kernel does not interpret the digest. A non-emptypayload.binding_faultcan only deny.runtime/witness.py) checks that the receipt log chains, the receipt exists, the verdict isallow, the digest matches, the allow is unused, and it is not expired. It appends a signedstartedentry before dispatch, thencompletedorfailed. Mismatch does not consume the allow. One allow, one execution. No retry.infinityctl witness-append/witness-verify).throughkey retirement is not applied; a key file that uses it is refused.Tests
tests/test_execution_binding.pycovers:mismatch, nothing sent, then the read still runs once.reused, one dispatch.unauthorized.late), a broken receipt log (unauthorized), a failed send consuming the allow, a real localhost GET (the mismatched POST is not seen), and redirects not followed.What this does not prove
completedmeans this process sent the call and got bytes back.infinityctl evaluatewithout the signer still trusts the caller's description.call_digest. Onlyruntime/call_binding.pycomputes it.ickverify.pydoes not recompute it and does not read the witness log.state_ref, retries, a witness heartbeat, or two OS accounts for the witness. The tests use two keys in one process.issued_atis true. That a taken-over witness cannot sign a false execution. That the target cannot be reached except through the witness.Details and the remaining limits are in
docs/executor-mode.md.