技術書展4でTomoriNao Vol.2を頒布してきた!!

11時20分くらいに着いたら整理券が1918番で結局入れたのは12時半ごろだった。予想以上に人が多い。

f:id:TAKEmaru:20180422113318j:plain

13時頃には200冊全部売れてよかったですね。

f:id:TAKEmaru:20180422150141j:plain

urandomとかksnctfとかハニーポットとか言語処理系の本が買えたのもよかった。

TomoriNao Vol.1, Vol.2ともにkindleで発売中なので、よろしくお願いします!!

rails 5.1.6 のアプリをrails 5.2.0にアップデートしたときに困ったとこメモ

rails 5.1.6 のアプリをrails 5.2.0にアップデートしたときに、いろいろハマったのでメモ。

rails

rails側での作業メモ。

cannot load such file -- bootsnap/setup

とりあえず rails app:updateしてみる。 route.rbなどは上書きしたらダメだけど、boot.rbとか触った覚えのないファイルは上書きしていく。

$ rails app:update
conflict  config/boot.rb
Overwrite /Users/tkmru/code/old_app/config/boot.rb? (enter "h" for help) [Ynaqdh] Y
       force  config/boot.rb
       exist  config
    conflict  config/routes.rb
Overwrite /Users/tkmru/code/old_app/config/routes.rb? (enter "h" for help) [Ynaqdh] n
...

rails serverを起動するとbootsnapというrailsの起動を早くするgemがないとエラーが出た。railsが標準で使うようになったとのこと。

週刊Railsウォッチ(20170728)bootsnapがRailsで正式採用、Ruby Prizeの推薦開始、PostgreSQL配列の重複を除去ほか

gemファイルに追加してbundle installする。

$ bin/rails s
Traceback (most recent call last):
    3: from bin/rails:3:in `<main>'
    2: from bin/rails:3:in `require_relative'
    1: from /Users/tkmru/code/old_app/config/boot.rb:4:in `<top (required)>'
/Users/tkmru/code/old_app/config/boot.rb:4:in `require': cannot load such file -- bootsnap/setup (LoadError)

undefined method `halt_callback_chains_on_return_false=' for ActiveSupport:Module

halt_callback_chains_on_return_falseはRails 4との後方互換のためのメソッドで、rails serverを起動するとこれがないというエラーが出た。

$ bin/rails s
=> Booting Puma
=> Rails 5.2.0 application starting in development 
=> Run `rails server -h` for more startup options
Exiting
Traceback (most recent call last):
    73: from bin/rails:4:in `<main>'
    72: from /Users/tkmru/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/activesupport-5.2.0/lib/active_support/dependencies.rb:283:in `require'
    71: from /Users/tkmru/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/activesupport-5.2.0/lib/active_support/dependencies.rb:249:in `load_dependency'
    70: from /Users/tkmru/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/activesupport-5.2.0/lib/active_support/dependencies.rb:283:in `block in require'
...
    10: from /Users/tkmru/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.2.0/lib/rails/engine.rb:613:in `each'
     9: from /Users/tkmru/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.2.0/lib/rails/engine.rb:614:in `block (2 levels) in <class:Engine>'
     8: from /Users/tkmru/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.2.0/lib/rails/engine.rb:656:in `load_config_initializer'
     7: from /Users/tkmru/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/activesupport-5.2.0/lib/active_support/notifications.rb:170:in `instrument'
     6: from /Users/tkmru/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.2.0/lib/rails/engine.rb:657:in `block in load_config_initializer'
     5: from /Users/tkmru/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/activesupport-5.2.0/lib/active_support/dependencies.rb:277:in `load'
     4: from /Users/tkmru/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/activesupport-5.2.0/lib/active_support/dependencies.rb:249:in `load_dependency'
     3: from /Users/tkmru/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/activesupport-5.2.0/lib/active_support/dependencies.rb:277:in `block in load'
     2: from /Users/tkmru/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/bootsnap-1.3.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:50:in `load'
     1: from /Users/tkmru/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/bootsnap-1.3.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:50:in `load'
/Users/tkmru/code/old_app/config/initializers/new_framework_defaults.rb:23:in `<main>': undefined method `halt_callback_chains_on_return_false=' for ActiveSupport:Module (NoMethodError)

Ruby on Rails 5.2.0 Deprecations – Drifting Rubyによると、 5.2よりhalt_callback_chains_on_return_falseは削除されたみたい。 config/initializers/new_framework_defaults.rbの中のhalt_callback_chains_on_return_falseの行をコメントアウトした。

# Be sure to restart your server when you modify this file.
#
# This file contains migration options to ease your Rails 5.0 upgrade.
#
# Read the Guide for Upgrading Ruby on Rails for more info on each option.

Rails.application.config.raise_on_unfiltered_parameters = true

# Enable per-form CSRF tokens. Previous versions had false.
Rails.application.config.action_controller.per_form_csrf_tokens = true

# Enable origin-checking CSRF mitigation. Previous versions had false.
Rails.application.config.action_controller.forgery_protection_origin_check = true

# Make Ruby 2.4 preserve the timezone of the receiver when calling `to_time`.
# Previous versions had false.
ActiveSupport.to_time_preserves_timezone = true

# Require `belongs_to` associations by default. Previous versions had false.
Rails.application.config.active_record.belongs_to_required_by_default = true

# Do not halt callback chains when a callback returns false. Previous versions had true.
# ActiveSupport.halt_callback_chains_on_return_false = false # これをコメントアウトした!!

# Configure SSL options to enable HSTS with subdomains. Previous versions had false.
Rails.application.config.ssl_options = { hsts: { subdomains: true } }

これでrailsは起動するようになった。

frontend 側

フロントエンド側の作業メモ

can't find executable webpack for gem webpacker

webpackを実行してみると、gemのwebpackerから動かせるwebpackがないってエラーが出た。

$ bin/webpack
Traceback (most recent call last):
    2: from bin/webpack:17:in `<main>'
    1: from /Users/tkmru/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/bundler-1.16.1/lib/bundler/rubygems_integration.rb:489:in `block in replace_bin_path'
/Users/tkmru/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/bundler-1.16.1/lib/bundler/rubygems_integration.rb:458:in `block in replace_bin_path': can't find executable webpack for gem webpacker (Gem::Exception)

rails webpacker:binstubsでwebpackのバイナリを再インストールすると、webpackも動くようになった。

$ bin/rails webpacker:binstubs
Copying binstubs
       exist  bin
    conflict  bin/webpack
Overwrite /Users/tkmru/code/old_app/bin/webpack? (enter "h" for help) [Ynaqdh] Y
       force  bin/webpack
    conflict  bin/webpack-dev-server
Overwrite /Users/tkmru/code/old_app/bin/webpack-dev-server? (enter "h" for help) [Ynaqdh] Y
       force  bin/webpack-dev-server

$ bin/webpack
set is deprecated! Use append instead

Hash: 9c54321948fe9d42f554
Version: webpack 3.11.0
Time: 4625ms
                                                                                       Asset     Size  Chunks                    Chunk Names
                                                         application-07d7627f2dffd5e35ab1.js   607 kB       1  [emitted]  [big]  application
  _/node_modules/font-awesome/fonts/fontawesome-webfont-674f50d287a8c48dc19ba404d20fe713.eot   166 kB          [emitted]         
 _/node_modules/font-awesome/fonts/fontawesome-webfont-fee66e712a8a08eef5805a46892932ad.woff    98 kB          [emitted]         
...

技術書典4で TomoriNao vol.2 を頒布します!!

技術書典4で TomoriNao vol.2 を頒布します!! 場所は「お16」です!!!

techbookfest.org

f:id:TAKEmaru:20180416133313j:plain

f:id:TAKEmaru:20180415220914j:plain

ぼくは、「アンチデバックのためのデッドコードをLLVM optimizerで緩和してみる」という題で書きました。 LLVMのパスを使った難読化/難読化緩和の研究がちょくちょくあるけど、 バイナリをLLVM IRにデコンパイルして、LLVMのデフォルトの最適化パスを使うだけで、 デッドコードくらいならまあまあ消えるのでは〜という実験をやってみたという内容です。

そのうち、自作パスによる難読化/難読化緩和もやってみたいですね!!

みなさま!ご購入の検討を!!よろしくお願いします!!!

JSONを扱いやすくするコマンド(jq, gron)のメモ

JSONを扱いやすくするコマンドのjqgronのメモ。

jq コマンド

jq コマンドはJSON向けのawkのようなコマンド。

インストール方法(on Mac

$ brew install jq

使い方

パイプで渡されたJSONデータにフィルターをかけることができる。

GitHub APIを使ってリポジトリ名を列挙する例

$ curl -s `curl -s https://api.github.com/users/tkmru | jq -r .repos_url`  | jq '.[].name'
"anarchy_proof"
"anti_debugging_test"
"aoj"
"awesome-linux-rootkits"
"a_and_d_web_nara"
"biwx"
...
"isucon4-qualifier-mokumoku"
"isucon6-qual-practice"
"isucon_pixv"
"ldap3"
"linux-driver-playground"
"linux-insides"
"linux-insides-ja"
"machine-learning-playground"

GitHub APIを使って最新コミット情報を取って来る例

$ curl 'https://api.github.com/repos/tkmru/dotfiles/commits?per_page=1' | jq '.[0]'
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  7328  100  7328    0     0   9488      0 --:--:-- --:--:-- --:--:--  9492
{
  "sha": "c764b1baad95cb18cec14a1b7f84b460b6f0b3cc",
  "commit": {
    "author": {
      "name": "tkmru",
      "email": "i.am.tkmru@gmail.com",
      "date": "2018-04-10T14:33:34Z"
    },
    "committer": {
      "name": "tkmru",
      "email": "i.am.tkmru@gmail.com",
      "date": "2018-04-10T14:33:34Z"
    },
    "message": "Merge branch 'master' of github.com:tkmru/dotfiles",
  ...
  "parents": [
    {
      "sha": "495ddbfd8c19564a5c72260eb9c857f2d7f3a6d5",
      "url": "https://api.github.com/repos/tkmru/dotfiles/commits/495ddbfd8c19564a5c72260eb9c857f2d7f3a6d5",
      "html_url": "https://github.com/tkmru/dotfiles/commit/495ddbfd8c19564a5c72260eb9c857f2d7f3a6d5"
    },
    {
      "sha": "7f0f75610a2856c6cc97a3b1d949f5a4345a53df",
      "url": "https://api.github.com/repos/tkmru/dotfiles/commits/7f0f75610a2856c6cc97a3b1d949f5a4345a53df",
      "html_url": "https://github.com/tkmru/dotfiles/commit/7f0f75610a2856c6cc97a3b1d949f5a4345a53df"
    }
  ]
}

GitHub APIを使ってコミットメッセージ、名前を列挙する例

$ curl 'https://api.github.com/repos/tkmru/dotfiles/commits?per_page=2' | jq '[.[] | {message: .commit.message, name: .commit.committer.name}]'
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  7328  100  7328    0     0   9382      0 --:--:-- --:--:-- --:--:--  9382
[
  {
    "message": "Merge branch 'master' of github.com:tkmru/dotfiles",
    "name": "tkmru"
  },
  {
    "message": "add ungron",
    "name": "tkmru"
  }
]

gron コマンド

JSONgrepしやすい形式、JavaScriptで扱える形式に変換してくれるコマンド。 Golang製。

インストール方法(on Mac

$ brew install gron

使い方

URLもしくはJSONファイルを指定すると変換してくれる。

$ gron "https://api.github.com/repos/tkmru/dotfiles/commits?per_page=1"
json = [];
json[0] = {};
json[0].author = {};
json[0].author.avatar_url = "https://avatars3.githubusercontent.com/u/1628214?v=4";
json[0].author.events_url = "https://api.github.com/users/tkmru/events{/privacy}";
json[0].author.followers_url = "https://api.github.com/users/tkmru/followers";
json[0].author.following_url = "https://api.github.com/users/tkmru/following{/other_user}";
....
json[0].parents[1].html_url = "https://github.com/tkmru/dotfiles/commit/7f0f75610a2856c6cc97a3b1d949f5a4345a53df";
json[0].parents[1].sha = "7f0f75610a2856c6cc97a3b1d949f5a4345a53df";
json[0].parents[1].url = "https://api.github.com/repos/tkmru/dotfiles/commits/7f0f75610a2856c6cc97a3b1d949f5a4345a53df";
json[0].sha = "c764b1baad95cb18cec14a1b7f84b460b6f0b3cc";
json[0].url = "https://api.github.com/repos/tkmru/dotfiles/commits/c764b1baad95cb18cec14a1b7f84b460b6f0b3cc";

これによってgrepしやすくなる。

$ gron "https://api.github.com/repos/tkmru/dotfiles/commits?per_page=1" | grep commit.message
json[0].commit.message = "Merge branch 'master' of github.com:tkmru/dotfiles";

ungron

gronの出力結果をJSONに戻すには--ungronオプションを付ければいい。 以下のようにaliasを設定するよう、READMEで推奨されている。

alias norg="gron --ungron"
alias ungron="gron --ungron"

grepした結果をJSONで欲しいときに使える。

$ gron "https://api.github.com/repos/tkmru/dotfiles/commits?per_page=1" | grep commit.message | ungron
[
  {
    "commit": {
      "message": "Merge branch 'master' of github.com:tkmru/dotfiles"
    }
  }
]

diffもgronを使えば見やすい結果で取れる。

$ diff <(gron http://echo.jsontest.com/number/one) <(gron http://echo.jsontest.com/number/two)
2c2
< json.number = "one";
---
> json.number = "two";

JavaScriptから出力結果をさわる

出力されたテキストはJavaScriptのObjectとして扱える。

$ gron http://headers.jsontest.com/ > tmp.js
$ echo "console.log(json);" >> tmp.js
$ node tmp.js
{ Accept: 'application/json',
  Host: 'headers.jsontest.com',
  'User-Agent': 'gron/dev',
  'X-Cloud-Trace-Context': '0f152eb1d17dc08fd257b8b4383faaa6/9190834354357706108' }

IDAプラグインの更新をサボっていたら割れIDAへのリンクを貼られた

IDA 7.0が昨年9月くらいに出たので、IDA 6.xのプラグインはIDA 7.xに対応するべく更新する必要がありました。 更新されたAPIへの差し替え、32bitアプリケーションだったのが64bitアプリケーションになったことによる変更などなど....

www.hex-rays.com

naoというプラグインを昔つくっていて、これをIDA 7.xに対応させる必要があり、 GitHubリポジトリにIssueをたてられたりしましたが、 IDA 7.0を当時は持ってなかったのでその旨を返信して放置していました。 すると、これを使えよ〜というノリで割れIDAへのリンクを貼られてしまった!!!! 治安が悪い!!!!!

f:id:TAKEmaru:20180214060412p:plain

社会性の塊なので、このスクショでは割れIDAへのURLの一部をマスクしています。偉い!

github.com

その裏でIDA 7.xに対応するプルリクを投げてくれた親切な人がおり、今ではIDA 7.xに対応しています。めでたしめでたし。

https://github.com/tkmru/nao/pull/39github.com

Rails appのコードを変更したときに、Guardに自動でRuboCop、RSpecを実行してもらう

Guardとは

Guardはファイルに変更があったときに、タスクを走らせてくれるgemで、コードを変更したときに、静的なコードチェックをしてくれるRuboCopやRSpecで書かれたテストを実行させることができる。RuboCopやテストコードを随時走らせてコーディングしていくと、問題を即座に把握できるので、プルリク前にあわててテストコードを走らせて修正....というハメに陥らなくて済む。

導入方法

Gemfile

Gemfileに以下のgemを追加。RSpec、RuboCopの導入はすでに終わっているものとする。

group :development do
  ...
  gem 'guard-rspec'
  gem 'guard-rubocop'
  ...
end

インストールも忘れずに。

$ bundle install

Guardfile

Guardの設定ファイルを作成する必要がある。以下のコマンドで生成できる。

$ bundle exec guard init rspec
$ bundle exec guard init rubocop

このようなGuardfileになる。このファイルを変更することで、監視対象とするファイルを変更したり、rspecが落ちた時の RuboCopの実行をスキップしたりできる。

guard :rubocop, cli: '--rails' do
  watch(/.+\.rb$/)
  watch(%r{(?:.+/)?\.rubocop\.yml$}) { |m| File.dirname(m[0]) }
end

guard :rspec, cmd: 'bundle exec rspec' do
  require 'guard/rspec/dsl'
  dsl = Guard::RSpec::Dsl.new(self)

  # RSpec files
  rspec = dsl.rspec
  watch(rspec.spec_helper) { rspec.spec_dir }
  watch(rspec.spec_support) { rspec.spec_dir }
  watch(rspec.spec_files)

  # Ruby files
  ruby = dsl.ruby
  dsl.watch_spec_files_for(ruby.lib_files)

  # Rails files
  rails = dsl.rails(view_extensions: %w(erb haml slim))
  dsl.watch_spec_files_for(rails.app_files)
  dsl.watch_spec_files_for(rails.views)

  watch(rails.controllers) do |m|
    [
      rspec.spec.call("routing/#{m[1]}_routing"),
      rspec.spec.call("controllers/#{m[1]}_controller"),
      rspec.spec.call("acceptance/#{m[1]}")
    ]
  end

  watch(%r{^app/api/(.+)\.rb$}) { |m| "spec/api/#{m[1]}_spec.rb" }

  # Rails config changes
  watch(rails.spec_helper)     { rspec.spec_dir }
  watch(rails.routes)          { "#{rspec.spec_dir}/routing" }
  watch(rails.app_controller)  { "#{rspec.spec_dir}/controllers" }

  # Turnip features and steps
  watch(%r{^spec/features/(.+)\.feature$})
  watch(%r{^spec/steps/(.+)_steps\.rb$}) do |m|
    Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/features'
  end
end

rspecが落ちた時に RuboCopの実行をスキップしたい場合は、 以下のようにGuardfileを変更するとよい。

# This group allows to skip running RuboCop when RSpec failed.
group :red_green_refactor, halt_on_fail: true do
  guard :rspec do
    # ...
  end

  guard :rubocop do
    # ...
  end
end

Guardを実行してファイルを監視

実行するだけ。

$ bundle exec guard

おわりに

Guardを使って開発しているとプルリクする前にあわててテストを実行しなくてよくて便利。 快適railsライフを送りましょう。