feat: reject update calls for delegations with queries-only permissions#10449
Draft
aterga wants to merge 3 commits into
Draft
feat: reject update calls for delegations with queries-only permissions#10449aterga wants to merge 3 commits into
aterga wants to merge 3 commits into
Conversation
Adds an optional permissions field to request delegations, mirroring the existing targets field. When a delegation in a request's delegation chain carries permissions = "queries", the ingress validator rejects update calls authenticated through that chain with the new UpdateCallNotPermittedByDelegation error, while query and read_state requests remain permitted. Delegations with permissions = "updates" or without the field are unrestricted, and any other value is rejected as unsupported (fail-closed, since no pre-existing delegations carry the field). The field is covered by the delegation signature (it is part of the representation-independent hash), so a client cannot strip it to lift the restriction: removing the field changes the delegation hash and invalidates the signature. For the same reason, replicas that predate this change fail closed on restricted delegations. This enables issuers like Internet Identity to sign read-only delegations that can read on the user's behalf (perform query calls) but cannot change state (perform update calls), enforced by the protocol regardless of the client's cooperation. It is the strictly-enforced counterpart to the sender_info-based attribute approach (#10447). https://claude.ai/code/session_01BQNgPJKgxWohrJ6owwJBzz
Contributor
There was a problem hiding this comment.
Pull request overview
This PR extends IC request delegations with an optional permissions field to support queries-only delegations that are enforced during ingress validation (rejecting /call update requests), while remaining backward compatible for existing delegations and failing closed on unsupported permission values.
Changes:
- Add
Delegation.permissionstoic-types, include it in the delegation’s signed bytes, and expose constructors/accessors. - Thread delegation permission restrictions through
ic-validatordelegation-chain validation and reject update calls when any delegation in the chain haspermissions = "queries". - Add test utilities and end-to-end tests covering acceptance/rejection behavior across request types and invalid permission values.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| rs/validator/tests/ingress_validation.rs | Adds a golden signed-bytes test covering the new permissions field hashing. |
| rs/validator/src/ingress_validation/tests.rs | Updates unit tests to match the new validate_signature return type (restrictions vs targets). |
| rs/validator/src/ingress_validation.rs | Implements delegation permissions parsing, restriction accumulation, and update-call rejection. |
| rs/validator/ingress_message/tests/validate_request.rs | Adds e2e tests verifying update rejection and query/read_state acceptance for queries-only delegations. |
| rs/validator/ingress_message/src/lib.rs | Exposes the new validation/authentication error variants in the standalone validator API. |
| rs/validator/ingress_message/src/internal/mod.rs | Maps new ic_validator error variants into ic_validator_ingress_message equivalents. |
| rs/validator/http_request_test_utils/src/lib.rs | Extends delegation-chain builder utilities to create delegations with permissions. |
| rs/types/types/src/messages/http/tests.rs | Updates CBOR serialization tests to include the new permissions field (null or string). |
| rs/types/types/src/messages/http.rs | Adds Delegation.permissions, constructor/accessor, and includes it in signed-bytes hashing when present. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Short-circuit the queries-only delegation rejection before sender_info canister signature verification on the call path, make the error message byte-identical across the validator crates, and strengthen test assertions to also check queries_only. 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.
Queries-only permissions on delegations
This is the strictly-enforced counterpart to the
sender_info-attribute approach in #10447: instead of (or in addition to) reading permissions out of certified session attributes, the restriction is carried by the delegation itself, so the protocol enforces it regardless of the client's cooperation.What it does
Request delegations gain an optional
permissionsfield, mirroring the existingtargetsfield:permissionsabsent or"updates"→ unrestricted (today's semantics, byte-for-byte identical hash for existing delegations).permissions = "queries"→ the sender authenticated through this chain may make query and read_state requests, but update calls are rejected during ingress validation with the newRequestValidationError::UpdateCallNotPermittedByDelegation.AuthenticationError::UnsupportedDelegationPermissions(fail-closed: no pre-existing delegations carry the field, so unknown values need no legacy leniency — unlike the sender_info variant, which must fail open on unparseable legacy blobs).A restriction anywhere in the chain applies to the whole chain (like
targets, restrictions only accumulate).Why this can't be bypassed, and why it's backward compatible
HttpRequestVerifier<SignedIngressContent>— the same verifier used by the ingress manager for block validation, so a malicious boundary node or replica cannot smuggle a restricted update call into a block.Rationale
Enables issuers like Internet Identity to sign read-only delegations: sessions that can read on the user's behalf (query calls) but cannot change state (update calls). In the companion design, II sets this field from the same "Read-only mode" checkbox that drives the
implicit:permissionscertified attribute of #10447 — the delegation field is the enforcement bit, the attribute remains the canister-visible metadata (ic0.msg_caller_info_data_*).Changes
ic-types:Delegation.permissions(optional),new_with_permissions, accessor, inclusion in the signed bytes (hash_of_mapkey"permissions").ic-validator:DelegationRestrictions(targets + queries-only) threaded through delegation-chain validation; update-call rejection; fail-closed handling of unsupported values; new error variants mirrored inic-validator-ingress-message.ic-validator-http-request-test-utils:delegate_to_with_permissionschain-builder support."updates"-permitted / unknown-value-rejected / restriction-in-the-middle-of-a-chain.Caveats / follow-ups
/callpath is restricted, including replicated queries (the validator cannot know method kinds).verify_delegationsformal conditions) to follow in dfinity/portal, and II-side issuance + agent (@dfinity/agent) round-tripping of the field.rs/tests/crypto/ingress_verification_test.rs(mirroring the delegation tests there) is a natural follow-up; the validator-level e2e tests in this PR cover the enforcement semantics.cargo test -p ic-types -p ic-validator -p ic-validator-ingress-messagepasses and clippy is clean; downstream consumers (ic-http-endpoints-public,ic-ingress-manager,ic-canister-client,ic-state-machine-tests) compile. 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