<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Supply-Chain on 万屋猫Labs</title><link>https://yn-labs.com/tags/supply-chain/</link><description>Recent content in Supply-Chain on 万屋猫Labs</description><generator>Hugo</generator><language>ja</language><lastBuildDate>Sat, 04 Jul 2026 10:00:00 +0900</lastBuildDate><atom:link href="https://yn-labs.com/tags/supply-chain/index.xml" rel="self" type="application/rss+xml"/><item><title>dotfiles にも CI を — 破壊的インストーラの冪等性を Ubuntu と Kali の二役で検証する</title><link>https://yn-labs.com/posts/dotfiles-ci-idempotency/</link><pubDate>Sat, 04 Jul 2026 10:00:00 +0900</pubDate><guid>https://yn-labs.com/posts/dotfiles-ci-idempotency/</guid><description>&lt;h2 id="自分の開発環境がある日再現できなくなる"&gt;自分の開発環境が、ある日再現できなくなる&lt;/h2&gt;
&lt;p&gt;開発環境を1本のスクリプトにまとめている。シェル設定・プロンプト・ターミナルマルチプレクサ・言語ランタイム・クラウドCLIを、&lt;code&gt;./setup_env.sh&lt;/code&gt; 一発で入れる。最終的に 1,358 行になった。新しいマシンでも、OS を入れ直した後でも、同じ環境がすぐ戻ってくる。便利だ。&lt;/p&gt;
&lt;p&gt;便利なのだが、ひとつ不安が残った。今度は &lt;strong&gt;そのスクリプト自体が壊れたときに気づけない&lt;/strong&gt;。うっかり片方の OS でしか通らない書き方をしても、次にそのマシンを触るまで分からない。設定ファイルを追記する処理が既存の &lt;code&gt;.zshrc&lt;/code&gt; を壊しても、実際に事故ってから気づく。手作業をスクリプトにまとめた結果、こんどはその 1 本のスクリプトに、環境の再現を丸ごと預けることになった。&lt;/p&gt;
&lt;p&gt;それで、dotfiles にも CI をつけた。やることは本番インフラの検証と変わらない。&lt;strong&gt;「危険な変更が入ったら、その場で赤くする」&lt;/strong&gt; を、開発環境の構築スクリプトに対してやる。この記事では、その CI（GitHub Actions）を抜粋して紹介する。リポジトリ固有の名前やレイアウト名は伏せるか一般化し、コードは要点を示す抜粋にしてある。&lt;/p&gt;
&lt;h3 id="数字で見た中身"&gt;数字で見た中身&lt;/h3&gt;
&lt;p&gt;実環境の中身は出せないので、代わりに構成の規模で示す。以下はこの dotfiles と CI を実測した値だ。&lt;/p&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;&lt;code&gt;setup_env.sh&lt;/code&gt; 行数（単一エントリポイント）&lt;/td&gt;
 &lt;td&gt;1,358&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;CI ジョブ（builder / breaker / aggregate）&lt;/td&gt;
 &lt;td&gt;3&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;検証環境（Ubuntu runner / Kali コンテナ）&lt;/td&gt;
 &lt;td&gt;2&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;scripts/ci/validate_*&lt;/code&gt; チェッカ&lt;/td&gt;
 &lt;td&gt;14&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;CI で生成検証する Zellij レイアウト（総数9本のうち）&lt;/td&gt;
 &lt;td&gt;8&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;インストーラ検証の段階（dry-run → 実行 → &lt;code&gt;--clean&lt;/code&gt; 再構築）&lt;/td&gt;
 &lt;td&gt;3&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="全体構成"&gt;全体構成&lt;/h2&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt; push / PR / dispatch
 │
 ┌────────────────┴────────────────┐
 ▼ ▼
 ┌──────────────────────┐ ┌──────────────────────────┐
 │ builder (Ubuntu) │ │ breaker (Kali container) │
 │ shellcheck / clippy │ │ shellcheck / clippy │
 │ setup --dry-run │ │ setup --dry-run │
 │ 隔離HOMEで実インストール │ │ 隔離HOMEで実インストール │
 │ --clean で再構築 │ │ --clean で再構築 │
 │ layout ×4 を assert │ │ layout ×4 を assert │
 └──────────┬───────────┘ └────────────┬─────────────┘
 │ report (artifact) │ report (artifact)
 └────────────────┬──────────────────┘
 ▼
 ┌──────────────────────┐
 │ aggregate │
 │ 2環境のレポートを統合 │
 │ → CI step summary │
 └──────────────────────┘
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;CI は 3 ジョブに分けている。同じインストーラを 2 つの OS で流す &lt;code&gt;builder&lt;/code&gt; と &lt;code&gt;breaker&lt;/code&gt;、そして両者のレポートを 1 枚にまとめる &lt;code&gt;aggregate&lt;/code&gt; だ。&lt;/p&gt;</description></item><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>