pre-commit-hook.rb 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. #!/usr/bin/env ruby
  2. require "open3"
  3. #
  4. # Check that modules actually pass msftidy checks before committing
  5. # or after merging.
  6. #
  7. # Simply symlink this script to your local .git/hooks/pre-commit script
  8. # and your .git/hooks/post-merge scripts. Note the lack of a trailing
  9. # .rb
  10. #
  11. # If you are in the top-level dir, the symlink commands would be:
  12. #
  13. # ln -sf ../../tools/dev/pre-commit-hook.rb .git/hooks/pre-commit
  14. # ln -sf ../../tools/dev/pre-commit-hook.rb .git/hooks/post-merge
  15. #
  16. # That way, you will track changes to this script when it updates
  17. # (rarely). If you'd prefer to copy it directly, that's okay, too (mark
  18. # it +x and don't name it filename.rb, just filename).
  19. #
  20. def run(command, exception: true)
  21. puts command
  22. stdout, status = ::Open3.capture2(command)
  23. if !status.success? && exception
  24. raise "Command failed with status (#{status.exitstatus}): #{command}"
  25. end
  26. stdout
  27. end
  28. def merge_error_message
  29. msg = []
  30. msg << "[*] This merge contains modules failing msftidy.rb"
  31. msg << "[*] Please fix this if you intend to publish these"
  32. msg << "[*] modules to a popular metasploit-framework repo"
  33. puts "-" * 72
  34. puts msg.join("\n")
  35. puts "-" * 72
  36. end
  37. valid = true # Presume validity
  38. files_to_check = []
  39. # Who called us? If it's a post-merge check things operate a little
  40. # differently.
  41. puts "[*] Running msftidy.rb in #{$0} mode"
  42. case $0
  43. when /post-merge/
  44. base_caller = :post_merge
  45. when /pre-commit/
  46. base_caller = :pre_commit
  47. else
  48. base_caller = :msftidy
  49. end
  50. if base_caller == :post_merge
  51. changed_files = run('git diff --name-only HEAD^ HEAD')
  52. else
  53. changed_files = run('git diff --cached --name-only')
  54. end
  55. changed_files.each_line do |fname|
  56. fname.strip!
  57. next unless File.exist?(fname)
  58. next unless File.file?(fname)
  59. next unless fname =~ /^modules.+\.rb/
  60. files_to_check << fname
  61. end
  62. if files_to_check.empty?
  63. puts "--- No Metasploit modules to check ---"
  64. else
  65. puts "--- Checking new and changed module syntax with tools/dev/msftidy.rb ---"
  66. files_to_check.each do |fname|
  67. command = "bundle exec ruby ./tools/dev/msftidy.rb #{fname}"
  68. msftidy_output, status = ::Open3.capture2(command)
  69. valid = false unless status.success?
  70. puts "#{fname} - msftidy check passed" if msftidy_output.empty?
  71. msftidy_output.each_line do |line|
  72. puts line
  73. end
  74. end
  75. puts "-" * 72
  76. end
  77. unless valid
  78. if base_caller == :post_merge
  79. puts merge_error_message
  80. exit(0x10)
  81. else
  82. puts "[!] msftidy.rb objected, aborting commit"
  83. puts "[!] To bypass this check use: git commit --no-verify"
  84. puts "-" * 72
  85. exit(0x01)
  86. end
  87. end