# ===========================================================================
#  Учебный конвейер РБПО для журнала учёта МНИ — КОНВЕЙЕР ЭТАЛОНА.
#
#  Важно понимать, ЧТО он проверяет: эталонный код лекции. Файлы
#  step3_defect.py и step3_student.py из проверок исключены — первый обязан
#  содержать дефекты, второй в стартовом состоянии их тоже содержит.
#
#  Если вы захотите проверять этим конвейером СВОЮ работу, уберите
#  step3_student.py из списка исключений в шагах lint и sast и добавьте
#  запуск test_student.py в шаг test. Пока задание 3 не сделано, конвейер
#  будет красным — и это правильное поведение.
#
#  Здесь нет ничего, чего вы не вводили руками на занятии. Это ровно те же
#  команды — просто записанные так, чтобы GitLab запускал их сам при каждом
#  изменении кода.
#
#  В этом и состоит вся идея непрерывной интеграции: проверки выполняются
#  не тогда, когда о них вспомнили, а всегда.
# ===========================================================================

stages:
  - lint        # стиль и очевидные ошибки
  - test        # поведение программы
  - security    # опасные конструкции и уязвимые зависимости

default:
  image: python:3.12@sha256:3b524c305ebbec824b8b8f65b72d0f82527eae50c32998160f0a9fca5337f594
  before_script:
    - python -m pip install --upgrade pip
    - python -m pip install -r requirements-dev.txt

# --- Шаг 1. Линтер --------------------------------------------------------
# Стиль, мёртвый код, опечатки. Уязвимостей не ищет и не должен.
lint:
  stage: lint
  script:
    - ruff check . --exclude step3_defect.py --exclude step3_student.py
  # step3_defect.py и step3_student.py исключены: это учебные образцы,
  # они ОБЯЗАНЫ содержать дефекты, и линтер честно находит в них
  # неиспользуемую переменную. Исключение стоит здесь, в конфигурации
  # конвейера, а не в самом файле: на занятии слушатель запускает
  # `ruff check step3_defect.py` вручную и должен увидеть находку своими
  # глазами. Правило простое — глушить проверку в коде можно только там,
  # где находка действительно ложная.

# --- Шаг 2. Тесты ---------------------------------------------------------
# Функциональные тесты и регрессионные тесты безопасности.
# Это ЖЁСТКИЙ quality gate: красные тесты останавливают всё.
test:
  stage: test
  script:
    - python -m unittest -v test_journal.py

# --- Шаг 3. Статический анализ безопасности (SAST) ------------------------
# Ищет опасные конструкции языка: склейку SQL, секреты в коде,
# небезопасные вызовы. Процесс 5.10 ГОСТ Р 56939-2024.
sast:
  stage: security
  script:
    - bandit -r . -x ./step3_defect.py,./step3_student.py
  # step3_defect.py исключён намеренно: это учебный образец с дефектами,
  # он обязан их содержать. В реальном проекте каждое такое исключение
  # согласуется и обосновывается письменно — иначе список исключений
  # за год разрастается так, что анализатор перестаёт что-либо проверять.

# --- Шаг 4. Композиционный анализ (SCA) -----------------------------------
# Проверяет ЧУЖОЙ код — зависимости — по базам известных уязвимостей.
# Процесс 5.16 ГОСТ Р 56939-2024.
sca:
  stage: security
  script:
    - pip-audit --requirement requirements-dev.txt
  # allow_failure: true означает «предупреждать, но не останавливать».
  # Так делают на старте внедрения, пока команда разбирает накопленный долг
  # по зависимостям. Оставлять это состояние навсегда — самообман:
  # отчёт, который ничего не останавливает, довольно быстро перестают читать.
  allow_failure: true

# ===========================================================================
#  ВОПРОС К ЗАНЯТИЮ (задание 4, шаг 4.7)
#
#  Какой шаг обязан останавливать сборку, а какой может только предупреждать?
#
#  Разбор:
#    lint  — на старте можно сделать предупреждающим, но быстро переводят
#            в блокирующий: иначе замечания копятся и обесцениваются.
#    test  — всегда блокирующий. Красный тест означает, что программа
#            делает не то, что заявлено. Выпускать такое нельзя.
#    sast  — блокирующий по находкам высокой критичности.
#    sca   — часто начинают с предупреждающего, потому что уязвимость
#            в чужой библиотеке не всегда можно закрыть сегодня.
#
#  Шаг, отрицательный результат которого останавливает сборку, называется
#  quality gate. Конвейер без единого quality gate — это не конвейер,
#  а генератор отчётов.
# ===========================================================================
