feat: Nexus 向け x86_64 Edge Core package と health 契約 (#424) - #425
Merged
Merged
Conversation
Azazel-Nexus がローカルの Edge Core を検証して起動できるようにするための成果物。 **既存 network installer とは完全に分離する** — 使用も移植もしない。packager は ネットワークを設定せず、interface に触れず、何もインストールしない。 ## Nexus が見る 5 項目と、受理が意味しないこと package 存在 / version 一致 / digest 一致 / health 応答 / 起動状態。 **package を受理して確立できるのは最初の 4 つまでで、5 つ目は確立できない。** manifest 自身が `not_established_by_accepting_this_package` でそう述べ、テストが その項目に「payload が起動しているとは限らない」と「edge-baseline-ready」の 両方が含まれることを確認する。ディスク上の package は起動中の Edge ではない。 ## digest は署名しない — 明示する #424 が明示を求めている。Nexus は「tag が署名されている」と「digest が署名されて いる」を区別する。**どちらも真ではない。** 署名鍵操作は本成果物の範囲外。 未署名 digest が確立するのは**偶発的変化に対する完全性** — 切り詰められたコピー、 書きかけのファイル、置き違えたビルド。**package と manifest を同時に書き換えられる 攻撃者に対する完全性ではない。** manifest は `"signed": false` と理由を携え、 消費側は authenticity として扱わず縮退する。 ## 決定論的 — digest を比較するのだから 同一入力はバイト同一出力になる。entry を sort、mtime を 0、uid/gid を 0、 uname/gname を空、mode を固定、gzip header に timestamp を置かない。いずれも ビルドホストが digest に漏れ出す箇所。 payload は**列挙し、glob しない。** 作業コピーの状態で内容が決まる package は、 マシンごとに違う意味の digest を持つ。 binary の `--version` を実行して Cargo.toml と照合し、食い違えば拒否する。 **別チェックアウトの binary は digest が捕まえられない唯一の誤り** — どちらも 内部的には整合しているから。 ## health 契約 — network HTTP ではなく固定 CLI `bin/azazel-edge-core --health` が JSON を出力して終了する。 **healthy は 4 条件すべてを要する**: exit 0 かつ JSON として解析でき、かつ `contract` が一致し、かつ `status` が `healthy`。**切り詰められた/壊れた stdout が healthy と読めてはならない**という #424 の要求そのもの。 **評価できなかったものは unhealthy。** check を省いて healthy を返す経路は無い — 緑の check を数える読み手は、1 つ足りないことに気付かない。 **one-shot で、読まず書かず socket を開かずループに入らない。** ノードを変える health check は、誰も実行できない health check になる。 **binary を確立し、daemon は確立しない。** 起動状態は Nexus が別に判定する。 posture check 5 つはそれぞれ単独で失敗させられることをテストが示す。 **何をしても失敗しない check は常に緑であり、check が無いのと区別できない。** ## 敵対的レビュー Python 10 変異 + Rust 6 変異。**Rust は全件 CAUGHT**(R5 は binary がループに入り subprocess が timeout する形で検出された)。 Python は 4 件が生き残り、**いずれもテスト側の弱さだった**: - gzip timestamp: 2 回のビルドが同一秒に収まれば一致してしまう → header の MTIME フィールドを直接読む - entry sort: `PAYLOAD` がたまたま sort 済みで no-op だった → 逆順を渡して検査 - version 照合: 実際に食い違う tree を作って拒否を確認 - not-established list: 連結文字列に "running" が別項目由来で含まれていた → 項目ごとに検査 ## 既存ガードによる捕捉 `test_runtime_dependency_contract.py` が最初のフルラン時に捕捉した。モジュール名 `build` が PyPI の同名パッケージを sys.path 上で隠していた。`nexus_core_package` へ改名した。 併せて、同テストの first-party ディレクトリ一覧に `packaging` を加えた。 `packaging/nexus-core/` は本 issue で新設した first-party の置き場であり、 3 ディレクトリ決め打ちの一覧がそれを third-party と誤認していた。**ガードは 弱めていない** — 実在しない third-party import を足して、依然として捕捉することを 確認済み。 tests 892 → 896 passed, 4 skipped。cargo test 30 passed。 Refs #424, Azazel-Nexus#44 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SsboPSj6GyJju6mTXwHHjq
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Azazel-Nexus がローカルの Edge Core を検証して起動できるようにするための成果物。既存 network installer とは完全に分離する — 使用も移植もしない。packager はネットワークを設定せず、interface に触れず、何もインストールしない。
packaging/nexus-core/nexus_core_package.pyが、ビルド済み binary と固定の設定ファイルから決定論的な tarball と manifest を作る。azazel-edge-core --health/--versionを追加した。Nexus が見る 5 項目と、受理が意味しないこと
package 存在 / version 一致 / digest 一致 / health 応答 / 起動状態。
package を受理して確立できるのは最初の 4 つまでで、5 つ目は確立できない。 manifest 自身が
not_established_by_accepting_this_packageでそう述べ、テストがその項目に「payload が起動しているとは限らない」と「edge-baseline-ready」の両方が含まれることを確認する。ディスク上の package は起動中の Edge ではない。digest は署名しない — 明示する
#424 が明示を求めている。Nexus は「tag が署名されている」と「digest が署名されている」を区別する。どちらも真ではない。 署名鍵操作は本成果物の範囲外。
未署名 digest が確立するのは偶発的変化に対する完全性(切り詰められたコピー、書きかけのファイル、置き違えたビルド)であって、package と manifest を同時に書き換えられる攻撃者に対する完全性ではない。manifest は
"signed": falseと理由を携える。health 契約 — network HTTP ではなく固定 CLI
healthy は 4 条件すべてを要する: exit 0 かつ JSON として解析でき、かつ
contractが一致し、かつstatusがhealthy。切り詰められた/壊れた stdout が healthy と読めてはならないという #424 の要求そのもの。評価できなかったものは unhealthy。 check を省いて healthy を返す経路は無い — 緑の check を数える読み手は、1 つ足りないことに気付かない。
one-shot で、読まず書かず socket を開かずループに入らない。 ノードを変える health check は、誰も実行できない health check になる。
binary を確立し、daemon は確立しない。 起動状態は Nexus が別に判定する。
決定論的 — digest を比較するのだから
entry を sort、mtime を 0、uid/gid を 0、uname/gname を空、mode を固定、gzip header に timestamp を置かない。payload は列挙し、glob しない。binary の
--versionを Cargo.toml と照合して食い違えば拒否する — 別チェックアウトの binary は digest が捕まえられない唯一の誤りで、どちらも内部的には整合しているため。Type of change
Checklist
PYTHONPATH=. pytest -qpasses — 896 passed, 4 skipped(892 → 896)。cargo test30 passeddocs/nexus-core-package.mdfalseを宣言し、health check がそれぞれ独立に検査する--health/--versionは one-shot で、常駐経路のメモリ挙動を変えないinstaller/,systemd/,security/without explicit justification below — これら 3 ディレクトリへの変更は一切ありませんNotes for reviewers
制限領域に触れていないこと
installer/systemd/security/は未変更です。AGENTS.md の禁止事項に該当する変更はありません。#424 が「既存 network installer は使用も移植もしない」と要求しているため、新設のpackaging/nexus-core/に分離しました。テストが packager の中にinstaller/internal/nmcli/iptables/nftが現れないことを静的に確認します。既存ガードが 2 度捕捉しました
test_runtime_dependency_contract.pyが最初のフルランで捕捉。モジュール名buildが PyPI の同名パッケージをsys.path上で隠していました。nexus_core_packageへ改名。packagingを追加しました。packaging/nexus-core/は本 issue で新設した first-party の置き場で、3 ディレクトリ決め打ちの一覧がそれを third-party と誤認していたためです。ガードは弱めていません — 実在しない third-party import を足して、依然として捕捉することを確認済みです。敵対的レビュー
Python 10 変異 + Rust 6 変異。Rust は全件 CAUGHT(うち 1 件は binary がループに入り subprocess が timeout する形で検出)。
Python は 4 件が生き残り、いずれもテスト側の弱さでした。gzip timestamp(2 回のビルドが同一秒なら一致してしまう → header の MTIME を直接読む)、entry sort(
PAYLOADがたまたま sort 済みで no-op → 逆順を渡す)、version 照合(実際に食い違う tree を作る)、not-established list(連結文字列に別項目由来の "running" が含まれていた → 項目ごとに検査)。いずれも修正し再変異で捕捉を確認しました。無関係な差分を入れていないこと
テスト実行が
docs/issues/bhusa-2026-vegas-readiness/配下の生成レポートを、このコンテナの日付とgh不在で書き換えました。環境固有のノイズのためgit checkoutで戻し、本 PR には含めていません。この PR が確立しないこと
edge-baseline-ready(Nexus 側が 5 項目すべてから判定)Related issues
Refs #424, Azazel-Nexus#44
🤖 Generated with Claude Code
https://claude.ai/code/session_01SsboPSj6GyJju6mTXwHHjq
Generated by Claude Code