An approval was corrected to Declined: how to test permission revocation
Your fixture session received Approved and granted a local permission. A later event says Declined. You need to decide whether that event revokes access, and how to tell a real correction from a replayed or stale callback. This article tests that decision in the synthetic fixture and separates what the fixture does from what your application must design. The problem: an approval that no longer…
When a seller's verification status changes, it can affect whether a local permission remains granted or needs to be revoked. This article explores how to test permission revocation using a synthetic fixture setup.
In this setup, a fixture session initially receives an "Approved" status and grants a local permission. Later, a "Declined" event arrives for the same session. The key question is whether this correction should revoke access or not. If the code treats all terminal status changes as final, it may ignore the correction and keep access open. However, if it treats every incoming event as fresh, a replayed callback could cause the state to flip back and forth unpredictably.
The goal is to ensure that a new "Declined" correction after an "Approved" status sets the permission_granted flag from true to false, while keeping the grant_count at 1. Duplicate or stale events should not affect the outcome. The behavior of real providers depends on their specific contract, but the fixture allows you to practice the necessary logic.
The fixture implementation uses SQLite to store sessions and processed event IDs. It accepts events with specific modes and source types, and only processes event IDs starting with "fixture-". It first checks tenant and subject binding, then deduplicates based on the session and event ID pair. If the stored status is "approved" and the incoming status is "Declined", the fixture records the event, updates the status to "declined", and leaves the grant count unchanged.
Any other event against an approved, declined, or expired session returns the current state unchanged.
The correction check runs before the deadline check, so a "Declined" correction after "Approved" is applied even if it arrives late. However, the fixture does not handle actual permission revocation in production systems. It simply tests the logic for determining if a correction should revoke access.
The example demonstrates the expected outputs for different scenarios. Sending an event with "fixture-approved" status and policy set to true results in a permission_granted flag set to true and a grant_count of 1. Replaying the same event ID leaves both fields unchanged. Sending a new event with "fixture-correction" status "Declined" sets the status to "declined", permission_granted to false, and grant_count remains at 1.
The fixture also defines behavior for other cases. Duplicate or stale events do not change the state. Late approvals after a correction are ignored, preventing permission from being restored. A second "Declined" correction does not affect the state further. The fixture returns the current state without recording any stale pending events.
To implement real revocation, a caller-owned revocation receipt could be used. This receipt would record the session, correcting event ID, previous and new status, grant count at revocation, and a timestamp. Downstream actions would be requested and confirmed in the same transaction as clearing the permission. The receipt should be written in an idempotent manner to handle partial failures gracefully.
Before trusting a correction, the downstream system should fetch the authoritative decision through an authorized provider route.
Several failure scenarios need to be handled appropriately. If a correction fails the binding check, it raises a BINDING_MISMATCH alert instead of revoking access. Non-synthetic sources raise a PRODUCTION_SIGNATURE_VERIFIER_NOT_IMPLEMENTED error. Events without the "fixture-" prefix raise a SYNTHETIC_EVENT_REQUIRED error. Unknown sessions raise a SESSION_NOT_FOUND error.
The recover method only expires pending, review, or unknown sessions locally and does not poll providers or reverse approvals. It should not be relied upon to catch missed corrections. If downstream revocation partially fails, the permission should remain cleared, and the receipt should be marked incomplete for review. Access should not be restored in such cases.
To confirm the correctness of the correction semantics against the real provider contract, the synthetic example provided in the fixture should be run. This allows for testing the behavior in a controlled environment before deploying any changes to live systems.
Written by urgent.news from Dev.to's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.