From 4246e6bec1163f5ba1cfe156cc45af486a437714 Mon Sep 17 00:00:00 2001 From: msj Date: Thu, 8 Jun 2023 12:34:17 -0400 Subject: [PATCH 1/2] Add clean cli failsafe --- pupa/cli/commands/clean.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/pupa/cli/commands/clean.py b/pupa/cli/commands/clean.py index 6a4cb1c..bc4dd83 100644 --- a/pupa/cli/commands/clean.py +++ b/pupa/cli/commands/clean.py @@ -88,11 +88,21 @@ def handle(self, args, other): ) self.report_stale_objects() else: - if not args.noinput: + num_stale_objects = len(list(self.get_stale_objects(args.window))) + + if args.noinput: + # Fail-safe to avoid deleting a large amount of objects + # without explicit confimation + if num_stale_objects > 10: + print( + "This command would delete more than 10 objects." + "If you're sure, re-run without --noinput to provide confirmation." + ) + sys.exit(1) + else: print( f"This will permanently delete" - f" {len(list(self.get_stale_objects(args.window)))}" - " objects from your database" + f" {num_stale_objects} objects from your database" f" that have not been scraped within the last {args.window}" " days. Are you sure? (Y/N)" ) From 1b9a31308bfe7cfb8533ca91ffc2da6107f8c47c Mon Sep 17 00:00:00 2001 From: msj Date: Thu, 8 Jun 2023 12:56:15 -0400 Subject: [PATCH 2/2] Add failsafe test --- pupa/tests/clean/test_clean.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/pupa/tests/clean/test_clean.py b/pupa/tests/clean/test_clean.py index c845cb2..d4494fc 100644 --- a/pupa/tests/clean/test_clean.py +++ b/pupa/tests/clean/test_clean.py @@ -97,3 +97,25 @@ def test_clean_command(subparsers): for obj in expected_not_stale_objects: was_not_deleted = type(obj).objects.filter(id=obj.id).exists() assert was_not_deleted + + +@pytest.mark.django_db +def test_clean_command_failsafe(subparsers): + _ = create_jurisdiction() + o = Organization.objects.create(name="WWE", jurisdiction_id="jid") + + stale_people = [ + Person.objects.create(name="George Washington", family_name="Washington") + for i in range(20) + ] + stale_memberships = [ # noqa + p.memberships.create(organization=o) for p in stale_people + ] + + a_week_from_now = datetime.now(tz=timezone.utc) + timedelta(days=7) + with freeze_time(a_week_from_now): + with pytest.raises(SystemExit): + # Should trigger failsafe exist when deleting more than 10 objects + Command(subparsers).handle( + argparse.Namespace(noinput=True, report=False, window=7), [] + )