Пиков / КАПО
Как читать авторский курс и нормативные материалы

Это учебные материалы, а не заключение о соответствии конкретного продукта. Организационные модели курса отделяйте от терминов стандарта: ППК в опубликованном проекте — машиночитаемый перечень, а живой реестр его версий является практикой сопровождения. Термин OSA в разных материалах имеет разный охват. Статус и обязательность нормативного документа проверяются отдельно; проект КАПО опубликован как проект первой редакции.

П12. ORT и license policy

Зачем эта практика ScanCode отвечает на вопрос «какая лицензия найдена», но не «можно ли с ней выпускаться». OSS Review Toolkit (ORT) добавляет недостающий слой — исполняемую политику: правила на Kotlin DSL, которые из набора лицензий вычисляют нарушения (violations) с уровнем ERROR/WARNING/HINT. Это превращает лицензионный анализ из ручного просмотра в воспроизводимый CI-gate: pipeline падает не потому, что «кому-то не понравился GPL», а потому что сработало записанное правило.

Цель

Прогнать проект через конвейер ORT analyze → scan → evaluate → report со своим файлом политики и получить отчёт, где есть хотя бы одно зафиксированное нарушение (например, strong copyleft в продукте, помеченном как проприетарный) с категорией severity. Проверяемый результат — отчёт ORT и ненулевой код возврата ort evaluate, на котором можно строить CI-gate.

Команда или действие

ort --version

# 1. Построить дерево зависимостей и собрать заявленные лицензии
ort analyze -i . -o out/

# 2. (опц.) досканировать исходники детектором лицензий — точные находки
ort scan -i out/analyzer-result.yml -o out/

# 3. Применить политику: правила превращают лицензии в violations
ort evaluate \
  -i out/scan-result.yml \
  --rules-file curations/rules.kts \
  --license-classifications-file curations/license-classifications.yml \
  -o out/

# 4. Человекочитаемые и машинные отчёты
ort report -i out/evaluation-result.yml -o out/ \
  -f WebApp,CycloneDX,SpdxDocument

Минимальный фрагмент политики (rules.kts) — блокировать strong copyleft в проприетарной поставке:

fun RuleSet.copyleftRule() = packageRule("STRONG_COPYLEFT_IN_DISTRIBUTION") {
    require { -isExcluded() }
    licenseRule("STRONG_COPYLEFT", LicenseView.CONCLUDED_OR_DECLARED_AND_DETECTED) {
        require { isStrongCopyleft() }  // класс из license-classifications.yml
        error(
            "Лицензия ${license} класса strong copyleft в распространяемом компоненте ${pkg.id.toCoordinates()}.",
            "Получить юридическое заключение либо заменить компонент."
        )
    }
}

LicenseView решает, какие лицензии считать CONCLUDED_OR_DECLARED_AND_DETECTED берёт сначала concluded-вердикт (если человек его внёс через curations), иначе declared + detected. Это и есть мост между П11 (detected) и П27 (concluded): курация в ORT поднимает ручной вердикт выше машинной находки, и правило перестаёт срабатывать на уже разобранном кейсе.

Что вы должны увидеть

ort evaluate пишет в stdout сводку и завершается ненулевым кодом при наличии ошибок:

Resolved 248 license findings.
Found 3 rule violations:
  ERROR:   STRONG_COPYLEFT_IN_DISTRIBUTION — GPL-3.0-only in 'NPM::somelib:2.4.1'
  WARNING: WEAK_COPYLEFT_REVIEW — LGPL-3.0-or-later in 'NPM::otherlib:1.0.0'
  HINT:    UNHANDLED_LICENSE — LicenseRef-custom-eula in 'PyPI::vendored:0.9'

Скелет evaluation-result.yml (секция нарушений):

evaluator:
  violations:
  - rule: "STRONG_COPYLEFT_IN_DISTRIBUTION"
    pkg: "NPM::somelib:2.4.1"
    license: "GPL-3.0-only"
    severity: "ERROR"
    message: "Лицензия GPL-3.0-only класса strong copyleft..."

Проверка для CI: после ort evaluate команда echo $? должна вернуть 2 (есть violations с severity ERROR) — именно этот код останавливает pipeline. Если правил нет или классы не заданы, violations будет 0 и gate пропустит copyleft — это ложноотрицательный результат, а не «всё чисто».

Если не получилось

Типичные ошибки - ort: command not found — ORT не установлен. Проще всего запускать официальным образом: docker run --rm -v "$PWD":/project ghcr.io/oss-review-toolkit/ort:latest .... Самостоятельная сборка требует JDK 17+. - analyze находит 0 пакетов — не отработал нужный package manager (нет package-lock.json / go.sum). ORT читает реальные lock-файлы; без них дерево зависимостей пустое. Проверьте секцию analyzer в результате. - violations всегда 0, хотя copyleft в проекте есть — не подключён --license-classifications-file или в нём не размечены классы (isStrongCopyleft() не на что опереться). Правило компилируется, но никогда не истинно. - ort evaluate падает с ошибкой компиляции .kts — синтаксис Kotlin DSL чувствителен к версии ORT; сверьте сигнатуры функций с версией из ort --version, не копируйте правила из старых примеров вслепую.

Критерий зачёта

Показать преподавателю: (1) evaluation-result.yml с минимум одним severity: ERROR; (2) ваш rules.kts и license-classifications.yml (политика, а не дефолт); (3) вывод echo $? после ort evaluate с ненулевым кодом и формулировку, как этот код встроить в CI-шаг (needs/allow_failure: false). Запуск без собственной политики не засчитывается — суть практики именно в policy-driven подходе.

Нормативная связка