hyperledger-identus / hyperledger-identus/cloud-agent

In-flight deactivation guard not enforced: duplicate deactivate submissions during confirmation window

Open
#1,885 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Scala
Stars
95
Forks
34
Avg merge
1d 5h
Merged PRs (30d)
14

Description

Found while analyzing #1883 / #1884.

## Description

The endpoint description of `POST /did-registrar/dids/{didRef}/deactivations` states:

> The deactivation operation is an asynchronous operation and the agent will reject a new deactivate request if the previous operation is not yet confirmed.

This rejection is not implemented for deactivations. A second deactivation submitted while the first is still unconfirmed is accepted (202) and a duplicate signed operation is submitted to the VDR.

## Root cause

`ManagedDIDServiceImpl.deactivateManagedDID` guards with `getUnconfirmedUpdateOperationByDid(...).filterOrFail(_.isEmpty)(MultipleInflightUpdateNotAllowed)` (L236-237), but that store is only populated by `updateManagedDID`, which persists the materialized operation before submission (L201). The deactivation path (`doDeactivate`, L210-215) only signs and submits, persisting nothing, so the guard never sees an in-flight deactivation and is vacuous.

There is a TODO on the method acknowledging this: `// TODO: refactor this method to use the same handler as updateManagedDID`.

Consequence: during the confirmation window the resolved DID is not yet deactivated, all checks pass, and a second `PrismDIDOperation.Deactivate` referencing the same `previousOperationHash` is signed and submitted. One operation confirms and the other is rejected by the VDR as stale. Also note the interlock with #1884: during the window you get a duplicate submission (this issue); after the window you get the 500 instead of 409 (#1884).

## Fix direction

Persist the deactivation operation the same way updates do (share the handler per the TODO), so the in-flight guard sees it. The `MultipleInflightUpdateNotAllowed` 409 it would then raise also needs the endpoint fix tracked in #1884.

## Reproduce

1. Create and publish a DID.
2. `POST .../deactivations`, then immediately `POST .../deactivations` again before the first operation confirms.
3. Observe: second request returns 202 (accepted) instead of the documented rejection.

Contributor guide

Open the contributing guide

Research direction

Start in ManagedDIDServiceImpl.deactivateManagedDID and trace doDeactivate alongside updateManagedDID, especially the store persistence and the TODO about sharing the handler. Reproduce the two immediate POST /did-registrar/dids/{didRef}/deactivations requests, then verify the first deactivation is persisted before submission so the in-flight guard rejects the second request.

Written by the indexing model from the issue text.

Assessment

Tech stack
scala
Domain
api, backend
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
72/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.