Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fisma sensitivity #1599

Merged
merged 36 commits into from
Jul 2, 2021
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
640e144
changelog
davidpofo May 21, 2021
6fb52e8
FISMA IMPACT LEVEL is now SECURITY SENSITIVITY LEVEL
davidpofo May 21, 2021
a80b555
Merge branch 'develop' into fisma_sensitivity
davidpofo May 21, 2021
e7e8b9c
td not th
davidpofo Jun 19, 2021
4fe11c0
td not th
davidpofo Jun 19, 2021
5a9f3b9
Revert "td not th"
davidpofo Jun 28, 2021
09ab1c9
Merge branch 'develop' into da/comp_comparison_v2
davidpofo Jun 28, 2021
360a035
these values are safe
davidpofo Jun 28, 2021
892f18b
removing extra differences obj.
davidpofo Jun 28, 2021
e4e38a1
safe and efficiency
davidpofo Jun 29, 2021
f3849f3
adding select/deselect all. checkbox container wrap.
davidpofo Jun 29, 2021
538a5de
control structure for compare button toggle
davidpofo Jun 29, 2021
c839077
Maintain sort order of compare_list otherwise Django will order ascen…
davidpofo Jun 29, 2021
0438239
adding change component button to change what the prime component of …
davidpofo Jun 29, 2021
cbfbac8
remove commented out code from template
davidpofo Jun 30, 2021
db86b7c
fixing styling of portfolio table
davidpofo Jun 30, 2021
ab6bb5e
using django guardian ObjectPermissionChecker to prefetch permissions…
davidpofo Jun 30, 2021
e1b6e19
hide_registration revert
davidpofo Jun 30, 2021
b4fbac2
removing change component comparison button for now.
davidpofo Jun 30, 2021
64855a9
implemented persistent storage of checks by changing value in hidden …
davidpofo Jun 30, 2021
e1091fa
test test_portfolio_projects
davidpofo Jul 1, 2021
781bf70
name not value for statement enums
davidpofo Jul 1, 2021
a05e13b
name not value for enums
davidpofo Jul 2, 2021
5de8edb
Merge branch 'develop' into fisma_sensitivity
davidpofo Jul 2, 2021
b7ae55f
missed one get
davidpofo Jul 2, 2021
d8ea20f
Merge branch 'develop' into da/comp_comparison_v2
davidpofo Jul 2, 2021
68a4885
need to force login as authenticated user and then reset login
davidpofo Jul 2, 2021
0783a29
url
davidpofo Jul 2, 2021
bfc196b
snyk update to avoid SQL injection vuln found in Django 3.2.4
davidpofo Jul 2, 2021
3b5dcff
check if previously checked and if so then don't hide compare button.
davidpofo Jul 2, 2021
88159fc
Merge branch 'develop' into fisma_sensitivity
davidpofo Jul 2, 2021
a0fe66d
Merge branch 'develop' of https://github.com/govready/govready-q into…
davidpofo Jul 2, 2021
c0dce9b
Merge branch 'develop' into fisma_sensitivity
davidpofo Jul 2, 2021
41550d2
fix conflicting migrations detected
davidpofo Jul 2, 2021
5d6d0b7
systems-security-sensitivity-level
davidpofo Jul 2, 2021
aa354be
Merge branch 'da/comp_comparison_v2' into fisma_sensitivity
davidpofo Jul 2, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ GovReady-Q Release Notes
v999 (June XX, 2021)
---------------------

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


v0.9.5 (June 23, 2021)
Expand All @@ -30,9 +31,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 @@ -66,6 +69,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 @@ -6,5 +6,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),
),
]
54 changes: 27 additions & 27 deletions controls/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ def create_prototype(self):
return self.prototype
# check if prototype content is the same, report error if not, or overwrite if permission approved
prototype = deepcopy(self)
prototype.statement_type=StatementTypeEnum.CONTROL_IMPLEMENTATION_PROTOTYPE.value
prototype.statement_type=StatementTypeEnum.CONTROL_IMPLEMENTATION_PROTOTYPE.name
prototype.consumer_element_id = None
prototype.id = None
prototype.save()
Expand All @@ -139,7 +139,7 @@ def create_system_control_smt_from_component_prototype_smt(self, consumer_elemen
return self.prototype

instance = deepcopy(self)
instance.statement_type=StatementTypeEnum.CONTROL_IMPLEMENTATION.value
instance.statement_type=StatementTypeEnum.CONTROL_IMPLEMENTATION.name
instance.consumer_element_id = consumer_element_id
instance.id = None
# Set prototype attribute to newly created instance
Expand Down Expand Up @@ -240,7 +240,7 @@ class Element(auto_prefetch.Model, TagModelMixin):
# e.statements_consumed.all()
#
# Retrieve statements that are control implementations
# e.statements_consumed.filter(statement_type=StatementTypeEnum.CONTROL_IMPLEMENTATION.value)
# e.statements_consumed.filter(statement_type=StatementTypeEnum.CONTROL_IMPLEMENTATION.name)

def __str__(self):
return "'%s id=%d'" % (self.name, self.id)
Expand Down Expand Up @@ -347,7 +347,7 @@ def consuming_systems(self):
def get_control_impl_smts_prototype_count(self):
"""Return count of statements with this element as producer_element"""

smt_count = Statement.objects.filter(producer_element=self, statement_type=StatementTypeEnum.CONTROL_IMPLEMENTATION_PROTOTYPE.value).count()
smt_count = Statement.objects.filter(producer_element=self, statement_type=StatementTypeEnum.CONTROL_IMPLEMENTATION_PROTOTYPE.name).count()

return smt_count

Expand Down Expand Up @@ -480,7 +480,7 @@ class System(auto_prefetch.Model):
# Notes
# Retrieve system implementation statements
# system = System.objects.get(pk=2)
# system.root_element.statements_consumed.filter(statement_type=StatementTypeEnum.CONTROL_IMPLEMENTATION.value)
# system.root_element.statements_consumed.filter(statement_type=StatementTypeEnum.CONTROL_IMPLEMENTATION.name)
#
# Retrieve system common controls statements
# system = System.objects.get(pk=2)
Expand Down Expand Up @@ -533,55 +533,55 @@ def remove_control(self, control_id):
control = ElementControl.objects.get(pk=control_id)

# Delete Control Statements
self.root_element.statements_consumed.filter(statement_type=StatementTypeEnum.CONTROL_IMPLEMENTATION.value,
self.root_element.statements_consumed.filter(statement_type=StatementTypeEnum.CONTROL_IMPLEMENTATION.name,
sid_class=control.oscal_catalog_key,
sid=control.oscal_ctl_id
).delete()
control.delete()
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.
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

# 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.value, producer_element=self.root_element,consumer_element=self.root_element, body=fisma_impact_level)
return fisma_impact_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.value, 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.value)
security_objective_smt = self.root_element.statements_consumed.filter(statement_type=StatementTypeEnum.SECURITY_IMPACT_LEVEL.name)
if security_objective_smt.exists():
security_objective_smt.update(body=security_impact_level)
else:
# Set the security_impact_level smt for element; should only have 1 statement
security_objective_smt, created = Statement.objects.get_or_create(statement_type=StatementTypeEnum.SECURITY_IMPACT_LEVEL.value, producer_element=self.root_element,consumer_element=self.root_element, body=security_impact_level)
security_objective_smt, created = Statement.objects.get_or_create(statement_type=StatementTypeEnum.SECURITY_IMPACT_LEVEL.name, producer_element=self.root_element,consumer_element=self.root_element, body=security_impact_level)
return security_impact_level, security_objective_smt

@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:
smt = Statement.objects.get(statement_type=StatementTypeEnum.SECURITY_IMPACT_LEVEL.value, producer_element=self.root_element, consumer_element=self.root_element)
smt = Statement.objects.get(statement_type=StatementTypeEnum.SECURITY_IMPACT_LEVEL.name, producer_element=self.root_element, consumer_element=self.root_element)
security_impact_level = eval(smt.body)# Evaluate string of dictionary
return security_impact_level
except Statement.DoesNotExist:
return {}


@property
def smts_common_controls_as_dict(self):
common_controls = self.root_element.common_controls.all()
Expand All @@ -595,7 +595,7 @@ def smts_common_controls_as_dict(self):

@property
def smts_control_implementation_as_dict(self):
smts = self.root_element.statements_consumed.filter(statement_type=StatementTypeEnum.CONTROL_IMPLEMENTATION.value).order_by('pid')
smts = self.root_element.statements_consumed.filter(statement_type=StatementTypeEnum.CONTROL_IMPLEMENTATION.name).order_by('pid')
smts_as_dict = {}
for smt in smts:
if smt.sid in smts_as_dict:
Expand All @@ -612,7 +612,7 @@ def control_implementation_as_dict(self):
elm = self.root_element
selected_controls = elm.controls.all().values("oscal_ctl_id", "uuid")
# Get the smts_control_implementations ordered by part, e.g. pid
smts = elm.statements_consumed.filter(statement_type=StatementTypeEnum.CONTROL_IMPLEMENTATION.value).order_by('pid')
smts = elm.statements_consumed.filter(statement_type=StatementTypeEnum.CONTROL_IMPLEMENTATION.name).order_by('pid')

smts_as_dict = {}

Expand Down Expand Up @@ -699,12 +699,12 @@ def controls_status_count(self):
# Fetch all selected controls
elm = self.root_element

counts = Statement.objects.filter(statement_type=StatementTypeEnum.CONTROL_IMPLEMENTATION.value, status__in=status_list).values('status').order_by('status').annotate(count=Count('status'))
counts = Statement.objects.filter(statement_type=StatementTypeEnum.CONTROL_IMPLEMENTATION.name, status__in=status_list).values('status').order_by('status').annotate(count=Count('status'))
status_stats.update({r['status']: r['count'] for r in counts})

# TODO add index on statement status
# Get overall controls addressed (e.g., covered)
status_stats['Addressed'] = elm.statements_consumed.filter(statement_type=StatementTypeEnum.CONTROL_IMPLEMENTATION.value).values('sid').distinct().count()
status_stats['Addressed'] = elm.statements_consumed.filter(statement_type=StatementTypeEnum.CONTROL_IMPLEMENTATION.name).values('sid').distinct().count()
return status_stats

@cached_property
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
12 changes: 6 additions & 6 deletions siteapp/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -1484,21 +1484,21 @@ def test_display_impact_level(self):

# Display imact level testing
# New project should not be categorized
self.assertInNodeText("Mission Impact: Not Categorized", "#systems-fisma-impact-level")
self.assertInNodeText("Mission Impact: Not Categorized", "#systems-security-sensitivity-level")

# Update impact level
# Get project.system.root_element to attach statement holding fisma impact level
project = self.current_project
fil = "Low"
# Test change and test system fisma_impact_level set/get methods
project.system.set_fisma_impact_level(fil)
# Test change and test system security_sensitivity_level set/get methods
project.system.set_security_sensitivity_level(fil)
# Check value changed worked
self.assertEqual(project.system.get_fisma_impact_level, fil)
self.assertEqual(project.system.get_security_sensitivity_level, fil)
# Refresh project page
self.click_element('#btn-project-home')
# See if project page has changed
wait_for_sleep_after( lambda: self.assertInNodeText("low", "#systems-fisma-impact-level") )
impact_level_smts = project.system.root_element.statements_consumed.filter(statement_type=StatementTypeEnum.FISMA_IMPACT_LEVEL.value)
wait_for_sleep_after( lambda: self.assertInNodeText("low", "#systems-security-sensitivity-level") )
impact_level_smts = project.system.root_element.statements_consumed.filter(statement_type=StatementTypeEnum.SECURITY_SENSITIVITY_LEVEL.name)
self.assertEqual(impact_level_smts.count(), 1)

def test_security_objectives(self):
Expand Down
17 changes: 8 additions & 9 deletions siteapp/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -966,15 +966,15 @@ def project(request, project):
if approx_compliance_degrees > 358:
approx_compliance_degrees = 358

# Fetch statement defining FISMA impact level if set
impact_level_smts = project.system.root_element.statements_consumed.filter(
statement_type=StatementTypeEnum.FISMA_IMPACT_LEVEL.value)
if len(impact_level_smts) > 0:
impact_level = impact_level_smts.first().body

# Fetch statement defining Security Sensitivity level if set
security_sensitivity_smts = project.system.root_element.statements_consumed.filter(statement_type=StatementTypeEnum.SECURITY_SENSITIVITY_LEVEL.name)
if len(security_sensitivity_smts) > 0:
security_sensitivity = security_sensitivity_smts.first().body
else:
impact_level = None
security_sensitivity = None

security_objective_smt = project.system.root_element.statements_consumed.filter(statement_type=StatementTypeEnum.SECURITY_IMPACT_LEVEL.value)
security_objective_smt = project.system.root_element.statements_consumed.filter(statement_type=StatementTypeEnum.SECURITY_IMPACT_LEVEL.name)
if security_objective_smt.exists():
security_body = project.system.get_security_impact_level
confidentiality, integrity, availability = security_body.get('security_objective_confidentiality',
Expand All @@ -987,7 +987,7 @@ def project(request, project):
return render(request, "project.html", {
"is_project_page": True,
"project": project,
"impact_level": impact_level,
"security_sensitivity": security_sensitivity,
"confidentiality": confidentiality,
"integrity": integrity,
"availability": availability,
Expand Down Expand Up @@ -1053,7 +1053,6 @@ def project_security_objs_edit(request, project_id):
# project to update
project = Project.objects.get(id=project_id)

# TODO: Move security impact levels to an admin only form. adding validation.
confidentiality = request.POST.get("confidentiality", "").strip() or None
integrity = request.POST.get("integrity", "").strip() or None
availability = request.POST.get("availability", "").strip() or None
Expand Down
6 changes: 3 additions & 3 deletions templates/project.html
Original file line number Diff line number Diff line change
Expand Up @@ -193,9 +193,9 @@ <h2 class="status">{{ poam_status_count.Open }}</h2> <span class="status-small">
#B2E0B2 0 235deg);"> </h2>
<span class="status-small">{{ percent_compliant_100|floatformat:2 }}% compliance (unassessed)</span>
<br/>
<span id="systems-fisma-impact-level" class="status-small">
{% if impact_level %}
Mission Impact: <b>{{ impact_level|lower }}</b>
<span id="systems-security-sensitivity-level" class="status-small">
{% if security_sensitivity %}
Mission Impact: <b>{{ security_sensitivity|lower }}</b>
{% else %}
Mission Impact: <b>Not Categorized</b>
{% endif %}
Expand Down