Codebase hardening: 102 fixes across 35+ files

Deep audit identified 106 findings; 102 fixed, 4 deferred. Covers 8 areas:

- Settings & deploy: env-gated DEBUG/SECRET_KEY, HTTPS headers, gunicorn, celery worker
- Auth (registered_user): password write_only, request.data fixes, transaction safety, proper HTTP status codes
- Workout app: IDOR protection, get_object_or_404, prefetch_related N+1 fixes, transaction.atomic
- Video/scripts: path traversal sanitization, HLS trigger guard, auth on cache wipe
- Models (exercise/equipment/muscle/superset): null-safe __str__, stable IDs, prefetch support
- Generator views: helper for registered_user lookup, logger.exception, bulk_update, transaction wrapping
- Generator core (rules/selector/generator): push-pull ratio, type affinity normalization, modality checks, side-pair exact match, word-boundary regex, equipment cache clearing
- Generator services (plan_builder/analyzer/normalizer): transaction.atomic, muscle cache, bulk_update, glutes classification fix

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Trey t
2026-02-27 22:29:14 -06:00
parent 63b57a83ab
commit c80c66c2e5
58 changed files with 3363 additions and 1049 deletions

View File

@@ -919,8 +919,8 @@ class Command(BaseCommand):
verbose = options['verbose']
strategy = options.get('classification_strategy', 'rules')
exercises = Exercise.objects.all()
total = exercises.count()
exercises = list(Exercise.objects.all())
total = len(exercises)
updated = 0
stats = {
'is_compound': {'True': 0, 'False': 0},
@@ -938,6 +938,10 @@ class Command(BaseCommand):
if ex.name:
name_to_exercise[ex.name] = ex
# Collect exercises to bulk_update instead of saving one at a time
exercises_to_update = []
fields_to_update = set()
for ex in exercises:
if strategy == 'regex':
from generator.management.commands.classify_exercises import classify_exercise
@@ -1003,7 +1007,9 @@ class Command(BaseCommand):
ex.stretch_position = stretch
if progression_target:
ex.progression_of = progression_target
ex.save()
exercises_to_update.append(ex)
for field, _, _ in changes:
fields_to_update.add(field)
updated += 1
if verbose:
prefix = '[DRY RUN] ' if dry_run else ''
@@ -1011,6 +1017,12 @@ class Command(BaseCommand):
for field, old, new in changes:
self.stdout.write(f' {field}: {old} -> {new}')
# Bulk update all modified exercises in batches
if exercises_to_update and not dry_run:
Exercise.objects.bulk_update(
exercises_to_update, list(fields_to_update), batch_size=500
)
# Fix #11: Correct is_weight=True on known non-weight exercises
NON_WEIGHT_OVERRIDES = ['wall sit', 'agility ladder', 'plank', 'dead hang', 'l sit']
weight_fixed = 0