feat: delegations can require calls to carry a signed sender_info#10452
Draft
aterga wants to merge 2 commits into
Draft
feat: delegations can require calls to carry a signed sender_info#10452aterga wants to merge 2 commits into
aterga wants to merge 2 commits into
Conversation
Adds an optional sender_info_required field to request delegations, covered by the delegation signature. When a delegation in a request's delegation chain sets it to true, update calls authenticated through that chain must carry a (signed and verified) sender_info; calls without one are rejected with the new SenderInfoRequiredByDelegation error. Query and read_state requests are unaffected (read_state cannot even carry a sender_info, and query responses cannot change state). Since the field is part of the delegation's representation-independent hash, the bearer of the delegation cannot lift the requirement by stripping the field: doing so invalidates the delegation signature. For the same reason, replicas that predate this change fail closed on such delegations. Combined with sender_info attribute checking (#10447), this lets issuers like Internet Identity enforce read-only sessions end to end: the delegation forces the certified session attributes to be present on every update call, and the attributes' implicit:permissions = "queries" then causes the call to be rejected. Without this bit, a dapp holding the session key could lift the restriction by omitting the sender_info. https://claude.ai/code/session_01BQNgPJKgxWohrJ6owwJBzz
Contributor
There was a problem hiding this comment.
Pull request overview
This PR introduces an optional sender_info_required bit on request delegations (covered by the delegation signature / representation-independent hash) and enforces that update calls authenticated via a delegation chain must include a sender_info when any delegation in the chain requires it. This is part of combining the read-only delegation experiments by making “certified attributes must be present” protocol-enforceable.
Changes:
- Add
Delegation.sender_info_required: Option<bool>(hashes as nat 0/1 undersender_info_required) plus constructor/accessor and CBOR coverage. - Thread
DelegationRestrictionsthrough delegation validation and enforcesender_infopresence on the update/callpath (with a newSenderInfoRequiredByDelegationerror). - Add test utilities and ingress-message e2e tests covering required/optional behavior and chain accumulation.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| rs/validator/src/ingress_validation.rs | Introduces DelegationRestrictions, propagates sender_info_required through delegation validation, and enforces sender_info presence for update calls. |
| rs/types/types/src/messages/http.rs | Adds sender_info_required to Delegation, constructor/accessor, and includes it in signed-bytes hashing when present. |
| rs/types/types/src/messages/http/tests.rs | Updates Delegation CBOR serialization tests to include sender_info_required (null/bool). |
| rs/validator/tests/ingress_validation.rs | Adds a signed-bytes golden test for delegations with sender_info_required. |
| rs/validator/src/ingress_validation/tests.rs | Updates signature-validation unit tests to assert the returned restrictions include sender_info_required == false by default. |
| rs/validator/http_request_test_utils/src/lib.rs | Extends delegation-chain builders to create delegations with sender_info_required. |
| rs/validator/ingress_message/tests/validate_request.rs | Adds e2e tests for “required ⇒ reject missing sender_info”, “required ⇒ accept valid sender_info”, and “query unaffected”. |
| rs/validator/ingress_message/src/lib.rs | Exposes the new error variant in the ingress-message wrapper crate and its Display text. |
| rs/validator/ingress_message/src/internal/mod.rs | Maps the new ic_validator error variant into the wrapper crate’s error enum. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Avoid duplicating the shared request-content validation on the call path by enforcing the sender_info_required restriction inside validate_request_content behind a parameter, and fix a comment to say query requests rather than query responses. https://claude.ai/code/session_01BQNgPJKgxWohrJ6owwJBzz
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.
Delegations can require calls to carry a signed
sender_infoThis is step 1 of combining the two read-only-delegation experiments (#10447:
sender_infoattribute checking, #10449: delegation-level permissions): request delegations gain one bit — an optionalsender_info_requiredfield, covered by the delegation signature — that forces update calls authenticated through the chain to carry a (signed and verified)sender_info.Why
The
sender_infoattribute mechanism of #10447 enforcesimplicit:permissions = "queries"when the attributes are present — but the party we want to constrain (the dapp holding the session key) decides whether to attach them, so it can lift the restriction by omitting the blob. This bit closes that hole while keeping all permission semantics in the certified attributes:sender_info, signed by the same issuer underic-sender-info) say what the session may do, e.g.implicit:permissions = "queries"→ update calls rejected per feat: reject update calls when sender_info restricts permissions to queries #10447.Together: an issuer like Internet Identity signs a read-only delegation chain whose update calls must carry attributes that in turn forbid update calls — protocol-enforced, regardless of client cooperation. #10447 is being rebased on top of this PR so the stack forms the complete combined design.
Semantics
false→ today's behavior, byte-for-byte identical hashes for existing delegations; nothing in the ecosystem changes.sender_info_required = trueanywhere in the chain → update calls (/callpath) without asender_infoare rejected with the newRequestValidationError::SenderInfoRequiredByDelegation; calls with one proceed through the existing signature verification of the blob. Requirements only accumulate along the chain (liketargets).sender_infoat all, and queries are not restricted by the permissions attribute anyway.sender_infoitself.Changes
ic-types:Delegation.sender_info_required(optional bool; hashed as nat 0/1 under the keysender_info_required), constructor, accessor; CBOR encoding tests.ic-validator:DelegationRestrictionsthreaded through delegation-chain validation; presence enforcement on the call path; new error variant mirrored inic-validator-ingress-message.ic-validator-http-request-test-utils:delegate_to_with_sender_info_requiredchain-builder support.falseunrestricted / requirement in the middle of a chain.Follow-ups
cargo test -p ic-types -p ic-validator -p ic-validator-ingress-messagepasses and clippy is clean. Bazel was not available in the development container, so CI should confirm the Bazel build.https://claude.ai/code/session_01BQNgPJKgxWohrJ6owwJBzz
Generated by Claude Code