ssrf.dev

Obsidianやら何やらを組み合わせたブログをつくりました

目次
  1. N度目の正直の新しいブログを立ち上げ
  2. 裏側
  3. 記事公開までのフロー
  4. Vault→ブログのrepoの同期ワークフロー
  5. お悩みポイント
  6. 所感

N度目の正直の新しいブログを立ち上げ

こんにちは、yagihashです。

Obsidianからブログを更新できるようにした — tellme.tokyoを見て「お、それいいじゃん」と思い立ってしばらく経ちまして、ssrf.devを立ち上げました。所要時間はClaude Codeにぶん投げて12時間くらい?ブログはいろいろやってきましたが正直あまり長続きしなくて、何度目かわかりませんが今回こそは長生きして欲しいなーと思っています。

やってること自体はbabarotとほぼ同じなんですが、ガワを作るところからだったりしたのでちょっと時間かかったかなーという感触。とはいえ今回まじで自分でコード1行も書いてないですね。同期用のGitHub AppのPrivate Keyを入れるKMSとかWIFの設定含めて何もかもClaude Code任せでした。

深夜に思い立ってCloudflare Pagesでプレビューを確認できる環境まで整えて、あとはremote-controlでベッドから作業して、変更の都度プレビューで確認、みたいな感じでした。寝落ちして朝起きてmacで作業を再開して、なんやかんやあって今に至るという具合です。

普段ブログはもっぱらyagihash|しずかなインターネットに書いてるんですが、コードとか載せようとするとさすがにちょっと用途が違うよね、という感じがあり、かといって何もかもzennに載せるのもちょっとなぁというのがあり、ちょうどいいブログ枠としてこれに期待しています。

裏側

記事公開までのフロー

Claude Codeに書かせたので合ってるかは知らないです。冗長だなーと思いつつ書き直す元気はないのでほぼそのまま載せます。

flowchart TD
      subgraph local["ローカル"]
          obsidian["Obsidian (ブログ執筆)"]
      end

      subgraph vault["yagihash/obsidian"]
          main["main blog/*.md"]
      end

      subgraph gcp["Google Cloud"]
          wif["Workload Identity Federation"]
          kms["Cloud KMS (GitHub App 秘密鍵)"]
      end

      subgraph actions["GitHub Actions (yagihash/obsidian)"]
          sync["sync-blog-to-ssrf-dev push トリガー"]
          reconcile["reconcile-blog-to-ssrf-dev 毎時 / 手動"]
      end

      subgraph ssrfdev["yagihash/ssrf.dev"]
          branch["obsidian/{slug} ブランチ (signed commit)"]
          pr["Pull Request"]
          site["🌐 ssrf.dev"]
      end

      obsidian -->|"Obsidian Git 自動 push"| main
      main -->|"blog/*.md 変更時"| sync
      main -->|"毎時"| reconcile

      sync & reconcile -->|"WIF 認証"| wif
      wif --> kms
      kms -->|"Installation Token"| sync & reconcile

      sync -->|"変換 + signed commit"| branch
      reconcile -->|"差分検出 + signed commit"| branch
      branch --> pr
      pr -->|"手動マージ"| site

Vault→ブログのrepoの同期ワークフロー

pushで動くやつ

基本的にはこっちのワークフローでObsidianのVaultに置かれたMarkdownファイルとか画像ファイルを良い感じにしてブログのrepoに配置するPRを立てに行く、という流れです。

flowchart TD
      push["blog/*.md が push された"]
      changed["変更ファイルを検出 git diff HEAD~1 HEAD"]
      meta["フロントマターから slug / title / pubDate 抽出"]
      branch{"obsidian/{slug} が origin に存在?"}
      checkout_existing["既存ブランチを checkout"]
      checkout_new["新規ブランチを作成"]
      convert["convert-blog-post.py Obsidian → Astro 形式に変換 (![[画像]] → ![](/) など)"]
      signed["push-signed-commit.py GitHub API で signed commit 作成"]
      pr_exists{"open な PR が存在?"}
      create_pr["gh pr create [obsidian] Add/Update: タイトル"]
      skip["スキップ"]

      push --> changed --> meta
      meta --> branch
      branch -->|"Yes"| checkout_existing
      branch -->|"No"| checkout_new
      checkout_existing & checkout_new --> convert --> signed
      signed --> pr_exists
      pr_exists -->|"No"| create_pr
      pr_exists -->|"Yes"| skip

スケジュールor手動で動くやつ

必要かどうかけっこう悩んだのですが差分見て全部綺麗にするPRを立てる、みたいなワークフローはあっても良さそうだな、と思って用意しました。使うかどうかは今のところわからず。

flowchart TD
      trigger["毎時 or 手動実行"]
      compare["reconcile-blog-posts.py blog/ と ssrf.dev/ を全件比較"]
      changes["変更リスト (JSON) add / update / delete"]
      loop["各記事をループ処理"]

      add["convert-blog-post.py で変換・コピー"]
      update["convert-blog-post.py で変換・コピー"]
      delete["rm でファイル削除"]

      signed["push-signed-commit.py で signed commit"]
      pr["PR 作成 or スキップ"]

      trigger --> compare --> changes --> loop
      loop -->|"action=add"| add
      loop -->|"action=update"| update
      loop -->|"action=delete"| delete
      add & update & delete --> signed --> pr

お悩みポイント

Obsidianのアプリ同士の同期はObsidian Syncを使っているので、例えば出先でiPhoneで記事を書いて各端末に同期する、というところまでは実現可能なんですが、GitHubへの同期はiOSとの相性があまりよくないCommunity PluginのGitを使っていて、ここが最後の壁になっています。(つまり今はiOS→GitHubの経路がない)

常時起動してObsidian Syncで流れてきた差分をGitHubに流してくれる環境をひとつ持っておくのがたぶん簡単なんですが、なんだかなぁという感じです。Claude Codeのremote-controlとかloopとかももっとがっつり使いたいですし、Mac miniを買うか割と真剣に迷っています。

所感

Vault→ブログのrepoにPR立てにいくところとか、Markdownの変換とか、個人的にはいくつか「めんどくさいなー」というポイントがあったんですが、イマドキのめんどくさいのハードルはめちゃくちゃ下がったのを改めて強く感じました。Actionsがコケたのもrun-id渡してこれ見て直して、で終わりですし、試行錯誤の質がだいぶ変わったと思います。

せっかく作ったのでちょこちょこ更新していきたいなーと思います。次回をお楽しみに。