Skip to content

Подписанные чеки верификации

После завершения tausik verify записывает компактный, подписанный ed25519 документ о том, что именно было проверено, — чек (receipt). Ценность в одной строке:

можно доказать, что задача действительно была проверена, а не просто заявлена проверенной.

Чек привязан к гейтам, которые отработали, и к текущему git HEAD. Поскольку он подписан проектным ключом, «зелёный» вердикт нельзя подделать или переиграть ручной правкой строки в БД или переносом старого результата на новый коммит. task done (QG-2) перед закрытием задачи читает кэшированный verify-прогон, поэтому подпись и есть доказательство за «зелёным».

Чеки переносимы и проверяемы офлайн: выгрузите его в JSON-файл, приложите к PR или артефакту CI — и кто угодно перепроверит подпись без базы данных, без хранилища ключей и без SDK TAUSIK.

Как появляется чек

bash
tausik key init                  # один раз на проект — создаёт пару ключей
tausik verify --task my-feature  # прогоняет гейты и подписывает чек

verify записывает verification_run, а затем выпускает для него чек. Выпуск — best-effort: на проекте без ключа он деградирует до «нет ключа», и verify-прогон всё равно успешен — просто без подписанного доказательства. В конце прогона verify сообщает результат:

Recorded verification_run (task_slug=my-feature, exit=0).
Receipt: signed (run #412, key 9f3c1a2b4d5e6f70).

Чек удостоверяет только фактически отработавшие гейты — пропущенный (skipped) гейт ничего не доказывает, поэтому в чек не попадает, даже если для вердикта он считается «passed».

Формат конверта (tausik-signed/v1)

Подписанный чек — это конверт (envelope), оборачивающий канонический чек и его подпись. Подпись вычисляется по каноническим байтам только объекта receipt, а не самого конверта.

json
{
  "envelope": "tausik-signed/v1",
  "receipt": {
    "schema": "tausik-receipt/v1",
    "task_slug": "my-feature",
    "git_sha": "0123456789abcdef0123456789abcdef01234567",
    "scope": "standard",
    "gates": [
      {"name": "pytest", "passed": true, "severity": "block"},
      {"name": "ruff",   "passed": true, "severity": "warn"}
    ],
    "passed": true,
    "ran_at": "2026-06-13T10:42:07Z",
    "files_hash": "a1b2c3d4...",
    "key_fingerprint": "9f3c1a2b4d5e6f70"
  },
  "signature": {
    "algorithm": "ed25519",
    "key_fingerprint": "9f3c1a2b4d5e6f70",
    "value": "<128 hex-символов — 64-байтная подпись ed25519>"
  }
}

Пояснения к полям:

  • git_sha — sha HEAD на момент verify, либо null вне git-репозитория. Именно это привязывает «зелёный» к конкретному коммиту и блокирует перенос на новый код.
  • gates[] — сведены к подписываемой тройке {name, passed, severity}. Объёмный и недетерминированный вывод гейтов в чек намеренно не входит.
  • passed — общий вердикт: все непропущенные гейты со severity: "block" прошли и хотя бы один гейт отработал.
  • key_fingerprint — первые 16 hex от SHA-256 публичного ключа; то же значение показывает tausik key show.
  • value — 128 hex-символов (64-байтная подпись ed25519).

Чек каноничен (в духе JCS / RFC 8785): ключи отсортированы на каждом уровне, без пробелов, только ASCII, числа с плавающей точкой отвергаются. Один и тот же логический чек всегда сериализуется в одни и те же байты, поэтому подпись проверяется одинаково на любой машине и платформе.

Управление ключами

bash
tausik key init    # создать проектную пару ed25519 (не перезапишет существующую)
tausik key show    # показать публичный ключ и отпечаток (никогда — seed)

Ключи лежат в .tausik/keys/:

ФайлСодержимоеМожно делиться?
project.keyприватный 32-байтный seed (ed25519:<64 hex>)Нет — не покидает машину; .tausik/ в gitignore
project.pubпубличный ключ (ed25519:<64 hex>)Да — раздавайте по доверенному каналу для проверки

Ротация — tausik key init --force. Учтите: существующие подписи перестанут проверяться против нового ключа.

Работа с чеками

tausik receipt show

Показать последний сохранённый конверт для задачи (или конкретного прогона) и перепроверить его подпись против проектного ключа.

bash
tausik receipt show --task my-feature      # либо: --run 412
tausik receipt show --task my-feature --json   # сырой JSON конверта

Коды выхода: 0 — валидна, 1 — подпись невалидна (изменены данные или подпись), 2 — не найдено / нет ключа.

tausik receipt export

Сформировать самодостаточный переносимый артефакт — конверт плюс встроенный публичный ключ — для PR или внешнего аудита. Экспорт откажется работать, если сохранённая подпись не проверяется против текущего ключа (испорченная строка или сменённый ключ).

bash
tausik receipt export --task my-feature           # пишет в .tausik/receipts/
tausik receipt export --task my-feature --out receipt.json
tausik receipt export --task my-feature --stdout  # вывести, а не записывать

Экспорт оборачивает конверт в артефакт tausik-receipt-export/v1, встраивающий публичный ключ, — его можно проверить где угодно:

json
{
  "export": "tausik-receipt-export/v1",
  "envelope": { "...tausik-signed/v1, без изменений..." },
  "public_key": "ed25519:<64 hex>",
  "key_fingerprint": "9f3c1a2b4d5e6f70"
}

tausik receipt verify <file>

Офлайн-проверка целостности экспортированного артефакта — без базы данных, без хранилища ключей, без SDK. По умолчанию используется публичный ключ, встроенный в файл. Чтобы не доверять этому ключу, передайте свой по доверенному каналу:

bash
tausik receipt verify receipt.json
tausik receipt verify receipt.json --pub ed25519:7c2f...e0

Коды выхода: 0 — валидна, 1 — настоящий артефакт с плохой подписью, 2 — файл не является корректным артефактом экспорта.

Модель доверия

Подпись доказывает целостность — чек не изменялся после подписания. Сама по себе она не доказывает происхождение: встроенный отпечаток доверия ровно столько, сколько файл, в котором он едет. Чтобы привязать происхождение, сверьте key_fingerprint с доверенным каналом — выводом tausik key show, зафиксированной переменной CI или описанием PR — и никогда не доверяйте отпечатку, встроенному в тот же артефакт, который вы проверяете.

Офлайн / проверка без SDK по HTTP

Для агентов и CI, которым недоступны CLI или MCP, tausik serve отдаёт то же подписание и проверку через stateless HTTP-эндпоинт — отправьте результаты гейтов и получите тот же чек tausik-signed/v1. Эндпоинты, клиент на stdlib и сниппет для GitHub Actions — в no-sdk-verify.md.

Смотрите также

  • cli.md — полный справочник CLI (key, verify, receipt).
  • mcp.md — эквивалентные MCP-инструменты.
  • no-sdk-verify.md — HTTP-эндпоинт верификации (tausik serve).
  • senar.md — принцип verify-first из SENAR, стоящий за QG-2.