diff --git a/.gitignore b/.gitignore index da8a3d8..fbaeba4 100644 --- a/.gitignore +++ b/.gitignore @@ -16,4 +16,5 @@ AGENT*.md # Diagram cache directory media/diagram_cache/ .env -data/db.sqlite3 +data/ +dataremote/ diff --git a/VorgabenUI/settings-docker.py b/VorgabenUI/settings-docker.py deleted file mode 100644 index 7aaf28b..0000000 --- a/VorgabenUI/settings-docker.py +++ /dev/null @@ -1,141 +0,0 @@ -""" -Django settings for VorgabenUI project. - -Generated by 'django-admin startproject' using Django 5.2. - -For more information on this file, see -https://docs.djangoproject.com/en/5.2/topics/settings/ - -For the full list of settings and their values, see -https://docs.djangoproject.com/en/5.2/ref/settings/ -""" - -import os -from pathlib import Path - -# Build paths inside the project like this: BASE_DIR / 'subdir'. -BASE_DIR = Path(__file__).resolve().parent.parent - - -# Quick-start development settings - unsuitable for production -# See https://docs.djangoproject.com/en/5.2/howto/deployment/checklist/ - -# SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = os.environ.get("SECRET_KEY") - -# SECURITY WARNING: don't run with debug turned on in production! -DEBUG = bool(os.environ.get("DEBUG", default=0)) - -ALLOWED_HOSTS = os.environ.get("DJANGO_ALLOWED_HOSTS","127.0.0.1").split(",") - - -# Application definition - -INSTALLED_APPS = [ - 'django.contrib.admin', - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.messages', - 'django.contrib.staticfiles', - 'dokumente', - 'abschnitte', - 'stichworte', - 'mptt', - 'nested_admin', -] - -MIDDLEWARE = [ - 'django.middleware.security.SecurityMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.common.CommonMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - 'django.middleware.clickjacking.XFrameOptionsMiddleware', -] - -ROOT_URLCONF = 'VorgabenUI.urls' - -TEMPLATES = [ - { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [], - 'APP_DIRS': True, - 'OPTIONS': { - 'context_processors': [ - 'django.template.context_processors.request', - 'django.contrib.auth.context_processors.auth', - 'django.contrib.messages.context_processors.messages', - ], - }, - }, -] - -WSGI_APPLICATION = 'VorgabenUI.wsgi.application' - - -# Database -# https://docs.djangoproject.com/en/5.2/ref/settings/#databases - -DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': BASE_DIR / 'data/db.sqlite3', - } -} - - -# Password validation -# https://docs.djangoproject.com/en/5.2/ref/settings/#auth-password-validators - -AUTH_PASSWORD_VALIDATORS = [ - { - 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', - }, -] - - -# Internationalization -# https://docs.djangoproject.com/en/5.2/topics/i18n/ - -LANGUAGE_CODE = 'de-ch' - -TIME_ZONE = 'UTC' - -USE_I18N = True - -USE_TZ = True - - -# Static files (CSS, JavaScript, Images) -# https://docs.djangoproject.com/en/5.2/howto/static-files/ - -STATIC_URL = '/static/' -STATIC_ROOT="/home/adebaumann/VorgabenUI/staticfiles/" -STATICFILES_DIRS= ( - os.path.join(BASE_DIR,"static"), - ) - -# Media files (User-uploaded content) -MEDIA_URL = '/media/' -MEDIA_ROOT = os.path.join(BASE_DIR, 'media') - -# Diagram cache settings -DIAGRAM_CACHE_DIR = 'diagram_cache' # relative to MEDIA_ROOT - -# Default primary key field type -# https://docs.djangoproject.com/en/5.2/ref/settings/#default-auto-field - -DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' -DATA_UPLOAD_MAX_NUMBER_FIELDS=10250 -NESTED_ADMIN_LAZY_INLINES = True diff --git a/VorgabenUI/settings.py b/VorgabenUI/settings.py index 26a43c7..dc48a85 100644 --- a/VorgabenUI/settings.py +++ b/VorgabenUI/settings.py @@ -138,7 +138,7 @@ AUTH_PASSWORD_VALIDATORS = [ LANGUAGE_CODE = 'de-ch' -TIME_ZONE = 'UTC' +TIME_ZONE = 'Europe/Zurich' USE_I18N = True diff --git a/argocd/deployment.yaml b/argocd/deployment.yaml index 38d44f1..aab0629 100644 --- a/argocd/deployment.yaml +++ b/argocd/deployment.yaml @@ -25,7 +25,7 @@ spec: mountPath: /data containers: - name: web - image: git.baumann.gr/adebaumann/vui:0.982 + image: git.baumann.gr/adebaumann/vui:0.983 imagePullPolicy: Always securityContext: runAsUser: 99 diff --git a/code-review.md b/code-review.md new file mode 100644 index 0000000..c944d1a --- /dev/null +++ b/code-review.md @@ -0,0 +1,512 @@ +# Code Review: vgui-cicd Django Project + +**Date:** January 20, 2026 +**Reviewer:** AI Code Review +**Project Path:** /home/adebaumann/development/vgui-cicd + +--- + +## 1. PROJECT STRUCTURE + +### Overview +The project follows Django conventions with a clear app structure: +- **VorgabenUI** - Main project settings, URLs, WSGI/ASGI +- **dokumente** - Core document and Vorgabe models (315 lines) +- **abschnitte** - Text section models and utilities +- **stichworte** - Keyword/stichwort models +- **referenzen** - Reference models (MPTT-based) +- **rollen** - Role models +- **pages** - General pages and views +- **diagramm_proxy** - Diagram caching functionality + +### Issues Found + +**Minor - settings-docker.py**: The `settings-docker.py` file has duplicate `AUTH_PASSWORD_VALIDATORS` definitions (lines 92-105 and 183-199), which is redundant. +- **File**: `/home/adebaumann/development/vgui-cicd/VorgabenUI/settings-docker.py` (lines 92-105 and 183-199) + +--- + +## 2. SETTINGS REVIEW + +### Critical Issues + +**1. Fallback SECRET_KEY in production** (`/home/adebaumann/development/vgui-cicd/VorgabenUI/settings.py`, lines 27-47) +```python +SECRET_KEY = os.environ.get('VORGABENUI_SECRET') +if not SECRET_KEY: + is_build_env = any([...]) + debug_mode = ... + if debug_mode or is_build_env: + SECRET_KEY = 'dev-fallback-key-for-local-debugging-only-not-for-production-use-12345' +``` +- **Issue**: Even though there's a check for build environments, the hardcoded fallback key creates a significant security risk if the environment variable is not properly set in production +- **Recommendation**: The fallback should NEVER be enabled, even in development - require the environment variable to be set + +**2. DEBUG mode default** (`/home/adebaumann/development/vgui-cicd/VorgabenUI/settings.py`, line 24) +```python +DEBUG = os.environ.get('DEBUG', 'True').lower() in ('true', '1', 'yes', 'on') +``` +- **Issue**: DEBUG defaults to True, which could expose sensitive information if environment variables are misconfigured +- **Recommendation**: Require explicit setting of DEBUG to False in production + +### Major Issues + +**3. ALLOWED_HOSTS with wildcard** (`/home/adebaumann/development/vgui-cicd/VorgabenUI/settings.py`, line 50) +```python +ALLOWED_HOSTS = os.environ.get('DJANGO_ALLOWED_HOSTS', "10.128.128.144,localhost,127.0.0.1,*").split(",") +``` +- **Issue**: Default includes `*` which allows any host - dangerous in production +- **Recommendation**: Default should not include wildcard; require explicit configuration + +**4. No rate limiting on authentication** (`/home/adebaumann/development/vgui-cicd/VorgabenUI/settings.py`) +- **Issue**: No login throttling or rate limiting configured for authentication endpoints +- **Recommendation**: Add `django-axes` or similar for brute-force protection + +**5. SQLite in production** (`/home/adebaumann/development/vgui-cicd/VorgabenUI/settings.py`, lines 109-114) +```python +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': BASE_DIR / 'data/db.sqlite3', + } +} +``` +- **Issue**: SQLite is used as default database - not suitable for production with concurrent access +- **Recommendation**: Configure PostgreSQL or other production-ready database + +### Minor Issues + +**6. TIME_ZONE mismatch** (`/home/adebaumann/development/vgui-cicd/VorgabenUI/settings.py`, lines 139-145) +- **Issue**: `LANGUAGE_CODE = 'de-ch'` but `TIME_ZONE = 'UTC'` - timezone should probably be 'Europe/Zurich' for Swiss deployment +- **File**: `/home/adebaumann/development/vgui-cicd/VorgabenUI/settings.py` (lines 141) + +--- + +## 3. MODELS REVIEW + +### Major Issues + +**1. Missing `verbose_name` on models** - Several models are missing proper `verbose_name` in their Meta class: +- `Stichwort` (`/home/adebaumann/development/vgui-cicd/stichworte/models.py`, lines 4-11) - missing verbose_name +- `Referenz` (`/home/adebaumann/development/vgui-cicd/referenzen/models.py`, lines 6-27) - missing verbose_name +- `Rolle` (`/home/adebaumann/development/vgui-cicd/rollen/models.py`, lines 5-11) - missing verbose_name +- `Person` (`/home/adebaumann/development/vgui-cicd/dokumente/models.py`, lines 22-30) - missing verbose_name +- `Thema` (`/home/adebaumann/development/vgui-cicd/dokumente/models.py`, lines 32-39) - missing verbose_name + +**2. BooleanField with `blank=True` but no default** (`/home/adebaumann/development/vgui-cicd/dokumente/models.py`, line 52) +```python +aktiv = models.BooleanField(blank=True) +``` +- **Issue**: BooleanField should have explicit `default=False` for clarity +- **Recommendation**: Add `default=False` + +**3. No database constraints for date validation** (`/home/adebaumann/development/vgui-cicd/dokumente/models.py`, lines 96-97) +```python +gueltigkeit_von = models.DateField() +gueltigkeit_bis = models.DateField(blank=True,null=True) +``` +- **Issue**: No database-level constraint ensuring `gueltigkeit_bis >= gueltigkeit_von` +- **Recommendation**: Add constraint validation or override `save()` method + +### Minor Issues + +**4. Inconsistent naming in foreign key fields** - Some models use plural related names inconsistently: +- `autoren` and `pruefende` on `Dokument` use plural (correct) +- Could consider singular `related_name` for consistency where applicable + +**5. Missing `related_name` on some ManyToMany fields** (`/home/adebaumann/development/vgui-cicd/dokumente/models.py`, line 289) +```python +autoren = models.ManyToManyField(Person) # Missing related_name +``` +- **Recommendation**: Add `related_name='changelog_entries'` for clarity + +--- + +## 4. VIEWS REVIEW + +### Critical Issues + +**1. No CSRF protection on comment endpoints** (`/home/adebaumann/development/vgui-cicd/dokumente/views.py`, lines 321-377) +```python +@require_POST +@login_required +def add_vorgabe_comment(request, vorgabe_id): + # No @csrf_exempt but also no CSRF token verification in the view +``` +- **Issue**: The view uses `@require_POST` but doesn't verify CSRF tokens for the JSON endpoint +- **Recommendation**: Add `@csrf_exempt` ONLY if intentionally bypassing, or ensure CSRF is handled via the X-CSRFToken header (which is done in the template) + +**Note**: Looking at line 368, the template sends `'X-CSRFToken': getCookie('csrftoken')`, so this is actually properly handled. **Not a bug.** + +**2. XSS in comment display** (`/home/adebaumann/development/vgui-cicd/dokumente/views.py`, lines 305-306) +```python +escaped_text = escape(comment.text).replace('\n', '
') +``` +- **Issue**: Using `escape()` is good, but line breaks are converted to `
` which could still be exploited +- **Note**: The `dangerous_patterns` check at lines 339-343 provides some protection +- **Recommendation**: Consider using a more robust HTML sanitization library + +**3. No input validation on comment length** (`/home/adebaumann/development/vgui-cicd/dokumente/views.py`, line 335) +```python +if len(text) > 2000: # Reasonable length limit +``` +- **Issue**: This is actually properly implemented with a 2000 character limit +- **Status**: OK + +### Major Issues + +**4. Referenz view lacks error handling** (`/home/adebaumann/development/vgui-cicd/referenzen/views.py`, lines 11-19) +```python +def detail(request, refid): + referenz_item = Referenz.objects.get(id=refid) +``` +- **Issue**: `DoesNotExist` exception not caught - will return 500 error instead of 404 +- **Recommendation**: Use `get_object_or_404` for consistency + +### Minor Issues + +**5. Search view allows complex regex patterns** (`/home/adebaumann/development/vgui-cicd/pages/views.py`, lines 36-70) +- **Issue**: The validation is good but the `groupby` usage at line 54 could fail if data is not properly sorted +- **Recommendation**: Add explicit ordering before groupby + +**6. No rate limiting on search** (`/home/adebaumann/development/vgui-cicd/pages/views.py`) +- **Issue**: Search endpoint could be abused for DoS +- **Recommendation**: Add rate limiting + +--- + +## 5. URL CONFIGURATION + +### Minor Issues + +**1. No URL namespace for include** (`/home/adebaumann/development/vgui-cicd/VorgabenUI/urls.py`, lines 31-35) +```python +path('dokumente/', include("dokumente.urls")), +path('stichworte/', include("stichworte.urls")), +``` +- **Issue**: No `app_name` namespace defined in included apps +- **Recommendation**: Add `app_name = 'dokumente'` to `dokumente/urls.py` for cleaner reversals + +**2. Inconsistent trailing slashes** - Most URLs have trailing slashes but not all - ensure consistency + +--- + +## 6. TEMPLATES REVIEW + +### Critical Issues + +**1. XSS vulnerability in `standard_detail.html`** (`/home/adebaumann/development/vgui-cicd/dokumente/templates/standards/standard_detail.html`, lines 163-164) +```html +{% for ref in vorgabe.referenzpfade %} +{{ ref|safe }}{% if not forloop.last %}, {% endif %} +``` +- **Issue**: Using `|safe` on reference paths could allow XSS if malicious content is stored +- **Recommendation**: Use `escape` filter and handle line breaks separately + +**2. JavaScript in template without CSP** (`/home/adebaumann/development/vgui-cicd/dokumente/templates/standards/standard_detail.html`, lines 249-424) +- **Issue**: Inline JavaScript in template +- **Note**: CSP headers are set in the view (line 316-317), but inline scripts violate strict CSP +- **Recommendation**: Move JavaScript to external file + +### Major Issues + +**3. Missing ARIA labels and roles** - Several accessibility issues: +- Base template (`/home/adebaumann/development/vgui-cicd/pages/templates/base.html`) has navigation but missing `aria-label` on some elements +- The mobile navigation could use better ARIA attributes + +**4. Missing alt attributes on images** (`/home/adebaumann/development/vgui-cicd/pages/templates/base.html`, lines 39-41) +```html +Zur Startseite +``` +- **Issue**: alt is present but could be more descriptive +- **Status**: Acceptable + +### Minor Issues + +**5. Hardcoded URLs in templates** (`/home/adebaumann/development/vgui-cicd/dokumente/templates/standards/incomplete_vorgaben.html`, line 21) +```html +
-

Version {{ version|default:"0.980" }}

+

Version {{ version|default:"0.983" }}

diff --git a/referenzen/migrations/0004_alter_referenz_options.py b/referenzen/migrations/0004_alter_referenz_options.py new file mode 100644 index 0000000..a678996 --- /dev/null +++ b/referenzen/migrations/0004_alter_referenz_options.py @@ -0,0 +1,17 @@ +# Generated by Django 6.0.1 on 2026-01-20 08:57 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('referenzen', '0003_alter_referenzerklaerung_options'), + ] + + operations = [ + migrations.AlterModelOptions( + name='referenz', + options={'verbose_name': 'Referenz', 'verbose_name_plural': 'Referenzen'}, + ), + ] diff --git a/referenzen/models.py b/referenzen/models.py index aa99d60..477caff 100644 --- a/referenzen/models.py +++ b/referenzen/models.py @@ -25,6 +25,7 @@ class Referenz(MPTTModel): class Meta: verbose_name_plural="Referenzen" + verbose_name="Referenz" class Referenzerklaerung (Textabschnitt): erklaerung = models.ForeignKey(Referenz,on_delete=models.CASCADE) diff --git a/referenzen/views.py b/referenzen/views.py index 1e1821b..cf2ddfb 100644 --- a/referenzen/views.py +++ b/referenzen/views.py @@ -9,7 +9,7 @@ def tree(request): def detail(request, refid): - referenz_item = Referenz.objects.get(id=refid) + referenz_item = Referenz.objects.get_object_or_404(id=refid) referenz_item.erklaerung = render_textabschnitte(referenz_item.referenzerklaerung_set.order_by("order")) referenz_item.children = list(referenz_item.get_descendants(include_self=True)) for child in referenz_item.children: diff --git a/requirements.txt b/requirements.txt index 5c1cc5f..21fe605 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,37 +1,44 @@ appdirs==1.4.4 -asgiref==3.8.1 -blessed==1.21.0 -certifi==2025.8.3 -charset-normalizer==3.4.3 +asgiref==3.11.0 +bleach==6.3.0 +blessed==1.27.0 +certifi==2026.1.4 +charset-normalizer==3.4.4 +coverage==7.13.1 curtsies==0.4.3 -cwcwidth==0.1.10 -Django==5.2.9 -django-admin-sortable2==2.2.8 +cwcwidth==0.1.12 +Django==6.0.1 +django-admin-sortable2==2.3 django-js-asset==3.1.2 -django-mptt==0.17.0 -django-mptt-admin==2.8.0 -django-nested-admin==4.1.1 +django-mptt==0.18.0 +django-mptt-admin==2.9.0 +django-nested-admin==4.1.6 django-nested-inline==0.4.6 django-revproxy==0.13.0 -greenlet==3.2.4 +greenlet==3.3.0 gunicorn==23.0.0 -idna==3.10 +idna==3.11 jedi==0.19.2 -Markdown==3.8.2 +jproperties==2.1.2 +Markdown==3.10 packaging==25.0 parsedatetime==2.6 -parso==0.8.4 +parso==0.8.5 pep8==1.7.1 -prompt_toolkit==3.0.51 +prompt_toolkit==3.0.52 +pyfakefs==5.9.3 Pygments==2.19.2 +pysonar==1.2.1.3951 python-dateutil==2.9.0.post0 python-monkey-business==1.1.0 pyxdg==0.28 +PyYAML==6.0.3 requests==2.32.5 +responses==0.25.8 six==1.17.0 -sqlparse==0.5.3 +sqlparse==0.5.5 +tomli==2.2.1 urllib3==2.6.3 -wcwidth==0.2.13 -bleach==6.1.0 -coverage==7.6.1 -whitenoise==6.8.2 +wcwidth==0.2.14 +webencodings==0.5.1 +whitenoise==6.11.0 diff --git a/rollen/migrations/0002_alter_rolle_options.py b/rollen/migrations/0002_alter_rolle_options.py new file mode 100644 index 0000000..194072d --- /dev/null +++ b/rollen/migrations/0002_alter_rolle_options.py @@ -0,0 +1,17 @@ +# Generated by Django 6.0.1 on 2026-01-20 08:57 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('rollen', '0001_initial'), + ] + + operations = [ + migrations.AlterModelOptions( + name='rolle', + options={'verbose_name': 'Rolle (für Relevanz)', 'verbose_name_plural': 'Rolleni (für Relevanz)'}, + ), + ] diff --git a/rollen/models.py b/rollen/models.py index f5093ae..14e00fb 100644 --- a/rollen/models.py +++ b/rollen/models.py @@ -9,9 +9,10 @@ class Rolle(models.Model): return self.name class Meta: verbose_name_plural="Rollen" + verbose_name="Rolle" class RollenBeschreibung(Textabschnitt): abschnitt=models.ForeignKey(Rolle,on_delete=models.CASCADE) class Meta: verbose_name_plural="Rollenbeschreibung" - verbose_name="Rollenbeschreibungs-Abschnitt" \ No newline at end of file + verbose_name="Rollenbeschreibungs-Abschnitt" diff --git a/scripts/deploy-django-secret.sh b/scripts/deploy-django-secret.sh deleted file mode 100755 index 5a0c695..0000000 --- a/scripts/deploy-django-secret.sh +++ /dev/null @@ -1,201 +0,0 @@ -#!/bin/bash - -# deploy-django-secret.sh -# Script to generate a secure Django SECRET_KEY and deploy it to Kubernetes - -set -euo pipefail - -# Configuration -NAMESPACE="${NAMESPACE:-vorgabenui}" -SECRET_NAME="vorgabenui-secrets" -SECRET_KEY_NAME="vorgabenui_secret" -K8S_DIR="$(dirname "$0")/../k8s" -SECRET_YAML="$K8S_DIR/django-secret.yaml" - -# Colors for output -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -NC='\033[0m' # No Color - -# Logging functions -log_info() { - echo -e "${GREEN}[INFO]${NC} $1" -} - -log_warn() { - echo -e "${YELLOW}[WARN]${NC} $1" -} - -log_error() { - echo -e "${RED}[ERROR]${NC} $1" -} - -# Function to generate a secure Django SECRET_KEY -generate_secret_key() { - # Generate a 50-character secret key using Python (same as Django's default) - python3 -c " -import secrets -import string - -# Django-style secret key generation -chars = string.ascii_letters + string.digits + '!@#$%^&*(-_=+)' -print(''.join(secrets.choice(chars) for _ in range(50))) -" -} - -# Function to check if kubectl is available -check_kubectl() { - if ! command -v kubectl &> /dev/null; then - log_error "kubectl is not installed or not in PATH" - exit 1 - fi -} - -# Function to check if Python3 is available -check_python() { - if ! command -v python3 &> /dev/null; then - log_error "python3 is not installed or not in PATH" - exit 1 - fi -} - -# Function to create the secret -create_secret() { - local secret_key="$1" - local encoded_key - - # Base64 encode the secret key - encoded_key=$(echo -n "$secret_key" | base64 -w 0) - - log_info "Creating Kubernetes secret '$SECRET_NAME' in namespace '$NAMESPACE'..." - - # Create the secret directly with kubectl - kubectl create secret generic "$SECRET_NAME" \ - --from-literal="$SECRET_KEY_NAME=$secret_key" \ - --namespace="$NAMESPACE" \ - --dry-run=client -o yaml | kubectl apply -f - - - if [ $? -eq 0 ]; then - log_info "Successfully created/updated secret '$SECRET_NAME'" - else - log_error "Failed to create/update secret '$SECRET_NAME'" - exit 1 - fi -} - -# Function to verify the secret -verify_secret() { - log_info "Verifying secret deployment..." - - if kubectl get secret "$SECRET_NAME" --namespace="$NAMESPACE" &> /dev/null; then - log_info "Secret '$SECRET_NAME' exists in namespace '$NAMESPACE'" - - # Show secret (without revealing the actual key) - kubectl describe secret "$SECRET_NAME" --namespace="$NAMESPACE" - return 0 - else - log_error "Secret '$SECRET_NAME' not found in namespace '$NAMESPACE'" - return 1 - fi -} - -# Function to show usage -show_usage() { - echo "Usage: $0 [OPTIONS]" - echo "" - echo "Options:" - echo " -n, --namespace NAMESPACE Kubernetes namespace (default: vorgabenui)" - echo " -s, --secret-name NAME Secret name (default: django-secrets)" - echo " -k, --key-name NAME Secret key name (default: django-secret-key)" - echo " -h, --help Show this help message" - echo "" - echo "Environment variables:" - echo " NAMESPACE Override default namespace" - echo "" - echo "Examples:" - echo " $0 # Deploy to vorgabenui namespace" - echo " $0 -n production # Deploy to production namespace" - echo " NAMESPACE=staging $0 # Deploy to staging namespace" -} - -# Parse command line arguments -while [[ $# -gt 0 ]]; do - case $1 in - -n|--namespace) - NAMESPACE="$2" - shift 2 - ;; - -s|--secret-name) - SECRET_NAME="$2" - shift 2 - ;; - -k|--key-name) - SECRET_KEY_NAME="$2" - shift 2 - ;; - -h|--help) - show_usage - exit 0 - ;; - *) - log_error "Unknown option: $1" - show_usage - exit 1 - ;; - esac -done - -# Main execution -main() { - log_info "Django SECRET_KEY Deployment Script" - log_info "===================================" - log_info "Namespace: $NAMESPACE" - log_info "Secret Name: $SECRET_NAME" - log_info "Secret Key Name: $SECRET_KEY_NAME" - echo "" - - # Perform checks - check_kubectl - check_python - - # Generate new secret key - log_info "Generating new Django SECRET_KEY..." - SECRET_KEY=$(generate_secret_key) - - if [ -z "$SECRET_KEY" ]; then - log_error "Failed to generate secret key" - exit 1 - fi - - log_info "Generated secret key (first 10 chars): ${SECRET_KEY:0:10}..." - - # Create namespace if it doesn't exist - if ! kubectl get namespace "$NAMESPACE" &> /dev/null; then - log_warn "Namespace '$NAMESPACE' does not exist, creating..." - kubectl create namespace "$NAMESPACE" - fi - - # Create the secret - create_secret "$SECRET_KEY" - - # Verify deployment - verify_secret - - echo "" - log_info "Deployment completed successfully!" - log_info "To use this secret in your Django deployment, add the following to your pod spec:" - echo "" - echo " env:" - echo " - name: VORGABENUI_SECRET" - echo " valueFrom:" - echo " secretKeyRef:" - echo " name: $SECRET_NAME" - echo " key: $SECRET_KEY_NAME" - echo "" - log_warn "The old secret key in settings.py has been replaced with environment variable lookup." - log_warn "Make sure your Django deployment uses the environment variable before deploying." -} - -# Run main function -main \ No newline at end of file diff --git a/scripts/deploy_secret.sh b/scripts/deploy_secret.sh index 4af545f..02b90b1 100755 --- a/scripts/deploy_secret.sh +++ b/scripts/deploy_secret.sh @@ -3,7 +3,7 @@ NAMESPACE="vorgabenui" SECRET_NAME="django-secret" -SECRET_FILE="argocd/secret.yaml" +SECRET_FILE="templates/secret.yaml" # Check if secret file exists if [ ! -f "$SECRET_FILE" ]; then diff --git a/stichworte/migrations/0004_alter_stichwort_options.py b/stichworte/migrations/0004_alter_stichwort_options.py new file mode 100644 index 0000000..0eadd15 --- /dev/null +++ b/stichworte/migrations/0004_alter_stichwort_options.py @@ -0,0 +1,17 @@ +# Generated by Django 6.0.1 on 2026-01-20 08:57 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('stichworte', '0003_alter_stichworterklaerung_options'), + ] + + operations = [ + migrations.AlterModelOptions( + name='stichwort', + options={'verbose_name': 'Stichwort', 'verbose_name_plural': 'Stichworte'}, + ), + ] diff --git a/stichworte/models.py b/stichworte/models.py index b4a82dc..4281fd8 100644 --- a/stichworte/models.py +++ b/stichworte/models.py @@ -9,6 +9,7 @@ class Stichwort(models.Model): class Meta: verbose_name_plural="Stichworte" + verbose_name = "Stichwort" class Stichworterklaerung (Textabschnitt): erklaerung = models.ForeignKey(Stichwort,on_delete=models.CASCADE)