Skip to content

fix(push): persist client revocation until it succeeds - #8706

Open
jmecom wants to merge 16 commits into
jm/push-ingress-limitsfrom
jm/push-client-revocation
Open

jmecom wants to merge 16 commits into
jm/push-ingress-limitsfrom
jm/push-client-revocation

Conversation

@jmecom

@jmecom jmecom commented Oct 29, 2026 •

Copy link
Copy Markdown
Collaborator

Turning off push or removing a community must retire its gateway permission and relay lease after a restart or lost response. Persist the two cleanup operations separately, so either can finish while the other is unavailable. Journal the gateway target before native revocation can erase it, and retry while the relay is disconnected. Preserve shared grants, installation/signer ownership, and stale-enrollment protection.

Validation: 67 focused Flutter tests and clean mobile analysis, covering either cleanup operation failing, restart recovery, opt-out, and shared ownership. The tests mock native callbacks; physical-device App Attest/APNs verification remains pending.

Stack (merge in order): #8673 → #8703 → #8704 → #8705 → #8706 → #8707 → #8708.

* commit '4353f060f407f63cf79765a4a960aa73d18ca2de':
  test(desktop): bind duplicate voice players to message IDs

Signed-off-by: jm <[email protected]>
@jmecom
jmecom removed this pull request from stack #8721 October 30, 2026 00:25
@jmecom
jmecom added this pull request to stack #8724 October 30, 2026 00:25
brow pushed a commit that referenced this pull request Nov 3, 2026
## Summary

Fix community removal failing with “Expected exactly one endpoint grant
for push lease revocation” when saved push state exists but the current
build has no cached grant, including builds without a push gateway.

When the community has a saved installation ID, journal its targeted
revocation without requiring the grant. An unknown grant expiry stays
unknown: retain cleanup credentials until the relay accepts the
revocation. Existing known-expiry cleanup and legacy grant-based
addressing remain unchanged.

### Related issue

No matching open issue found. Follows [the durable revocation
outbox](#8706).

### Testing

The new regression fails with the reported error on the preceding
implementation. It now verifies missing-grant enqueue, offline retry,
persistence across restart, the exact lease address and eventual cleanup
after acceptance. On a physical iPhone with the fix applied to the
onboarding test build, the previously failing community removal
succeeded.

Unknown-expiry records retain their signing key in secure storage until
successful revocation. Downgrading to a client that requires an integer
expiry will reject those pending records.

Signed-off-by: John Tennant <[email protected]>
Co-authored-by: Aaron <f425b86c3b780d43f8d9cf1802429d04dd985bf92eac44fca9468b5ad3887c5e@buzz.block.builderlab.xyz>
@jmecom
jmecom marked this pull request as ready for review November 3, 2026 20:54
@jmecom
jmecom requested a review from a team as a code owner November 3, 2026 20:54

@joahg joahg left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

🤖 Read the outbox split into gateway-only and relay records, the shared-grant recheck at execution time, and the Swift revoke/settle paths; each cleanup is journaled before native inventory is erased. P3: records carrying a gateway target are exempt from the expiresAt purge, so a gateway rejection that never clears (e.g. a non-retryable 4xx) retries forever; worth confirming only transient errors reach that path. Physical-device App Attest/APNs verification is still pending per the description.

@jmecom
jmecom removed this pull request from stack #8724 November 5, 2026 21:43
@jmecom
jmecom added this pull request to stack #9143 November 5, 2026 21:43

@joahg joahg left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

🤖 Re-approving. Most of the new diff adapts to the base's nullable expiresAt and HostedRelayAuth. The one semantic change, journaling a relay-only revocation when a community has a pushLeaseInstallationId but no matching grant, is null-safe: grant! only runs when exactly one grant matched. P3: records with a null expiresAt retry forever against a dead relay and keep the nsec in secure storage, so a max age would bound that.

This branch has not been deployed

No deployments
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.

2 participants