Skip to content

docs: extend interface spec with delegation permissions field#292

Open
aterga wants to merge 5 commits into
mainfrom
claude/gracious-cerf-zou2uv
Open

docs: extend interface spec with delegation permissions field#292
aterga wants to merge 5 commits into
mainfrom
claude/gracious-cerf-zou2uv

Conversation

@aterga

@aterga aterga commented Jun 12, 2026

Copy link
Copy Markdown

Summary

Extends the IC interface spec with the optional permissions field of request delegations, as drafted in the replica implementation in dfinity/ic#10449.

  • https-interface.md (Authentication): documents the new permissions field of the delegation map. "queries" restricts the delegation to query calls and read_state requests; requests to /call endpoints are not accepted if any delegation in the chain carries this value, and a later delegation cannot lift the restriction. "all" is the same as omitting the field. Any other value makes the delegation invalid for requests of any kind (fail-closed). Also adds permissions to the string-typed field examples in the representation-independent hashing section, since the field is covered by the delegation signature.
  • abstract-behavior.md (formal model): extends SignedDelegation with permissions : Text | Unrestricted. verify_delegations now requires every delegation's permissions field to hold a supported value, and verify_envelope fails for update calls (content of type Request) when any delegation in the chain is restricted to "queries". Because verify_envelope can distinguish update calls from read-only requests by the type of the enclosed content, no changes to the nine call sites of verify_envelope were needed.
  • changelog.md: adds a 0.63.0 entry visibly marked "unreleased"; an HTML comment instructs to assign the final version number and release date when the feature ships.

Structural decisions

  • The whole-chain semantics ("queries" anywhere in the chain restricts the entire chain; unsupported values reject all request kinds) mirror validate_delegations in rs/validator/src/ingress_validation.rs of the draft implementation, including its test for a restriction sitting in the middle of a chain.
  • The restriction is phrased against /call endpoints rather than "update calls" alone, so replicated queries (query methods submitted as update calls) are explicitly covered, matching the implementation which rejects at ingress validation.

npm run build passes (209 pages).

https://claude.ai/code/session_01WBqBka57Q7xYi4btZYfPqT

Specify the optional permissions field of request delegations drafted
in dfinity/ic#10449:

- https-interface.md: document the permissions field of the delegation
  map ("queries" restricts the delegation to query calls and read_state
  requests, "all" is the same as omitting the field, any other value
  makes the delegation invalid for all kinds of requests) and add
  permissions to the string-typed fields in the representation-
  independent hashing section.
- abstract-behavior.md: extend SignedDelegation with
  permissions : Text | Unrestricted and amend verify_envelope /
  verify_delegations so that unsupported values fail verification for
  all requests and update calls fail if any delegation in the chain is
  restricted to queries.
- changelog.md: add a 0.63.0 entry for the feature.

https://claude.ai/code/session_01WBqBka57Q7xYi4btZYfPqT
@github-actions github-actions Bot added the interface-spec Changes to the IC interface specification label Jun 12, 2026
@github-actions

github-actions Bot commented Jun 12, 2026

Copy link
Copy Markdown

🤖 Here's your preview: https://k7oic-piaaa-aaaam-ai7uq-cai.icp0.io

@aterga aterga marked this pull request as ready for review June 12, 2026 16:26
@aterga aterga requested review from a team as code owners June 12, 2026 16:26

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the Internet Computer (IC) interface specification to describe a new optional permissions field on request delegations, aligning the spec and formal model with the draft replica implementation semantics (including “whole-chain” restrictions).

Changes:

  • Documented the optional permissions delegation field and its semantics in the HTTPS interface spec (including hashing coverage for signatures).
  • Updated the formal model (abstract-behavior.md) to model permissions and enforce it in verify_delegations / verify_envelope.
  • Added a changelog entry for the new field (currently marked as needing release/version/date confirmation).

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
docs/references/ic-interface-spec/https-interface.md Adds permissions to delegation documentation and includes it in hashing examples.
docs/references/ic-interface-spec/abstract-behavior.md Extends the formal SignedDelegation model and updates verification predicates to enforce permissions semantics.
docs/references/ic-interface-spec/changelog.md Adds a new changelog entry describing the permissions delegation field.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread docs/references/ic-interface-spec/changelog.md Outdated
The draft status was only visible in an HTML comment, so the rendered
changelog presented a provisional version and date as a finalized
release. Mark the entry visibly as unreleased and drop the date until
the feature ships.

https://claude.ai/code/session_01WBqBka57Q7xYi4btZYfPqT

aterga commented Jun 12, 2026

Copy link
Copy Markdown
Author

Feedback addressed:

  • The changelog entry no longer presents a provisional release as final: the heading now reads 0.63.0 (unreleased) in the rendered changelog, the fabricated date is gone, and the HTML comment instructs to assign the final version and release date when the feature ships.

Generated by Claude Code

Comment thread docs/references/ic-interface-spec/abstract-behavior.md Outdated
@Dfinity-Bjoern

Copy link
Copy Markdown

We should also adapt /developer-docs/references/requests.cddl to match this change.

Mirror the new optional permissions field of request delegations in the
CBOR schema. Enumerate the supported values ("queries" / "all") to match
the spec, consistent with how request_type and status enumerate literals.

https://claude.ai/code/session_01WBqBka57Q7xYi4btZYfPqT

@Dfinity-Bjoern Dfinity-Bjoern left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me now.

Per review on abstract-behavior.md, type the permissions field as the
literal enumeration "queries" | "all" | Unrestricted, consistent with the
requests.cddl encoding and with how request_type and status enumerate
literals. The type now constrains the supported values, so the explicit
membership check in verify_delegations is redundant and removed; the
update-call restriction (queries-restricted delegations reject update
calls) stays.

https://claude.ai/code/session_01WBqBka57Q7xYi4btZYfPqT
Comment thread docs/references/ic-interface-spec/abstract-behavior.md Outdated
…odel

Apply review suggestion: use capitalized variant names
Queries | All | Unrestricted for the permissions field, matching the
formal model's convention for enumerations (e.g. RequestStatus) rather
than quoted string literals. Update the verify_envelope comparison and
the predicate's preamble to reference the Queries variant, noting it is
encoded as the text "queries". The requests.cddl keeps the quoted
"queries" / "all" encoding.

https://claude.ai/code/session_01WBqBka57Q7xYi4btZYfPqT
aterga pushed a commit to dfinity/ic that referenced this pull request Jun 23, 2026
Per the settled interface-spec model (dfinity/developer-docs#292, which
defines the field as the union `Queries | All | Unrestricted`), replace
the `Option<String>` `permissions` field with a typed
`Option<DelegationPermissions>` enum whose `Queries`/`All` variants are
encoded on the wire (and in the representation-independent hash) as the
text `"queries"`/"all"".

Consequences:
- Unsupported values are now rejected when the request is decoded (the
  field is a closed enum), so the runtime
  AuthenticationError::UnsupportedDelegationPermissions check in
  validate_delegations is gone, along with the error variant in both the
  validator and ingress-message crates.
- The "unsupported value rejected" coverage moves to a CBOR-decoding test
  in ic-types (delegation_permissions_rejects_unsupported_value), which
  also covers case/whitespace variants of the supported values.
- The validator/e2e/system tests that previously constructed invalid
  string permissions are removed or switched to the typed enum.

https://claude.ai/code/session_01BQNgPJKgxWohrJ6owwJBzz
pull Bot pushed a commit to mikeyhodl/ic that referenced this pull request Jun 24, 2026
…ns (dfinity#10449)

# Queries-only permissions on delegations

**This is the consolidated read-only-sessions feature** (the previously
stacked alternatives dfinity#10447/dfinity#10452, which carried the restriction in
certified `sender_info` attributes, were closed in favor of this more
lightweight approach).

## What it does

Request delegations gain an optional `permissions` field, mirroring the
existing `targets` field. It is modeled as a typed enum
`DelegationPermissions` whose variants are encoded on the wire (and in
the representation-independent hash) as text:

* `permissions` **absent** or **`"all"`** (`DelegationPermissions::All`)
→ the sender can execute all functions — queries, replicated queries,
and updates (today's semantics; byte-for-byte identical hash for
existing delegations without the field).
* **`"queries"`** (`DelegationPermissions::Queries`) → the sender can
only execute queries: requests to `/call` endpoints (updates *and*
replicated queries) authenticated through such a chain are rejected
during ingress validation with the new
`RequestValidationError::UpdateCallNotPermittedByDelegation`; query and
`read_state` requests remain permitted.
* **Any other value** → because the field is a closed enum, an
unsupported value fails to deserialize, so the request is **rejected
when it is decoded** (before validation). There is no dedicated
validator error for it.

A restriction anywhere in the chain applies to the whole chain (like
`targets`, restrictions only accumulate). The matching interface-spec
change (dfinity/developer-docs#292) models the field as the union
`Queries | All | Unrestricted`, which this enum mirrors exactly.

## Why this can't be bypassed, and why it's backward compatible

* The field is part of the delegation's representation-independent hash,
i.e. covered by the delegation signature. A dapp holding the session key
**cannot strip the field** — doing so changes the hash and invalidates
the signature.
* **Old replicas fail closed**: they parse the delegation without the
unknown field (serde ignores unknown map keys), recompute the hash
without it, and signature verification fails. A restricted delegation is
unusable on un-upgraded replicas rather than silently unrestricted.
Rollout: replicas first, issuers (Internet Identity) after.
* Delegations without the field are completely unaffected, so existing
agents, dapps, and issuers need no changes. Agents only need to
round-trip the new field once they want to carry restricted delegations;
an agent that drops it fails closed.
* The enforcement point is `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), enforced by the protocol
regardless of the client's cooperation. II sets this field from a
"Read-only mode" checkbox in the authorize flow (II-side changes
prepared separately).

Historical precedent: the interface spec already extended the delegation
map with an optional restriction field once — the `senders` field (added
Dec 2021, never implemented by the replica, removed in
[interface-spec#246](dfinity/interface-spec#246)).
This PR follows the same formal pattern (`verify_delegations`
accumulation), but implementation-first.

## Changes

* `ic-types`: typed `DelegationPermissions { Queries, All }` enum
(serialized as `"queries"`/`"all"`); optional `Delegation.permissions`
field included in the signed bytes (`hash_of_map` key `"permissions"`);
chainable `with_targets`/`with_permissions` builder methods (replacing
the former `new_with_targets`/`new_with_permissions` constructors so a
delegation can carry both).
* `ic-validator`: `DelegationRestrictions` (targets + queries-only)
threaded through delegation-chain validation; update-call rejection via
`RequestValidationError::UpdateCallNotPermittedByDelegation`. The
`/call` path uses the shared `validate_request_content` (no
special-casing) and checks the restriction afterwards.
* `ic-validator-ingress-message`: the new error variant mirrored.
* `ic-validator-http-request-test-utils`: `delegate_to_with_permissions`
chain-builder support.
* Tests: signed-bytes golden test for the new field; CBOR encoding +
round-trip tests; a decode-rejection test
(`delegation_permissions_rejects_unsupported_value`) covering
unsupported values including case/whitespace variants; validator-level
e2e tests (update-rejected / query-and-read_state-permitted /
`"all"`-permitted / restriction-mid-chain / combined
targets+permissions); and a system test
(`requests_with_delegation_permissions` in
`rs/tests/crypto/ingress_verification_test.rs`, tagged `long_test`)
exercising the full HTTP path against a real replica.

## Caveats / follow-ups

* Calls to query methods submitted via the `/call` path (replicated
queries) are rejected for `"queries"` delegations by design — the
`"all"` vocabulary makes this explicit.
* Interface-spec change in dfinity/developer-docs#292; II-side issuance
and agent (`@icp-sdk/core`) round-tripping of the field
prepared/pending.

`cargo test -p ic-types -p ic-validator -p ic-validator-ingress-message`
passes and clippy is clean; downstream consumers
(`ic-http-endpoints-public`, `ic-ingress-manager`, `ic-canister-client`,
`ic-state-machine-tests`) and both affected system-test binaries
compile.

https://claude.ai/code/session_01BQNgPJKgxWohrJ6owwJBzz

---------

Co-authored-by: Claude <noreply@anthropic.com>
Comment on lines +11 to +12
<!-- Needs human verification: assign the final version number and replace "unreleased" with the release date when the permissions feature ships -->
### 0.63.0 (unreleased) {$0_63_0}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The date should be updated and the PR merged when the feature is rolled out to all subnets (tentatively on Monday, July 6).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

interface-spec Changes to the IC interface specification

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants