testable constraint

関心

Rails を利用するに当たって先日の脆弱性

Rails 4.2.11.1, 5.0.7.2, 5.1.6.2, 5.2.2.1, and 6.0.0.beta3 have been released! | Riding Rails

の対策などはいちいち controller に処理が渡る前に処理を終わらせて 404 などのエラーを返してしまいたい。実際に稼働中のアプリに脆弱性がない場合でも悪意のある bot 対策という意味ではいろいろなケースで同様のことが言える。

これは具体的には routing の constraint を利用することで実現可能である。1

このような設計にしておくことには controller の before_action callback などで処理する手法に比べて以下のようなメリットがある。

  • action の dispatch に掛かるコストを節約できる(脆弱性目的のアクセスは過負荷になりがち)
  • controller は自分の責務に集中したコードだけを書けばよいので読み書きしやすい

ではどうやってこれを実現すればよいだろうか。

複雑なconstraintをProcで書くのは無理がある

しかし constraint を Proc で書こうとすると非常に書きにくい。単純な文字列比較などならよいが、request オブジェクトの中身を検証するようなものは

  • コードが長くなって rouitng が読みにくくなる
  • そもそもテストしにくい
    • routing のテストになるが、routing spec の DSL ではそのまま request header をセットすることができない
  • 条件を変えてテストコードを書いておきたいが、例えば constraint が外れていた場合に実際に問題が発生する(脆弱性に繋がる例外があがる)ことを検証しようとするとますます複雑になる

という問題がある。

Objectで書こう

constraint は Object と method で書くこともできる。

Rails Routing from the Outside In — Ruby on Rails Guides

これを読むと

#matches?

を呼べさえすればよい。#matches? に request が渡ってくるのでオッケーかどうかを true か false で返してあげるという寸法だ。

class Constraint
  def matches?(request)
  end
end

で new して渡しても

class Constraint
  def self.matches?(request)
  end
end

でそのまま渡しても include Singleton してもよい。

テストする場合は request object をそのまま渡せばよいので、ActionDispatch::Request や ActionDispatch::TestRequest を使えばよい。

これで routing spec の DSL が足りないといって気を揉む必要もなくなる。

条件を変える

constraint のテストだけでは constraint が与えた request に基づいて true を返すか false を返すかしか検証できない。慣れてしまえばこれだけで十分と判断できるかもしれないが、本当のことを言うと特定の条件を満たす request に対して Rails アプリがどのように反応するかもテストしたいはずである。つまり、constraint が有効な場合と無効な場合のテストが書けないと不安にならないだろうか?

constraint は基本的に routing にそのまま書くので適用されっぱなしになってしまう。Proc オブジェクトで書く場合は Proc の中で条件分岐させることができるが、Object と matches? メソッドで書く場合はそういうわけにいかない。

そこで stub out 可能なメソッドを用意しておく。こんな感じだ。

class Constraint
  def enabled?
    true
  end

  def matches?(request)
    if enabled?
      ..
    else
      true
    end
  end
end

これでテストの際には enabled? を false に stub out してあげれば、constraint が無効な場合にどんな問題が起きるかをテストできるようになった。そのうえで e2e の request を投げてあげれば、Rails アプリ全体がどのように反応するかが分かる。

余談だが、簡単に stub out できる Plain Old Object スバラシイと改めて思う。

  1. Rack middleware や Web サーバでも可能だけど response の返し方を揃えておくとか、利用しているフレームワークのそばに書いてある方が関連を理解しやすいという意味では Rails の中で処理するのが望ましそう。異論は認める。 

まだ Perl で YAML は Syck が主流かな?

夏 DOKI Lisp スティック - YAML パーサのベンチマーク

yaml.com の PyYAML の Perl 移植版てのはまだ全然若いので、現実的には Syck 一択って感じか。

Syck のインストールができない場合は Syck 互換の YAML.pm かな?

Trac には svn log の limit オプションをそのまま利用する方法はないのか?

Trac に Revision Log っていうのがあるんだけど、これが使いにくい。

svn コマンドには

--limit 件数

っていうオプションがあるので、最新の更新 20件とかのログをすぐに取得できる。しかしせっかく RSS 生成機能のある Trac ではこれを活かすことができない。0.9.x では表示開始 revision を指定したり最終 revision を指定することはできるんだけど、素直に最新の何件というログは取得できない。

なんでやねん。何百とか commit されてるファイルの Log はうっかり開くこともできやしない。

無断リーブは難しいし、無断と呼ばない方がよいのでは

「無断リーブ」しましょ?

無断リンクをきらう側は勝手に内容の改変、ページの移動などを行えばよい、これを無断リーブと呼ぼうという話。こうすればモヒカン族の blog にリンク切れを発生させることができると。

しかし内容は短期的には Google キャッシュに、長期的には archive.org に補足されてしまう。(ほかにもキャッシュするサービスはいっぱいあると思うけど。)キャッシュを消去することは可能だろうけど、少なくとも改変の事実はバレてしまう。それは気持ち悪くないんだろうか?

またページの移動を行った場合、ムラびとにはそれを通知する必要がある。1これはメールで行うのだろうか? メールで完結するなら問題ない。そうでない場合は Web 上のどこかに移転先を書く必要がある。しかし書いたが最後、これは機械的に補足可能。モヒカンは容易に追跡してしまう。しかもソーシャルブックマークのある今、URL をみんなで補正していき、登録情報を利用して自動的に permalink を設定することだってできる。対してリーブする側は一人の手で内容の改変や移動を行わなければいけない。

無断リーブをやろうとする側の方が圧倒的に不利ではないか。

あと、「無断」という言葉は礼節や共同社会のルールに反する不届きものの行いに対して冠すべき言葉だから、「無断リーブ」は無断リンクの対抗手段のネーミングとしてよろしくないのでは? それに無断に対して殺伐と無断で返すのは無言のどつき合いであり、モヒカン族の流儀ではなかろうか。

  1. ページの更新を仲のいい人には教えたい心理が働いているだろうという予測がベースにあるので、これが外れている場合はこの推論は意味を成さない。しかし更新の通知なんかどうでもいいよという人は恐らく殺伐系に属するのでこの予測は大きくは間違っていないだろう。 

情報処理技術者試験で出題されるプログラミング言語

自分の頭の中にあったのは

  • PL/I
  • COBOL
  • FORTRAN
  • CASL
  • C

で、PL/I がずいぶん前になくなったのは知っていた(自分が試験を知ったときには C もなかった)が、さっきチェックしたら

  • FORTRAN

が消えていて

  • C++
  • Java
  • Visual Basic
  • Perl

ができていた。

Java はまだ分かるが、Perl って他の言語とやたらと性格が違うし、Visual Basic は特定のベンダーの言語なんですけど、それ国家試験でやるのかーという、かなり新鮮な驚き。

最終的には

  • C
  • C++
  • CASL II
  • COBOL
  • Java
  • Visual Basic
  • Perl

のラインアップ。Perl やるなら Python か Ruby の方が勉強になると思うんだけどなぁ。なんつーか、往年の「BASIC は初学者には学んでほしくない」のと同じ理由で Perl は勉強してほしくないんだけど。。。昔は消去法で Perl を学ぶべきだと言いましたけどね。Python コミュニティからすれば Perl が入っていて教育に向いているはずの Python が入っていないなんてちょっと信じらんないって感じかも。

この中で自分が勧めるなら Eclipse で Java かなぁ。IDE の方が学習は楽そうだし、情報は揃ってるし、プラットフォームを選ばないから手持ちのマシンでやれる。VB や CASL だと Windows 以外選択肢なさそうだし、COBOL も厳しいかな。C は基本を学ぶにはいいかもしれないけど、動くものを作るのがちょっと大変なので、作って動かす喜びを感じながら学習するにはちょっと不向きだと個人的には思う。(まぁ作って動かすって意味では VB と Perl がいちばんお手軽な気がするけど。)

まだ体調が優れない

ので休みをもらった。

するとなぜか自宅サーバの file system が一部壊れていることに気づく。ログを見てるとこのエラーはさっき初めて見つかったっぽい。げー。おれの身体は疲れてるんだよ、復旧作業とか考えるのやだよ。

とりあえず無事なものとそうでないものを ls で確認していくと、それほど大きな問題はなさそうだ。この程度なら最悪データが取り出せなくてもたいした被害じゃない。fsck を掛けてもよいんだけど、掛けてとどめを刺す可能性も頭をよぎったのでバックアップが済んでから考えよう。

ま、それより何よりまずは温泉で身体をほぐしてこよう。ディスクの増強とか考えるのメンドイです。でもとりあえず 4.10R の iso イメージは落としておこう。ついでに上げちゃうかもしんないし。さ、温泉温泉。

About

例によって個人のなんちゃらです