fastlane-plugin-seclane 1.0.0 → 1.0.1

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: 784dd68429a97b3d8e10a7a2641850c3061d9fd15c5519f2f8b284f3cd6c3911
4
- data.tar.gz: 16e2bf24282d861bf7b68453a41223d493aaff3098affdd9bcc06fa1cee4adff
3
+ metadata.gz: 115fb009ca9775fe981b9e4d60963a747a9ae061314c890bbb54a250b1d19e66
4
+ data.tar.gz: 384da5ee580f34b77121d56821afd5924cfedf388aa6b169e75db88f62d61799
5
5
  SHA512:
6
- metadata.gz: 4e27c5fd15088c5fab4159eb4da6bab220dd67129ce2fbace7e7070ab315d89e59b65590c45709a2963c2951f4f1bbbde926e872df3d5c50455821294bbac54e
7
- data.tar.gz: 63c04aff74bdd23d9291c346f1574339420798f61e0b6b0d2e25ccb779d5fdf8bd9e4f21128a75bfe94036541310764ebd9e5f00aa7334a086a9903935dee4ff
6
+ metadata.gz: 27da8ab0bc8d46f630f8a7dca0bea3d3424266f4b3958b02e9ef38575983bdbe8d7429e96fa8163b9432f6f9eaf953b7dbcf429342eff9ee5c49a716f4010d99
7
+ data.tar.gz: e966b7846584da5c34b17d29963d7c7da9236cd518957ba0a28cf9c750353646738dc132b67c0f9dd7bdeed15386602ad2b5abcdb79c6485a0cee3d912deeab2
@@ -1,39 +1,126 @@
1
- require "seclane"
1
+ require "json"
2
+ require "open-uri"
3
+ require "fileutils"
2
4
 
3
5
  module Fastlane
4
6
  module Actions
5
7
  class SeclaneScanAction < Action
8
+ SECLANE_VERSION = "1.0.1"
9
+
6
10
  def self.run(params)
7
- config = ::Seclane::Configuration.new(
8
- platform: params[:platform],
9
- scan_mode: params[:scan_mode],
10
- base_branch: params[:base_branch],
11
- severity_threshold: params[:severity_threshold],
12
- fail_on_severity: params[:fail_on_severity],
13
- fail_on_count: params[:fail_on_count],
14
- custom_patterns: params[:custom_patterns],
15
- exclude_patterns: params[:exclude_patterns],
16
- disabled_rules: params[:disabled_rules],
17
- disabled_categories: params[:disabled_categories],
18
- output_format: params[:output_format],
19
- config_file: params[:config_file]
20
- )
21
-
22
- scanner = ::Seclane::Scanner.new(config)
23
- scanner.run
24
-
25
- report = scanner.report
11
+ binary = ensure_binary(params[:version] || SECLANE_VERSION)
12
+
13
+ args = [
14
+ "scan",
15
+ "--platform", params[:platform],
16
+ "--scan-mode", params[:scan_mode],
17
+ "--base-branch", params[:base_branch],
18
+ "--severity-threshold", params[:severity_threshold],
19
+ "--fail-on-severity", params[:fail_on_severity],
20
+ "--fail-on-count", params[:fail_on_count].to_s,
21
+ "--output-format", params[:output_format],
22
+ "--config-file", params[:config_file],
23
+ "--json-stdout"
24
+ ]
25
+
26
+ if params[:custom_patterns] && !params[:custom_patterns].empty?
27
+ args += ["--custom-patterns", params[:custom_patterns].join(",")]
28
+ end
29
+ if params[:exclude_patterns] && !params[:exclude_patterns].empty?
30
+ args += ["--exclude-patterns", params[:exclude_patterns].join(",")]
31
+ end
32
+ if params[:disabled_rules] && !params[:disabled_rules].empty?
33
+ args += ["--disabled-rules", params[:disabled_rules].join(",")]
34
+ end
35
+ if params[:disabled_categories] && !params[:disabled_categories].empty?
36
+ args += ["--disabled-categories", params[:disabled_categories].join(",")]
37
+ end
38
+
39
+ report_file = File.join(Dir.tmpdir, "seclane-report.#{params[:output_format]}")
40
+ args += ["--output-file", report_file]
41
+
42
+ cmd = ([binary] + args).shelljoin
43
+ output = `#{cmd} 2>&1`
44
+ exit_code = $?.exitstatus
45
+
46
+ if exit_code == 2
47
+ UI.user_error!("Seclane configuration error: #{output}")
48
+ end
49
+
50
+ report = File.exist?(report_file) ? File.read(report_file) : output
26
51
  UI.message(report)
27
52
 
28
- findings = scanner.filtered_findings
29
- Actions.lane_context[SharedValues::SECLANE_FINDINGS_COUNT] = findings.length
53
+ findings_count = 0
54
+ begin
55
+ parsed = JSON.parse(output.strip.split("\n").last)
56
+ findings_count = parsed["findings_count"] || 0
57
+ rescue JSON::ParserError
58
+ end
59
+
60
+ Actions.lane_context[SharedValues::SECLANE_FINDINGS_COUNT] = findings_count
30
61
  Actions.lane_context[SharedValues::SECLANE_REPORT] = report
31
62
 
32
- if scanner.failed?
33
- UI.user_error!("Seclane found #{findings.length} secret(s) meeting the failure threshold")
63
+ if exit_code == 1
64
+ UI.user_error!("Seclane found #{findings_count} secret(s) meeting the failure threshold")
65
+ end
66
+
67
+ findings_count
68
+ end
69
+
70
+ def self.ensure_binary(version)
71
+ unless version.match?(/\A\d+\.\d+\.\d+\z/)
72
+ UI.user_error!("Invalid version format: #{version}. Must be X.Y.Z")
73
+ end
74
+
75
+ bin_dir = File.join(Dir.home, ".seclane", "bin")
76
+ FileUtils.mkdir_p(bin_dir)
77
+
78
+ os = RUBY_PLATFORM.include?("darwin") ? "darwin" : "linux"
79
+
80
+ if RUBY_PLATFORM =~ /mingw|mswin|cygwin/
81
+ UI.user_error!("Seclane does not support Windows. Supported platforms: Linux (amd64, arm64), macOS (amd64, arm64).")
82
+ end
83
+
84
+ arch = case RUBY_PLATFORM
85
+ when /arm64|aarch64/ then "arm64"
86
+ else "amd64"
87
+ end
88
+
89
+ binary = File.join(bin_dir, "seclane-#{version}")
90
+
91
+ unless File.executable?(binary)
92
+ base_url = "https://github.com/tsvetilian-ty/seclane/releases/download/v#{version}"
93
+ bin_url = "#{base_url}/seclane-#{os}-#{arch}"
94
+ checksums_url = "#{base_url}/checksums.txt"
95
+
96
+ UI.message("Downloading seclane v#{version}...")
97
+ URI.open(bin_url) do |remote|
98
+ File.open(binary, "wb") { |f| f.write(remote.read) }
99
+ end
100
+
101
+ require "digest"
102
+ actual_sha256 = Digest::SHA256.file(binary).hexdigest
103
+
104
+ begin
105
+ checksums_content = URI.open(checksums_url).read
106
+ expected_line = checksums_content.lines.find { |l| l.include?("seclane-#{os}-#{arch}") }
107
+ if expected_line
108
+ expected_sha256 = expected_line.strip.split(/\s+/).first
109
+ unless actual_sha256 == expected_sha256
110
+ File.delete(binary) if File.exist?(binary)
111
+ UI.user_error!("Checksum verification failed for seclane binary. Expected #{expected_sha256}, got #{actual_sha256}")
112
+ end
113
+ else
114
+ UI.important("Could not find checksum entry for seclane-#{os}-#{arch} in checksums.txt, skipping verification")
115
+ end
116
+ rescue OpenURI::HTTPError => e
117
+ UI.important("Could not download checksums.txt (#{e.message}), skipping verification")
118
+ end
119
+
120
+ FileUtils.chmod(0o755, binary)
34
121
  end
35
122
 
36
- findings.length
123
+ binary
37
124
  end
38
125
 
39
126
  def self.description
@@ -49,7 +136,7 @@ module Fastlane
49
136
  end
50
137
 
51
138
  def self.details
52
- "Uses git diff to detect changed files and scans them for hardcoded secrets, API keys, tokens, private keys, and other sensitive data. Supports Android and iOS specific patterns."
139
+ "Uses git diff to detect changed files and scans them for hardcoded secrets, API keys, tokens, private keys, and other sensitive data. Supports Android, iOS, Flutter, and React Native."
53
140
  end
54
141
 
55
142
  def self.available_options
@@ -59,12 +146,7 @@ module Fastlane
59
146
  env_name: "SECLANE_PLATFORM",
60
147
  description: "Target platform: 'android', 'ios', 'flutter', 'react_native'",
61
148
  optional: false,
62
- type: String,
63
- verify_block: proc do |value|
64
- unless %w[android ios flutter react_native].include?(value)
65
- UI.user_error!("Invalid platform: #{value}. Must be 'android', 'ios', 'flutter', or 'react_native'")
66
- end
67
- end
149
+ type: String
68
150
  ),
69
151
  FastlaneCore::ConfigItem.new(
70
152
  key: :scan_mode,
@@ -72,12 +154,7 @@ module Fastlane
72
154
  description: "Scan mode: 'diff' for changed files only, 'full' for all files",
73
155
  default_value: "diff",
74
156
  optional: true,
75
- type: String,
76
- verify_block: proc do |value|
77
- unless %w[diff full].include?(value)
78
- UI.user_error!("Invalid scan_mode: #{value}. Must be 'diff' or 'full'")
79
- end
80
- end
157
+ type: String
81
158
  ),
82
159
  FastlaneCore::ConfigItem.new(
83
160
  key: :base_branch,
@@ -93,12 +170,7 @@ module Fastlane
93
170
  description: "Minimum severity to report: 'low', 'medium', 'high'",
94
171
  default_value: "low",
95
172
  optional: true,
96
- type: String,
97
- verify_block: proc do |value|
98
- unless %w[low medium high].include?(value)
99
- UI.user_error!("Invalid severity_threshold: #{value}")
100
- end
101
- end
173
+ type: String
102
174
  ),
103
175
  FastlaneCore::ConfigItem.new(
104
176
  key: :fail_on_severity,
@@ -106,17 +178,12 @@ module Fastlane
106
178
  description: "Fail the lane at this severity: 'low', 'medium', 'high', 'none'",
107
179
  default_value: "high",
108
180
  optional: true,
109
- type: String,
110
- verify_block: proc do |value|
111
- unless %w[low medium high none].include?(value)
112
- UI.user_error!("Invalid fail_on_severity: #{value}")
113
- end
114
- end
181
+ type: String
115
182
  ),
116
183
  FastlaneCore::ConfigItem.new(
117
184
  key: :fail_on_count,
118
185
  env_name: "SECLANE_FAIL_ON_COUNT",
119
- description: "Number of findings at fail severity needed to fail the lane (default: 1)",
186
+ description: "Number of findings at fail severity needed to fail the lane",
120
187
  default_value: 1,
121
188
  optional: true,
122
189
  type: Integer
@@ -137,19 +204,6 @@ module Fastlane
137
204
  optional: true,
138
205
  type: Array
139
206
  ),
140
- FastlaneCore::ConfigItem.new(
141
- key: :output_format,
142
- env_name: "SECLANE_OUTPUT_FORMAT",
143
- description: "Output format: 'text', 'json', 'junit', 'markdown'",
144
- default_value: "text",
145
- optional: true,
146
- type: String,
147
- verify_block: proc do |value|
148
- unless %w[text json junit markdown sonarqube].include?(value)
149
- UI.user_error!("Invalid output_format: #{value}")
150
- end
151
- end
152
- ),
153
207
  FastlaneCore::ConfigItem.new(
154
208
  key: :disabled_rules,
155
209
  env_name: "SECLANE_DISABLED_RULES",
@@ -161,11 +215,19 @@ module Fastlane
161
215
  FastlaneCore::ConfigItem.new(
162
216
  key: :disabled_categories,
163
217
  env_name: "SECLANE_DISABLED_CATEGORIES",
164
- description: "List of rule categories to disable (e.g., 'ai_provider', 'saas_tokens')",
218
+ description: "List of rule categories to disable",
165
219
  default_value: [],
166
220
  optional: true,
167
221
  type: Array
168
222
  ),
223
+ FastlaneCore::ConfigItem.new(
224
+ key: :output_format,
225
+ env_name: "SECLANE_OUTPUT_FORMAT",
226
+ description: "Output format: 'text', 'json', 'junit', 'markdown', 'sonarqube'",
227
+ default_value: "text",
228
+ optional: true,
229
+ type: String
230
+ ),
169
231
  FastlaneCore::ConfigItem.new(
170
232
  key: :config_file,
171
233
  env_name: "SECLANE_CONFIG_FILE",
@@ -173,6 +235,14 @@ module Fastlane
173
235
  default_value: ".seclane.yml",
174
236
  optional: true,
175
237
  type: String
238
+ ),
239
+ FastlaneCore::ConfigItem.new(
240
+ key: :version,
241
+ env_name: "SECLANE_VERSION",
242
+ description: "Seclane CLI version to download",
243
+ default_value: SECLANE_VERSION,
244
+ optional: true,
245
+ type: String
176
246
  )
177
247
  ]
178
248
  end
@@ -1,5 +1,5 @@
1
1
  module Fastlane
2
2
  module Seclane
3
- VERSION = "1.0.0"
3
+ VERSION = "1.0.1"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fastlane-plugin-seclane
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Seclane by Cluelane
@@ -10,20 +10,6 @@ bindir: bin
10
10
  cert_chain: []
11
11
  date: 2026-03-29 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: seclane-core
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: '1.0'
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: '1.0'
27
13
  - !ruby/object:Gem::Dependency
28
14
  name: bundler
29
15
  requirement: !ruby/object:Gem::Requirement