Commit Graph

9 Commits

Author SHA1 Message Date
Paperclip CTO
80df6d4baf fix(tests): align dwell tracking user creation with email-only account model
Some checks failed
CI / lint (push) Successful in 5s
CI / test (push) Failing after 29s
CI / build-container (push) Has been skipped
2026-05-18 15:07:37 +02:00
Paperclip CTO
7e7e094fb7 fix(tests): unblock sqlite CI failures in mocks, helpers, and legacy cms route
Some checks failed
CI / lint (push) Successful in 6s
CI / test (push) Failing after 26s
CI / build-container (push) Has been skipped
2026-05-18 15:05:47 +02:00
Paperclip CTO
01661bf5a8 fix: restore CI by fixing lint, test collection, and notification syntax
Some checks failed
CI / lint (push) Successful in 6s
CI / test (push) Failing after 7s
CI / build-container (push) Has been skipped
2026-05-18 14:53:29 +02:00
Paperclip CTO
ca0352fa33 fix(ci): resolve ruff lint violations blocking CI pipeline
- Move `from datetime import timedelta` to top of base.py (E402)
- Add `# noqa: E402` to conditional sentry imports in prod.py (E402)
- Remove unused `import time` and `IsAdminUser` from api/views.py (F401)
- Remove unused `NoReverseMatch` import from tests/test_smoke.py (F401)

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-05-08 07:52:08 +02:00
Paperclip CTO
90f7a78197 feat(TRA-248): WCAG 2.1 AA baseline and de/en i18n framework
Some checks failed
CI / Tests (Python 3.12) (push) Failing after 7m3s
CI / OpenAPI Schema (push) Has been skipped
CI / Lint (push) Failing after 4s
A11y:
- Add alt_text field to MediaAsset and ContentBlock (WCAG 2.1 AA 1.1.1)
- Expose alt_text in MediaAssetSerializer and ContentBlockSerializer so
  frontends can render <img alt="..."> and <video aria-label="..."> correctly
- Migration 0002 adds the two alt_text columns

i18n:
- Add LocaleMiddleware to MIDDLEWARE stack (after SessionMiddleware per Django docs)
- Add LANGUAGES = [("de", ...), ("en", ...)] and LOCALE_PATHS = [BASE_DIR/"locale"]
- Add USE_L10N = True
- Seed locale/de/LC_MESSAGES/django.po and locale/en/LC_MESSAGES/django.po with
  translations for all user-facing API strings (upload errors, notification titles)

Tests (tests/a11y/test_a11y_i18n.py):
- alt_text field round-trip on MediaAsset and ContentBlock
- Serializer exposes and accepts alt_text on create, list, PATCH
- LANGUAGES/LOCALE_PATHS/LocaleMiddleware settings assertions
- Accept-Language header switching smoke test against /api/v1/notifications/

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-07 09:36:31 +02:00
Paperclip CTO
cfa9ad6f53 feat(TRA-236,TRA-238): M2 course domain model and dwell-time tracking
TRA-236 — Course domain model:
- courses/models.py: Course → Module → Lesson → Page hierarchy with UUID
  PKs, ordering fields, required_seconds navigation gate, version tracking,
  and UniqueConstraint per (parent, order) pair
- courses/migrations/0001_initial.py: initial migration (applies cleanly on
  a fresh DB)
- tests/test_course_domain.py: migration smoke, relation integrity, cascade
  delete, ordering, and uniqueness-constraint tests

TRA-238 — Dwell-time tracking:
- tracking/models.py: Enrollment, PageProgress (can_advance property), and
  DwellEvent models appended alongside existing AuditEvent
- tracking/services.py: record_dwell_event, compute_eligible_seconds (pure),
  check_navigation_gate, _recompute_accumulated — reconnect merging within
  RECONNECT_TOLERANCE_SECONDS and anti-idle cap at MAX_VALID_EVENT_SECONDS
- tracking/migrations/0001_initial.py: updated to include all four models
  (AuditEvent, Enrollment, PageProgress, DwellEvent) with FK dependencies
  on courses.Course and courses.Page
- tests/test_dwell_tracking.py: event replay, reconnect tolerance, anti-idle
  cap, gate pass/block, and can_advance DB integration tests

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-05-07 09:11:23 +02:00
Paperclip CTO
686acf259a feat(TRA-246): implement audit logging and compliance controls (M5)
Delivers the append-only audit trail system for all compliance-critical
actions per the TRA-246 acceptance criteria.

- tracking/models.py: AuditEvent model with ORM-level immutability guard
  (save raises on update, delete raises on direct call)
- tracking/audit.py: single record() call point; never raises in production
- tracking/admin.py: read-only Django admin for AuditEvent inspection
- tracking/migrations/0001_initial.py: DB schema with composite indexes
- tracking/serializers.py: PII metadata gating (oidc_sub stripped for
  non-admin callers)
- tracking/views.py: read-only AuditEventViewSet (IsPrivileged + 60/min
  throttle)
- tracking/urls.py: registers audit/events/ router
- tracking/management/commands/prune_audit_log.py: retention enforcement
  command with --dry-run and --class filter; writes access.admin_action
  event on real prune runs
- config/settings/base.py: AUDIT_RETENTION_DAYS per event class + audit
  throttle rate
- api/exceptions.py: wires access.permission_denied audit event on every
  PermissionDenied exception (M1 integration point)
- tests/test_audit.py: 26-event taxonomy coverage, immutability, retention,
  API permission, PII gating, and service helper unit tests

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-05-07 09:11:23 +02:00
Paperclip CTO
1f6a4183d4 feat(TRA-247): M5 security hardening — tests, markers, and header enforcement
- tests/test_security.py: 30 security regression tests covering secure
  headers, CSP directives, middleware ordering, DRF throttle configuration,
  and SecurityAuditMiddleware event-detection logic
- tests/test_upload.py: 19 upload defense tests covering extension allow-list,
  byte-length limits, and magic-byte signature validation (polyglot / disguised
  executable detection)
- pytest.ini: register 'security' and 'upload' markers (--strict-markers
  enforcement was already on)

Security settings already committed in feat(TRA-233) via harness include:
SECURE_REFERRER_POLICY, CSP_* directives, DEFAULT_THROTTLE_*, MAX_UPLOAD_SIZE,
SESSION/CSRF cookie hardening, AWS presigned URL policy, and
SecurityAuditMiddleware with dual-logger (access + security) pattern.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-05-07 09:11:23 +02:00
Paperclip CTO
8054c1e1e4 feat(TRA-233): Django M1 foundation scaffold
- Environment-split settings: base/local/test/prod with django-environ
- Postgres + Redis + Celery wiring (broker, beat, result backend)
- All 9 domain app stubs: accounts, courses, cms, tracking, quizzes,
  training, certificates, reports, notifications
- api app: /healthz/ endpoint, custom DRF exception handler,
  SecurityAuditMiddleware, permissions/throttle/upload-validation stubs
- DRF global baseline: JWT+session auth, closed-by-default permissions,
  cursor/page pagination, drf-spectacular schema generation
- Dockerfile (multi-env build arg), docker-compose.yml (local),
  docker-compose.test.yml (CI-friendly tmpfs Postgres)
- pytest.ini with smoke + settings marker definitions
- tests/test_smoke.py: startup, URL resolution, healthcheck shape
- tests/test_settings_matrix.py: per-profile security assertions
- .github/workflows/ci.yml: test, lint, schema CI jobs
- .env.example with all required vars documented
- .gitignore

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-05-07 09:11:23 +02:00