「下書き」のつもりのお知らせが、全世界に公開されていた
Kimiのkimi-for-codingで執筆しました
個人でやっているサービスの、お知らせ(News)まわりを整えていたときの話です。
障害が起きたときや、機能を足したときに、ちゃんと告知を残す運用を作ろうとしていました。サイトは静的サイト(=あらかじめ全ページをHTMLに焼いて配る方式)で、お知らせは1記事1ファイルのMarkdown。ファイルの先頭に、こんな設定を書きます。
draft: true
「これは下書きだから、まだ表に出さないでね」の意味です。当然そう思いますよね。自分も思っていました。
一覧に出ないから、安心していた
サイトのお知らせ一覧をブラウザで開くと、draft: trueの記事はちゃんと出てきません。非公開になっている。うん、想定どおり。
で、テンプレ代わりにdraft: trueの記事を1本、リポジトリに置いていたんです。「新機能お知らせのひな形」みたいなやつ。中身は未完成の埋め草。一覧に出ないなら、置きっぱなしでいいや、と。
念のため、URLを直打ちして確かめてみました。一覧に出ないんだから、当然404で弾かれるはず。
200が返ってきました。
未完成の埋め草が、URLさえ知っていれば、世界中の誰でも読める状態で本番に鎮座していた。ホラー映画ですか?自分の本番サイトが舞台の。
犯人は「地図を作る関数」だった
種を明かします。静的サイトは、公開前に全ページのURL一覧(=地図)を作って、その地図の分だけHTMLを焼きます。
問題は、この地図を作る処理が draftを見ていなかったこと。
- 一覧を作る処理は、
draft: trueをちゃんと除外していた(だから一覧には出ない) - URLの地図を作る処理は、
draftをおかまいなしに全部拾っていた(だから直リンクは焼かれて公開される)
同じ「記事を集める」でも、片方は下書きを弾いて、もう片方は弾いていない。左手が隠したものを、右手がこっそり全部出していた、という間抜けな構図です。
つまりdraft: trueは、この構成では「一覧に載せない」以上の意味を持っていなかった。非公開フラグだと思っていたものは、ただの「目次から外す」フラグだったわけです。
静的サイトに「こっそりプレビュー」は無い、という話
ここで効いてくる、地味だけど大事な前提があります。
静的サイトは、焼いた瞬間に全部が公開物になります。「本番に置いてあるけど、自分だけ見られる下書き」みたいな中間状態は、素の状態だと存在しないんです。焼かれたHTMLは、URLを知っている人には等しく届く。
動的なブログCMSだと「ログインした自分だけプレビュー」ができたりします。あの感覚のまま静的サイトに来ると、事故る。draftと書いた瞬間に守られている気がしてしまうのが、罠のいちばん深いところでした。
どう直したか
やったことは2つです。
- 下書き・テンプレの類を、公開されるフォルダから追い出した。ひな形はドキュメント側(公開対象外のところ)に置いて、実際に出すときだけ公開フォルダにコピーする。公開フォルダに未完成品を置かない、という当たり前の運用に戻しました。
- 本当のプレビューは、別環境にデプロイして見る。本番とは別の確認用サイトに出して、そこで見てから本番に上げる。「本番に下書きを置いて自分だけ見る」を諦めて、「確認用の場所を別に持つ」に切り替えました。
それと、地図を作る側のコードも直しました。 下書きは地図に載せない、と関数のほうに書いた。 運用で気をつけるだけにしておくと、次に同じ置き方をした瞬間、また同じ形で漏れるので。
合言葉はこれです。
「下書き」と書いても、置き場所が公開フォルダなら、それは公開物。
未完成品を公開フォルダに置いている方は、今すぐURLを直打ちして
- 静的サイトの
draftフラグは、実装が対応していて初めて非公開になる。フラグの名前を信用してはいけない。名前は願望で、挙動が現実です。 - 「一覧に出ない」と「アクセスできない」はまったく別物。目次から消えただけで、部屋の鍵は開いている。URL直打ちで必ず確かめる。
- 静的サイトに「本番上のこっそりプレビュー」は原則無い。プレビューが欲しいなら、別環境を用意する。守られている気分がいちばん危ない。
公開フォルダに未完成品を置いている方、今すぐURLを直打ちしてみてください。200が返ってきたら、それはもう下書きではありません。皆様もお気をつけください。