Skip to content
This repository has been archived by the owner on Nov 30, 2022. It is now read-only.

Backend: Updating or Deleting Access Webhooks [#1388][#1389] #1394

Merged
merged 5 commits into from
Sep 28, 2022

Conversation

pattisdr
Copy link
Contributor

@pattisdr pattisdr commented Sep 27, 2022

Purpose

Address some edge cases that surfaced in testing #1377

  1. Deleting or disabling a webhook can leave Privacy Requests stuck in a requires_input state with no way to move them forward
  2. If data has already been saved for a webhook, but then the webhook definition itself changes, we can run into issues trying to retrieve the data for the webhook because of the mismatch. The user needs to be alerted that data needs to be resubmitted for the altered webhook. We currently throw a 429 if the webhook definition had a field removed, but we should also handle if the webhook definition had a field added. Both should require a re-review.

Changes

  • If a manual webhook is deleted or disabled, check if there are any remaining active manual webhooks configured. If not, meaning we just disabled/deleted the last one, queue any Privacy Requests stuck in "requires_input" for processing.
  • In the view_uploaded_manual_webhook_data endpoint, load cached webhook data for a privacy request in strict mode. If it fails (no data saved, extra field saved, field missing), return checked=False, so the user knows they need to re-upload data for this webhook before it can be submitted.
    • Previously, we would return a 429 if there were extra fields saved for the webhook. Now we return a 200 but surface that the data needs to be re-uploaded.
    • Return the data in non-strict mode, so we just show the overlap between the data saved and the fields defined.
    • Any webhooks that have checked=True will prevent the privacy request from being submitted

Checklist

  • Update CHANGELOG.md file
    • Merge in main so the most recent CHANGELOG.md file is being appended to
    • Add description within the Unreleased section in an appropriate category. Add a new category from the list at the top of the file if the needed one isn't already there.
    • Add a link to this PR at the end of the description with the PR number as the text. example: #1
  • Applicable documentation updated (guides, quickstart, postman collections, tutorial, fidesdemo, database diagram.
  • If docs updated (select one):
    • documentation complete, or draft/outline provided (tag docs-team to complete/review on this branch)
    • documentation issue created (tag docs-team to complete issue separately)
  • Good unit test/integration test coverage
  • This PR contains a DB migration. If checked, the reviewer should confirm with the author that the down_revision correctly references the previous migration before merging
  • The Run Unsafe PR Checks label has been applied, and checks have passed, if this PR touches any external services

Ticket

Fixes #1388
Fixes #1389

…maining active manual webhooks configured. If not, queue any Privacy Requests stuck in "requires_input" for processing.
…for a privacy request in strict mode. If it fails (no data saved, extra field saved, field missing), return checked=True, so the user knows they need to reupload data for this webhook before it can be submitted.

Return the data in non-strict mode, so we just show the overlap between the data saved and the fields defined.
…this is the only module it's being called - both where you update and delete a connection config.
@pattisdr pattisdr marked this pull request as ready for review September 27, 2022 18:46
@seanpreston seanpreston self-assigned this Sep 27, 2022
)
checked = False
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Previously, "checked=False" was only returned if there was no data in the cache, so Chris's UI would show that that webhook still needed to be reviewed and the submit DSR button would be grayed out.

In addition to this use case, we now show checked=False if the webhook definition has changed, which prompts the user to have to re-review.

The variable name checked might need to be updated in the future, but I left it like this for now, because it's the field Chris is using in the FE.

Comment on lines +1397 to +1398
data = privacy_request.get_manual_webhook_input_non_strict(
manual_webhook=access_manual_webhook
Copy link
Contributor Author

@pattisdr pattisdr Sep 27, 2022

Choose a reason for hiding this comment

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

This is the endpoint that returns data that was already uploaded for a webhook if applicable.

I load the webhook data in non-strict mode here if there's an issue, which really just returns the overlap between the saved fields and the new webhook field definitions.

Note that I don't update the data that is actually cached, I just return this "safe mode version". This keeps this endpoint idempotent in case it is hit multiple times or by different people. Regardless, until the webhook fields are updated by a user to match the latest webhook definition, the privacy request itself will not be able to be submitted, because it will also try to access the webhook data in "strict mode" and fail.

@@ -505,27 +506,50 @@ def cache_manual_webhook_input(
parsed_data.dict(),
)

def get_manual_webhook_input(
def get_manual_webhook_input_strict(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated this existing method to "strict mode" which used to just look for extra fields and/or no data cached, but now it also looks for missing fields.

raise NoCachedManualWebhookEntry(
f"No data cached for privacy_request_id '{self.id}' for connection config '{manual_webhook.connection_config.key}'"
)

def get_manual_webhook_input_non_strict(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added a "non strict" mode to load webhook data where we really just preserve the overlap.

# Access Manual Webhooks are cascade deleted if their ConnectionConfig is deleted,
# so we queue any privacy requests that are no longer blocked by webhooks
if connection_type == ConnectionType.manual_webhook:
requeue_requires_input_requests(db)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

As a first step, I am just re-queuing applicable privacy requests if a connection is disabled or deleted. I omitted adding a recurring task to also check if any of these fell through the cracks in the interest of time. I think this kind of thing could be added as a piece of a broader work where we look for privacy requests of multiple statuses that are stuck.

@@ -859,6 +913,17 @@ def test_delete_manual_webhook_connection_config(
.first()
is None
)
assert (
mock_queue.called
), "Deleting this last webhook caused 'requires_input' privacy requests to be queued"
Copy link
Contributor

Choose a reason for hiding this comment

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

Just to confirm this is deleting the last webhook, so Fidesops is sure there's no more input required from the user before dispatch?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, the last webhook is deleted, so the privacy request just needs to be re-queued. Data is no longer required for the webhook. If any data was previously uploaded, it would be ignored.

assert response.json() == {
"checked": False,
"fields": {
"id_number": None,
Copy link
Contributor

Choose a reason for hiding this comment

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

Using the user preferred naming for this field in the response is a nice touch

def requeue_requires_input_requests(db: Session) -> None:
"""
Queue privacy requests with request status "requires_input" if they are no longer blocked by
access manual webhooks.
Copy link
Contributor

Choose a reason for hiding this comment

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

It'd be better to say explicitly this is if all access manual webhooks are disabled or deleted.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks Sean, I've tried to improve this docstring

@seanpreston seanpreston merged commit 592e1f0 into main Sep 28, 2022
@seanpreston seanpreston deleted the fidesops_1388_1389_webhooks_updated_or_deleted branch September 28, 2022 19:22
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Backend: Indicate Webhook Fields have Changed Backend: Manual Webhooks Re-Queue Requires Input
2 participants