Skip to content

Commit

Permalink
Merge pull request #1599 from GovReady/fisma_sensitivity
Browse files Browse the repository at this point in the history
Fisma sensitivity
  • Loading branch information
davidpofo committed Jul 2, 2021
2 parents a03ec87 + aa354be commit 48b17dd
Show file tree
Hide file tree
Showing 18 changed files with 341 additions and 201 deletions.
8 changes: 6 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ GovReady-Q Release Notes

v0.9.6-dev (June XX, 2021)

--------------------------

**UI changes**

* Display legacy control implementation statements within system's statements.
Expand All @@ -21,6 +19,9 @@ v0.9.6-dev (June XX, 2021)

* Set all `StatementTypeEnum.<LABEL>.value` to `StatementTypeEnum.<LABEL>.name` in order for relevant label/term to show up in Django database admin interface.

* Fisma impact level is now represented as Security Sensitivity level following OSCAL's schema.


v0.9.5 (June 23, 2021)
----------------------

Expand All @@ -45,9 +46,11 @@ v0.9.4 (June 13, 2021)
* Created a modal to allow an admin user to add security objectives confidentiality, integrity, and availability.
* Add field to identify user's default portfolio.


**UI changes**

* Can now edit a system componet's state and type in the detail page for a selected component.
* Can now create a component with a state and type with the `ElementForm`
* Improve project pages appearance: decrease action button width and left align text; widen from 9 to 10 columns main content.
* Remove "Refresh Documents" button on task finished page because caches are now automatically cleared and document content refreshed.
* Display system component component_state and component_type when component is listed for a system.
Expand Down Expand Up @@ -81,6 +84,7 @@ v0.9.4 (June 13, 2021)
* File upload validator now accepts files with capitalized extensions, e.g. ".JPG".
* File upload validator now recognizes ".jpeg" in addition to ".jpg" extension on JPEG files.


v0.9.3.5.3 (May 16, 2021)
-------------------------

Expand Down
2 changes: 1 addition & 1 deletion controls/enums/statements.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ class StatementTypeEnum(BaseEnum):
CONTROL_IMPLEMENTATION_PROTOTYPE = "control_implementation_prototype"
ASSESSMENT_RESULT = "assessment_result"
POAM = "POAM"
FISMA_IMPACT_LEVEL = "fisma_impact_level"
SECURITY_SENSITIVITY_LEVEL = "security_sensitivity_level"
SECURITY_IMPACT_LEVEL = "security_impact_level"
23 changes: 23 additions & 0 deletions controls/migrations/0052_auto_20210521_1422.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Generated by Django 3.2 on 2021-05-21 14:22

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('controls', '0051_auto_20210520_1213'),
]

operations = [
migrations.AlterField(
model_name='historicalstatement',
name='statement_type',
field=models.CharField(blank=True, choices=[('CONTROL_IMPLEMENTATION', 'control_implementation'), ('CONTROL_IMPLEMENTATION_PROTOTYPE', 'control_implementation_prototype'), ('ASSESSMENT_RESULT', 'assessment_result'), ('POAM', 'POAM'), ('SECURITY_SENSITIVITY_LEVEL', 'security_sensitivity_level'), ('SECURITY_IMPACT_LEVEL', 'security_impact_level')], help_text='Statement type.', max_length=150, null=True),
),
migrations.AlterField(
model_name='statement',
name='statement_type',
field=models.CharField(blank=True, choices=[('CONTROL_IMPLEMENTATION', 'control_implementation'), ('CONTROL_IMPLEMENTATION_PROTOTYPE', 'control_implementation_prototype'), ('ASSESSMENT_RESULT', 'assessment_result'), ('POAM', 'POAM'), ('SECURITY_SENSITIVITY_LEVEL', 'security_sensitivity_level'), ('SECURITY_IMPACT_LEVEL', 'security_impact_level')], help_text='Statement type.', max_length=150, null=True),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Generated by Django 3.2.3 on 2021-07-02 17:26

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('controls', '0052_auto_20210521_1422'),
('controls', '0053_auto_20210701_1133'),
]

operations = [
]
29 changes: 14 additions & 15 deletions controls/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -541,26 +541,24 @@ def remove_control(self, control_id):
return control

@transaction.atomic
def set_fisma_impact_level(self, fisma_impact_level):
"""Assign FISMA impact level to system"""
# TODO: Fisma impact level is actually the security-sensitivity-level as defined in oscal ssp schema.

# Get or create the fisma_impact_level smt for system's root_element; should only have 1 statement
smt = Statement.objects.create(statement_type=StatementTypeEnum.FISMA_IMPACT_LEVEL.name, producer_element=self.root_element,consumer_element=self.root_element, body=fisma_impact_level)
return fisma_impact_level, smt
def set_security_sensitivity_level(self, security_sensitivity_level):
"""Assign Security Sensitivty level to system"""
# Get or create the security_sensitivity_level smt for system's root_element; should only have 1 statement
smt = Statement.objects.create(statement_type=StatementTypeEnum.SECURITY_SENSITIVITY_LEVEL.name, producer_element=self.root_element, consumer_element=self.root_element, body=security_sensitivity_level)
return security_sensitivity_level, smt

@property
def get_fisma_impact_level(self):
"""Assign FISMA impact level to system"""
def get_security_sensitivity_level(self):
"""Assign Security Sensitivty level to system"""

# Get or create the fisma_impact_level smt for system's root_element; should only have 1 statement
smt, created = Statement.objects.get_or_create(statement_type=StatementTypeEnum.FISMA_IMPACT_LEVEL.name, producer_element=self.root_element,consumer_element=self.root_element)
fisma_impact_level = smt.body
return fisma_impact_level
# Get or create the security_sensitivity_level smt for system's root_element; should only have 1 statement
smt, created = Statement.objects.get_or_create(statement_type=StatementTypeEnum.SECURITY_SENSITIVITY_LEVEL.name, producer_element=self.root_element, consumer_element=self.root_element)
security_sensitivity_level = smt.body
return security_sensitivity_level

@transaction.atomic
def set_security_impact_level(self, security_impact_level):
"""Assign Security impact levels to system"""
"""Assign one or more of the System Security impact levels (e.g. confidentiality, integrity, availability)"""

security_objective_smt = self.root_element.statements_consumed.filter(statement_type=StatementTypeEnum.SECURITY_IMPACT_LEVEL.name)
if security_objective_smt.exists():
Expand All @@ -572,7 +570,7 @@ def set_security_impact_level(self, security_impact_level):

@property
def get_security_impact_level(self):
"""Assign Security impact levels to system"""
"""Get one or more of the System Security impact levels (e.g. confidentiality, integrity, availability)"""

# Get the security_impact_level smt for element; should only have 1 statement
try:
Expand All @@ -582,6 +580,7 @@ def get_security_impact_level(self):
except Statement.DoesNotExist:
return {}


@property
def smts_common_controls_as_dict(self):
common_controls = self.root_element.common_controls.all()
Expand Down
24 changes: 14 additions & 10 deletions controls/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -432,18 +432,21 @@ def compare_components(request):
"""
Compare submitted components
"""
# TODO: need to figure out how to accumulate all checked boxes not one in pageobj
compare_list = request.POST.getlist('componentcomparecheckbox')
if compare_list:
element_list = list(Element.objects.filter(pk__in=compare_list).exclude(element_type='system').distinct())
compare_prime, element_list = element_list[0], element_list[1:]# The first component selected will be compared against the rest
compare_prime_smts = compare_prime.statements(StatementTypeEnum.CONTROL_IMPLEMENTATION_PROTOTYPE.name)
elif len(compare_list) <= 1:

checks = json.loads(request.POST.get('hiddenChecks'))
compare_list = list(checks.values())
if len(compare_list) <= 1:
# add messages
messages.add_message(request, messages.WARNING, f"Not enough components were selected to compare!")
return HttpResponseRedirect("/controls/components")
else:
ele_q = Element.objects.filter(pk__in=compare_list).exclude(element_type='system').distinct()
# Maintain sort order of compare_list otherwise Django will order ascending
element_list = sorted(ele_q, key=lambda x: compare_list.index(str(x.id)))
compare_prime, element_list = element_list[0], element_list[
1:] # The first component selected will be compared against the rest
compare_prime_smts = compare_prime.statements(StatementTypeEnum.CONTROL_IMPLEMENTATION_PROTOTYPE.name)
difference_tuples = []
differences = []
for component in element_list:
differences = []
# compare each component's statements to prime
Expand All @@ -458,14 +461,15 @@ def compare_components(request):
else:
diff = f"<span><ins style='background:#e6ffe6;'>{smt.body}</ins><span>"
differences.append(diff)
difference_tuples.extend(zip([component.name] * len(cmt_smts), cmt_smts, differences))
difference_tuples.extend(zip([component.id] * len(cmt_smts),[component.name] * len(cmt_smts), cmt_smts, differences))
if request.method == 'POST':
context = {
"element_list": element_list,
"compare_prime": compare_prime,
"prime_smts": compare_prime_smts,
"secondary_smts": cmt_smts,
"differences": difference_tuples
"differences": difference_tuples,
"compare_list": compare_list
}
return render(request, "components/compare_components.html", context)

Expand Down
12 changes: 6 additions & 6 deletions guidedmodules/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -494,15 +494,15 @@ def redirect_to():
object={"object": "system", "id": system.id, "name": system.root_element.name},
user={"id": request.user.id, "username": request.user.username}
)
# Set fisma_impact_level statement
# Set security_sensitivity_level statement
if baseline.lower() in ["low", "moderate", "high"]:
fisma_impact_level, smt = system.set_fisma_impact_level(baseline)
if fisma_impact_level == baseline.lower():
security_sensitivity_level, smt = system.set_security_sensitivity_level(baseline)
if security_sensitivity_level == baseline.lower():
messages.add_message(request, messages.INFO,
f'I\'ve set the system FISMA impact level to "{fisma_impact_level}.')
# Log setting fisma_impact_level
f'I\'ve set the system FISMA impact level to "{security_sensitivity_level}.')
# Log setting security_sensitivity_level
logger.info(
event=f"system assign_fisma_impact_level {fisma_impact_level}",
event=f"system assign_security_sensitivity_level {security_sensitivity_level}",
object={"object": "system", "id": system.id, "name": system.root_element.name, "statementid": smt.id},
user={"id": request.user.id, "username": request.user.username}
)
Expand Down
2 changes: 1 addition & 1 deletion requirements.in
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jsonschema # MIT License
filetype # MIT License
# Common Django Packages
# Django==2.2.12 # BSD License
Django==3.2.4 # BSD License
Django==3.2.5 # BSD License
django-debug-toolbar # BSD License
django-allauth # MIT License
django-bootstrap3 # BSD 3-Clause License
Expand Down
Loading

0 comments on commit 48b17dd

Please sign in to comment.