Skip to content

Commit

Permalink
Merge pull request #52 from pep-un/v3.0
Browse files Browse the repository at this point in the history
Publish v3.0
  • Loading branch information
pep-un authored Oct 13, 2024
2 parents e90f071 + e778450 commit 64e51ea
Show file tree
Hide file tree
Showing 52 changed files with 1,910 additions and 391 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/django.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
strategy:
max-parallel: 4
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11"]
python-version: ["3.9", "3.10", "3.11", "3.12"]

steps:
- uses: actions/checkout@v3
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/pylint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11"]
python-version: ["3.9", "3.10", "3.11", "3.12"]
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
__pycache__
db.sqlite3
media
attachments/

# Backup files #
*.bak
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

Oxomium is an opensource project build to help company to manage the cybersecurity compliance of organisations.

It provides help to CISO or other security people to follow conformity to a Policy.
It provides help to CISO or other security people to follow conformity to a Framework.

More information on [Oxomium Website](https://www.oxomium.org).

Expand Down
23 changes: 12 additions & 11 deletions conformity/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from django.contrib import admin
from import_export import resources
from import_export.admin import ImportExportModelAdmin
from .models import Organization, Policy, Measure, Conformity, Audit, Finding, Action, Control, ControlPoint
from .models import Organization, Framework, Requirement, Conformity, Audit, Finding, Action, Control, ControlPoint, Attachment


class OrganizationResources(resources.ModelResource):
Expand All @@ -17,22 +17,22 @@ class OrganizationAdmin(ImportExportModelAdmin):
ressource_class = Organization


class PolicyResources(resources.ModelResource):
class FrameworkResources(resources.ModelResource):
class Meta:
model = Policy
model = Framework


class PolicyAdmin(ImportExportModelAdmin):
ressource_class = Policy
class FrameworkAdmin(ImportExportModelAdmin):
ressource_class = Framework


class MeasureResources(resources.ModelResource):
class RequirementResources(resources.ModelResource):
class Meta:
model = Measure
model = Requirement


class MeasureAdmin(ImportExportModelAdmin):
ressource_class = Measure
class RequirementAdmin(ImportExportModelAdmin):
ressource_class = Requirement


class ConformityResources(resources.ModelResource):
Expand All @@ -55,12 +55,13 @@ class ActionAdmin(ImportExportModelAdmin):


# Registration
admin.site.register(Policy, PolicyAdmin)
admin.site.register(Measure, MeasureAdmin)
admin.site.register(Framework, FrameworkAdmin)
admin.site.register(Requirement, RequirementAdmin)
admin.site.register(Conformity, ConformityAdmin)
admin.site.register(Action, ActionAdmin)
admin.site.register(Audit)
admin.site.register(Finding)
admin.site.register(Organization, OrganizationAdmin)
admin.site.register(Control)
admin.site.register(ControlPoint)
admin.site.register(Attachment)
11 changes: 9 additions & 2 deletions conformity/filterset.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from django_filters import FilterSet, CharFilter
from .models import Action, ControlPoint
from .models import Action, Control, ControlPoint, Attachment


class ActionFilter(FilterSet):
Expand All @@ -10,6 +10,13 @@ class Meta:


class ControlFilter(FilterSet):
class Meta:
model = Control
fields = ['level', 'organization', 'conformity__id', 'frequency']


class ControlPointFilter(FilterSet):
class Meta:
model = ControlPoint
fields = ['control__level', 'control__organization', 'control__conformity__id', 'control__control__id', 'control__frequency', 'control__level']
fields = [ 'control__id', 'control__frequency', 'status' ]

29 changes: 23 additions & 6 deletions conformity/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
Forms for front-end editing of Models instance
"""

from django.forms import ModelForm
from django.forms import ModelForm, FileField, ClearableFileInput
from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import request
from django.utils import timezone
Expand All @@ -22,15 +22,18 @@ def __init__(self, *args, **kwargs):


class OrganizationForm(LoginRequiredMixin, ModelForm):
attachments = FileField(required=False, widget=ClearableFileInput())
class Meta:
model = Organization
fields = '__all__'
fields = ['name', 'administrative_id', 'description', 'applicable_frameworks']


class AuditForm(LoginRequiredMixin, ModelForm):
attachments = FileField(required=False, widget=ClearableFileInput())
class Meta:
model = Audit
fields = '__all__'
exclude = ['attachment']


class FindingForm(LoginRequiredMixin, ModelForm):
Expand Down Expand Up @@ -77,15 +80,29 @@ class Meta:


class ControlPointForm(LoginRequiredMixin, ModelForm):
attachments = FileField(required=False, widget=ClearableFileInput())
class Meta:
model = ControlPoint
fields = ['control_date', 'control_user', 'status', 'comment']
fields = ['control_date', 'control_user', 'status', 'comment', 'attachments']

def __init__(self, *args, **kwargs):
self.user = kwargs.pop('user', None)
super(ControlPointForm, self).__init__(*args, **kwargs)
self.initial['control_date'] = timezone.now()
self.fields['control_date'].disabled = True

if self.get_initial_for_field(self.fields['status'], 'status') != ControlPoint.Status.TOBEEVALUATED.value:
# Set some value for all situation
self.fields['control_date'].disabled = True
self.fields['control_user'].disabled = True

# Set some value if the ControlPoint has to be evaluated
if self.get_initial_for_field(self.fields['status'], 'status') == ControlPoint.Status.TOBEEVALUATED.value:
self.initial['control_date'] = timezone.now()
self.initial['control_user'] = self.user
self.fields['status'].widget.choices = [
(ControlPoint.Status.COMPLIANT, ControlPoint.Status.COMPLIANT.label),
(ControlPoint.Status.NONCOMPLIANT, ControlPoint.Status.NONCOMPLIANT.label),
]
# Switch to display mode if ControlPoint is not to be evaluated
else:
del self.fields['attachments']
for field in self.fields:
self.fields[field].disabled = True
51 changes: 51 additions & 0 deletions conformity/middleware.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
from django.contrib.auth.signals import user_logged_in
from django.dispatch import receiver
from datetime import datetime
from dateutil.relativedelta import relativedelta
from .models import ControlPoint


class SanityCheckMiddleware:
last_checked = datetime.today() # Class variable to store the last check date

def __init__(self, get_response):
self.get_response = get_response

def __call__(self, request):
response = self.get_response(request)
self.run_daily_checks()
return response

def run_daily_checks(self):
"""Performs the daily integrity checks."""
today = datetime.today().date()

if SanityCheckMiddleware.last_checked != today:
self.check_control_points(today)
SanityCheckMiddleware.last_checked = today

@staticmethod
def check_control_points(today):
"""Checks and updates the status of ControlPoint."""
yesterday=today - relativedelta(days=1)

"""Update SCHD to TOBE when period start"""
s=today.replace(day=1)
e=today.replace(day=1) + relativedelta(months=1)
scheduled_controls = ControlPoint.objects.filter(period_start_date__lte=today,
period_end_date__gte=today,
status="SCHD")
scheduled_controls.update(status='TOBE')

"""Update expired TOBE to MISS """
missed_controls = ControlPoint.objects.filter(period_start_date__lt=today,
period_end_date__lt=today,
status="TOBE")
missed_controls.update(status='MISS')


# Connect the user login signal
@receiver(user_logged_in)
def update_on_login(sender, user, request, **kwargs):
middleware = SanityCheckMiddleware(None)
middleware.run_daily_checks()
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class Migration(migrations.Migration):
('name', models.CharField(max_length=256)),
('administrative_id', models.CharField(blank=True, max_length=256)),
('description', models.CharField(blank=True, max_length=256)),
('applicable_policies', models.ManyToManyField(blank=True, to='conformity.policy')),
('applicable_frameworks', models.ManyToManyField(blank=True, to='conformity.policy')),
],
),
migrations.CreateModel(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class Migration(migrations.Migration):
('name', models.CharField(max_length=256, unique=True)),
('administrative_id', models.CharField(blank=True, max_length=256)),
('description', models.TextField(blank=True, max_length=4096)),
('applicable_policies', models.ManyToManyField(blank=True, to='conformity.policy')),
('applicable_frameworks', models.ManyToManyField(blank=True, to='conformity.policy')),
],
options={
'ordering': ['name'],
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Generated by Django 4.2.9 on 2024-08-25 02:39

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('conformity', '0040_alter_control_level'),
]

operations = [
migrations.RenameModel(
old_name='Policy',
new_name='Framework',
),
migrations.AlterModelOptions(
name='framework',
options={'ordering': ['name'], 'verbose_name': 'Framework', 'verbose_name_plural': 'Frameworks'},
),
migrations.RenameField(
model_name='measure',
old_name='policy',
new_name='framework',
),
migrations.RenameField(
model_name='audit',
old_name='audited_policies',
new_name='audited_frameworks',
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Generated by Django 4.2.9 on 2024-08-25 04:38

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('conformity', '0041_rename_policy_framework_alter_framework_options_and_more'),
]

operations = [
migrations.RenameModel(
old_name='Measure',
new_name='Requirement',
),
migrations.AlterModelOptions(
name='conformity',
options={'ordering': ['organization', 'requirement'], 'verbose_name': 'Conformity', 'verbose_name_plural': 'Conformities'},
),
migrations.RenameField(
model_name='conformity',
old_name='measure',
new_name='requirement',
),
migrations.AlterUniqueTogether(
name='conformity',
unique_together={('organization', 'requirement')},
),
]
24 changes: 24 additions & 0 deletions conformity/migrations/0043_attachment.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Generated by Django 4.2.9 on 2024-10-12 02:57

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


class Migration(migrations.Migration):

dependencies = [
('conformity', '0042_rename_measure_requirement_alter_conformity_options_and_more'),
]

operations = [
migrations.CreateModel(
name='Attachment',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('file', models.FileField(upload_to='attachments/')),
('comment', models.TextField(blank=True, max_length=4096)),
('mime_type', models.CharField(blank=True, max_length=255)),
('create_date', models.DateField(default=django.utils.timezone.now)),
],
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Generated by Django 4.2.9 on 2024-10-12 03:03

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('conformity', '0043_attachment'),
]

operations = [
migrations.AddField(
model_name='action',
name='attachment',
field=models.ManyToManyField(blank=True, related_name='actions', to='conformity.attachment'),
),
migrations.AddField(
model_name='audit',
name='attachment',
field=models.ManyToManyField(blank=True, related_name='audits', to='conformity.attachment'),
),
migrations.AddField(
model_name='controlpoint',
name='attachment',
field=models.ManyToManyField(blank=True, related_name='ControlPoint', to='conformity.attachment'),
),
migrations.AddField(
model_name='finding',
name='attachment',
field=models.ManyToManyField(blank=True, related_name='findings', to='conformity.attachment'),
),
migrations.AddField(
model_name='framework',
name='attachment',
field=models.ManyToManyField(blank=True, related_name='frameworks', to='conformity.attachment'),
),
migrations.AddField(
model_name='organization',
name='attachment',
field=models.ManyToManyField(blank=True, related_name='organizations', to='conformity.attachment'),
),
]
Loading

0 comments on commit 64e51ea

Please sign in to comment.