lex-detect 0.1.7 → 0.2.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f0a985e71fac2b9cbee47bb0f1eef3d7eb744dbbea99b573f0d90dba9ca7bc89
4
- data.tar.gz: dca63d849d77bb5aa83da69ce23146a8294666c594bb155b6f3d964d7416dccc
3
+ metadata.gz: 7e40e042cb6111ce0d3708ed3de574e32baf92839704e2a22ed4c239bcaf4907
4
+ data.tar.gz: 4fdd6b3f2388a5aeb8a5a862e57cc29d57aa239793dbccdcabbdc1967267a031
5
5
  SHA512:
6
- metadata.gz: c8718ab255658b92ce9579815b01032afc68ded3cece3d6c13eaaaa714143203303023541ffb4b24f3d275a69004f7c043492f030b775c78b371d1edce3c76ba
7
- data.tar.gz: 2695aff906451268b4733463190117c099f8c2fbb6be063003fd9ff3216db0494d0d3e265d9b8c5ebdd538b817132975dff186b37bc75f0838578b49d60e2b72
6
+ metadata.gz: 8d8a294a962b08b21d08d26b9189ab01e7194a244e04299b2094e3eecfd5b00f40cebc56d438ea71b5ed2a47aab10bb77bf465eb8b71eff5821fdb5e11cd9f55
7
+ data.tar.gz: 634257c97700a444f7a846ef249d69d718e5cf2d0202793bd38ba156bb48fae025410d98e7aeba56a8735647334d34c2f4bfd7cbdf53fc2c8870e50bf55297ce
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.2.0] - 2026-03-22
4
+
5
+ ### Added
6
+ - SARIF 2.1.0 formatter (`Formatters::Sarif`) for GitHub Code Scanning integration
7
+ - Markdown PR comment formatter (`Formatters::MarkdownPr`) for GitHub PR annotations
8
+ - `format_results(format:, detections:)` public API method supporting `:sarif`, `:markdown`, and `:json` output formats
9
+
3
10
  ## [0.1.7] - 2026-03-22
4
11
 
5
12
  ### Fixed
data/CLAUDE.md CHANGED
@@ -10,7 +10,7 @@ Legion Extension that scans the local environment and recommends which `lex-*` e
10
10
 
11
11
  **GitHub**: https://github.com/LegionIO/lex-detect
12
12
  **License**: MIT
13
- **Version**: 0.1.4
13
+ **Version**: 0.2.0
14
14
 
15
15
  ## Architecture
16
16
 
@@ -57,7 +57,7 @@ Legion::Extensions::Detect.catalog # raw CATALOG constant
57
57
 
58
58
  ## Testing
59
59
 
60
- 40 specs across 6 spec files.
60
+ 54 specs across 9 spec files.
61
61
 
62
62
  ```bash
63
63
  bundle install
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Detect
6
+ module Formatters
7
+ module MarkdownPr
8
+ module_function
9
+
10
+ def format(detections)
11
+ missing = collect_missing(detections)
12
+ installed = collect_installed(detections)
13
+
14
+ lines = ["## Legion Detect Findings\n"]
15
+
16
+ if missing.any?
17
+ lines << "### Missing Extensions (#{missing.size})\n"
18
+ missing.each do |m|
19
+ lines << "- **#{m[:name]}**: `#{m[:extension]}` not installed"
20
+ lines << " Detected by: #{m[:signals].join(', ')}"
21
+ lines << " Install: `gem install #{m[:extension]}`\n"
22
+ end
23
+ end
24
+
25
+ if installed.any?
26
+ lines << "### Installed (#{installed.size})\n"
27
+ installed.each do |i|
28
+ lines << "- #{i[:name]}: `#{i[:extension]}` :white_check_mark:"
29
+ end
30
+ end
31
+
32
+ lines << "No extensions detected.\n" if missing.empty? && installed.empty?
33
+
34
+ lines << "\n---\n*Generated by legion-detect v#{VERSION}*"
35
+ lines.join("\n")
36
+ end
37
+
38
+ def collect_missing(detections)
39
+ detections.flat_map do |d|
40
+ d[:extensions].filter_map do |ext|
41
+ next if d[:installed][ext]
42
+
43
+ { name: d[:name], extension: ext, signals: d[:matched_signals] }
44
+ end
45
+ end
46
+ end
47
+
48
+ def collect_installed(detections)
49
+ detections.flat_map do |d|
50
+ d[:extensions].filter_map do |ext|
51
+ next unless d[:installed][ext]
52
+
53
+ { name: d[:name], extension: ext }
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
5
+ module Legion
6
+ module Extensions
7
+ module Detect
8
+ module Formatters
9
+ module Sarif
10
+ SCHEMA = 'https://json.schemastore.org/sarif-2.1.0.json'
11
+ SARIF_VERSION = '2.1.0'
12
+
13
+ SEVERITY_MAP = {
14
+ missing: 'warning',
15
+ installed: 'note'
16
+ }.freeze
17
+
18
+ module_function
19
+
20
+ def format(detections)
21
+ rules = build_rules(detections)
22
+ results = build_results(detections)
23
+
24
+ {
25
+ '$schema' => SCHEMA,
26
+ 'version' => SARIF_VERSION,
27
+ 'runs' => [{
28
+ 'tool' => {
29
+ 'driver' => {
30
+ 'name' => 'legion-detect',
31
+ 'version' => VERSION,
32
+ 'informationUri' => 'https://github.com/LegionIO/lex-detect',
33
+ 'rules' => rules
34
+ }
35
+ },
36
+ 'results' => results
37
+ }]
38
+ }
39
+ end
40
+
41
+ def to_json(detections)
42
+ ::JSON.pretty_generate(format(detections))
43
+ end
44
+
45
+ def build_rules(detections)
46
+ rules = detections.flat_map do |detection|
47
+ detection[:extensions].map do |ext|
48
+ {
49
+ 'id' => "detect/#{ext}",
50
+ 'name' => detection[:name],
51
+ 'shortDescription' => { 'text' => "#{detection[:name]} detected — #{ext} recommended" },
52
+ 'defaultConfiguration' => { 'level' => 'warning' }
53
+ }
54
+ end
55
+ end
56
+ rules.uniq { |r| r['id'] }
57
+ end
58
+
59
+ def build_results(detections)
60
+ detections.flat_map do |detection|
61
+ detection[:extensions].filter_map do |ext|
62
+ next if detection[:installed][ext]
63
+
64
+ {
65
+ 'ruleId' => "detect/#{ext}",
66
+ 'level' => 'warning',
67
+ 'message' => {
68
+ 'text' => "#{detection[:name]} detected (#{detection[:matched_signals].join(', ')}) but #{ext} is not installed"
69
+ },
70
+ 'properties' => {
71
+ 'matched_signals' => detection[:matched_signals],
72
+ 'detection_name' => detection[:name]
73
+ }
74
+ }
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
@@ -3,7 +3,7 @@
3
3
  module Legion
4
4
  module Extensions
5
5
  module Detect
6
- VERSION = '0.1.7'
6
+ VERSION = '0.2.0'
7
7
  end
8
8
  end
9
9
  end
@@ -4,6 +4,8 @@ require 'legion/extensions/detect/version'
4
4
  require 'legion/extensions/detect/catalog'
5
5
  require 'legion/extensions/detect/scanner'
6
6
  require 'legion/extensions/detect/installer'
7
+ require 'legion/extensions/detect/formatters/sarif'
8
+ require 'legion/extensions/detect/formatters/markdown_pr'
7
9
  require_relative 'detect/runners/task_observer'
8
10
  require_relative 'detect/runners/cancel_task'
9
11
 
@@ -41,6 +43,15 @@ module Legion
41
43
  def catalog
42
44
  CATALOG
43
45
  end
46
+
47
+ def format_results(format: :json, detections: nil)
48
+ results = detections || scan
49
+ case format.to_sym
50
+ when :sarif then Formatters::Sarif.to_json(results)
51
+ when :markdown then Formatters::MarkdownPr.format(results)
52
+ else results
53
+ end
54
+ end
44
55
  end
45
56
 
46
57
  require_relative 'detect/actors/full_scan' if defined?(Legion::Extensions::Actors::Once)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lex-detect
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.7
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Esity
@@ -31,6 +31,8 @@ files:
31
31
  - lib/legion/extensions/detect/actors/full_scan.rb
32
32
  - lib/legion/extensions/detect/actors/observer_tick.rb
33
33
  - lib/legion/extensions/detect/catalog.rb
34
+ - lib/legion/extensions/detect/formatters/markdown_pr.rb
35
+ - lib/legion/extensions/detect/formatters/sarif.rb
34
36
  - lib/legion/extensions/detect/installer.rb
35
37
  - lib/legion/extensions/detect/local_migrations/20260319000001_create_detect_results.rb
36
38
  - lib/legion/extensions/detect/local_migrations/20260320000001_create_observer_events.rb