-
Notifications
You must be signed in to change notification settings - Fork 59
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
Findings dashboard for all organizations #4007
Open
madelondohmen
wants to merge
109
commits into
main
Choose a base branch
from
feature/findings-dashboard-for-all-orgs
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 104 commits
Commits
Show all changes
109 commits
Select commit
Hold shift + click to select a range
8aa5814
Report recipe for all orgs
Rieven fe1c88a
Create Findings Aggregate Report
madelondohmen e8269b2
add model and signal
Rieven f82cbfd
Merge branch 'feature/findings-dashboard-for-all-orgs' of github.com:…
Rieven b3308bb
Merge branch 'main' of github.com:minvws/nl-kat-coordination into fea…
Rieven 7c410a2
check pk instead of id
Rieven ee9eb65
Fixes for organization Dashboard
Rieven 1567bfa
fix get findings from bytes
Rieven 92ff8a5
return 1 finding
Rieven 6ee322c
Update templates and aggregate report
madelondohmen 1114a10
Fix merge conflict
madelondohmen 1ec80c1
Fixes in templates
madelondohmen 6b717e4
fix scheduler is ready
Rieven a1ca8d9
Fix logic
Rieven eac10c7
Fix aggregate summary
madelondohmen 683033e
Merge branch 'feature/findings-dashboard-for-all-orgs' of https://git…
madelondohmen 5e636fe
Fix occurrences count
madelondohmen 80d8e94
Add sorting to reports to get latest report
madelondohmen bfc5a7d
fix none findings for orgs
Rieven ef0b5c2
Merge branch 'feature/findings-dashboard-for-all-orgs' of github.com:…
Rieven 4f43a9d
Update templates
madelondohmen 98b1598
Fix merge conflict
madelondohmen c7db309
Changes in templates
madelondohmen 68d75ef
Add findings org summary and show datetime
madelondohmen 47e1f00
change models and data
Rieven 1a50e80
Merge branch 'feature/findings-dashboard-for-all-orgs' of github.com:…
Rieven 929fcb5
More table fixes
madelondohmen 85ed236
fixes models, views, templates
Rieven 09adcc5
Merge branch 'feature/findings-dashboard-for-all-orgs' of github.com:…
Rieven 4083062
Create Multi Report Findings Report
madelondohmen c8e79d5
Merge branch 'feature/findings-dashboard-for-all-orgs' of https://git…
madelondohmen b34e2e2
Add dashboard org table to findings report
madelondohmen 0d5c5df
fix integer in seeder
Rieven e68f6ec
Merge branch 'feature/findings-dashboard-for-all-orgs' of github.com:…
Rieven 648ea8f
fix report data
Rieven d8da888
Create findings_report_data method
madelondohmen b7cb246
Show 5 most recent reports on scheduled report page
madelondohmen d464c13
Merge branch 'feature/findings-dashboard-for-all-orgs' of https://git…
madelondohmen b6ea32f
fix report data
Rieven d5dc74f
Fix findings report
madelondohmen 7b4d630
Merge branch 'feature/findings-dashboard-for-all-orgs' of github.com:…
Rieven cd14b63
Merge branch 'feature/findings-dashboard-for-all-orgs' of github.com:…
Rieven 73ebd07
Model changes and views
Rieven 0be5dd8
Create two tabs for crisis room: dashboards and findings
madelondohmen 7a11d1b
Resolve merge conflict
madelondohmen d0fd2b3
Fix crisis room findings templates
madelondohmen 70a5657
fix views
Rieven a973727
fix views
Rieven fcc0f79
Merge branch 'feature/findings-dashboard-for-all-orgs' of github.com:…
Rieven c8485f3
organizations findings
Rieven d095abf
Fix include template
madelondohmen 23b899d
Merge branch 'feature/findings-dashboard-for-all-orgs' of https://git…
madelondohmen 4c6b58f
Fix duplicates on finding dashboards
madelondohmen 1e93b8d
set limit report
Rieven df2551a
set offset report
Rieven aca2b86
add description
Rieven 91b59e4
Add titels to crisis rooms + styling and naming fixes
madelondohmen 7cccfa4
findings settings
Rieven cc3ecc9
extend report data with report instance
Rieven aa2ec80
Add findings to report sidemenu
madelondohmen 9a96847
Update intro text in findings report
madelondohmen 1ab95a0
Small fix in template
madelondohmen a241b95
Add highest_risk_level and report_id to report data + show only 25 cr…
madelondohmen a48c5fe
Add links to findings report
madelondohmen 88da5ea
Move textblocks to improve readability
madelondohmen 8f5f75d
Fix dashboard template
madelondohmen c07e8a2
Changes in template
madelondohmen b0cad1d
fix view
Rieven 775492b
Remove navbar and update headers
madelondohmen ac8e944
Merge branch 'feature/findings-dashboard-for-all-orgs' of github.com:…
Rieven e78d4a4
Merge branch 'feature/findings-dashboard-for-all-orgs' of github.com:…
Rieven 081dbe1
Remove findings header
madelondohmen c327ef4
Merge branch 'main' of github.com:minvws/nl-kat-coordination into fea…
Rieven 82a7500
Merge branch 'feature/findings-dashboard-for-all-orgs' of github.com:…
Rieven 1c9fb27
Fix buttons
madelondohmen a075275
fix models and migrations
Rieven c9d2f6e
Add empty text for 0 organizations
madelondohmen 26db560
Add documentation
madelondohmen e531500
Merge branch 'feature/findings-dashboard-for-all-orgs' of https://git…
madelondohmen d3af0e1
Add created_at date and recurrence
madelondohmen f3ea66d
Cages for report and making tests easier
Rieven ca8ecd4
Merge branch 'feature/findings-dashboard-for-all-orgs' of github.com:…
Rieven 87e6fdb
Small fixes in templates
madelondohmen eca40ea
Add setup for tests
madelondohmen 9bf0e50
Update empty state text for findings dashboard
madelondohmen b9ea527
fix test
Rieven 5016ea6
Merge branch 'feature/findings-dashboard-for-all-orgs' of github.com:…
Rieven b0a71de
fix test
Rieven cbda800
fix test
Rieven 06ba31a
Check for findings dashboard name
madelondohmen 5273f19
Add tests
madelondohmen 59e9525
add more test
Rieven 2cd168d
Merge branch 'main' into feature/findings-dashboard-for-all-orgs
madelondohmen c4c1d1b
Update translations
madelondohmen 5529aed
Make dashboards done
Rieven 818a8eb
file changes
Rieven 978cfc2
Update translations and small fix
madelondohmen 4b2f7e1
fix test and lang
Rieven 48fa856
Merge branch 'feature/findings-dashboard-for-all-orgs' of github.com:…
Rieven 7bb8d75
Merge branch 'main' into feature/findings-dashboard-for-all-orgs
Rieven ea90b5c
Add breadcrumbs
Rieven 8c005be
Merge branch 'feature/findings-dashboard-for-all-orgs' of github.com:…
Rieven 0c507c9
revert the unnecessary
Rieven 4c96bf6
update recipe seder
Rieven a22f1bd
Update rocky/crisis_room/models.py
Rieven 2e9eeac
fixes for review and QA notes
Rieven 37b6663
Merge branch 'feature/findings-dashboard-for-all-orgs' of github.com:…
Rieven c4da3db
Merge branch 'main' into feature/findings-dashboard-for-all-orgs
Rieven 247074e
check if dashboard is updated or created
Rieven File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
=========== | ||
Crisis Room | ||
=========== | ||
|
||
In OpenKAT we differentiate two Crisis Rooms: | ||
|
||
- **Single Organization Crisis Room:** a Crisis Room for each organization separately | ||
- **General Crisis Room:** one general Crisis Room with for all organizations | ||
|
||
|
||
Single Organization Crisis Room | ||
=============================== | ||
|
||
This page shows a Crisis Room for each organization separately. | ||
Currently, this Crisis Room shows the top 10 most severe Findings. | ||
In the future it will serve as a dashboard which can be customized by the user. | ||
|
||
|
||
General Crisis Room | ||
=================== | ||
|
||
This page shows the Crisis Room for all organizations. | ||
Currently, this Crisis Room only shows the Findings, but in the future it will also show dashboards, | ||
which can be customized by the user. | ||
|
||
Findings | ||
-------- | ||
This section shows all the findings that have been identified for all organizations. | ||
These findings are shown in a table, grouped by organization and finding types. | ||
|
||
Every organization has one default report recipe. This recipe is used to create an Aggregate Findings Report. | ||
The output of this report, for each organization, is shown in this section. | ||
|
||
The default settings for this report recipe are: | ||
|
||
- report_name_format = ``Crisis Room Aggregate Report`` | ||
- ooi_types = ``["IPAddressV6", "Hostname", "IPAddressV4"]`` | ||
- scan_level = ``[1, 2, 3]`` | ||
- scan_type = ``["declared"]`` | ||
- report_types = ``["systems-report", "findings-report"]`` | ||
- cron_expression = ``0 * * * *`` (every hour) | ||
|
||
It is possible to update the report recipe*. To do this: | ||
|
||
- Go to "Reports" | ||
- Click on the tab "Scheduled" | ||
- Look for the "Criris Room Aggregate Report" | ||
- Open the row | ||
- Click on "Edit report recipe" | ||
|
||
*\*Note: if you want to update the report recipe, you have to do this for every organization.* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
import json | ||
from datetime import datetime, timezone | ||
from pathlib import Path | ||
from typing import Any | ||
from uuid import uuid4 | ||
|
||
from crisis_room.models import Dashboard, DashboardData | ||
from django.conf import settings | ||
from django.core.management import BaseCommand | ||
from tools.models import Organization | ||
from tools.ooi_helpers import create_ooi | ||
|
||
from octopoes.connector.octopoes import OctopoesAPIConnector | ||
from octopoes.models.ooi.reports import ReportRecipe | ||
from rocky.bytes_client import get_bytes_client | ||
from rocky.scheduler import ReportTask, ScheduleRequest, scheduler_client | ||
|
||
FINDINGS_DASHBOARD_NAME = "Crisis Room Findings Dashboard" | ||
|
||
|
||
def get_or_create_default_dashboard(organization: Organization): | ||
valid_time = datetime.now(timezone.utc) | ||
is_scheduler_ready_for_schedule = is_scheduler_enabled(organization) | ||
|
||
if is_scheduler_ready_for_schedule: | ||
path = Path(__file__).parent / "recipe_seeder.json" | ||
with path.open("r") as recipe_seeder: | ||
recipe_default = json.load(recipe_seeder) | ||
|
||
dashboard, _ = Dashboard.objects.get_or_create(name=FINDINGS_DASHBOARD_NAME, organization=organization) | ||
|
||
dashboard_data, created = DashboardData.objects.get_or_create(dashboard=dashboard) | ||
if created: | ||
recipe = create_organization_recipe(valid_time, organization, recipe_default) | ||
dashboard_data.recipe = recipe.primary_key | ||
schedule_request = create_schedule_request(valid_time, organization, recipe) | ||
scheduler_client(organization.code).post_schedule(schedule=schedule_request) | ||
|
||
dashboard_data.findings_dashboard = True | ||
dashboard_data.save() | ||
|
||
|
||
def create_organization_recipe( | ||
valid_time: datetime, organization: Organization, recipe_default: dict[str, Any] | ||
) -> ReportRecipe: | ||
report_recipe = ReportRecipe(recipe_id=uuid4(), **recipe_default) | ||
|
||
octopoes_client = OctopoesAPIConnector( | ||
settings.OCTOPOES_API, organization.code, timeout=settings.ROCKY_OUTGOING_REQUEST_TIMEOUT | ||
) | ||
bytes_client = get_bytes_client(organization.code) | ||
|
||
create_ooi(api_connector=octopoes_client, bytes_client=bytes_client, ooi=report_recipe, observed_at=valid_time) | ||
return report_recipe | ||
|
||
|
||
def is_scheduler_enabled(organization: Organization) -> bool: | ||
scheduler_id = f"report-{organization.code}" | ||
return scheduler_client(organization.code).is_scheduler_ready(scheduler_id) | ||
|
||
|
||
def create_schedule_request( | ||
start_datetime: datetime, organization: Organization, report_recipe: ReportRecipe | ||
) -> ScheduleRequest: | ||
report_task = ReportTask( | ||
organisation_id=organization.code, report_recipe_id=str(report_recipe.recipe_id) | ||
).model_dump() | ||
|
||
return ScheduleRequest( | ||
scheduler_id=f"report-{organization.code}", | ||
data=report_task, | ||
schedule=report_recipe.cron_expression, | ||
deadline_at=start_datetime.isoformat(), | ||
) | ||
|
||
|
||
class Command(BaseCommand): | ||
def handle(self, *args, **options): | ||
organizations = Organization.objects.all() | ||
for organization in organizations: | ||
get_or_create_default_dashboard(organization) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
{ | ||
"report_name_format": "Crisis Room Aggregate Report", | ||
"subreport_name_format": "Findings Report for ${ooi}", | ||
"input_recipe": { | ||
"query": { | ||
"ooi_types": [ | ||
"IPAddressV6", | ||
"Hostname", | ||
"IPAddressV4", | ||
"URL" | ||
], | ||
"scan_level": [ | ||
1, | ||
2, | ||
3, | ||
4 | ||
], | ||
"scan_type": [ | ||
"declared" | ||
], | ||
"search_string": "", | ||
"order_by": "object_type", | ||
"asc_desc": "desc" | ||
} | ||
}, | ||
"parent_report_type": "aggregate-organisation-report", | ||
"report_types": [ | ||
"systems-report", | ||
"findings-report" | ||
], | ||
"cron_expression": "0 * * * *" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
# Generated by Django 5.0.9 on 2024-12-18 11:29 | ||
|
||
import django.core.validators | ||
import django.db.models.deletion | ||
from django.db import migrations, models | ||
|
||
|
||
class Migration(migrations.Migration): | ||
initial = True | ||
|
||
dependencies = [("tools", "0044_alter_organization_options")] | ||
|
||
operations = [ | ||
migrations.CreateModel( | ||
name="Dashboard", | ||
fields=[ | ||
("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), | ||
("name", models.CharField(max_length=126)), | ||
( | ||
"organization", | ||
models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to="tools.organization"), | ||
), | ||
], | ||
options={"unique_together": {("name", "organization")}}, | ||
), | ||
migrations.CreateModel( | ||
name="DashboardData", | ||
fields=[ | ||
("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), | ||
("recipe", models.CharField(max_length=126)), | ||
("template", models.CharField(blank=True, default="findings_report/report.html", max_length=126)), | ||
( | ||
"position", | ||
models.IntegerField( | ||
blank=True, | ||
default=1, | ||
help_text="Where on the dashboard do you want to show the data? Position 1 is the most top level and the max position is 16.", | ||
max_length=126, | ||
validators=[ | ||
django.core.validators.MinValueValidator(1), | ||
django.core.validators.MaxValueValidator(16), | ||
], | ||
), | ||
), | ||
( | ||
"display_in_crisis_room", | ||
models.BooleanField( | ||
default=False, help_text="Will be displayed on the general crisis room, for all organizations." | ||
), | ||
), | ||
( | ||
"display_in_dashboard", | ||
models.BooleanField( | ||
default=False, help_text="Will be displayed on a single organization dashboard" | ||
), | ||
), | ||
( | ||
"findings_dashboard", | ||
models.BooleanField( | ||
default=False, help_text="Will be displayed on the findings dashboard for all organizations" | ||
), | ||
), | ||
( | ||
"dashboard", | ||
models.ForeignKey( | ||
null=True, on_delete=django.db.models.deletion.SET_NULL, to="crisis_room.dashboard" | ||
), | ||
), | ||
], | ||
options={"unique_together": {("dashboard", "findings_dashboard"), ("dashboard", "position")}}, | ||
), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
from django.core.validators import MaxValueValidator, MinValueValidator | ||
from django.db import models | ||
from django.utils.translation import gettext_lazy as _ | ||
from tools.models import Organization | ||
|
||
|
||
class Dashboard(models.Model): | ||
name = models.CharField(blank=False, max_length=126) | ||
organization = models.ForeignKey(Organization, on_delete=models.SET_NULL, null=True) | ||
|
||
class Meta: | ||
unique_together = ["name", "organization"] | ||
|
||
def __str__(self) -> str: | ||
if self.name: | ||
return f"{self.name} for organization {self.organization}" | ||
return super().__str__() | ||
|
||
|
||
class DashboardData(models.Model): | ||
dashboard = models.ForeignKey(Dashboard, on_delete=models.SET_NULL, null=True) | ||
recipe = models.CharField(blank=False, max_length=126) | ||
template = models.CharField(blank=True, max_length=126, default="findings_report/report.html") | ||
position = models.IntegerField( | ||
blank=True, | ||
max_length=126, | ||
default=1, | ||
validators=[MinValueValidator(1), MaxValueValidator(16)], | ||
help_text=_( | ||
"Where on the dashboard do you want to show the data? " | ||
"Position 1 is the most top level and the max position is 16." | ||
), | ||
) | ||
display_in_crisis_room = models.BooleanField( | ||
default=False, help_text=_("Will be displayed on the general crisis room, for all organizations.") | ||
) | ||
display_in_dashboard = models.BooleanField( | ||
default=False, help_text=_("Will be displayed on a single organization dashboard") | ||
) | ||
findings_dashboard = models.BooleanField( | ||
default=False, help_text=_("Will be displayed on the findings dashboard for all organizations") | ||
) | ||
|
||
class Meta: | ||
unique_together = [["dashboard", "position"], ["dashboard", "findings_dashboard"]] | ||
|
||
def __str__(self) -> str: | ||
if self.dashboard: | ||
return f"{self.dashboard.name} for organization {self.dashboard.organization}" | ||
Rieven marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return super().__str__() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
{% extends "layouts/base.html" %} | ||
|
||
{% load i18n %} | ||
{% load static %} | ||
|
||
{% block content %} | ||
{% include "header.html" %} | ||
|
||
<main id="main-content" tabindex="-1" class="crisisroom"> | ||
<section> | ||
<div> | ||
<h1>{% translate "Crisis Room" %}</h1> | ||
<p class="emphasized">{% translate "Crisis Room overview for all organizations" %}</p> | ||
</div> | ||
{% include "crisis_room_findings.html" %} | ||
|
||
</section> | ||
</main> | ||
{% endblock content %} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
{% extends "layouts/base.html" %} | ||
|
||
{% load i18n %} | ||
{% load static %} | ||
|
||
{% block content %} | ||
{% include "header.html" %} | ||
|
||
<main id="main-content" tabindex="-1" class="crisisroom"> | ||
<section> | ||
<div> | ||
<h2>{% translate "Dashboards" %}</h2> | ||
<p> | ||
{% blocktranslate %} | ||
On this page you can see an overview of the dashboards for all organizations. | ||
**More context can be written here** | ||
{% endblocktranslate %} | ||
</p> | ||
</div> | ||
{% for organization, organization_dashboards in organizations_dashboards.items %} | ||
<section> | ||
<div> | ||
<h3>{{ organization.name }} {% translate "dashboards" %}</h3> | ||
{% if organization_dashboards %} | ||
{% for dashboards in organization_dashboards %} | ||
{% for dashboard_data, report in dashboards.items %} | ||
{% if report %} | ||
<section> | ||
<div> | ||
<h4>{{ dashboard_data }}</h4> | ||
{% include dashboard_data.template with data=report.1 is_dashboard="yes" %} | ||
|
||
</div> | ||
</section> | ||
{% endif %} | ||
{% endfor %} | ||
{% endfor %} | ||
{% else %} | ||
<p>{% translate "There are no dashboards to display." %}</p> | ||
{% endif %} | ||
</div> | ||
</section> | ||
{% endfor %} | ||
</section> | ||
</main> | ||
{% endblock content %} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a few suggestions:
dashboards
make target and the output of this command,dashboards
would be a better command name. I would suggest renaming this module todashboards.py
.