recog 2.3.20 → 2.3.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +8 -0
  3. data/.github/workflows/ci.yml +1 -1
  4. data/.github/workflows/verify.yml +89 -0
  5. data/.vscode/bin/monitor-recog-fingerprints.sh +54 -0
  6. data/.vscode/extensions.json +5 -0
  7. data/.vscode/settings.json +8 -0
  8. data/.vscode/tasks.json +77 -0
  9. data/CONTRIBUTING.md +8 -0
  10. data/README.md +17 -0
  11. data/bin/recog_standardize +28 -13
  12. data/bin/recog_verify +42 -8
  13. data/cpe-remap.yaml +62 -3
  14. data/features/data/schema_failure.xml +4 -0
  15. data/features/data/tests_with_failures.xml +6 -0
  16. data/features/support/hooks.rb +9 -0
  17. data/features/verify.feature +85 -21
  18. data/identifiers/fields.txt +6 -5
  19. data/identifiers/hw_device.txt +8 -0
  20. data/identifiers/hw_family.txt +8 -0
  21. data/identifiers/hw_product.txt +54 -0
  22. data/identifiers/os_device.txt +2 -0
  23. data/identifiers/os_family.txt +2 -0
  24. data/identifiers/os_product.txt +18 -2
  25. data/identifiers/service_product.txt +26 -0
  26. data/identifiers/vendor.txt +62 -1
  27. data/lib/recog/db.rb +2 -1
  28. data/lib/recog/fingerprint.rb +33 -6
  29. data/lib/recog/fingerprint_parse_error.rb +10 -0
  30. data/lib/recog/nizer.rb +1 -82
  31. data/lib/recog/verifier.rb +9 -9
  32. data/lib/recog/verify_reporter.rb +17 -6
  33. data/lib/recog/version.rb +1 -1
  34. data/requirements.txt +1 -1
  35. data/spec/data/external_example_fingerprint/hp_printer_ex_01.txt +1 -0
  36. data/spec/data/external_example_fingerprint/hp_printer_ex_02.txt +1 -0
  37. data/spec/data/external_example_fingerprint.xml +8 -0
  38. data/spec/data/external_example_illegal_path_fingerprint.xml +7 -0
  39. data/spec/lib/fingerprint_self_test_spec.rb +1 -0
  40. data/spec/lib/recog/db_spec.rb +84 -61
  41. data/spec/lib/recog/fingerprint_spec.rb +4 -4
  42. data/spec/lib/recog/verify_reporter_spec.rb +73 -4
  43. data/tools/dev/hooks/pre-commit +21 -0
  44. data/update_cpes.py +130 -37
  45. data/xml/apache_os.xml +98 -56
  46. data/xml/architecture.xml +15 -1
  47. data/xml/dhcp_vendor_class.xml +206 -0
  48. data/xml/dns_versionbind.xml +26 -13
  49. data/xml/favicons.xml +236 -47
  50. data/xml/fingerprints.xsd +9 -1
  51. data/xml/ftp_banners.xml +213 -197
  52. data/xml/h323_callresp.xml +101 -101
  53. data/xml/hp_pjl_id.xml +84 -84
  54. data/xml/html_title.xml +715 -45
  55. data/xml/http_cookies.xml +143 -80
  56. data/xml/http_servers.xml +510 -310
  57. data/xml/http_wwwauth.xml +177 -75
  58. data/xml/imap_banners.xml +10 -10
  59. data/xml/mdns_device-info_txt.xml +421 -26
  60. data/xml/mysql_banners.xml +3 -2
  61. data/xml/nntp_banners.xml +12 -9
  62. data/xml/ntp_banners.xml +97 -97
  63. data/xml/operating_system.xml +98 -83
  64. data/xml/pop_banners.xml +27 -27
  65. data/xml/rsh_resp.xml +3 -3
  66. data/xml/sip_banners.xml +46 -8
  67. data/xml/sip_user_agents.xml +180 -27
  68. data/xml/smb_native_lm.xml +5 -5
  69. data/xml/smb_native_os.xml +28 -25
  70. data/xml/smtp_banners.xml +258 -254
  71. data/xml/smtp_ehlo.xml +1 -1
  72. data/xml/smtp_help.xml +11 -11
  73. data/xml/smtp_noop.xml +2 -2
  74. data/xml/snmp_sysdescr.xml +1554 -1429
  75. data/xml/snmp_sysobjid.xml +27 -27
  76. data/xml/ssh_banners.xml +27 -20
  77. data/xml/telnet_banners.xml +256 -57
  78. data/xml/tls_jarm.xml +48 -6
  79. data/xml/x11_banners.xml +3 -3
  80. data/xml/x509_issuers.xml +69 -2
  81. data/xml/x509_subjects.xml +144 -33
  82. metadata +24 -4
  83. data/lib/recog/verifier_factory.rb +0 -13
data/lib/recog/nizer.rb CHANGED
@@ -8,13 +8,13 @@ class Nizer
8
8
  # Non-weighted host attributes that can be extracted from fingerprint matches
9
9
  HOST_ATTRIBUTES = %W{
10
10
  host.domain
11
- host.id
12
11
  host.ip
13
12
  host.mac
14
13
  host.name
15
14
  host.time
16
15
  hw.device
17
16
  hw.family
17
+ hw.serial_number
18
18
  hw.product
19
19
  hw.vendor
20
20
  }
@@ -264,84 +264,3 @@ class Nizer
264
264
 
265
265
  end
266
266
  end
267
-
268
- =begin
269
-
270
- Current key names:
271
-
272
- apache.info
273
- apache.variant
274
- apache.variant.version
275
- cookie
276
- host.domain
277
- host.id
278
- host.ip
279
- host.mac
280
- host.name
281
- host.time
282
- hw.device
283
- hw.family
284
- hw.product
285
- hw.vendor
286
- imail.eval
287
- jetty.info
288
- junction.cookie
289
- junction.name
290
- linux.kernel.version
291
- loadbalancer.poolname
292
- mdaemon.unregistered
293
- mercur.os.info
294
- metainfo.version
295
- metainfo.version.version
296
- ms.nttp.version
297
- notes.build.version
298
- notes.intl
299
- ntmail.id
300
- openssh.comment
301
- openssh.cvepatch
302
- os.arch
303
- os.build
304
- os.certainty
305
- os.device
306
- os.edition
307
- os.family
308
- os.product
309
- os.vendor
310
- os.version
311
- os.version.version
312
- os.version.version.version
313
- postfix.os.info
314
- postoffice.build
315
- postoffice.id
316
- proftpd.server.name
317
- pureftpd.config
318
- qpopper.version
319
- sendmail.config.version
320
- sendmail.hpux.phne.version
321
- sendmail.vendor.version
322
- service.certainty
323
- service.component.family
324
- service.component.product
325
- service.component.vendor
326
- service.component.version
327
- service.family
328
- service.product
329
- service.vendor
330
- service.version
331
- service.version.version
332
- service.version.version.version
333
- service.version.version.version.version
334
- service.version.version.version.version.version
335
- siemens.model
336
- snmp.fpmib.oid.1
337
- snmp.fpmib.oid.2
338
- system.time
339
- system.time.format
340
- system.time.micros
341
- system.time.millis
342
- thttpd.mx-patch
343
- timeout
344
- tomcat.info
345
- zmailer.ident
346
-
347
- =end
@@ -1,23 +1,23 @@
1
1
  module Recog
2
2
  class Verifier
3
- attr_reader :fingerprints, :reporter
3
+ attr_reader :db, :reporter
4
4
 
5
- def initialize(fingerprints, reporter)
6
- @fingerprints = fingerprints
5
+ def initialize(db, reporter)
6
+ @db = db
7
7
  @reporter = reporter
8
8
  end
9
9
 
10
10
  def verify
11
- reporter.report(fingerprints.count) do
12
- fingerprints.each do |fp|
11
+ reporter.report(db.fingerprints.count) do
12
+ db.fingerprints.each do |fp|
13
13
  reporter.print_name fp
14
14
 
15
15
  fp.verify_params do |status, message|
16
16
  case status
17
17
  when :warn
18
- reporter.warning "WARN: #{message}"
18
+ reporter.warning message, fp.line
19
19
  when :fail
20
- reporter.failure "FAIL: #{message}"
20
+ reporter.failure message, fp.line
21
21
  when :success
22
22
  reporter.success(message)
23
23
  end
@@ -25,9 +25,9 @@ class Verifier
25
25
  fp.verify_tests do |status, message|
26
26
  case status
27
27
  when :warn
28
- reporter.warning "WARN: #{message}"
28
+ reporter.warning message, fp.line
29
29
  when :fail
30
- reporter.failure "FAIL: #{message}"
30
+ reporter.failure message, fp.line
31
31
  when :success
32
32
  reporter.success(message)
33
33
  end
@@ -3,14 +3,18 @@ class VerifyReporter
3
3
  attr_reader :formatter
4
4
  attr_reader :success_count, :warning_count, :failure_count
5
5
 
6
- def initialize(options, formatter)
6
+ def initialize(options, formatter, path=nil)
7
7
  @options = options
8
8
  @formatter = formatter
9
+ @path = path
9
10
  reset_counts
10
11
  end
11
12
 
12
13
  def report(fingerprint_count)
13
14
  reset_counts
15
+ if detail? and !@path.to_s.empty?
16
+ formatter.status_message("\n#{@path}:\n")
17
+ end
14
18
  yield self
15
19
  summarize(fingerprint_count) unless @options.quiet
16
20
  end
@@ -20,15 +24,15 @@ class VerifyReporter
20
24
  formatter.success_message("#{padding}#{text}") if detail?
21
25
  end
22
26
 
23
- def warning(text)
27
+ def warning(text, line=nil)
24
28
  return unless @options.warnings
25
29
  @warning_count += 1
26
- formatter.warning_message("#{padding}#{text}")
30
+ formatter.warning_message("#{path_label(line)}#{padding}WARN: #{text}")
27
31
  end
28
32
 
29
- def failure(text)
33
+ def failure(text, line=nil)
30
34
  @failure_count += 1
31
- formatter.failure_message("#{padding}#{text}")
35
+ formatter.failure_message("#{path_label(line)}#{padding}FAIL: #{text}")
32
36
  end
33
37
 
34
38
  def print_name(fingerprint)
@@ -61,12 +65,19 @@ class VerifyReporter
61
65
  @options.detail
62
66
  end
63
67
 
68
+ def path_label(line=nil)
69
+ unless detail?
70
+ line_label = line ? line.to_s + ":" : ""
71
+ @path.to_s.empty? ? "" : "#{@path}:#{line_label} "
72
+ end
73
+ end
74
+
64
75
  def padding
65
76
  ' ' if @options.detail
66
77
  end
67
78
 
68
79
  def summary_line
69
- summary = "SUMMARY: Test completed with "
80
+ summary = "#{path_label}SUMMARY: Test completed with "
70
81
  summary << "#{@success_count} successful"
71
82
  summary << ", #{@warning_count} warnings"
72
83
  summary << ", and #{@failure_count} failures"
data/lib/recog/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Recog
2
- VERSION = '2.3.20'
2
+ VERSION = '2.3.23'
3
3
  end
data/requirements.txt CHANGED
@@ -1,2 +1,2 @@
1
- lxml==4.6.3
1
+ lxml==4.6.5
2
2
  pyyaml
@@ -0,0 +1 @@
1
+ HP LaserJet 4100 Series
@@ -0,0 +1 @@
1
+ HP LaserJet 2200
@@ -0,0 +1,8 @@
1
+ <fingerprints>
2
+ <fingerprint pattern="laserjet (.*)(?: series)?" flags="REG_ICASE">
3
+ <description>HP JetDirect Printer</description>
4
+ <example _filename="hp_printer_ex_01.txt"/>
5
+ <example _filename="hp_printer_ex_02.txt"/>
6
+ <param pos="0" name="service.vendor" value="HP"/>
7
+ </fingerprint>
8
+ </fingerprints>
@@ -0,0 +1,7 @@
1
+ <fingerprints>
2
+ <fingerprint pattern="laserjet (.*)(?: series)?" flags="REG_ICASE">
3
+ <description>HP JetDirect Printer</description>
4
+ <example _filename="../bad_path.txt"/>
5
+ <param pos="0" name="service.vendor" value="HP"/>
6
+ </fingerprint>
7
+ </fingerprints>
@@ -151,6 +151,7 @@ describe Recog::DB do
151
151
  # test any extractions specified in the example
152
152
  example.attributes.each_pair do |k,v|
153
153
  next if k == '_encoding'
154
+ next if k == '_filename'
154
155
  expect(match[k]).to eq(v), "Regex didn't extract expected value for fingerprint attribute #{k} -- got #{match[k]} instead of #{v}"
155
156
  end
156
157
  end
@@ -1,97 +1,120 @@
1
1
  require 'recog/db'
2
2
 
3
3
  describe Recog::DB do
4
- let(:xml_file) { File.expand_path File.join('spec', 'data', 'test_fingerprints.xml') }
5
- subject { Recog::DB.new(xml_file) }
6
4
 
7
5
  describe "#fingerprints" do
8
- subject(:fingerprints) { described_class.new(xml_file).fingerprints }
6
+ context "with inline example content" do
7
+ let(:xml_file) { File.expand_path File.join('spec', 'data', 'test_fingerprints.xml') }
8
+ subject { Recog::DB.new(xml_file) }
9
9
 
10
- it { is_expected.to be_a(Enumerable) }
10
+ subject(:fingerprints) { described_class.new(xml_file).fingerprints }
11
11
 
12
- context "with only a pattern" do
13
- subject(:entry) { described_class.new(xml_file).fingerprints[0] }
12
+ it { is_expected.to be_a(Enumerable) }
14
13
 
15
- it "has a blank name with no description" do
16
- expect(entry.name).to be_empty
17
- end
14
+ context "with only a pattern" do
15
+ subject(:entry) { described_class.new(xml_file).fingerprints[0] }
18
16
 
19
- it "has a pattern" do
20
- expect(entry.regex.source).to eq(".*\\(iSeries\\).*")
21
- end
17
+ it "has a blank name with no description" do
18
+ expect(entry.name).to be_empty
19
+ end
22
20
 
23
- it "has no params" do
24
- expect(entry.params).to be_empty
25
- end
21
+ it "has a pattern" do
22
+ expect(entry.regex.source).to eq(".*\\(iSeries\\).*")
23
+ end
24
+
25
+ it "has no params" do
26
+ expect(entry.params).to be_empty
27
+ end
26
28
 
27
- it "has no tests" do
28
- expect(entry.tests).to be_empty
29
+ it "has no tests" do
30
+ expect(entry.tests).to be_empty
31
+ end
29
32
  end
30
- end
31
33
 
32
- context "with params" do
33
- subject(:entry) { described_class.new(xml_file).fingerprints[1] }
34
+ context "with params" do
35
+ subject(:entry) { described_class.new(xml_file).fingerprints[1] }
34
36
 
35
- it "has a name" do
36
- expect(entry.name).to eq('PalmOS')
37
- end
37
+ it "has a name" do
38
+ expect(entry.name).to eq('PalmOS')
39
+ end
38
40
 
39
- it "has a pattern" do
40
- expect(entry.regex.source).to eq(".*\\(PalmOS\\).*")
41
- end
41
+ it "has a pattern" do
42
+ expect(entry.regex.source).to eq(".*\\(PalmOS\\).*")
43
+ end
42
44
 
43
- it "has params" do
44
- expect(entry.params).to eq({"os.vendor"=>[1, "Palm"], "os.device"=>[2, "General"]})
45
- end
45
+ it "has params" do
46
+ expect(entry.params).to eq({"os.vendor"=>[1, "Palm"], "os.device"=>[2, "General"]})
47
+ end
46
48
 
47
- it "has no tests" do
48
- expect(entry.tests).to be_empty
49
+ it "has no tests" do
50
+ expect(entry.tests).to be_empty
51
+ end
49
52
  end
50
- end
51
53
 
52
- context "with pattern flags" do
53
- subject(:entry) { described_class.new(xml_file).fingerprints[2] }
54
+ context "with pattern flags" do
55
+ subject(:entry) { described_class.new(xml_file).fingerprints[2] }
54
56
 
55
- it "has a name and only uses the first value" do
56
- expect(entry.name).to eq('HP Designjet printer')
57
- end
57
+ it "has a name and only uses the first value" do
58
+ expect(entry.name).to eq('HP Designjet printer')
59
+ end
58
60
 
59
- it 'creates a Regexp with expected flags' do
60
- expect(entry.regex).to be_a(Regexp)
61
- expect(entry.regex.options).to eq(Recog::Fingerprint::RegexpFactory::DEFAULT_FLAGS | Regexp::IGNORECASE)
62
- end
61
+ it 'creates a Regexp with expected flags' do
62
+ expect(entry.regex).to be_a(Regexp)
63
+ expect(entry.regex.options).to eq(Recog::Fingerprint::RegexpFactory::DEFAULT_FLAGS | Regexp::IGNORECASE)
64
+ end
63
65
 
64
- it "has a pattern" do
65
- expect(entry.regex).to be_a(Regexp)
66
- expect(entry.regex.source).to eq("(designjet \\S+)")
67
- end
66
+ it "has a pattern" do
67
+ expect(entry.regex).to be_a(Regexp)
68
+ expect(entry.regex.source).to eq("(designjet \\S+)")
69
+ end
70
+
71
+ it "has params" do
72
+ expect(entry.params).to eq({"service.vendor"=>[0, "HP"]})
73
+ end
68
74
 
69
- it "has params" do
70
- expect(entry.params).to eq({"service.vendor"=>[0, "HP"]})
75
+ it "has no tests" do
76
+ expect(entry.tests).to be_empty
77
+ end
71
78
  end
72
79
 
73
- it "has no tests" do
74
- expect(entry.tests).to be_empty
80
+ context "with test" do
81
+ subject(:entry) { described_class.new(xml_file).fingerprints[3] }
82
+
83
+ it "has a name" do
84
+ expect(entry.name).to eq('HP JetDirect Printer')
85
+ end
86
+
87
+ it "has a pattern" do
88
+ expect(entry.regex.source).to eq("laserjet (.*)(?: series)?")
89
+ end
90
+
91
+ it "has params" do
92
+ expect(entry.params).to eq({"service.vendor"=>[0, "HP"]})
93
+ end
94
+
95
+ it "has tests" do
96
+ expect(entry.tests.map(&:content)).to match_array(["HP LaserJet 4100 Series", "HP LaserJet 2200"])
97
+ end
75
98
  end
76
99
  end
77
100
 
78
- context "with test" do
79
- subject(:entry) { described_class.new(xml_file).fingerprints[3] }
101
+ context "with external example content" do
102
+ let(:xml_file) { File.expand_path File.join('spec', 'data', 'external_example_fingerprint.xml') }
103
+ subject { Recog::DB.new(xml_file) }
80
104
 
81
- it "has a name" do
82
- expect(entry.name).to eq('HP JetDirect Printer')
83
- end
105
+ subject(:entry) { described_class.new(xml_file).fingerprints[0] }
84
106
 
85
- it "has a pattern" do
86
- expect(entry.regex.source).to eq("laserjet (.*)(?: series)?")
107
+ it "has tests" do
108
+ expect(entry.tests.map(&:content)).to match_array(["HP LaserJet 4100 Series", "HP LaserJet 2200"])
87
109
  end
110
+ end
88
111
 
89
- it "has params" do
90
- expect(entry.params).to eq({"service.vendor"=>[0, "HP"]})
91
- end
112
+ context "with external example content illegal path" do
113
+ let(:xml_file) { File.expand_path File.join('spec', 'data', 'external_example_illegal_path_fingerprint.xml') }
114
+ subject { Recog::DB.new(xml_file) }
92
115
 
93
- it "has no tests" do
94
- expect(entry.tests.map(&:content)).to match_array(["HP LaserJet 4100 Series", "HP LaserJet 2200"])
116
+ it "raises an illegal file path error" do
117
+ expect { subject }.to raise_error(/an example specifies an illegal file path '.+'/)
95
118
  end
96
119
  end
97
120
  end
@@ -75,7 +75,7 @@ describe Recog::Fingerprint do
75
75
  let(:entry) { described_class.new(doc.xpath("//fingerprints/fingerprint")[6]) }
76
76
 
77
77
  it "identifies when a parameter defined by a capture group is not included in one example" do
78
- expect { |unused| entry.verify_tests_have_capture_groups(&unused) }.to yield_successive_args([:warn, String])
78
+ expect { |unused| entry.verify_tests_have_capture_groups(&unused) }.to yield_successive_args([:fail, String])
79
79
  end
80
80
  end
81
81
 
@@ -83,7 +83,7 @@ describe Recog::Fingerprint do
83
83
  let(:entry) { described_class.new(doc.xpath("//fingerprints/fingerprint")[7]) }
84
84
 
85
85
  it "identifies when two parameters defined by a capture groups are not included in one example" do
86
- expect { |unused| entry.verify_tests_have_capture_groups(&unused) }.to yield_successive_args([:warn, String], [:warn, String])
86
+ expect { |unused| entry.verify_tests_have_capture_groups(&unused) }.to yield_successive_args([:fail, String], [:fail, String])
87
87
  end
88
88
  end
89
89
 
@@ -92,7 +92,7 @@ describe Recog::Fingerprint do
92
92
  let(:entry) { described_class.new(doc.xpath("//fingerprints/fingerprint")[8]) }
93
93
 
94
94
  it "identifies when a parameter defined by a capture group is not included in one example" do
95
- expect { |unused| entry.verify_tests_have_capture_groups(&unused) }.to yield_successive_args([:warn, String])
95
+ expect { |unused| entry.verify_tests_have_capture_groups(&unused) }.to yield_successive_args([:fail, String])
96
96
  end
97
97
  end
98
98
 
@@ -100,7 +100,7 @@ describe Recog::Fingerprint do
100
100
  let(:entry) { described_class.new(doc.xpath("//fingerprints/fingerprint")[9]) }
101
101
 
102
102
  it "identifies when two parameters defined by a capture groups are not included in one example" do
103
- expect { |unused| entry.verify_tests_have_capture_groups(&unused) }.to yield_successive_args([:warn, String], [:warn, String])
103
+ expect { |unused| entry.verify_tests_have_capture_groups(&unused) }.to yield_successive_args([:fail, String], [:fail, String])
104
104
  end
105
105
  end
106
106
 
@@ -7,6 +7,7 @@ describe Recog::VerifyReporter do
7
7
  let(:summary_line) do
8
8
  "SUMMARY: Test completed with 1 successful, 1 warnings, and 1 failures"
9
9
  end
10
+ let(:path) { "fingerprint.xml" }
10
11
 
11
12
  subject { Recog::VerifyReporter.new(double(detail: false, quiet: false, warnings: true), formatter) }
12
13
 
@@ -21,12 +22,12 @@ describe Recog::VerifyReporter do
21
22
 
22
23
  describe "#report" do
23
24
  it "prints warnings" do
24
- expect(formatter).to receive(:warning_message).with('a warning')
25
+ expect(formatter).to receive(:warning_message).with('WARN: a warning')
25
26
  run_report
26
27
  end
27
28
 
28
29
  it "prints failures" do
29
- expect(formatter).to receive(:failure_message).with('a failure')
30
+ expect(formatter).to receive(:failure_message).with('FAIL: a failure')
30
31
  run_report
31
32
  end
32
33
 
@@ -49,12 +50,80 @@ describe Recog::VerifyReporter do
49
50
  end
50
51
 
51
52
  it "prints warnings" do
52
- expect(formatter).to receive(:warning_message).with(' a warning')
53
+ expect(formatter).to receive(:warning_message).with(' WARN: a warning')
53
54
  run_report
54
55
  end
55
56
 
56
57
  it "prints failures" do
57
- expect(formatter).to receive(:failure_message).with(' a failure')
58
+ expect(formatter).to receive(:failure_message).with(' FAIL: a failure')
59
+ run_report
60
+ end
61
+
62
+ it "prints the fingerprint count" do
63
+ expect(formatter).to receive(:status_message).with("\nVerified 1 fingerprints:")
64
+ run_report
65
+ end
66
+
67
+ it "prints summary" do
68
+ expect(formatter).to receive(:failure_message).with(summary_line)
69
+ run_report
70
+ end
71
+
72
+ context "with no fingerprint tests" do
73
+ let(:tests) { [] }
74
+
75
+ it "does not print the name" do
76
+ expect(formatter).not_to receive(:status_message).with("\na name")
77
+ run_report
78
+ end
79
+ end
80
+ end
81
+
82
+ context "with fingerprint path" do
83
+
84
+ subject { Recog::VerifyReporter.new(double(detail: false, quiet: false, warnings: true), formatter, path) }
85
+
86
+ it "prints warnings" do
87
+ expect(formatter).to receive(:warning_message).with("#{path}: WARN: a warning")
88
+ run_report
89
+ end
90
+
91
+ it "prints failures" do
92
+ expect(formatter).to receive(:failure_message).with("#{path}: FAIL: a failure")
93
+ run_report
94
+ end
95
+
96
+ it "prints summary" do
97
+ expect(formatter).to receive(:failure_message).with("#{path}: #{summary_line}")
98
+ run_report
99
+ end
100
+ end
101
+
102
+ context "with fingerprint path and detail" do
103
+ subject { Recog::VerifyReporter.new(double(detail: true, quiet: false, warnings: true), formatter, path) }
104
+
105
+ it "prints the fingerprint path" do
106
+ expect(formatter).to receive(:status_message).with("\n#{path}:\n")
107
+ run_report
108
+ end
109
+
110
+ it "prints the fingerprint name" do
111
+ expect(formatter).to receive(:status_message).with("\na name")
112
+ run_report
113
+ end
114
+
115
+ it "prints successes" do
116
+ expect(formatter).to receive(:success_message).with(' passed')
117
+ run_report
118
+ end
119
+
120
+ it "prints warnings" do
121
+ expect(formatter).to receive(:warning_message).with(' WARN: a warning')
122
+ run_report
123
+ end
124
+
125
+ it "prints failures" do
126
+ expect(formatter).to receive(:failure_message).with(' FAIL: a failure')
58
127
  run_report
59
128
  end
60
129
 
@@ -0,0 +1,21 @@
1
+ #!/bin/sh
2
+ #
3
+ # Hook script to verify changes about to be committed.
4
+ # The hook should exit with non-zero status after issuing an appropriate
5
+ # message if it wants to stop the commit.
6
+
7
+ # Verify that each fingerprint asserts known identifiers.
8
+ git diff --cached --name-only --diff-filter=ACM -z xml/*.xml | xargs -0 ./bin/recog_standardize --write
9
+
10
+ # get status
11
+ status=$?
12
+
13
+ if [ $status -ne 0 ]; then
14
+ echo "Please review any new additions to the text files under 'identifiers/'."
15
+ echo "If any of these names are close to an existing name, update the offending"
16
+ echo "fingerprint to use the existing name instead. Once the fingerprints are fixed,"
17
+ echo "remove the 'extra' names from the identifiers files, and run the tool again."
18
+ exit 1
19
+ fi
20
+
21
+ exit 0