cuerda blog

cuerda の開発者が考えていることを発信

連載 ChatGPTとCodexで進めるUbuntu開発環境移行

【第11回】ライセンス判定とRSSレスポンスの不一致を安全に切り分ける

投稿日:

ライセンス認証

みなさま、こんにちは。クエルダ開発担当の渡部公也です。

前回は、長期間開発と運用を続けているWordPressプラグイン「Cuerda-Feed-Total」をUbuntuへ移しました。

Gitリポジトリだけでなく、Codexへプロジェクト固有のルールを伝えるAGENTS.md、検査手順をまとめた専用スキル、Composer、PHPCS、WordPressとの接続方法も新しい環境へ引き継ぎました。

今回は、Ubuntuへ移したCuerda-Feed-Totalで、実際のRSS出力を確認します。

確認の途中で、WordPress内部ではライセンスが無効と判定されている一方、ブラウザと同じHTTP経由では正常なRSSが返るという、異なる結果が見つかりました。

このような場合、どちらか一方の結果だけを見て、ライセンスが有効または無効と判断することはできません。

今回は、ライセンスキー、トークン、APIレスポンスなどの秘密情報を表示せず、WordPress内部の状態とHTTPレスポンスを分けて確認します。

また、結果が一致しなかった場合に、データベース、テーマ、キャッシュなどを安易に変更せず、安全に調査を停止する考え方についても紹介します。

RSSの表示確認だけでは不十分な理由

Cuerda-Feed-Totalは、配信先ごとの仕様に合わせたRSSを生成するWordPressプラグインです。

ブラウザやcurlからRSSへアクセスし、XMLが表示されれば、正常に動作しているように見えます。

しかし、RSSが返ったという事実だけでは、内部のライセンス判定まで正常であるとは限りません。

反対に、WordPress内部の確認でライセンスが無効と判定されても、HTTPレスポンスではRSSが返る場合があります。

これは、ライセンス確認とRSS生成が、必ずしも一つの処理だけで完結しているわけではないためです。

例えば、次のような処理が関係する可能性があります。

  • WordPressへ保存されているライセンス状態
  • 外部ライセンスサーバーから取得した結果
  • 一時的に保存されたキャッシュ
  • 配信先ごとに異なるライセンス判定
  • RSSリクエスト時に実行される条件分岐
  • 過去の検証で生成されたレスポンス
  • 通常のWordPress実行とHTTPリクエストの環境差

そのため、ライセンスとRSSを確認する場合は、内部状態と外部から見える結果を分けて調査します。

今回確認する二つの経路

今回の検証では、同じ配信先について、二つの異なる経路から状態を確認しました。

ライセンスとRSSを確認する経路
確認経路 確認する内容
WordPress内部 プラグインのライセンス確認関数が返す状態
HTTPレスポンス 実際のRSS URLへアクセスした際のステータスと本文

WordPress内部の確認では、Cuerda-Feed-Totalが保持しているライセンス状態を、プラグイン内部の処理を通して確認します。

HTTPレスポンスの確認では、ブラウザや外部のRSS取得システムに近い方法で、実際のURLへアクセスします。

この二つが一致すれば、内部状態と外部出力の関係は比較的分かりやすくなります。

結果が一致しない場合は、どの処理経路で差が生じているのかを、さらに調査する必要があります。

調査前の基準状態を確認する

最初に、Cuerda-Feed-TotalのGitリポジトリへ移動します。

cd /mnt/studio317-data/development/projects/cuerda-feed-total

調査を始める前に、ブランチ、作業ツリー、最新コミットを確認しました。

git status --short --branch
git log -1 --oneline --decorate
git remote -v

この確認で、未コミットの変更がないことと、予定しているGitHubリポジトリを参照していることを確認します。

続いて、WordPress側でプラグインが認識され、有効になっていることも確認しました。

cd /var/www/studio317/wordpress-dev/public

wp plugin status cuerda-feed-total

調査前の状態を記録しておけば、確認作業によってソースコードやWordPressの状態が変化していないかを、後から比較できます。

秘密情報を表示しない検査方針

ライセンスの確認では、ライセンスキー、認証トークン、外部サーバーからのレスポンスなどを扱う可能性があります。

しかし、今回必要なのは、ライセンスの値そのものではなく、プラグインが最終的にどの状態と判定したかです。

そこで、確認結果は次のいずれかへ正規化し、判定だけを表示する方針としました。

  • valid
  • invalid
  • unknown
  • error

次の情報は出力しません。

  • ライセンスキー
  • ライセンスサーバーのURL
  • アクセストークン
  • 認証用のヘッダー
  • 外部APIの生レスポンス
  • WordPressへ保存されている秘密情報

Codexへ確認を依頼する場合も、戻り値をそのまま表示するのではなく、状態だけを報告するように指定します。

Codexへ内部ライセンス確認を依頼する

今回確認する配信先は、Cuerda-Feed-Total内部でlnrとして扱われています。

Codexには、ライセンス確認関数の戻り値を安全に正規化し、最終的な判定だけを報告するよう依頼しました。

このリポジトリとローカルWordPressを使用して、
lnrの内部ライセンス状態を確認してください。

cuerda_check_license_status( 'lnr' )の戻り値だけを使用し、
結果をvalid、invalid、unknown、errorのいずれかへ正規化してください。

ライセンスキー、トークン、保存されている設定値、
外部APIのURLやレスポンスは出力しないでください。

確認だけを行い、PHPファイル、データベース、
テーマ、プラグイン設定、キャッシュは変更しないでください。

内部状態がvalid以外の場合は、
RSSの修正や環境変更へ進まず停止してください。

今回の確認では、内部ライセンス状態はinvalidと判定されました。

この時点で、ライセンスが実際に無効であると確定したわけではありません。

確認できたのは、現在のWordPress内部からライセンス確認関数を実行した場合に、無効として正規化されたという事実です。

HTTP経由でRSSを取得する

続いて、実際のRSS URLへHTTPでアクセスします。

今回のローカル検証環境では、次のURLを使用しました。

http://127.0.0.1:18083/?feed=cuerda_total&lnr=1

curlを利用し、HTTPヘッダーとRSS本文を別々の一時ファイルへ保存します。

curl -sS \
-D /tmp/cuerda-lnr-headers.txt \
-o /tmp/cuerda-lnr-response.xml \
'http://127.0.0.1:18083/?feed=cuerda_total&lnr=1'

-DでHTTPヘッダーを、-oでレスポンス本文を保存しています。

RSS本文には投稿内容などが含まれる可能性があるため、必要がない限りChatGPTや外部サービスへそのまま共有しません。

HTTPステータスを確認する

最初に、HTTPレスポンスのステータスコードを確認します。

head -n 1 /tmp/cuerda-lnr-headers.txt

今回の結果は、HTTPステータス200でした。

HTTPステータス200は、Webサーバーがリクエストを正常に処理し、何らかのレスポンスを返したことを示します。

ただし、200が返っただけでは、RSSの内容やライセンス判定が正しいことまでは分かりません。

エラーメッセージが記載されたページや、不完全なXMLでも、HTTPステータス200が返ることがあります。

RSS本文が空ではないことを確認する

続いて、保存されたレスポンス本文が空ではないことを確認しました。

test -s /tmp/cuerda-lnr-response.xml \
&& echo "response is not empty" \
|| echo "response is empty"

今回のレスポンスは空ではありませんでした。

ファイルサイズも確認できます。

wc -c /tmp/cuerda-lnr-response.xml

本文が存在していても、それがRSSとは限りません。

次に、XMLとRSSの基本構造を確認します。

RSSの開始タグと終了タグを確認する

RSSとして最低限の構造が存在することを確認するため、<rssから始まる要素と</rss>の終了タグを検索しました。

grep -q '<rss' /tmp/cuerda-lnr-response.xml \
&& echo "RSS start tag found" \
|| echo "RSS start tag not found"

grep -q '' /tmp/cuerda-lnr-response.xml 
&& echo "RSS end tag found" 
|| echo "RSS end tag not found"

今回のレスポンスには、RSSの開始タグと終了タグの両方が含まれていました。

これにより、単なるHTMLのエラーページではなく、少なくともRSS形式の文書が返っていることを確認できます。

ただし、この確認だけでは、すべての必須要素や配信先固有の仕様を満たしているかまでは判断できません。

ライセンスエラーの文言を確認する

Cuerda-Feed-Totalでは、ライセンスが無効な場合に、レスポンスへエラーを示す文言が含まれることがあります。

今回の配信先について、次の文言が含まれていないか確認しました。

grep -Fq \
'License invalid for ISP: lnr' \
/tmp/cuerda-lnr-response.xml \
&& echo "license error found" \
|| echo "license error not found"

今回のHTTPレスポンスには、License invalid for ISP: lnrという文言は含まれていませんでした。

HTTP側の確認結果だけを見ると、ライセンスエラーは表示されず、有効な形式のRSSが返っているように見えます。

二つの確認結果を比較する

今回の確認結果をまとめると、次のようになりました。

内部ライセンス状態とHTTPレスポンスの比較
確認項目 結果
WordPress内部のライセンス状態 invalid
HTTPステータス 200
レスポンス本文 空ではない
RSS開始タグ あり
RSS終了タグ あり
ライセンス無効の文言 含まれない

WordPress内部では無効と判定されましたが、HTTP経由では正常なRSSが返っています。

二つの結果は一致していません。

この状態で、「HTTPでRSSが返ったからライセンスは有効」と判断することも、「内部判定が無効だからRSSは利用できない」と判断することもできません。

確認経路の違いによって、異なる条件やデータが使用されている可能性があります。

HTTPステータス200はライセンス有効を意味しない

HTTPステータス200は、HTTPリクエストが処理されたことを示す結果です。

ライセンスサーバーとの通信、ライセンスキーの有効性、配信先の利用権限などを保証するものではありません。

同様に、RSSの開始タグと終了タグがあることも、内部ライセンスが有効である証明にはなりません。

次のような状況でも、RSS形式のレスポンスが返る可能性があります。

  • ライセンス判定を通らない別の処理経路がある
  • 過去の有効状態がキャッシュされている
  • HTTPリクエストでは別のWordPress環境へ接続している
  • 配信先固有の判定が実行されていない
  • 無効時にも空のRSSを返す設計になっている
  • エラーをRSS内へ出力しない設定になっている

そのため、HTTP側では、ステータスだけでなく、レスポンスの生成経路も確認する必要があります。

内部ライセンス無効も確定結果とは限らない

WordPress内部の関数がinvalidを返した場合も、実際の契約やライセンスキーが無効であると、ただちに確定できるとは限りません。

内部判定には、次のような要因が影響する可能性があります。

  • 現在のWordPressへライセンス情報が保存されていない
  • 別のローカル環境のデータベースを参照している
  • 配信先を示す識別子が想定と異なる
  • 一時的な通信エラーが無効として扱われている
  • キャッシュされた古い状態を参照している
  • CLI実行時とHTTP実行時で初期化処理が異なる
  • 必要なWordPressフックがCLI側では実行されていない

特に、WP-CLIから関数を直接実行した場合と、通常のHTTPリクエストでは、WordPressの起動後に実行される処理やフックの順序が異なることがあります。

内部関数の結果も、どの実行環境で取得したものなのかを含めて評価する必要があります。

最初に同じ環境を見ているか確認する

二つの結果が一致しない場合、最初に確認するのは、内部確認とHTTP確認が同じWordPressを参照しているかという点です。

次の項目を比較します。

  • WordPressの設置場所
  • サイトURL
  • データベース
  • 有効なプラグイン
  • Cuerda-Feed-Totalのバージョン
  • Gitリポジトリの最新コミット
  • HTTPリクエストを受け付けているポート

WP-CLIが操作しているWordPressのURLは、次のコマンドで確認できます。

wp option get siteurl
wp option get home

WordPress本体の場所も確認します。

wp eval 'echo ABSPATH, PHP_EOL;'

HTTP側のポートをどのサービスが使用しているかは、次のように確認できます。

sudo ss -lntp | grep ':18083'

内部確認とHTTP確認が異なるWordPress環境を参照していれば、結果が一致しなくても不思議ではありません。

すぐにキャッシュを削除しない

ライセンス状態が一致しない場合、最初にキャッシュを削除したくなることがあります。

しかし、原因を確認する前にキャッシュを消すと、調査に必要な状態まで失われる可能性があります。

また、キャッシュの削除によって一時的に結果が一致しても、なぜ不一致が発生したのか分からなくなります。

最初は、次のような情報を変更せずに確認します。

  • ライセンス状態の保存場所
  • キャッシュまたはTransientのキー
  • 保存された時刻
  • 有効期限
  • 読み込み処理と更新処理
  • CLIとHTTPで同じ値を参照しているか

値そのものに秘密情報が含まれる場合は、内容を表示せず、存在の有無、型、更新時刻、状態の分類だけを確認します。

RSSの入口から処理を追跡する

次に確認するのは、RSSリクエストがどのPHPコードから処理されているかです。

今回のURLには、次のクエリが含まれています。

?feed=cuerda_total&lnr=1

最初に、cuerda_totalというフィードを登録している場所を調べます。

grep -RIn \
--exclude-dir=.git \
--exclude-dir=vendor \
"cuerda_total" \
.

続いて、lnrのリクエスト値を確認している場所を検索します。

grep -RIn \
--exclude-dir=.git \
--exclude-dir=vendor \
"lnr" \
.

検索結果から、次の処理を順番に確認します。

  1. フィードの登録

    WordPressへcuerda_totalを登録している処理を確認します。

  2. 配信先の判定

    lnr=1を受け取り、配信先を決定する処理を確認します。

  3. ライセンス確認

    RSS生成前に、どの関数でライセンスを判定しているか確認します。

  4. RSSテンプレートの選択

    どのテンプレートまたは生成クラスが使用されるか確認します。

  5. エラー時の処理

    ライセンス無効時に処理を停止するのか、エラー文を出すのか、空のRSSを返すのか確認します。

HTTPレスポンスだけでは見えない処理の流れを、ソースコードから確認します。

同じHTTPリクエスト内でライセンス状態を確認する

WP-CLIで確認した内部状態とHTTPレスポンスが一致しない場合、同じHTTPリクエスト内でどのライセンス状態が使用されているかを確認する必要があります。

ただし、ライセンス判定をRSS本文へ直接出力すると、外部へ内部情報を公開する危険があります。

そのため、確認を行う場合は、次の条件を満たす一時的な診断方法を検討します。

  • ローカル環境だけで動作する
  • 管理者またはCLIからだけ確認できる
  • ライセンスキーやトークンを出力しない
  • valid、invalidなどの分類だけを記録する
  • RSS本文の構造を変更しない
  • 確認後に診断コードを削除できる
  • Git差分で追加と削除を確認できる

今回の段階では、原因が特定されていないため、一時的な診断コードの追加までは行いませんでした。

まずは既存コード、現在の設定、実行環境の違いを確認することを優先します。

Codexへ不一致の調査を依頼する

内部状態とHTTP結果が一致しなかったため、Codexには修正ではなく、原因候補の調査だけを依頼しました。

lnrについて、次の不一致が確認されています。

・cuerda_check_license_status( 'lnr' )の内部確認はinvalid
・HTTPレスポンスは200
・レスポンス本文は空ではない
・RSSの開始タグと終了タグがある
・License invalid for ISP: lnrは含まれない

ファイルやデータを変更せず、次の内容を調査してください。

・内部確認とHTTPリクエストが同じWordPress環境を参照しているか
・cuerda_totalフィードの登録場所
・lnrリクエストの処理経路
・HTTP側で使用されるライセンス確認処理
・CLIとHTTPで初期化処理に差がある可能性
・キャッシュやTransientを参照する処理
・ライセンス無効時のRSS生成処理
・結果が一致しない原因候補

ライセンスキー、トークン、APIレスポンス、
データベースの秘密情報は出力しないでください。

データベース、テーマ、プラグイン設定、
キャッシュ、PHPファイルは変更しないでください。
コミットとpushも行わないでください。

原因が分からない段階で修正まで依頼すると、根拠のない変更が行われる可能性があります。

まず事実と処理経路を整理し、変更が必要かどうかを判断します。

安全条件を満たさない場合は停止する

今回の確認では、内部ライセンス状態がinvalidでした。

一方、HTTP側では正常なRSSが返っていました。

この状態では、どちらの結果を正しい基準として扱うべきか判断できません。

そのため、次の操作は行わず、調査を停止しました。

  • データベースのライセンス状態を書き換える
  • ライセンスキーを再保存する
  • キャッシュやTransientを削除する
  • テーマを切り替える
  • RSS生成コードを変更する
  • ライセンス判定を迂回する
  • 配信先へ実際のRSSを送信する
  • 原因が不明なままコミットする

調査を停止することは、作業の失敗ではありません。

安全に判断できない状態で環境を変更しないことも、開発と保守における重要な判断です。

確認後にGitの状態を確認する

今回の作業は調査だけであり、ソースコードを変更していません。

最後に、Gitの状態を確認しました。

cd /mnt/studio317-data/development/projects/cuerda-feed-total

git status --short --branch
git diff
git diff --check

未コミットの変更がなく、作業前の基準状態が保たれていることを確認します。

また、一時ファイルとして保存したHTTPヘッダーとRSS本文は、確認後に不要であれば削除します。

rm -f \
/tmp/cuerda-lnr-headers.txt \
/tmp/cuerda-lnr-response.xml

RSS本文に投稿内容が含まれている可能性があるため、共有ディレクトリやGitリポジトリへ残さないようにします。

今回の調査で分かったこと

今回の確認では、ライセンスの有効性そのものを確定することはできませんでした。

一方で、次の事実を分けて確認できました。

  • WordPress内部の確認関数はinvalidと判定した
  • ローカルのRSS URLはHTTPステータス200を返した
  • レスポンス本文は空ではなかった
  • RSSの開始タグと終了タグが存在した
  • ライセンス無効を示す文言は含まれていなかった
  • 内部状態とHTTPレスポンスは一致していなかった
  • 原因が不明なため、環境やコードは変更しなかった

調査では、分かったことと、まだ分からないことを分けて記録することが重要です。

「RSSが表示された」という結果だけで問題なしとせず、「内部状態が無効だった」という結果だけでライセンス切れとも判断しません。

ChatGPT、Codex、人間の役割

今回のような診断作業では、AIにすべての判断を任せるのではなく、それぞれの役割を明確にします。

ChatGPT
内部状態とHTTPレスポンスを分ける考え方、秘密情報を出さない確認方法、調査を停止する条件を整理します。
Codex
WordPress内部の状態、RSSの処理経路、Gitの状態を、指定された範囲内で確認します。
curlとWP-CLI
HTTPレスポンスとWordPress内部の状態を、それぞれ別の経路から確認します。
Git
調査中にソースコードへ意図しない変更が行われていないことを確認します。
人間
秘密情報の扱い、調査範囲、変更を許可する条件、作業を停止する判断を担当します。

AIは調査を支援できますが、どの結果を根拠として環境を変更するかは、人間が確認して決定します。

今回の到達点

今回は、Ubuntuへ移したCuerda-Feed-Totalで、WordPress内部のライセンス状態と、HTTP経由のRSSレスポンスを分けて確認しました。

内部のcuerda_check_license_status( 'lnr' )invalidと判定しました。

一方、HTTP経由ではステータス200が返り、レスポンスは空ではなく、RSSの開始タグと終了タグも存在しました。

また、License invalid for ISP: lnrというエラー文も含まれていませんでした。

二つの結果が一致しなかったため、ライセンスの有効性を確定せず、データベース、テーマ、キャッシュ、ソースコードなどの変更は行いませんでした。

ライセンスキー、トークン、APIレスポンスなどの秘密情報を出力せず、判定結果だけを確認できたことも重要な成果です。

問題をすぐに修正するのではなく、確認経路の違いを整理し、安全に停止するところまでを一つの診断作業として完了しました。

次回の予定

次回は、内部ライセンス状態とHTTPレスポンスが一致しなかった原因を、RSSリクエストの入口から順番に調査します。

cuerda_totalフィードの登録、lnrの判定、ライセンス確認、キャッシュ、RSS生成処理をたどり、CLIとHTTPで異なる処理が実行されていないか確認します。

必要な場合は、秘密情報を出力せず、ローカル環境だけで使用できる一時的な診断方法を検討し、原因を特定できるまでソースコードやデータベースの修正は行わない方針で進めます。