Skip to content

Conversation

@Qnadia
Copy link
Contributor

@Qnadia Qnadia commented Nov 3, 2025

Cette Pull Request ajoute la bibliothèque YAML loi-05-20-06082020.yml, correspondant à la Loi n° 05-20 relative à la cybersécurité au Maroc.

Contenu du fichier :

Articles 1 à 53 de la Loi 05-20, organisés par chapitres

Description textuelle fidèle au texte officiel marocain du 6 août 2020

Métadonnées (chapitre, article, description, références)

Objectif :
Intégrer la Loi 05-20 dans la base de connaissances CISO Assistant afin de permettre son alignement avec les normes ISO/IEC 27001 et la DNSSI 2023.

Contexte :
Ce référentiel constitue le socle juridique national marocain en matière de cybersécurité, et servira de base pour les mappings et analyses de conformité.

Summary by CodeRabbit

  • New Features

    • Added calendar functionality for event management.
    • Introduced comprehensive API test coverage across all endpoints.
  • Infrastructure

    • Added Docker containerization for backend and multi-platform builds.
    • Implemented GitHub Actions CI/CD pipelines for automated testing, linting, and migrations.
  • Documentation

    • Extensively updated README with improved setup guidance and feature documentation.
    • Enhanced contributing guidelines with clearer workflows.
    • Added licensing clarification (AGPL vs. commercial).
  • Configuration

    • Added pre-commit hooks for code quality.
    • Configured ESLint and formatting standards.

Mohamed-Hacene and others added 30 commits December 23, 2024 14:55
When writing a custom `get_object` method in a viewset, we must perform
call `self.check_object_permissions(request, obj)`. Otherwise,
`RBACPermissions.has_object_permission` will **not** be called.
New format is <branch>-<timestamp>-<artifact name>
eric-intuitem and others added 25 commits January 27, 2025 10:20
* starting point

* variant with filesystem - experimental

* First implementation

* checkpoint

* checkpoint

* checkpoint valkey

* sqlite backend for huey, compatible with pg for the rest of the app

* compose preperation

* Introduce MAIL_DEBUG env variable

* checkpoint

* logging and error management

* wip

* target value

* slow down the scheduler given the current use cases to save CPU

* fixup

* back to default worker class for now

* Use the global setting and default to false
…em#1430)

* small optimizations of library presentation headers

* Ajustement du code pour CI Semantics
* Check permissions for each model to import before attempting to create objects

* Wrap form return values with withFiles wrapper

* Localize domain import permission denied error

* Style domain import button

* Remove dead code

* Tidy import domain functions

* Use RoleAsignment.is_access_allowed rather than user.permissions

* Enforce RBAC on domain export

* chore: Remove duplicate import
intuitem#1431)

Add files via upload

Added so called elementary threats by german BSI in order to assign in risk-management
annotated base query for better perf
…ios (intuitem#1442)

* freat: current/residual criticality filters for risk scenarios

* fix: created correct filter

* fix: minor fix
…item#1445)

Expose extra variables for a more flexible infra tuning
* checkpoint

* error management

* Moving component

* counters asynchronously as well

* clean up and cleaner syntax
* Align EE settings

* Fix languages
* feat: check required libraries after domain creation

* feat: improve error handling

* chore: format
* Add a progress field on applied controls

* changed save model function & regionalize

* inverse colors and add a validator on the progress field model
* fix: diffentiate cell's tooltips using matrixName%

* fix: typo and code readability
* Increase limit_request_line param for gunicorn

Increase limit_request_line param for gunicorn, this allows some IDP (such as GoAuthentik) provider to work as the request line often goes beyond the default value of 4094.

* Update startup.sh

Forgot backslash...
…1451)

* put entityy mendatory with red star UI

* changed implementation
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 3, 2025

Caution

Review failed

Failed to post review comments

Walkthrough

This is a comprehensive multi-system update introducing extensive CI/CD automation via GitHub Actions workflows, a complete backend test suite with shared testing utilities, new calendar functionality, multiple Django model migrations, and substantial documentation overhauls including licensing restructuring and README reorganization.

Changes

Cohort / File(s) Summary
Project Configuration
.dockerignore, .gitignore, .eslintrc.js, .pre-commit-config.yaml, Caddyfile
Updated ignore patterns for Python/Node environments; added ESLint TypeScript linting rules; configured pre-commit hooks for ruff formatting and frontend linting; added reverse proxy configuration for development
GitHub Actions Workflows – Backend CI
.github/workflows/backend-api-tests.yml, backend-coverage.yaml, backend-linters.yaml, backend-migrations-check.yaml
Added parallel CI pipelines for API testing (pytest with HTML reports), code coverage analysis (with PostgreSQL service), linting (ruff format check), and Django migration validation
GitHub Actions Workflows – Frontend CI
.github/workflows/frontend-coverage.yaml, frontend-linters.yaml, frontend-unit-tests.yml
Added Node.js–based workflows for frontend coverage (pnpm), linting (Prettier, with ESLint/svelte-check commented), and unit testing via pnpm test:ci
GitHub Actions Workflows – Integration & Docker
.github/workflows/functional-tests.yml, startup-tests.yml, docker-build-and-push.yml, docker-build-and-push-dummy.yml, docker-build-and-push-ee.yml, cla.yml, version-change-check.yml
Added end-to-end Playwright-based functional tests, startup validation tests, multi-platform Docker image building/pushing for community and enterprise editions, CLA assistant automation, and version change checks
GitHub Actions Workflows – Removed
.github/workflows/unit-test-ciso-assistant.yml
Removed legacy unit test workflow (replaced by new modular backend CI workflows)
GitHub Actions Issue Template
.github/ISSUE_TEMPLATE/feature_request.md
Added standardized feature request template with YAML metadata and structured form sections
Docker & Build Configuration
backend/.dockerignore, backend/Dockerfile
Added backend-specific Docker exclusions and new Dockerfile for Python 3.12 with Poetry-based dependency management and startup script
Root Dockerfile Removal
Dockerfile
Removed root-level Dockerfile (refactored into backend-specific Dockerfile)
Backend Application Settings
backend/ciso_assistant/settings.py, backend/ciso_assistant/urls.py, backend/ciso_assistant/wsgi.py, backend/ciso_assistant/asgi.py
Added comprehensive Django settings with environment-driven configuration for databases, logging (structlog), REST framework, authentication, email, and integrations; configured URL routing and WSGI/ASGI interfaces
Backend Build Metadata
backend/ciso_assistant/VERSION, backend/ciso_assistant/build.json, backend/ciso_assistant/scripts/generate_build_file.sh
Added version tracking, build metadata generation, and shell script for build context creation
Backend Core Configuration
backend/core/__init__.py, backend/core/apps.py, backend/core/admin_config.py, backend/core/filters.py
Added app configuration with startup hooks, admin UI metadata, and DjangoFilter configurations; renamed model filter classes (SecurityMeasure→AppliedControl, SecurityFunction→ReferenceControl, Assessment→ComplianceAssessment)
Backend Core Models & Utilities
backend/core/base_models.py, backend/core/helpers.py, backend/core/generators.py
Added abstract base models with lifecycle hooks and UUID PKs; introduced 40+ analytics/reporting helpers for compliance, risk, and audit metrics; added matplotlib-based chart generation utilities
Calendar App
backend/cal/, backend/cal/models.py, backend/cal/utils.py, backend/cal/apps.py, backend/cal/migrations/0001_initial.py, backend/cal/tests/test_models.py, backend/cal/tests/test_utils.py
Added new Event model and Calendar utility for rendering monthly HTML calendars with embedded compliance/risk events
Backend Management Commands
backend/core/management/commands/reset_mail.py, welcome_mail.py, status.py
Added commands for password reset emails, welcome emails, and system status reporting
Backend Migrations (0001–0028)
backend/core/migrations/
Comprehensive schema evolution: initial models, FK/M2M relationships, library/storage model restructuring (Library→LoadedLibrary + StoredLibrary), model renames (SecurityFunction→ReferenceControl, SecurityMeasure→AppliedControl), field additions (csf_function, cost, owner, qualifications, translations), and data migrations for URN fixes and library metadata
Backend Test Infrastructure
backend/app_tests/conftest.py, backend/app_tests/test_vars.py, backend/app_tests/test_utils.py, backend/app_tests/test_file.txt
Added pytest fixtures for authenticated/unauthenticated clients with role/folder context; centralized test constants (endpoints, URNs, user permissions); introduced EndpointTestsUtils and EndpointTestsQueries helper classes for API endpoint testing
Backend API Tests
backend/app_tests/api/test_api_*.py (16 test modules)
Added comprehensive API test suites for all major endpoints: AppliedControls, Assets, ComplianceAssessments, Evidences, Folders, Libraries, Policies, Projects, ReferenceControls, RequirementAssessments, RequirementNodes, RiskAcceptances, RiskAssessments, RiskScenarios, Threats, UserGroups, Users
Documentation & Licensing
README.md, CODE_OF_CONDUCT.md, CONTRIBUTING.md, LICENSE, LICENSE-AGPL.txt, LICENSE.md, SECURITY.md
Overhauled README with centered HTML layout, GRC framing, Docker/cloud deployment emphasis, and updated development workflow; added Discord to Code of Conduct; restructured contributing guide; replaced single LICENSE with dual AGPL/Commercial licensing structure with LICENSE.md clarification

Sequence Diagram(s)

sequenceDiagram
    participant GHA as GitHub Actions
    participant Checkout
    participant Python/Poetry
    participant Pytest
    participant Coverage
    participant Artifact

    GHA->>Checkout: PR triggered (backend/**)
    Checkout->>Python/Poetry: Setup Python 3.12 + Poetry
    Python/Poetry->>Pytest: Install deps, migrations, pytest
    Pytest->>Coverage: Run tests with coverage
    Coverage->>Artifact: Generate HTML report
    Artifact-->>GHA: Upload pytest-report artifact
Loading
sequenceDiagram
    participant Test as API Test
    participant Utils as EndpointTestsUtils
    participant DRF as DRF APIClient
    participant Model as Django ORM
    participant Assert as Assertion

    Test->>Utils: EndpointTestsQueries.get_object()
    Utils->>DRF: GET /api/endpoint/
    DRF->>Model: Fetch from DB
    Model-->>DRF: Return queryset
    DRF-->>Utils: JSON response + status
    Utils->>Assert: Validate response schema
    Assert-->>Test: Pass/Fail + details
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

  • Specific areas requiring extra attention:
    • All 28 Django migrations (0001–0028) — verify schema evolution logic, data migrations (fix_urns_for_enisa_5g_scm, fix_libraries_objects_meta, set_assessment_folder), and uniqueness constraints
    • New test infrastructure (conftest.py, test_utils.py) — validate fixture parametrization, EndpointTestsQueries/EndpointTestsUtils helper logic, and database transaction handling across 16+ API test modules
    • GitHub Actions workflows — ensure correct Python/Node version pinning, database service setup, artifact retention, and concurrency/matrix configurations across 12+ workflow files
    • Backend settings.py — validate environment variable handling, logging configuration, database selection logic, and third-party integrations (Knox, allauth, Huey, structlog)
    • Model naming/renaming consistency (SecurityMeasure→AppliedControl, SecurityFunction→ReferenceControl, Assessment→ComplianceAssessment) across helpers, filters, migrations, and tests
    • Licensing structure changes — verify LICENSE.md dual licensing clarity and LICENSE/LICENSE-AGPL.txt correctness
    • Calendar app integration — ensure Event model relationships and HTML rendering logic align with backend compliance/risk event tracking

Possibly related PRs

Suggested labels

documentation, backend, testing, ci-cd, docker, migrations, licensing

Suggested reviewers

  • nas-tabchiche
  • eric-intuitem

🐰 Behold! A massive refactor, so grand and so wide,
With tests and migrations running side by side,
New workflows dance in the Actions so bright,
While models are renamed to get things just right!
From AGPL to commercial, the license now split,
This PR's got enough changes to make any dev sit! 🚀✨

Pre-merge checks and finishing touches

✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title 'Ajout du référentiel Loi 05-20 (Maroc)' clearly describes the main change: adding a new reference framework (Moroccan Law 05-20) to the system. The title is concise, specific, and in French matching the project context. It accurately summarizes the primary intent of the changeset without being vague or misleading.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 49

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.github/workflows/version-change-check.yml (1)

19-27: CRITICAL: Path mismatch in VERSION file check will cause workflow to fail.

Line 21 references ciso_assistant/VERSION but the actual file location is backend/ciso_assistant/VERSION. The git diff check will not find the file at the incorrect path, causing the workflow to always fail with the error "VERSION file must be modified in this pull request," even when the file is properly updated.

Apply this diff to fix the path:

-          version_file="ciso_assistant/VERSION"
+          version_file="backend/ciso_assistant/VERSION"
🧹 Nitpick comments (28)
Caddyfile (1)

1-10: Consider operational hardening for production use.

The configuration is functional for development/internal environments (indicated by .lan domain and comment on Line 1), but consider these improvements if deploying to production or shared environments:

  1. Health checks: Add health_uri and health_interval to detect backend failures
  2. Timeouts: Configure dial_timeout, read_timeout, and write_timeout to prevent hung connections
  3. Security headers: Add common security headers (HSTS, X-Frame-Options, CSP)
  4. Observability: Enable access logging for troubleshooting

Example enhanced configuration:

 u24.proxmox.lan:8443 {
-    reverse_proxy frontend:3000
+    reverse_proxy frontend:3000 {
+        health_uri /health
+        health_interval 10s
+        transport http {
+            dial_timeout 5s
+            response_header_timeout 30s
+        }
+    }
+    header {
+        Strict-Transport-Security "max-age=31536000; includeSubDomains"
+        X-Frame-Options "SAMEORIGIN"
+        X-Content-Type-Options "nosniff"
+    }
+    log {
+        output file /var/log/caddy/frontend-access.log
+    }
     tls internal
 }
backend/core/filters.py (1)

15-18: Redundant imports from core.models.

Line 15 uses a wildcard import (from core.models import *), and line 18 explicitly imports specific models from the same module. This creates redundancy and can lead to confusion about which models are available.

Consider removing the wildcard import and using only explicit imports for better clarity and to avoid namespace pollution:

-from core.models import *
 from core.forms import SearchableSelect, SearchableCheckboxSelectMultiple
 from iam.models import User, UserGroup, RoleAssignment, Folder
-from core.models import Project, Threat, ReferenceControl, AppliedControl
+from core.models import (
+    Project,
+    Threat,
+    ReferenceControl,
+    AppliedControl,
+    Framework,
+    ComplianceAssessment,
+    RequirementAssessment,
+    RequirementNode,
+    Evidence,
+)
backend/core/admin_config.py (1)

11-13: Consider adding type hints and simplifying.

The function could be more concise and benefit from type hints for better IDE support and maintainability.

Apply this diff to add type hints and simplify:

-def get_config(key):
-    value = config.get(key, None)
-    return value
+def get_config(key: str) -> str | None:
+    """Get a configuration value by key.
+    
+    Args:
+        key: Configuration key to retrieve
+        
+    Returns:
+        Configuration value or None if key doesn't exist
+    """
+    return config.get(key)
backend/core/management/commands/reset_mail.py (2)

13-13: Use self.stdout.write() instead of print().

For consistency with Django management command conventions and to ensure output respects verbosity levels, use self.stdout.write() instead of print().


20-21: Log the exception for debugging.

The exception is caught but the exception variable e is unused. Include exception details in the error message to aid troubleshooting.

Apply this diff:

-        except Exception as e:
-            self.stdout.write("cannot send reset mail")
+        except Exception as e:
+            self.stdout.write(self.style.ERROR(f"Cannot send reset mail: {e}"))
backend/core/management/commands/welcome_mail.py (3)

12-12: Use self.stdout.write() instead of print().

For consistency with Django management command conventions and to ensure output respects verbosity levels, use self.stdout.write() instead of print().


16-16: Make the subject translatable for internationalization.

Unlike the reset_mail command which uses gettext_lazy for translation, this command has a hardcoded English subject. For consistency and i18n support, the subject should be wrapped in translation.

Apply this diff:

+from django.utils.translation import gettext_lazy as _
+
 from django.core.management.base import BaseCommand
-from core.models import *
 from iam.models import User
-from ciso_assistant.settings import CISO_ASSISTANT_SUPERUSER_EMAIL

Then update the subject:

             admin.mailing(
                 email_template_name="registration/first_connexion_email.html",
-                subject="Welcome to CISO Assistant!",
+                subject=_("Welcome to CISO Assistant!"),
             )

19-20: Log the exception for debugging.

The exception is caught but the exception variable e is unused. Include exception details in the error message to aid troubleshooting.

Apply this diff:

-        except Exception as e:
-            self.stdout.write("cannot send welcome mail")
+        except Exception as e:
+            self.stdout.write(self.style.ERROR(f"Cannot send welcome mail: {e}"))
backend/core/management/commands/status.py (1)

30-37: Consider simplifying the last_login logic.

The list comprehension and max() call works correctly with the default=None, but could be more readable using a queryset method.

Apply this diff for a more concise approach:

-        last_login = max(
-            [
-                x["last_login"]
-                for x in User.objects.all().values("last_login")
-                if x["last_login"]
-            ],
-            default=None,
-        )
+        last_login = User.objects.exclude(last_login__isnull=True).aggregate(
+            models.Max('last_login')
+        )['last_login__max']

Add the import at the top:

 from django.core.management.base import BaseCommand
+from django.db import models
backend/cal/models.py (1)

5-9: Consider adding __str__ method and Meta class.

The Event model lacks a __str__ method for better representation in admin and debugging, and a Meta class for ordering and verbose names.

Apply this diff:

 class Event(models.Model):
     name = models.CharField(max_length=200)
     description = models.TextField()
     start_time = models.DateTimeField()
     end_time = models.DateTimeField()
+    
+    def __str__(self):
+        return self.name
+    
+    class Meta:
+        ordering = ['start_time']
+        verbose_name = "Event"
+        verbose_name_plural = "Events"
backend/cal/utils.py (1)

34-51: Consider adding input validation for year and month.

The formatmonth method uses self.year and self.month without validating they were set during initialization. If Calendar is instantiated with None values, this could cause runtime errors.

Apply this diff:

     def formatmonth(self, withyear=True):
+        if self.year is None or self.month is None:
+            raise ValueError("Calendar year and month must be set")
+        
         events = {
             "mtg": AppliedControl.objects.filter(
                 eta__year=self.year, eta__month=self.month
             ),
.github/workflows/version-change-check.yml (1)

8-13: Environment variable UBUNTU_VERSION is declared but unused.

Line 9 defines UBUNTU_VERSION: "ubuntu-24.04" but it is not referenced elsewhere in the workflow. While pinning to a specific Ubuntu version on line 13 is a best practice (avoiding drift from ubuntu-latest), the environment variable appears to be dead code unless it's intended for use in other jobs or future expansion. Consider removing it or documenting its purpose.

If the variable is not needed, remove it:

-env:
-  UBUNTU_VERSION: "ubuntu-24.04"
-
 jobs:
.github/workflows/backend-linters.yaml (1)

38-41: Tech debt: Full ruff check is disabled.

The commented-out ruff check indicates pending codebase cleanup work. This is acceptable for initial setup, but ensure there's a tracking issue to enable this check.

Would you like me to create a tracking issue for enabling the full ruff check once the codebase is cleaned up?

.github/workflows/frontend-linters.yaml (2)

18-18: Verify PUBLIC_BACKEND_API_URL is necessary.

The backend API URL is typically not needed for linting operations (Prettier, ESLint, svelte-check). Consider removing this unless it's required for specific linting rules.


43-52: Tech debt: ESLint and svelte-check disabled.

The commented-out ESLint and svelte-check steps indicate pending codebase cleanup. Ensure there's a tracking issue to enable these checks.

Would you like me to create a tracking issue for enabling ESLint and svelte-check once the frontend codebase is cleaned up?

.eslintrc.js (1)

1-16: Rename to .eslintrc.json for proper JSON format.

The file contains JSON but uses a .js extension. ESLint supports both, but .eslintrc.json is more accurate since this is pure JSON without JavaScript logic. This would also resolve the Biome parsing errors.

--- a/.eslintrc.js
+++ b/.eslintrc.json

The configuration itself is solid: it properly enforces unused variable detection while allowing underscore-prefixed identifiers for intentionally unused parameters.

.github/workflows/frontend-coverage.yaml (1)

26-31: Upgrade to checkout v4 for 24.04 runners

actions/checkout@v3 no longer supports ubuntu-24.04 runners; switching to v4 avoids fails flagged by actionlint. citeturn0static_analysis_hints0

Apply this diff:

-      - uses: actions/checkout@v3
+      - uses: actions/checkout@v4
.github/workflows/backend-coverage.yaml (1)

37-38: Upgrade to checkout v4

actions/checkout@v3 is deprecated for ubuntu-24.04 runners; bumping to v4 resolves the actionlint warning and keeps the workflow runnable. citeturn1static_analysis_hints0

Apply this diff:

-      - uses: actions/checkout@v3
+      - uses: actions/checkout@v4
CONTRIBUTING.md (1)

6-25: Use the correct GitHub capitalization

Brand names should be spelled “GitHub”; please update the two occurrences in this section. citeturn3static_analysis_hints0

Apply this diff:

-- Check that the bug was not previously reported on Github issues (see above).
+- Check that the bug was not previously reported on GitHub issues (see above).
@@
-- Have a look to the tools directory and its readme. A python script will help you create your library very simply from an Excel file. To share it with the community, make a PR, or contact us if you are not familiar with Github.
+- Have a look to the tools directory and its readme. A python script will help you create your library very simply from an Excel file. To share it with the community, make a PR, or contact us if you are not familiar with GitHub.
backend/core/migrations/0026_appliedcontrol_cost.py (1)

15-19: Consider DecimalField instead of FloatField for currency values.

Using FloatField for currency can lead to floating-point precision issues (e.g., 0.1 + 0.2 != 0.3). For financial data, DecimalField with explicit max_digits and decimal_places is the recommended approach to avoid rounding errors and ensure accurate calculations.

Apply this diff if you decide to use DecimalField:

             field=models.FloatField(
+            field=models.DecimalField(
+                max_digits=15,
+                decimal_places=2,
                 help_text="Cost of the measure (using globally-chosen currency)",
                 null=True,
                 verbose_name="Cost",
.github/workflows/docker-build-and-push-ee.yml (1)

38-48: Quote shell variables to prevent globbing and word splitting.

The static analysis tool flagged unquoted variables in the shell script. While these particular variables (git describe and git rev-parse output) are unlikely to contain spaces or special characters, it's a best practice to quote them.

Apply this diff to quote the variables:

       - name: Get version and Create .meta file
         run: |
-          echo "VERSION=$(git describe --tags --always)" >> $GITHUB_ENV
-          echo "BUILD=$(git rev-parse --short HEAD)" >> $GITHUB_ENV
+          echo "VERSION=$(git describe --tags --always)" >> "$GITHUB_ENV"
+          echo "BUILD=$(git rev-parse --short HEAD)" >> "$GITHUB_ENV"
 
           echo "CISO_ASSISTANT_VERSION=$(git describe --tags --always)" > .meta
           echo "CISO_ASSISTANT_BUILD=$(git rev-parse --short HEAD)" >> .meta
.github/workflows/docker-build-and-push-dummy.yml (2)

1-1: Workflow name suggests pushing but images are only loaded locally.

The workflow is named "Build and Push Docker Images Dummy" but all build steps use load: true instead of push: true, meaning images are loaded into the local Docker daemon but not pushed to a registry. Consider renaming to "Build Docker Images (Test)" or similar to clarify intent.


29-36: Quote shell variables to prevent globbing and word splitting.

Same quoting issue as in the EE workflow. While unlikely to cause problems with git command output, quoting is a best practice.

Apply this diff:

       - name: Get version and Create .meta file
         run: |
-          echo "VERSION=$(git describe --tags --always)" >> $GITHUB_ENV
-          echo "BUILD=$(git rev-parse --short HEAD)" >> $GITHUB_ENV
+          echo "VERSION=$(git describe --tags --always)" >> "$GITHUB_ENV"
+          echo "BUILD=$(git rev-parse --short HEAD)" >> "$GITHUB_ENV"
           echo "CISO_ASSISTANT_VERSION=$(git describe --tags --always)" > .meta
           echo "CISO_ASSISTANT_BUILD=$(git rev-parse --short HEAD)" >> .meta
backend/app_tests/api/test_api_requirement_assessments.py (1)

1-307: LGTM with optional refactor suggestion.

The test suite provides comprehensive coverage of the RequirementAssessments API, including unauthenticated/authenticated flows, permission checks, and complex nested object serialization.

Consider extracting the repeated parent_requirement access pattern to reduce redundancy:

In lines 143-166 and 269-292, the same RequirementNode.objects.all()[0].parent_requirement is accessed multiple times. You could refactor as:

parent_req = RequirementNode.objects.all()[0].parent_requirement
"parent_requirement": {
    "str": parent_req.get("str"),
    "urn": parent_req.get("urn"),
    "id": str(parent_req.get("id")),
    "ref_id": parent_req.get("ref_id"),
    "name": parent_req.get("name"),
    "description": parent_req.get("description"),
}
if parent_req
else None,

This would improve readability and potentially reduce redundant evaluations of the property.

.github/workflows/backend-api-tests.yml (1)

43-56: Consider grouping echo redirects for efficiency.

While the current approach works, grouping the echo statements can be more efficient and cleaner.

You could refactor as:

       - name: Create environment variables file
         working-directory: ${{env.backend-directory}}
         run: |
-          touch .env
-          echo DJANGO_DEBUG='True' >> .env
-          echo DB_HOST=localhost >> .env
-          echo EMAIL_HOST=localhost >> .env
-          echo EMAIL_PORT=1025 >> .env
-          echo EMAIL_HOST_USER='' >> .env
-          echo EMAIL_HOST_PASSWORD='' >> .env
-          #echo EMAIL_USE_TLS=False >> .env
-          echo DEFAULT_FROM_EMAIL='[email protected]' >> .env
-          echo CISO_ASSISTANT_SUPERUSER_EMAIL='' >> .env
-          echo CISO_ASSISTANT_URL=http://127.0.0.1:5173 >> .env
+          cat > .env << 'EOF'
+          DJANGO_DEBUG='True'
+          DB_HOST=localhost
+          EMAIL_HOST=localhost
+          EMAIL_PORT=1025
+          EMAIL_HOST_USER=''
+          EMAIL_HOST_PASSWORD=''
+          DEFAULT_FROM_EMAIL='[email protected]'
+          CISO_ASSISTANT_SUPERUSER_EMAIL=''
+          CISO_ASSISTANT_URL=http://127.0.0.1:5173
+          EOF
backend/app_tests/api/test_api_risk_acceptances.py (1)

18-22: Update hardcoded dates to avoid potential validation issues.

The hardcoded dates (2024-01-01, 2024-01-02) are already in the past relative to the PR date (November 2025). If the RiskAcceptance model has validation logic for expiry or acceptance dates, these past dates could cause test failures.

Consider using dynamic dates relative to the current date:

-RISK_ACCEPTANCE_EXPIRY_DATE = "2024-01-01"
-RISK_ACCEPTANCE_ACCEPTED_DATE = "2024-01-02"
-RISK_ACCEPTANCE_REJECTED_DATE = "2024-01-02"
-RISK_ACCEPTANCE_REVOKED_DATE = "2024-01-02"
+from datetime import datetime, timedelta
+
+RISK_ACCEPTANCE_EXPIRY_DATE = (datetime.now() + timedelta(days=30)).strftime("%Y-%m-%d")
+RISK_ACCEPTANCE_ACCEPTED_DATE = (datetime.now() + timedelta(days=1)).strftime("%Y-%m-%d")
+RISK_ACCEPTANCE_REJECTED_DATE = (datetime.now() + timedelta(days=1)).strftime("%Y-%m-%d")
+RISK_ACCEPTANCE_REVOKED_DATE = (datetime.now() + timedelta(days=1)).strftime("%Y-%m-%d")
backend/app_tests/api/test_api_compliance_assessments.py (1)

21-37: Design inconsistency: authenticated_client in unauthenticated test.

The test_get_compliance_assessments method in the TestComplianceAssessmentsUnauthenticated class receives an authenticated_client fixture to import a Framework. This creates unnecessary coupling and makes the test setup confusing.

Consider one of these approaches:

  1. Move the Framework import to a shared fixture or setup method that runs once for all tests
  2. Use database fixtures/factories to pre-populate required data
  3. If Framework import requires authentication, add a comment explaining this design decision

This same pattern appears in test_update_compliance_assessments (line 55) and test_delete_compliance_assessments (line 80).

backend/core/migrations/0017_requirementassessment_mapping_inference_and_more.py (1)

84-118: Clarify reverse accessor names for framework relations.

Both target_framework and source_framework FKs expose reverse managers on core.Framework with the same singular names as the local fields. That makes the reverse side ambiguous to read and raises the risk of colliding with any actual attribute or method named the same on Framework. Everywhere else in this app the reverse names are plural and model-specific (e.g., frameworks, risk_matrices). Renaming these accessors now will keep the ORM API consistent.

-                        related_name="target_framework",
+                        related_name="target_requirement_mapping_sets",
-                        related_name="source_framework",
+                        related_name="source_requirement_mapping_sets",
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1993bfa and 1db9a4a.

⛔ Files ignored due to path filters (5)
  • backend/app_tests/sample_640x480.jpg is excluded by !**/*.jpg
  • backend/app_tests/test_image.jpg is excluded by !**/*.jpg
  • backend/core/templates/core/audit_report_template.docx is excluded by !**/*.docx
  • backend/core/templates/core/audit_report_template_en.docx is excluded by !**/*.docx
  • backend/core/templates/core/audit_report_template_fr.docx is excluded by !**/*.docx
📒 Files selected for processing (107)
  • .dockerignore (1 hunks)
  • .eslintrc.js (1 hunks)
  • .github/ISSUE_TEMPLATE/feature_request.md (1 hunks)
  • .github/workflows/backend-api-tests.yml (1 hunks)
  • .github/workflows/backend-coverage.yaml (1 hunks)
  • .github/workflows/backend-linters.yaml (1 hunks)
  • .github/workflows/backend-migrations-check.yaml (1 hunks)
  • .github/workflows/cla.yml (1 hunks)
  • .github/workflows/docker-build-and-push-dummy.yml (1 hunks)
  • .github/workflows/docker-build-and-push-ee.yml (1 hunks)
  • .github/workflows/docker-build-and-push.yml (1 hunks)
  • .github/workflows/frontend-coverage.yaml (1 hunks)
  • .github/workflows/frontend-linters.yaml (1 hunks)
  • .github/workflows/frontend-unit-tests.yml (1 hunks)
  • .github/workflows/functional-tests.yml (1 hunks)
  • .github/workflows/startup-tests.yml (1 hunks)
  • .github/workflows/unit-test-ciso-assistant.yml (0 hunks)
  • .github/workflows/version-change-check.yml (1 hunks)
  • .gitignore (1 hunks)
  • .pre-commit-config.yaml (1 hunks)
  • CODE_OF_CONDUCT.md (1 hunks)
  • CONTRIBUTING.md (1 hunks)
  • Caddyfile (1 hunks)
  • Dockerfile (0 hunks)
  • LICENSE (0 hunks)
  • LICENSE-AGPL.txt (1 hunks)
  • LICENSE.md (1 hunks)
  • README.md (3 hunks)
  • SECURITY.md (1 hunks)
  • backend/.dockerignore (1 hunks)
  • backend/.gitignore (1 hunks)
  • backend/Dockerfile (1 hunks)
  • backend/app_tests/api/test_api_applied_controls.py (1 hunks)
  • backend/app_tests/api/test_api_assets.py (1 hunks)
  • backend/app_tests/api/test_api_compliance_assessments.py (1 hunks)
  • backend/app_tests/api/test_api_evidences.py (1 hunks)
  • backend/app_tests/api/test_api_folders.py (1 hunks)
  • backend/app_tests/api/test_api_libraries.py (1 hunks)
  • backend/app_tests/api/test_api_policies.py (1 hunks)
  • backend/app_tests/api/test_api_projects.py (1 hunks)
  • backend/app_tests/api/test_api_reference_controls.py (1 hunks)
  • backend/app_tests/api/test_api_requirement_assessments.py (1 hunks)
  • backend/app_tests/api/test_api_requirement_nodes.py (1 hunks)
  • backend/app_tests/api/test_api_risk_acceptances.py (1 hunks)
  • backend/app_tests/api/test_api_risk_assessments.py (1 hunks)
  • backend/app_tests/api/test_api_risk_scenarios.py (1 hunks)
  • backend/app_tests/api/test_api_threats.py (1 hunks)
  • backend/app_tests/api/test_api_user_groups.py (1 hunks)
  • backend/app_tests/api/test_api_users.py (1 hunks)
  • backend/app_tests/api/test_utils.py (1 hunks)
  • backend/app_tests/conftest.py (1 hunks)
  • backend/app_tests/test_file.txt (1 hunks)
  • backend/app_tests/test_vars.py (1 hunks)
  • backend/cal/admin.py (1 hunks)
  • backend/cal/apps.py (1 hunks)
  • backend/cal/migrations/0001_initial.py (1 hunks)
  • backend/cal/models.py (1 hunks)
  • backend/cal/tests/test_models.py (1 hunks)
  • backend/cal/tests/test_utils.py (1 hunks)
  • backend/cal/utils.py (1 hunks)
  • backend/ciso_assistant/VERSION (1 hunks)
  • backend/ciso_assistant/asgi.py (1 hunks)
  • backend/ciso_assistant/build.json (1 hunks)
  • backend/ciso_assistant/scripts/generate_build_file.sh (1 hunks)
  • backend/ciso_assistant/settings.py (1 hunks)
  • backend/ciso_assistant/urls.py (1 hunks)
  • backend/ciso_assistant/wsgi.py (1 hunks)
  • backend/core/__init__.py (1 hunks)
  • backend/core/admin_config.py (1 hunks)
  • backend/core/apps.py (1 hunks)
  • backend/core/base_models.py (1 hunks)
  • backend/core/filters.py (7 hunks)
  • backend/core/generators.py (1 hunks)
  • backend/core/helpers.py (1 hunks)
  • backend/core/locale/fr/LC_MESSAGES/django.po (1 hunks)
  • backend/core/management/commands/reset_mail.py (1 hunks)
  • backend/core/management/commands/status.py (1 hunks)
  • backend/core/management/commands/welcome_mail.py (1 hunks)
  • backend/core/migrations/0001_initial.py (1 hunks)
  • backend/core/migrations/0002_initial.py (1 hunks)
  • backend/core/migrations/0003_alter_riskscenario_strength_of_knowledge.py (1 hunks)
  • backend/core/migrations/0004_complianceassessment_is_published_and_more.py (1 hunks)
  • backend/core/migrations/0005_alter_project_lc_status_alter_securitymeasure_effort.py (1 hunks)
  • backend/core/migrations/0006_remove_securitymeasure_security_function_and_more.py (1 hunks)
  • backend/core/migrations/0007_alter_requirementlevel_framework_and_more.py (1 hunks)
  • backend/core/migrations/0008_alter_complianceassessment_status_and_more.py (1 hunks)
  • backend/core/migrations/0009_framework_max_score_framework_min_score_and_more.py (1 hunks)
  • backend/core/migrations/0010_rename_score_definition_framework_scores_definition_and_more.py (1 hunks)
  • backend/core/migrations/0011_auto_20240501_1342.py (1 hunks)
  • backend/core/migrations/0012_alter_appliedcontrol_updated_at_and_more.py (1 hunks)
  • backend/core/migrations/0013_requirementnode_typical_evidence.py (1 hunks)
  • backend/core/migrations/0014_auto_20240522_1731.py (1 hunks)
  • backend/core/migrations/0015_remove_complianceassessment_result_and_more.py (1 hunks)
  • backend/core/migrations/0016_riskscenario_owner.py (1 hunks)
  • backend/core/migrations/0017_requirementassessment_mapping_inference_and_more.py (1 hunks)
  • backend/core/migrations/0018_appliedcontrol_csf_function_and_more.py (1 hunks)
  • backend/core/migrations/0018_framework_translations_loadedlibrary_translations_and_more.py (1 hunks)
  • backend/core/migrations/0019_merge_20240726_2156.py (1 hunks)
  • backend/core/migrations/0020_fix_libraries_objects_meta.py (1 hunks)
  • backend/core/migrations/0021_alter_framework_urn_alter_loadedlibrary_urn_and_more.py (1 hunks)
  • backend/core/migrations/0022_riskscenario_qualifications.py (1 hunks)
  • backend/core/migrations/0023_alter_appliedcontrol_status.py (1 hunks)
  • backend/core/migrations/0024_appliedcontrol_owner.py (1 hunks)
  • backend/core/migrations/0025_complianceassessment_folder_riskassessment_folder_and_more.py (1 hunks)
  • backend/core/migrations/0026_appliedcontrol_cost.py (1 hunks)
  • backend/core/migrations/0027_requirementassessment_answer_and_more.py (1 hunks)
  • backend/core/migrations/0028_complianceassessment_observation_and_more.py (1 hunks)
⛔ Files not processed due to max files limit (22)
  • backend/core/migrations/0029_alter_appliedcontrol_link_alter_evidence_link.py
  • backend/core/migrations/0030_appliedcontrol_start_date.py
  • backend/core/migrations/0031_vulnerability_riskscenario_vulnerabilities.py
  • backend/core/migrations/0032_vulnerability_applied_controls_filteringlabel_and_more.py
  • backend/core/migrations/0033_fix_mitre_lib_version.py
  • backend/core/migrations/0034_fix_loaded_libraries_objects_meta.py
  • backend/core/migrations/0035_riskscenario_existing_applied_controls.py
  • backend/core/migrations/0036_asset_owner.py
  • backend/core/migrations/0037_appliedcontrol_priority.py
  • backend/core/migrations/0038_asset_disaster_recovery_objectives_and_more.py
  • backend/core/migrations/0039_make_urn_lowercase.py
  • backend/core/migrations/0040_riskscenario_ref_id.py
  • backend/core/migrations/0041_add_ref_id_to_project_appliedcontrol_assessment.py
  • backend/core/migrations/0042_asset_filtering_labels.py
  • backend/core/migrations/0043_historicalmetric.py
  • backend/core/migrations/0044_qualification.py
  • backend/core/migrations/0045_alter_appliedcontrol_category_and_more.py
  • backend/core/migrations/0046_riskassessment_ebios_rm_study.py
  • backend/core/migrations/0047_loadedlibrary_publication_date_and_more.py
  • backend/core/migrations/0048_alter_asset_security_objectives.py
  • backend/core/migrations/0049_complianceassessment_show_documentation_score_and_more.py
  • backend/core/migrations/0050_appliedcontrol_progress_field.py
💤 Files with no reviewable changes (3)
  • Dockerfile
  • LICENSE
  • .github/workflows/unit-test-ciso-assistant.yml
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-09-19T08:44:33.744Z
Learnt from: Mohamed-Hacene
Repo: intuitem/ciso-assistant-community PR: 2550
File: backend/core/views.py:3753-3762
Timestamp: 2025-09-19T08:44:33.744Z
Learning: In the domain export/import functionality in backend/core/views.py, Evidence.owner M2M relationships are intentionally not set during import because User objects are not exported. The owner_ids are collected in _process_model_relationships only to prevent M2M field validation errors during import, but they are deliberately not applied in _set_many_to_many_relations since users are environment-specific.

Applied to files:

  • backend/core/migrations/0024_appliedcontrol_owner.py
  • backend/core/migrations/0016_riskscenario_owner.py
📚 Learning: 2025-08-25T08:51:15.404Z
Learnt from: Mohamed-Hacene
Repo: intuitem/ciso-assistant-community PR: 2422
File: backend/core/serializers.py:1018-1030
Timestamp: 2025-08-25T08:51:15.404Z
Learning: The CISO Assistant project uses a custom permission system where RoleAssignment.get_accessible_object_ids() provides special handling for Permission objects by filtering them by content_type app_label rather than folder hierarchy, since Permission objects don't belong to folders. This allows safe CRUD operations on permissions while preventing privilege escalation by restricting access to only application-specific permissions from allowed apps: "core", "ebios_rm", "tprm", "privacy", "resilience", and "cal".

Applied to files:

  • backend/core/filters.py
🧬 Code graph analysis (15)
backend/app_tests/api/test_api_assets.py (3)
backend/core/models.py (2)
  • Asset (1397-1683)
  • Type (1400-1410)
backend/iam/models.py (1)
  • Folder (55-177)
backend/app_tests/api/test_utils.py (3)
  • EndpointTestsQueries (117-1070)
  • Auth (340-1070)
  • get_object_options (501-558)
backend/core/migrations/0001_initial.py (1)
backend/core/validators.py (2)
  • validate_file_size (23-34)
  • validate_file_name (37-65)
backend/app_tests/api/test_api_libraries.py (3)
backend/core/models.py (2)
  • Framework (950-1025)
  • StoredLibrary (243-356)
backend/iam/models.py (2)
  • Folder (55-177)
  • get_root_folder (62-64)
backend/app_tests/api/test_utils.py (9)
  • EndpointTestsQueries (117-1070)
  • EndpointTestsUtils (15-114)
  • get_object (120-178)
  • get_object (343-499)
  • import_object (319-338)
  • import_object (959-1009)
  • Auth (340-1070)
  • get_stored_library_content (38-40)
  • expected_request_response (83-114)
backend/app_tests/api/test_api_users.py (1)
backend/app_tests/api/test_utils.py (10)
  • EndpointTestsQueries (117-1070)
  • get_object (120-178)
  • get_object (343-499)
  • create_object (180-209)
  • create_object (560-694)
  • update_object (211-266)
  • update_object (696-844)
  • delete_object (268-317)
  • delete_object (846-957)
  • Auth (340-1070)
backend/core/management/commands/status.py (2)
backend/iam/models.py (2)
  • get_editors (539-544)
  • get_root_folder (62-64)
backend/core/models.py (3)
  • LoadedLibrary (665-751)
  • ComplianceAssessment (2737-3291)
  • RiskAssessment (2097-2427)
backend/app_tests/api/test_api_requirement_assessments.py (3)
backend/core/models.py (8)
  • ComplianceAssessment (2737-3291)
  • RequirementNode (1028-1098)
  • RequirementAssessment (3294-3459)
  • Framework (950-1025)
  • AppliedControl (1740-1955)
  • associated_reference_controls (1063-1070)
  • associated_threats (1073-1080)
  • parent_requirement (1083-1094)
backend/iam/models.py (1)
  • Folder (55-177)
backend/app_tests/api/test_utils.py (3)
  • EndpointTestsQueries (117-1070)
  • Auth (340-1070)
  • get_object_options (501-558)
backend/app_tests/api/test_api_compliance_assessments.py (3)
backend/core/models.py (2)
  • ComplianceAssessment (2737-3291)
  • Framework (950-1025)
backend/iam/models.py (1)
  • Folder (55-177)
backend/app_tests/api/test_utils.py (2)
  • EndpointTestsQueries (117-1070)
  • Auth (340-1070)
backend/app_tests/api/test_api_user_groups.py (1)
backend/iam/models.py (2)
  • RoleAssignment (563-796)
  • get_permissions (778-786)
backend/core/generators.py (1)
backend/core/models.py (5)
  • ComplianceAssessment (2737-3291)
  • get_requirement_assessments (2908-2939)
  • AppliedControl (1740-1955)
  • RequirementAssessment (3294-3459)
  • get_selected_implementation_groups (2895-2906)
backend/app_tests/api/test_utils.py (2)
backend/core/models.py (1)
  • StoredLibrary (243-356)
backend/iam/models.py (4)
  • Folder (55-177)
  • UserGroup (214-241)
  • create_user (301-311)
  • create_superuser (313-326)
backend/app_tests/api/test_api_risk_scenarios.py (2)
backend/iam/models.py (1)
  • Folder (55-177)
backend/app_tests/api/test_utils.py (11)
  • EndpointTestsQueries (117-1070)
  • get_object (120-178)
  • get_object (343-499)
  • create_object (180-209)
  • create_object (560-694)
  • update_object (211-266)
  • update_object (696-844)
  • delete_object (268-317)
  • delete_object (846-957)
  • Auth (340-1070)
  • get_object_options (501-558)
backend/core/base_models.py (1)
backend/ebios_rm/models.py (10)
  • name (669-674)
  • get_scope (482-483)
  • get_scope (555-556)
  • get_scope (600-601)
  • save (254-256)
  • save (372-374)
  • save (488-490)
  • save (558-560)
  • save (603-606)
  • save (652-654)
backend/app_tests/api/test_api_projects.py (3)
backend/core/models.py (2)
  • Project (1351-1394)
  • create (1962-1964)
backend/iam/models.py (1)
  • Folder (55-177)
backend/app_tests/api/test_utils.py (3)
  • EndpointTestsQueries (117-1070)
  • Auth (340-1070)
  • get_object_options (501-558)
backend/ciso_assistant/settings.py (1)
enterprise/backend/enterprise_core/settings.py (1)
  • set_ciso_assistant_url (34-36)
backend/core/helpers.py (1)
backend/iam/models.py (7)
  • Folder (55-177)
  • RoleAssignment (563-796)
  • User (338-544)
  • get_accessible_object_ids (673-759)
  • get_root_folder (62-64)
  • get_parent_folders (116-120)
  • get_sub_folders (105-113)
🪛 actionlint (1.7.8)
.github/workflows/frontend-linters.yaml

26-26: the runner of "actions/checkout@v3" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)

.github/workflows/docker-build-and-push-dummy.yml

30-30: shellcheck reported issue in this script: SC2086:info:1:51: Double quote to prevent globbing and word splitting

(shellcheck)


30-30: shellcheck reported issue in this script: SC2086:info:2:47: Double quote to prevent globbing and word splitting

(shellcheck)

.github/workflows/functional-tests.yml

49-49: the runner of "actions/setup-python@v4" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)


79-79: shellcheck reported issue in this script: SC2129:style:2:1: Consider using { cmd1; cmd2; } >> file instead of individual redirects

(shellcheck)


99-99: shellcheck reported issue in this script: SC2046:warning:1:8: Quote this to prevent word splitting

(shellcheck)


105-105: shellcheck reported issue in this script: SC2046:warning:1:8: Quote this to prevent word splitting

(shellcheck)


118-118: shellcheck reported issue in this script: SC2086:info:1:44: Double quote to prevent globbing and word splitting

(shellcheck)


120-120: shellcheck reported issue in this script: SC2086:info:1:76: Double quote to prevent globbing and word splitting

(shellcheck)


187-187: shellcheck reported issue in this script: SC2129:style:2:1: Consider using { cmd1; cmd2; } >> file instead of individual redirects

(shellcheck)


209-209: shellcheck reported issue in this script: SC2046:warning:1:8: Quote this to prevent word splitting

(shellcheck)


214-214: shellcheck reported issue in this script: SC2046:warning:1:8: Quote this to prevent word splitting

(shellcheck)


224-224: shellcheck reported issue in this script: SC2086:info:1:44: Double quote to prevent globbing and word splitting

(shellcheck)


226-226: shellcheck reported issue in this script: SC2086:info:1:76: Double quote to prevent globbing and word splitting

(shellcheck)

.github/workflows/backend-migrations-check.yaml

29-29: the runner of "actions/setup-python@v4" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)


43-43: shellcheck reported issue in this script: SC2129:style:2:1: Consider using { cmd1; cmd2; } >> file instead of individual redirects

(shellcheck)


58-58: shellcheck reported issue in this script: SC2046:warning:1:8: Quote this to prevent word splitting

(shellcheck)


90-90: shellcheck reported issue in this script: SC2129:style:2:1: Consider using { cmd1; cmd2; } >> file instead of individual redirects

(shellcheck)


107-107: shellcheck reported issue in this script: SC2046:warning:1:8: Quote this to prevent word splitting

(shellcheck)


107-107: shellcheck reported issue in this script: SC2181:style:3:6: Check exit code directly with e.g. 'if ! mycmd;', not indirectly with $?

(shellcheck)

.github/workflows/startup-tests.yml

72-72: shellcheck reported issue in this script: SC2129:style:2:1: Consider using { cmd1; cmd2; } >> file instead of individual redirects

(shellcheck)


87-87: shellcheck reported issue in this script: SC2046:warning:1:8: Quote this to prevent word splitting

(shellcheck)


92-92: shellcheck reported issue in this script: SC2046:warning:1:8: Quote this to prevent word splitting

(shellcheck)


103-103: shellcheck reported issue in this script: SC2086:info:1:44: Double quote to prevent globbing and word splitting

(shellcheck)


105-105: shellcheck reported issue in this script: SC2086:info:1:76: Double quote to prevent globbing and word splitting

(shellcheck)


109-109: property "playwright-browser" is not defined in object type {python-version: number}

(expression)


139-139: shellcheck reported issue in this script: SC2046:warning:2:8: Quote this to prevent word splitting

(shellcheck)


214-214: shellcheck reported issue in this script: SC2129:style:2:1: Consider using { cmd1; cmd2; } >> file instead of individual redirects

(shellcheck)


230-230: shellcheck reported issue in this script: SC2046:warning:1:8: Quote this to prevent word splitting

(shellcheck)


235-235: shellcheck reported issue in this script: SC2046:warning:1:8: Quote this to prevent word splitting

(shellcheck)


243-243: shellcheck reported issue in this script: SC2086:info:1:44: Double quote to prevent globbing and word splitting

(shellcheck)


245-245: shellcheck reported issue in this script: SC2086:info:1:76: Double quote to prevent globbing and word splitting

(shellcheck)


249-249: property "playwright-browser" is not defined in object type {python-version: number}

(expression)


274-274: shellcheck reported issue in this script: SC2046:warning:2:8: Quote this to prevent word splitting

(shellcheck)

.github/workflows/backend-coverage.yaml

37-37: the runner of "actions/checkout@v3" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)


39-39: the runner of "actions/setup-python@v4" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)


53-53: shellcheck reported issue in this script: SC2129:style:2:1: Consider using { cmd1; cmd2; } >> file instead of individual redirects

(shellcheck)


70-70: shellcheck reported issue in this script: SC2046:warning:1:8: Quote this to prevent word splitting

(shellcheck)


76-76: property access of object must be type of string but got "number"

(expression)


77-77: shellcheck reported issue in this script: SC2046:warning:1:8: Quote this to prevent word splitting

(shellcheck)


77-77: shellcheck reported issue in this script: SC2038:warning:2:1: Use 'find .. -print0 | xargs -0 ..' or 'find .. -exec .. +' to allow non-alphanumeric filenames

(shellcheck)


83-83: property access of object must be type of string but got "number"

(expression)

.github/workflows/frontend-unit-tests.yml

25-25: the runner of "actions/checkout@v3" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)

.github/workflows/docker-build-and-push.yml

39-39: shellcheck reported issue in this script: SC2086:info:1:51: Double quote to prevent globbing and word splitting

(shellcheck)


39-39: shellcheck reported issue in this script: SC2086:info:2:47: Double quote to prevent globbing and word splitting

(shellcheck)

.github/workflows/backend-linters.yaml

27-27: the runner of "actions/setup-python@v4" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)

.github/workflows/backend-api-tests.yml

10-10: unexpected key "workflow_dispatch" for "pull_request" section. expected one of "branches", "branches-ignore", "paths", "paths-ignore", "tags", "tags-ignore", "types", "workflows"

(syntax-check)


29-29: the runner of "actions/checkout@v3" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)


31-31: the runner of "actions/setup-python@v4" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)


45-45: shellcheck reported issue in this script: SC2129:style:2:1: Consider using { cmd1; cmd2; } >> file instead of individual redirects

(shellcheck)


59-59: shellcheck reported issue in this script: SC2046:warning:1:8: Quote this to prevent word splitting

(shellcheck)


64-64: shellcheck reported issue in this script: SC2046:warning:1:8: Quote this to prevent word splitting

(shellcheck)

.github/workflows/frontend-coverage.yaml

26-26: the runner of "actions/checkout@v3" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)

.github/workflows/docker-build-and-push-ee.yml

39-39: shellcheck reported issue in this script: SC2086:info:1:51: Double quote to prevent globbing and word splitting

(shellcheck)


39-39: shellcheck reported issue in this script: SC2086:info:2:47: Double quote to prevent globbing and word splitting

(shellcheck)

🪛 Biome (2.1.2)
.eslintrc.js

[error] 2-2: Expected a semicolon or an implicit semicolon after a statement, but found none

An explicit or implicit semicolon is expected here...

...Which is required to end this statement

(parse)


[error] 3-3: Expected a semicolon or an implicit semicolon after a statement, but found none

An explicit or implicit semicolon is expected here...

...Which is required to end this statement

(parse)


[error] 6-6: Expected a semicolon or an implicit semicolon after a statement, but found none

An explicit or implicit semicolon is expected here...

...Which is required to end this statement

(parse)


[error] 14-14: Expected a statement but instead found ']'.

Expected a statement here.

(parse)

🪛 Checkov (3.2.334)
.github/workflows/backend-coverage.yaml

[medium] 76-77: Basic Auth Credentials

(CKV_SECRET_4)

🪛 LanguageTool
README.md

[grammar] ~42-~42: Use a hyphen to join words.
Context: ...neration Our vision is to provide a one stop shop for cyber security posture man...

(QB_NEW_EN_HYPHEN)


[uncategorized] ~552-~552: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...y contains the source code for both the Open Source edition of CISO Assistant (Community Ed...

(EN_COMPOUND_ADJECTIVE_INTERNAL)

LICENSE-AGPL.txt

[style] ~16-~16: Consider using only “Public” to avoid wordiness.
Context: ...and change the works. By contrast, our General Public Licenses are intended to guarantee your...

(GENERAL_XX)


[style] ~21-~21: Consider using only “Public” to avoid wordiness.
Context: ...e referring to freedom, not price. Our General Public Licenses are designed to make sure that...

(GENERAL_XX)


[style] ~27-~27: Consider using only “Public” to avoid wordiness.
Context: ...hese things. Developers that use our General Public Licenses protect your rights with two s...

(GENERAL_XX)


[style] ~177-~177: ‘with respect to’ might be wordy. Consider a shorter alternative.
Context: ...by exercising rights under this License with respect to the covered work, and you disclaim any ...

(EN_WORDINESS_PREMIUM_WITH_RESPECT_TO)


[style] ~407-~407: ‘prior to’ might be wordy. Consider a shorter alternative.
Context: ... the violation by some reasonable means prior to 60 days after the cessation. Moreove...

(EN_WORDINESS_PREMIUM_PRIOR_TO)


[style] ~414-~414: ‘prior to’ might be wordy. Consider a shorter alternative.
Context: ...ight holder, and you cure the violation prior to 30 days after your receipt of the notic...

(EN_WORDINESS_PREMIUM_PRIOR_TO)


[style] ~425-~425: Consider a more concise word here.
Context: ...are not required to accept this License in order to receive or run a copy of the Program. ...

(IN_ORDER_TO_PREMIUM)


[style] ~427-~427: To make your writing clearer, consider a shorter, more direct phrase.
Context: ...tion of a covered work occurring solely as a consequence of using peer-to-peer transmission to rece...

(AS_A_CONSEQUENCE_OF)


[uncategorized] ~516-~516: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...conveying the work, and under which the third party grants, to any of the parties who would...

(EN_COMPOUND_ADJECTIVE_INTERNAL)


[style] ~522-~522: ‘prior to’ might be wordy. Consider a shorter alternative.
Context: ...nt, or that patent license was granted, prior to 28 March 2007. Nothing in this Licen...

(EN_WORDINESS_PREMIUM_PRIOR_TO)


[style] ~533-~533: ‘So as to’ expresses purpose and is used in formal texts. Consider using “to”.
Context: ...e. If you cannot convey a covered work so as to satisfy simultaneously your obligations...

(SO_AS_TO)

CONTRIBUTING.md

[uncategorized] ~6-~6: The official name of this software platform is spelled with a capital “H”.
Context: ... the bug was not previously reported on Github issues (see above). - If it's the case,...

(GITHUB)


[uncategorized] ~25-~25: The official name of this software platform is spelled with a capital “H”.
Context: ...contact us if you are not familiar with Github.

(GITHUB)

🪛 markdownlint-cli2 (0.18.1)
CODE_OF_CONDUCT.md

63-63: Bare URL used

(MD034, no-bare-urls)

.github/ISSUE_TEMPLATE/feature_request.md

11-11: Bare URL used

(MD034, no-bare-urls)

README.md

25-25: Images should have alternate text (alt text)

(MD045, no-alt-text)


48-48: Images should have alternate text (alt text)

(MD045, no-alt-text)


61-61: Bare URL used

(MD034, no-bare-urls)


80-80: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


100-100: Blank line inside blockquote

(MD028, no-blanks-blockquote)


297-297: Emphasis used instead of a heading

(MD036, no-emphasis-as-heading)


301-301: Emphasis used instead of a heading

(MD036, no-emphasis-as-heading)


318-318: Emphasis used instead of a heading

(MD036, no-emphasis-as-heading)


356-356: Bare URL used

(MD034, no-bare-urls)


505-505: Blank line inside blockquote

(MD028, no-blanks-blockquote)


530-530: Images should have alternate text (alt text)

(MD045, no-alt-text)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: GitGuardian Security Checks

Comment on lines +3 to +10
on:
pull_request:
branches: [main, develop]
types: [opened, synchronize]
paths:
- "backend/**"
- ".github/workflows/backend-api-tests.yml"
workflow_dispatch:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Fix workflow trigger configuration.

The workflow_dispatch key should be at the same indentation level as pull_request, not nested within it.

Apply this diff to fix the structure:

 on:
   pull_request:
     branches: [main, develop]
     types: [opened, synchronize]
     paths:
       - "backend/**"
       - ".github/workflows/backend-api-tests.yml"
+  workflow_dispatch:
-    workflow_dispatch:
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
on:
pull_request:
branches: [main, develop]
types: [opened, synchronize]
paths:
- "backend/**"
- ".github/workflows/backend-api-tests.yml"
workflow_dispatch:
on:
pull_request:
branches: [main, develop]
types: [opened, synchronize]
paths:
- "backend/**"
- ".github/workflows/backend-api-tests.yml"
workflow_dispatch:
🧰 Tools
🪛 actionlint (1.7.8)

10-10: unexpected key "workflow_dispatch" for "pull_request" section. expected one of "branches", "branches-ignore", "paths", "paths-ignore", "tags", "tags-ignore", "types", "workflows"

(syntax-check)

🤖 Prompt for AI Agents
In .github/workflows/backend-api-tests.yml around lines 3 to 10, the
workflow_dispatch key is incorrectly nested under pull_request; move
workflow_dispatch out to the same indentation level as pull_request (i.e., under
on:) so both pull_request and workflow_dispatch are siblings, ensuring the file
triggers on pull_request events and manual dispatch.

Comment on lines +29 to +31
- uses: actions/checkout@v3
- name: Set up python ${{ matrix.python-version }}
uses: actions/setup-python@v4
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Update GitHub Actions to latest versions.

The checkout and setup-python actions are using outdated versions that may not run correctly on current GitHub Actions runners.

Apply this diff to update to current versions:

-      - uses: actions/checkout@v3
+      - uses: actions/checkout@v4
       - name: Set up python ${{ matrix.python-version }}
-        uses: actions/setup-python@v4
+        uses: actions/setup-python@v5
         with:
           python-version: ${{ matrix.python-version }}
           cache: "pip"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- uses: actions/checkout@v3
- name: Set up python ${{ matrix.python-version }}
uses: actions/setup-python@v4
- uses: actions/checkout@v4
- name: Set up python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: "pip"
🧰 Tools
🪛 actionlint (1.7.8)

29-29: the runner of "actions/checkout@v3" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)


31-31: the runner of "actions/setup-python@v4" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)

🤖 Prompt for AI Agents
In .github/workflows/backend-api-tests.yml around lines 29 to 31, update the
GitHub Actions to their current major releases: change uses: actions/checkout@v3
to uses: actions/checkout@v4 and ensure uses: actions/setup-python@v4 (or the
latest setup-python stable tag) is used; save the file and run the workflow
linter / a test run to confirm no breakage.

Comment on lines +57 to +66
- name: Run migrations
working-directory: ${{env.backend-directory}}
run: |
export $(grep -v '^#' .env | xargs)
poetry run python manage.py migrate
- name: Run API tests
working-directory: ${{env.backend-directory}}
run: |
export $(grep -v '^#' .env | xargs)
poetry run pytest app_tests/api --html=pytest-report.html --self-contained-html
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Quote command substitution to prevent word splitting.

The export $(grep ...) pattern should have the command substitution quoted to avoid potential word splitting issues.

Apply this diff:

       - name: Run migrations
         working-directory: ${{env.backend-directory}}
         run: |
-          export $(grep -v '^#' .env | xargs)
+          export "$(grep -v '^#' .env | xargs)"
           poetry run python manage.py migrate
       - name: Run API tests
         working-directory: ${{env.backend-directory}}
         run: |
-          export $(grep -v '^#' .env | xargs)
+          export "$(grep -v '^#' .env | xargs)"
           poetry run pytest app_tests/api --html=pytest-report.html --self-contained-html

Alternatively, consider using set -a; source .env; set +a for a more robust approach to loading environment variables.

Committable suggestion skipped: line range outside the PR's diff.

🧰 Tools
🪛 actionlint (1.7.8)

59-59: shellcheck reported issue in this script: SC2046:warning:1:8: Quote this to prevent word splitting

(shellcheck)


64-64: shellcheck reported issue in this script: SC2046:warning:1:8: Quote this to prevent word splitting

(shellcheck)

🤖 Prompt for AI Agents
In .github/workflows/backend-api-tests.yml around lines 57 to 66, the workflow
uses unquoted command substitution export $(grep -v '^#' .env | xargs) which can
suffer word-splitting; fix by quoting the substitution like export "$(grep -v
'^#' .env | xargs)" to preserve spaces, or replace the approach with a more
robust loader: use set -a; source .env; set +a (or a dedicated env-file action)
in both the "Run migrations" and "Run API tests" steps so environment variables
are loaded safely.

Comment on lines +18 to +75
env:
backend-directory: ./backend

services:
postgres:
image: postgres:16
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres # test credential
POSTGRES_DB: postgres
ports: ["5432:5432"]
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5

strategy:
max-parallel: 4
matrix:
python-version: ["3.12"]

steps:
- uses: actions/checkout@v3
- name: Set up python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
cache: "pip"
- name: Install Poetry
uses: snok/install-poetry@v1
with:
virtualenvs-create: false
installer-parallel: true
- name: Install backend requirements
working-directory: ${{ env.backend-directory }}
run: poetry install
- name: Create environment variables file
working-directory: ${{env.backend-directory}}
run: |
touch .env
echo DJANGO_DEBUG='True' >> .env
echo POSTGRES_NAME=postgres >> .env
echo POSTGRES_USER=postgres >> .env
echo POSTGRES_PASSWORD=postgres >> .env
echo DB_HOST=localhost >> .env
echo EMAIL_HOST=localhost >> .env
echo EMAIL_PORT=1025 >> .env
echo EMAIL_HOST_USER='' >> .env
echo EMAIL_HOST_PASSWORD='' >> .env
#echo EMAIL_USE_TLS=False >> .env
echo DEFAULT_FROM_EMAIL='[email protected]' >> .env
echo CISO_ASSISTANT_SUPERUSER_EMAIL='' >> .env
echo CISO_ASSISTANT_URL=http://127.0.0.1:5173 >> .env
- name: Run migrations
working-directory: ${{env.backend-directory}}
run: |
export $(grep -v '^#' .env | xargs)
poetry run python manage.py migrate
- name: Run coverage
working-directory: ${{env.backend-directory}}
env:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Fix env context key to avoid expression errors

${{ env.backend-directory }} is parsed as env.backend - directory, so steps fail to resolve the working directory. Rename the variable with underscores (and update references) so the workflow evaluates. citeturn1static_analysis_hints0

Apply this diff:

-    env:
-      backend-directory: ./backend
+    env:
+      BACKEND_DIRECTORY: ./backend
@@
-      - name: Install backend requirements
-        working-directory: ${{ env.backend-directory }}
+      - name: Install backend requirements
+        working-directory: ${{ env.BACKEND_DIRECTORY }}
@@
-      - name: Create environment variables file
-        working-directory: ${{env.backend-directory}}
+      - name: Create environment variables file
+        working-directory: ${{ env.BACKEND_DIRECTORY }}
@@
-      - name: Run migrations
-        working-directory: ${{env.backend-directory}}
+      - name: Run migrations
+        working-directory: ${{ env.BACKEND_DIRECTORY }}
@@
-      - name: Run coverage
-        working-directory: ${{env.backend-directory}}
+      - name: Run coverage
+        working-directory: ${{ env.BACKEND_DIRECTORY }}
@@
-      - name: Display coverage report
-        working-directory: ${{env.backend-directory}}
+      - name: Display coverage report
+        working-directory: ${{ env.BACKEND_DIRECTORY }}

Committable suggestion skipped: line range outside the PR's diff.

🧰 Tools
🪛 actionlint (1.7.8)

37-37: the runner of "actions/checkout@v3" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)


39-39: the runner of "actions/setup-python@v4" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)


53-53: shellcheck reported issue in this script: SC2129:style:2:1: Consider using { cmd1; cmd2; } >> file instead of individual redirects

(shellcheck)


70-70: shellcheck reported issue in this script: SC2046:warning:1:8: Quote this to prevent word splitting

(shellcheck)

🤖 Prompt for AI Agents
In .github/workflows/backend-coverage.yaml around lines 18 to 75 the env key
backend-directory uses a hyphen which GitHub Actions parses as an expression
(env.backend - directory) causing working-directory lookups to fail; rename the
variable to backend_directory in the env section and update every reference
(e.g. replace all occurrences of ${{ env.backend-directory }} with ${{
env.backend_directory }} and any other places that reference the old name) so
the workflow resolves the path correctly.

Comment on lines +76 to +84
DATABASE_URL: "postgres://postgres:postgres@localhost:${{ job.services.postgres.ports[5432] }}/postgres"
run: |
export $(grep -v '^#' .env | xargs)
find . -path '*/tests/*' -and -name 'test*.py' -and -not -path "./venv/*" | xargs coverage run -m pytest
- name: Display coverage report
working-directory: ${{env.backend-directory}}
env:
DATABASE_URL: "postgres://postgres:postgres@localhost:${{ job.services.postgres.ports[5432] }}/postgres"
run: coverage report
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Quote the service port key

job.services.postgres.ports[5432] is invalid because the port map keys are strings; actionlint already flags this and the job fails. Use the quoted key instead. citeturn1static_analysis_hints0

Apply this diff:

-          DATABASE_URL: "postgres://postgres:postgres@localhost:${{ job.services.postgres.ports[5432] }}/postgres"
+          DATABASE_URL: "postgres://postgres:postgres@localhost:${{ job.services.postgres.ports['5432'] }}/postgres"
@@
-          DATABASE_URL: "postgres://postgres:postgres@localhost:${{ job.services.postgres.ports[5432] }}/postgres"
+          DATABASE_URL: "postgres://postgres:postgres@localhost:${{ job.services.postgres.ports['5432'] }}/postgres"
🧰 Tools
🪛 actionlint (1.7.8)

76-76: property access of object must be type of string but got "number"

(expression)


77-77: shellcheck reported issue in this script: SC2046:warning:1:8: Quote this to prevent word splitting

(shellcheck)


77-77: shellcheck reported issue in this script: SC2038:warning:2:1: Use 'find .. -print0 | xargs -0 ..' or 'find .. -exec .. +' to allow non-alphanumeric filenames

(shellcheck)


83-83: property access of object must be type of string but got "number"

(expression)

🪛 Checkov (3.2.334)

[medium] 76-77: Basic Auth Credentials

(CKV_SECRET_4)

🤖 Prompt for AI Agents
In .github/workflows/backend-coverage.yaml around lines 76 to 84, the workflow
references job.services.postgres.ports[5432] using an unquoted numeric key which
is invalid; update the references to use the string key form
job.services.postgres.ports['5432'] (or job.services.postgres.ports."5432"
depending on YAML parser) wherever the port is accessed (both DATABASE_URL
lines) so actionlint and the workflow can resolve the port mapping correctly.

Comment on lines +10 to +12
def handle(self, *args, **kwargs):
admin = User.objects.get(email=CISO_ASSISTANT_SUPERUSER_EMAIL)
print(admin)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Handle potential User.objects.get() exceptions.

Line 11 will raise User.DoesNotExist if no user with the configured email exists, or User.MultipleObjectsReturned if multiple users exist. The command will crash without a helpful error message.

Apply this diff to handle these cases:

     def handle(self, *args, **kwargs):
-        admin = User.objects.get(email=CISO_ASSISTANT_SUPERUSER_EMAIL)
-        print(admin)
+        try:
+            admin = User.objects.get(email=CISO_ASSISTANT_SUPERUSER_EMAIL)
+        except User.DoesNotExist:
+            self.stdout.write(self.style.ERROR(f"No user found with email: {CISO_ASSISTANT_SUPERUSER_EMAIL}"))
+            return
+        except User.MultipleObjectsReturned:
+            self.stdout.write(self.style.ERROR(f"Multiple users found with email: {CISO_ASSISTANT_SUPERUSER_EMAIL}"))
+            return
+        
+        self.stdout.write(f"Sending welcome email to: {admin}")
         try:

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In backend/core/management/commands/welcome_mail.py around lines 10 to 12, the
call to User.objects.get(email=CISO_ASSISTANT_SUPERUSER_EMAIL) can raise
User.DoesNotExist or User.MultipleObjectsReturned and currently crashes; wrap
the get() call in a try/except that catches these two exceptions and raise a
django.core.management.base.CommandError (or log a clear error and sys.exit(1))
with a helpful message indicating whether the superuser was not found or
multiple users found and include the configured email value so the management
command fails gracefully and informs the operator what to fix.

Comment on lines +31 to +33
"updated_at",
models.DateTimeField(auto_now=True, verbose_name="UpdatedÒ at"),
),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Correct the “Updated at” verbose label

There’s an “Ò” in the verbose name ("UpdatedÒ at"). This typo will surface anywhere the admin renders the label; please fix it (and the other occurrences in this migration).

Apply this diff:

-                    models.DateTimeField(auto_now=True, verbose_name="UpdatedÒ at"),
+                    models.DateTimeField(auto_now=True, verbose_name="Updated at"),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"updated_at",
models.DateTimeField(auto_now=True, verbose_name="UpdatedÒ at"),
),
"updated_at",
models.DateTimeField(auto_now=True, verbose_name="Updated at"),
),
🤖 Prompt for AI Agents
In backend/core/migrations/0001_initial.py around lines 31 to 33, the
verbose_name for the updated_at field contains a stray character ("UpdatedÒ
at"); find this and any other occurrences of "UpdatedÒ at" in this migration and
replace them with the correct string "Updated at" (preserve surrounding code and
formatting), ensuring all verbose_name values use the corrected label.

Comment on lines +9 to +26
enisa_5g_scm_stored_library = StoredLibrary.objects.filter(
urn="urn:intuitem:risk:library:enisa-5g-scm-v1.3"
)
if enisa_5g_scm_stored_library:
enisa_5g_scm_stored_library[
0
].delete() # the lib will be added again in the store at the end of the migration
enisa_5g_scm_loaded_library = LoadedLibrary.objects.filter(
urn="urn:intuitem:risk:library:enisa-5g-scm-v1.3"
)
if enisa_5g_scm_loaded_library:
count = 0
for b in enisa_5g_scm_loaded_library[0].reference_controls.all():
if b.urn[:4] != "urn:":
b.urn = "urn:intuitem:" + b.urn
b.save()
count += 1
print(f"fixed {count} URNs")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Avoid truthiness checks on QuerySets

In Django 5, evaluating a QuerySet in a boolean context raises ValueError, so this migration will crash before touching the data. Grab the first object (or call .exists()) instead of relying on truthiness, and reuse that handle inside the loop.

-    enisa_5g_scm_stored_library = StoredLibrary.objects.filter(
-        urn="urn:intuitem:risk:library:enisa-5g-scm-v1.3"
-    )
-    if enisa_5g_scm_stored_library:
-        enisa_5g_scm_stored_library[
-            0
-        ].delete()  # the lib will be added again in the store at the end of the migration
-    enisa_5g_scm_loaded_library = LoadedLibrary.objects.filter(
-        urn="urn:intuitem:risk:library:enisa-5g-scm-v1.3"
-    )
-    if enisa_5g_scm_loaded_library:
+    stored_library = StoredLibrary.objects.filter(
+        urn="urn:intuitem:risk:library:enisa-5g-scm-v1.3"
+    ).first()
+    if stored_library:
+        stored_library.delete()  # the lib will be added again in the store at the end of the migration
+    loaded_library = LoadedLibrary.objects.filter(
+        urn="urn:intuitem:risk:library:enisa-5g-scm-v1.3"
+    ).first()
+    if loaded_library:
         count = 0
-        for b in enisa_5g_scm_loaded_library[0].reference_controls.all():
+        for b in loaded_library.reference_controls.all():
             if b.urn[:4] != "urn:":
                 b.urn = "urn:intuitem:" + b.urn
                 b.save()
                 count += 1
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
enisa_5g_scm_stored_library = StoredLibrary.objects.filter(
urn="urn:intuitem:risk:library:enisa-5g-scm-v1.3"
)
if enisa_5g_scm_stored_library:
enisa_5g_scm_stored_library[
0
].delete() # the lib will be added again in the store at the end of the migration
enisa_5g_scm_loaded_library = LoadedLibrary.objects.filter(
urn="urn:intuitem:risk:library:enisa-5g-scm-v1.3"
)
if enisa_5g_scm_loaded_library:
count = 0
for b in enisa_5g_scm_loaded_library[0].reference_controls.all():
if b.urn[:4] != "urn:":
b.urn = "urn:intuitem:" + b.urn
b.save()
count += 1
print(f"fixed {count} URNs")
stored_library = StoredLibrary.objects.filter(
urn="urn:intuitem:risk:library:enisa-5g-scm-v1.3"
).first()
if stored_library:
stored_library.delete() # the lib will be added again in the store at the end of the migration
loaded_library = LoadedLibrary.objects.filter(
urn="urn:intuitem:risk:library:enisa-5g-scm-v1.3"
).first()
if loaded_library:
count = 0
for b in loaded_library.reference_controls.all():
if b.urn[:4] != "urn:":
b.urn = "urn:intuitem:" + b.urn
b.save()
count += 1
print(f"fixed {count} URNs")
🤖 Prompt for AI Agents
In backend/core/migrations/0014_auto_20240522_1731.py around lines 9 to 26, the
migration uses QuerySet truthiness and index access which raises ValueError in
Django 5 and is inefficient; replace the truthiness/indexing with explicit
lookups (e.g., .first() or .exists()) and store the retrieved object in a
variable, use that variable for .delete() (for StoredLibrary) and for
iterating/modifying its reference_controls (for LoadedLibrary), avoiding
re-querying or boolean evaluation of the QuerySet.

Comment on lines +1 to +24
# Generated by Django 5.1 on 2024-08-30 11:05

from django.conf import settings
from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("core", "0023_alter_appliedcontrol_status"),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]

operations = [
migrations.AddField(
model_name="appliedcontrol",
name="owner",
field=models.ManyToManyField(
blank=True,
related_name="applied_controls",
to=settings.AUTH_USER_MODEL,
verbose_name="Owner",
),
),
]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

LGTM! Verify export/import handling for consistency.

The migration correctly adds an owner ManyToManyField to AppliedControl, following the same pattern as other ownership relationships in the codebase. Based on learnings, ensure that the export/import functionality handles this new M2M relationship consistently with Evidence.owner (i.e., owner_ids are collected to prevent validation errors but not applied during import since users are environment-specific).


🏁 Script executed:

#!/bin/bash
# Verify how export/import handles owner M2M relationships
rg -n "owner.*M2M|_process_model_relationships|_set_many_to_many_relations" backend/core/views.py -A5 -B5

Length of output: 1931



---

🏁 Script executed:

```shell
#!/bin/bash
# Get full implementation of _process_model_relationships
rg -n "def _process_model_relationships" backend/core/views.py -A100 | head -120

Length of output: 4440


🏁 Script executed:

#!/bin/bash
# Get full implementation of _set_many_to_many_relations
rg -n "def _set_many_to_many_relations" backend/core/views.py -A100

Length of output: 5150


🏁 Script executed:

#!/bin/bash
# Search for AppliedControl owner handling in export/import
rg -n "appliedcontrol|applied_control" backend/core/views.py -i -C3

Length of output: 27678


🏁 Script executed:

#!/bin/bash
# Search for Evidence.owner handling as reference
rg -n "evidence.*owner|owner.*evidence" backend/core/views.py -i -C3

Length of output: 0



---

🏁 Script executed:

```shell
#!/bin/bash
# Search for Evidence model definition and owner field
rg -n "class Evidence" backend/core/models.py -A30 | head -50

Length of output: 1186


🏁 Script executed:

#!/bin/bash
# Search for export/dump logic that serializes owner fields
rg -n "owner|_get_dump_database_objects|serialize" backend/core/views.py -B2 -A2 | grep -A5 -B5 "owner"

Length of output: 3014


🏁 Script executed:

#!/bin/bash
# Check if any M2M relationships collect owner_ids in export
rg -n "owner_ids|owner.*get_mapped_ids" backend/core/views.py

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Look for the full evidence case in _process_model_relationships and _set_many_to_many_relations
rg -n "case \"evidence\"" backend/core/views.py -A10

Length of output: 547



---

🏁 Script executed:

```shell
#!/bin/bash
# Find AppliedControl model definition and check owner field constraints
rg -n "class AppliedControl" backend/core/models.py -A60 | grep -A3 -B3 "owner"

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Check migration to see if owner field has blank=True or constraints
rg -n "owner" backend/core/migrations/0024_appliedcontrol_owner.py -B2 -A2

Length of output: 180



---

🏁 Script executed:

```shell
#!/bin/bash
# Search for owner field handling in the full export/import process
rg -n "_get_dump_database_objects|export.*owner" backend/core/views.py -B5 -A10 | head -100

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Check if Evidence actually has owner M2M by looking at Evidence model more completely
fd -e "models.py" backend/core/ -x grep -n "class Evidence" {} + -A100 | grep -i "owner"

Length of output: 357


🏁 Script executed:

#!/bin/bash
# Search for what fields are actually exported in the dump
rg -n "fields_to_export|excluded_fields|get_serialized_data" backend/core/views.py -B3 -A10

Length of output: 0



---

🏁 Script executed:

```shell
#!/bin/bash
# Find where objects are serialized for export/dump
rg -n "def.*dump|def.*export|model_to_dict|serialize" backend/core/views.py | grep -i dump

Length of output: 226


🏁 Script executed:

#!/bin/bash
# Look for the actual dump/export serialization logic
rg -n "_get_model_list_for_export|_get_database_objects|objects.values\(\)" backend/core/views.py -B2 -A5

Length of output: 758


🏁 Script executed:

#!/bin/bash
# Find where the dump data is created - look for json.dumps or similar export pattern
rg -n "json.dumps|\.values\(|model_to_dict" backend/core/views.py -B3 -A3 | head -80

Length of output: 3532


🏁 Script executed:

#!/bin/bash
# Check what happens between create and set_many_to_many - search for fields.pop or related
rg -n "fields.pop|_fields.pop" backend/core/views.py -B1 -A1

Length of output: 2835


Add export/import handling for AppliedControl.owner M2M relationship.

The new owner field is not handled in the domain export/import logic. Currently, the appliedcontrol case in _process_model_relationships (lines 2627–2630) and _set_many_to_many_relations (lines 2804–2806) only processes evidences. Following the established pattern and the learnings on environment-specific user handling, you must:

  1. In _process_model_relationships (appliedcontrol case): Collect owner_ids via get_mapped_ids() and pop the owner field, storing the mapped IDs in many_to_many_map_ids (to prevent M2M validation errors during import, similar to Evidence.owner).

  2. In _set_many_to_many_relations (appliedcontrol case): Do not apply owner relationships during import (users are environment-specific and should not be transferred across domains).

This ensures the new M2M field is handled consistently with other ownership relationships in the codebase.

Comment on lines +12 to +41
RUN apt-get update && apt-get install -y \
libyaml-cpp-dev \
libffi-dev \
libglib2.0-0 \
pango-1.0 \
libcairo2 \
locales \
tzdata \
gettext \
fontconfig \
fonts-freefont-ttf \
zlib1g-dev \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* \
&& locale-gen en_US.UTF-8 \
&& locale-gen ar_SA.UTF-8 \
&& locale-gen fr_FR.UTF-8 \
&& locale-gen pt_PT.UTF-8 \
&& locale-gen es_ES.UTF-8 \
&& locale-gen de_DE.UTF-8 \
&& locale-gen nl_NL.UTF-8 \
&& locale-gen it_IT.UTF-8 \
&& locale-gen pl_PL.UTF-8 \
&& locale-gen ro_RO.UTF-8 \
&& locale-gen hi_IN.UTF-8 \
&& locale-gen ur_PK.UTF-8 \
&& locale-gen cs_CZ.UTF-8 \
&& locale-gen sv_SE.UTF-8 \
&& locale-gen id_ID.UTF-8 \
&& pip install --no-cache-dir --upgrade pip poetry==2.0.1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Package name pango-1.0 breaks the build
apt-get doesn’t ship a pango-1.0 package on Debian/Ubuntu; the runtime libs live in packages such as libpango-1.0-0, libpangocairo-1.0-0, or the meta-package pango1.0. As written the layer fails with “Unable to locate package pango-1.0”, so the image never builds. Please swap in the actual package name(s) you need (for example libpango-1.0-0 and friends) before continuing with Poetry install. (packages.debian.org)

Copy link
Collaborator

@nas-tabchiche nas-tabchiche left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bonjour @Qnadia,

Merci pour vos contributions !
Afin que l'on puisse merge, pouvez-vous synchroniser vos branches avec main ?

Merci beaucoup.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.