Skip to content

chore: Add Expiry Extraction Utilities to gator-permissions-controller#7195

Merged
hanzel98 merged 16 commits intomainfrom
feat/gator-permissions-expiry-extraction
Dec 2, 2025
Merged

chore: Add Expiry Extraction Utilities to gator-permissions-controller#7195
hanzel98 merged 16 commits intomainfrom
feat/gator-permissions-expiry-extraction

Conversation

@hanzel98
Copy link
Contributor

@hanzel98 hanzel98 commented Nov 19, 2025

Explanation

This PR export the delegation framework version and skips the rules from the sanitization of the permissions response. The rules include the expiry.

Solution

This PR introduces:

  1. Skip rules from sanitization

    • The rules is part of the permission stored in the profile sync it includes the expiration date
  2. DELEGATION_FRAMEWORK_VERSION constant

    • Moved to new constants.ts file to prevent circular dependencies
    • Ensures version consistency across implementations

References

Checklist

  • I've updated the test suite for new or updated code as appropriate
  • I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate
  • I've communicated my changes to consumers by updating changelogs for packages I've changed, highlighting breaking changes as necessary
  • I've prepared draft pull requests for clients and consumer packages to resolve any breaking changes (not applicable - no breaking changes)

Note

Keeps rules in sanitized permission responses, introduces strict TimestampEnforcer expiry parsing/validation, and exports DELEGATION_FRAMEWORK_VERSION from a new constants.ts.

  • Decode/validation (BREAKING)
    • Add extractExpiryFromCaveatTerms and enforce strict TimestampEnforcer terms: exact length, timestampAfterThreshold must be 0, timestampBeforeThreshold > 0, and safe-integer checks; update error messages accordingly.
  • Controller & Types
    • Sanitization now only removes dependencyInfo and signer; preserves permissionResponse.rules.
    • PermissionResponseSanitized updated to retain rules.
  • Exports & Constants
    • Move DELEGATION_FRAMEWORK_VERSION to new constants.ts and export via package index; update imports.
  • Tests
    • Update tests to verify preserved rules and new expiry validation scenarios.
  • Changelog
    • Document breaking validation changes and new exports.

Written by Cursor Bugbot for commit 9313be3. This will update automatically on new commits. Configure here.

@hanzel98 hanzel98 requested review from a team as code owners November 19, 2025 21:37
@hanzel98 hanzel98 self-assigned this Nov 19, 2025
@hanzel98 hanzel98 requested review from MoMannn and mj-kiwi November 19, 2025 22:42
@hanzel98 hanzel98 changed the title feat: add expiry extraction utilities to gator-permissions-controller chore: Add Expiry Extraction Utilities to gator-permissions-controller Nov 19, 2025
mj-kiwi
mj-kiwi previously approved these changes Nov 19, 2025
Copy link

@mj-kiwi mj-kiwi left a comment

Choose a reason for hiding this comment

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

LGTM

@hanzel98 hanzel98 requested a review from mj-kiwi November 20, 2025 05:43
Copy link
Member

@MoMannn MoMannn left a comment

Choose a reason for hiding this comment

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

I think that instead of a util function the expiry should be decoded and saved under Rules in the permission. So that anyone fetching the permissions would already get decoded expiry and does not need to decode every time.

- Export extractExpiryFromPermissionContext to extract expiry from delegation contexts
- Export DELEGATION_FRAMEWORK_VERSION constant for consistency
- Add extractExpiryFromCaveatTerms helper for parsing TimestampEnforcer terms
- Add validation for terms length (must be exactly 32 bytes)
- Add overflow protection for timestamps exceeding Number.MAX_SAFE_INTEGER
- Add comprehensive test coverage for new functions
- Refactor existing code to use new shared expiry extraction logic
- Fix import of DELEGATION_FRAMEWORK_VERSION in test file
- Remove redundant Number.isSafeInteger check (hexToNumber already validates)
- Update extractExpiry tests to reflect actual error behavior
- Update error message tests in decodePermission.test.ts
- Add tests with real encoded delegations using encodeDelegations
- Cover success case: extraction from valid context with timestamp caveat
- Cover edge cases: no timestamp caveat, zero expiry, multiple delegations
- Cover error cases: invalid context, unsupported chain, malformed data
- This increases coverage for lines 276-299 in decodePermission.ts
- Add test mocking decodeDelegations to return array with undefined element
- This covers line 278: the defensive check for null/undefined delegation
- Should achieve 100% code coverage
…sionResponseSanitized

- Export DELEGATION_FRAMEWORK_VERSION constant for version consistency
- Include rules property in PermissionResponseSanitized for stronger typing
- Remove extractExpiryFromPermissionContext (no longer needed)
- Keep extractExpiryFromCaveatTerms as internal implementation detail
- Update tests and remove unused exports
- Fix linting issues
@hanzel98 hanzel98 force-pushed the feat/gator-permissions-expiry-extraction branch from a544388 to b90b881 Compare November 20, 2025 17:04
- Move extractExpiryFromCaveatTerms tests to decodePermission.test.ts for consistency
- Make extractExpiryFromCaveatTerms internal (remove export) as it's only used within decodePermission.ts
- Add comprehensive edge case tests through getPermissionDataAndExpiry:
  - Terms too short/long validation
  - Safe integer validation for expiry timestamps
  - Large valid timestamp handling
- Delete separate extractExpiry.test.ts file
- All 49 tests passing with 100% coverage of extraction logic
MoMannn
MoMannn previously approved these changes Nov 24, 2025
Copy link
Member

@MoMannn MoMannn left a comment

Choose a reason for hiding this comment

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

There are some merge conflicts in changelog

- Update test to verify rules are preserved (not removed) in sanitized responses
- Add test case with rules containing expiry to demonstrate rules can include expiry data
- Remove assertion that rules should be undefined (rules are now preserved per PR #7195)
Resolved CHANGELOG.md conflict by properly organizing Added and Changed sections
- Add test to verify that when timestampBeforeThreshold is 0, expiry returns null
- This covers the missing branch in extractExpiryFromCaveatTerms function
- Achieves 100% branch coverage
jeffsmale90
jeffsmale90 previously approved these changes Nov 27, 2025
Copy link
Contributor

@jeffsmale90 jeffsmale90 left a comment

Choose a reason for hiding this comment

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

Looks good!

- Add validation to reject timestampBeforeThreshold === 0
- Update extractExpiryFromCaveatTerms to throw on zero expiry
- Update test to expect error instead of null for zero expiry
- Document validation errors in CHANGELOG
Resolved conflicts:
- CHANGELOG.md: Combined both sets of changes
- GatorPermissionsController.test.ts: Kept both imports
MoMannn
MoMannn previously approved these changes Nov 28, 2025
@jeffsmale90 jeffsmale90 added the team-delegation MetaMask Delegation Team label Nov 30, 2025
Resolved conflicts:
- CHANGELOG.md: Moved unreleased changes to new Unreleased section after 0.7.0 release
Copy link
Contributor

@jeffsmale90 jeffsmale90 left a comment

Choose a reason for hiding this comment

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

This looks good - it would be great to add a reference to the PR to the changelog

Resolved conflicts:
- CHANGELOG.md: Combined timestamp validation changes with transaction-controller bump
Copy link
Contributor

@jeffsmale90 jeffsmale90 left a comment

Choose a reason for hiding this comment

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

Let's goooo!

@hanzel98 hanzel98 added this pull request to the merge queue Dec 2, 2025
Merged via the queue into main with commit d08256e Dec 2, 2025
281 checks passed
@hanzel98 hanzel98 deleted the feat/gator-permissions-expiry-extraction branch December 2, 2025 19:44
github-merge-queue bot pushed a commit to MetaMask/metamask-extension that referenced this pull request Jan 12, 2026
## **Description**

Fixes #464 - Gator permissions with expiry were displaying "No
expiration" in the UI.

**Root Cause:** The expiry timestamp was excluded as part of a
sanitization of the permissions response because it was stored in the
permission.

**Solution:** 
- Include the rules as part of the permissions responde so we can find
the expirty inside, this part of the work is done in the
gator-permissions-controller

## **Changelog**

CHANGELOG entry: Fixed gator permissions displaying "No expiration" when
expiry timestamp exists

## **Related issues**

Fixes: #464

## **Manual testing steps**

1. Create a gator permission with an expiry timestamp from
`jeff.dripfund.xyz`
2. Navigate to Settings → Permissions → All Permissions
3. Locate the gator permission from `jeff.dripfund.xyz`
4. Expand the permission details
5. Verify the expiration date displays correctly (e.g., "11/13/2026")
instead of "No expiration"

## **Screenshots/Recordings**

### **Before**
Permission showed "No expiration" despite having an expiry timestamp in
the delegation context.

### **After**
Permission now correctly displays the expiration date (e.g.,
"11/13/2026") extracted from the `TimestampEnforcer` caveat.

## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask
Extension Coding
Standards](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable (7 comprehensive test cases
covering all edge cases)
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

- [x] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.


<img width="1278" height="2074" alt="image"
src="https://github.com/user-attachments/assets/b5e29995-4127-49b1-bac5-c6e49a73dd41"
/>



<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> Fixes incorrect "No expiration" display by sourcing expiry from
delegation rules.
> 
> - Use `extractExpiryToReadableDate(permissionResponse.rules || [])` in
`ReviewGatorPermissionItem` for stream/periodic/revocation permissions;
fallback to `gatorPermissionNoExpiration` when no expiry rule exists
> - Update memo/callback dependencies to include
`permissionResponse.rules`
> - Tests: add expiry rule to mocks and assert exact dates; add cases
for no rules and non-expiry rules showing "No expiration"; cover native
and ERC20 stream/periodic, revocation, and date formatting
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
464f0b5. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->





Depends on this one MetaMask/core#7195 Pending
to upgrade to the gator-permissions-controller: ^0.6.0

---------

Co-authored-by: Tadej Vengust <tadej.vengust@consensys.net>
github-merge-queue bot pushed a commit to MetaMask/metamask-extension that referenced this pull request Jan 12, 2026
## **Description**

Fixes #464 - Gator permissions with expiry were displaying "No
expiration" in the UI.

**Root Cause:** The expiry timestamp was excluded as part of a
sanitization of the permissions response because it was stored in the
permission.

**Solution:** 
- Include the rules as part of the permissions responde so we can find
the expirty inside, this part of the work is done in the
gator-permissions-controller

## **Changelog**

CHANGELOG entry: Fixed gator permissions displaying "No expiration" when
expiry timestamp exists

## **Related issues**

Fixes: #464

## **Manual testing steps**

1. Create a gator permission with an expiry timestamp from
`jeff.dripfund.xyz`
2. Navigate to Settings → Permissions → All Permissions
3. Locate the gator permission from `jeff.dripfund.xyz`
4. Expand the permission details
5. Verify the expiration date displays correctly (e.g., "11/13/2026")
instead of "No expiration"

## **Screenshots/Recordings**

### **Before**
Permission showed "No expiration" despite having an expiry timestamp in
the delegation context.

### **After**
Permission now correctly displays the expiration date (e.g.,
"11/13/2026") extracted from the `TimestampEnforcer` caveat.

## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask
Extension Coding
Standards](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable (7 comprehensive test cases
covering all edge cases)
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

- [x] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.


<img width="1278" height="2074" alt="image"
src="https://github.com/user-attachments/assets/b5e29995-4127-49b1-bac5-c6e49a73dd41"
/>



<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> Fixes incorrect "No expiration" display by sourcing expiry from
delegation rules.
> 
> - Use `extractExpiryToReadableDate(permissionResponse.rules || [])` in
`ReviewGatorPermissionItem` for stream/periodic/revocation permissions;
fallback to `gatorPermissionNoExpiration` when no expiry rule exists
> - Update memo/callback dependencies to include
`permissionResponse.rules`
> - Tests: add expiry rule to mocks and assert exact dates; add cases
for no rules and non-expiry rules showing "No expiration"; cover native
and ERC20 stream/periodic, revocation, and date formatting
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
464f0b5. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->





Depends on this one MetaMask/core#7195 Pending
to upgrade to the gator-permissions-controller: ^0.6.0

---------

Co-authored-by: Tadej Vengust <tadej.vengust@consensys.net>
github-merge-queue bot pushed a commit to MetaMask/metamask-extension that referenced this pull request Jan 13, 2026
## **Description**

Fixes #464 - Gator permissions with expiry were displaying "No
expiration" in the UI.

**Root Cause:** The expiry timestamp was excluded as part of a
sanitization of the permissions response because it was stored in the
permission.

**Solution:** 
- Include the rules as part of the permissions responde so we can find
the expirty inside, this part of the work is done in the
gator-permissions-controller

## **Changelog**

CHANGELOG entry: Fixed gator permissions displaying "No expiration" when
expiry timestamp exists

## **Related issues**

Fixes: #464

## **Manual testing steps**

1. Create a gator permission with an expiry timestamp from
`jeff.dripfund.xyz`
2. Navigate to Settings → Permissions → All Permissions
3. Locate the gator permission from `jeff.dripfund.xyz`
4. Expand the permission details
5. Verify the expiration date displays correctly (e.g., "11/13/2026")
instead of "No expiration"

## **Screenshots/Recordings**

### **Before**
Permission showed "No expiration" despite having an expiry timestamp in
the delegation context.

### **After**
Permission now correctly displays the expiration date (e.g.,
"11/13/2026") extracted from the `TimestampEnforcer` caveat.

## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask
Extension Coding
Standards](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable (7 comprehensive test cases
covering all edge cases)
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

- [x] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.


<img width="1278" height="2074" alt="image"
src="https://github.com/user-attachments/assets/b5e29995-4127-49b1-bac5-c6e49a73dd41"
/>



<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> Fixes incorrect "No expiration" display by sourcing expiry from
delegation rules.
> 
> - Use `extractExpiryToReadableDate(permissionResponse.rules || [])` in
`ReviewGatorPermissionItem` for stream/periodic/revocation permissions;
fallback to `gatorPermissionNoExpiration` when no expiry rule exists
> - Update memo/callback dependencies to include
`permissionResponse.rules`
> - Tests: add expiry rule to mocks and assert exact dates; add cases
for no rules and non-expiry rules showing "No expiration"; cover native
and ERC20 stream/periodic, revocation, and date formatting
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
464f0b5. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->





Depends on this one MetaMask/core#7195 Pending
to upgrade to the gator-permissions-controller: ^0.6.0

---------

Co-authored-by: Tadej Vengust <tadej.vengust@consensys.net>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

no-changelog team-delegation MetaMask Delegation Team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants