Проблема выглядит убедительно на словах: рядом с образом есть attestation, поэтому кажется, что его происхождение установлено. Цена ошибки появляется при первом спорном deploy. Если statement относится к другому digest, не проверена identity builder или никто не сравнивает вход выкладки с тем же артефактом, команда не знает, что именно защищает её решение. Наличие файла создаёт ощущение завершённости, хотя главное сопоставление не сделано.
Вторая потеря менее заметна: секрет, доступный build, начинает считаться частью provenance. Это разные вопросы. Provenance должно описывать происхождение и свойства output в заданной модели; обращение с секретом — отдельная trust boundary с собственным evidence. Если их склеить в одну декларацию «CI безопасен», нельзя проверить ни то, что secret не попал в output, ни то, что артефакт получен ожидаемым способом. Вместо проверяемого контракта остаётся набор обещаний.
Разделите пять уровней утверждения
Начните с того, что разные слова отвечают на разные вопросы. Source revision обозначает выбранный вход. Builder identity обозначает, кого ожидают видеть исполнителем. Artifact digest обозначает конкретный результат. Attestation statement заявляет связь между полями. Verification — отдельная операция, которая проверяет допустимые свойства statement в известном контексте. Deploy input — ещё один факт: его нужно сопоставить с артефактом, а не вывести из названия release.
SLSA v1.0 полезна как рамка именно для такой дисциплины. Спецификация описывает уровни, recommended attestation formats и provenance; она не включает в себя память о каждом вашем запуске CI. Документация Sigstore объясняет, что подпись и attestation проверяются с параметрами доверия. Из этого следует практический вывод: имя формата или наличие подписи нельзя выдавать за результат реальной verification. Модель сначала фиксирует условия, которые должны быть проверены, и только затем допускает отдельную процедуру.
| Уровень | Допустимая запись | Недопустимый вывод | Что добавить для следующего уровня |
|---|---|---|---|
| Source | выбрана synthetic source revision | этот input действительно собрался | факт запуска build в заданном контексте |
| Builder | ожидается synthetic builder identity | identity доверена и исполнила build | правило доверия и результат проверки |
| Artifact | назван synthetic digest output | именно он поступил в deploy | сопоставление с deploy input |
| Attestation | statement ссылается на тот же synthetic digest | statement подписан и правдив | проверка подписи, identity и claims |
| Secret boundary | указана synthetic ссылка без значения | значение не утекло в output | отдельная проверка пути передачи |
| Release | нужен ручной review | артефакт применён в среде | наблюдаемый deploy input и его связь с digest |
Контракт attestation должен быть маленьким и точным
У учебной записи есть три строгие границы. Первая: `artifactDigest` равен `attestationSubjectDigest`. Вторая: secret представлен как label `synthetic-secret-reference-no-value`, а не как значение. Третья: вход принимает только заранее перечисленные поля, поэтому `secretValue` или произвольный extra field не может тихо пройти в accepted record. Первая связь защищает от бессмысленного statement про чужой output. Вторая и третья защищают от более простой ошибки в документации: не превращать разбор цепочки в новый канал распространения чувствительных данных. Ни одна из границ не утверждает, что криптографический материал существует.
Вместо булева поля `trusted: true` модель возвращает ограничения явными значениями: signature not-created, verification not-executed, provenance requires-verification и release manual-review-required. Это не излишняя осторожность, а полезный интерфейс. Читатель сразу видит, чего модель не делает. Если функции присвоить статус «verified» без внешней проверки, она создаст ложное evidence, потому что локальная строка будет выглядеть как результат работы реального verifier.
Исполнимый fixture проверяет форму, не поставку
Функция `assembleSyntheticSupplyChain()` принимает только явно synthetic input и закрытый набор полей. Она отклоняет пустой builder, непомеченную source revision, другой subject digest, label, похожий на попытку передать значение секрета, и отдельное поле secretValue. Затем `runSupplyChainFixture()` проверяет, что valid record остаётся ручным кандидатом на review, а не получает разрешение на deploy. Это удобно для изменения модели: при добавлении нового поля становится видно, какую отрицательную ветку надо добавить.
import {
assembleSyntheticSupplyChain,
runSupplyChainFixture,
} from './upgrade-2023-06.mjs';
const flow = assembleSyntheticSupplyChain({
synthetic: true,
sourceRevision: 'synthetic-source-revision-A',
builderIdentity: 'synthetic-builder-identity-A',
secretLabel: 'synthetic-secret-reference-no-value',
artifactDigest: 'synthetic-digest-artifact-A',
attestationSubjectDigest: 'synthetic-digest-artifact-A',
attestationDeclaration: 'synthetic-attestation-declaration',
});
const report = runSupplyChainFixture();
if (!Object.values(report.assertions).every(Boolean)) throw new Error('fixture failed');
console.log(flow.release.status); // manual-review-required
// Не создаёт secret, certificate, signature, attestation или deploy.
node web/scripts/upgrade-2023-06.mjs --verify-fixture
# PASS проверяет детерминированные synthetic objects в памяти.
# Он не запускает CI, не обращается к secret store и не вызывает verifier.
Fixture намеренно не использует hash-функцию. Здесь `synthetic-digest-artifact-A` — label, а не digest реального файла. Иначе пример стал бы выглядеть как проверка артефакта, хотя не знает его байтов, registry, execution context и доверенной цепочки. Для production проверка должна работать с известным форматом, актуальным ключом или identity и точным input. В учебном материале полезнее сохранить честную границу, чем имитировать криптографию красивым именем поля.
Почему declaration не доказывает provenance
Даже если declaration подписан, из этого ещё не следует, что output произошёл из заявленного source. Надо определить, кому доверяют как signer или builder, какая версия формата приемлема, какие claims обязаны совпасть, какой subject проверяется и как проверка связана с deploy. Каждый пункт имеет вероятность оказаться не выполненным. Поэтому фраза «есть signed attestation» описывает только часть состояния. Она не должна становиться короткой формой для «provenance доказано».
То же относится к секрету. Указание, что build вправе получить секрет, не доказывает отсутствие следа в layer, cache, metadata, журнале или другом output. Нельзя проверить это, перечислив места утечки из головы. Нужно выбрать конкретный поток передачи, владельца и безопасный метод наблюдения в закрытом рабочем контуре. Если он пока не определён, контракт должен сказать `not-observed`. Это точнее, чем обещание «секретов в образе нет» без реального исследования.
Маршрут: симптом → причина → проверка → действие
- Симптом. Attestation существует, но reviewer не может ответить, относится ли она к deploy input и какой факт о builder был проверен.
- Причина. В одной строке смешаны subject, подпись, provenance, работа с секретом и выпуск; у них нет отдельных условий и статусов.
- Проверка. Сравните subject statement с artifact digest. Затем перечислите отдельными полями signature, verification, provenance и release. Прогоните fixture и убедитесь, что он отвергает несовпадающий subject.
- Действие. Оставьте declaration только declaration. В release design запишите реальную процедуру verification, её владельца, доверенные входы и ожидаемый результат без публикации чувствительных данных.
- Проверка границы секрета. Уберите значение из документа и спланируйте отдельное evidence о маршруте передачи, а не о содержимом секрета.
- Следующий шаг. Включите сопоставление deploy input с digest как самостоятельный acceptance criterion, когда для него согласованы среда и владелец.
Rollback не отменяет уже сделанные заявления
У этой учебной модели rollback восстанавливает только исходные labels. Он не отзывает ключ, не удаляет artefact, не исправляет реальную запись или deployment. В production откат должен сначала ответить на два вопроса: какой факт оказался недостоверным и что уже зависит от спорного output. Затем выбирают действие, которое не увеличивает неопределённость: остановить следующий шаг, сохранить минимальное evidence и вернуться к известному кандидату. Механизм работает только при заранее определённых границах ответственности.
Нельзя считать reset документа доказательством, что риск исчез. Если statement уже был использован в release decision, надо отдельно пересмотреть это решение. Если вопрос касается секрета, его жизненный цикл и возможная смена доступа живут в операционном плане, а не в функции, которая сравнивает labels. Простая модель полезна тем, что не маскирует эту разницу: возврат записи — это возврат записи, не исправление среды.
Ограничения и следующий шаг
Пакет не содержит реального секрета, token, URL рабочей системы, policy, CVE, CI log, scanner data или сведений о конкретном образе. Он не генерирует certificate, signature, attestation, SBOM или release. Источники объясняют версию SLSA, доступный инструмент и практику SSDF, но не предоставляют проекту автоматического соответствия. В частности, declaration signing или attestation не доказывает provenance и не доказывает, что артефакт был использован в deploy.
Следующий шаг — не внедрять все уровни сразу. Возьмите один существующий release design и выпишите пять разных утверждений из таблицы. Там, где обещание не имеет метода проверки, оставьте `requires-verification` и назначьте владельца следующего маленького исследования. Это делает обсуждение короче: команда спорит не о красивом слове provenance, а о конкретном отсутствующем сопоставлении.
Историческая граница июня 2023
Версии в этой статье не выходят за июнь 2023: SLSA v1.0 стала финальной 19.04.2023, Cosign v2.0.0 опубликован 24.02.2023, SSDF v1.1 — 03.02.2022. Поэтому нет ссылок на будущие функции платформ и нет предположения, что современный формат attestation был доступен автору тогда. Термины применены как язык для проектного контракта, а не как обещание уровня зрелости.
Проверяемые источники
- SLSA: SLSA v1.0 is now final!, 19 апреля 2023 — официальное объявление фиксирует первый стабильный выпуск SLSA v1.0, доступный к июню 2023. Сам факт выпуска не доказывает соответствие какого-либо pipeline.
- SLSA specification v1.0 — версионная спецификация описывает уровни и рекомендуемые форматы attestation, включая provenance. Сейчас версия помечена retired, но это сохранённая спецификация именно v1.0.
- sigstore/cosign: Release v2.0.0, 24 февраля 2023 — официальный release проекта Sigstore, опубликованный до июня 2023. Наличие инструмента и его формата не означает, что конкретный артефакт был им подписан или проверен.
- NIST SP 800-218 SSDF Version 1.1, Final, 3 февраля 2022 — официальное руководство NIST по практикам безопасной разработки и общему словарю для поставщиков и потребителей. Оно не заменяет evidence конкретного выпуска.