Skip to content

feat: Nexus 向け x86_64 Edge Core package と health 契約 (#424) - #425

Merged
01rabbit merged 1 commit into
mainfrom
claude/zealous-edison-k5vt5j
Sep 21, 2026
Merged

01rabbit merged 1 commit into
mainfrom
claude/zealous-edison-k5vt5j

Conversation

@01rabbit

Copy link
Copy Markdown
Owner

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

  • feat — new feature

Checklist

  • PYTHONPATH=. pytest -q passes — 896 passed, 4 skipped(892 → 896)。cargo test 30 passed
  • Related documentation updated in this PR — docs/nexus-core-package.md
  • Deterministic First principle not violated — 本 PR は AI 判断を一切導入しない。posture は observe-only 固定で、enforcement / redirect / 外部機器変更 / ネットワーク設定変更はいずれも false を宣言し、health check がそれぞれ独立に検査する
  • Raspberry Pi constraints not broken — 本 package は x86_64 専用で、aarch64 の経路・既存 Pi 構成のいずれにも触れない。追加した --health / --version は one-shot で、常駐経路のメモリ挙動を変えない
  • No changes to 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 度捕捉しました

  1. test_runtime_dependency_contract.py が最初のフルランで捕捉。モジュール名 build が PyPI の同名パッケージを sys.path 上で隠していました。nexus_core_package へ改名。
  2. 同テストの first-party ディレクトリ一覧に 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 が確立しないこと

  • payload が実機で正しく動くこと(ビルドと自己検査のみ)
  • digest の真正性(§3)
  • edge-baseline-ready(Nexus 側が 5 項目すべてから判定)
  • 実ネットワークに関する一切(package はネットワークを設定せず、実網で試験もしていません)

Related issues

Refs #424, Azazel-Nexus#44


🤖 Generated with Claude Code

https://claude.ai/code/session_01SsboPSj6GyJju6mTXwHHjq


Generated by Claude Code

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
@01rabbit
01rabbit marked this pull request as ready for review September 21, 2026 01:11
@01rabbit
01rabbit merged commit bb8186f into main Sep 21, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants