ai_root_shield 0.3.0 → 0.5.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 +4 -4
- data/CHANGELOG.md +25 -0
- data/Gemfile.lock +1 -1
- data/README.md +210 -12
- data/examples/policies/banking_policy.json +79 -0
- data/examples/policies/development_policy.json +64 -0
- data/examples/policies/enterprise_policy.json +89 -0
- data/exe/ai_root_shield +314 -8
- data/lib/ai_root_shield/advanced_proxy_detector.rb +406 -0
- data/lib/ai_root_shield/certificate_pinning_helper.rb +258 -0
- data/lib/ai_root_shield/enterprise_policy_manager.rb +431 -0
- data/lib/ai_root_shield/version.rb +1 -1
- data/lib/ai_root_shield.rb +290 -4
- metadata +15 -5
data/exe/ai_root_shield
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
|
4
4
|
require "optparse"
|
5
5
|
require "json"
|
6
|
+
require "fileutils"
|
6
7
|
require_relative "../lib/ai_root_shield"
|
7
8
|
|
8
9
|
# Command line interface for AI Root Shield
|
@@ -19,13 +20,42 @@ class AiRootShieldCLI
|
|
19
20
|
enable_network_analysis: true,
|
20
21
|
enable_ai_behavioral_analysis: true,
|
21
22
|
enable_rasp_protection: false,
|
22
|
-
rasp_monitoring_time: 5
|
23
|
+
rasp_monitoring_time: 5,
|
24
|
+
policy_file: nil,
|
25
|
+
enable_certificate_pinning: false,
|
26
|
+
enable_proxy_detection: false,
|
27
|
+
target_ip: nil,
|
28
|
+
target_url: nil,
|
29
|
+
# v0.5.0 new options
|
30
|
+
platform: nil,
|
31
|
+
safetynet_api_key: nil,
|
32
|
+
package_name: nil,
|
33
|
+
ci_mode: false,
|
34
|
+
artifacts_path: './security_test_artifacts',
|
35
|
+
siem_platform: nil,
|
36
|
+
siem_endpoint: nil,
|
37
|
+
siem_token: nil,
|
38
|
+
start_dashboard: false,
|
39
|
+
dashboard_port: 4567,
|
40
|
+
generate_ci_config: nil,
|
41
|
+
enable_unified_reporting: false
|
23
42
|
}
|
24
43
|
end
|
25
44
|
|
26
45
|
def run(args)
|
27
46
|
parse_options(args)
|
28
47
|
|
48
|
+
# Handle special commands first
|
49
|
+
if @options[:start_dashboard]
|
50
|
+
start_dashboard
|
51
|
+
return
|
52
|
+
end
|
53
|
+
|
54
|
+
if @options[:generate_ci_config]
|
55
|
+
generate_ci_config
|
56
|
+
return
|
57
|
+
end
|
58
|
+
|
29
59
|
if args.empty?
|
30
60
|
puts "Error: Please provide a device logs file path"
|
31
61
|
puts "Usage: ai_root_shield [options] <device_logs.json>"
|
@@ -40,6 +70,33 @@ class AiRootShieldCLI
|
|
40
70
|
end
|
41
71
|
|
42
72
|
begin
|
73
|
+
# Configure SIEM if provided
|
74
|
+
if @options[:siem_platform] && @options[:siem_endpoint] && @options[:siem_token]
|
75
|
+
puts "Configuring SIEM integration (#{@options[:siem_platform]})..." if @options[:verbose]
|
76
|
+
AiRootShield.configure_siem(@options[:siem_platform].to_sym, {
|
77
|
+
api_endpoint: @options[:siem_endpoint],
|
78
|
+
api_key: @options[:siem_token]
|
79
|
+
})
|
80
|
+
end
|
81
|
+
|
82
|
+
# Configure enterprise policy if provided
|
83
|
+
if @options[:policy_file]
|
84
|
+
puts "Loading enterprise policy from #{@options[:policy_file]}..." if @options[:verbose]
|
85
|
+
AiRootShield.configure_policy(@options[:policy_file])
|
86
|
+
end
|
87
|
+
|
88
|
+
# Configure certificate pinning if enabled
|
89
|
+
if @options[:enable_certificate_pinning]
|
90
|
+
puts "Configuring certificate pinning..." if @options[:verbose]
|
91
|
+
AiRootShield.configure_certificate_pinning
|
92
|
+
end
|
93
|
+
|
94
|
+
# Configure proxy detection if enabled
|
95
|
+
if @options[:enable_proxy_detection]
|
96
|
+
puts "Configuring proxy detection..." if @options[:verbose]
|
97
|
+
AiRootShield.configure_proxy_detection
|
98
|
+
end
|
99
|
+
|
43
100
|
# Start RASP protection if enabled
|
44
101
|
if @options[:enable_rasp_protection]
|
45
102
|
puts "Starting RASP protection..." if @options[:verbose]
|
@@ -60,13 +117,34 @@ class AiRootShieldCLI
|
|
60
117
|
sleep(@options[:rasp_monitoring_time])
|
61
118
|
end
|
62
119
|
|
63
|
-
|
120
|
+
# Run analysis based on mode
|
121
|
+
if @options[:ci_mode]
|
122
|
+
result = run_ci_cd_analysis(device_logs_path)
|
123
|
+
elsif @options[:platform]
|
124
|
+
result = run_platform_specific_analysis(device_logs_path)
|
125
|
+
else
|
126
|
+
result = AiRootShield.scan_device_with_config(device_logs_path, @options)
|
127
|
+
end
|
128
|
+
|
129
|
+
# Send to SIEM if configured
|
130
|
+
if @options[:siem_platform]
|
131
|
+
puts "Sending results to SIEM..." if @options[:verbose]
|
132
|
+
AiRootShield.send_to_siem(result, {
|
133
|
+
cli_version: AiRootShield::VERSION,
|
134
|
+
scan_timestamp: Time.now.utc.iso8601
|
135
|
+
})
|
136
|
+
end
|
64
137
|
|
65
138
|
# Add RASP status to result if enabled
|
66
139
|
if @options[:enable_rasp_protection] && AiRootShield.rasp_active?
|
67
140
|
result[:rasp_status] = AiRootShield.rasp_protection.protection_status
|
68
141
|
end
|
69
142
|
|
143
|
+
# Add security status if verbose
|
144
|
+
if @options[:verbose]
|
145
|
+
result[:security_status] = AiRootShield.security_status
|
146
|
+
end
|
147
|
+
|
70
148
|
output_result(result)
|
71
149
|
|
72
150
|
rescue AiRootShield::Error => e
|
@@ -136,6 +214,90 @@ class AiRootShieldCLI
|
|
136
214
|
@options[:rasp_monitoring_time] = time
|
137
215
|
end
|
138
216
|
|
217
|
+
opts.on("--policy FILE", "Enterprise policy file path") do |file|
|
218
|
+
@options[:policy_file] = file
|
219
|
+
end
|
220
|
+
|
221
|
+
opts.on("--enable-cert-pinning", "Enable certificate pinning validation") do
|
222
|
+
@options[:enable_certificate_pinning] = true
|
223
|
+
end
|
224
|
+
|
225
|
+
opts.on("--enable-proxy-detection", "Enable advanced proxy detection") do
|
226
|
+
@options[:enable_proxy_detection] = true
|
227
|
+
end
|
228
|
+
|
229
|
+
opts.on("--target-ip IP", "Target IP address for network analysis") do |ip|
|
230
|
+
@options[:target_ip] = ip
|
231
|
+
end
|
232
|
+
|
233
|
+
opts.on("--target-url URL", "Target URL for certificate pinning validation") do |url|
|
234
|
+
@options[:target_url] = url
|
235
|
+
end
|
236
|
+
|
237
|
+
# v0.5.0 Platform-specific options
|
238
|
+
opts.separator ""
|
239
|
+
opts.separator "Platform-specific Analysis (v0.5.0):"
|
240
|
+
|
241
|
+
opts.on("--platform PLATFORM", ["android", "ios"], "Platform-specific analysis (android, ios)") do |platform|
|
242
|
+
@options[:platform] = platform
|
243
|
+
end
|
244
|
+
|
245
|
+
opts.on("--safetynet-key KEY", "Google SafetyNet API key for Android analysis") do |key|
|
246
|
+
@options[:safetynet_api_key] = key
|
247
|
+
end
|
248
|
+
|
249
|
+
opts.on("--package-name NAME", "Android package name for analysis") do |name|
|
250
|
+
@options[:package_name] = name
|
251
|
+
end
|
252
|
+
|
253
|
+
opts.on("--unified-report", "Generate unified cross-platform report") do
|
254
|
+
@options[:enable_unified_reporting] = true
|
255
|
+
end
|
256
|
+
|
257
|
+
# CI/CD Integration options
|
258
|
+
opts.separator ""
|
259
|
+
opts.separator "CI/CD Integration (v0.5.0):"
|
260
|
+
|
261
|
+
opts.on("--ci-mode", "Run in CI/CD mode with test artifacts") do
|
262
|
+
@options[:ci_mode] = true
|
263
|
+
end
|
264
|
+
|
265
|
+
opts.on("--artifacts-path PATH", "Path for CI/CD test artifacts (default: ./security_test_artifacts)") do |path|
|
266
|
+
@options[:artifacts_path] = path
|
267
|
+
end
|
268
|
+
|
269
|
+
opts.on("--generate-ci-config PLATFORM", ["github", "gitlab", "jenkins", "azure"], "Generate CI config for platform") do |platform|
|
270
|
+
@options[:generate_ci_config] = platform
|
271
|
+
end
|
272
|
+
|
273
|
+
# SIEM Integration options
|
274
|
+
opts.separator ""
|
275
|
+
opts.separator "SIEM Integration (v0.5.0):"
|
276
|
+
|
277
|
+
opts.on("--siem-platform PLATFORM", ["splunk", "elastic", "qradar", "sentinel", "datadog", "chronicle", "arcsight"], "SIEM platform") do |platform|
|
278
|
+
@options[:siem_platform] = platform
|
279
|
+
end
|
280
|
+
|
281
|
+
opts.on("--siem-endpoint URL", "SIEM API endpoint URL") do |url|
|
282
|
+
@options[:siem_endpoint] = url
|
283
|
+
end
|
284
|
+
|
285
|
+
opts.on("--siem-token TOKEN", "SIEM API authentication token") do |token|
|
286
|
+
@options[:siem_token] = token
|
287
|
+
end
|
288
|
+
|
289
|
+
# Dashboard options
|
290
|
+
opts.separator ""
|
291
|
+
opts.separator "Dashboard (v0.5.0):"
|
292
|
+
|
293
|
+
opts.on("--start-dashboard", "Start web dashboard server") do
|
294
|
+
@options[:start_dashboard] = true
|
295
|
+
end
|
296
|
+
|
297
|
+
opts.on("--dashboard-port PORT", Integer, "Dashboard port (default: 4567)") do |port|
|
298
|
+
@options[:dashboard_port] = port
|
299
|
+
end
|
300
|
+
|
139
301
|
opts.on("-h", "--help", "Show this help message") do
|
140
302
|
puts opts
|
141
303
|
exit
|
@@ -149,7 +311,7 @@ class AiRootShieldCLI
|
|
149
311
|
end
|
150
312
|
|
151
313
|
def output_result(result)
|
152
|
-
case @options[:
|
314
|
+
case @options[:format]
|
153
315
|
when "json"
|
154
316
|
puts JSON.pretty_generate(result)
|
155
317
|
when "text"
|
@@ -167,6 +329,42 @@ class AiRootShieldCLI
|
|
167
329
|
puts "Version: #{result[:version]}"
|
168
330
|
puts ""
|
169
331
|
|
332
|
+
# Display compliance status if available
|
333
|
+
if result[:compliance]
|
334
|
+
puts "Policy Compliance:"
|
335
|
+
puts " Status: #{result[:compliance][:compliant] ? 'COMPLIANT' : 'NON-COMPLIANT'}"
|
336
|
+
puts " Policy Version: #{result[:compliance][:policy_version]}"
|
337
|
+
|
338
|
+
if result[:compliance][:violations].any?
|
339
|
+
puts " Violations:"
|
340
|
+
result[:compliance][:violations].each do |violation|
|
341
|
+
puts " • #{violation[:message]} (#{violation[:severity]})"
|
342
|
+
end
|
343
|
+
end
|
344
|
+
puts ""
|
345
|
+
end
|
346
|
+
|
347
|
+
# Display network analysis if available
|
348
|
+
if result[:network_analysis]
|
349
|
+
puts "Network Security Analysis:"
|
350
|
+
|
351
|
+
if result[:network_analysis][:proxy_detection]
|
352
|
+
proxy = result[:network_analysis][:proxy_detection]
|
353
|
+
puts " Proxy Detection: #{proxy[:proxy_detected] ? 'DETECTED' : 'Clean'}"
|
354
|
+
if proxy[:proxy_detected]
|
355
|
+
puts " Types: #{proxy[:proxy_types].join(', ')}"
|
356
|
+
puts " Confidence: #{(proxy[:confidence_score] * 100).round}%"
|
357
|
+
end
|
358
|
+
end
|
359
|
+
|
360
|
+
if result[:network_analysis][:certificate_pinning]
|
361
|
+
pinning = result[:network_analysis][:certificate_pinning]
|
362
|
+
puts " Certificate Pinning: #{pinning[:valid] ? 'VALID' : 'FAILED'}"
|
363
|
+
puts " Reason: #{pinning[:reason]}" unless pinning[:valid]
|
364
|
+
end
|
365
|
+
puts ""
|
366
|
+
end
|
367
|
+
|
170
368
|
if result[:factors].any?
|
171
369
|
puts "Detected Security Factors:"
|
172
370
|
result[:factors].each do |factor|
|
@@ -184,17 +382,125 @@ class AiRootShieldCLI
|
|
184
382
|
else
|
185
383
|
puts "No security threats detected."
|
186
384
|
end
|
385
|
+
|
386
|
+
# Display RASP status if available
|
387
|
+
if result[:rasp_status]
|
388
|
+
puts ""
|
389
|
+
puts "RASP Protection Status:"
|
390
|
+
puts " Active: #{result[:rasp_status][:active] ? 'YES' : 'NO'}"
|
391
|
+
puts " Events Detected: #{result[:rasp_status][:events_detected] || 0}"
|
392
|
+
puts " Protection Level: #{result[:rasp_status][:protection_level] || 'Standard'}"
|
393
|
+
end
|
187
394
|
end
|
188
395
|
|
189
396
|
def output_summary_format(result)
|
190
|
-
|
397
|
+
# Handle unified report format
|
398
|
+
if result[:executive_summary]
|
399
|
+
risk_level = result[:executive_summary][:overall_risk_level]
|
400
|
+
security_score = result[:executive_summary][:security_posture_score]
|
401
|
+
threat_count = result[:executive_summary][:critical_findings]&.length || 0
|
402
|
+
|
403
|
+
puts "Risk Level: #{risk_level} (Security Score: #{security_score}/100)"
|
404
|
+
puts "Threats: #{threat_count} critical findings detected"
|
405
|
+
|
406
|
+
if result[:executive_summary][:key_recommendations]&.any?
|
407
|
+
puts "Primary Concerns: #{result[:executive_summary][:key_recommendations].first(3).join(', ')}"
|
408
|
+
end
|
409
|
+
else
|
410
|
+
# Handle regular analysis format
|
411
|
+
risk_level = AiRootShield::RiskCalculator.risk_level_description(result[:risk_score])
|
412
|
+
|
413
|
+
puts "Risk Level: #{risk_level} (#{result[:risk_score]}/100)"
|
414
|
+
puts "Threats: #{result[:factors]&.length || 0} detected"
|
415
|
+
|
416
|
+
if result[:factors]&.any?
|
417
|
+
puts "Primary Concerns: #{result[:factors].first(3).join(', ')}"
|
418
|
+
end
|
419
|
+
end
|
420
|
+
end
|
421
|
+
|
422
|
+
# v0.5.0 New Methods
|
423
|
+
def run_platform_specific_analysis(device_logs_path)
|
424
|
+
puts "Running #{@options[:platform]} platform-specific analysis..." if @options[:verbose]
|
191
425
|
|
192
|
-
|
193
|
-
|
426
|
+
case @options[:platform]
|
427
|
+
when 'android'
|
428
|
+
config = {}
|
429
|
+
config[:safetynet_api_key] = @options[:safetynet_api_key] if @options[:safetynet_api_key]
|
430
|
+
config[:package_name] = @options[:package_name] if @options[:package_name]
|
431
|
+
|
432
|
+
result = AiRootShield.analyze_android_device(device_logs_path, config)
|
433
|
+
when 'ios'
|
434
|
+
result = AiRootShield.analyze_ios_device(device_logs_path)
|
435
|
+
else
|
436
|
+
raise "Unsupported platform: #{@options[:platform]}"
|
437
|
+
end
|
194
438
|
|
195
|
-
if
|
196
|
-
puts "
|
439
|
+
if @options[:enable_unified_reporting]
|
440
|
+
puts "Generating unified cross-platform report..." if @options[:verbose]
|
441
|
+
case @options[:platform]
|
442
|
+
when 'android'
|
443
|
+
unified_result = AiRootShield.generate_unified_report(android_results: result)
|
444
|
+
when 'ios'
|
445
|
+
unified_result = AiRootShield.generate_unified_report(ios_results: result)
|
446
|
+
end
|
447
|
+
return unified_result
|
197
448
|
end
|
449
|
+
|
450
|
+
result
|
451
|
+
end
|
452
|
+
|
453
|
+
def run_ci_cd_analysis(device_logs_path)
|
454
|
+
puts "Running CI/CD security analysis..." if @options[:verbose]
|
455
|
+
|
456
|
+
# Create artifacts directory
|
457
|
+
Dir.mkdir(@options[:artifacts_path]) unless Dir.exist?(@options[:artifacts_path])
|
458
|
+
|
459
|
+
# Run CI/CD tests
|
460
|
+
result = AiRootShield.run_ci_cd_tests(device_logs_path, {
|
461
|
+
artifacts_path: @options[:artifacts_path],
|
462
|
+
verbose: @options[:verbose]
|
463
|
+
})
|
464
|
+
|
465
|
+
puts "CI/CD test artifacts saved to: #{@options[:artifacts_path]}" if @options[:verbose]
|
466
|
+
result
|
467
|
+
end
|
468
|
+
|
469
|
+
def start_dashboard
|
470
|
+
puts "Starting AI Root Shield Dashboard on port #{@options[:dashboard_port]}..."
|
471
|
+
puts "Dashboard will be available at: http://localhost:#{@options[:dashboard_port]}"
|
472
|
+
puts "Press Ctrl+C to stop the dashboard"
|
473
|
+
|
474
|
+
begin
|
475
|
+
AiRootShield.start_dashboard(@options[:dashboard_port])
|
476
|
+
rescue Interrupt
|
477
|
+
puts "\nDashboard stopped."
|
478
|
+
end
|
479
|
+
end
|
480
|
+
|
481
|
+
def generate_ci_config
|
482
|
+
puts "Generating CI/CD configuration for #{@options[:generate_ci_config]}..."
|
483
|
+
|
484
|
+
config_content = AiRootShield.generate_ci_config(@options[:generate_ci_config].to_sym)
|
485
|
+
|
486
|
+
filename = case @options[:generate_ci_config]
|
487
|
+
when 'github'
|
488
|
+
'.github/workflows/security-scan.yml'
|
489
|
+
when 'gitlab'
|
490
|
+
'.gitlab-ci.yml'
|
491
|
+
when 'jenkins'
|
492
|
+
'Jenkinsfile'
|
493
|
+
when 'azure'
|
494
|
+
'azure-pipelines.yml'
|
495
|
+
end
|
496
|
+
|
497
|
+
# Create directory if needed
|
498
|
+
dir = File.dirname(filename)
|
499
|
+
FileUtils.mkdir_p(dir) unless Dir.exist?(dir) || dir == '.'
|
500
|
+
|
501
|
+
File.write(filename, config_content)
|
502
|
+
puts "CI/CD configuration saved to: #{filename}"
|
503
|
+
puts "Please review and customize the configuration as needed."
|
198
504
|
end
|
199
505
|
end
|
200
506
|
|