Skip to content

Commit

Permalink
Enforce Expiration Date for UEI Validation Waivers (#4106)
Browse files Browse the repository at this point in the history
* Enforce expiration date for UEI validation waivers

* Include `justification` in UEI validation admin

* Add a test to ensure expired waivers don't work

* Whoops, opposite assetion.
  • Loading branch information
jperson1 committed Jul 25, 2024
1 parent 97a2af9 commit 03b0fb3
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 16 deletions.
21 changes: 21 additions & 0 deletions backend/api/test_serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
from unittest import TestCase

from unittest.mock import patch
from django.utils import timezone as django_timezone
from datetime import timedelta
from django.test import SimpleTestCase
from model_bakery import baker

Expand Down Expand Up @@ -110,6 +112,25 @@ def test_waived_uei_payload(self):
mock_get.return_value.json.return_value = json.loads(missing_uei_results)
self.assertTrue(UEISerializer(data=valid).is_valid())

def test_expired_waived_uei_payload(self):
"""
A UEI with an expired validation waiver should not pass.
"""
yesterday = django_timezone.now() - timedelta(days=1)
expired = {"auditee_uei": "SUPERC00LUE1", "expiration": yesterday}

baker.make(
UeiValidationWaiver,
uei=expired["auditee_uei"],
expiration=expired["expiration"],
)

# Invalid due to the waiver being expired. Mock the SAM call as though the entity doesnt exist.
with patch("api.uei.SESSION.get") as mock_get:
mock_get.return_value.status_code = 200
mock_get.return_value.json.return_value = json.loads(missing_uei_results)
self.assertFalse(UEISerializer(data=expired).is_valid())

def test_quirky_uei_payload(self):
"""
It turns out that some entries can be missing fields that we thought would
Expand Down
10 changes: 4 additions & 6 deletions backend/api/uei.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from django.utils import timezone as django_timezone
import logging
import requests
import ssl
Expand Down Expand Up @@ -161,13 +162,10 @@ def get_uei_info_from_sam_gov(uei: str) -> dict:
if results["valid"] and (not results.get("errors")):
return results

# To honor expiration dates:
# from datetime import date
# today = date.today()
# waiver = UeiValidationWaiver.objects.filter(uei=uei, expiration__gte=today).first()

# 3. Check for a waiver.
waiver = UeiValidationWaiver.objects.filter(uei=uei).first()
waiver = UeiValidationWaiver.objects.filter(
uei=uei, expiration__gte=django_timezone.now()
).first()
if not waiver:
return {"valid": False, "errors": ["UEI was not found in SAM.gov"]}

Expand Down
2 changes: 2 additions & 0 deletions backend/audit/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,8 +228,10 @@ class UeiValidationWaiverAdmin(admin.ModelAdmin):
"id",
"uei",
"timestamp",
"expiration",
"approver_email",
"requester_email",
"justification",
)
search_fields = (
"id",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Generated by Django 5.0.4 on 2024-07-23 15:54

import audit.models.models
import django.utils.timezone
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("audit", "0010_alter_ueivalidationwaiver_uei"),
]

operations = [
migrations.AddField(
model_name="ueivalidationwaiver",
name="expiration",
field=models.DateTimeField(
default=audit.models.models.one_month_from_today,
verbose_name="When the waiver will expire",
),
),
migrations.AddField(
model_name="ueivalidationwaiver",
name="timestamp",
field=models.DateTimeField(
default=django.utils.timezone.now,
verbose_name="When the waiver was created",
),
),
]
21 changes: 11 additions & 10 deletions backend/audit/models/models.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from datetime import datetime, timezone
from datetime import datetime, timezone, timedelta
from itertools import chain
import json
import logging
Expand Down Expand Up @@ -71,6 +71,10 @@ def generate_sac_report_id(end_date=None, source="GSAFAC", count=None):
return report_id


def one_month_from_today():
return django_timezone.now() + timedelta(days=30)


class SingleAuditChecklistManager(models.Manager):
"""Manager for SAC"""

Expand Down Expand Up @@ -704,16 +708,13 @@ def __str__(self):

# Not unique, in the case that one UEI needs to be waived several times with different expiration dates.
uei = models.TextField("UEI")
timestamp = (
models.DateTimeField(
"When the waiver was created",
default=django_timezone.now,
),
timestamp = models.DateTimeField(
"When the waiver was created",
default=django_timezone.now,
)
expiration = (
models.DateTimeField(
"When the waiver expires",
),
expiration = models.DateTimeField(
"When the waiver will expire",
default=one_month_from_today,
)
approver_email = models.TextField(
"Email address of FAC staff member approving the waiver",
Expand Down

0 comments on commit 03b0fb3

Please sign in to comment.