Skip to content

fix(delegation): a present non-integer depth makes a legacy record invalid - #26

Merged
aeoess merged 2 commits into
mainfrom
fix/legacy-maxdepth-nonnumeric
Oct 11, 2026
Merged

aeoess merged 2 commits into
mainfrom
fix/legacy-maxdepth-nonnumeric

Conversation

@aeoess

@aeoess aeoess commented Oct 11, 2026 •

Copy link
Copy Markdown
Member

What problem this solves

agent-passport-system/agent-passport-system#223. verify_delegation skipped the depth comparison for a signed maxDepth or currentDepth that is not a number, so the record verified at any depth. The TypeScript verifier coerced "1" to 1 and rejected the same record.

Why this change was made

A verifier should not report a depth result it did not establish, and the two SDKs should agree on validity for the same signed bytes.

User impact

  • A present maxDepth or currentDepth must be a non-negative integer no greater than 2**53 - 1, matching the TypeScript safe-integer limit. Anything else makes the record invalid, with a Malformed maxDepth or Malformed currentDepth error. depthExceeded stays False because no comparison was made.
  • Integer-valued floats such as 2.0 remain accepted, since they sign to the same bytes as 2.
  • An absent or None member is not compared, matching the TypeScript verifier.
  • _is_depth moves to module level, so verify_delegation, sub_delegate and create_delegation share one depth rule.
  • create_delegation now raises ValueError for a max_depth its verifier would reject, so the SDK cannot return a signed record its own verifier rejects. None is unchanged: it signs as no maxDepth member, which verifies with no ceiling.
  • The TypeScript side is fix(delegation): a present non-integer depth makes a legacy record invalid agent-passport-system#225 with the same rule.

Evidence

  • tests/test_legacy_maxdepth_absent.py: the test that pinned the old skip is replaced. Malformed maxDepth at depth 0 and 2, malformed currentDepth with and without a ceiling, integer-valued floats, None and absent members. With the verifier change reverted, the new cases fail.
  • Writer tests: 1.5, -1, 2**53, NaN, infinity, "1" and True raise, and 0, 1, 2.0, 2**53 - 1 and None sign and verify. With the writer guard reverted, the refusal test fails.
  • maxDepth 2**53 is malformed and 2**53 - 1 is accepted, in both SDKs.
  • pytest: 2756 passed, 6 skipped.

Boundaries

…valid

verify_delegation skipped the depth comparison for a signed maxDepth or currentDepth that is not a number, so the record verified at any depth, while the TypeScript verifier coerced "1" to 1 and rejected it. A present maxDepth or currentDepth that is not a non-negative integer is now invalid, with no depth result reported. Integer-valued floats are compared as before. An absent or None member is not compared, matching the TypeScript verifier. Refs agent-passport-system/agent-passport-system#223.

Signed-off-by: Tymofii Pidlisnyi <tima@aeoess.com>
…ejects

create_delegation signed a max_depth such as -1 or 1.5 that verify_delegation now reports malformed. It now raises ValueError for any value that is not a non-negative integer up to 2**53 - 1. None is unchanged: it signs as no maxDepth member, which verifies with no ceiling. Refs agent-passport-system/agent-passport-system#223.

Signed-off-by: Tymofii Pidlisnyi <tima@aeoess.com>
@aeoess
aeoess merged commit 41b8e13 into main Oct 11, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant