Артефакт, версия и хэши файлов
Курс «Лаборатория GitLab CI/CD»
Передача dist/ между заданиями предусмотрена описанной конфигурацией, но имя папки не отвечает на вопрос, какой именно результат находится внутри. Два разных pipeline могут создать папки с одинаковыми именами и разным HTML. Теперь разберём метаданные, которые готовый генератор архива уже создаёт: версию исходников, идентификатор pipeline и хэши файлов. На этом шаге также зададим имя и срок хранения артефакта.
Хэш помогает сравнить содержимое, а commit связывает результат с исходниками. Эти значения не взаимозаменяемы. Одна версия исходников может дать разные файлы, если сборка использует меняющиеся внешние данные или окружение. Наша небольшая лаборатория специально ограничивает входы, чтобы связь была понятной и пригодной для разбора.
Происхождение сборки
В полном build.mjs после записи index.html создаётся release.json. Программа читает CI_COMMIT_SHA и CI_PIPELINE_ID из окружения GitLab; при самостоятельном локальном запуске использует явные значения local-not-a-commit и local. Такие подписи не притворяются настоящими сведениями о Git-истории.
{
"schema": 1,
"commit": "COMMIT_SHA_FROM_CI",
"pipeline": "PIPELINE_ID_FROM_CI",
"files": [
{"path": "index.html", "sha256": "EXPECTED_SHA256", "bytes": 1234}
]
}
Это схема ожидаемого файла, а не полученный результат. В реальном самостоятельном запуске значения хэша и размера будут другими. Не копируйте EXPECTED_SHA256 в проверочную программу: build вычисляет его из записанных bytes. Строка commit не вставляется вручную для каждого урока, а читается из контекста конкретной сборки.
Для хэширования используется SHA-256 из встроенного модуля node:crypto. Программа сначала записывает HTML, затем читает его bytes и вычисляет значение. Это важно: метаданные описывают именно файл на диске. Хэш строки до записи мог бы отличаться при дополнительном преобразовании содержимого, поэтому выбираем одну понятную границу результата.
Проверяем тот же файл
verify.mjs читает метаданные из dist/release.json, затем файл dist/index.html, вычисляет SHA-256 и сравнивает с ожидаемым значением. Он также проверяет размер bytes и наличие главных элементов страницы. Новая сборка внутри verify не выполняется. Иначе проверка могла бы оценить собственный свежий HTML, оставив предыдущий артефакт непроверенным.
Измените мысленно одно слово в index.html после build. Содержимое перестанет соответствовать хэшу, даже если страница открывается и выглядит нормально. Ожидаем ошибку verify с указанием файла. Это полезно для понимания целостности передачи: мы ищем незапланированное изменение bytes, а не оцениваем красоту или полноту учебного содержания.
Сам release.json не включаем в список своих же хэшей. Файл, содержащий собственный хэш, потребовал бы специальной схемы, потому что запись значения снова меняет содержимое. Для нашей задачи метаданные описывают полезные файлы каталога. Архив выпуска при необходимости может получать отдельный внешний хэш после упаковки.
Хэш не является цифровой подписью и не доказывает доверие к сборщику. Если злоумышленник изменит и HTML, и метаданные, простая сверка пройдёт. В лаборатории он обнаруживает случайную подмену или повреждение при передаче. Доверие к источнику, runner и правам проекта — отдельная задача, которую нельзя заменить одним контрольным числом.
Имя и срок артефакта
В build job добавьте имя архива с идентификаторами, сохраняя пути предыдущего урока. Имя помогает человеку отличить результаты в интерфейсе, но программы по-прежнему читают известную папку dist/ внутри своего job.
artifacts:
name: 'course-card-$CI_COMMIT_SHORT_SHA-$CI_PIPELINE_ID'
paths:
- dist/
expire_in: 7 days
Переменные в этой настройке раскрываются средствами GitLab Runner. Это не выражение, которое выполняет build.mjs. Не вставляйте shell-команду вычисления имени туда, где ожидается строка конфигурации. У каждого слоя свои правила: YAML, переменные Runner и JavaScript-программа не являются одним общим языком.
Права просмотра артефакта зависят от настроек проекта и GitLab. Для учебной папки мы не сохраняем секретов и не предполагаем общедоступный доступ. Если позже появится закрытый отчёт, его нужно рассматривать отдельно. Подробные варианты сохранения и получения приведены в документации артефактов.
Изменяемое название SITE_TITLE входит в HTML, поэтому одинаковый commit не гарантирует одинаковый хэш при разных значениях параметра окружения. Хэш описывает фактически подготовленные bytes, а commit — только один из входов сборки. В лаборатории сохраняем название в release metadata, чтобы было видно это различие. Для более строгой воспроизводимости понадобился бы полный договор всех входов, включая версию среды и разрешённые параметры. Не расширяем маленький пример до такой системы, но и не называем один commit исчерпывающим доказательством идентичного результата.
Почему кэш не хранит выпуск
Кэш предназначен для повторно используемых промежуточных данных и может отсутствовать. Артефакт сохраняет результат конкретного job. Если build не создал артефакт, verify должен получить понятную ошибку, а не взять случайный старый dist/ из общего cache. Иначе зелёный pipeline может относится к предыдущей версии сайта.
Поэтому не добавляем dist/ в cache:paths. Позже кэш получит отдельную .cache/, а все финальные файлы останутся артефактом. В документации кэширования эти механизмы рассматриваются отдельно. Такое разделение нужно не ради чистоты папок, а для сохранения смысла проверки.
Срок хранения должен учитывать ручную подготовку staging. Если человек нажмёт кнопку после удаления артефакта, система не сможет восстановить именно этот результат только по имени. Можно выполнить новый pipeline для той же версии, но это уже новая работа с собственным ID. В метаданных следует сохранять различие, а не выдавать пересборку за исходный сохранённый файл.
Добавьте к обсуждению два выпуска с одинаковым HTML и разными pipeline ID. Хэши файла совпадают, потому что bytes одинаковы, но метаданные происхождения отличаются. Для анализа содержимого можно сказать, что страницы совпадают; для истории действий нельзя утверждать, что это один запуск. Наоборот, при одном commit и разных SITE_TITLE хэши изменятся: параметр является входом сборки. Поэтому журнал версии должен сохранять достаточно сведений об окружении, влияющем на результат, а не только короткое имя ветки. Наша лаборатория явно записывает title и использует ограниченный набор входов.
Дополнение к внешней отправке
В некоторых старых учебных материалах следующий шаг связан с S3 или другим внешним хранилищем. В нашей лаборатории механизм передачи изучается на локальном job-артефакте. Это собственное дополнение по актуальной документации; оно не описывает выполненную операцию автора и не требует учётной записи AWS. Облачные права и стоимость не нужны для понимания идентичности результата.
На выходе ожидаем release.json, который связывает bytes каталога с commit и pipeline. Программы используют его при проверке и позднее при подготовке staging, сохраняя один результат. Никакие хэши при подготовке курса не вычислялись для запущенного примера: приведённые значения являются схемой. Следующий урок выразит зависимости jobs через needs, чтобы эта передача была видна и в графе работы.