Skip to content

Commit

Permalink
Merge from main back to NZISM (#1)
Browse files Browse the repository at this point in the history
* Create docker-compose.ps1

This is the initialization script for Windows user

* translate doc-pol in French

* Create cjis.yaml

create mapping for cjis update
fix error message

* Avoid reckless error localization lookups

* Remove is_open_for_signup method override

The signup check is already done in the SAML views

* chore: Organize imports

* chore: Some cleaning

* Modèle ANSSI

ajout de nouveaux framework et homogénéisation des références des bibliothèques

* Modèles ANSSI

ajout de nouveaux framework et homogénéisation des références des bibliothèques

* Fix objects_meta always counting 1 object even when there is more than that

* Fix null name for implementation groups

* Add extra log useful for mapping issues

* Update utils.py

fix and rationalize messages

* Update utils.py

* add GL on costs and losses

* Add migration to fix the wrong objects_meta counters

* Formatter

* quick cleanup

* Fix reference controls french translation

It translates to "Mesures de référence", not "Contrôles de référence"

* Remove debug code

* Remove unnecessary click handler

* Change all backend endpoint URLs not ending with a slash to stop useless redirections when requesting the API

* Fix broken dependency links for loaded library detail views

* Backend formatter

* Update data-model.md

* Simplify post token generation flow

This essentially removes redundant or irrelevant checks from allauth.
As we will most certainly only have a single social account adapter for the
entire lifespan of the project, these changes will only save us from headaches.

* Render IdP-initiated SSO rejected error

* Create enum for SAML-related auth errors

* Internationalize auth errors

* Use FieldsRelatedField to serialize dependencies

* chore: Run formatting

* chore: Organize imports

* Bump django from 5.0.7 to 5.0.8 in /backend

Bumps [django](https://github.com/django/django) from 5.0.7 to 5.0.8.
- [Commits](django/django@5.0.7...5.0.8)

---
updated-dependencies:
- dependency-name: django
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <[email protected]>

* TPRM model

Leverage compliance assessment.

* fix translation spec

* Update data-model.md

clarify solution.
small fixes.

* Update data-model.md

Consider contract as a subset of applied controls.
A domain can be owned by one entity at most.

* Update id and new template anssi framework

* Update id and new template anssi framework

* TPRM

* Update data-model.md

* Update startup-tests.yml

try fix docker test error

* Update startup-tests.yml

try fix docker test

* 724: improve framework naming rendering

* Small ui improvement

* also improve library view

* Add RTS DORA on JET, on OVS

* Add PART-IS

* fix: typo in quality checks

* chore: update translations with Fink 🐦

* Update libraries.test.ts

try fix functional tests

* try fix functional tests

- une name instead of ref to get a lib.
- adjust library name for NIST CSF, so that lib name=referential name (assumption for tests)

* Update page-content.ts

prettier

* Update README.md

* fix: allow empty link

* fix French translation for iso27005 matrix

* Update README.md

* fix: revert evidence link field schema

* chore: add missing comma

* Render authentication errors

* feat: raise urn max length

* chore: format migration

* Add Romanian translation

* update the excel sheet

* generate the new yaml with annotations and levels

* Update README.md

Add in 1.6.6

* Update README.md

* Update README.md

---------

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: Fabrizio Di Carlo <[email protected]>
Co-authored-by: eric-intuitem <[email protected]>
Co-authored-by: Nassim Tabchiche <[email protected]>
Co-authored-by: protocolpaladin <[email protected]>
Co-authored-by: Nassim <[email protected]>
Co-authored-by: monsieurswag <[email protected]>
Co-authored-by: Abder <[email protected]>
Co-authored-by: ImanABS <[email protected]>
Co-authored-by: monsieurswag <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Mohamed-Hacene <[email protected]>
Co-authored-by: Mohamed-Hacene <[email protected]>
  • Loading branch information
13 people authored Aug 16, 2024
1 parent 83e9c50 commit 7ce6cbb
Show file tree
Hide file tree
Showing 75 changed files with 18,422 additions and 334 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/startup-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ jobs:
export $(grep -v '^#' .env | xargs)
- name: Config the Docker app
run: |
sleep 30 # give the migrations time to finish (included in the up on the previous step)
sleep 60 # give the migrations time to finish (included in the up on the previous step)
docker compose -f docker-compose-build.yml exec backend /bin/bash -c "[email protected] DJANGO_SUPERUSER_PASSWORD=1234 python manage.py createsuperuser --noinput && exit 0"
- name: Run tests
working-directory: ${{ env.working-directory }}
Expand Down
19 changes: 12 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ Star the project 🌟 to get releases notification and help growing the communit
</p>

<p align="center">
<a href="https://trendshift.io/repositories/9343" target="_blank"><img src="https://trendshift.io/api/badge/repositories/9343" alt="intuitem%2Fciso-assistant-community | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
<br />
<a href="https://intuitem.com">intuitem.com</a>
·
Expand All @@ -16,13 +17,15 @@ Star the project 🌟 to get releases notification and help growing the communit
·
<a href="#supported-frameworks-">Frameworks</a>
<br />

</p>

![](gh_banner.png)

[![Backend code coverage](https://github.com/intuitem/ciso-assistant-community/actions/workflows/backend-coverage.yaml/badge.svg)](https://github.com/intuitem/ciso-assistant-community/actions/workflows/backend-coverage.yaml)
[![CodeFactor](https://www.codefactor.io/repository/github/intuitem/ciso-assistant-community/badge)](https://www.codefactor.io/repository/github/intuitem/ciso-assistant-community)
[![API Tests](https://github.com/intuitem/ciso-assistant-community/actions/workflows/backend-api-tests.yml/badge.svg)](https://github.com/intuitem/ciso-assistant-community/actions/workflows/backend-api-tests.yml)
[![Functional Tests](https://github.com/intuitem/ciso-assistant-community/actions/workflows/functional-tests.yml/badge.svg?branch=main)](https://github.com/intuitem/ciso-assistant-community/actions/workflows/functional-tests.yml)
[![Codacy Badge](https://app.codacy.com/project/badge/Grade/795e9d4203bf469dafcc45a9f3131d57)](https://app.codacy.com/gh/intuitem/ciso-assistant-community/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)

CISO Assistant brings a different take to **GRC** and Cyber Security Posture Management:

Expand Down Expand Up @@ -103,7 +106,7 @@ Check out the online documentation on https://intuitem.gitbook.io/ciso-assistant
9. General Data Protection Regulation (GDPR): Full text and checklist from GDPR.EU 🇪🇺
10. Essential Eight 🇦🇺
11. NYDFS 500 with 2023-11 amendments 🇺🇸
12. DORA 🇪🇺
12. DORA (Act, RTS, ITS and GL) 🇪🇺
13. NIST AI Risk Management Framework 🇺🇸🤖
14. NIST SP 800-53 rev5 🇺🇸
15. France LPM/OIV rules 🇫🇷
Expand Down Expand Up @@ -145,6 +148,7 @@ Check out the online documentation on https://intuitem.gitbook.io/ciso-assistant
51. California Consumer Privacy Act Regulations 🇺🇸
52. NCSC Cyber Essentials 🇬🇧
53. Directive Nationale de la Sécurité des Systèmes d'Information (DNSSI) Maroc 🇲🇦
54. Part-IS ✈️🇪🇺

### Community contributions

Expand All @@ -153,9 +157,10 @@ Check out the online documentation on https://intuitem.gitbook.io/ciso-assistant
3. ANSSI : Recommandations de configuration d'un système GNU/Linux 🇫🇷
4. PSSI-MCAS (Politique de sécurité des systèmes d’information pour les ministères chargés des affaires sociales) 🇫🇷
5. ANSSI : Recommandations pour la protection des systèmes d'information essentiels 🇫🇷
6. New Zealand Information Security Manual (NZISM) ɴᴢ

<br/>
6. ANSSI : Recommandations de sécurité pour l'architecture d'un système de journalisation 🇫🇷
7. ANSSI : Recommandations de sécurité relatives à TLS 🇫🇷
8. New Zealand Information Security Manual (NZISM) ɴᴢ
br/>

> [!NOTE]
> `*` These frameworks require an extra manual step of getting the latest Excel sheet through their website as their license prevent direct usage.
Expand All @@ -166,10 +171,9 @@ Checkout the [library](/backend/library/libraries/) and [tools](/tools/) for the

### Coming soon

- Part-IS
- ENS Esquema Nacional de seguridad (español)
- NIST 800-82
- Korea ISA: ISMS-P
- ENS Esquema Nacional de seguridad (español)

- and much more: just ask on [Discord](https://discord.gg/qvkaMdQ8da). If it's an open standard, we'll do it for you, _free of charge_ 😉

Expand Down Expand Up @@ -475,6 +479,7 @@ Set DJANGO_DEBUG=False for security reason.
- NL: Dutch
- IT: Italian
- PL: Polish
- RO: Romanian

## Built With 💜

Expand Down
6 changes: 4 additions & 2 deletions backend/ciso_assistant/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,8 @@ def set_ciso_assistant_url(_, __, event_dict):
("nd", "Dutch"),
("pl", "Polish"),
("pt", "Portuguese"),
("ar", "Arabic"),
("ro", "Romanian"),
]

PROJECT_PATH = os.path.dirname(os.path.abspath(__file__))
Expand Down Expand Up @@ -359,8 +361,8 @@ def set_ciso_assistant_url(_, __, event_dict):

SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")

ACCOUNT_ADAPTER = "iam.adapter.MyAccountAdapter"
SOCIALACCOUNT_ADAPTER = "iam.adapter.MySocialAccountAdapter"
ACCOUNT_ADAPTER = "iam.adapter.AccountAdapter"
SOCIALACCOUNT_ADAPTER = "iam.adapter.SocialAccountAdapter"

SOCIALACCOUNT_EMAIL_AUTHENTICATION = True
SOCIALACCOUNT_EMAIL_AUTHENTICATION_AUTO_CONNECT = True
Expand Down
38 changes: 38 additions & 0 deletions backend/core/migrations/0020_fix_libraries_objects_meta.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
from django.db import migrations
import json


def fix_libraries_objects_meta(apps, schema_editor):
StoredLibrary = apps.get_model("core", "StoredLibrary")
LoadedLibrary = apps.get_model("core", "LoadedLibrary")

for library in StoredLibrary.objects.all():
objects = json.loads(library.content)
library.objects_meta = {
key: (1 if key in ["framework", "requirement_mapping_set"] else len(value))
for key, value in objects.items()
}
library.save()

for library in LoadedLibrary.objects.all():
objects_meta = {}
for object_name, object_set in [
("frameworks", library.frameworks),
("threats", library.threats),
("reference_controls", library.reference_controls),
("risk_matrix", library.risk_matrices),
]:
count = object_set.count()
if count > 0:
objects_meta[object_name] = count

library.objects_meta = objects_meta
library.save()


class Migration(migrations.Migration):
dependencies = [
("core", "0019_merge_20240726_2156"),
]

operations = [migrations.RunPython(fix_libraries_objects_meta)]
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Generated by Django 5.0.4 on 2024-08-14 12:05

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("core", "0020_fix_libraries_objects_meta"),
]

operations = [
migrations.AlterField(
model_name="framework",
name="urn",
field=models.CharField(
blank=True, max_length=255, null=True, unique=True, verbose_name="URN"
),
),
migrations.AlterField(
model_name="loadedlibrary",
name="urn",
field=models.CharField(
blank=True, max_length=255, null=True, verbose_name="URN"
),
),
migrations.AlterField(
model_name="referencecontrol",
name="urn",
field=models.CharField(
blank=True, max_length=255, null=True, unique=True, verbose_name="URN"
),
),
migrations.AlterField(
model_name="requirementmappingset",
name="urn",
field=models.CharField(
blank=True, max_length=255, null=True, unique=True, verbose_name="URN"
),
),
migrations.AlterField(
model_name="requirementnode",
name="parent_urn",
field=models.CharField(
blank=True, max_length=255, null=True, verbose_name="Parent URN"
),
),
migrations.AlterField(
model_name="requirementnode",
name="urn",
field=models.CharField(
blank=True, max_length=255, null=True, unique=True, verbose_name="URN"
),
),
migrations.AlterField(
model_name="riskmatrix",
name="urn",
field=models.CharField(
blank=True, max_length=255, null=True, unique=True, verbose_name="URN"
),
),
migrations.AlterField(
model_name="storedlibrary",
name="urn",
field=models.CharField(
blank=True, max_length=255, null=True, verbose_name="URN"
),
),
migrations.AlterField(
model_name="threat",
name="urn",
field=models.CharField(
blank=True, max_length=255, null=True, unique=True, verbose_name="URN"
),
),
]
56 changes: 28 additions & 28 deletions backend/core/models.py
Original file line number Diff line number Diff line change
@@ -1,34 +1,31 @@
import json
import os
import re
from datetime import date, datetime
from pathlib import Path
from typing import Self, Type, Union

import yaml
from django.apps import apps
from django.core.validators import MaxValueValidator
from django.forms.models import model_to_dict
from django.contrib.auth import get_user_model
from django.db import models, transaction
from django.utils.translation import gettext_lazy as _
from django.db.models import Q

from .base_models import AbstractBaseModel, NameDescriptionMixin, ETADueDateMixin
from .validators import validate_file_size, validate_file_name
from .utils import camel_case, sha256
from iam.models import FolderMixin, PublishInRootFolderMixin
from django.core import serializers
from django.utils.translation import get_language
from library.helpers import update_translations_in_object, update_translations

import os
import json
import yaml
import re

from django.core.exceptions import ValidationError

from django.core.validators import MaxValueValidator
from django.db import models, transaction
from django.db.models import Q
from django.forms.models import model_to_dict
from django.urls import reverse
from datetime import date, datetime
from typing import Union, Dict, Set, List, Tuple, Type, Self
from django.utils.html import format_html

from django.utils.translation import get_language
from django.utils.translation import gettext_lazy as _
from iam.models import FolderMixin, PublishInRootFolderMixin
from library.helpers import update_translations, update_translations_in_object
from structlog import get_logger

from .base_models import AbstractBaseModel, ETADueDateMixin, NameDescriptionMixin
from .utils import camel_case, sha256
from .validators import validate_file_name, validate_file_size

logger = get_logger(__name__)

User = get_user_model()
Expand All @@ -54,7 +51,7 @@ class ReferentialObjectMixin(AbstractBaseModel, FolderMixin):
"""

urn = models.CharField(
max_length=100, null=True, blank=True, unique=True, verbose_name=_("URN")
max_length=255, null=True, blank=True, unique=True, verbose_name=_("URN")
)
ref_id = models.CharField(
max_length=100, blank=True, null=True, verbose_name=_("Reference ID")
Expand Down Expand Up @@ -135,7 +132,7 @@ class Meta:
abstract = True
unique_together = [["urn", "locale", "version"]]

urn = models.CharField(max_length=100, null=True, blank=True, verbose_name=_("URN"))
urn = models.CharField(max_length=255, null=True, blank=True, verbose_name=_("URN"))
copyright = models.CharField(
max_length=4096, null=True, blank=True, verbose_name=_("Copyright")
)
Expand Down Expand Up @@ -220,7 +217,7 @@ def store_library_content(
outdated_library.delete()

objects_meta = {
key: (1 if key == "framework" or "requirement_mapping_set" else len(value))
key: (1 if key in ["framework", "requirement_mapping_set"] else len(value))
for key, value in library_data["objects"].items()
}

Expand Down Expand Up @@ -882,6 +879,9 @@ def process_node(self, node):
]
return node_dict

def __str__(self) -> str:
return f"{self.provider} - {self.name}"


class RequirementNode(ReferentialObjectMixin, I18nObjectMixin):
threats = models.ManyToManyField(
Expand All @@ -905,7 +905,7 @@ class RequirementNode(ReferentialObjectMixin, I18nObjectMixin):
related_name="requirement_nodes",
)
parent_urn = models.CharField(
max_length=100, null=True, blank=True, verbose_name=_("Parent URN")
max_length=255, null=True, blank=True, verbose_name=_("Parent URN")
)
order_id = models.IntegerField(null=True, verbose_name=_("Order ID"))
implementation_groups = models.JSONField(
Expand Down Expand Up @@ -2185,13 +2185,13 @@ def quality_check(self) -> dict:
requirement_assessments.append(ra_dict)
for requirement_assessment in requirement_assessments:
if (
requirement_assessment["status"] in ("compliant", "partially_compliant")
requirement_assessment["result"] in ("compliant", "partially_compliant")
and len(requirement_assessment["applied_controls"]) == 0
):
warnings_lst.append(
{
"msg": _(
"{}: Requirement assessment status is compliant or partially compliant with no applied control applied"
"{}: Requirement assessment result is compliant or partially compliant with no applied control applied"
).format(requirement_assessment["name"]),
"msgid": "requirementAssessmentNoAppliedControl",
"link": f"requirement-assessments/{requirement_assessment['id']}",
Expand Down
25 changes: 8 additions & 17 deletions backend/iam/adapter.py
Original file line number Diff line number Diff line change
@@ -1,32 +1,23 @@
from allauth.account.utils import perform_login
from allauth.socialaccount.helpers import ImmediateHttpResponse
from allauth.socialaccount.models import app_settings
from django.conf import settings
from urllib.parse import urlparse

from allauth.account.adapter import DefaultAccountAdapter
from allauth.socialaccount.adapter import (
DefaultSocialAccountAdapter,
MultipleObjectsReturned,
warnings,
)
from allauth.socialaccount.models import app_settings
from django.conf import settings
from django.contrib.auth import get_user_model
from django.db.models import Q
from allauth.socialaccount.adapter import DefaultSocialAccountAdapter
from allauth.core import context
from django.dispatch import receiver
from allauth.socialaccount.signals import pre_social_login
from django.contrib.auth import login, get_user_model
from django.utils.http import url_has_allowed_host_and_scheme
from rest_framework.response import Response
from rest_framework.status import HTTP_401_UNAUTHORIZED
from knox.views import LoginView
from django.utils.http import url_has_allowed_host_and_scheme
from urllib.parse import urlparse

User = get_user_model()


class MyAccountAdapter(DefaultAccountAdapter):
def is_open_for_signup(self, request):
return False

class AccountAdapter(DefaultAccountAdapter):
def is_safe_url(self, url):
allowed_hosts = {urlparse(settings.CISO_ASSISTANT_URL).hostname} | set(
settings.ALLOWED_HOSTS
Expand All @@ -38,7 +29,7 @@ def is_safe_url(self, url):
return url_has_allowed_host_and_scheme(url, allowed_hosts=allowed_hosts)


class MySocialAccountAdapter(DefaultSocialAccountAdapter):
class SocialAccountAdapter(DefaultSocialAccountAdapter):
def pre_social_login(self, request, sociallogin):
email_address = next(iter(sociallogin.account.extra_data.values()))[0]
try:
Expand Down
Loading

0 comments on commit 7ce6cbb

Please sign in to comment.