Введение
Проверенная поставка полезна лишь тогда, когда работающий выпуск использует именно проверенные байты. Waymark нужен многократно используемый скрипт приёма, который отклоняет неодобренный пакет до изменения путеводителя по прогулкам фестиваля.
Вы замените короткий shell-скрипт, испытаете его решения об отказе и опубликуете запрошенное организатором обновление. Эта независимая среда начинается с исходного путеводителя и собственных пакетов. В предыдущем занятии вы изучили подписи, независимо доверенные ключи, запрошенные метаданные и хеши архивов. Теперь вы объедините их; программирование на Python не потребуется.
Изучите работающий путеводитель и контракт скрипта приёма
На этом шаге вы определите, что обновление должно изменить, а что сохранить. Откройте Event Guide, затем Old Mill Walk. Исходная редакция event-guide — 2.0, время встречи — 11:00. Вернитесь через All walks и скачайте маршрутный лист. После обновления должны работать и страница описания, и скачивание.
На главной странице путеводителя редакция указана над заголовком, а время встречи каждой прогулки — на её карточке:

Переключитесь на Workspace. cd меняет каталог; этот абсолютный путь работает из любого места:
cd /home/labex/project/waymark
cat выводит файлы. Прочитайте независимо предоставленный запрос на обновление:
cat /opt/labex-waymark/trust/request.json
Он запрашивает продукт event-guide, версию 2.1. Одобренное обновление переносит встречу Old Mill Walk на 14:00. Другая прогулка остаётся в 09:30. Прочитайте начальный скрипт:
cat receive.sh
Начальный скрипт берёт хеш из самого пакета и передаёт его программе публикации. Другой издатель тоже может предоставить согласованные манифест и архив. Этот скрипт пока не проверяет ни подпись, ни запрошенные организатором продукт и версию. Вы замените его перед публикацией.
Обязательный интерфейс:
bash receive.sh CANDIDATE_DIRECTORY DESTINATION_DIRECTORY
Первый аргумент — один пакет поставщика. Второй — каталог публикации путеводителя; в работающем проекте это published. Оба пути могут быть абсолютными или относительными, переименованными и содержать пробелы. Не задавайте метку пакета или каталог назначения жёстко в скрипте. Успешное обновление возвращает ноль. Отказ возвращает ненулевой код и оставляет все существующие файлы публикации неизменными. Допустимое обновление сохраняет предыдущие выпуски и посторонние загруженные файлы.
Вы можете редактировать receive.sh и создавать временные файлы. Не меняйте исходные пакеты, независимые ключ и запрос, подготовленную программу публикации и другие файлы среды. Скрипт приёма должен работать из другого каталога при копировании только самого скрипта, если доступны те же подготовленные инструменты и независимые файлы доверия. Проверка испытывает этот контракт на одноразовых каталогах, а также проверяет настоящий путеводитель.
При опечатке в пути выполните приведённую выше абсолютную команду cd, проверьте метки через ls candidates и повторите команду. Неудачная проверка — повод изучить соответствующие свидетельства, а не сбрасывать среду.
Спроектируйте скрипт приёма, останавливающийся до публикации
На этом шаге вы разберёте короткий скрипт, прежде чем написать его. Оставайтесь в Workspace.
Скрипт скопирует все три связанных файла в закрытый временный каталог, проверит скопированный манифест, сравнит его продукт и версию с независимым запросом и передаст скопированный архив вместе с подписанным хешем подготовленной программе публикации. Он никогда не будет проверять один пакет, а затем заново открывать другой путь к пакету для поставки.
Программа публикации /opt/labex-waymark/publish.py — подготовленный код обработки архивов. Она читает переданный архив в один байтовый буфер, проверяет этот буфер по переданному хешу, безопасно извлекает только site.json и routes.csv и публикует те же байты. Она сохраняет предыдущие выпуски и uploads/. Она не решает, чьей подписи доверять и какие продукт и версию запросил организатор; эти решения принадлежат вашему скрипту приёма.
Вы будете использовать следующие возможности оболочки:
#!/bin/bashуказывает оболочку скрипта. Запускbash receive.shтакже явно выбирает Bash.set -euo pipefailостанавливает скрипт при необработанной ошибке команды, неопределённой переменной или ошибке конвейера. После неудачной проверки подписи выполнение ни в коем случае не должно доходить до публикации.$1и$2— два аргумента.candidate=$1сохраняет значение;"$candidate"разворачивает его в один аргумент, включая пробелы.$#считает аргументы, а[ "$#" -ne 2 ]проверяет, что их число не равно двум.if,thenиfiограничивают условный блок.$(command)сохраняет вывод команды.mktemp -dсоздаёт уникальный временный каталог.trap '...' EXITвыполняет очистку при завершении скрипта. Здесьrm -rf -- "$stage"удаляет только этот созданный временный каталог; никогда не подставляйте каталог проекта.--завершает разбор параметров, чтобы путь считался данными.cp -- SOURCE SOURCE SOURCE DIRECTORY/копирует три файла. Последняя косая черта обозначает каталог назначения.jq -r .product FILEчитает строку JSON без кавычек JSON.jq -eвозвращает код ошибки для ложного результата.--arg product "$product"передаёт фильтру строковую переменную$product.andтребует выполнения каждого условия. Одинарные кавычки сохраняют текст фильтра для jq.> /dev/nullотбрасывает выведенное логическое значение, сохраняя код выхода.echo ... >&2пишет ошибку в поток ошибок;exit 2завершает работу с ненулевым кодом.
Команда проверки подписи использует тот же независимо закреплённый открытый ключ, что и в предыдущем занятии. Её --bundle указывает на скопированный bundle подписи, а последний аргумент — скопированный манифест. --insecure-ignore-tlog — явное ограничение этих автономных учебных данных: он пропускает проверку публичного журнала, но проверяет подпись закреплённого ключа. Этот скрипт не проверяет публичную идентичность или журнал прозрачности.
Последняя команда Python вызывает подготовленную программу публикации; вы не пишете Python. Она получает скопированный архив, хеш из проверенного манифеста и запрошенный каталог назначения. Если хеш не совпадает с байтами архива, она отклоняет обновление, прежде чем затронуть существующий путеводитель.
Сохраните многократно используемый скрипт приёма
На этом шаге вы напишете скрипт приёма, используя только что рассмотренные механизмы. Начните в Workspace, в /home/labex/project/waymark.
Следующая команда заменяет receive.sh. cat > receive.sh перенаправляет переданный текст в файл. <<'RECEIVER' начинает here-document: всё до строки, содержащей только RECEIVER, становится содержимым файла. Кавычки вокруг маркера сохраняют $1, $stage и переменные jq для последующего исполнения скрипта. Вставьте весь блок, включая завершающий маркер:
cat > receive.sh <<'RECEIVER'
#!/bin/bash
set -euo pipefail
if [ "$#" -ne 2 ]; then
echo "Usage: bash receive.sh CANDIDATE_DIRECTORY DESTINATION_DIRECTORY" >&2
exit 2
fi
candidate=$1
destination=$2
stage=$(mktemp -d)
trap 'rm -rf -- "$stage"' EXIT
cp -- "$candidate/manifest.json" "$candidate/manifest.sigstore.json" "$candidate/guide.tar.gz" "$stage/"
/opt/labex-waymark/bin/cosign verify-blob --key /opt/labex-waymark/trust/publisher.pub --bundle "$stage/manifest.sigstore.json" --insecure-ignore-tlog "$stage/manifest.json"
product=$(jq -r .product /opt/labex-waymark/trust/request.json)
version=$(jq -r .version /opt/labex-waymark/trust/request.json)
jq -e --arg product "$product" --arg version "$version" '.product == $product and .version == $version and .archive == "guide.tar.gz"' "$stage/manifest.json" > /dev/null
digest=$(jq -r .sha256 "$stage/manifest.json")
python3 /opt/labex-waymark/publish.py "$stage/guide.tar.gz" "$digest" "$destination"
RECEIVER
Прочитайте сохранённый файл:
cat receive.sh
Убедитесь, что открытый ключ и запрос берутся из /opt/labex-waymark/trust/, а манифест, bundle и архив — из "$stage". Обратите внимание: после копирования исходный каталог пакета больше не читается. Изменение или переименование поставки после копирования не может подменить байты, передаваемые программе публикации.
Если терминал показывает приглашение продолжения из-за пропущенного завершающего маркера, введите RECEIVER в отдельной строке и нажмите Enter. Если файл вставлен неверно, повторите весь here-document; это заменит только receive.sh. Не запускайте неполный скрипт приёма.
Подготовленная проверка политики запускает ваш неизменённый скрипт от обычной учётной записи на одноразовых каталогах публикации. Она проверяет фактически опубликованные файлы, случаи отказа и сохранение данных; конкретное написание команд не требуется:
sudo python3 /opt/labex-waymark/verify.py policy
sudo требуется подготовленной проверке для запуска изолированной обычной учётной записи, а не вашему скрипту. Проверка не затрагивает работающий путеводитель. Ожидайте, что последняя строка подтвердит принятие запрошенного подписанного путеводителя и отказ в четырёх неодобренных случаях. При неудаче изучите указанное решение и исправьте receive.sh, прежде чем продолжать.
Понаблюдайте отказы перед обновлением работающего путеводителя
На этом шаге вы подтвердите, что скрипт останавливается при трёх разных ошибках, а исходный путеводитель остаётся доступным. Начните в Workspace, в /home/labex/project/waymark.
Сначала попробуйте пакет, подписанный другим издателем. Ожидайте ошибку проверки подписи и ненулевой код:
bash receive.sh candidates/parcel-102 published
$? содержит код выхода непосредственно предыдущей команды. Прочитайте его до выполнения чего-либо ещё:
echo $?
Теперь попробуйте подлинную, но более раннюю редакцию. Ожидайте успешную проверку подписи, после которой будет возвращён ненулевой код, поскольку сравнение с запрошенными продуктом и версией ложно:
bash receive.sh candidates/parcel-101 published
echo $?
Сравнение jq намеренно ничего не выводит; ненулевой код фиксирует отказ. Действительная подпись не отменила независимый запрос.
Наконец, попробуйте изменённый архив. Ожидайте успешную проверку подписи, но сообщение программы публикации о несовпадении хеша и сохранение существующего путеводителя:
bash receive.sh candidates/parcel-103 published
echo $?
Переключитесь на Event Guide и обновите страницу. Редакция должна остаться 2.0; время встречи Old Mill Walk — 11:00. Вернитесь через All walks, скачайте маршрутный лист и откройте Visitor notice. Скрипт, отклоняющий вообще всё, тоже сохранил бы старый путеводитель, поэтому требуется и успешное допустимое обновление.
Отсутствие файла или ошибка соединения не равнозначны этим ожидаемым отказам политики. При опечатке в пути пакета вернитесь в рабочий каталог по абсолютному пути, выведите содержимое candidates и повторите команду. Если сайт недоступен, изучите сообщённую ошибку; не считайте это успешным отказом.
Опубликуйте и используйте одобренный новый путеводитель
На этом шаге вы доставите проверенное обновление и используете его настоящие страницы и скачивание. Начните в Workspace, в /home/labex/project/waymark.
Примите одобренный пакет:
bash receive.sh candidates/parcel-104 published
Ожидайте Verified OK и:
Published event-guide 2.1. Previous releases and uploads kept.
Сразу проверьте код выхода:
echo $?
Ожидайте 0. Переключитесь на Event Guide и обновите страницу. Теперь главная страница показывает event-guide редакции 2.1. Откройте Old Mill Walk и подтвердите 14:00, затем через All walks откройте Riverside Welcome и убедитесь, что её встреча в 09:30 сохранилась. Вернитесь через All walks и скачайте новый маршрутный лист. Обе строки должны соответствовать страницам описания. Откройте Visitor notice, чтобы подтвердить сохранение исходных рекомендаций.
Одобренная главная страница показывает редакцию 2.1; обратите внимание на время встречи Old Mill Walk 14:00:

Переключитесь на Workspace. Самопроверка работающего сервиса читает страницу описания, скачанные байты маршрутного листа, файлы текущего путеводителя, сохранённый предыдущий выпуск и уведомление:
python3 /opt/labex-waymark/verify.py live
Ожидайте:
The running guide and download match the approved release. Previous releases and visitor notice are preserved.
ls перечисляет сохранённые каталоги выпусков:
ls published/releases
Должны присутствовать предыдущий выпуск event-guide-2.0-... и новый event-guide-2.1-.... Завершающие символы получены из хеша фактического архива; запоминать их не нужно.
Если проверка работающего сервиса не прошла, по её сообщению отличите решение о приёме от недоступности сайта или изменения исходного файла. При необходимости исправьте скрипт, затем снова примите исходный одобренный пакет. Повтор того же допустимого обновления безопасен: программа публикации повторно использует идентичный выпуск и сохраняет предыдущие файлы. Повторите самопроверку работающего сервиса, чтобы подтвердить результат.
Резюме
Вы заменили скрипт приёма, доверявший самой поставке, на скрипт, который проверяет независимый ключ издателя и запрос организатора, а затем связывает подписанный хеш архива с фактически публикуемыми байтами. Неверные подписанты, подлинные старые выпуски и изменённые архивы были отклонены, а исходный сервис оставался работоспособным.
Одобренное обновление теперь стало настоящим путеводителем с работающими страницами описания и соответствующим скачиваемым маршрутным листом. В самостоятельном задании эти же инструменты применяются к путеводителю с доступными маршрутами; среди пакетов есть подлинно подписанный пакет для неверного продукта.


