Skip to content

Commit

Permalink
Merge branch 'main' into global_setting_for_default_language
Browse files Browse the repository at this point in the history
  • Loading branch information
monsieurswag committed Oct 21, 2024
2 parents 5af90ec + ed658e6 commit 9cff37b
Show file tree
Hide file tree
Showing 53 changed files with 396 additions and 581 deletions.
27 changes: 18 additions & 9 deletions .github/workflows/functional-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,14 @@ jobs:
- uses: actions/setup-node@v4
with:
node-version: latest
- name: Install requirements
- 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: |
python -m pip install --upgrade pip
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
run: poetry install
- name: Install dependencies
working-directory: ${{ env.frontend-directory }}
run: |
Expand All @@ -72,6 +75,8 @@ jobs:
working-directory: ${{ env.backend-directory }}
run: |
touch .env
echo LOG_LEVEL=DEBUG >> .env
echo LOG_OUTFILE=ciso-assistant.log >> .env
echo DJANGO_DEBUG=True >> .env
echo [email protected] >> .env
echo DJANGO_SUPERUSER_PASSWORD=1234 >> .env
Expand All @@ -90,14 +95,14 @@ jobs:
working-directory: ${{ env.backend-directory }}
run: |
export $(grep -v '^#' .env | xargs)
python manage.py makemigrations
python manage.py migrate
poetry run python manage.py makemigrations
poetry run python manage.py migrate
- name: Start test server
working-directory: ${{ env.backend-directory }}
run: |
export $(grep -v '^#' .env | xargs)
python manage.py createsuperuser --noinput
nohup python manage.py runserver &
poetry run python manage.py createsuperuser --noinput
nohup poetry run python manage.py runserver &
- name: Build frontend
working-directory: ${{ env.frontend-directory }}
run: pnpm run build
Expand All @@ -111,6 +116,7 @@ jobs:
with:
name: functional-tests-report-${{ matrix.playwright-browser }}
path: |
${{ env.backend-directory }}/*.log
${{ env.frontend-directory }}/tests/results/
${{ env.frontend-directory }}/tests/reports/
retention-days: 5
Expand Down Expand Up @@ -173,6 +179,8 @@ jobs:
working-directory: ${{ env.backend-directory }}
run: |
touch .env
echo LOG_LEVEL=DEBUG >> .env
echo LOG_OUTFILE=ciso-assistant.log >> .env
echo DJANGO_DEBUG=True >> .env
echo [email protected] >> .env
echo DJANGO_SUPERUSER_PASSWORD=1234 >> .env
Expand All @@ -198,7 +206,7 @@ jobs:
working-directory: ${{ env.backend-directory }}
run: |
export $(grep -v '^#' .env | xargs)
poetry run python manage.py createsuperuser --noinput
poetry run python manage.py createsuperuser --noinput --settings=${{ env.enterprise-backend-settings-module }}
nohup poetry run python manage.py runserver --settings=${{ env.enterprise-backend-settings-module }} &
- name: Run tests with browser ${{ matrix.playwright-browser }}
working-directory: ${{ env.enterprise-frontend-build-directory }}
Expand All @@ -210,6 +218,7 @@ jobs:
with:
name: enterprise-functional-tests-report-${{ matrix.playwright-browser }}
path: |
${{ env.backend-directory }}/*.log
${{ env.enterprise-frontend-build-directory }}/tests/results/
${{ env.enterprise-frontend-build-directory }}/tests/reports/
retention-days: 5
8 changes: 7 additions & 1 deletion .github/workflows/startup-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ jobs:
working-directory: ${{ env.backend-directory }}
run: |
touch .env
echo LOG_LEVEL=DEBUG >> .env
echo LOG_OUTFILE=ciso-assistant.log >> .env
echo DJANGO_DEBUG=True >> .env
echo [email protected] >> .env
echo DJANGO_SUPERUSER_PASSWORD=1234 >> .env
Expand Down Expand Up @@ -98,6 +100,7 @@ jobs:
with:
name: startup-functional-test-report
path: |
${{ env.backend-directory }}/*.log
${{ env.frontend-directory }}/tests/reports/
retention-days: 5

Expand Down Expand Up @@ -196,6 +199,8 @@ jobs:
working-directory: ${{ env.backend-directory }}
run: |
touch .env
echo LOG_LEVEL=DEBUG >> .env
echo LOG_OUTFILE=ciso-assistant.log >> .env
echo DJANGO_DEBUG=True >> .env
echo [email protected] >> .env
echo DJANGO_SUPERUSER_PASSWORD=1234 >> .env
Expand All @@ -215,7 +220,7 @@ jobs:
working-directory: ${{ env.backend-directory }}
run: |
export $(grep -v '^#' .env | xargs)
poetry run python manage.py createsuperuser --noinput
poetry run python manage.py createsuperuser --noinput --settings=${{ env.enterprise-backend-settings-module }}
nohup poetry run python manage.py runserver --settings=${{ env.enterprise-backend-settings-module }} &
- name: Run tests
working-directory: ${{ env.enterprise-frontend-build-directory }}
Expand All @@ -225,6 +230,7 @@ jobs:
with:
name: enterprise-startup-functional-test-report
path: |
${{ env.backend-directory }}/*.log
${{ env.enterprise-frontend-build-directory }}/tests/reports/
retention-days: 5

Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*.sqlite3
django_secret_key
temp/
./db/
db/
.dccache
/backend/profiles
./backend/ciso_assistant/.meta
Expand Down
1 change: 1 addition & 0 deletions backend/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ db/pg_password.txt
.coverage
pytest-report.html
enterprise/
*.log
10 changes: 10 additions & 0 deletions backend/ciso_assistant/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

LOG_LEVEL = os.environ.get("LOG_LEVEL", "INFO")
LOG_FORMAT = os.environ.get("LOG_FORMAT", "plain")
LOG_OUTFILE = os.environ.get("LOG_OUTFILE", "")

CISO_ASSISTANT_URL = os.environ.get("CISO_ASSISTANT_URL", "http://localhost:5173")

Expand Down Expand Up @@ -59,6 +60,15 @@ def set_ciso_assistant_url(_, __, event_dict):
},
}

if LOG_OUTFILE:
LOGGING["handlers"]["file"] = {
"level": LOG_LEVEL,
"class": "logging.handlers.WatchedFileHandler",
"filename": "ciso-assistant.log",
"formatter": "json",
}
LOGGING["loggers"][""]["handlers"].append("file")

structlog.configure(
processors=[
structlog.contextvars.merge_contextvars,
Expand Down
38 changes: 38 additions & 0 deletions enterprise/backend/enterprise_core/permissions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import os
from datetime import datetime

import structlog
from rest_framework import permissions

logger = structlog.get_logger(__name__)


class LicensePermission(permissions.BasePermission):
def has_permission(self, request, view):
expiration_date_str = os.environ.get("LICENSE_EXPIRATION")

if not expiration_date_str:
# Handle the case where no expiration date is set
logger.warning("License expiration date is not set.")
return True

try:
expiration_date = datetime.fromisoformat(expiration_date_str)
except ValueError:
logger.error(
"Invalid expiration date format. Expiration date should follow ISO 8601 format.",
expiration_date=expiration_date_str,
)
return False

if expiration_date < datetime.now():
# License has expired, only allow read operations
if request.method not in permissions.SAFE_METHODS:
logger.warning(
"License has expired, only read operations are allowed.",
expiration_date=expiration_date,
)
return False

# License is valid, allow all operations
return True
18 changes: 17 additions & 1 deletion enterprise/backend/enterprise_core/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

LOG_LEVEL = os.environ.get("LOG_LEVEL", "INFO")
LOG_FORMAT = os.environ.get("LOG_FORMAT", "plain")
LOG_OUTFILE = os.environ.get("LOG_OUTFILE", "")

CISO_ASSISTANT_URL = os.environ.get("CISO_ASSISTANT_URL", "http://localhost:5173")

Expand Down Expand Up @@ -59,6 +60,16 @@ def set_ciso_assistant_url(_, __, event_dict):
},
}

if LOG_OUTFILE:
LOGGING["handlers"]["file"] = {
"level": LOG_LEVEL,
"class": "logging.handlers.WatchedFileHandler",
"filename": "ciso-assistant.log",
"formatter": "json",
}
LOGGING["loggers"][""]["handlers"].append("file")


structlog.configure(
processors=[
structlog.contextvars.merge_contextvars,
Expand Down Expand Up @@ -198,6 +209,7 @@ def set_ciso_assistant_url(_, __, event_dict):
"DEFAULT_PERMISSION_CLASSES": [
"rest_framework.permissions.IsAuthenticated",
"core.permissions.RBACPermissions",
"enterprise_core.permissions.LicensePermission",
],
"DEFAULT_FILTER_CLASSES": ["django_filters.rest_framework.DjangoFilterBackend"],
"DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.PageNumberPagination",
Expand Down Expand Up @@ -396,10 +408,14 @@ def set_ciso_assistant_url(_, __, event_dict):
}

logger.info(
"Enterprise startup info", feature_flags=FEATURE_FLAGS, module_paths=MODULE_PATHS
"Enterprise startup information",
feature_flags=FEATURE_FLAGS,
module_paths=MODULE_PATHS,
)

LICENSE_SEATS = int(os.environ.get("LICENSE_SEATS", 1))
LICENSE_EXPIRATION = os.environ.get("LICENSE_EXPIRATION", "unset")

logger.info("License information", seats=LICENSE_SEATS, expiration=LICENSE_EXPIRATION)

INSTALLED_APPS.append("enterprise_core")
3 changes: 2 additions & 1 deletion enterprise/backend/enterprise_core/urls.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
from django.urls import include, path


from .views import get_build
from .views import LicenseStatusView, get_build

urlpatterns = [
path("build/", get_build, name="get_build"),
path("license-status/", LicenseStatusView.as_view(), name="license-status"),
]
47 changes: 44 additions & 3 deletions enterprise/backend/enterprise_core/views.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
import magic
from datetime import datetime
from django.utils.formats import date_format

import magic
import structlog
from core.views import BaseModelViewSet
from django.conf import settings
from iam.models import User
from rest_framework import status
from rest_framework.permissions import AllowAny
from rest_framework.decorators import (
action,
api_view,
permission_classes,
)
from rest_framework.parsers import FileUploadParser
from rest_framework.permissions import AllowAny
from rest_framework.response import Response
from rest_framework.views import APIView

from django.conf import settings

Expand Down Expand Up @@ -158,6 +164,35 @@ def upload_favicon(self, request, pk):
return self.handle_file_upload(request, pk, "favicon")


class LicenseStatusView(APIView):
def get(self, request):
expiry_date_str = settings.LICENSE_EXPIRATION

if not expiry_date_str:
return Response(
{"status": "unknown", "message": "No expiry date set"},
status=status.HTTP_400_BAD_REQUEST,
)

try:
expiry_date = datetime.fromisoformat(expiry_date_str)
except ValueError as e:
logger.error("Invalid expiry date format", exc_info=e)
return Response(
{"status": "error", "message": "Invalid expiry date format"},
status=status.HTTP_500_INTERNAL_SERVER_ERROR,
)

now = datetime.now()

if expiry_date > now:
days_left = (expiry_date - now).days
return Response({"status": "active", "days_left": days_left})
else:
days_expired = (now - expiry_date).days
return Response({"status": "expired", "days_expired": days_expired})


@api_view(["GET"])
def get_build(request):
"""
Expand All @@ -167,12 +202,18 @@ def get_build(request):
BUILD = settings.BUILD
LICENSE_SEATS = settings.LICENSE_SEATS
LICENSE_EXPIRATION = settings.LICENSE_EXPIRATION
try:
expiration_iso = datetime.fromisoformat(LICENSE_EXPIRATION)
license_expiration = date_format(expiration_iso, use_l10n=True)
except ValueError:
logger.error("Invalid expiry date format", exc_info=True)
license_expiration = LICENSE_EXPIRATION
return Response(
{
"version": VERSION,
"build": BUILD,
"license_seats": LICENSE_SEATS,
"available_seats": LICENSE_SEATS - len(User.get_editors()),
"license_expiration": LICENSE_EXPIRATION,
"license_expiration": license_expiration,
}
)
Loading

0 comments on commit 9cff37b

Please sign in to comment.