ai_root_shield 0.4.0 → 1.0.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 +52 -4
- data/README.md +191 -14
- data/bindings/python/README.md +304 -0
- data/bindings/python/ai_root_shield.py +438 -0
- data/bindings/python/setup.py +65 -0
- data/examples/device_logs/android_safetynet_device.json +148 -0
- data/examples/device_logs/ios_jailbroken_device.json +172 -0
- data/exe/ai_root_shield +220 -7
- data/lib/ai_root_shield/ci_cd/security_test_module.rb +743 -0
- data/lib/ai_root_shield/dashboard/web_dashboard.rb +441 -0
- data/lib/ai_root_shield/enterprise/alert_system.rb +601 -0
- data/lib/ai_root_shield/enterprise/hybrid_detection_engine.rb +650 -0
- data/lib/ai_root_shield/enterprise/performance_optimizer.rb +613 -0
- data/lib/ai_root_shield/enterprise/policy_manager.rb +637 -0
- data/lib/ai_root_shield/integrations/siem_connector.rb +695 -0
- data/lib/ai_root_shield/platform/android_security_module.rb +263 -0
- data/lib/ai_root_shield/platform/hardware_security_analyzer.rb +452 -0
- data/lib/ai_root_shield/platform/ios_security_module.rb +513 -0
- data/lib/ai_root_shield/platform/unified_report_generator.rb +613 -0
- data/lib/ai_root_shield/version.rb +1 -1
- data/lib/ai_root_shield.rb +152 -1
- data/security_test_artifacts/security_report.json +124 -0
- data/security_test_artifacts/security_results.sarif +16 -0
- data/security_test_artifacts/security_tests.xml +3 -0
- metadata +20 -1
@@ -0,0 +1,743 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'yaml'
|
5
|
+
require 'fileutils'
|
6
|
+
|
7
|
+
module AiRootShield
|
8
|
+
module CiCd
|
9
|
+
# CI/CD integration security testing module
|
10
|
+
class SecurityTestModule
|
11
|
+
# Supported CI/CD platforms
|
12
|
+
SUPPORTED_PLATFORMS = %w[
|
13
|
+
github_actions
|
14
|
+
gitlab_ci
|
15
|
+
jenkins
|
16
|
+
azure_devops
|
17
|
+
circleci
|
18
|
+
travis_ci
|
19
|
+
bitbucket_pipelines
|
20
|
+
].freeze
|
21
|
+
|
22
|
+
# Test result statuses
|
23
|
+
TEST_STATUSES = {
|
24
|
+
passed: 'PASSED',
|
25
|
+
failed: 'FAILED',
|
26
|
+
warning: 'WARNING',
|
27
|
+
skipped: 'SKIPPED',
|
28
|
+
error: 'ERROR'
|
29
|
+
}.freeze
|
30
|
+
|
31
|
+
def initialize(config = {})
|
32
|
+
@config = config
|
33
|
+
@test_results = []
|
34
|
+
@artifacts_path = config[:artifacts_path] || './security_test_artifacts'
|
35
|
+
@report_format = config[:report_format] || 'json'
|
36
|
+
@fail_on_high_risk = config[:fail_on_high_risk] || true
|
37
|
+
@risk_threshold = config[:risk_threshold] || 70
|
38
|
+
end
|
39
|
+
|
40
|
+
# Run comprehensive security tests for CI/CD pipeline
|
41
|
+
def run_security_tests(device_logs_path, options = {})
|
42
|
+
setup_test_environment
|
43
|
+
|
44
|
+
test_suite = {
|
45
|
+
metadata: generate_test_metadata(options),
|
46
|
+
test_results: [],
|
47
|
+
summary: {},
|
48
|
+
artifacts: []
|
49
|
+
}
|
50
|
+
|
51
|
+
begin
|
52
|
+
# Load device logs
|
53
|
+
device_logs = load_device_logs(device_logs_path)
|
54
|
+
|
55
|
+
# Run platform-specific tests
|
56
|
+
if device_logs['platform'] == 'android'
|
57
|
+
test_suite[:test_results] << run_android_security_tests(device_logs)
|
58
|
+
elsif device_logs['platform'] == 'ios'
|
59
|
+
test_suite[:test_results] << run_ios_security_tests(device_logs)
|
60
|
+
else
|
61
|
+
test_suite[:test_results] << run_generic_security_tests(device_logs)
|
62
|
+
end
|
63
|
+
|
64
|
+
# Run cross-platform tests
|
65
|
+
test_suite[:test_results] << run_cross_platform_tests(device_logs)
|
66
|
+
|
67
|
+
# Generate test summary
|
68
|
+
test_suite[:summary] = generate_test_summary(test_suite[:test_results])
|
69
|
+
|
70
|
+
# Generate artifacts
|
71
|
+
test_suite[:artifacts] = generate_test_artifacts(test_suite)
|
72
|
+
|
73
|
+
# Determine pipeline result
|
74
|
+
pipeline_result = determine_pipeline_result(test_suite[:summary])
|
75
|
+
test_suite[:pipeline_result] = pipeline_result
|
76
|
+
|
77
|
+
# Export results
|
78
|
+
export_test_results(test_suite)
|
79
|
+
|
80
|
+
test_suite
|
81
|
+
|
82
|
+
rescue StandardError => e
|
83
|
+
handle_test_error(e, test_suite)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# Generate CI/CD configuration for specific platform
|
88
|
+
def generate_ci_config(platform, options = {})
|
89
|
+
case platform.to_s.downcase
|
90
|
+
when 'github', 'github_actions'
|
91
|
+
generate_github_actions_config(options)
|
92
|
+
when 'gitlab', 'gitlab_ci'
|
93
|
+
generate_gitlab_ci_config(options)
|
94
|
+
when 'jenkins'
|
95
|
+
generate_jenkins_config(options)
|
96
|
+
when 'azure', 'azure_devops'
|
97
|
+
generate_azure_devops_config(options)
|
98
|
+
when 'circleci'
|
99
|
+
generate_circleci_config(options)
|
100
|
+
else
|
101
|
+
raise "Unsupported CI/CD platform: #{platform}"
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
private
|
106
|
+
|
107
|
+
# Setup test environment
|
108
|
+
def setup_test_environment
|
109
|
+
FileUtils.mkdir_p(@artifacts_path) unless Dir.exist?(@artifacts_path)
|
110
|
+
@test_start_time = Time.now
|
111
|
+
end
|
112
|
+
|
113
|
+
# Load and validate device logs
|
114
|
+
def load_device_logs(device_logs_path)
|
115
|
+
unless File.exist?(device_logs_path)
|
116
|
+
raise "Device logs file not found: #{device_logs_path}"
|
117
|
+
end
|
118
|
+
|
119
|
+
content = File.read(device_logs_path)
|
120
|
+
JSON.parse(content)
|
121
|
+
rescue JSON::ParserError => e
|
122
|
+
raise "Invalid JSON in device logs: #{e.message}"
|
123
|
+
end
|
124
|
+
|
125
|
+
# Run Android-specific security tests
|
126
|
+
def run_android_security_tests(device_logs)
|
127
|
+
android_module = AiRootShield::Platform::AndroidSecurityModule.new
|
128
|
+
results = android_module.analyze_device_security(device_logs)
|
129
|
+
|
130
|
+
{
|
131
|
+
test_name: 'Android Security Analysis',
|
132
|
+
platform: 'android',
|
133
|
+
status: determine_test_status(results[:risk_score]),
|
134
|
+
risk_score: results[:risk_score],
|
135
|
+
risk_factors: results[:risk_factors],
|
136
|
+
details: {
|
137
|
+
safetynet: format_safetynet_test_results(results[:safetynet]),
|
138
|
+
play_integrity: format_play_integrity_test_results(results[:play_integrity]),
|
139
|
+
hardware_security: format_hardware_test_results(results[:hardware_security]),
|
140
|
+
system_integrity: format_system_integrity_test_results(results[:system_integrity])
|
141
|
+
},
|
142
|
+
recommendations: generate_android_test_recommendations(results),
|
143
|
+
execution_time: calculate_execution_time
|
144
|
+
}
|
145
|
+
end
|
146
|
+
|
147
|
+
# Run iOS-specific security tests
|
148
|
+
def run_ios_security_tests(device_logs)
|
149
|
+
ios_module = AiRootShield::Platform::IosSecurityModule.new
|
150
|
+
results = ios_module.analyze_device_security(device_logs)
|
151
|
+
|
152
|
+
{
|
153
|
+
test_name: 'iOS Security Analysis',
|
154
|
+
platform: 'ios',
|
155
|
+
status: determine_test_status(results[:risk_score]),
|
156
|
+
risk_score: results[:risk_score],
|
157
|
+
risk_factors: results[:risk_factors],
|
158
|
+
details: {
|
159
|
+
jailbreak_detection: format_jailbreak_test_results(results[:jailbreak_detection]),
|
160
|
+
code_signing: format_code_signing_test_results(results[:code_signing]),
|
161
|
+
sandbox_integrity: format_sandbox_test_results(results[:sandbox_integrity]),
|
162
|
+
dyld_injection: format_dyld_test_results(results[:dyld_injection]),
|
163
|
+
hardware_security: format_hardware_test_results(results[:hardware_security]),
|
164
|
+
system_integrity: format_system_integrity_test_results(results[:system_integrity])
|
165
|
+
},
|
166
|
+
recommendations: generate_ios_test_recommendations(results),
|
167
|
+
execution_time: calculate_execution_time
|
168
|
+
}
|
169
|
+
end
|
170
|
+
|
171
|
+
# Run generic security tests
|
172
|
+
def run_generic_security_tests(device_logs)
|
173
|
+
# Basic security analysis for unknown platforms
|
174
|
+
risk_factors = []
|
175
|
+
risk_score = 0
|
176
|
+
|
177
|
+
# Check for basic compromise indicators
|
178
|
+
if device_logs.dig('root_indicators')&.any?
|
179
|
+
risk_factors << 'ROOT_INDICATORS_DETECTED'
|
180
|
+
risk_score += 30
|
181
|
+
end
|
182
|
+
|
183
|
+
if device_logs.dig('debug_enabled')
|
184
|
+
risk_factors << 'DEBUG_MODE_ENABLED'
|
185
|
+
risk_score += 15
|
186
|
+
end
|
187
|
+
|
188
|
+
{
|
189
|
+
test_name: 'Generic Security Analysis',
|
190
|
+
platform: 'generic',
|
191
|
+
status: determine_test_status(risk_score),
|
192
|
+
risk_score: risk_score,
|
193
|
+
risk_factors: risk_factors,
|
194
|
+
details: {
|
195
|
+
basic_checks: {
|
196
|
+
root_indicators: device_logs.dig('root_indicators') || [],
|
197
|
+
debug_enabled: device_logs.dig('debug_enabled') || false,
|
198
|
+
developer_options: device_logs.dig('developer_options') || false
|
199
|
+
}
|
200
|
+
},
|
201
|
+
recommendations: generate_generic_test_recommendations(risk_factors),
|
202
|
+
execution_time: calculate_execution_time
|
203
|
+
}
|
204
|
+
end
|
205
|
+
|
206
|
+
# Run cross-platform security tests
|
207
|
+
def run_cross_platform_tests(device_logs)
|
208
|
+
cross_platform_risks = []
|
209
|
+
risk_score = 0
|
210
|
+
|
211
|
+
# Network security checks
|
212
|
+
if device_logs.dig('network', 'proxy_enabled')
|
213
|
+
cross_platform_risks << 'PROXY_DETECTED'
|
214
|
+
risk_score += 10
|
215
|
+
end
|
216
|
+
|
217
|
+
if device_logs.dig('network', 'vpn_active')
|
218
|
+
cross_platform_risks << 'VPN_ACTIVE'
|
219
|
+
risk_score += 5
|
220
|
+
end
|
221
|
+
|
222
|
+
# Certificate checks
|
223
|
+
custom_cas = device_logs.dig('network', 'custom_certificates') || []
|
224
|
+
if custom_cas.any?
|
225
|
+
cross_platform_risks << 'CUSTOM_CA_CERTIFICATES'
|
226
|
+
risk_score += 15
|
227
|
+
end
|
228
|
+
|
229
|
+
{
|
230
|
+
test_name: 'Cross-Platform Security Analysis',
|
231
|
+
platform: 'cross_platform',
|
232
|
+
status: determine_test_status(risk_score),
|
233
|
+
risk_score: risk_score,
|
234
|
+
risk_factors: cross_platform_risks,
|
235
|
+
details: {
|
236
|
+
network_security: {
|
237
|
+
proxy_enabled: device_logs.dig('network', 'proxy_enabled') || false,
|
238
|
+
vpn_active: device_logs.dig('network', 'vpn_active') || false,
|
239
|
+
custom_certificates: custom_cas.size,
|
240
|
+
tls_version: device_logs.dig('network', 'tls_version')
|
241
|
+
}
|
242
|
+
},
|
243
|
+
recommendations: generate_cross_platform_recommendations(cross_platform_risks),
|
244
|
+
execution_time: calculate_execution_time
|
245
|
+
}
|
246
|
+
end
|
247
|
+
|
248
|
+
# Generate test metadata
|
249
|
+
def generate_test_metadata(options)
|
250
|
+
{
|
251
|
+
test_suite_version: '1.0',
|
252
|
+
ai_root_shield_version: AiRootShield::VERSION,
|
253
|
+
execution_timestamp: @test_start_time.utc.iso8601,
|
254
|
+
ci_environment: detect_ci_environment,
|
255
|
+
test_configuration: @config,
|
256
|
+
git_information: extract_git_information,
|
257
|
+
build_information: options[:build_info] || {}
|
258
|
+
}
|
259
|
+
end
|
260
|
+
|
261
|
+
# Determine test status based on risk score
|
262
|
+
def determine_test_status(risk_score)
|
263
|
+
case risk_score
|
264
|
+
when 0..20
|
265
|
+
TEST_STATUSES[:passed]
|
266
|
+
when 21..40
|
267
|
+
TEST_STATUSES[:warning]
|
268
|
+
when 41..70
|
269
|
+
TEST_STATUSES[:failed]
|
270
|
+
else
|
271
|
+
TEST_STATUSES[:failed]
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
# Generate test summary
|
276
|
+
def generate_test_summary(test_results)
|
277
|
+
total_tests = test_results.size
|
278
|
+
passed_tests = test_results.count { |t| t[:status] == TEST_STATUSES[:passed] }
|
279
|
+
failed_tests = test_results.count { |t| t[:status] == TEST_STATUSES[:failed] }
|
280
|
+
warning_tests = test_results.count { |t| t[:status] == TEST_STATUSES[:warning] }
|
281
|
+
|
282
|
+
max_risk_score = test_results.map { |t| t[:risk_score] }.max || 0
|
283
|
+
all_risk_factors = test_results.flat_map { |t| t[:risk_factors] }.uniq
|
284
|
+
|
285
|
+
{
|
286
|
+
total_tests: total_tests,
|
287
|
+
passed: passed_tests,
|
288
|
+
failed: failed_tests,
|
289
|
+
warnings: warning_tests,
|
290
|
+
success_rate: (passed_tests.to_f / total_tests * 100).round(2),
|
291
|
+
max_risk_score: max_risk_score,
|
292
|
+
overall_status: determine_overall_status(max_risk_score),
|
293
|
+
total_risk_factors: all_risk_factors.size,
|
294
|
+
critical_risk_factors: all_risk_factors.select { |f| f.include?('CRITICAL') },
|
295
|
+
execution_time: Time.now - @test_start_time
|
296
|
+
}
|
297
|
+
end
|
298
|
+
|
299
|
+
# Determine pipeline result
|
300
|
+
def determine_pipeline_result(summary)
|
301
|
+
if @fail_on_high_risk && summary[:max_risk_score] >= @risk_threshold
|
302
|
+
{
|
303
|
+
result: 'FAILED',
|
304
|
+
reason: "Risk score #{summary[:max_risk_score]} exceeds threshold #{@risk_threshold}",
|
305
|
+
exit_code: 1
|
306
|
+
}
|
307
|
+
elsif summary[:failed] > 0
|
308
|
+
{
|
309
|
+
result: 'FAILED',
|
310
|
+
reason: "#{summary[:failed]} security tests failed",
|
311
|
+
exit_code: 1
|
312
|
+
}
|
313
|
+
elsif summary[:warnings] > 0
|
314
|
+
{
|
315
|
+
result: 'WARNING',
|
316
|
+
reason: "#{summary[:warnings]} security warnings detected",
|
317
|
+
exit_code: 0
|
318
|
+
}
|
319
|
+
else
|
320
|
+
{
|
321
|
+
result: 'PASSED',
|
322
|
+
reason: 'All security tests passed',
|
323
|
+
exit_code: 0
|
324
|
+
}
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
# Generate test artifacts
|
329
|
+
def generate_test_artifacts(test_suite)
|
330
|
+
artifacts = []
|
331
|
+
|
332
|
+
# Generate detailed report
|
333
|
+
report_file = File.join(@artifacts_path, "security_report.#{@report_format}")
|
334
|
+
File.write(report_file, format_report(test_suite))
|
335
|
+
artifacts << { type: 'report', path: report_file, format: @report_format }
|
336
|
+
|
337
|
+
# Generate SARIF report for security tools integration
|
338
|
+
sarif_file = File.join(@artifacts_path, 'security_results.sarif')
|
339
|
+
File.write(sarif_file, generate_sarif_report(test_suite))
|
340
|
+
artifacts << { type: 'sarif', path: sarif_file, format: 'sarif' }
|
341
|
+
|
342
|
+
# Generate JUnit XML for CI integration
|
343
|
+
junit_file = File.join(@artifacts_path, 'security_tests.xml')
|
344
|
+
File.write(junit_file, generate_junit_xml(test_suite))
|
345
|
+
artifacts << { type: 'junit', path: junit_file, format: 'xml' }
|
346
|
+
|
347
|
+
artifacts
|
348
|
+
end
|
349
|
+
|
350
|
+
# Export test results
|
351
|
+
def export_test_results(test_suite)
|
352
|
+
# Set environment variables for CI/CD consumption
|
353
|
+
ENV['ARS_RISK_SCORE'] = test_suite[:summary][:max_risk_score].to_s
|
354
|
+
ENV['ARS_TEST_STATUS'] = test_suite[:pipeline_result][:result]
|
355
|
+
ENV['ARS_CRITICAL_FACTORS'] = test_suite[:summary][:critical_risk_factors].join(',')
|
356
|
+
|
357
|
+
# Output summary to console
|
358
|
+
puts generate_console_output(test_suite)
|
359
|
+
|
360
|
+
# Exit with appropriate code if configured
|
361
|
+
if @config[:exit_on_completion]
|
362
|
+
exit(test_suite[:pipeline_result][:exit_code])
|
363
|
+
end
|
364
|
+
end
|
365
|
+
|
366
|
+
# Handle test errors
|
367
|
+
def handle_test_error(error, test_suite)
|
368
|
+
error_details = {
|
369
|
+
test_name: 'Security Test Suite',
|
370
|
+
status: TEST_STATUSES[:error],
|
371
|
+
error_message: error.message,
|
372
|
+
error_backtrace: error.backtrace&.first(10),
|
373
|
+
execution_time: Time.now - @test_start_time
|
374
|
+
}
|
375
|
+
|
376
|
+
test_suite[:test_results] << error_details
|
377
|
+
test_suite[:pipeline_result] = {
|
378
|
+
result: 'ERROR',
|
379
|
+
reason: "Test execution failed: #{error.message}",
|
380
|
+
exit_code: 2
|
381
|
+
}
|
382
|
+
|
383
|
+
export_test_results(test_suite)
|
384
|
+
test_suite
|
385
|
+
end
|
386
|
+
|
387
|
+
# CI/CD configuration generators
|
388
|
+
|
389
|
+
def generate_github_actions_config(options)
|
390
|
+
config = {
|
391
|
+
'name' => 'AI Root Shield Security Tests',
|
392
|
+
'on' => {
|
393
|
+
'push' => { 'branches' => ['main', 'develop'] },
|
394
|
+
'pull_request' => { 'branches' => ['main'] }
|
395
|
+
},
|
396
|
+
'jobs' => {
|
397
|
+
'security-tests' => {
|
398
|
+
'runs-on' => 'ubuntu-latest',
|
399
|
+
'steps' => [
|
400
|
+
{
|
401
|
+
'name' => 'Checkout code',
|
402
|
+
'uses' => 'actions/checkout@v3'
|
403
|
+
},
|
404
|
+
{
|
405
|
+
'name' => 'Setup Ruby',
|
406
|
+
'uses' => 'ruby/setup-ruby@v1',
|
407
|
+
'with' => { 'ruby-version' => '3.0' }
|
408
|
+
},
|
409
|
+
{
|
410
|
+
'name' => 'Install AI Root Shield',
|
411
|
+
'run' => 'gem install ai_root_shield'
|
412
|
+
},
|
413
|
+
{
|
414
|
+
'name' => 'Run Security Tests',
|
415
|
+
'run' => 'ai_root_shield --ci-mode --format json device_logs.json'
|
416
|
+
},
|
417
|
+
{
|
418
|
+
'name' => 'Upload Security Reports',
|
419
|
+
'uses' => 'actions/upload-artifact@v3',
|
420
|
+
'if' => 'always()',
|
421
|
+
'with' => {
|
422
|
+
'name' => 'security-reports',
|
423
|
+
'path' => 'security_test_artifacts/'
|
424
|
+
}
|
425
|
+
}
|
426
|
+
]
|
427
|
+
}
|
428
|
+
}
|
429
|
+
}
|
430
|
+
|
431
|
+
YAML.dump(config)
|
432
|
+
end
|
433
|
+
|
434
|
+
def generate_gitlab_ci_config(options)
|
435
|
+
config = {
|
436
|
+
'stages' => ['security'],
|
437
|
+
'security_tests' => {
|
438
|
+
'stage' => 'security',
|
439
|
+
'image' => 'ruby:3.0',
|
440
|
+
'before_script' => [
|
441
|
+
'gem install ai_root_shield'
|
442
|
+
],
|
443
|
+
'script' => [
|
444
|
+
'ai_root_shield --ci-mode --format json device_logs.json'
|
445
|
+
],
|
446
|
+
'artifacts' => {
|
447
|
+
'reports' => {
|
448
|
+
'junit' => 'security_test_artifacts/security_tests.xml'
|
449
|
+
},
|
450
|
+
'paths' => ['security_test_artifacts/'],
|
451
|
+
'when' => 'always'
|
452
|
+
},
|
453
|
+
'allow_failure' => false
|
454
|
+
}
|
455
|
+
}
|
456
|
+
|
457
|
+
YAML.dump(config)
|
458
|
+
end
|
459
|
+
|
460
|
+
def generate_jenkins_config(options)
|
461
|
+
# Jenkins pipeline configuration
|
462
|
+
pipeline_script = <<~PIPELINE
|
463
|
+
pipeline {
|
464
|
+
agent any
|
465
|
+
|
466
|
+
stages {
|
467
|
+
stage('Security Tests') {
|
468
|
+
steps {
|
469
|
+
script {
|
470
|
+
sh 'gem install ai_root_shield'
|
471
|
+
sh 'ai_root_shield --ci-mode --format json device_logs.json'
|
472
|
+
}
|
473
|
+
}
|
474
|
+
post {
|
475
|
+
always {
|
476
|
+
archiveArtifacts artifacts: 'security_test_artifacts/**/*', allowEmptyArchive: true
|
477
|
+
publishTestResults testResultsPattern: 'security_test_artifacts/security_tests.xml'
|
478
|
+
}
|
479
|
+
}
|
480
|
+
}
|
481
|
+
}
|
482
|
+
}
|
483
|
+
PIPELINE
|
484
|
+
|
485
|
+
pipeline_script
|
486
|
+
end
|
487
|
+
|
488
|
+
def generate_azure_devops_config(options)
|
489
|
+
config = {
|
490
|
+
'trigger' => ['main'],
|
491
|
+
'pool' => { 'vmImage' => 'ubuntu-latest' },
|
492
|
+
'steps' => [
|
493
|
+
{
|
494
|
+
'task' => 'UseRubyVersion@0',
|
495
|
+
'inputs' => { 'versionSpec' => '3.0' }
|
496
|
+
},
|
497
|
+
{
|
498
|
+
'script' => 'gem install ai_root_shield',
|
499
|
+
'displayName' => 'Install AI Root Shield'
|
500
|
+
},
|
501
|
+
{
|
502
|
+
'script' => 'ai_root_shield --ci-mode --format json device_logs.json',
|
503
|
+
'displayName' => 'Run Security Tests'
|
504
|
+
},
|
505
|
+
{
|
506
|
+
'task' => 'PublishTestResults@2',
|
507
|
+
'inputs' => {
|
508
|
+
'testResultsFormat' => 'JUnit',
|
509
|
+
'testResultsFiles' => 'security_test_artifacts/security_tests.xml'
|
510
|
+
}
|
511
|
+
}
|
512
|
+
]
|
513
|
+
}
|
514
|
+
|
515
|
+
YAML.dump(config)
|
516
|
+
end
|
517
|
+
|
518
|
+
def generate_circleci_config(options)
|
519
|
+
config = {
|
520
|
+
'version' => 2.1,
|
521
|
+
'jobs' => {
|
522
|
+
'security-tests' => {
|
523
|
+
'docker' => [{ 'image' => 'cimg/ruby:3.0' }],
|
524
|
+
'steps' => [
|
525
|
+
'checkout',
|
526
|
+
{
|
527
|
+
'run' => {
|
528
|
+
'name' => 'Install AI Root Shield',
|
529
|
+
'command' => 'gem install ai_root_shield'
|
530
|
+
}
|
531
|
+
},
|
532
|
+
{
|
533
|
+
'run' => {
|
534
|
+
'name' => 'Run Security Tests',
|
535
|
+
'command' => 'ai_root_shield --ci-mode --format json device_logs.json'
|
536
|
+
}
|
537
|
+
},
|
538
|
+
{
|
539
|
+
'store_artifacts' => {
|
540
|
+
'path' => 'security_test_artifacts',
|
541
|
+
'destination' => 'security-reports'
|
542
|
+
}
|
543
|
+
}
|
544
|
+
]
|
545
|
+
}
|
546
|
+
},
|
547
|
+
'workflows' => {
|
548
|
+
'security-workflow' => {
|
549
|
+
'jobs' => ['security-tests']
|
550
|
+
}
|
551
|
+
}
|
552
|
+
}
|
553
|
+
|
554
|
+
YAML.dump(config)
|
555
|
+
end
|
556
|
+
|
557
|
+
# Utility methods
|
558
|
+
|
559
|
+
def calculate_execution_time
|
560
|
+
Time.now - @test_start_time
|
561
|
+
end
|
562
|
+
|
563
|
+
def determine_overall_status(max_risk_score)
|
564
|
+
case max_risk_score
|
565
|
+
when 0..20
|
566
|
+
'SECURE'
|
567
|
+
when 21..40
|
568
|
+
'MODERATE_RISK'
|
569
|
+
when 41..70
|
570
|
+
'HIGH_RISK'
|
571
|
+
else
|
572
|
+
'CRITICAL_RISK'
|
573
|
+
end
|
574
|
+
end
|
575
|
+
|
576
|
+
def detect_ci_environment
|
577
|
+
ci_indicators = {
|
578
|
+
'GITHUB_ACTIONS' => 'GitHub Actions',
|
579
|
+
'GITLAB_CI' => 'GitLab CI',
|
580
|
+
'JENKINS_URL' => 'Jenkins',
|
581
|
+
'AZURE_HTTP_USER_AGENT' => 'Azure DevOps',
|
582
|
+
'CIRCLECI' => 'CircleCI',
|
583
|
+
'TRAVIS' => 'Travis CI'
|
584
|
+
}
|
585
|
+
|
586
|
+
ci_indicators.each do |env_var, platform|
|
587
|
+
return platform if ENV[env_var]
|
588
|
+
end
|
589
|
+
|
590
|
+
'Unknown'
|
591
|
+
end
|
592
|
+
|
593
|
+
def extract_git_information
|
594
|
+
git_info = {}
|
595
|
+
|
596
|
+
begin
|
597
|
+
git_info[:commit_sha] = `git rev-parse HEAD`.strip
|
598
|
+
git_info[:branch] = `git rev-parse --abbrev-ref HEAD`.strip
|
599
|
+
git_info[:commit_message] = `git log -1 --pretty=%B`.strip
|
600
|
+
git_info[:author] = `git log -1 --pretty=%an`.strip
|
601
|
+
rescue StandardError
|
602
|
+
git_info[:error] = 'Git information not available'
|
603
|
+
end
|
604
|
+
|
605
|
+
git_info
|
606
|
+
end
|
607
|
+
|
608
|
+
def format_report(test_suite)
|
609
|
+
case @report_format
|
610
|
+
when 'json'
|
611
|
+
JSON.pretty_generate(test_suite)
|
612
|
+
when 'yaml'
|
613
|
+
YAML.dump(test_suite)
|
614
|
+
else
|
615
|
+
JSON.pretty_generate(test_suite)
|
616
|
+
end
|
617
|
+
end
|
618
|
+
|
619
|
+
def generate_sarif_report(test_suite)
|
620
|
+
# Generate SARIF (Static Analysis Results Interchange Format) report
|
621
|
+
sarif = {
|
622
|
+
'$schema' => 'https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json',
|
623
|
+
'version' => '2.1.0',
|
624
|
+
'runs' => [
|
625
|
+
{
|
626
|
+
'tool' => {
|
627
|
+
'driver' => {
|
628
|
+
'name' => 'AI Root Shield',
|
629
|
+
'version' => AiRootShield::VERSION,
|
630
|
+
'informationUri' => 'https://github.com/ahmetxhero/ai-root-shield'
|
631
|
+
}
|
632
|
+
},
|
633
|
+
'results' => convert_to_sarif_results(test_suite[:test_results])
|
634
|
+
}
|
635
|
+
]
|
636
|
+
}
|
637
|
+
|
638
|
+
JSON.pretty_generate(sarif)
|
639
|
+
end
|
640
|
+
|
641
|
+
def generate_junit_xml(test_suite)
|
642
|
+
# Generate JUnit XML for CI/CD integration
|
643
|
+
xml = <<~XML
|
644
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
645
|
+
<testsuites name="AI Root Shield Security Tests" tests="#{test_suite[:summary][:total_tests]}" failures="#{test_suite[:summary][:failed]}" time="#{test_suite[:summary][:execution_time]}">
|
646
|
+
XML
|
647
|
+
|
648
|
+
test_suite[:test_results].each do |test|
|
649
|
+
xml += generate_junit_test_case(test)
|
650
|
+
end
|
651
|
+
|
652
|
+
xml += "</testsuites>\n"
|
653
|
+
xml
|
654
|
+
end
|
655
|
+
|
656
|
+
def generate_console_output(test_suite)
|
657
|
+
output = <<~OUTPUT
|
658
|
+
|
659
|
+
═══════════════════════════════════════════════════════════════
|
660
|
+
AI Root Shield Security Test Results
|
661
|
+
═══════════════════════════════════════════════════════════════
|
662
|
+
|
663
|
+
Overall Status: #{test_suite[:pipeline_result][:result]}
|
664
|
+
Max Risk Score: #{test_suite[:summary][:max_risk_score]}/100
|
665
|
+
Tests Run: #{test_suite[:summary][:total_tests]}
|
666
|
+
Passed: #{test_suite[:summary][:passed]}
|
667
|
+
Failed: #{test_suite[:summary][:failed]}
|
668
|
+
Warnings: #{test_suite[:summary][:warnings]}
|
669
|
+
|
670
|
+
Critical Risk Factors: #{test_suite[:summary][:critical_risk_factors].size}
|
671
|
+
#{test_suite[:summary][:critical_risk_factors].map { |f| " • #{f}" }.join("\n")}
|
672
|
+
|
673
|
+
Execution Time: #{test_suite[:summary][:execution_time].round(2)}s
|
674
|
+
|
675
|
+
Artifacts Generated:
|
676
|
+
#{test_suite[:artifacts].map { |a| " • #{a[:path]} (#{a[:format]})" }.join("\n")}
|
677
|
+
|
678
|
+
═══════════════════════════════════════════════════════════════
|
679
|
+
OUTPUT
|
680
|
+
|
681
|
+
output
|
682
|
+
end
|
683
|
+
|
684
|
+
# Placeholder methods for formatting test results
|
685
|
+
|
686
|
+
def format_safetynet_test_results(safetynet_data)
|
687
|
+
safetynet_data
|
688
|
+
end
|
689
|
+
|
690
|
+
def format_play_integrity_test_results(play_integrity_data)
|
691
|
+
play_integrity_data
|
692
|
+
end
|
693
|
+
|
694
|
+
def format_hardware_test_results(hardware_data)
|
695
|
+
hardware_data
|
696
|
+
end
|
697
|
+
|
698
|
+
def format_system_integrity_test_results(system_data)
|
699
|
+
system_data
|
700
|
+
end
|
701
|
+
|
702
|
+
def format_jailbreak_test_results(jailbreak_data)
|
703
|
+
jailbreak_data
|
704
|
+
end
|
705
|
+
|
706
|
+
def format_code_signing_test_results(code_signing_data)
|
707
|
+
code_signing_data
|
708
|
+
end
|
709
|
+
|
710
|
+
def format_sandbox_test_results(sandbox_data)
|
711
|
+
sandbox_data
|
712
|
+
end
|
713
|
+
|
714
|
+
def format_dyld_test_results(dyld_data)
|
715
|
+
dyld_data
|
716
|
+
end
|
717
|
+
|
718
|
+
def generate_android_test_recommendations(results)
|
719
|
+
[]
|
720
|
+
end
|
721
|
+
|
722
|
+
def generate_ios_test_recommendations(results)
|
723
|
+
[]
|
724
|
+
end
|
725
|
+
|
726
|
+
def generate_generic_test_recommendations(risk_factors)
|
727
|
+
[]
|
728
|
+
end
|
729
|
+
|
730
|
+
def generate_cross_platform_recommendations(risk_factors)
|
731
|
+
[]
|
732
|
+
end
|
733
|
+
|
734
|
+
def convert_to_sarif_results(test_results)
|
735
|
+
[]
|
736
|
+
end
|
737
|
+
|
738
|
+
def generate_junit_test_case(test)
|
739
|
+
""
|
740
|
+
end
|
741
|
+
end
|
742
|
+
end
|
743
|
+
end
|