# Учебный код: от работающего прототипа к проверяемому выпуску

Одно приложение — **журнал учёта машинных носителей информации** — на четырёх стадиях развития. Файлы читаются и запускаются по порядку, каждый следующий отвечает на вопрос, который поставил предыдущий.

Всё работает на **стандартной библиотеке Python**: ни `sqlite3`, ни `unittest` ставить не нужно. Установка требуется только для инструментов пятой пары, и без них занятие проводится полностью.

## Порядок работы

| Файл | Пара | Что показывает | Запуск |
|---|---|---|---|
| `step1_list.py` | 2 | Первая работающая версия: данные в памяти, никаких проверок | `py step1_list.py` |
| `step2_class.py` | 3 | Класс с валидацией: невалидную запись нельзя создать | `py step2_class.py` |
| `languages/` | 3 | Одна задача на четырёх языках из расписания | `py languages/copy_name.py` |
| `step3_defect.py` | 4 | **Образец с четырьмя дефектами. Не трогать** | `py step3_defect.py` |
| `step3_student.py` | 4 | **Ваш рабочий файл.** Копия образца — его и правите | `py step3_student.py` |
| `step3_fixed.py` | 4 | Эталон. Открыть после того, как сделаете сами | `py step3_fixed.py` |
| `test_journal.py` | 5 | 19 проверок эталона — образец зелёного результата | `py -m unittest -v test_journal.py` |
| `test_student.py` | 5 | Те же проверки, но **вашего** файла | `py -m unittest -v test_student.py` |
| `.gitlab-ci.yml` | 5 | Те же команды, запускаемые автоматически | читается |
| `.gitignore` | 2 | Что не должно попадать в репозиторий и почему | читается |

## Предупреждение

> `step3_defect.py` и его копия `step3_student.py` содержат **намеренно оставленные уязвимости** и предназначен только для учебного разбора: SQL-инъекция (CWE-89), выход за пределы каталога (CWE-22), секрет в коде (CWE-798), секрет в журнале (CWE-532). В рабочие проекты этот код не переносится.

## Четыре языка

Каталог `languages/` — одна и та же задача: скопировать строку в буфер на 16 символов.

| Файл | Язык | Запускать? |
|---|---|---|
| `copy_name.asm` | x86-64, NASM | Нет, только читать |
| `CopyName.pas` | Object Pascal | По желанию: `fpc CopyName.pas` или onlinegdb.com |
| `CopyName.cs` | C# / .NET | По желанию: `dotnet run` или dotnetfiddle.net |
| `copy_name.py` | Python | **Да:** `py languages/copy_name.py` |

Собирать первые три на занятии не требуется — ключевая мысль держится на сравнении текстов.

## Контрольный результат эталона

Команды ниже показывают ожидаемый результат на поддерживаемой версии Python 3.x:

```
py step1_list.py            -> таблица из 3 записей
py step2_class.py           -> 3 невалидные записи отклонены
py languages/copy_name.py   -> IndexError перехвачен, срез работает
py step3_defect.py              -> утекло 2 конфиденциальные записи, путь ушёл за каталог
py step3_fixed.py               -> утекло 0, путь отклонён
py -m unittest test_journal.py  -> Ran 19 tests, OK  (эталон)
py -m unittest test_student.py  -> красный, пока не выполнено задание 3
py -m ruff check .              -> замечания только в дефектных образцах
```

Версии опциональных инструментов задаются диапазонами в `requirements-dev.txt`. Перед демонстрацией их доступность нужно проверить командами из этого файла. Bandit на Windows запускается с ключом `-X utf8`: `py -X utf8 -m bandit step3_defect.py`.

## Если Python недоступен

Все задания 1–3 выполняются в браузере на onlinegdb.com или programiz.com. Выпадают git, файловые операции задания 3.4 и все инструменты пятой пары — они показываются с машины преподавателя. Конкретный порядок работы в этом случае подскажет преподаватель.
