Merge pull request #2305 from cisagov/rh/2273-ds-record-change

ISSUE #2273: Add logging for DS data changes
This commit is contained in:
Rebecca H 2024-06-17 08:14:28 -07:00 committed by GitHub
commit 7c74eca92f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 80 additions and 16 deletions

View file

@ -0,0 +1,18 @@
# Generated by Django 4.2.10 on 2024-06-14 19:26
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("registrar", "0101_domaininformation_cisa_representative_first_name_and_more"),
]
operations = [
migrations.AddField(
model_name="domain",
name="dsdata_last_change",
field=models.TextField(blank=True, help_text="Record of the last change event for ds data", null=True),
),
]

View file

@ -40,6 +40,8 @@ from .utility.time_stamped_model import TimeStampedModel
from .public_contact import PublicContact
from .user_domain_role import UserDomainRole
logger = logging.getLogger(__name__)
@ -672,11 +674,29 @@ class Domain(TimeStampedModel, DomainHelper):
remRequest = commands.UpdateDomain(name=self.name)
remExtension = commands.UpdateDomainDNSSECExtension(**remParams)
remRequest.add_extension(remExtension)
dsdata_change_log = ""
# Get the user's email
user_domain_role = UserDomainRole.objects.filter(domain=self).first()
user_email = user_domain_role.user.email if user_domain_role else "unknown user"
try:
if "dsData" in _addDnssecdata and _addDnssecdata["dsData"] is not None:
added_record = "dsData" in _addDnssecdata and _addDnssecdata["dsData"] is not None
deleted_record = "dsData" in _remDnssecdata and _remDnssecdata["dsData"] is not None
if added_record:
registry.send(addRequest, cleaned=True)
if "dsData" in _remDnssecdata and _remDnssecdata["dsData"] is not None:
dsdata_change_log = f"{user_email} added a DS data record"
if deleted_record:
registry.send(remRequest, cleaned=True)
if dsdata_change_log != "": # if they add and remove a record at same time
dsdata_change_log = f"{user_email} added and deleted a DS data record"
else:
dsdata_change_log = f"{user_email} deleted a DS data record"
if dsdata_change_log != "":
self.dsdata_last_change = dsdata_change_log
self.save() # audit log will now record this as a change
except RegistryError as e:
logger.error("Error updating DNSSEC, code was %s error was %s" % (e.code, e))
raise e
@ -1057,6 +1077,12 @@ class Domain(TimeStampedModel, DomainHelper):
verbose_name="first ready on",
)
dsdata_last_change = TextField(
null=True,
blank=True,
help_text="Record of the last change event for ds data",
)
def isActive(self):
return self.state == Domain.State.CREATED

View file

@ -1901,12 +1901,8 @@ class TestRegistrantDNSSEC(MockEppLib):
3 - setter adds the UpdateDNSSECExtension extension to the command
4 - setter causes the getter to call info domain on next get from cache
5 - getter properly parses dnssecdata from InfoDomain response and sets to cache
"""
# need to use a separate patcher and side_effect for this test, as
# response from InfoDomain must be different for different iterations
# of the same command
def side_effect(_request, cleaned):
if isinstance(_request, commands.InfoDomain):
if mocked_send.call_count == 1:
@ -1924,17 +1920,30 @@ class TestRegistrantDNSSEC(MockEppLib):
mocked_send = patcher.start()
mocked_send.side_effect = side_effect
domain, _ = Domain.objects.get_or_create(name="dnssec-dsdata.gov")
# Check initial dsdata_last_change value (should be None)
initial_change = domain.dsdata_last_change
# Adding dnssec data
domain.dnssecdata = self.dnssecExtensionWithDsData
# get the DNS SEC extension added to the UpdateDomain command and
# Check dsdata_last_change is updated after adding data
domain = Domain.objects.get(name="dnssec-dsdata.gov")
self.assertIsNotNone(domain.dsdata_last_change)
self.assertNotEqual(domain.dsdata_last_change, initial_change)
# Get the DNS SEC extension added to the UpdateDomain command and
# verify that it is properly sent
# args[0] is the _request sent to registry
args, _ = mocked_send.call_args
# assert that the extension on the update matches
# Assert that the extension on the update matches
self.assertEquals(
args[0].extensions[0],
self.createUpdateExtension(self.dnssecExtensionWithDsData),
)
# test that the dnssecdata getter is functioning properly
# Test that the dnssecdata getter is functioning properly
dnssecdata_get = domain.dnssecdata
mocked_send.assert_has_calls(
[
@ -2129,13 +2138,9 @@ class TestRegistrantDNSSEC(MockEppLib):
2 - first setter calls UpdateDomain command
3 - second setter calls InfoDomain command again
3 - setter then calls UpdateDomain command
4 - setter adds the UpdateDNSSECExtension extension to the command with rem
4 - setter adds the UpdateDNSSExtension extension to the command with rem
"""
# need to use a separate patcher and side_effect for this test, as
# response from InfoDomain must be different for different iterations
# of the same command
def side_effect(_request, cleaned):
if isinstance(_request, commands.InfoDomain):
if mocked_send.call_count == 1:
@ -2153,10 +2158,25 @@ class TestRegistrantDNSSEC(MockEppLib):
mocked_send = patcher.start()
mocked_send.side_effect = side_effect
domain, _ = Domain.objects.get_or_create(name="dnssec-dsdata.gov")
# dnssecdata_get_initial = domain.dnssecdata # call to force initial mock
# domain._invalidate_cache()
# Initial setting of dnssec data
domain.dnssecdata = self.dnssecExtensionWithDsData
# Check dsdata_last_change is updated
domain = Domain.objects.get(name="dnssec-dsdata.gov")
self.assertIsNotNone(domain.dsdata_last_change)
initial_change = domain.dsdata_last_change
# Remove dnssec data
domain.dnssecdata = self.dnssecExtensionRemovingDsData
# Check that dsdata_last_change is updated again
domain = Domain.objects.get(name="dnssec-dsdata.gov")
self.assertIsNotNone(domain.dsdata_last_change)
self.assertNotEqual(domain.dsdata_last_change, initial_change)
# get the DNS SEC extension added to the UpdateDomain command and
# verify that it is properly sent
# args[0] is the _request sent to registry