Отделите метаданные сборки от исполняемого кода

ShellBeginner
Практиковаться сейчас

Введение

Участник предлагает изменение кода с заголовком и описанием. Задание сборки превращает эти метаданные в предварительный артефакт. Непрерывная интеграция (CI) означает автоматический запуск таких заданий при поступлении изменений. Исполнитель — программа, выполняющая задание. Здесь вы сами запускаете предоставленный небольшой локальный исполнитель.

Все люди и события вымышлены. Исполнитель запускает настоящий Bash в одноразовом контейнере без сети и реквизитов развёртывания. production в release.conf — локальное тестовое значение, не вызывающее публикацию. Практикум моделирует подстановку текста и выполнение shell, а не триггеры или права облачного CI. CI Workshop — ваш терминал обслуживания; Topology объясняет поток и после обновления показывает реальные каналы запусков.

Вы выполните обычную сборку, проследите инъекцию в скрипт, измените два коротких файла и повторно проверите точность метаданных. Достаточно базового знакомства с терминалом; необходимый JSON и синтаксис Bash объясняются до использования.

Выполните обычную сборку

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

Чтобы начать этот шаг, выберите вкладку CI Workshop в интерфейсе лабораторной работы.

Перейдите на вкладку CI Workshop. pwd выводит текущий каталог; ls перечисляет файлы. Рабочая область — /home/labex/project/ci-workshop.

Перед выполнением следующей команды перейдите на вкладку CI Workshop.

pwd
ls

cat показывает текстовый файл. Объект JSON заключает именованные поля в фигурные скобки; двоеточие связывает имя с значением. Строки используют двойные кавычки. Внутри строки \n обозначает перевод строки. Прочитайте обычное событие:

cat events/ordinary.json

Его title равен Improve search results. body — многострочное описание. Это данные участника, поэтому сборка не должна доверять им как командам.

Прочитайте небольшое определение задания и его скрипт:

cat job.json
cat build.sh
Элемент Значение в локальном исполнителе
script Исполняемый файл Bash, сейчас build.sh
env Сопоставление имён окружения со строками; сейчас пустое {}
{{event.title}} Заменить этот точный шаблон заголовком до запуска Bash
{{event.body}} Такая же подстановка описания
artifact.txt Созданный сборкой файл метаданных
release.conf Канал, инициализируемый как preview для каждого запуска

Bash читает инструкции оболочки. TITLE="..." присваивает значение переменной; вокруг = пробелы запрещены. "$TITLE" раскрывает значение как один аргумент с сохранением пробелов и переводов строк. printf '%s' выводит строку без дополнительного перевода; одинарные кавычки сохраняют %s буквально. > перенаправляет вывод в файл, заменяя его содержимое. Точка с запятой разделяет команды. set -euo pipefail останавливает скрипт при типичных ошибках команд, неопределённых переменных и конвейеров, но не предотвращает инъекцию.

ci — команда подготовленного исполнителя. run принимает имя события без .json и новое имя выходного каталога. Каждый запуск начинает с новой конфигурации preview:

ci run ordinary first

Ожидаются channel=preview и exit=0. Ноль означает успешное завершение Bash. Посмотрите сгенерированный скрипт, артефакт и конфигурацию через show:

ci show first

Артефакт отображается как строка JSON, "Improve search results", чтобы далее можно было увидеть невидимые переводы строк. Это настоящее содержимое файла, а не имитация успешного результата. Последний раздел должен показывать preview. Перейдите на вкладку Topology и обновите страницу: её строка first читает тот же файл конфигурации.

Повторный run с именем first намеренно сообщает о существующем каталоге, сохраняя старые результаты. Выберите новое имя, например first-again. Неудачный запуск также сохраняет сгенерированный скрипт и build.log в runs/NAME для диагностики.

Проследите опасную подстановку

На этом шаге вы увидите превращение данных в исполняемый код и изменение канала внутри изолированного демонстрационного запуска.

Чтобы начать этот шаг, выберите вкладку CI Workshop в интерфейсе лабораторной работы.

Поток: событие → задание → сгенерированный shell-код → Bash → артефакт. Опасна подстановка до разбора кавычек Bash. Двойные кавычки защищают раскрытие переменной в уже разобранной команде, но не исходное значение, вставленное в код до разбора.

Прочитайте предоставленное безвредное демонстрационное событие:

Перед выполнением следующей команды перейдите на вкладку CI Workshop.

cat events/hostile.json

title содержит двойную кавычку, точку с запятой, printf, ещё одну точку с запятой и #. В Bash кавычка завершает исходную строку, точка с запятой начинает новую команду, а # комментирует остаток строки. Этот printf меняет только синтетическую release.conf данного запуска. \" в JSON кодирует кавычку, но не делает её безопасной при последующей вставке в shell-код.

Запустите событие в новом рабочем каталоге:

ci run hostile demo
ci show demo

Ожидайте channel=production, хотя исполнитель начал с preview. В generated.sh найдите вставленный printf между точками с запятой: Bash действительно выполнил его. Артефакт может содержать лишь Update, потому что остальной текст стал синтаксисом вместо заголовка. Это и нужно исправить.

Каталог demo отделён от first; ни один запуск не изменяет job.json или build.sh. Перейдите на вкладку Topology и обновите страницу, чтобы сравнить фактические каналы. Строка production означает изменённые учебные данные, а не настоящий релиз. Не выполняйте текст события вручную в своей оболочке обслуживания.

Topology сравнивает каналы обычного запуска и уязвимой демонстрации

Общий риск описан в документации GitHub об инъекциях в скрипты. Наши шаблоны и формат задания намеренно меньше GitHub Actions; общий механизм — подстановка перед разбором.

Передайте значение как данные

На этом шаге вы исключите текст участника из исходного shell-кода, сохранив пробелы, кавычки и несколько строк.

Чтобы начать этот шаг, выберите вкладку CI Workshop в интерфейсе лабораторной работы.

Переменная окружения — именованная строка, передаваемая новому процессу. Сопоставление env задаёт её напрямую, не создавая shell-присваивание. В JSON это ещё один объект в фигурных скобках. Задайте BUILD_TITLE из {{event.title}}, а Bash пусть раскрывает "$BUILD_TITLE" во время выполнения. Кавычки, точки с запятой, $() и обратные кавычки внутри раскрытого значения не интерпретируются как новые команды. Не применяйте eval и не передавайте значение в bash -c: они разберут его снова.

Заменим два файла с помощью here-document. cat > filename <<'JSON' записывает следующие строки до строки, содержащей только JSON. Кавычки вокруг ограничителя запрещают оболочке обслуживания раскрывать $ и другой синтаксис. Копируйте блок целиком, включая завершающий ограничитель. Он заменяет весь файл, поэтому помогает восстановиться после опечаток.

Перед выполнением следующей команды перейдите на вкладку CI Workshop.

cat > job.json <<'JSON'
{
  "script": "build.sh",
  "env": {
    "BUILD_TITLE": "{{event.title}}"
  }
}
JSON

Теперь замените скрипт. Ограничитель BASH имеет тот же смысл буквальной записи. Скрипт напрямую использует окружение и больше не содержит шаблон участника.

cat > build.sh <<'BASH'
set -euo pipefail
printf '%s' "$BUILD_TITLE" > artifact.txt
printf 'channel='; cat release.conf
BASH

Перечитайте оба файла знакомой командой cat. Пропущенная запятая или скобка вызывает ошибку JSON; неверное имя окружения — ошибку неопределённой переменной. Полностью повторите нужный блок и попробуйте снова. Старый запуск относится к старому скрипту, поэтому выберите новое имя:

ci run ordinary repaired
ci show repaired

Сгенерированный код теперь содержит "$BUILD_TITLE", а не символы заголовка. Артефакт по-прежнему содержит Improve search results, канал — preview.

Перед проверкой прочитайте примеры пунктуации и нескольких строк:

cat events/quotes.json
cat events/multiline.json

\n в JSON означает реальный перевод строки; последний \n тоже должен сохраниться. Апостроф в O'Brien и двойные кавычки в заголовке — допустимые данные. Тем же способом передаётся многострочный body: ссылка меняется на {{event.body}}, правило кавычек вокруг переменной остаётся прежним. Это пригодится в испытании с примечаниями к выпуску.

ci test normal выполняет неизменённые отправленные задание и скрипт с обычными, пунктуационными и многострочными событиями в одноразовых временных каталогах. Он сравнивает точные байты и проверяет preview. Удаляются только эти каталоги; отправленные файлы и сохранённые запуски остаются неизменными.

ci test normal

Для каждого примера ожидается exact metadata; channel=preview. Удаление пунктуации, склеивание строк, фиксированный заголовок, отказ всем событиям или пропуск сборки провалят проверку полезной функции. Ошибка называет пример: прочитайте его и исправьте два файла перед повтором.

Повторно проверьте границу сборки

На этом шаге вы подтвердите, что исправленное задание сохраняет обычные метаданные и предотвращает показанный побочный эффект.

Чтобы начать этот шаг, выберите вкладку CI Workshop в интерфейсе лабораторной работы.

Повторите вредоносный пример с новым именем вывода:

Перед выполнением следующей команды перейдите на вкладку CI Workshop.

ci run hostile repaired-hostile
ci show repaired-hostile

Теперь артефакт должен содержать весь вредоносный заголовок как текст. В JSON-представлении видны точки с запятой и кавычки, а release.conf остаётся preview. Старые результаты demo не меняются: это другой рабочий каталог.

Другой пример содержит $() и обратные кавычки — формы подстановки команд, если они записаны в shell-коде. В раскрытом значении окружения в двойных кавычках эти символы остаются данными. Прочитайте пример:

cat events/substitution.json

Проверьте все пять примеров с теми же отправленными файлами:

ci test all

ordinary, quotes, multiline, hostile и substitution должны сохранить точные метаданные и preview, после чего появится сообщение об очистке. Проверяются реальное выполнение Bash и выходные файлы, а не фраза журнала или выдуманное secure=true. Проверка завершения повторяет временные тесты без изменений задания, скрипта и сохранённых запусков.

Если сбой остаётся только во враждебном случае, проверьте, остались ли в файле оболочки шаблоны событий или повторный разбор переменной. Если не проходят пунктуация или многострочный текст, проверьте printf '%s' с переменной в двойных кавычках. Не удаляйте проблемные входные данные: корректная обработка законных метаданных — часть результата. Перейдите на вкладку Topology и обновите страницу, чтобы увидеть исправленный враждебный запуск рядом с прежней демонстрацией.

Topology показывает, что исправленный запуск сохраняет канал preview

Резюме

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