<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Release on 万屋猫Labs</title><link>https://yn-labs.com/tags/release/</link><description>Recent content in Release on 万屋猫Labs</description><generator>Hugo</generator><language>ja</language><lastBuildDate>Mon, 15 Jun 2026 12:00:00 +0900</lastBuildDate><atom:link href="https://yn-labs.com/tags/release/index.xml" rel="self" type="application/rss+xml"/><item><title>「秘密が漏れない」を Lean で証明して CI ゲートにした Rust CLI のリリースパイプライン</title><link>https://yn-labs.com/posts/secure-rust-cicd-release/</link><pubDate>Mon, 15 Jun 2026 12:00:00 +0900</pubDate><guid>https://yn-labs.com/posts/secure-rust-cicd-release/</guid><description>&lt;h2 id="テストが緑で満足できなかった理由"&gt;「テストが緑」で満足できなかった理由&lt;/h2&gt;
&lt;p&gt;エージェントに本物の API キーを渡さずに動かす CLI ツールを開発している。守りたい性質はシンプルで、子プロセスに本物の鍵を渡さないこと。ここが崩れれば、このツールを使う意味はない。&lt;/p&gt;
&lt;p&gt;ただ、テストが通っているだけでは確認として物足りなかった。テストが言えるのは「この入力では問題ない」までで、「どんな入力でも問題ない」ではない。鍵を扱う以上、その差は無視できない。&lt;/p&gt;
&lt;p&gt;そこで Lean で証明を書き、CI でビルドするようにした。手間はかかるが、扱うものを考えれば妥当な投資だと思う。この記事では、そのときに組んだ CI/CD を抜粋して紹介する。プロジェクト固有の内部名は伏せ、設計と仕組みのところだけを残した。&lt;/p&gt;
&lt;h3 id="数字で見た中身"&gt;数字で見た中身&lt;/h3&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;指標&lt;/th&gt;
 &lt;th&gt;値&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;Lean の定理／補題（&lt;code&gt;formal/lean&lt;/code&gt;）&lt;/td&gt;
 &lt;td&gt;28&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Lean 証明中の &lt;code&gt;sorry&lt;/code&gt; / &lt;code&gt;axiom&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;0&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;安全不変条件ゲート（CI ステップ）&lt;/td&gt;
 &lt;td&gt;11&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;リリース配布ターゲット（matrix）&lt;/td&gt;
 &lt;td&gt;5&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;サプライチェーン検査&lt;/td&gt;
 &lt;td&gt;cargo-deny + Trivy&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;地味だが効いているのが、&lt;code&gt;sorry&lt;/code&gt;（証明の穴埋めサボり）と &lt;code&gt;axiom&lt;/code&gt;（無証明の仮定）が両方とも 0 という点だ。核の不変条件を仮定でごまかさず最後まで証明している、ということで、これが CI を緑にする条件に入っている。&lt;/p&gt;
&lt;h2 id="ci-は三層に分けている"&gt;CI は三層に分けている&lt;/h2&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;┌─────────────────────────────────────────────┐
│ 1. 形式検証（核） │
│ 「子プロセスは本物の鍵を受け取らない」を │
│ Lean で証明 — 定理28 / sorry・axiom 0 │
├─────────────────────────────────────────────┤
│ 2. 安全不変条件ゲート × 11 │
│ deny-before-inject / DNS guard / │
│ audit boundary / secret-type … を │
│ 1条件＝1ゲートで機械チェック │
├─────────────────────────────────────────────┤
│ 3. 汎用品質 + サプライチェーン │
│ fmt / clippy -D warnings / test / │
│ cargo-deny（advisories, bans, sources） │
└─────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="1-核は-lean-で証明してci-でビルドする"&gt;1. 核は Lean で証明して、CI でビルドする&lt;/h3&gt;
&lt;p&gt;「子プロセスは本物の鍵を受け取らない」という核の性質は、&lt;code&gt;formal/lean&lt;/code&gt; に証明として置いている。定理と補題で28本、うち &lt;code&gt;sorry&lt;/code&gt; も &lt;code&gt;axiom&lt;/code&gt; も無し。CI は毎回この証明をビルドして、サボりや無証明の仮定なしで通ることを確かめる。&lt;/p&gt;</description></item></channel></rss>