К содержанию
Свобода кода Открытые программные проекты

Аудит зависимостей: lock-файл, NOTICE и SBOM

Статья показывает, как связать исходное дерево, собранный артефакт, lock-файл, SBOM и лицензионные уведомления, не выдавая инвентаризацию за полный аудит безопасности, лицензий или происхождения.

Цепочка поставки Редакция «Свобода кода»
Главная редакционная иллюстрация сверки manifest, lock, build-инвентаря, артефакта, SBOM, LICENSE и NOTICE для одной точной сборки без обещания полного security или legal audit.
Редакционная иллюстрация, созданная с помощью Grok Imagine; не документальная фиксация. Created with Grok.

Аудит зависимостей нужно привязывать одновременно к конкретному исходному дереву и к конкретному собранному артефакту. Манифест показывает заявленное намерение проекта, lock-файл — разрешённые точные версии там, где экосистема действительно поддерживает такое разрешение, инвентаризация во время сборки — компоненты, обнаруженные на пути к выпуску, а SBOM — снимок состава и связей на выбранный момент. После этого файлы LICENSE и NOTICE сверяют не с абстрактным репозиторием, а с тем, что фактически включено в распространяемый пакет.

Практический порядок таков: зафиксировать идентичность исходников и артефакта, разнести зависимости по ролям, получить перечень как можно ближе к сборке, сгенерировать SBOM с указанием версии генератора, сопоставить его с lock-файлом и распакованным дистрибутивом, объяснить различия и отдельно проверить лицензионные уведомления. Результат такого прохода — проверяемая инвентаризация с журналом неизвестного, а не доказательство безопасности, юридической совместимости, происхождения каждого компонента или отсутствия уязвимостей.

Сначала зафиксировать объект проверки

Сравнение списков теряет смысл, если участники называют одним выпуском разные состояния проекта. До чтения манифестов и SBOM нужно записать, какое именно исходное дерево рассматривается, какой lock-файл относится к нему, каким сборщиком и на какой платформе получен артефакт, а также какой файл или набор файлов распространяется. Эта запись образует границу аудита: всё последующее относится только к обозначенной паре «исходники — артефакт».

Для исходной стороны достаточно устойчивого признака, позволяющего повторно открыть то же состояние дерева. Для артефакта нужен признак, позволяющий не перепутать его с другой сборкой. Хеш полезен как подтверждение того, что проверяемые байты совпадают с ранее зафиксированным значением. Он не подтверждает происхождение файла, корректность сборки или безопасность содержимого, поэтому в журнале его следует хранить как идентификатор наблюдаемого объекта, а не как знак доверия.

Входные данные аудита должны быть перечислены явно: манифесты, lock-файлы, сведения о сборщике и платформе, результат инвентаризации во время сборки, SBOM, распакованный артефакт, тексты LICENSE и NOTICE, а также журнал расхождений. Если какого-либо входа нет, это не повод молча заменить его предположением. Отсутствие отмечают как ограничение текущего прохода.

Граница должна сохраняться и при повторной сборке. Если исходное дерево осталось тем же, но изменились lock-файл, сборщик, платформа или упаковка, прежний перечень нельзя автоматически считать перечнем нового артефакта. И наоборот, одинаковое имя выпуска не связывает разные наборы байтов. В журнале поэтому фиксируют не условное название проекта, а конкретные входы и конкретный результат, между которыми выполняется сопоставление.

Разделить компоненты по их роли

Один общий список зависимостей скрывает различия, от которых зависит проверка. Прямой компонент назван проектом явно. Транзитивный приходит через другой компонент. Необязательный включается только при определённом выборе. Зависимость разработки нужна для работы над проектом, но не обязательно попадает в выпуск. Сборочная зависимость участвует в создании артефакта. Встроенный компонент поставляется внутри дистрибутива. Эти признаки не следует выводить только из названия пакета: роль подтверждается тем, где и как компонент наблюдается.

Отдельно нужно оставить место для системных, вручную вложенных, подключаемых и динамически загружаемых компонентов. Они могут не появиться в lock-файле. Плагин может разрешаться вне обычного дерева пакетов, системная библиотека — предоставляться платформой, вручную вложенный код — храниться прямо в исходниках, а динамический компонент — определяться только при выполнении. Наличие такой категории ещё не доказывает, что компонент попал в выпуск; оно лишь предотвращает ложный вывод, будто lock-файл исчерпывает все возможные источники.

  • Прямые и транзитивные: показать путь, по которому компонент входит в дерево.
  • Необязательные: записать условие, при котором они включаются.
  • Разработка и сборка: отделить участие в процессе от присутствия в дистрибутиве.
  • Встроенные: подтвердить наличие внутри распространяемых байтов.
  • Системные, подключаемые и динамические: отметить источник сведений и предел наблюдаемости.

Не приравнивать манифест к готовой сборке

Манифест удобен как описание намерения: он показывает заявленные зависимости и правила их выбора. Но диапазон версии, необязательная ветка или условие платформы ещё не говорят, какая точная версия оказалась в конкретном выпуске. Поэтому манифест нельзя использовать как окончательный перечень содержимого артефакта.

Lock-файл обычно ближе к точному разрешению прямых и транзитивных версий в тех экосистемах, которые записывают такие данные. Однако это не универсальная гарантия. Его полнота зависит от поддерживаемого формата и способа сборки. Компоненты, разрешаемые только во время сборки, предоставляемые системой, вложенные вручную, подключаемые как плагины или загружаемые динамически, могут остаться за его пределами.

Поэтому наблюдаемые списки нужно читать как разные свидетельства. Манифест отвечает на вопрос «что проект намерен использовать». Lock-файл — «что разрешено и зафиксировано данным механизмом». Инвентаризация во время сборки — «что увидел процесс создания артефакта». Распакованный дистрибутив — «какие файлы и вложенные компоненты можно наблюдать после сборки». Ни один слой не заменяет остальные.

Генерировать SBOM рядом с артефактом

SBOM полезен, когда его происхождение понятно. В журнале нужно сохранить, из какого источника данных он создан, для какого состояния исходников и артефакта, на каком этапе, каким генератором и какой версией генератора. Чем ближе этот этап к фактической упаковке, тем меньше промежуток, в котором состав мог измениться без отражения в перечне.

Версия генератора нужна не как формальность. При повторной проверке она помогает отделить изменение наблюдаемого состава от изменения способа, которым этот состав был описан. Если новый SBOM отличается от прежнего, сначала сопоставляют исходники, артефакт, источник данных и генератор, а уже затем называют разницу изменением зависимостей. Без такой записи два снимка могут выглядеть сопоставимыми, хотя получены из разных областей наблюдения.

В SBOM ожидают увидеть компоненты, версии, идентификаторы пакетов и связи между ними; в зависимости от источника могут присутствовать лицензионные сведения, пути транзитивных зависимостей и сведения об авторских правах. Неизвестное поле, отсутствующая версия или неразрешённая связь должны оставаться неизвестными. Заполнять их догадкой ради внешней полноты нельзя, потому что это превращает пробел в неподтверждённое утверждение.

SBOM исходного дерева и SBOM двоичного артефакта могут различаться без ошибки. В двоичной сборке могут появиться сгенерированные или встроенные компоненты, а часть зависимостей разработки может не попасть в дистрибутив. Такое различие требует объяснения, но само по себе не доказывает дефект.

SBOM следует считать зафиксированным представлением доступных данных, а не исчерпывающей картой всего, что существует вокруг проекта.

Сопоставить три наблюдаемых слоя

Основная проверка начинается после получения SBOM. Для каждого компонента сравнивают запись в lock-файле, запись в SBOM и признаки в распакованном артефакте. Цель не в том, чтобы заставить списки совпасть любой ценой, а в том, чтобы каждое различие получило проверяемое объяснение или осталось явно обозначенным неизвестным.

  1. Найти компонент, присутствующий в lock-файле, но отсутствующий в SBOM, и проверить, относится ли он только к разработке, сборке, необязательной ветке или действительно потерян генератором.
  2. Найти компонент в SBOM, которого нет в lock-файле, и проверить сборочные, системные, встроенные, подключаемые и динамические источники.
  3. Найти признаки компонента в артефакте, которого нет в обоих списках, и записать путь к наблюдаемым байтам и возможный источник включения.
  4. Сверить точные версии там, где они указаны, не заменяя конфликт более широким диапазоном из манифеста.
  5. Отметить записи без версии, идентификатора, связи или понятного происхождения как незавершённые, а не как автоматически допустимые.

Журнал расхождений должен содержать наблюдение, использованное свидетельство, объяснение, оставшееся неизвестное и решение по текущему проходу. Полезные состояния просты: различие объяснено; различие подтверждено, но требует изменения сборки или описания; данных недостаточно; компонент не относится к распространяемому артефакту. Такая запись позволяет повторить проверку после изменения входов и не смешивать факт с выводом.

Перед закрытием расхождения нужно указать не только итоговую пометку, но и границу объяснения. Например, запись о зависимости разработки объясняет её отсутствие в артефакте лишь тогда, когда это подтверждается наблюдаемым составом выпуска; пометка «сборочная» не доказывает, что компонент не был встроен. Если свидетельство отвечает только на часть вопроса, оставшаяся часть сохраняется отдельно. Так журнал не превращает удобную классификацию в замену фактической проверки.

Проверить LICENSE и NOTICE по фактическому содержимому

Лицензионный проход начинается только после того, как состав дистрибутива хотя бы рабоче описан. Проверять уведомления по манифесту недостаточно: в нём могут быть зависимости, не вошедшие в выпуск, а двоичный пакет может содержать дополнительные компоненты. Для каждого фактически встроенного компонента нужно связать точную версию, наблюдаемый текст лицензии, требуемые уведомления и место, где они представлены в распространяемом наборе.

Метаданные пакета с названием лицензии полезны как указатель, но не заменяют чтение точного текста и проверку права распространения конкретного содержимого. Одно и то же краткое обозначение не отвечает на вопросы о фактическом файле, исключениях, дополнительных уведомлениях или соответствии версии компонента. Если точный текст не найден, в журнале остаётся пробел, а не догадка.

NOTICE нельзя превращать в универсальный перечень всего обнаруженного. Такой файл существует не для каждой лицензии, а его назначение и обязательность зависят от точного текста и конкретного дистрибутива. Встроенные и невстроенные зависимости также не следует обрабатывать одинаково без основания. Проверяемый критерий здесь один: LICENSE и NOTICE должны соответствовать тем компонентам и версиям, которые действительно поставляются, в пределах применимых к ним требований.

Разнести инвентаризацию, уязвимости и лицензионный вывод

После согласования состава можно проводить отдельный проход по известным уязвимостям. У него собственные входы, момент проверки и ограничения. Отсутствие предупреждения не доказывает отсутствие известной или неизвестной уязвимости, а неполный SBOM сужает область поиска. Поэтому результат формулируют как проверку указанного перечня на выбранный момент, а не как обещание безопасности.

Лицензионный обзор также ведут отдельно. Инвентаризация помогает найти компоненты и точные версии, но сама не устанавливает юридическую совместимость и не подтверждает право распространения. Для такого вывода требуются дополнительные свидетельства и чтение точных текстов. То же относится к происхождению: совпадающий хеш и запись в SBOM не доказывают, откуда получены байты и кто контролировал путь их появления.

Разделение проходов делает границы видимыми. Один журнал отвечает за состав, другой — за проверку уязвимостей, третий — за лицензионные вопросы и уведомления. Между ними можно ссылаться на один и тот же идентификатор компонента, но нельзя переносить вывод из одного прохода в другой без отдельного основания.

Критерий остановки и повторный запуск

Инвентаризационный проход можно остановить, когда зафиксированы исходники и артефакт, классифицированы наблюдаемые компоненты, сохранены версия и источник SBOM, а каждое расхождение между lock-файлом, SBOM и распакованным дистрибутивом либо объяснено свидетельством, либо оставлено как явно записанное неизвестное. Дополнительно LICENSE и NOTICE должны быть сверены с фактически включёнными компонентами настолько, насколько позволяют доступные тексты и данные.

Этот критерий не означает, что проект безопасен, юридически совместим или имеет полностью доказанное происхождение. Он означает только, что текущий проход инвентаризации завершён без скрытых расхождений: известные пробелы названы, а область вывода ограничена конкретным артефактом.

Аудит повторяют после изменения исходного дерева, lock-файла, сборщика, платформы или состава дистрибутива. Новый запуск не должен перезаписывать старый результат без следа. Сохранённая пара идентичностей, версия генератора и журнал различий позволяют увидеть, что именно изменилось и почему прежний вывод больше нельзя автоматически переносить на новый выпуск.

Минимальная запись результата

Итоговая запись может быть короткой, если она сохраняет проверяемость. В ней указывают объект проверки, входные данные, способ получения SBOM, классификацию компонентов, список объяснённых и необъяснённых различий, состояние LICENSE и NOTICE, а также отдельные ограничения проверки уязвимостей, лицензий и происхождения.

  • Объект: какое исходное дерево и какой артефакт проверены.
  • Состав: какие перечни использованы и где остаются неизвестные компоненты или версии.
  • Сопоставление: какие различия между lock-файлом, SBOM и артефактом объяснены.
  • Уведомления: как LICENSE и NOTICE связаны с фактически включёнными компонентами.
  • Границы: какие выводы не делаются о безопасности, юридической совместимости и происхождении.
  • Повторная проверка: какие изменения требуют нового прохода.

Такой результат не пытается выглядеть полным аудитом всего проекта. Его ценность в другом: любой последующий проверяющий видит, какие байты рассматривались, откуда взяты списки, где они расходятся, чем объяснены решения и какие вопросы остались открытыми.

Что важно учитывать

  • Манифест отражает намерение проекта и не является точным перечнем компонентов конкретного артефакта.
  • Lock-файл даёт точные версии только в пределах поддерживаемой экосистемы и может не охватывать сборочные, системные, встроенные, подключаемые или динамически загружаемые компоненты.
  • Инвентаризация во время сборки отражает только то, что смог увидеть применённый способ наблюдения.
  • Полнота SBOM зависит от источника данных, этапа генерации, возможностей и версии генератора; отдельные поля могут остаться неизвестными.
  • SBOM исходного дерева и SBOM двоичного артефакта могут различаться из-за сгенерированных и встроенных компонентов.
  • Лицензионные метаданные пакета не заменяют точный текст лицензии и проверку права распространения конкретного содержимого.
  • NOTICE не является универсальным файлом; его назначение и требования зависят от точной лицензии и состава дистрибутива.
  • Отсутствие предупреждения об уязвимости не доказывает безопасность или отсутствие известных и неизвестных уязвимостей.
  • Хеш подтверждает совпадение байтов с известным значением, но не подтверждает их происхождение или безопасность.
  • Согласованная инвентаризация не является полным аудитом безопасности.
  • Сопоставление компонентов и уведомлений не является универсальным юридическим выводом о совместимости или праве распространения.
  • Записи в lock-файле и SBOM сами по себе не образуют полный аудит происхождения компонентов.

Факты и границы материала проверены редакцией на дату обновления.

Как подготовлен материал: редакция сопоставила внутренний реестр первичных и дополнительных источников и использовала ИИ при подготовке текста. Факты проверены по материалам реестра. Подписанные AI-иллюстрации объясняют этапы и не являются фотографиями испытания или доказательством результата.