fix(mobile): CalDAV を TLS の vhost に直し、adopt と週次 drift CI を足す - #277
Merged
Conversation
radicale の 5232 を直接指していたが、hosts/homeserver.nix の sites 表が dav の vhost を立てて Caddy が ACME 証明書で終端している。直接続だと資格情報が平文で 流れるうえ、そもそも指す先を間違えていた。
Play にしか無い行は Obtainium が追えず、端末側の import 1 回では載らない 唯一の穴だった。bitwarden/android は GitHub Releases に APK を出しているので そちらに寄せた。これで宣言した全アプリが Obtainium の URL リスト import で 端末に載る。play の経路自体は残す (今後 Play 限定のものが出たとき用)。
「Aurora Store は?」「設定は自動か?」への答え。 apps.sh adopt: 端末に在って宣言に無いものを、配布元を引いて経路を判定した tsv 行として出す。Aurora Store で入れたものを packageId を目で追って書き写す 作業を機械にやらせる。>>apps.tsv で追記してから整える運用。 週次 CI (mobile-drift.yml): 実機は触れないので、確かめるのは宣言が腐って いないかだけ。packageId/bundleId が配布元から消えていないか、GitHub の repo が 改名されていないか。押した瞬間に気付けないものこそ定期実行の対象にする。 PR で mobile/ を触ったときにも走る。 実機に触る側 (status / os.sh / install) は手動のまま。端末が常時繋がって いないので、繋がっていない間に「適用したつもり」の状態を作りたくない。 その線引きを mobile/README.md に表で書いた。
「アプリ側の import で完結できないか」への答え。両方できた。
apps.sh aurora: play 行を Aurora Store の Favourites に import できる JSON で
出す。Aurora 4.6 以降は Favourites の import/export と一括インストールを持って
いるので、Play しか配布元が無いものもファイルを渡す形で済む。形式は AuroraStore
の data/room/favourite/{ImportExport,Favourite}.kt に合わせた。added は 0 固定
(実行のたびに変えるとファイルが毎回差分になる)。
os.sh を端末内でも走るようにした。Termux に WRITE_SECURE_SETTINGS を一度 adb で
与えておけば、以降は母艦を出さずに settings を当てられる (Termux:Boot や cron から
呼べる)。uname -o が Android を返すことで判定し、adb を挟まない形に切り替える。
adb 呼び出しは dev() に寄せたので </dev/null の付け忘れも 1 箇所で済む。
debloat とアプリ個別は端末内からは通らない。pm uninstall は DELETE_PACKAGES、
pm grant は GRANT_RUNTIME_PERMISSIONS で、どちらも署名レベル。adb の shell uid
だから通るのであって、アプリの uid には与えられない。黙って飛ばさず理由を出す。
これで母艦とケーブルが要るのは、その 2 つと実機との差分を数える status だけに
なった。線引きは mobile/README.md の表を更新した。
手で組んだ plist が `shortcuts sign` に通らない件は、Cherri (github.com/electrikmilk/cherri) で解決した。テキストから署名済みの .shortcut (AEA1 コンテナ) を直接吐く Go 製コンパイラで、flake があるので nix run で足りる。 hello world を実際にコンパイルして AEA1 が出ることを確認済み。 既存のショートカットは母艦の ~/Library/Shortcuts/Shortcuts.sqlite から取れた。 ZSHORTCUTACTIONS.ZDATA が素の bplist で暗号化されていない。iCloud で iPhone と 往復しているので、端末を繋がずに 5 件とも書き出せた。XML plist に開いて 差分が読める形で置いてある。実体が iCloud にしか無く消えたら戻せないので、 これはバックアップとレビューを兼ねる。 BLOB は hex で受けて xxd で戻す。sqlite3 の writefile は出力先がファイルでないと 使えず、素の SELECT ではバイナリが壊れる。 書き出した Home / Haus は SESAME スマートロックのトグルで、機器の UUID が 入っている (URL やトークンは無い)。公開して困るなら 2 件だけ外す。
パソコン以外で Web UI が真実になっていたものを順に潰す。 DNS (scripts/check-dns-drift.sh): hosts/homeserver.nix の sites 表は reverse proxy と死活監視を駆動しているのに、 A レコードだけ手作業で取り残されていた。Caddy の virtualHosts (sites 表そのもの ではなく生成後) と Cloudflare の A レコードを突き合わせ、足りないものと宛先違いを 出す。--apply で寄せる。宛先は tailnet の homeserver で、Tailscale が割り当てる ので nix には書けず tailscale status から引く。 実行したところ 21/21 一致で、Proxmox 時代の残骸が 7 件 (pve/dockge/jellyfin/ navidrome/backrest/wud/dns) 浮かんだ。EXTRA では落とさない — apex や Pages 向けの 正当なレコードが同じ zone に同居しているため。 tailnet (scripts/tailscale-policy.sh) と NextDNS (scripts/nextdns-profile.sh): どちらも管理コンソールにしか設定が無く、repo に一文字も無かった。fetch で現物を 落とし、diff でずれを見て、apply で戻す。API トークンをまだ作っていないので **ライブ API に対しては未検証**。最初の fetch が動作確認を兼ねる。 ESPHome (esphome/): サービスは sites 表に載っているのにデバイスの YAML がコンテナの中にしか無かった。 gapul/esp32-plant-watering の docs/design.md をそのまま YAML にした。部品が届く前 なので閾値と給水秒数は仮置き。設計上の制約 (ADC1 系のみ / strapping pin 回避 / センサーは測るときだけ通電 / ポンプは script 経由 / 再起動で回さない / 4 鉢は順番) はコメントで理由ごと残した。1 鉢分を common/pot.yaml にして packages で 4 回展開する 構成は設計書の指示どおり。 validate.sh が実機も鍵も無しで構文検証する (雛形の secrets を使う)。CI に載せた。 esphome config は検証エラーを stdout に出すので、>/dev/null すると黙って失敗する。
A レコード (tailnet 内向け) しか見ておらず、CNAME でトンネルを向く公開面が 射程外だった。ingress は homelab/cloudflared.nix に宣言してあるので、CNAME が それと食い違えば機械に言わせられる。「homeserver は生きているのにトンネルだけ 旧 IP を向いている」で Matrix の federation を一日落とした前科がある面なので、 ここを見ないのは片手落ちだった。 アカウントのトンネル一覧も出す。宣言の無いものに ? を付けるだけだが、それで 2 つ見つかった: - homelab-pi (8fe36752) が down / 接続 0 のまま消されずに残っている。 cloudflared.nix のコメントどおり homeserver へ作り直した後の残骸。 - manabi (5f908e74) は healthy で接続 4。manabi-api.gapul.net を実際に 提供している別プロジェクトで、この repo の管理外。 管理外のトンネルを向く CNAME では落とさない。別プロジェクトが正当に同居して いることがあるので、素性を出すだけにする (A レコードの EXTRA と同じ扱い)。 docs/HOMELAB.md の「Cloudflare に A レコード追加」という手作業の指示を just dns への差し替えに直した。
DNS の EXTRA 7 件を素性ごとに分けた。消すのが正しいのは 5 件だけだった。 jellyfin / navidrome は消す側ではなかった。サービスは homelab で宣言して動いて いて、ダッシュボードも https://jellyfin.gapul.net へリンクしているのに、sites 表に vhost だけ無かった。つまり https では繋がらず、直接ポートを叩けば見えるので 気付かれていなかった。DNS を消すのではなく vhost を足して宣言側に載せる。 dns.gapul.net は AdGuard だが AdGuard は Pi に居て、レコードは homeserver を 指していた。誰も応答しないので、ダッシュボードのリンクを Pi の実アドレスへ 向け直したうえでレコードを消した。 Cloudflare 側で消したもの (repo の変更ではない): - A: backrest / dns / dockge / pve / wud — いずれも Proxmox 時代の残骸で、 vhost もサービスも無い - トンネル: homelab-pi (down / 接続 0)。cloudflared.nix のコメントどおり homeserver へ作り直した後の残骸で、これを向く CNAME も無かった これで just dns は 23/23 一致、EXTRA なし。残るのは manabi (稼働中の別 プロジェクト) だけで、これは管理外として素性を出すに留める。
ドメインのメールは Cloudflare Email Routing に載っているが、必要なレコードが 消えても誰も何も言わない。配送されなくなるだけで、気付くのは「返事が来ない」と 言われたときになる。静かに壊れる面なので機械に見せる。 期待値は Cloudflare 自身が持っている。/email/routing/dns が「この zone で メールを受けるのに必要なレコード」を返すので、それを SSOT にして実レコードと 突き合わせる。こちらで MX の優先度や SPF の文面を書き写す必要が無く、 Cloudflare 側が要求を変えれば自動で追従する。 比較の前に均す必要があるものが 3 つあった。要求側は FQDN の末尾にドットが付く。 TXT は囲みの引用符の有無が食い違う。そして TXT は 1 文字列 255 バイト上限で 分割されるので、実レコード側が "前半" "後半" になる。DKIM がまさにこれで、 連結分の 3 文字だけずれて「存在するのに MISSING」と誤報していた。 これで just dns は A レコード / トンネルの CNAME / メールの 3 面を見る。 現状は全面一致で exit 0。
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.
#270 のマージ後に積んでいた 3 コミットが取り残されていたので出し直す。
1. CalDAV プロファイルの宛先が間違っていた (これが本命)
radicale の
127.0.0.1:5232をhomeserver.gapul.net:5232として直接指し、CalDAVUseSSL = falseにしていた。実際にはnix/hosts/homeserver.nixのsites表がdavの vhost を立てていて Caddy が ACME 証明書で終端している。そのままだと CalDAV/CardDAV の資格情報が平文で流れるうえ、宛先自体が違う。
dav.gapul.net+UseSSL = trueに修正。ポート指定も落とした (443)。2. Aurora Store の担当をゼロにし、
adoptで実機から回収できるようにしたplay→githubに移した。これでplay行がゼロになり、宣言した Android アプリ全件が Obtainium の URL リスト import 一発で端末に載る。apps.sh adopt— 端末に在って宣言に無いものを、配布元を引いて経路を判定した tsv 行として出す。Aurora Store で先に入れたものを packageId を目で追って書き写す作業を機械にやらせる。>>apps.tsvで追記してから整える。3. 宣言の腐りを週次 CI で見る (
.github/workflows/mobile-drift.yml)実機は CI から触れないので、確かめるのは宣言が腐っていないかだけ。packageId / bundleId が配布元から消えていないか、GitHub の repo が改名されていないか。押した瞬間には気付けないものだけを定期実行に回す方針。PR で
mobile/**を触ったときにも走る。実機に触る側 (
status/os.sh/install) は手動のまま。端末が常時繋がっていないので、繋がっていない間に「適用したつもり」の状態を作りたくない。この線引きはmobile/README.mdに表で書いた。検証
just mobile-test→ 12 項目すべて ok (実機不要)nix build .#ios-profiles→ 生成物の宛先がdav.gapul.net/UseSSL=trueであることを確認just docs再生成済み、pre-commit 通過